From e42417d532ee3984f9c35fbf2539133741c655da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sousa?= Date: Sat, 29 Jul 2023 19:50:47 +0100 Subject: [PATCH 01/20] chore!: upgrade to .net 6 --- .../KafkaFlow.Sample.BatchOperations.csproj | 2 +- .../KafkaFlow.Sample.FlowControl.csproj | 4 ++-- .../KafkaFlow.Sample.PauseConsumerOnError.csproj | 2 +- .../KafkaFlow.Sample.SchemaRegistry.csproj | 2 +- samples/KafkaFlow.Sample/KafkaFlow.Sample.csproj | 2 +- src/Directory.Build.props | 2 +- .../KafkaFlow.Admin.Dashboard.csproj | 4 ++-- src/KafkaFlow.Admin.WebApi/KafkaFlow.Admin.WebApi.csproj | 8 ++++---- src/KafkaFlow.Admin/KafkaFlow.Admin.csproj | 2 +- .../KafkaFlow.Extensions.Hosting.csproj | 2 +- .../KafkaFlow.IntegrationTests.csproj | 4 ++-- .../KafkaFlow.LogHandler.Console.csproj | 4 ++-- .../KafkaFlow.LogHandler.Microsoft.csproj | 4 ++-- .../KafkaFlow.Microsoft.DependencyInjection.csproj | 2 +- .../KafkaFlow.Serializer.JsonCore.csproj | 4 ++-- src/KafkaFlow/KafkaFlow.csproj | 2 +- 16 files changed, 25 insertions(+), 25 deletions(-) diff --git a/samples/KafkaFlow.Sample.BatchOperations/KafkaFlow.Sample.BatchOperations.csproj b/samples/KafkaFlow.Sample.BatchOperations/KafkaFlow.Sample.BatchOperations.csproj index 970ff0ec6..f51dbe58e 100644 --- a/samples/KafkaFlow.Sample.BatchOperations/KafkaFlow.Sample.BatchOperations.csproj +++ b/samples/KafkaFlow.Sample.BatchOperations/KafkaFlow.Sample.BatchOperations.csproj @@ -17,7 +17,7 @@ - + diff --git a/samples/KafkaFlow.Sample.FlowControl/KafkaFlow.Sample.FlowControl.csproj b/samples/KafkaFlow.Sample.FlowControl/KafkaFlow.Sample.FlowControl.csproj index c0be1644d..e4a1914e1 100644 --- a/samples/KafkaFlow.Sample.FlowControl/KafkaFlow.Sample.FlowControl.csproj +++ b/samples/KafkaFlow.Sample.FlowControl/KafkaFlow.Sample.FlowControl.csproj @@ -5,7 +5,7 @@ net6.0 false false - 9 + 10 true @@ -18,7 +18,7 @@ - + diff --git a/samples/KafkaFlow.Sample.PauseConsumerOnError/KafkaFlow.Sample.PauseConsumerOnError.csproj b/samples/KafkaFlow.Sample.PauseConsumerOnError/KafkaFlow.Sample.PauseConsumerOnError.csproj index 1520146c4..f6f6d1e42 100644 --- a/samples/KafkaFlow.Sample.PauseConsumerOnError/KafkaFlow.Sample.PauseConsumerOnError.csproj +++ b/samples/KafkaFlow.Sample.PauseConsumerOnError/KafkaFlow.Sample.PauseConsumerOnError.csproj @@ -20,7 +20,7 @@ - + diff --git a/samples/KafkaFlow.Sample.SchemaRegistry/KafkaFlow.Sample.SchemaRegistry.csproj b/samples/KafkaFlow.Sample.SchemaRegistry/KafkaFlow.Sample.SchemaRegistry.csproj index d03e43ef4..220139cdf 100644 --- a/samples/KafkaFlow.Sample.SchemaRegistry/KafkaFlow.Sample.SchemaRegistry.csproj +++ b/samples/KafkaFlow.Sample.SchemaRegistry/KafkaFlow.Sample.SchemaRegistry.csproj @@ -30,7 +30,7 @@ - + diff --git a/samples/KafkaFlow.Sample/KafkaFlow.Sample.csproj b/samples/KafkaFlow.Sample/KafkaFlow.Sample.csproj index 28d5d3a31..dcf23e1b3 100644 --- a/samples/KafkaFlow.Sample/KafkaFlow.Sample.csproj +++ b/samples/KafkaFlow.Sample/KafkaFlow.Sample.csproj @@ -30,7 +30,7 @@ - + diff --git a/src/Directory.Build.props b/src/Directory.Build.props index b50a98807..673cb04c4 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,6 +1,6 @@ - 9.0 + 10.0 true true snupkg diff --git a/src/KafkaFlow.Admin.Dashboard/KafkaFlow.Admin.Dashboard.csproj b/src/KafkaFlow.Admin.Dashboard/KafkaFlow.Admin.Dashboard.csproj index 6a9338a13..8c6e2431a 100644 --- a/src/KafkaFlow.Admin.Dashboard/KafkaFlow.Admin.Dashboard.csproj +++ b/src/KafkaFlow.Admin.Dashboard/KafkaFlow.Admin.Dashboard.csproj @@ -1,7 +1,7 @@  - netcoreapp3.1 + net6.0 true Latest true @@ -23,7 +23,7 @@ - + diff --git a/src/KafkaFlow.Admin.WebApi/KafkaFlow.Admin.WebApi.csproj b/src/KafkaFlow.Admin.WebApi/KafkaFlow.Admin.WebApi.csproj index b517840d5..44b6cf74e 100644 --- a/src/KafkaFlow.Admin.WebApi/KafkaFlow.Admin.WebApi.csproj +++ b/src/KafkaFlow.Admin.WebApi/KafkaFlow.Admin.WebApi.csproj @@ -1,7 +1,7 @@ - netcoreapp3.1 + net6.0 Library KafkaFlow.Admin.WebApi Allows KafkaFlow to use the Admin Web API @@ -9,12 +9,12 @@ - + + - - + diff --git a/src/KafkaFlow.Admin/KafkaFlow.Admin.csproj b/src/KafkaFlow.Admin/KafkaFlow.Admin.csproj index aca4ff1d3..58d220888 100644 --- a/src/KafkaFlow.Admin/KafkaFlow.Admin.csproj +++ b/src/KafkaFlow.Admin/KafkaFlow.Admin.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/KafkaFlow.Extensions.Hosting/KafkaFlow.Extensions.Hosting.csproj b/src/KafkaFlow.Extensions.Hosting/KafkaFlow.Extensions.Hosting.csproj index 57778d492..0533b40c3 100644 --- a/src/KafkaFlow.Extensions.Hosting/KafkaFlow.Extensions.Hosting.csproj +++ b/src/KafkaFlow.Extensions.Hosting/KafkaFlow.Extensions.Hosting.csproj @@ -13,7 +13,7 @@ - + diff --git a/src/KafkaFlow.IntegrationTests/KafkaFlow.IntegrationTests.csproj b/src/KafkaFlow.IntegrationTests/KafkaFlow.IntegrationTests.csproj index 7eda46e68..bb3a336e7 100644 --- a/src/KafkaFlow.IntegrationTests/KafkaFlow.IntegrationTests.csproj +++ b/src/KafkaFlow.IntegrationTests/KafkaFlow.IntegrationTests.csproj @@ -16,8 +16,8 @@ - - + + diff --git a/src/KafkaFlow.LogHandler.Console/KafkaFlow.LogHandler.Console.csproj b/src/KafkaFlow.LogHandler.Console/KafkaFlow.LogHandler.Console.csproj index 900323d60..44287854f 100644 --- a/src/KafkaFlow.LogHandler.Console/KafkaFlow.LogHandler.Console.csproj +++ b/src/KafkaFlow.LogHandler.Console/KafkaFlow.LogHandler.Console.csproj @@ -6,11 +6,11 @@ - + - + diff --git a/src/KafkaFlow.LogHandler.Microsoft/KafkaFlow.LogHandler.Microsoft.csproj b/src/KafkaFlow.LogHandler.Microsoft/KafkaFlow.LogHandler.Microsoft.csproj index 45f3b48f1..a2ef2b168 100644 --- a/src/KafkaFlow.LogHandler.Microsoft/KafkaFlow.LogHandler.Microsoft.csproj +++ b/src/KafkaFlow.LogHandler.Microsoft/KafkaFlow.LogHandler.Microsoft.csproj @@ -12,8 +12,8 @@ - - + + diff --git a/src/KafkaFlow.Microsoft.DependencyInjection/KafkaFlow.Microsoft.DependencyInjection.csproj b/src/KafkaFlow.Microsoft.DependencyInjection/KafkaFlow.Microsoft.DependencyInjection.csproj index 4c74f2831..ebd8ab6a0 100644 --- a/src/KafkaFlow.Microsoft.DependencyInjection/KafkaFlow.Microsoft.DependencyInjection.csproj +++ b/src/KafkaFlow.Microsoft.DependencyInjection/KafkaFlow.Microsoft.DependencyInjection.csproj @@ -13,7 +13,7 @@ - + diff --git a/src/KafkaFlow.Serializer.JsonCore/KafkaFlow.Serializer.JsonCore.csproj b/src/KafkaFlow.Serializer.JsonCore/KafkaFlow.Serializer.JsonCore.csproj index 35a8df07d..252b999e7 100644 --- a/src/KafkaFlow.Serializer.JsonCore/KafkaFlow.Serializer.JsonCore.csproj +++ b/src/KafkaFlow.Serializer.JsonCore/KafkaFlow.Serializer.JsonCore.csproj @@ -8,10 +8,10 @@ - + - + diff --git a/src/KafkaFlow/KafkaFlow.csproj b/src/KafkaFlow/KafkaFlow.csproj index 1aa6b346b..ddf21310f 100644 --- a/src/KafkaFlow/KafkaFlow.csproj +++ b/src/KafkaFlow/KafkaFlow.csproj @@ -8,7 +8,7 @@ - + From 682c84259c5e4e73002a60ebf77e2268fe219295 Mon Sep 17 00:00:00 2001 From: "jose.sousa@farfetch.com" Date: Wed, 26 Jul 2023 22:50:26 +0100 Subject: [PATCH 02/20] fix!: update dashboard and client app routes to kafkaflow --- .../Program.cs | 2 +- samples/KafkaFlow.Sample.Dashboard/README.md | 2 +- samples/KafkaFlow.Sample.Dashboard/Startup.cs | 4 +- samples/KafkaFlow.Sample.WebApi/Program.cs | 8 +- .../ApplicationBuilderExtensions.cs | 2 +- .../ClientApp/angular.json | 4 +- .../ClientApp/dist/index.html | 2 +- .../ClientApp/dist/main.js | 392 +++++++------- .../src/environments/environment.prod.ts | 2 +- .../ClientApp/src/environments/environment.ts | 2 +- .../DashboardConfigurationBuilder.cs | 2 +- .../Controllers/ConsumersController.cs | 4 +- .../Controllers/GroupsController.cs | 4 +- .../Controllers/TelemetryController.cs | 2 +- .../Handlers/PauseConsumerByNameHandler.cs | 2 +- .../RewindConsumerOffsetToDateTimeHandler.cs | 2 +- .../ProducerTest.cs | 1 - .../Controllers/ConsumersControllerTests.cs | 506 ++++++++++++++++++ .../Controllers/GroupsControllerTests.cs | 91 ++++ .../Controllers/TelemetryControllerTests.cs | 130 +++++ .../KafkaFlow.UnitTests.csproj | 4 +- 21 files changed, 948 insertions(+), 220 deletions(-) create mode 100644 src/KafkaFlow.UnitTests/Admin.WebApi/Controllers/ConsumersControllerTests.cs create mode 100644 src/KafkaFlow.UnitTests/Admin.WebApi/Controllers/GroupsControllerTests.cs create mode 100644 src/KafkaFlow.UnitTests/Admin.WebApi/Controllers/TelemetryControllerTests.cs diff --git a/samples/KafkaFlow.Sample.BatchOperations/Program.cs b/samples/KafkaFlow.Sample.BatchOperations/Program.cs index a47f7a704..1515286ed 100644 --- a/samples/KafkaFlow.Sample.BatchOperations/Program.cs +++ b/samples/KafkaFlow.Sample.BatchOperations/Program.cs @@ -30,7 +30,7 @@ .AddConsumer( consumerBuilder => consumerBuilder .Topic(batchTestTopic) - .WithGroupId("kafka-flow-sample") + .WithGroupId("kafkaflow-sample") .WithBufferSize(10000) .WithWorkersCount(1) .AddMiddlewares( diff --git a/samples/KafkaFlow.Sample.Dashboard/README.md b/samples/KafkaFlow.Sample.Dashboard/README.md index 88ac8c9e7..a5c37c4e1 100644 --- a/samples/KafkaFlow.Sample.Dashboard/README.md +++ b/samples/KafkaFlow.Sample.Dashboard/README.md @@ -27,4 +27,4 @@ Using your terminal of choice, start the sample for the sample folder. dotnet run ``` -The dashboard UI will be available at `/kafka-flow`. +The dashboard UI will be available at `/kafkaflow`. diff --git a/samples/KafkaFlow.Sample.Dashboard/Startup.cs b/samples/KafkaFlow.Sample.Dashboard/Startup.cs index cd7090457..289b2bef6 100644 --- a/samples/KafkaFlow.Sample.Dashboard/Startup.cs +++ b/samples/KafkaFlow.Sample.Dashboard/Startup.cs @@ -20,8 +20,8 @@ public void ConfigureServices(IServiceCollection services) const string topicName = "topic-dashboard"; cluster .WithBrokers(new[] { "localhost:9092" }) - .EnableAdminMessages("kafka-flow.admin", "kafka-flow.admin.group.id") - .EnableTelemetry("kafka-flow.admin", "kafka-flow.telemetry.group.id") + .EnableAdminMessages("kafkaflow.admin", "kafkaflow.admin.group.id") + .EnableTelemetry("kafkaflow.admin", "kafkaflow.telemetry.group.id") .CreateTopicIfNotExists(topicName, 3, 1) .AddConsumer( consumer => diff --git a/samples/KafkaFlow.Sample.WebApi/Program.cs b/samples/KafkaFlow.Sample.WebApi/Program.cs index 62e03129a..d50287655 100644 --- a/samples/KafkaFlow.Sample.WebApi/Program.cs +++ b/samples/KafkaFlow.Sample.WebApi/Program.cs @@ -10,7 +10,7 @@ .AddCluster( cluster => cluster .WithBrokers(new[] { "localhost:9092" }) - .EnableAdminMessages("kafka-flow.admin") + .EnableAdminMessages("kafkaflow.admin") ) ); @@ -19,11 +19,11 @@ c => { c.SwaggerDoc( - "kafka-flow", + "kafkaflow", new OpenApiInfo { Title = "KafkaFlow Admin", - Version = "kafka-flow", + Version = "kafkaflow", }); }) .AddControllers(); @@ -37,7 +37,7 @@ app.UseSwagger(); app.UseSwaggerUI(c => { - c.SwaggerEndpoint("/swagger/kafka-flow/swagger.json", "KafkaFlow Admin"); + c.SwaggerEndpoint("/swagger/kafkaflow/swagger.json", "KafkaFlow Admin"); }); var kafkaBus = app.Services.CreateKafkaBus(); diff --git a/src/KafkaFlow.Admin.Dashboard/ApplicationBuilderExtensions.cs b/src/KafkaFlow.Admin.Dashboard/ApplicationBuilderExtensions.cs index 0eff65f3f..f525b9a1a 100644 --- a/src/KafkaFlow.Admin.Dashboard/ApplicationBuilderExtensions.cs +++ b/src/KafkaFlow.Admin.Dashboard/ApplicationBuilderExtensions.cs @@ -16,7 +16,7 @@ namespace KafkaFlow.Admin.Dashboard public static class ApplicationBuilderExtensions { /// - /// Enable the KafkaFlow dashboard. The path will be `/kafka-flow` + /// Enable the KafkaFlow dashboard. The path will be `/kafkaflow` /// /// Instance of /// diff --git a/src/KafkaFlow.Admin.Dashboard/ClientApp/angular.json b/src/KafkaFlow.Admin.Dashboard/ClientApp/angular.json index 8546c530d..e0f737e14 100644 --- a/src/KafkaFlow.Admin.Dashboard/ClientApp/angular.json +++ b/src/KafkaFlow.Admin.Dashboard/ClientApp/angular.json @@ -29,7 +29,7 @@ "customWebpackConfig": { "path": "./webpack.config.js" }, - "baseHref": "/kafka-flow/", + "baseHref": "/kafkaflow/", "outputPath": "dist", "index": "src/index.html", "main": "src/main.ts", @@ -143,4 +143,4 @@ } }, "defaultProject": "dashboard" -} \ No newline at end of file +} diff --git a/src/KafkaFlow.Admin.Dashboard/ClientApp/dist/index.html b/src/KafkaFlow.Admin.Dashboard/ClientApp/dist/index.html index a83bac539..71b0381c3 100644 --- a/src/KafkaFlow.Admin.Dashboard/ClientApp/dist/index.html +++ b/src/KafkaFlow.Admin.Dashboard/ClientApp/dist/index.html @@ -3,7 +3,7 @@ KafkaFlow - Dashboard - + diff --git a/src/KafkaFlow.Admin.Dashboard/ClientApp/dist/main.js b/src/KafkaFlow.Admin.Dashboard/ClientApp/dist/main.js index 60bad6258..4d471d3b3 100644 --- a/src/KafkaFlow.Admin.Dashboard/ClientApp/dist/main.js +++ b/src/KafkaFlow.Admin.Dashboard/ClientApp/dist/main.js @@ -1,4 +1,4 @@ -(self.webpackChunkdashboard=self.webpackChunkdashboard||[]).push([[179],{381:(gr,th,iu)=>{"use strict";function ye(e){return"function"==typeof e}function V(e){const t=e(i=>{Error.call(i),i.stack=(new Error).stack});return t.prototype=Object.create(Error.prototype),t.prototype.constructor=t,t}const qa=V(e=>function(t){e(this),this.message=t?`${t.length} errors occurred during unsubscription:\n${t.map((i,r)=>`${r+1}) ${i.toString()}`).join("\n ")}`:"",this.name="UnsubscriptionError",this.errors=t});function dn(e,n){if(e){const t=e.indexOf(n);0<=t&&e.splice(t,1)}}class Ct{constructor(n){this.initialTeardown=n,this.closed=!1,this._parentage=null,this._finalizers=null}unsubscribe(){let n;if(!this.closed){this.closed=!0;const{_parentage:t}=this;if(t)if(this._parentage=null,Array.isArray(t))for(const o of t)o.remove(this);else t.remove(this);const{initialTeardown:i}=this;if(ye(i))try{i()}catch(o){n=o instanceof qa?o.errors:[o]}const{_finalizers:r}=this;if(r){this._finalizers=null;for(const o of r)try{qt(o)}catch(s){n=n??[],s instanceof qa?n=[...n,...s.errors]:n.push(s)}}if(n)throw new qa(n)}}add(n){var t;if(n&&n!==this)if(this.closed)qt(n);else{if(n instanceof Ct){if(n.closed||n._hasParent(this))return;n._addParent(this)}(this._finalizers=null!==(t=this._finalizers)&&void 0!==t?t:[]).push(n)}}_hasParent(n){const{_parentage:t}=this;return t===n||Array.isArray(t)&&t.includes(n)}_addParent(n){const{_parentage:t}=this;this._parentage=Array.isArray(t)?(t.push(n),t):t?[t,n]:n}_removeParent(n){const{_parentage:t}=this;t===n?this._parentage=null:Array.isArray(t)&&dn(t,n)}remove(n){const{_finalizers:t}=this;t&&dn(t,n),n instanceof Ct&&n._removeParent(this)}}Ct.EMPTY=(()=>{const e=new Ct;return e.closed=!0,e})();const we=Ct.EMPTY;function bs(e){return e instanceof Ct||e&&"closed"in e&&ye(e.remove)&&ye(e.add)&&ye(e.unsubscribe)}function qt(e){ye(e)?e():e.unsubscribe()}const Jt={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1},Zi={setTimeout(e,n,...t){const{delegate:i}=Zi;return i?.setTimeout?i.setTimeout(e,n,...t):setTimeout(e,n,...t)},clearTimeout(e){const{delegate:n}=Zi;return(n?.clearTimeout||clearTimeout)(e)},delegate:void 0};function Ja(e){Zi.setTimeout(()=>{const{onUnhandledError:n}=Jt;if(!n)throw e;n(e)})}function Dn(){}const ii=Mo("C",void 0,void 0);function Mo(e,n,t){return{kind:e,value:n,error:t}}let Ci=null;function mr(e){if(Jt.useDeprecatedSynchronousErrorHandling){const n=!Ci;if(n&&(Ci={errorThrown:!1,error:null}),e(),n){const{errorThrown:t,error:i}=Ci;if(Ci=null,t)throw i}}else e()}class No extends Ct{constructor(n){super(),this.isStopped=!1,n?(this.destination=n,bs(n)&&n.add(this)):this.destination=ri}static create(n,t,i){return new vr(n,t,i)}next(n){this.isStopped?Ds(function le(e){return Mo("N",e,void 0)}(n),this):this._next(n)}error(n){this.isStopped?Ds(function nh(e){return Mo("E",void 0,e)}(n),this):(this.isStopped=!0,this._error(n))}complete(){this.isStopped?Ds(ii,this):(this.isStopped=!0,this._complete())}unsubscribe(){this.closed||(this.isStopped=!0,super.unsubscribe(),this.destination=null)}_next(n){this.destination.next(n)}_error(n){try{this.destination.error(n)}finally{this.unsubscribe()}}_complete(){try{this.destination.complete()}finally{this.unsubscribe()}}}const Za=Function.prototype.bind;function _r(e,n){return Za.call(e,n)}class Wn{constructor(n){this.partialObserver=n}next(n){const{partialObserver:t}=this;if(t.next)try{t.next(n)}catch(i){Zt(i)}}error(n){const{partialObserver:t}=this;if(t.error)try{t.error(n)}catch(i){Zt(i)}else Zt(n)}complete(){const{partialObserver:n}=this;if(n.complete)try{n.complete()}catch(t){Zt(t)}}}class vr extends No{constructor(n,t,i){let r;if(super(),ye(n)||!n)r={next:n??void 0,error:t??void 0,complete:i??void 0};else{let o;this&&Jt.useDeprecatedNextContext?(o=Object.create(n),o.unsubscribe=()=>this.unsubscribe(),r={next:n.next&&_r(n.next,o),error:n.error&&_r(n.error,o),complete:n.complete&&_r(n.complete,o)}):r=n}this.destination=new Wn(r)}}function Zt(e){Jt.useDeprecatedSynchronousErrorHandling?function ru(e){Jt.useDeprecatedSynchronousErrorHandling&&Ci&&(Ci.errorThrown=!0,Ci.error=e)}(e):Ja(e)}function Ds(e,n){const{onStoppedNotification:t}=Jt;t&&Zi.setTimeout(()=>t(e,n))}const ri={closed:!0,next:Dn,error:function ou(e){throw e},complete:Dn},Qa="function"==typeof Symbol&&Symbol.observable||"@@observable";function xn(e){return e}function Cs(e){return 0===e.length?xn:1===e.length?e[0]:function(t){return e.reduce((i,r)=>r(i),t)}}let je=(()=>{class e{constructor(t){t&&(this._subscribe=t)}lift(t){const i=new e;return i.source=this,i.operator=t,i}subscribe(t,i,r){const o=function el(e){return e&&e instanceof No||function oi(e){return e&&ye(e.next)&&ye(e.error)&&ye(e.complete)}(e)&&bs(e)}(t)?t:new vr(t,i,r);return mr(()=>{const{operator:s,source:a}=this;o.add(s?s.call(o,a):a?this._subscribe(o):this._trySubscribe(o))}),o}_trySubscribe(t){try{return this._subscribe(t)}catch(i){t.error(i)}}forEach(t,i){return new(i=su(i))((r,o)=>{const s=new vr({next:a=>{try{t(a)}catch(l){o(l),s.unsubscribe()}},error:o,complete:r});this.subscribe(s)})}_subscribe(t){var i;return null===(i=this.source)||void 0===i?void 0:i.subscribe(t)}[Qa](){return this}pipe(...t){return Cs(t)(this)}toPromise(t){return new(t=su(t))((i,r)=>{let o;this.subscribe(s=>o=s,s=>r(s),()=>i(o))})}}return e.create=n=>new e(n),e})();function su(e){var n;return null!==(n=e??Jt.Promise)&&void 0!==n?n:Promise}const ws=V(e=>function(){e(this),this.name="ObjectUnsubscribedError",this.message="object unsubscribed"});let Ue=(()=>{class e extends je{constructor(){super(),this.closed=!1,this.currentObservers=null,this.observers=[],this.isStopped=!1,this.hasError=!1,this.thrownError=null}lift(t){const i=new yr(this,this);return i.operator=t,i}_throwIfClosed(){if(this.closed)throw new ws}next(t){mr(()=>{if(this._throwIfClosed(),!this.isStopped){this.currentObservers||(this.currentObservers=Array.from(this.observers));for(const i of this.currentObservers)i.next(t)}})}error(t){mr(()=>{if(this._throwIfClosed(),!this.isStopped){this.hasError=this.isStopped=!0,this.thrownError=t;const{observers:i}=this;for(;i.length;)i.shift().error(t)}})}complete(){mr(()=>{if(this._throwIfClosed(),!this.isStopped){this.isStopped=!0;const{observers:t}=this;for(;t.length;)t.shift().complete()}})}unsubscribe(){this.isStopped=this.closed=!0,this.observers=this.currentObservers=null}get observed(){var t;return(null===(t=this.observers)||void 0===t?void 0:t.length)>0}_trySubscribe(t){return this._throwIfClosed(),super._trySubscribe(t)}_subscribe(t){return this._throwIfClosed(),this._checkFinalizedStatuses(t),this._innerSubscribe(t)}_innerSubscribe(t){const{hasError:i,isStopped:r,observers:o}=this;return i||r?we:(this.currentObservers=null,o.push(t),new Ct(()=>{this.currentObservers=null,dn(o,t)}))}_checkFinalizedStatuses(t){const{hasError:i,thrownError:r,isStopped:o}=this;i?t.error(r):o&&t.complete()}asObservable(){const t=new je;return t.source=this,t}}return e.create=(n,t)=>new yr(n,t),e})();class yr extends Ue{constructor(n,t){super(),this.destination=n,this.source=t}next(n){var t,i;null===(i=null===(t=this.destination)||void 0===t?void 0:t.next)||void 0===i||i.call(t,n)}error(n){var t,i;null===(i=null===(t=this.destination)||void 0===t?void 0:t.error)||void 0===i||i.call(t,n)}complete(){var n,t;null===(t=null===(n=this.destination)||void 0===n?void 0:n.complete)||void 0===t||t.call(n)}_subscribe(n){var t,i;return null!==(i=null===(t=this.source)||void 0===t?void 0:t.subscribe(n))&&void 0!==i?i:we}}function z(e){return ye(e?.lift)}function qe(e){return n=>{if(z(n))return n.lift(function(t){try{return e(t,this)}catch(i){this.error(i)}});throw new TypeError("Unable to lift unknown Observable type")}}function ke(e,n,t,i,r){return new Ss(e,n,t,i,r)}class Ss extends No{constructor(n,t,i,r,o,s){super(n),this.onFinalize=o,this.shouldUnsubscribe=s,this._next=t?function(a){try{t(a)}catch(l){n.error(l)}}:super._next,this._error=r?function(a){try{r(a)}catch(l){n.error(l)}finally{this.unsubscribe()}}:super._error,this._complete=i?function(){try{i()}catch(a){n.error(a)}finally{this.unsubscribe()}}:super._complete}unsubscribe(){var n;if(!this.shouldUnsubscribe||this.shouldUnsubscribe()){const{closed:t}=this;super.unsubscribe(),!t&&(null===(n=this.onFinalize)||void 0===n||n.call(this))}}}function ne(e,n){return qe((t,i)=>{let r=0;t.subscribe(ke(i,o=>{i.next(e.call(n,o,r++))}))})}function br(e){return this instanceof br?(this.v=e,this):new br(e)}function Ms(e,n,t){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var r,i=t.apply(e,n||[]),o=[];return r={},s("next"),s("throw"),s("return"),r[Symbol.asyncIterator]=function(){return this},r;function s(m){i[m]&&(r[m]=function(v){return new Promise(function(y,D){o.push([m,v,y,D])>1||a(m,v)})})}function a(m,v){try{!function l(m){m.value instanceof br?Promise.resolve(m.value.v).then(u,f):p(o[0][2],m)}(i[m](v))}catch(y){p(o[0][3],y)}}function u(m){a("next",m)}function f(m){a("throw",m)}function p(m,v){m(v),o.shift(),o.length&&a(o[0][0],o[0][1])}}function he(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t,n=e[Symbol.asyncIterator];return n?n.call(e):(e=function Rt(e){var n="function"==typeof Symbol&&Symbol.iterator,t=n&&e[n],i=0;if(t)return t.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&i>=e.length&&(e=void 0),{value:e&&e[i++],done:!e}}};throw new TypeError(n?"Object is not iterable.":"Symbol.iterator is not defined.")}(e),t={},i("next"),i("throw"),i("return"),t[Symbol.asyncIterator]=function(){return this},t);function i(o){t[o]=e[o]&&function(s){return new Promise(function(a,l){!function r(o,s,a,l){Promise.resolve(l).then(function(u){o({value:u,done:a})},s)}(a,l,(s=e[o](s)).done,s.value)})}}}const Ts=e=>e&&"number"==typeof e.length&&"function"!=typeof e;function As(e){return ye(e?.then)}function Ao(e){return ye(e[Qa])}function Ge(e){return Symbol.asyncIterator&&ye(e?.[Symbol.asyncIterator])}function nl(e){return new TypeError(`You provided ${null!==e&&"object"==typeof e?"an invalid object":`'${e}'`} where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.`)}const Io=function uu(){return"function"==typeof Symbol&&Symbol.iterator?Symbol.iterator:"@@iterator"}();function Is(e){return ye(e?.[Io])}function Oo(e){return Ms(this,arguments,function*(){const t=e.getReader();try{for(;;){const{value:i,done:r}=yield br(t.read());if(r)return yield br(void 0);yield yield br(i)}}finally{t.releaseLock()}})}function Dr(e){return ye(e?.getReader)}function ut(e){if(e instanceof je)return e;if(null!=e){if(Ao(e))return function ah(e){return new je(n=>{const t=e[Qa]();if(ye(t.subscribe))return t.subscribe(n);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}(e);if(Ts(e))return function Os(e){return new je(n=>{for(let t=0;t{e.then(t=>{n.closed||(n.next(t),n.complete())},t=>n.error(t)).then(null,Ja)})}(e);if(Ge(e))return Ro(e);if(Is(e))return function ko(e){return new je(n=>{for(const t of e)if(n.next(t),n.closed)return;n.complete()})}(e);if(Dr(e))return function $(e){return Ro(Oo(e))}(e)}throw nl(e)}function Ro(e){return new je(n=>{(function ch(e,n){var t,i,r,o;return function ih(e,n,t,i){return new(t||(t=Promise))(function(o,s){function a(f){try{u(i.next(f))}catch(p){s(p)}}function l(f){try{u(i.throw(f))}catch(p){s(p)}}function u(f){f.done?o(f.value):function r(o){return o instanceof t?o:new t(function(s){s(o)})}(f.value).then(a,l)}u((i=i.apply(e,n||[])).next())})}(this,void 0,void 0,function*(){try{for(t=he(e);!(i=yield t.next()).done;)if(n.next(i.value),n.closed)return}catch(s){r={error:s}}finally{try{i&&!i.done&&(o=t.return)&&(yield o.call(t))}finally{if(r)throw r.error}}n.complete()})})(e,n).catch(t=>n.error(t))})}function wi(e,n,t,i=0,r=!1){const o=n.schedule(function(){t(),r?e.add(this.schedule(null,i)):this.unsubscribe()},i);if(e.add(o),!r)return o}function dt(e,n,t=1/0){return ye(n)?dt((i,r)=>ne((o,s)=>n(i,o,r,s))(ut(e(i,r))),t):("number"==typeof n&&(t=n),qe((i,r)=>function Cn(e,n,t,i,r,o,s,a){const l=[];let u=0,f=0,p=!1;const m=()=>{p&&!l.length&&!u&&n.complete()},v=D=>u{o&&n.next(D),u++;let w=!1;ut(t(D,f++)).subscribe(ke(n,M=>{r?.(M),o?v(M):n.next(M)},()=>{w=!0},void 0,()=>{if(w)try{for(u--;l.length&&uy(M)):y(M)}m()}catch(M){n.error(M)}}))};return e.subscribe(ke(n,v,()=>{p=!0,m()})),()=>{a?.()}}(i,r,e,t)))}function Se(e=1/0){return dt(xn,e)}const Xt=new je(e=>e.complete());function si(e){return e&&ye(e.schedule)}function Ln(e){return e[e.length-1]}function rt(e){return ye(Ln(e))?e.pop():void 0}function en(e){return si(Ln(e))?e.pop():void 0}function Qi(e,n=0){return qe((t,i)=>{t.subscribe(ke(i,r=>wi(i,e,()=>i.next(r),n),()=>wi(i,e,()=>i.complete(),n),r=>wi(i,e,()=>i.error(r),n)))})}function du(e,n=0){return qe((t,i)=>{i.add(e.schedule(()=>t.subscribe(i),n))})}function fu(e,n){if(!e)throw new Error("Iterable cannot be null");return new je(t=>{wi(t,n,()=>{const i=e[Symbol.asyncIterator]();wi(t,n,()=>{i.next().then(r=>{r.done?t.complete():t.next(r.value)})},0,!0)})})}function gt(e,n){return n?function pu(e,n){if(null!=e){if(Ao(e))return function uh(e,n){return ut(e).pipe(du(n),Qi(n))}(e,n);if(Ts(e))return function ft(e,n){return new je(t=>{let i=0;return n.schedule(function(){i===e.length?t.complete():(t.next(e[i++]),t.closed||this.schedule())})})}(e,n);if(As(e))return function dh(e,n){return ut(e).pipe(du(n),Qi(n))}(e,n);if(Ge(e))return fu(e,n);if(Is(e))return function ks(e,n){return new je(t=>{let i;return wi(t,n,()=>{i=e[Io](),wi(t,n,()=>{let r,o;try{({value:r,done:o}=i.next())}catch(s){return void t.error(s)}o?t.complete():t.next(r)},0,!0)}),()=>ye(i?.return)&&i.return()})}(e,n);if(Dr(e))return function hu(e,n){return fu(Oo(e),n)}(e,n)}throw nl(e)}(e,n):ut(e)}function il(e,n,...t){if(!0===n)return void e();if(!1===n)return;const i=new vr({next:()=>{i.unsubscribe(),e()}});return n(...t).subscribe(i)} +(self.webpackChunkdashboard=self.webpackChunkdashboard||[]).push([[179],{381:(gr,th,iu)=>{"use strict";function ye(e){return"function"==typeof e}function V(e){const t=e(i=>{Error.call(i),i.stack=(new Error).stack});return t.prototype=Object.create(Error.prototype),t.prototype.constructor=t,t}const qa=V(e=>function(t){e(this),this.message=t?`${t.length} errors occurred during unsubscription:\n${t.map((i,r)=>`${r+1}) ${i.toString()}`).join("\n ")}`:"",this.name="UnsubscriptionError",this.errors=t});function dn(e,n){if(e){const t=e.indexOf(n);0<=t&&e.splice(t,1)}}class Ct{constructor(n){this.initialTeardown=n,this.closed=!1,this._parentage=null,this._finalizers=null}unsubscribe(){let n;if(!this.closed){this.closed=!0;const{_parentage:t}=this;if(t)if(this._parentage=null,Array.isArray(t))for(const o of t)o.remove(this);else t.remove(this);const{initialTeardown:i}=this;if(ye(i))try{i()}catch(o){n=o instanceof qa?o.errors:[o]}const{_finalizers:r}=this;if(r){this._finalizers=null;for(const o of r)try{qt(o)}catch(s){n=n??[],s instanceof qa?n=[...n,...s.errors]:n.push(s)}}if(n)throw new qa(n)}}add(n){var t;if(n&&n!==this)if(this.closed)qt(n);else{if(n instanceof Ct){if(n.closed||n._hasParent(this))return;n._addParent(this)}(this._finalizers=null!==(t=this._finalizers)&&void 0!==t?t:[]).push(n)}}_hasParent(n){const{_parentage:t}=this;return t===n||Array.isArray(t)&&t.includes(n)}_addParent(n){const{_parentage:t}=this;this._parentage=Array.isArray(t)?(t.push(n),t):t?[t,n]:n}_removeParent(n){const{_parentage:t}=this;t===n?this._parentage=null:Array.isArray(t)&&dn(t,n)}remove(n){const{_finalizers:t}=this;t&&dn(t,n),n instanceof Ct&&n._removeParent(this)}}Ct.EMPTY=(()=>{const e=new Ct;return e.closed=!0,e})();const we=Ct.EMPTY;function bs(e){return e instanceof Ct||e&&"closed"in e&&ye(e.remove)&&ye(e.add)&&ye(e.unsubscribe)}function qt(e){ye(e)?e():e.unsubscribe()}const Zt={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1},Ji={setTimeout(e,n,...t){const{delegate:i}=Ji;return i?.setTimeout?i.setTimeout(e,n,...t):setTimeout(e,n,...t)},clearTimeout(e){const{delegate:n}=Ji;return(n?.clearTimeout||clearTimeout)(e)},delegate:void 0};function Za(e){Ji.setTimeout(()=>{const{onUnhandledError:n}=Zt;if(!n)throw e;n(e)})}function Dn(){}const ii=No("C",void 0,void 0);function No(e,n,t){return{kind:e,value:n,error:t}}let Ci=null;function mr(e){if(Zt.useDeprecatedSynchronousErrorHandling){const n=!Ci;if(n&&(Ci={errorThrown:!1,error:null}),e(),n){const{errorThrown:t,error:i}=Ci;if(Ci=null,t)throw i}}else e()}class Eo extends Ct{constructor(n){super(),this.isStopped=!1,n?(this.destination=n,bs(n)&&n.add(this)):this.destination=ri}static create(n,t,i){return new vr(n,t,i)}next(n){this.isStopped?Ds(function le(e){return No("N",e,void 0)}(n),this):this._next(n)}error(n){this.isStopped?Ds(function nh(e){return No("E",void 0,e)}(n),this):(this.isStopped=!0,this._error(n))}complete(){this.isStopped?Ds(ii,this):(this.isStopped=!0,this._complete())}unsubscribe(){this.closed||(this.isStopped=!0,super.unsubscribe(),this.destination=null)}_next(n){this.destination.next(n)}_error(n){try{this.destination.error(n)}finally{this.unsubscribe()}}_complete(){try{this.destination.complete()}finally{this.unsubscribe()}}}const Ja=Function.prototype.bind;function _r(e,n){return Ja.call(e,n)}class Wn{constructor(n){this.partialObserver=n}next(n){const{partialObserver:t}=this;if(t.next)try{t.next(n)}catch(i){Jt(i)}}error(n){const{partialObserver:t}=this;if(t.error)try{t.error(n)}catch(i){Jt(i)}else Jt(n)}complete(){const{partialObserver:n}=this;if(n.complete)try{n.complete()}catch(t){Jt(t)}}}class vr extends Eo{constructor(n,t,i){let r;if(super(),ye(n)||!n)r={next:n??void 0,error:t??void 0,complete:i??void 0};else{let o;this&&Zt.useDeprecatedNextContext?(o=Object.create(n),o.unsubscribe=()=>this.unsubscribe(),r={next:n.next&&_r(n.next,o),error:n.error&&_r(n.error,o),complete:n.complete&&_r(n.complete,o)}):r=n}this.destination=new Wn(r)}}function Jt(e){Zt.useDeprecatedSynchronousErrorHandling?function ru(e){Zt.useDeprecatedSynchronousErrorHandling&&Ci&&(Ci.errorThrown=!0,Ci.error=e)}(e):Za(e)}function Ds(e,n){const{onStoppedNotification:t}=Zt;t&&Ji.setTimeout(()=>t(e,n))}const ri={closed:!0,next:Dn,error:function ou(e){throw e},complete:Dn},Qa="function"==typeof Symbol&&Symbol.observable||"@@observable";function Rn(e){return e}function Cs(e){return 0===e.length?Rn:1===e.length?e[0]:function(t){return e.reduce((i,r)=>r(i),t)}}let je=(()=>{class e{constructor(t){t&&(this._subscribe=t)}lift(t){const i=new e;return i.source=this,i.operator=t,i}subscribe(t,i,r){const o=function el(e){return e&&e instanceof Eo||function oi(e){return e&&ye(e.next)&&ye(e.error)&&ye(e.complete)}(e)&&bs(e)}(t)?t:new vr(t,i,r);return mr(()=>{const{operator:s,source:a}=this;o.add(s?s.call(o,a):a?this._subscribe(o):this._trySubscribe(o))}),o}_trySubscribe(t){try{return this._subscribe(t)}catch(i){t.error(i)}}forEach(t,i){return new(i=su(i))((r,o)=>{const s=new vr({next:a=>{try{t(a)}catch(l){o(l),s.unsubscribe()}},error:o,complete:r});this.subscribe(s)})}_subscribe(t){var i;return null===(i=this.source)||void 0===i?void 0:i.subscribe(t)}[Qa](){return this}pipe(...t){return Cs(t)(this)}toPromise(t){return new(t=su(t))((i,r)=>{let o;this.subscribe(s=>o=s,s=>r(s),()=>i(o))})}}return e.create=n=>new e(n),e})();function su(e){var n;return null!==(n=e??Zt.Promise)&&void 0!==n?n:Promise}const ws=V(e=>function(){e(this),this.name="ObjectUnsubscribedError",this.message="object unsubscribed"});let Ue=(()=>{class e extends je{constructor(){super(),this.closed=!1,this.currentObservers=null,this.observers=[],this.isStopped=!1,this.hasError=!1,this.thrownError=null}lift(t){const i=new yr(this,this);return i.operator=t,i}_throwIfClosed(){if(this.closed)throw new ws}next(t){mr(()=>{if(this._throwIfClosed(),!this.isStopped){this.currentObservers||(this.currentObservers=Array.from(this.observers));for(const i of this.currentObservers)i.next(t)}})}error(t){mr(()=>{if(this._throwIfClosed(),!this.isStopped){this.hasError=this.isStopped=!0,this.thrownError=t;const{observers:i}=this;for(;i.length;)i.shift().error(t)}})}complete(){mr(()=>{if(this._throwIfClosed(),!this.isStopped){this.isStopped=!0;const{observers:t}=this;for(;t.length;)t.shift().complete()}})}unsubscribe(){this.isStopped=this.closed=!0,this.observers=this.currentObservers=null}get observed(){var t;return(null===(t=this.observers)||void 0===t?void 0:t.length)>0}_trySubscribe(t){return this._throwIfClosed(),super._trySubscribe(t)}_subscribe(t){return this._throwIfClosed(),this._checkFinalizedStatuses(t),this._innerSubscribe(t)}_innerSubscribe(t){const{hasError:i,isStopped:r,observers:o}=this;return i||r?we:(this.currentObservers=null,o.push(t),new Ct(()=>{this.currentObservers=null,dn(o,t)}))}_checkFinalizedStatuses(t){const{hasError:i,thrownError:r,isStopped:o}=this;i?t.error(r):o&&t.complete()}asObservable(){const t=new je;return t.source=this,t}}return e.create=(n,t)=>new yr(n,t),e})();class yr extends Ue{constructor(n,t){super(),this.destination=n,this.source=t}next(n){var t,i;null===(i=null===(t=this.destination)||void 0===t?void 0:t.next)||void 0===i||i.call(t,n)}error(n){var t,i;null===(i=null===(t=this.destination)||void 0===t?void 0:t.error)||void 0===i||i.call(t,n)}complete(){var n,t;null===(t=null===(n=this.destination)||void 0===n?void 0:n.complete)||void 0===t||t.call(n)}_subscribe(n){var t,i;return null!==(i=null===(t=this.source)||void 0===t?void 0:t.subscribe(n))&&void 0!==i?i:we}}function Y(e){return ye(e?.lift)}function qe(e){return n=>{if(Y(n))return n.lift(function(t){try{return e(t,this)}catch(i){this.error(i)}});throw new TypeError("Unable to lift unknown Observable type")}}function Oe(e,n,t,i,r){return new Ss(e,n,t,i,r)}class Ss extends Eo{constructor(n,t,i,r,o,s){super(n),this.onFinalize=o,this.shouldUnsubscribe=s,this._next=t?function(a){try{t(a)}catch(l){n.error(l)}}:super._next,this._error=r?function(a){try{r(a)}catch(l){n.error(l)}finally{this.unsubscribe()}}:super._error,this._complete=i?function(){try{i()}catch(a){n.error(a)}finally{this.unsubscribe()}}:super._complete}unsubscribe(){var n;if(!this.shouldUnsubscribe||this.shouldUnsubscribe()){const{closed:t}=this;super.unsubscribe(),!t&&(null===(n=this.onFinalize)||void 0===n||n.call(this))}}}function ne(e,n){return qe((t,i)=>{let r=0;t.subscribe(Oe(i,o=>{i.next(e.call(n,o,r++))}))})}function br(e){return this instanceof br?(this.v=e,this):new br(e)}function Ns(e,n,t){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var r,i=t.apply(e,n||[]),o=[];return r={},s("next"),s("throw"),s("return"),r[Symbol.asyncIterator]=function(){return this},r;function s(m){i[m]&&(r[m]=function(v){return new Promise(function(y,D){o.push([m,v,y,D])>1||a(m,v)})})}function a(m,v){try{!function l(m){m.value instanceof br?Promise.resolve(m.value.v).then(u,f):p(o[0][2],m)}(i[m](v))}catch(y){p(o[0][3],y)}}function u(m){a("next",m)}function f(m){a("throw",m)}function p(m,v){m(v),o.shift(),o.length&&a(o[0][0],o[0][1])}}function he(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t,n=e[Symbol.asyncIterator];return n?n.call(e):(e=function xt(e){var n="function"==typeof Symbol&&Symbol.iterator,t=n&&e[n],i=0;if(t)return t.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&i>=e.length&&(e=void 0),{value:e&&e[i++],done:!e}}};throw new TypeError(n?"Object is not iterable.":"Symbol.iterator is not defined.")}(e),t={},i("next"),i("throw"),i("return"),t[Symbol.asyncIterator]=function(){return this},t);function i(o){t[o]=e[o]&&function(s){return new Promise(function(a,l){!function r(o,s,a,l){Promise.resolve(l).then(function(u){o({value:u,done:a})},s)}(a,l,(s=e[o](s)).done,s.value)})}}}const Ts=e=>e&&"number"==typeof e.length&&"function"!=typeof e;function Is(e){return ye(e?.then)}function Io(e){return ye(e[Qa])}function Ge(e){return Symbol.asyncIterator&&ye(e?.[Symbol.asyncIterator])}function nl(e){return new TypeError(`You provided ${null!==e&&"object"==typeof e?"an invalid object":`'${e}'`} where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.`)}const Ao=function uu(){return"function"==typeof Symbol&&Symbol.iterator?Symbol.iterator:"@@iterator"}();function As(e){return ye(e?.[Ao])}function ko(e){return Ns(this,arguments,function*(){const t=e.getReader();try{for(;;){const{value:i,done:r}=yield br(t.read());if(r)return yield br(void 0);yield yield br(i)}}finally{t.releaseLock()}})}function Dr(e){return ye(e?.getReader)}function ut(e){if(e instanceof je)return e;if(null!=e){if(Io(e))return function ah(e){return new je(n=>{const t=e[Qa]();if(ye(t.subscribe))return t.subscribe(n);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}(e);if(Ts(e))return function ks(e){return new je(n=>{for(let t=0;t{e.then(t=>{n.closed||(n.next(t),n.complete())},t=>n.error(t)).then(null,Za)})}(e);if(Ge(e))return xo(e);if(As(e))return function Oo(e){return new je(n=>{for(const t of e)if(n.next(t),n.closed)return;n.complete()})}(e);if(Dr(e))return function $(e){return xo(ko(e))}(e)}throw nl(e)}function xo(e){return new je(n=>{(function ch(e,n){var t,i,r,o;return function ih(e,n,t,i){return new(t||(t=Promise))(function(o,s){function a(f){try{u(i.next(f))}catch(p){s(p)}}function l(f){try{u(i.throw(f))}catch(p){s(p)}}function u(f){f.done?o(f.value):function r(o){return o instanceof t?o:new t(function(s){s(o)})}(f.value).then(a,l)}u((i=i.apply(e,n||[])).next())})}(this,void 0,void 0,function*(){try{for(t=he(e);!(i=yield t.next()).done;)if(n.next(i.value),n.closed)return}catch(s){r={error:s}}finally{try{i&&!i.done&&(o=t.return)&&(yield o.call(t))}finally{if(r)throw r.error}}n.complete()})})(e,n).catch(t=>n.error(t))})}function wi(e,n,t,i=0,r=!1){const o=n.schedule(function(){t(),r?e.add(this.schedule(null,i)):this.unsubscribe()},i);if(e.add(o),!r)return o}function dt(e,n,t=1/0){return ye(n)?dt((i,r)=>ne((o,s)=>n(i,o,r,s))(ut(e(i,r))),t):("number"==typeof n&&(t=n),qe((i,r)=>function Cn(e,n,t,i,r,o,s,a){const l=[];let u=0,f=0,p=!1;const m=()=>{p&&!l.length&&!u&&n.complete()},v=D=>u{o&&n.next(D),u++;let w=!1;ut(t(D,f++)).subscribe(Oe(n,N=>{r?.(N),o?v(N):n.next(N)},()=>{w=!0},void 0,()=>{if(w)try{for(u--;l.length&&uy(N)):y(N)}m()}catch(N){n.error(N)}}))};return e.subscribe(Oe(n,v,()=>{p=!0,m()})),()=>{a?.()}}(i,r,e,t)))}function Se(e=1/0){return dt(Rn,e)}const Xt=new je(e=>e.complete());function si(e){return e&&ye(e.schedule)}function Ln(e){return e[e.length-1]}function rt(e){return ye(Ln(e))?e.pop():void 0}function en(e){return si(Ln(e))?e.pop():void 0}function Qi(e,n=0){return qe((t,i)=>{t.subscribe(Oe(i,r=>wi(i,e,()=>i.next(r),n),()=>wi(i,e,()=>i.complete(),n),r=>wi(i,e,()=>i.error(r),n)))})}function du(e,n=0){return qe((t,i)=>{i.add(e.schedule(()=>t.subscribe(i),n))})}function fu(e,n){if(!e)throw new Error("Iterable cannot be null");return new je(t=>{wi(t,n,()=>{const i=e[Symbol.asyncIterator]();wi(t,n,()=>{i.next().then(r=>{r.done?t.complete():t.next(r.value)})},0,!0)})})}function gt(e,n){return n?function pu(e,n){if(null!=e){if(Io(e))return function uh(e,n){return ut(e).pipe(du(n),Qi(n))}(e,n);if(Ts(e))return function ft(e,n){return new je(t=>{let i=0;return n.schedule(function(){i===e.length?t.complete():(t.next(e[i++]),t.closed||this.schedule())})})}(e,n);if(Is(e))return function dh(e,n){return ut(e).pipe(du(n),Qi(n))}(e,n);if(Ge(e))return fu(e,n);if(As(e))return function Os(e,n){return new je(t=>{let i;return wi(t,n,()=>{i=e[Ao](),wi(t,n,()=>{let r,o;try{({value:r,done:o}=i.next())}catch(s){return void t.error(s)}o?t.complete():t.next(r)},0,!0)}),()=>ye(i?.return)&&i.return()})}(e,n);if(Dr(e))return function hu(e,n){return fu(ko(e),n)}(e,n)}throw nl(e)}(e,n):ut(e)}function il(e,n,...t){if(!0===n)return void e();if(!1===n)return;const i=new vr({next:()=>{i.unsubscribe(),e()}});return n(...t).subscribe(i)} /** * @license Angular v14.2.9 * (c) 2010-2022 Google LLC. https://angular.io/ @@ -17,14 +17,14 @@ * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */function Ve(e){if("string"==typeof e)return e;if(Array.isArray(e))return"["+e.map(Ve).join(", ")+"]";if(null==e)return""+e;if(e.overriddenName)return`${e.overriddenName}`;if(e.name)return`${e.name}`;const n=e.toString();if(null==n)return""+n;const t=n.indexOf("\n");return-1===t?n:n.substring(0,t)}function Rs(e,n){return null==e||""===e?null===n?"":n:null==n||""===n?e:e+" "+n} + */function Ve(e){if("string"==typeof e)return e;if(Array.isArray(e))return"["+e.map(Ve).join(", ")+"]";if(null==e)return""+e;if(e.overriddenName)return`${e.overriddenName}`;if(e.name)return`${e.name}`;const n=e.toString();if(null==n)return""+n;const t=n.indexOf("\n");return-1===t?n:n.substring(0,t)}function xs(e,n){return null==e||""===e?null===n?"":n:null==n||""===n?e:e+" "+n} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */const ph=$e({__forward_ref__:$e});function Te(e){return e.__forward_ref__=Te,e.toString=function(){return Ve(this())},e}function te(e){return xs(e)?e():e}function xs(e){return"function"==typeof e&&e.hasOwnProperty(ph)&&e.__forward_ref__===Te} + */const ph=$e({__forward_ref__:$e});function Te(e){return e.__forward_ref__=Te,e.toString=function(){return Ve(this())},e}function te(e){return Rs(e)?e():e}function Rs(e){return"function"==typeof e&&e.hasOwnProperty(ph)&&e.__forward_ref__===Te} /** * @license * Copyright Google LLC All Rights Reserved. @@ -39,21 +39,21 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -class P extends Error{constructor(n,t){super(function Ps(e,n){return`NG0${Math.abs(e)}${n?": "+n.trim():""}`} +class F extends Error{constructor(n,t){super(function Fs(e,n){return`NG0${Math.abs(e)}${n?": "+n.trim():""}`} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */(n,t)),this.code=n}}function oe(e){return"string"==typeof e?e:null==e?"":String(e)}function Vn(e,n){throw new P(-201,!1)} + */(n,t)),this.code=n}}function oe(e){return"string"==typeof e?e:null==e?"":String(e)}function Vn(e,n){throw new F(-201,!1)} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */function Sn(e,n){null==e&&function Oe(e,n,t,i){throw new Error(`ASSERTION ERROR: ${e}`+(null==i?"":` [Expected=> ${t} ${i} ${n} <=Actual]`))}(n,e,null,"!=")} + */function Sn(e,n){null==e&&function ke(e,n,t,i){throw new Error(`ASSERTION ERROR: ${e}`+(null==i?"":` [Expected=> ${t} ${i} ${n} <=Actual]`))}(n,e,null,"!=")} /** * @license * Copyright Google LLC All Rights Reserved. @@ -61,7 +61,7 @@ class P extends Error{constructor(n,t){super(function Ps(e,n){return`NG0${Math.a * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -function G(e){return{token:e.token,providedIn:e.providedIn||null,factory:e.factory,value:void 0}}function Me(e){return{providers:e.providers||[],imports:e.imports||[]}}function Vs(e){return mu(e,Jr)||mu(e,sl)}function mu(e,n){return e.hasOwnProperty(n)?e[n]:null}function Hs(e){return e&&(e.hasOwnProperty(ol)||e.hasOwnProperty(_u))?e[ol]:null}const Jr=$e({\u0275prov:$e}),ol=$e({\u0275inj:$e}),sl=$e({ngInjectableDef:$e}),_u=$e({ngInjectorDef:$e}); +function G(e){return{token:e.token,providedIn:e.providedIn||null,factory:e.factory,value:void 0}}function Ne(e){return{providers:e.providers||[],imports:e.imports||[]}}function Vs(e){return mu(e,Zr)||mu(e,sl)}function mu(e,n){return e.hasOwnProperty(n)?e[n]:null}function Bs(e){return e&&(e.hasOwnProperty(ol)||e.hasOwnProperty(_u))?e[ol]:null}const Zr=$e({\u0275prov:$e}),ol=$e({\u0275inj:$e}),sl=$e({ngInjectableDef:$e}),_u=$e({ngInjectorDef:$e}); /** * @license * Copyright Google LLC All Rights Reserved. @@ -75,7 +75,7 @@ function G(e){return{token:e.token,providedIn:e.providedIn||null,factory:e.facto * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */let al;function Hn(e){const n=al;return al=e,n}function ll(e,n,t){const i=Vs(e);return i&&"root"==i.providedIn?void 0===i.value?i.value=i.factory():i.value:t&X.Optional?null:void 0!==n?n:void Vn(Ve(e))} + */let al;function Bn(e){const n=al;return al=e,n}function ll(e,n,t){const i=Vs(e);return i&&"root"==i.providedIn?void 0===i.value?i.value=i.factory():i.value:t&X.Optional?null:void 0!==n?n:void Vn(Ve(e))} /** * @license * Copyright Google LLC All Rights Reserved. @@ -83,7 +83,7 @@ function G(e){return{token:e.token,providedIn:e.providedIn||null,factory:e.facto * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -function Bn(e){return{toString:e}.toString()} +function Hn(e){return{toString:e}.toString()} /** * @license * Copyright Google LLC All Rights Reserved. @@ -98,7 +98,7 @@ function Bn(e){return{toString:e}.toString()} * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -const We=(()=>typeof globalThis<"u"&&globalThis||typeof global<"u"&&global||typeof window<"u"&&window||typeof self<"u"&&typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope&&self)(),Xi={},Ae=[],jn=$e({\u0275cmp:$e}),ul=$e({\u0275dir:$e}),Fo=$e({\u0275pipe:$e}),vu=$e({\u0275mod:$e}),Mi=$e({\u0275fac:$e}),Po=$e({__NG_ELEMENT_ID__:$e}); +const We=(()=>typeof globalThis<"u"&&globalThis||typeof global<"u"&&global||typeof window<"u"&&window||typeof self<"u"&&typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope&&self)(),Xi={},Ie=[],jn=$e({\u0275cmp:$e}),ul=$e({\u0275dir:$e}),Po=$e({\u0275pipe:$e}),vu=$e({\u0275mod:$e}),Ni=$e({\u0275fac:$e}),Fo=$e({__NG_ELEMENT_ID__:$e}); /** * @license * Copyright Google LLC All Rights Reserved. @@ -113,7 +113,7 @@ const We=(()=>typeof globalThis<"u"&&globalThis||typeof global<"u"&&global||type * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -let Bs=0;function et(e){return Bn(()=>{const t=!0===e.standalone,i={},r={type:e.type,providersResolver:null,decls:e.decls,vars:e.vars,factory:null,template:e.template||null,consts:e.consts||null,ngContentSelectors:e.ngContentSelectors,hostBindings:e.hostBindings||null,hostVars:e.hostVars||0,hostAttrs:e.hostAttrs||null,contentQueries:e.contentQueries||null,declaredInputs:i,inputs:null,outputs:null,exportAs:e.exportAs||null,onPush:e.changeDetection===tn.OnPush,directiveDefs:null,pipeDefs:null,standalone:t,dependencies:t&&e.dependencies||null,getStandaloneInjector:null,selectors:e.selectors||Ae,viewQuery:e.viewQuery||null,features:e.features||null,data:e.data||{},encapsulation:e.encapsulation||ai.Emulated,id:"c"+Bs++,styles:e.styles||Ae,_:null,setInput:null,schemas:e.schemas||null,tView:null},o=e.dependencies,s=e.features;return r.inputs=Du(e.inputs,i),r.outputs=Du(e.outputs),s&&s.forEach(a=>a(r)),r.directiveDefs=o?()=>("function"==typeof o?o():o).map(yu).filter(bu):null,r.pipeDefs=o?()=>("function"==typeof o?o():o).map(nn).filter(bu):null,r})}function yu(e){return Re(e)||Ut(e)}function bu(e){return null!==e}function Ne(e){return Bn(()=>({type:e.type,bootstrap:e.bootstrap||Ae,declarations:e.declarations||Ae,imports:e.imports||Ae,exports:e.exports||Ae,transitiveCompileScopes:null,schemas:e.schemas||null,id:e.id||null}))}function Du(e,n){if(null==e)return Xi;const t={};for(const i in e)if(e.hasOwnProperty(i)){let r=e[i],o=r;Array.isArray(r)&&(o=r[1],r=r[0]),t[r]=i,n&&(n[r]=o)}return t}const H=et;function $t(e){return{type:e.type,name:e.name,factory:null,pure:!1!==e.pure,standalone:!0===e.standalone,onDestroy:e.type.prototype.ngOnDestroy||null}}function Re(e){return e[jn]||null}function Ut(e){return e[ul]||null}function nn(e){return e[Fo]||null}function En(e,n){const t=e[vu]||null;if(!t&&!0===n)throw new Error(`Type ${Ve(e)} does not have '\u0275mod' property.`);return t} +let Hs=0;function et(e){return Hn(()=>{const t=!0===e.standalone,i={},r={type:e.type,providersResolver:null,decls:e.decls,vars:e.vars,factory:null,template:e.template||null,consts:e.consts||null,ngContentSelectors:e.ngContentSelectors,hostBindings:e.hostBindings||null,hostVars:e.hostVars||0,hostAttrs:e.hostAttrs||null,contentQueries:e.contentQueries||null,declaredInputs:i,inputs:null,outputs:null,exportAs:e.exportAs||null,onPush:e.changeDetection===tn.OnPush,directiveDefs:null,pipeDefs:null,standalone:t,dependencies:t&&e.dependencies||null,getStandaloneInjector:null,selectors:e.selectors||Ie,viewQuery:e.viewQuery||null,features:e.features||null,data:e.data||{},encapsulation:e.encapsulation||ai.Emulated,id:"c"+Hs++,styles:e.styles||Ie,_:null,setInput:null,schemas:e.schemas||null,tView:null},o=e.dependencies,s=e.features;return r.inputs=Du(e.inputs,i),r.outputs=Du(e.outputs),s&&s.forEach(a=>a(r)),r.directiveDefs=o?()=>("function"==typeof o?o():o).map(yu).filter(bu):null,r.pipeDefs=o?()=>("function"==typeof o?o():o).map(nn).filter(bu):null,r})}function yu(e){return xe(e)||Ut(e)}function bu(e){return null!==e}function Ee(e){return Hn(()=>({type:e.type,bootstrap:e.bootstrap||Ie,declarations:e.declarations||Ie,imports:e.imports||Ie,exports:e.exports||Ie,transitiveCompileScopes:null,schemas:e.schemas||null,id:e.id||null}))}function Du(e,n){if(null==e)return Xi;const t={};for(const i in e)if(e.hasOwnProperty(i)){let r=e[i],o=r;Array.isArray(r)&&(o=r[1],r=r[0]),t[r]=i,n&&(n[r]=o)}return t}const B=et;function $t(e){return{type:e.type,name:e.name,factory:null,pure:!1!==e.pure,standalone:!0===e.standalone,onDestroy:e.type.prototype.ngOnDestroy||null}}function xe(e){return e[jn]||null}function Ut(e){return e[ul]||null}function nn(e){return e[Po]||null}function Mn(e,n){const t=e[vu]||null;if(!t&&!0===n)throw new Error(`Type ${Ve(e)} does not have '\u0275mod' property.`);return t} /** * @license * Copyright Google LLC All Rights Reserved. @@ -128,7 +128,7 @@ let Bs=0;function et(e){return Bn(()=>{const t=!0===e.standalone,i={},r={type:e. * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -function hn(e){return Array.isArray(e)&&"object"==typeof e[1]}function qn(e){return Array.isArray(e)&&!0===e[1]}function pl(e){return 0!=(8&e.flags)}function $s(e){return 2==(2&e.flags)}function Us(e){return 1==(1&e.flags)}function Jn(e){return null!==e.template}function Ah(e){return 0!=(256&e[2])} +function hn(e){return Array.isArray(e)&&"object"==typeof e[1]}function qn(e){return Array.isArray(e)&&!0===e[1]}function pl(e){return 0!=(8&e.flags)}function $s(e){return 2==(2&e.flags)}function Us(e){return 1==(1&e.flags)}function Zn(e){return null!==e.template}function Ih(e){return 0!=(256&e[2])} /** * @license * Copyright Google LLC All Rights Reserved. @@ -143,28 +143,28 @@ function hn(e){return Array.isArray(e)&&"object"==typeof e[1]}function qn(e){ret * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -function Nr(e,n){return e.hasOwnProperty(Mi)?e[Mi]:null} +function Er(e,n){return e.hasOwnProperty(Ni)?e[Ni]:null} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */class Fh{constructor(n,t,i){this.previousValue=n,this.currentValue=t,this.firstChange=i}isFirstChange(){return this.firstChange}} + */class Ph{constructor(n,t,i){this.previousValue=n,this.currentValue=t,this.firstChange=i}isFirstChange(){return this.firstChange}} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */function Kt(){return Su}function Su(e){return e.type.prototype.ngOnChanges&&(e.setInput=Gs),Ph}function Ph(){const e=Mu(this),n=e?.current;if(n){const t=e.previous;if(t===Xi)e.previous=n;else for(let i in n)t[i]=n[i];e.current=null,this.ngOnChanges(n)}}function Gs(e,n,t,i){const r=Mu(e)||function Lh(e,n){return e[Eu]=n} + */function zt(){return Su}function Su(e){return e.type.prototype.ngOnChanges&&(e.setInput=Gs),Fh}function Fh(){const e=Nu(this),n=e?.current;if(n){const t=e.previous;if(t===Xi)e.previous=n;else for(let i in n)t[i]=n[i];e.current=null,this.ngOnChanges(n)}}function Gs(e,n,t,i){const r=Nu(e)||function Lh(e,n){return e[Mu]=n} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */(e,{previous:Xi,current:null}),o=r.current||(r.current={}),s=r.previous,a=this.declaredInputs[t],l=s[a];o[a]=new Fh(l&&l.currentValue,n,s===Xi),e[i]=n}Kt.ngInherit=!0;const Eu="__ngSimpleChanges__";function Mu(e){return e[Eu]||null} + */(e,{previous:Xi,current:null}),o=r.current||(r.current={}),s=r.previous,a=this.declaredInputs[t],l=s[a];o[a]=new Ph(l&&l.currentValue,n,s===Xi),e[i]=n}zt.ngInherit=!0;const Mu="__ngSimpleChanges__";function Nu(e){return e[Mu]||null} /** * @license * Copyright Google LLC All Rights Reserved. @@ -172,21 +172,21 @@ function Nr(e,n){return e.hasOwnProperty(Mi)?e[Mi]:null} * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -function tt(e){for(;Array.isArray(e);)e=e[0];return e}function Ho(e,n){return tt(n[e])}function xt(e,n){return tt(n[e.index])}function Ks(e,n){return e.data[n]}function io(e,n){return e[n]}function Nn(e,n){const t=n[e];return hn(t)?t:t[0]}function zs(e){return 64==(64&e[2])}function tr(e,n){return null==n?null:e[n]}function Au(e){e[18]=0}function yl(e,n){e[5]+=n;let t=e,i=e[3];for(;null!==i&&(1===n&&1===t[5]||-1===n&&0===t[5]);)i[5]+=n,t=i,i=i[3] +function tt(e){for(;Array.isArray(e);)e=e[0];return e}function Bo(e,n){return tt(n[e])}function Rt(e,n){return tt(n[e.index])}function zs(e,n){return e.data[n]}function io(e,n){return e[n]}function En(e,n){const t=n[e];return hn(t)?t:t[0]}function Ys(e){return 64==(64&e[2])}function tr(e,n){return null==n?null:e[n]}function Iu(e){e[18]=0}function yl(e,n){e[5]+=n;let t=e,i=e[3];for(;null!==i&&(1===n&&1===t[5]||-1===n&&0===t[5]);)i[5]+=n,t=i,i=i[3] /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */}const re={lFrame:Pu(null),bindingsEnabled:!0};function Ou(){return re.bindingsEnabled}function k(){return re.lFrame.lView}function be(){return re.lFrame.tView}function mt(e){return re.lFrame.contextLView=e,e[8]}function _t(e){return re.lFrame.contextLView=null,e}function wt(){let e=Ys();for(;null!==e&&64===e.type;)e=e.parent;return e}function Ys(){return re.lFrame.currentTNode}function ci(e,n){const t=re.lFrame;t.currentTNode=e,t.isParent=n}function bl(){return re.lFrame.isParent}function jo(){re.lFrame.isParent=!1}function rn(){const e=re.lFrame;let n=e.bindingRootIndex;return-1===n&&(n=e.bindingRootIndex=e.tView.bindingStartIndex),n}function Tr(){return re.lFrame.bindingIndex++}function Ii(e){const n=re.lFrame,t=n.bindingIndex;return n.bindingIndex=n.bindingIndex+e,t}function Jh(e,n){const t=re.lFrame;t.bindingIndex=t.bindingRootIndex=e,wl(n)}function wl(e){re.lFrame.currentDirectiveIndex=e}function Sl(){return re.lFrame.currentQueryIndex}function El(e){re.lFrame.currentQueryIndex=e}function Qh(e){const n=e[1];return 2===n.type?n.declTNode:1===n.type?e[6]:null}function xu(e,n,t){if(t&X.SkipSelf){let r=n,o=e;for(;!(r=r.parent,null!==r||t&X.Host||(r=Qh(o),null===r||(o=o[15],10&r.type))););if(null===r)return!1;n=r,e=o}const i=re.lFrame=Fu();return i.currentTNode=n,i.lView=e,!0}function x(e){const n=Fu(),t=e[1];re.lFrame=n,n.currentTNode=t.firstChild,n.lView=e,n.tView=t,n.contextLView=e,n.bindingIndex=t.bindingStartIndex,n.inI18n=!1}function Fu(){const e=re.lFrame,n=null===e?null:e.child;return null===n?Pu(e):n}function Pu(e){const n={currentTNode:null,isParent:!0,lView:null,tView:null,selectedIndex:-1,contextLView:null,elementDepthCount:0,currentNamespace:null,currentDirectiveIndex:-1,bindingRootIndex:-1,bindingIndex:-1,currentQueryIndex:0,parent:e,child:null,inI18n:!1};return null!==e&&(e.child=n),n}function Ml(){const e=re.lFrame;return re.lFrame=e.parent,e.currentTNode=null,e.lView=null,e}const Ee=Ml;function ro(){const e=Ml();e.isParent=!0,e.tView=null,e.selectedIndex=-1,e.contextLView=null,e.elementDepthCount=0,e.currentDirectiveIndex=-1,e.currentNamespace=null,e.bindingRootIndex=-1,e.bindingIndex=-1,e.currentQueryIndex=0}function on(){return re.lFrame.selectedIndex}function nr(e){re.lFrame.selectedIndex=e}function st(){const e=re.lFrame;return Ks(e.tView,e.selectedIndex)}function qs(e,n){for(let t=n.directiveStart,i=n.directiveEnd;t=i)break}else n[l]<0&&(e[18]+=65536),(a>11>16&&(3&e[2])===n){e[2]+=2048;try{o.call(a)}finally{}}}else try{o.call(a)}finally{}} + */}const re={lFrame:Fu(null),bindingsEnabled:!0};function ku(){return re.bindingsEnabled}function O(){return re.lFrame.lView}function be(){return re.lFrame.tView}function mt(e){return re.lFrame.contextLView=e,e[8]}function _t(e){return re.lFrame.contextLView=null,e}function wt(){let e=Ks();for(;null!==e&&64===e.type;)e=e.parent;return e}function Ks(){return re.lFrame.currentTNode}function ci(e,n){const t=re.lFrame;t.currentTNode=e,t.isParent=n}function bl(){return re.lFrame.isParent}function jo(){re.lFrame.isParent=!1}function rn(){const e=re.lFrame;let n=e.bindingRootIndex;return-1===n&&(n=e.bindingRootIndex=e.tView.bindingStartIndex),n}function Tr(){return re.lFrame.bindingIndex++}function Ai(e){const n=re.lFrame,t=n.bindingIndex;return n.bindingIndex=n.bindingIndex+e,t}function Zh(e,n){const t=re.lFrame;t.bindingIndex=t.bindingRootIndex=e,wl(n)}function wl(e){re.lFrame.currentDirectiveIndex=e}function Sl(){return re.lFrame.currentQueryIndex}function Ml(e){re.lFrame.currentQueryIndex=e}function Qh(e){const n=e[1];return 2===n.type?n.declTNode:1===n.type?e[6]:null}function Ru(e,n,t){if(t&X.SkipSelf){let r=n,o=e;for(;!(r=r.parent,null!==r||t&X.Host||(r=Qh(o),null===r||(o=o[15],10&r.type))););if(null===r)return!1;n=r,e=o}const i=re.lFrame=Pu();return i.currentTNode=n,i.lView=e,!0}function R(e){const n=Pu(),t=e[1];re.lFrame=n,n.currentTNode=t.firstChild,n.lView=e,n.tView=t,n.contextLView=e,n.bindingIndex=t.bindingStartIndex,n.inI18n=!1}function Pu(){const e=re.lFrame,n=null===e?null:e.child;return null===n?Fu(e):n}function Fu(e){const n={currentTNode:null,isParent:!0,lView:null,tView:null,selectedIndex:-1,contextLView:null,elementDepthCount:0,currentNamespace:null,currentDirectiveIndex:-1,bindingRootIndex:-1,bindingIndex:-1,currentQueryIndex:0,parent:e,child:null,inI18n:!1};return null!==e&&(e.child=n),n}function Nl(){const e=re.lFrame;return re.lFrame=e.parent,e.currentTNode=null,e.lView=null,e}const Me=Nl;function ro(){const e=Nl();e.isParent=!0,e.tView=null,e.selectedIndex=-1,e.contextLView=null,e.elementDepthCount=0,e.currentDirectiveIndex=-1,e.currentNamespace=null,e.bindingRootIndex=-1,e.bindingIndex=-1,e.currentQueryIndex=0}function on(){return re.lFrame.selectedIndex}function nr(e){re.lFrame.selectedIndex=e}function st(){const e=re.lFrame;return zs(e.tView,e.selectedIndex)}function qs(e,n){for(let t=n.directiveStart,i=n.directiveEnd;t=i)break}else n[l]<0&&(e[18]+=65536),(a>11>16&&(3&e[2])===n){e[2]+=2048;try{o.call(a)}finally{}}}else try{o.call(a)}finally{}} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */class Tn{constructor(n,t,i){this.factory=n,this.resolving=!1,this.canSeeViewProviders=t,this.injectImpl=i}}function Xs(e,n,t){let i=0;for(;in){s=o-1;break}}}for(;on){s=o-1;break}}}for(;o>5)]|=1<=0?255&n:Ri:n}(t);if("function"==typeof o){if(!xu(n,e,i))return i&X.Host?c(r,0,i):d(n,t,i,r);try{const s=o(i);if(null!=s||i&X.Optional)return s;Vn()}finally{Ee()}}else if("number"==typeof o){let s=null,a=Wo(e,n),l=-1,u=i&X.Host?n[16][6]:null;for((-1===a||i&X.SkipSelf)&&(l=-1===a?ki(e,n):n[a+8],-1!==l&&Pe(i,!1)?(s=n[1],a=oo(l),n=so(l,n)):a=-1);-1!==a;){const f=n[1];if(ce(o,a,f.data)){const p=_(a,n,t,s,i,u);if(p!==hi)return p}l=n[a+8],-1!==l&&Pe(i,n[1].data[a+8]===u)&&ce(o,a,n)?(s=f,a=oo(l),n=so(l,n)):a=-1}}return r}function _(e,n,t,i,r,o){const s=n[1],a=s.data[e+8],f=b(a,s,t,null==i?$s(a)&&Al:i!=s&&0!=(3&a.type),r&X.Host&&o===a);return null!==f?N(n,s,f,a):hi}function b(e,n,t,i,r){const o=e.providerIndexes,s=n.data,a=1048575&o,l=e.directiveStart,f=o>>20,m=r?a+f:e.directiveEnd;for(let v=i?a:a+f;v=l&&y.type===t)return v}if(r){const v=s[l];if(v&&Jn(v)&&v.type===t)return l}return null}function N(e,n,t,i){let r=e[t];const o=n.data;if(function rp(e){return e instanceof Tn}(r)){const s=r;s.resolving&& + */let Il=!0;function ea(e){const n=Il;return Il=e,n}let cp=0;const hi={};function Go(e,n){const t=Wo(e,n);if(-1!==t)return t;const i=n[1];i.firstCreatePass&&(e.injectorIndex=n.length,Al(i.data,e),Al(n,null),Al(i.blueprint,null));const r=Oi(e,n),o=e.injectorIndex;if($u(r)){const s=oo(r),a=so(r,n),l=a[1].data;for(let u=0;u<8;u++)n[o+u]=a[s+u]|l[s+u]}return n[o+8]=r,o}function Al(e,n){e.push(0,0,0,0,0,0,0,0,n)}function Wo(e,n){return-1===e.injectorIndex||e.parent&&e.parent.injectorIndex===e.injectorIndex||null===n[e.injectorIndex+8]?-1:e.injectorIndex}function Oi(e,n){if(e.parent&&-1!==e.parent.injectorIndex)return e.parent.injectorIndex;let t=0,i=null,r=n;for(;null!==r;){if(i=dy(r),null===i)return-1;if(t++,r=r[15],-1!==i.injectorIndex)return i.injectorIndex|t<<16}return-1}function Ar(e,n,t){!function up(e,n,t){let i;"string"==typeof t?i=t.charCodeAt(0)||0:t.hasOwnProperty(Fo)&&(i=t[Fo]),null==i&&(i=t[Fo]=cp++);const r=255&i;n.data[e+(r>>5)]|=1<=0?255&n:xi:n}(t);if("function"==typeof o){if(!Ru(n,e,i))return i&X.Host?c(r,0,i):d(n,t,i,r);try{const s=o(i);if(null!=s||i&X.Optional)return s;Vn()}finally{Me()}}else if("number"==typeof o){let s=null,a=Wo(e,n),l=-1,u=i&X.Host?n[16][6]:null;for((-1===a||i&X.SkipSelf)&&(l=-1===a?Oi(e,n):n[a+8],-1!==l&&Fe(i,!1)?(s=n[1],a=oo(l),n=so(l,n)):a=-1);-1!==a;){const f=n[1];if(ce(o,a,f.data)){const p=_(a,n,t,s,i,u);if(p!==hi)return p}l=n[a+8],-1!==l&&Fe(i,n[1].data[a+8]===u)&&ce(o,a,n)?(s=f,a=oo(l),n=so(l,n)):a=-1}}return r}function _(e,n,t,i,r,o){const s=n[1],a=s.data[e+8],f=b(a,s,t,null==i?$s(a)&&Il:i!=s&&0!=(3&a.type),r&X.Host&&o===a);return null!==f?E(n,s,f,a):hi}function b(e,n,t,i,r){const o=e.providerIndexes,s=n.data,a=1048575&o,l=e.directiveStart,f=o>>20,m=r?a+f:e.directiveEnd;for(let v=i?a:a+f;v=l&&y.type===t)return v}if(r){const v=s[l];if(v&&Zn(v)&&v.type===t)return l}return null}function E(e,n,t,i){let r=e[t];const o=n.data;if(function rp(e){return e instanceof Tn}(r)){const s=r;s.resolving&& /** * @license * Copyright Google LLC All Rights Reserved. @@ -208,7 +208,7 @@ function tt(e){for(;Array.isArray(e);)e=e[0];return e}function Ho(e,n){return tt * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -function Ls(e,n){const t=n?`. Dependency path: ${n.join(" > ")} > ${e}`:"";throw new P(-200,`Circular dependency in DI detected for ${e}${t}`)}(function _e(e){return"function"==typeof e?e.name||e.toString():"object"==typeof e&&null!=e&&"function"==typeof e.type?e.type.name||e.type.toString():oe(e)}(o[t]));const a=ea(s.canSeeViewProviders);s.resolving=!0;const l=s.injectImpl?Hn(s.injectImpl):null;xu(e,i,X.Default);try{r=e[t]=s.factory(void 0,o,e,i),n.firstCreatePass&&t>=i.directiveStart&& +function Ls(e,n){const t=n?`. Dependency path: ${n.join(" > ")} > ${e}`:"";throw new F(-200,`Circular dependency in DI detected for ${e}${t}`)}(function _e(e){return"function"==typeof e?e.name||e.toString():"object"==typeof e&&null!=e&&"function"==typeof e.type?e.type.name||e.type.toString():oe(e)}(o[t]));const a=ea(s.canSeeViewProviders);s.resolving=!0;const l=s.injectImpl?Bn(s.injectImpl):null;Ru(e,i,X.Default);try{r=e[t]=s.factory(void 0,o,e,i),n.firstCreatePass&&t>=i.directiveStart&& /** * @license * Copyright Google LLC All Rights Reserved. @@ -216,7 +216,7 @@ function Ls(e,n){const t=n?`. Dependency path: ${n.join(" > ")} > ${e}`:"";throw * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -function np(e,n,t){const{ngOnChanges:i,ngOnInit:r,ngDoCheck:o}=n.type.prototype;if(i){const s=Su(n);(t.preOrderHooks||(t.preOrderHooks=[])).push(e,s),(t.preOrderCheckHooks||(t.preOrderCheckHooks=[])).push(e,s)}r&&(t.preOrderHooks||(t.preOrderHooks=[])).push(0-e,r),o&&((t.preOrderHooks||(t.preOrderHooks=[])).push(e,o),(t.preOrderCheckHooks||(t.preOrderCheckHooks=[])).push(e,o))}(t,o[t],n)}finally{null!==l&&Hn(l),ea(a),s.resolving=!1,Ee()}}return r}function ce(e,n,t){return!!(t[n+(e>>5)]&1<{const n=e.prototype.constructor,t=n[Mi]||dp(n),i=Object.prototype;let r=Object.getPrototypeOf(e.prototype).constructor;for(;r&&r!==i;){const o=r[Mi]||dp(r);if(o&&o!==t)return o;r=Object.getPrototypeOf(r)}return o=>new o})}function dp(e){return xs(e)?()=>{const n=dp(te(e));return n&&n()}:Nr(e)}function dy(e){const n=e[1],t=n.type;return 2===t?n.declTNode:1===t?e[6]:null} +function np(e,n,t){const{ngOnChanges:i,ngOnInit:r,ngDoCheck:o}=n.type.prototype;if(i){const s=Su(n);(t.preOrderHooks||(t.preOrderHooks=[])).push(e,s),(t.preOrderCheckHooks||(t.preOrderCheckHooks=[])).push(e,s)}r&&(t.preOrderHooks||(t.preOrderHooks=[])).push(0-e,r),o&&((t.preOrderHooks||(t.preOrderHooks=[])).push(e,o),(t.preOrderCheckHooks||(t.preOrderCheckHooks=[])).push(e,o))}(t,o[t],n)}finally{null!==l&&Bn(l),ea(a),s.resolving=!1,Me()}}return r}function ce(e,n,t){return!!(t[n+(e>>5)]&1<{const n=e.prototype.constructor,t=n[Ni]||dp(n),i=Object.prototype;let r=Object.getPrototypeOf(e.prototype).constructor;for(;r&&r!==i;){const o=r[Ni]||dp(r);if(o&&o!==t)return o;r=Object.getPrototypeOf(r)}return o=>new o})}function dp(e){return Rs(e)?()=>{const n=dp(te(e));return n&&n()}:Er(e)}function dy(e){const n=e[1],t=n.type;return 2===t?n.declTNode:1===t?e[6]:null} /** * @license * Copyright Google LLC All Rights Reserved. @@ -231,7 +231,7 @@ function np(e,n,t){const{ngOnChanges:i,ngOnInit:r,ngDoCheck:o}=n.type.prototype; * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -const na="__parameters__";function ra(e,n,t){return Bn(()=>{const i=function fp(e){return function(...t){if(e){const i=e(...t);for(const r in i)this[r]=i[r]}}}(n);function r(...o){if(this instanceof r)return i.apply(this,o),this;const s=new r(...o);return a.annotation=s,a;function a(l,u,f){const p=l.hasOwnProperty(na)?l[na]:Object.defineProperty(l,na,{value:[]})[na];for(;p.length<=f;)p.push(null);return(p[f]=p[f]||[]).push(s),l}}return t&&(r.prototype=Object.create(t.prototype)),r.prototype.ngMetadataName=e,r.annotationCls=r,r})} +const na="__parameters__";function ra(e,n,t){return Hn(()=>{const i=function fp(e){return function(...t){if(e){const i=e(...t);for(const r in i)this[r]=i[r]}}}(n);function r(...o){if(this instanceof r)return i.apply(this,o),this;const s=new r(...o);return a.annotation=s,a;function a(l,u,f){const p=l.hasOwnProperty(na)?l[na]:Object.defineProperty(l,na,{value:[]})[na];for(;p.length<=f;)p.push(null);return(p[f]=p[f]||[]).push(s),l}}return t&&(r.prototype=Object.create(t.prototype)),r.prototype.ngMetadataName=e,r.annotationCls=r,r})} /** * @license * Copyright Google LLC All Rights Reserved. @@ -246,7 +246,7 @@ class q{constructor(n,t){this._desc=n,this.ngMetadataName="InjectionToken",this. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */function Zn(e,n){void 0===n&&(n=e);for(let t=0;tArray.isArray(t)?Or(t,n):n(t))}function hy(e,n,t){n>=e.length?e.push(t):e.splice(n,0,t)}function Uu(e,n){return n>=e.length-1?e.pop():e.splice(n,1)[0]}function Rl(e,n){const t=[];for(let i=0;i=0?e[1|i]=t:(i=~i,function CN(e,n,t,i){let r=e.length;if(r==n)e.push(t,i);else if(1===r)e.push(i,e[0]),e[0]=t;else{for(r--,e.push(e[r-1],e[r]);r>n;)e[r]=e[r-2],r--;e[n]=t,e[n+1]=i}}(e,i,n,t)),i}function pp(e,n){const t=oa(e,n);if(t>=0)return e[1|t]}function oa(e,n){return function my(e,n,t){let i=0,r=e.length>>t;for(;r!==i;){const o=i+(r-i>>1),s=e[o<n?r=o:i=o+1}return~(r<Array.isArray(t)?kr(t,n):n(t))}function hy(e,n,t){n>=e.length?e.push(t):e.splice(n,0,t)}function Uu(e,n){return n>=e.length-1?e.pop():e.splice(n,1)[0]}function xl(e,n){const t=[];for(let i=0;i=0?e[1|i]=t:(i=~i,function CE(e,n,t,i){let r=e.length;if(r==n)e.push(t,i);else if(1===r)e.push(i,e[0]),e[0]=t;else{for(r--,e.push(e[r-1],e[r]);r>n;)e[r]=e[r-2],r--;e[n]=t,e[n+1]=i}}(e,i,n,t)),i}function pp(e,n){const t=oa(e,n);if(t>=0)return e[1|t]}function oa(e,n){return function my(e,n,t){let i=0,r=e.length>>t;for(;r!==i;){const o=i+(r-i>>1),s=e[o<n?r=o:i=o+1}return~(r<{const s=o;Tp(s,t,[],i)&&(r||(r=[]),r.push(s))}),void 0!==r&&$y(r,t),t}function $y(e,n){for(let t=0;t{n.push(o)})}}function Tp(e,n,t,i){if(!(e=te(e)))return!1;let r=null,o=Hs(e);const s=!o&&Re(e);if(o||s){if(s&&!s.standalone)return!1;r=e}else{const l=e.ngModule;if(o=Hs(l),!o)return!1;r=l}const a=i.has(r);if(s){if(a)return!1;if(i.add(r),s.dependencies){const l="function"==typeof s.dependencies?s.dependencies():s.dependencies;for(const u of l)Tp(u,n,t,i)}}else{if(!o)return!1;{if(null!=o.imports&&!a){let u;i.add(r);try{Or(o.imports,f=>{Tp(f,n,t,i)&&(u||(u=[]),u.push(f))})}finally{}void 0!==u&&$y(u,n)}if(!a){const u=Nr(r)||(()=>new r);n.push({provide:r,useFactory:u,deps:Ae},{provide:Hy,useValue:r,multi:!0},{provide:Np,useValue:()=>L(r),multi:!0})}const l=o.providers;null==l||a||Or(l,f=>{n.push(f)})}}return r!==e&&void 0!==e.providers}const vT=$e({provide:String,useValue:$e});function Ap(e){return null!==e&&"object"==typeof e&&vT in e}function zo(e){return"function"==typeof e} + */function _T(...e){return{\u0275providers:jy(0,e)}}function jy(e,...n){const t=[],i=new Set;let r;return kr(n,o=>{const s=o;Tp(s,t,[],i)&&(r||(r=[]),r.push(s))}),void 0!==r&&$y(r,t),t}function $y(e,n){for(let t=0;t{n.push(o)})}}function Tp(e,n,t,i){if(!(e=te(e)))return!1;let r=null,o=Bs(e);const s=!o&&xe(e);if(o||s){if(s&&!s.standalone)return!1;r=e}else{const l=e.ngModule;if(o=Bs(l),!o)return!1;r=l}const a=i.has(r);if(s){if(a)return!1;if(i.add(r),s.dependencies){const l="function"==typeof s.dependencies?s.dependencies():s.dependencies;for(const u of l)Tp(u,n,t,i)}}else{if(!o)return!1;{if(null!=o.imports&&!a){let u;i.add(r);try{kr(o.imports,f=>{Tp(f,n,t,i)&&(u||(u=[]),u.push(f))})}finally{}void 0!==u&&$y(u,n)}if(!a){const u=Er(r)||(()=>new r);n.push({provide:r,useFactory:u,deps:Ie},{provide:By,useValue:r,multi:!0},{provide:Ep,useValue:()=>L(r),multi:!0})}const l=o.providers;null==l||a||kr(l,f=>{n.push(f)})}}return r!==e&&void 0!==e.providers}const vT=$e({provide:String,useValue:$e});function Ip(e){return null!==e&&"object"==typeof e&&vT in e}function Yo(e){return"function"==typeof e} /** * @license * Copyright Google LLC All Rights Reserved. @@ -329,28 +329,28 @@ class By{get(n,t=xl){if(t===xl){const i=new Error(`NullInjectorError: No provide * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -const Ip=new q("Set Injector scope."),Zu={},bT={}; +const Ap=new q("Set Injector scope."),Ju={},bT={}; /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */let Op;function Qu(){return void 0===Op&&(Op=new By),Op}class lo{}class Wy extends lo{constructor(n,t,i,r){super(),this.parent=t,this.source=i,this.scopes=r,this.records=new Map,this._ngOnDestroyHooks=new Set,this._onDestroyHooks=[],this._destroyed=!1,Rp(n,s=>this.processProvider(s)),this.records.set(Vy,ca(void 0,this)),r.has("environment")&&this.records.set(lo,ca(void 0,this));const o=this.records.get(Ip);null!=o&&"string"==typeof o.value&&this.scopes.add(o.value),this.injectorDefTypes=new Set(this.get(Hy.multi,Ae,X.Self))}get destroyed(){return this._destroyed}destroy(){this.assertNotDestroyed(),this._destroyed=!0;try{for(const n of this._ngOnDestroyHooks)n.ngOnDestroy();for(const n of this._onDestroyHooks)n()}finally{this.records.clear(),this._ngOnDestroyHooks.clear(),this.injectorDefTypes.clear(),this._onDestroyHooks.length=0}}onDestroy(n){this._onDestroyHooks.push(n)}runInContext(n){this.assertNotDestroyed();const t=sa(this),i=Hn(void 0);try{return n()}finally{sa(t),Hn(i)}}get(n,t=xl,i=X.Default){this.assertNotDestroyed();const r=sa(this),o=Hn(void 0);try{if(!(i&X.SkipSelf)){let a=this.records.get(n);if(void 0===a){const l=function ET(e){return"function"==typeof e||"object"==typeof e&&e instanceof q}(n)&&Vs(n);a=l&&this.injectableDefInScope(l)?ca(kp(n),Zu):null,this.records.set(n,a)}if(null!=a)return this.hydrate(n,a)}return(i&X.Self?Qu():this.parent).get(n,t=i&X.Optional&&t===xl?null:t)}catch(s){if("NullInjectorError"===s.name){if((s[Wu]=s[Wu]||[]).unshift(Ve(n)),r)throw s;return function xN(e,n,t,i){const r=e[Wu];throw n[_y]&&r.unshift(n[_y]),e.message=function FN(e,n,t,i=null){e=e&&"\n"===e.charAt(0)&&"\u0275"==e.charAt(1)?e.slice(2):e;let r=Ve(n);if(Array.isArray(n))r=n.map(Ve).join(" -> ");else if("object"==typeof n){let o=[];for(let s in n)if(n.hasOwnProperty(s)){let a=n[s];o.push(s+":"+("string"==typeof a?JSON.stringify(a):Ve(a)))}r=`{${o.join(", ")}}`}return`${t}${i?"("+i+")":""}[${r}]: ${e.replace(IN,"\n ")}`}("\n"+e.message,r,t,i),e.ngTokenPath=r,e[Wu]=null,e}(s,n,"R3InjectorError",this.source)}throw s}finally{Hn(o),sa(r)}}resolveInjectorInitializers(){const n=sa(this),t=Hn(void 0);try{const i=this.get(Np.multi,Ae,X.Self);for(const r of i)r()}finally{sa(n),Hn(t)}}toString(){const n=[],t=this.records;for(const i of t.keys())n.push(Ve(i));return`R3Injector[${n.join(", ")}]`}assertNotDestroyed(){if(this._destroyed)throw new P(205,!1)}processProvider(n){let t=zo(n=te(n))?n:te(n&&n.provide);const i=function CT(e){return Ap(e)?ca(void 0,e.useValue):ca(Ky(e),Zu)}(n);if(zo(n)||!0!==n.multi)this.records.get(t);else{let r=this.records.get(t);r||(r=ca(void 0,Zu,!0),r.factory=()=>_p(r.multi),this.records.set(t,r)),t=n,r.multi.push(n)}this.records.set(t,i)}hydrate(n,t){return t.value===Zu&&(t.value=bT,t.value=t.factory()),"object"==typeof t.value&&t.value&&function ST(e){return null!==e&&"object"==typeof e&&"function"==typeof e.ngOnDestroy}(t.value)&&this._ngOnDestroyHooks.add(t.value),t.value}injectableDefInScope(n){if(!n.providedIn)return!1;const t=te(n.providedIn);return"string"==typeof t?"any"===t||this.scopes.has(t):this.injectorDefTypes.has(t)}}function kp(e){const n=Vs(e),t=null!==n?n.factory:Nr(e);if(null!==t)return t;if(e instanceof q)throw new P(204,!1);if(e instanceof Function)return function DT(e){const n=e.length;if(n>0)throw Rl(n,"?"),new P(204,!1);const t=function Dh(e){const n=e&&(e[Jr]||e[sl]);if(n){const t=function Ch(e){if(e.hasOwnProperty("name"))return e.name;const n=(""+e).match(/^function\s*([^\s(]+)/);return null===n?"":n[1]}(e);return console.warn(`DEPRECATED: DI is instantiating a token "${t}" that inherits its @Injectable decorator but does not provide one itself.\nThis will become an error in a future version of Angular. Please add @Injectable() to the "${t}" class.`),n}return null}(e);return null!==t?()=>t.factory(e):()=>new e}(e);throw new P(204,!1)}function Ky(e,n,t){let i;if(zo(e)){const r=te(e);return Nr(r)||kp(r)}if(Ap(e))i=()=>te(e.useValue);else if(function Gy(e){return!(!e||!e.useFactory)}(e))i=()=>e.useFactory(..._p(e.deps||[]));else if(function Uy(e){return!(!e||!e.useExisting)}(e))i=()=>L(te(e.useExisting));else{const r=te(e&&(e.useClass||e.provide));if(!function wT(e){return!!e.deps}(e))return Nr(r)||kp(r);i=()=>new r(..._p(e.deps))}return i}function ca(e,n,t=!1){return{factory:e,value:n,multi:t?[]:void 0}}function MT(e){return!!e.\u0275providers}function Rp(e,n){for(const t of e)Array.isArray(t)?Rp(t,n):MT(t)?Rp(t.\u0275providers,n):n(t)} + */let kp;function Qu(){return void 0===kp&&(kp=new Hy),kp}class lo{}class Wy extends lo{constructor(n,t,i,r){super(),this.parent=t,this.source=i,this.scopes=r,this.records=new Map,this._ngOnDestroyHooks=new Set,this._onDestroyHooks=[],this._destroyed=!1,xp(n,s=>this.processProvider(s)),this.records.set(Vy,ca(void 0,this)),r.has("environment")&&this.records.set(lo,ca(void 0,this));const o=this.records.get(Ap);null!=o&&"string"==typeof o.value&&this.scopes.add(o.value),this.injectorDefTypes=new Set(this.get(By.multi,Ie,X.Self))}get destroyed(){return this._destroyed}destroy(){this.assertNotDestroyed(),this._destroyed=!0;try{for(const n of this._ngOnDestroyHooks)n.ngOnDestroy();for(const n of this._onDestroyHooks)n()}finally{this.records.clear(),this._ngOnDestroyHooks.clear(),this.injectorDefTypes.clear(),this._onDestroyHooks.length=0}}onDestroy(n){this._onDestroyHooks.push(n)}runInContext(n){this.assertNotDestroyed();const t=sa(this),i=Bn(void 0);try{return n()}finally{sa(t),Bn(i)}}get(n,t=Rl,i=X.Default){this.assertNotDestroyed();const r=sa(this),o=Bn(void 0);try{if(!(i&X.SkipSelf)){let a=this.records.get(n);if(void 0===a){const l=function MT(e){return"function"==typeof e||"object"==typeof e&&e instanceof q}(n)&&Vs(n);a=l&&this.injectableDefInScope(l)?ca(Op(n),Ju):null,this.records.set(n,a)}if(null!=a)return this.hydrate(n,a)}return(i&X.Self?Qu():this.parent).get(n,t=i&X.Optional&&t===Rl?null:t)}catch(s){if("NullInjectorError"===s.name){if((s[Wu]=s[Wu]||[]).unshift(Ve(n)),r)throw s;return function RE(e,n,t,i){const r=e[Wu];throw n[_y]&&r.unshift(n[_y]),e.message=function PE(e,n,t,i=null){e=e&&"\n"===e.charAt(0)&&"\u0275"==e.charAt(1)?e.slice(2):e;let r=Ve(n);if(Array.isArray(n))r=n.map(Ve).join(" -> ");else if("object"==typeof n){let o=[];for(let s in n)if(n.hasOwnProperty(s)){let a=n[s];o.push(s+":"+("string"==typeof a?JSON.stringify(a):Ve(a)))}r=`{${o.join(", ")}}`}return`${t}${i?"("+i+")":""}[${r}]: ${e.replace(AE,"\n ")}`}("\n"+e.message,r,t,i),e.ngTokenPath=r,e[Wu]=null,e}(s,n,"R3InjectorError",this.source)}throw s}finally{Bn(o),sa(r)}}resolveInjectorInitializers(){const n=sa(this),t=Bn(void 0);try{const i=this.get(Ep.multi,Ie,X.Self);for(const r of i)r()}finally{sa(n),Bn(t)}}toString(){const n=[],t=this.records;for(const i of t.keys())n.push(Ve(i));return`R3Injector[${n.join(", ")}]`}assertNotDestroyed(){if(this._destroyed)throw new F(205,!1)}processProvider(n){let t=Yo(n=te(n))?n:te(n&&n.provide);const i=function CT(e){return Ip(e)?ca(void 0,e.useValue):ca(zy(e),Ju)}(n);if(Yo(n)||!0!==n.multi)this.records.get(t);else{let r=this.records.get(t);r||(r=ca(void 0,Ju,!0),r.factory=()=>_p(r.multi),this.records.set(t,r)),t=n,r.multi.push(n)}this.records.set(t,i)}hydrate(n,t){return t.value===Ju&&(t.value=bT,t.value=t.factory()),"object"==typeof t.value&&t.value&&function ST(e){return null!==e&&"object"==typeof e&&"function"==typeof e.ngOnDestroy}(t.value)&&this._ngOnDestroyHooks.add(t.value),t.value}injectableDefInScope(n){if(!n.providedIn)return!1;const t=te(n.providedIn);return"string"==typeof t?"any"===t||this.scopes.has(t):this.injectorDefTypes.has(t)}}function Op(e){const n=Vs(e),t=null!==n?n.factory:Er(e);if(null!==t)return t;if(e instanceof q)throw new F(204,!1);if(e instanceof Function)return function DT(e){const n=e.length;if(n>0)throw xl(n,"?"),new F(204,!1);const t=function Dh(e){const n=e&&(e[Zr]||e[sl]);if(n){const t=function Ch(e){if(e.hasOwnProperty("name"))return e.name;const n=(""+e).match(/^function\s*([^\s(]+)/);return null===n?"":n[1]}(e);return console.warn(`DEPRECATED: DI is instantiating a token "${t}" that inherits its @Injectable decorator but does not provide one itself.\nThis will become an error in a future version of Angular. Please add @Injectable() to the "${t}" class.`),n}return null}(e);return null!==t?()=>t.factory(e):()=>new e}(e);throw new F(204,!1)}function zy(e,n,t){let i;if(Yo(e)){const r=te(e);return Er(r)||Op(r)}if(Ip(e))i=()=>te(e.useValue);else if(function Gy(e){return!(!e||!e.useFactory)}(e))i=()=>e.useFactory(..._p(e.deps||[]));else if(function Uy(e){return!(!e||!e.useExisting)}(e))i=()=>L(te(e.useExisting));else{const r=te(e&&(e.useClass||e.provide));if(!function wT(e){return!!e.deps}(e))return Er(r)||Op(r);i=()=>new r(..._p(e.deps))}return i}function ca(e,n,t=!1){return{factory:e,value:n,multi:t?[]:void 0}}function NT(e){return!!e.\u0275providers}function xp(e,n){for(const t of e)Array.isArray(t)?xp(t,n):NT(t)?xp(t.\u0275providers,n):n(t)} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */class zy{} + */class Yy{} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */class AT{resolveComponentFactory(n){throw function TT(e){const n=Error(`No component factory found for ${Ve(e)}. Did you add it to @NgModule.entryComponents?`);return n.ngComponent=e,n}(n)}}let Gl=(()=>{class e{} + */class IT{resolveComponentFactory(n){throw function TT(e){const n=Error(`No component factory found for ${Ve(e)}. Did you add it to @NgModule.entryComponents?`);return n.ngComponent=e,n}(n)}}let Gl=(()=>{class e{} /** * @license * Copyright Google LLC All Rights Reserved. @@ -358,21 +358,21 @@ const Ip=new q("Set Injector scope."),Zu={},bT={}; * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -return e.NULL=new AT,e})();function IT(){return ua(wt(),k())}function ua(e,n){return new Ze(xt(e,n))}let Ze=(()=>{class e{constructor(t){this.nativeElement=t}}return e.__NG_ELEMENT_ID__=IT,e})();function OT(e){return e instanceof Ze?e.nativeElement:e} +return e.NULL=new IT,e})();function AT(){return ua(wt(),O())}function ua(e,n){return new Je(Rt(e,n))}let Je=(()=>{class e{constructor(t){this.nativeElement=t}}return e.__NG_ELEMENT_ID__=AT,e})();function kT(e){return e instanceof Je?e.nativeElement:e} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */class xp{}let pi=(()=>{class e{}return e.__NG_ELEMENT_ID__=()=>function kT(){const e=k(),t=Nn(wt().index,e);return(hn(t)?t:e)[11]} + */class Rp{}let pi=(()=>{class e{}return e.__NG_ELEMENT_ID__=()=>function OT(){const e=O(),t=En(wt().index,e);return(hn(t)?t:e)[11]} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */(),e})(),RT=(()=>{class e{} + */(),e})(),xT=(()=>{class e{} /** * @license * Copyright Google LLC All Rights Reserved. @@ -380,21 +380,21 @@ return e.NULL=new AT,e})();function IT(){return ua(wt(),k())}function ua(e,n){re * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -return e.\u0275prov=G({token:e,providedIn:"root",factory:()=>null}),e})();class Wl{constructor(n){this.full=n,this.major=n.split(".")[0],this.minor=n.split(".")[1],this.patch=n.split(".").slice(2).join(".")}}const xT=new Wl("14.2.9"),Fp={}; +return e.\u0275prov=G({token:e,providedIn:"root",factory:()=>null}),e})();class Wl{constructor(n){this.full=n,this.major=n.split(".")[0],this.minor=n.split(".")[1],this.patch=n.split(".").slice(2).join(".")}}const RT=new Wl("14.2.9"),Pp={}; /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */function Bp(e){return e.ngOriginalError} + */function Hp(e){return e.ngOriginalError} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */class da{constructor(){this._console=console}handleError(n){const t=this._findOriginalError(n);this._console.error("ERROR",n),t&&this._console.error("ORIGINAL ERROR",t)}_findOriginalError(n){let t=n&&Bp(n);for(;t&&Bp(t);)t=Bp(t);return t||null}} + */class da{constructor(){this._console=console}handleError(n){const t=this._findOriginalError(n);this._console.error("ERROR",n),t&&this._console.error("ORIGINAL ERROR",t)}_findOriginalError(n){let t=n&&Hp(n);for(;t&&Hp(t);)t=Hp(t);return t||null}} /** * @license * Copyright Google LLC All Rights Reserved. @@ -409,7 +409,7 @@ return e.\u0275prov=G({token:e,providedIn:"root",factory:()=>null}),e})();class * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -const jp=new Map;let KT=0;const Up="__ngContext__";function pn(e,n){hn(n)?(e[Up]=n[20],function YT(e){jp.set(e[20],e)}(n)):e[Up]=n}function Rr(e){return e instanceof Function?e():e} +const jp=new Map;let zT=0;const Up="__ngContext__";function pn(e,n){hn(n)?(e[Up]=n[20],function KT(e){jp.set(e[20],e)}(n)):e[Up]=n}function xr(e){return e instanceof Function?e():e} /** * @license * Copyright Google LLC All Rights Reserved. @@ -439,35 +439,35 @@ var Un=(()=>((Un=Un||{})[Un.Important=1]="Important",Un[Un.DashCase=2]="DashCase * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -function zl(e){const n=e[3];return qn(n)?n[3]:n}function Kp(e){return c0(e[13])}function zp(e){return c0(e[4])}function c0(e){for(;null!==e&&!qn(e);)e=e[4];return e} +function Yl(e){const n=e[3];return qn(n)?n[3]:n}function zp(e){return c0(e[13])}function Yp(e){return c0(e[4])}function c0(e){for(;null!==e&&!qn(e);)e=e[4];return e} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */function ha(e,n,t,i,r){if(null!=i){let o,s=!1;qn(i)?o=i:hn(i)&&(s=!0,i=i[0]);const a=tt(i);0===e&&null!==t?null==r?g0(n,t,a):Yo(n,t,a,r||null,!0):1===e&&null!==t?Yo(n,t,a,r||null,!0):2===e?function C0(e,n,t){const i=Xu(e,n);i&&function DA(e,n,t,i){e.removeChild(n,t,i)}(e,i,n,t)}(n,a,s):3===e&&n.destroyNode(a),null!=o&&function SA(e,n,t,i,r){const o=t[7];o!==tt(t)&&ha(n,e,i,o,r);for(let a=10;a0&&(e[t-1][4]=i[4]);const o=Uu(e,10+n);!function hA(e,n){Yl(e,n,n[11],2,null,null),n[0]=null,n[6]=null}(i[1],i);const s=o[19];null!==s&&s.detachView(o[1]),i[3]=null,i[4]=null,i[2]&=-65}return i}function f0(e,n){if(!(128&n[2])){const t=n[11];t.destroyNode&&Yl(e,n,t,3,null,null),function mA(e){let n=e[13];if(!n)return Zp(e[1],e);for(;n;){let t=null;if(hn(n))t=n[13];else{const i=n[10];i&&(t=i)}if(!t){for(;n&&!n[4]&&n!==e;)hn(n)&&Zp(n[1],n),n=n[3];null===n&&(n=e),hn(n)&&Zp(n[1],n),t=n&&n[4]}n=t}}(n)}}function Zp(e,n){if(!(128&n[2])){n[2]&=-65,n[2]|=128,function bA(e,n){let t;if(null!=e&&null!=(t=e.destroyHooks))for(let i=0;i=0?i[r=u]():i[r=-u].unsubscribe(),o+=2}else{const s=i[r=t[o+1]];t[o].call(s)}if(null!==i){for(let o=r+1;o0&&(e[t-1][4]=i[4]);const o=Uu(e,10+n);!function hI(e,n){Kl(e,n,n[11],2,null,null),n[0]=null,n[6]=null}(i[1],i);const s=o[19];null!==s&&s.detachView(o[1]),i[3]=null,i[4]=null,i[2]&=-65}return i}function f0(e,n){if(!(128&n[2])){const t=n[11];t.destroyNode&&Kl(e,n,t,3,null,null),function mI(e){let n=e[13];if(!n)return Jp(e[1],e);for(;n;){let t=null;if(hn(n))t=n[13];else{const i=n[10];i&&(t=i)}if(!t){for(;n&&!n[4]&&n!==e;)hn(n)&&Jp(n[1],n),n=n[3];null===n&&(n=e),hn(n)&&Jp(n[1],n),t=n&&n[4]}n=t}}(n)}}function Jp(e,n){if(!(128&n[2])){n[2]&=-65,n[2]|=128,function bI(e,n){let t;if(null!=e&&null!=(t=e.destroyHooks))for(let i=0;i=0?i[r=u]():i[r=-u].unsubscribe(),o+=2}else{const s=i[r=t[o+1]];t[o].call(s)}if(null!==i){for(let o=r+1;oo?"":r[p+1].toLowerCase();const v=8&i?m:null;if(v&&-1!==E0(v,u,0)||2&i&&u!==m){if(xi(i))return!1;s=!0}}}}else{if(!s&&!xi(i)&&!xi(l))return!1;if(s&&xi(l))continue;s=!1,i=l|1&i}}return xi(i)||s}function xi(e){return 0==(1&e)}function AA(e,n,t,i){if(null===n)return-1;let r=0;if(i||!t){let o=!1;for(;r-1)for(t++;t0?'="'+a+'"':"")+"]"}else 8&i?r+="."+s:4&i&&(r+=" "+s);else""!==r&&!xi(s)&&(n+=A0(o,r),r=""),i=s,o=o||!xi(i);t++}return""!==r&&(n+=A0(o,r)),n} + */const N0="ng-template";function NI(e,n,t){let i=0;for(;io?"":r[p+1].toLowerCase();const v=8&i?m:null;if(v&&-1!==M0(v,u,0)||2&i&&u!==m){if(Ri(i))return!1;s=!0}}}}else{if(!s&&!Ri(i)&&!Ri(l))return!1;if(s&&Ri(l))continue;s=!1,i=l|1&i}}return Ri(i)||s}function Ri(e){return 0==(1&e)}function II(e,n,t,i){if(null===n)return-1;let r=0;if(i||!t){let o=!1;for(;r-1)for(t++;t0?'="'+a+'"':"")+"]"}else 8&i?r+="."+s:4&i&&(r+=" "+s);else""!==r&&!Ri(s)&&(n+=I0(o,r),r=""),i=s,o=o||!Ri(i);t++}return""!==r&&(n+=I0(o,r)),n} /** * @license * Copyright Google LLC All Rights Reserved. @@ -482,7 +482,7 @@ const ae={}; * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */function F(e){I0(be(),k(),on()+e,!1)}function I0(e,n,t,i){if(!i)if(3==(3&n[2])){const o=e.preOrderCheckHooks;null!==o&&$o(n,o,t)}else{const o=e.preOrderHooks;null!==o&&Js(n,o,0,t)}nr(t)} + */function P(e){A0(be(),O(),on()+e,!1)}function A0(e,n,t,i){if(!i)if(3==(3&n[2])){const o=e.preOrderCheckHooks;null!==o&&$o(n,o,t)}else{const o=e.preOrderHooks;null!==o&&Zs(n,o,0,t)}nr(t)} /** * @license * Copyright Google LLC All Rights Reserved. @@ -497,14 +497,14 @@ const ae={}; * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -function x0(e,n=null,t=null,i){const r=F0(e,n,t,i);return r.resolveInjectorInitializers(),r}function F0(e,n=null,t=null,i,r=new Set){const o=[t||Ae,_T(e)];return i=i||("object"==typeof e?void 0:Ve(e)),new Wy(o,n||Qu(),i||null,r) +function R0(e,n=null,t=null,i){const r=P0(e,n,t,i);return r.resolveInjectorInitializers(),r}function P0(e,n=null,t=null,i,r=new Set){const o=[t||Ie,_T(e)];return i=i||("object"==typeof e?void 0:Ve(e)),new Wy(o,n||Qu(),i||null,r) /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */}let gn=(()=>{class e{static create(t,i){if(Array.isArray(t))return x0({name:""},i,t,"");{const r=t.name??"";return x0({name:r},t.parent,t.providers,r)}}} + */}let gn=(()=>{class e{static create(t,i){if(Array.isArray(t))return R0({name:""},i,t,"");{const r=t.name??"";return R0({name:r},t.parent,t.providers,r)}}} /** * @license * Copyright Google LLC All Rights Reserved. @@ -512,7 +512,7 @@ function x0(e,n=null,t=null,i){const r=F0(e,n,t,i);return r.resolveInjectorIniti * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -return e.THROW_IF_NOT_FOUND=xl,e.NULL=new By,e.\u0275prov=G({token:e,providedIn:"any",factory:()=>L(Vy)}),e.__NG_ELEMENT_ID__=-1,e})(); +return e.THROW_IF_NOT_FOUND=Rl,e.NULL=new Hy,e.\u0275prov=G({token:e,providedIn:"any",factory:()=>L(Vy)}),e.__NG_ELEMENT_ID__=-1,e})(); /** * @license * Copyright Google LLC All Rights Reserved. @@ -534,7 +534,7 @@ return e.THROW_IF_NOT_FOUND=xl,e.NULL=new By,e.\u0275prov=G({token:e,providedIn: * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -function C(e,n=X.Default){const t=k();return null===t?L(e,n):h(wt(),t,te(e),n)}function sg(){throw new Error("invalid")} +function C(e,n=X.Default){const t=O();return null===t?L(e,n):h(wt(),t,te(e),n)}function sg(){throw new Error("invalid")} /** * @license * Copyright Google LLC All Rights Reserved. @@ -549,7 +549,7 @@ function C(e,n=X.Default){const t=k();return null===t?L(e,n):h(wt(),t,te(e),n)}f * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -function id(e,n){return e<<17|n<<2}function Fi(e){return e>>17&32767}function ag(e){return 2|e}function xr(e){return(131068&e)>>2}function lg(e,n){return-131069&e|n<<2}function cg(e){return 1|e}function Q0(e,n){const t=e.contentQueries;if(null!==t)for(let i=0;i>17&32767}function ag(e){return 2|e}function Rr(e){return(131068&e)>>2}function lg(e,n){return-131069&e|n<<2}function cg(e){return 1|e}function Q0(e,n){const t=e.contentQueries;if(null!==t)for(let i=0;i>17&32767}function ag * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -function dI(e,n){const t=e.hostBindingOpCodes;if(null!==t)try{for(let i=0;i22&&I0(e,n,22,!1),t(i,r)}finally{nr(o)}}function yg(e,n,t){!Ou()||(function DI(e,n,t,i){const r=t.directiveStart,o=t.directiveEnd;e.firstCreatePass||Go(t,n),pn(i,n);const s=t.initialInputs;for(let a=r;a0;){const t=e[--n];if("number"==typeof t&&t<0)return t}return 0})(a)!=l&&a.push(l),a.push(i,r,s)}}function ab(e,n){null!==e.hostBindings&&e.hostBindings(1,n)}function lb(e,n){n.flags|=2,(e.components||(e.components=[])).push(n.index)}function EI(e,n,t){if(t){if(n.exportAs)for(let i=0;i0&&Sg(t)}}function Sg(e){for(let i=Kp(e);null!==i;i=zp(i))for(let r=10;r0&&Sg(o)}const t=e[1].components;if(null!==t)for(let i=0;i0&&Sg(r)}}function kI(e,n){const t=Nn(n,e),i=t[1];(function RI(e,n){for(let t=n.length;t22&&A0(e,n,22,!1),t(i,r)}finally{nr(o)}}function yg(e,n,t){!ku()||(function DA(e,n,t,i){const r=t.directiveStart,o=t.directiveEnd;e.firstCreatePass||Go(t,n),pn(i,n);const s=t.initialInputs;for(let a=r;a0;){const t=e[--n];if("number"==typeof t&&t<0)return t}return 0})(a)!=l&&a.push(l),a.push(i,r,s)}}function ab(e,n){null!==e.hostBindings&&e.hostBindings(1,n)}function lb(e,n){n.flags|=2,(e.components||(e.components=[])).push(n.index)}function MA(e,n,t){if(t){if(n.exportAs)for(let i=0;i0&&Sg(t)}}function Sg(e){for(let i=zp(e);null!==i;i=Yp(i))for(let r=10;r0&&Sg(o)}const t=e[1].components;if(null!==t)for(let i=0;i0&&Sg(r)}}function OA(e,n){const t=En(n,e),i=t[1];(function xA(e,n){for(let t=n.length;t-1&&(Jp(n,i),Uu(t,i))}this._attachedToViewContainer=!1}f0(this._lView[1],this._lView)}onDestroy(n){nb(this._lView[1],this._lView,null,n)}markForCheck(){Eg(this._cdRefInjectingView||this._lView)}detach(){this._lView[2]&=-65}reattach(){this._lView[2]|=64}detectChanges(){cd(this._lView[1],this._lView,this.context)}checkNoChanges(){}attachToViewContainerRef(){if(this._appRef)throw new P(902,!1);this._attachedToViewContainer=!0}detachFromAppRef(){this._appRef=null,function gA(e,n){Yl(e,n,n[11],2,null,null)}(this._lView[1],this._lView)}attachToAppRef(n){if(this._attachedToViewContainer)throw new P(902,!1);this._appRef=n}}class xI extends ql{constructor(n){super(n),this._view=n}detectChanges(){const n=this._view;cd(n[1],n,n[8],!1)}checkNoChanges(){}get context(){return null}} + */class ql{constructor(n,t){this._lView=n,this._cdRefInjectingView=t,this._appRef=null,this._attachedToViewContainer=!1}get rootNodes(){const n=this._lView,t=n[1];return dd(t,n,t.firstChild,[])}get context(){return this._lView[8]}set context(n){this._lView[8]=n}get destroyed(){return 128==(128&this._lView[2])}destroy(){if(this._appRef)this._appRef.detachView(this);else if(this._attachedToViewContainer){const n=this._lView[3];if(qn(n)){const t=n[8],i=t?t.indexOf(this):-1;i>-1&&(Zp(n,i),Uu(t,i))}this._attachedToViewContainer=!1}f0(this._lView[1],this._lView)}onDestroy(n){nb(this._lView[1],this._lView,null,n)}markForCheck(){Mg(this._cdRefInjectingView||this._lView)}detach(){this._lView[2]&=-65}reattach(){this._lView[2]|=64}detectChanges(){cd(this._lView[1],this._lView,this.context)}checkNoChanges(){}attachToViewContainerRef(){if(this._appRef)throw new F(902,!1);this._attachedToViewContainer=!0}detachFromAppRef(){this._appRef=null,function gI(e,n){Kl(e,n,n[11],2,null,null)}(this._lView[1],this._lView)}attachToAppRef(n){if(this._attachedToViewContainer)throw new F(902,!1);this._appRef=n}}class RA extends ql{constructor(n){super(n),this._view=n}detectChanges(){const n=this._view;cd(n[1],n,n[8],!1)}checkNoChanges(){}get context(){return null}} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */class Tg extends Gl{constructor(n){super(),this.ngModule=n}resolveComponentFactory(n){const t=Re(n);return new Jl(t,this.ngModule)}}function mb(e){const n=[];for(let t in e)e.hasOwnProperty(t)&&n.push({propName:e[t],templateName:t});return n}class PI{constructor(n,t){this.injector=n,this.parentInjector=t}get(n,t,i){const r=this.injector.get(n,Fp,i);return r!==Fp||t===Fp?r:this.parentInjector.get(n,t,i)}}class Jl extends zy{constructor(n,t){super(),this.componentDef=n,this.ngModule=t,this.componentType=n.type,this.selector=function FA(e){return e.map(xA).join(",")}(n.selectors),this.ngContentSelectors=n.ngContentSelectors?n.ngContentSelectors:[],this.isBoundToModule=!!t}get inputs(){return mb(this.componentDef.inputs)}get outputs(){return mb(this.componentDef.outputs)}create(n,t,i,r){let o=(r=r||this.ngModule)instanceof lo?r:r?.injector;o&&null!==this.componentDef.getStandaloneInjector&&(o=this.componentDef.getStandaloneInjector(o)||o);const s=o?new PI(n,o):n,a=s.get(xp,null);if(null===a)throw new P(407,!1);const l=s.get(RT,null),u=a.createRenderer(null,this.componentDef),f=this.componentDef.selectors[0][0]||"div",p=i?function gI(e,n,t){return e.selectRootElement(n,t===ai.ShadowDom)}(u,i,this.componentDef.encapsulation):qp(a.createRenderer(null,this.componentDef),f,function FI(e){const n=e.toLowerCase();return"svg"===n?"svg":"math"===n?"math":null}(f)),m=this.componentDef.onPush?288:272,v=Dg(0,null,null,1,0,null,null,null,null,null),y=sd(null,v,null,m,null,null,a,u,l,s,null);let D,w;x(y);try{const M=function HI(e,n,t,i,r,o){const s=t[1];t[22]=e;const l=ga(s,22,2,"#host",null),u=l.mergedAttrs=n.hostAttrs;null!==u&&(ud(l,u,!0),null!==e&&(Xs(r,e,u),null!==l.classes&&tg(r,e,l.classes),null!==l.styles&&S0(r,e,l.styles)));const f=i.createRenderer(e,n),p=sd(t,tb(n),null,n.onPush?32:16,t[22],l,i,f,o||null,null,null);return s.firstCreatePass&&(Ir(Go(l,t),s,n.type),lb(s,l),cb(l,t.length,1)),ld(t,p),t[22]=p}(p,this.componentDef,y,a,u);if(p)if(i)Xs(u,p,["ng-version",xT.full]);else{const{attrs:I,classes:S}=function PA(e){const n=[],t=[];let i=1,r=2;for(;i0&&tg(u,p,S.join(" "))}if(w=Ks(v,22),void 0!==t){const I=w.projection=[];for(let S=0;S0&&tg(u,p,S.join(" "))}if(w=zs(v,22),void 0!==t){const A=w.projection=[];for(let S=0;S=0;i--){const r=e[i];r.hostVars=n+=r.hostVars,r.hostAttrs=di(r.hostAttrs,t=di(t,r.hostAttrs))}}(i)}function Ag(e){return e===Xi?{}:e===Ae?[]:e}function UI(e,n){const t=e.viewQuery;e.viewQuery=t?(i,r)=>{n(i,r),t(i,r)}:n}function GI(e,n){const t=e.contentQueries;e.contentQueries=t?(i,r,o)=>{n(i,r,o),t(i,r,o)}:n}function WI(e,n){const t=e.hostBindings;e.hostBindings=t?(i,r)=>{n(i,r),t(i,r)}:n} + */function Be(e){let n=function _b(e){return Object.getPrototypeOf(e.prototype).constructor}(e.type),t=!0;const i=[e];for(;n;){let r;if(Zn(e))r=n.\u0275cmp||n.\u0275dir;else{if(n.\u0275cmp)throw new F(903,!1);r=n.\u0275dir}if(r){if(t){i.push(r);const s=e;s.inputs=Ig(e.inputs),s.declaredInputs=Ig(e.declaredInputs),s.outputs=Ig(e.outputs);const a=r.hostBindings;a&&WA(e,a);const l=r.viewQuery,u=r.contentQueries;if(l&&UA(e,l),u&&GA(e,u),rl(e.inputs,r.inputs),rl(e.declaredInputs,r.declaredInputs),rl(e.outputs,r.outputs),Zn(r)&&r.data.animation){const f=e.data;f.animation=(f.animation||[]).concat(r.data.animation)}}const o=r.features;if(o)for(let s=0;s=0;i--){const r=e[i];r.hostVars=n+=r.hostVars,r.hostAttrs=di(r.hostAttrs,t=di(t,r.hostAttrs))}}(i)}function Ig(e){return e===Xi?{}:e===Ie?[]:e}function UA(e,n){const t=e.viewQuery;e.viewQuery=t?(i,r)=>{n(i,r),t(i,r)}:n}function GA(e,n){const t=e.contentQueries;e.contentQueries=t?(i,r,o)=>{n(i,r,o),t(i,r,o)}:n}function WA(e,n){const t=e.hostBindings;e.hostBindings=t?(i,r)=>{n(i,r),t(i,r)}:n} /** * @license * Copyright Google LLC All Rights Reserved. @@ -615,7 +615,7 @@ let fd=null;function qo(){if(!fd){const e=We.Symbol;if(e&&e.iterator)fd=e.iterat * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */function Zl(e){return!!Ig(e)&&(Array.isArray(e)||!(e instanceof Map)&&qo()in e)}function Ig(e){return null!==e&&("function"==typeof e||"object"==typeof e)} + */function Jl(e){return!!Ag(e)&&(Array.isArray(e)||!(e instanceof Map)&&qo()in e)}function Ag(e){return null!==e&&("function"==typeof e||"object"==typeof e)} /** * @license * Copyright Google LLC All Rights Reserved. @@ -630,7 +630,7 @@ let fd=null;function qo(){if(!fd){const e=We.Symbol;if(e&&e.iterator)fd=e.iterat * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -function or(e,n,t){return e[n]=t}function mn(e,n,t){return!Object.is(e[n],t)&&(e[n]=t,!0)}function Jo(e,n,t,i){const r=mn(e,n,t);return mn(e,n+1,i)||r} +function or(e,n,t){return e[n]=t}function mn(e,n,t){return!Object.is(e[n],t)&&(e[n]=t,!0)}function Zo(e,n,t,i){const r=mn(e,n,t);return mn(e,n+1,i)||r} /** * @license * Copyright Google LLC All Rights Reserved. @@ -638,14 +638,14 @@ function or(e,n,t){return e[n]=t}function mn(e,n,t){return!Object.is(e[n],t)&&(e * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -function Ke(e,n,t,i){const r=k();return mn(r,Tr(),n)&&(be(),rr(st(),r,e,n,t,i)),Ke} +function ze(e,n,t,i){const r=O();return mn(r,Tr(),n)&&(be(),rr(st(),r,e,n,t,i)),ze} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */function J(e,n,t,i,r,o,s,a){const l=k(),u=be(),f=e+22,p=u.firstCreatePass? + */function Z(e,n,t,i,r,o,s,a){const l=O(),u=be(),f=e+22,p=u.firstCreatePass? /** * @license * Copyright Google LLC All Rights Reserved. @@ -653,56 +653,56 @@ function Ke(e,n,t,i){const r=k();return mn(r,Tr(),n)&&(be(),rr(st(),r,e,n,t,i)), * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -function XI(e,n,t,i,r,o,s,a,l){const u=n.consts,f=ga(n,e,4,s||null,tr(u,a));Cg(n,t,f,tr(u,l)),qs(n,f);const p=f.tViews=Dg(2,f,i,r,o,n.directiveRegistry,n.pipeRegistry,null,n.schemas,u);return null!==n.queries&&(n.queries.template(n,f),p.queries=n.queries.embeddedTView(f)),f}(f,u,l,n,t,i,r,o,s):u.data[f];ci(p,!1);const m=l[11].createComment("");ed(u,l,m,p),pn(m,l),ld(l,l[f]=db(m,l,m,p)),Us(p)&&yg(u,l,p),null!=s&&bg(l,p,a)} +function XA(e,n,t,i,r,o,s,a,l){const u=n.consts,f=ga(n,e,4,s||null,tr(u,a));Cg(n,t,f,tr(u,l)),qs(n,f);const p=f.tViews=Dg(2,f,i,r,o,n.directiveRegistry,n.pipeRegistry,null,n.schemas,u);return null!==n.queries&&(n.queries.template(n,f),p.queries=n.queries.embeddedTView(f)),f}(f,u,l,n,t,i,r,o,s):u.data[f];ci(p,!1);const m=l[11].createComment("");ed(u,l,m,p),pn(m,l),ld(l,l[f]=db(m,l,m,p)),Us(p)&&yg(u,l,p),null!=s&&bg(l,p,a)} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */function Pi(e){return io(function Yh(){return re.lFrame.contextLView}(),22+e)} + */function Fi(e){return io(function Kh(){return re.lFrame.contextLView}(),22+e)} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */function Q(e,n,t){const i=k();return mn(i,Tr(),n)&&function Xn(e,n,t,i,r,o,s,a){const l=xt(n,t);let f,u=n.inputs;!a&&null!=u&&(f=u[i])?(Ng(e,t,f,i,r),$s(n)&&ob(t,n.index)):3&n.type&&(i=function _I(e){return"class"===e?"className":"for"===e?"htmlFor":"formaction"===e?"formAction":"innerHtml"===e?"innerHTML":"readonly"===e?"readOnly":"tabindex"===e?"tabIndex":e}(i),r=null!=s?s(r,n.value||"",i):r,o.setProperty(l,i,r))}(be(),st(),i,e,n,i[11],t,!1),Q}function Og(e,n,t,i,r){const s=r?"class":"style";Ng(e,t,n.inputs[s],s,i)} + */function Q(e,n,t){const i=O();return mn(i,Tr(),n)&&function Xn(e,n,t,i,r,o,s,a){const l=Rt(n,t);let f,u=n.inputs;!a&&null!=u&&(f=u[i])?(Eg(e,t,f,i,r),$s(n)&&ob(t,n.index)):3&n.type&&(i=function _A(e){return"class"===e?"className":"for"===e?"htmlFor":"formaction"===e?"formAction":"innerHtml"===e?"innerHTML":"readonly"===e?"readOnly":"tabindex"===e?"tabIndex":e}(i),r=null!=s?s(r,n.value||"",i):r,o.setProperty(l,i,r))}(be(),st(),i,e,n,i[11],t,!1),Q}function kg(e,n,t,i,r){const s=r?"class":"style";Eg(e,t,n.inputs[s],s,i)} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */function E(e,n,t,i){const r=k(),o=be(),s=22+e,a=r[11],l=r[s]=qp(a,n,function Vu(){return re.lFrame.currentNamespace}()),u=o.firstCreatePass?function tO(e,n,t,i,r,o,s){const a=n.consts,u=ga(n,e,2,r,tr(a,o));return Cg(n,t,u,tr(a,s)),null!==u.attrs&&ud(u,u.attrs,!1),null!==u.mergedAttrs&&ud(u,u.mergedAttrs,!0),null!==n.queries&&n.queries.elementStart(n,u),u}(s,o,r,0,n,t,i):o.data[s];ci(u,!0);const f=u.mergedAttrs;null!==f&&Xs(a,l,f);const p=u.classes;null!==p&&tg(a,l,p);const m=u.styles;return null!==m&&S0(a,l,m),64!=(64&u.flags)&&ed(o,r,l,u),0===function Uh(){return re.lFrame.elementDepthCount}()&&pn(l,r),function Gh(){re.lFrame.elementDepthCount++}(),Us(u)&&(yg(o,r,u),function eb(e,n,t){if(pl(n)){const r=n.directiveEnd;for(let o=n.directiveStart;oa(tt(R[i.index])):i.index;let O=null;if(!a&&l&&(O=function iO(e,n,t,i){const r=e.cleanup;if(null!=r)for(let o=0;ol?a[l]:null}"string"==typeof s&&(o+=2)}return null}(e,n,r,i.index)),null!==O)(O.__ngLastListenerFn__||O).__ngNextListenerFn__=o,O.__ngLastListenerFn__=o,v=!1;else{o=kb(i,n,p,o,!1);const R=t.listen(M,r,o);m.push(o,R),f&&f.push(r,S,I,I+1)}}else o=kb(i,n,p,o,!1);const y=i.outputs;let D;if(v&&null!==y&&(D=y[r])){const w=D.length;if(w)for(let M=0;Ma(tt(x[i.index])):i.index;let k=null;if(!a&&l&&(k=function ik(e,n,t,i){const r=e.cleanup;if(null!=r)for(let o=0;ol?a[l]:null}"string"==typeof s&&(o+=2)}return null}(e,n,r,i.index)),null!==k)(k.__ngLastListenerFn__||k).__ngNextListenerFn__=o,k.__ngLastListenerFn__=o,v=!1;else{o=Ob(i,n,p,o,!1);const x=t.listen(N,r,o);m.push(o,x),f&&f.push(r,S,A,A+1)}}else o=Ob(i,n,p,o,!1);const y=i.outputs;let D;if(v&&null!==y&&(D=y[r])){const w=D.length;if(w)for(let N=0;N0;)n=n[15],e--;return n}(e,re.lFrame.contextLView))[8]}(e)} + */function z(e=1){return function Lu(e){return(re.lFrame.contextLView=function El(e,n){for(;e>0;)n=n[15],e--;return n}(e,re.lFrame.contextLView))[8]}(e)} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */function rO(e,n){let t=null;const i=function IA(e){const n=e.attrs;if(null!=n){const t=n.indexOf(5);if(0==(1&t))return n[t+1]}return null}(e);for(let r=0;r=0} + */function rk(e,n){let t=null;const i=function AI(e){const n=e.attrs;if(null!=n){const t=n.indexOf(5);if(0==(1&t))return n[t+1]}return null}(e);for(let r=0;r=0} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */const Pt={textEnd:0,key:0,keyEnd:0,value:0,valueEnd:0};function $b(e){return e.substring(Pt.key,Pt.keyEnd)}function Ub(e,n){const t=Pt.textEnd;return t===n?-1:(n=Pt.keyEnd=function dO(e,n,t){for(;n32;)n++;return n}(e,Pt.key=n,t),Ma(e,n,t))}function Ma(e,n,t){for(;n=0;t=Ub(n,t))Qn(e,$b(n),!0)}function Yb(e,n){return n>=e.expandoStartIndex}function qb(e,n,t,i){const r=e.data;if(null===r[t+1]){const o=r[on()],s=Yb(e,t);Xb(o,i)&&null===n&&!s&&(n=!1),n=function gO(e,n,t,i){const r=function ui(e){const n=re.lFrame.currentDirectiveIndex;return-1===n?null:e[n]}(e);let o=i?n.residualClasses:n.residualStyles;if(null===r)0===(i?n.classBindings:n.styleBindings)&&(t=ec(t=Hg(null,e,n,t,i),n.attrs,i),o=null);else{const s=n.directiveStylingLast;if(-1===s||e[s]!==r)if(t=Hg(r,e,n,t,i),null===o){let l=function mO(e,n,t){const i=t?n.classBindings:n.styleBindings;if(0!==xr(i))return e[Fi(i)]}(e,n,i);void 0!==l&&Array.isArray(l)&&(l=Hg(null,e,n,l[1],i),l=ec(l,n.attrs,i),function _O(e,n,t,i){e[Fi(t?n.classBindings:n.styleBindings)]=i}(e,n,i,l))}else o=function vO(e,n,t){let i;const r=n.directiveEnd;for(let o=1+n.directiveStylingLast;o0)&&(u=!0)}else f=t;if(r)if(0!==l){const m=Fi(e[a+1]);e[i+1]=id(m,a),0!==m&&(e[m+1]=lg(e[m+1],i)),e[a+1]=function tI(e,n){return 131071&e|n<<17}(e[a+1],i)}else e[i+1]=id(a,0),0!==a&&(e[a+1]=lg(e[a+1],i)),a=i;else e[i+1]=id(l,0),0===a?a=i:e[l+1]=lg(e[l+1],i),l=i;u&&(e[i+1]=ag(e[i+1])),jb(e,f,i,!0),jb(e,f,i,!1),function sO(e,n,t,i,r){const o=r?e.residualClasses:e.residualStyles;null!=o&&"string"==typeof n&&oa(o,n)>=0&&(t[i+1]=cg(t[i+1]))}(n,f,e,i,o),s=id(a,l),o?n.classBindings=s:n.styleBindings=s}(r,o,n,t,s,i)}}function Hg(e,n,t,i,r){let o=null;const s=t.directiveEnd;let a=t.directiveStylingLast;for(-1===a?a=t.directiveStart:a++;a0;){const l=e[r],u=Array.isArray(l),f=u?l[1]:l,p=null===f;let m=t[r+1];m===ae&&(m=p?Ae:void 0);let v=p?pp(m,i):f===i?m:void 0;if(u&&!gd(v)&&(v=pp(l,i)),gd(v)&&(a=v,s))return a;const y=e[r+1];r=s?Fi(y):xr(y)}if(null!==n){let l=o?n.residualClasses:n.residualStyles;null!=l&&(a=pp(l,i))}return a}function gd(e){return void 0!==e}function Xb(e,n){return 0!=(e.flags&(n?16:32))} + */const Ft={textEnd:0,key:0,keyEnd:0,value:0,valueEnd:0};function $b(e){return e.substring(Ft.key,Ft.keyEnd)}function Ub(e,n){const t=Ft.textEnd;return t===n?-1:(n=Ft.keyEnd=function dk(e,n,t){for(;n32;)n++;return n}(e,Ft.key=n,t),Na(e,n,t))}function Na(e,n,t){for(;n=0;t=Ub(n,t))Qn(e,$b(n),!0)}function Kb(e,n){return n>=e.expandoStartIndex}function qb(e,n,t,i){const r=e.data;if(null===r[t+1]){const o=r[on()],s=Kb(e,t);Xb(o,i)&&null===n&&!s&&(n=!1),n=function gk(e,n,t,i){const r=function ui(e){const n=re.lFrame.currentDirectiveIndex;return-1===n?null:e[n]}(e);let o=i?n.residualClasses:n.residualStyles;if(null===r)0===(i?n.classBindings:n.styleBindings)&&(t=ec(t=Bg(null,e,n,t,i),n.attrs,i),o=null);else{const s=n.directiveStylingLast;if(-1===s||e[s]!==r)if(t=Bg(r,e,n,t,i),null===o){let l=function mk(e,n,t){const i=t?n.classBindings:n.styleBindings;if(0!==Rr(i))return e[Pi(i)]}(e,n,i);void 0!==l&&Array.isArray(l)&&(l=Bg(null,e,n,l[1],i),l=ec(l,n.attrs,i),function _k(e,n,t,i){e[Pi(t?n.classBindings:n.styleBindings)]=i}(e,n,i,l))}else o=function vk(e,n,t){let i;const r=n.directiveEnd;for(let o=1+n.directiveStylingLast;o0)&&(u=!0)}else f=t;if(r)if(0!==l){const m=Pi(e[a+1]);e[i+1]=id(m,a),0!==m&&(e[m+1]=lg(e[m+1],i)),e[a+1]=function tA(e,n){return 131071&e|n<<17}(e[a+1],i)}else e[i+1]=id(a,0),0!==a&&(e[a+1]=lg(e[a+1],i)),a=i;else e[i+1]=id(l,0),0===a?a=i:e[l+1]=lg(e[l+1],i),l=i;u&&(e[i+1]=ag(e[i+1])),jb(e,f,i,!0),jb(e,f,i,!1),function sk(e,n,t,i,r){const o=r?e.residualClasses:e.residualStyles;null!=o&&"string"==typeof n&&oa(o,n)>=0&&(t[i+1]=cg(t[i+1]))}(n,f,e,i,o),s=id(a,l),o?n.classBindings=s:n.styleBindings=s}(r,o,n,t,s,i)}}function Bg(e,n,t,i,r){let o=null;const s=t.directiveEnd;let a=t.directiveStylingLast;for(-1===a?a=t.directiveStart:a++;a0;){const l=e[r],u=Array.isArray(l),f=u?l[1]:l,p=null===f;let m=t[r+1];m===ae&&(m=p?Ie:void 0);let v=p?pp(m,i):f===i?m:void 0;if(u&&!gd(v)&&(v=pp(l,i)),gd(v)&&(a=v,s))return a;const y=e[r+1];r=s?Pi(y):Rr(y)}if(null!==n){let l=o?n.residualClasses:n.residualStyles;null!=l&&(a=pp(l,i))}return a}function gd(e){return void 0!==e}function Xb(e,n){return 0!=(e.flags&(n?16:32))} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */function A(e,n=""){const t=k(),i=be(),r=e+22,o=i.firstCreatePass?ga(i,r,1,n,null):i.data[r],s=t[r]=function Yp(e,n){return e.createText(n)}(t[11],n);ed(i,t,s,o),ci(o,!1)} + */function I(e,n=""){const t=O(),i=be(),r=e+22,o=i.firstCreatePass?ga(i,r,1,n,null):i.data[r],s=t[r]=function Kp(e,n){return e.createText(n)}(t[11],n);ed(i,t,s,o),ci(o,!1)} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */function fo(e){return Be("",e,""),fo}function Be(e,n,t){const i=k(),r=function va(e,n,t,i){return mn(e,Tr(),t)?n+oe(t)+i:ae}(i,e,n,t);return r!==ae&&function Fr(e,n,t){const i=Ho(n,e);!function u0(e,n,t){e.setValue(n,t)}(e[11],i,t)}(i,on(),r),Be} + */function fo(e){return He("",e,""),fo}function He(e,n,t){const i=O(),r=function va(e,n,t,i){return mn(e,Tr(),t)?n+oe(t)+i:ae}(i,e,n,t);return r!==ae&&function Pr(e,n,t){const i=Bo(n,e);!function u0(e,n,t){e.setValue(n,t)}(e[11],i,t)}(i,on(),r),He} /** * @license * Copyright Google LLC All Rights Reserved. @@ -759,21 +759,21 @@ function XI(e,n,t,i,r,o,s,a,l){const u=n.consts,f=ga(n,e,4,s||null,tr(u,a));Cg(n * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -const Qo=void 0;var jO=["en",[["a","p"],["AM","PM"],Qo],[["AM","PM"],Qo,Qo],[["S","M","T","W","T","F","S"],["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],["Su","Mo","Tu","We","Th","Fr","Sa"]],Qo,[["J","F","M","A","M","J","J","A","S","O","N","D"],["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],["January","February","March","April","May","June","July","August","September","October","November","December"]],Qo,[["B","A"],["BC","AD"],["Before Christ","Anno Domini"]],0,[6,0],["M/d/yy","MMM d, y","MMMM d, y","EEEE, MMMM d, y"],["h:mm a","h:mm:ss a","h:mm:ss a z","h:mm:ss a zzzz"],["{1}, {0}",Qo,"{1} 'at' {0}",Qo],[".",",",";","%","+","-","E","\xd7","\u2030","\u221e","NaN",":"],["#,##0.###","#,##0%","\xa4#,##0.00","#E0"],"USD","$","US Dollar",{},"ltr",function BO(e){const t=Math.floor(Math.abs(e)),i=e.toString().replace(/^[^.]*\.?/,"").length;return 1===t&&0===i?1:5}]; +const Qo=void 0;var jk=["en",[["a","p"],["AM","PM"],Qo],[["AM","PM"],Qo,Qo],[["S","M","T","W","T","F","S"],["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],["Su","Mo","Tu","We","Th","Fr","Sa"]],Qo,[["J","F","M","A","M","J","J","A","S","O","N","D"],["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],["January","February","March","April","May","June","July","August","September","October","November","December"]],Qo,[["B","A"],["BC","AD"],["Before Christ","Anno Domini"]],0,[6,0],["M/d/yy","MMM d, y","MMMM d, y","EEEE, MMMM d, y"],["h:mm a","h:mm:ss a","h:mm:ss a z","h:mm:ss a zzzz"],["{1}, {0}",Qo,"{1} 'at' {0}",Qo],[".",",",";","%","+","-","E","\xd7","\u2030","\u221e","NaN",":"],["#,##0.###","#,##0%","\xa4#,##0.00","#E0"],"USD","$","US Dollar",{},"ltr",function Hk(e){const t=Math.floor(Math.abs(e)),i=e.toString().replace(/^[^.]*\.?/,"").length;return 1===t&&0===i?1:5}]; /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */let Ta={};function In(e){const n=function $O(e){return e.toLowerCase().replace(/_/g,"-")} + */let Ta={};function An(e){const n=function $k(e){return e.toLowerCase().replace(/_/g,"-")} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */(e);let t=yD(n);if(t)return t;const i=n.split("-")[0];if(t=yD(i),t)return t;if("en"===i)return jO;throw new P(701,!1)}function yD(e){return e in Ta||(Ta[e]=We.ng&&We.ng.common&&We.ng.common.locales&&We.ng.common.locales[e]),Ta[e]}var j=(()=>((j=j||{})[j.LocaleId=0]="LocaleId",j[j.DayPeriodsFormat=1]="DayPeriodsFormat",j[j.DayPeriodsStandalone=2]="DayPeriodsStandalone",j[j.DaysFormat=3]="DaysFormat",j[j.DaysStandalone=4]="DaysStandalone",j[j.MonthsFormat=5]="MonthsFormat",j[j.MonthsStandalone=6]="MonthsStandalone",j[j.Eras=7]="Eras",j[j.FirstDayOfWeek=8]="FirstDayOfWeek",j[j.WeekendRange=9]="WeekendRange",j[j.DateFormat=10]="DateFormat",j[j.TimeFormat=11]="TimeFormat",j[j.DateTimeFormat=12]="DateTimeFormat",j[j.NumberSymbols=13]="NumberSymbols",j[j.NumberFormats=14]="NumberFormats",j[j.CurrencyCode=15]="CurrencyCode",j[j.CurrencySymbol=16]="CurrencySymbol",j[j.CurrencyName=17]="CurrencyName",j[j.Currencies=18]="Currencies",j[j.Directionality=19]="Directionality",j[j.PluralCase=20]="PluralCase",j[j.ExtraData=21]="ExtraData",j))();const Aa="en-US"; + */(e);let t=yD(n);if(t)return t;const i=n.split("-")[0];if(t=yD(i),t)return t;if("en"===i)return jk;throw new F(701,!1)}function yD(e){return e in Ta||(Ta[e]=We.ng&&We.ng.common&&We.ng.common.locales&&We.ng.common.locales[e]),Ta[e]}var j=(()=>((j=j||{})[j.LocaleId=0]="LocaleId",j[j.DayPeriodsFormat=1]="DayPeriodsFormat",j[j.DayPeriodsStandalone=2]="DayPeriodsStandalone",j[j.DaysFormat=3]="DaysFormat",j[j.DaysStandalone=4]="DaysStandalone",j[j.MonthsFormat=5]="MonthsFormat",j[j.MonthsStandalone=6]="MonthsStandalone",j[j.Eras=7]="Eras",j[j.FirstDayOfWeek=8]="FirstDayOfWeek",j[j.WeekendRange=9]="WeekendRange",j[j.DateFormat=10]="DateFormat",j[j.TimeFormat=11]="TimeFormat",j[j.DateTimeFormat=12]="DateTimeFormat",j[j.NumberSymbols=13]="NumberSymbols",j[j.NumberFormats=14]="NumberFormats",j[j.CurrencyCode=15]="CurrencyCode",j[j.CurrencySymbol=16]="CurrencySymbol",j[j.CurrencyName=17]="CurrencyName",j[j.Currencies=18]="Currencies",j[j.Directionality=19]="Directionality",j[j.PluralCase=20]="PluralCase",j[j.ExtraData=21]="ExtraData",j))();const Ia="en-US"; /** * @license * Copyright Google LLC All Rights Reserved. @@ -788,7 +788,7 @@ const Qo=void 0;var jO=["en",[["a","p"],["AM","PM"],Qo],[["AM","PM"],Qo,Qo],[["S * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -let bD=Aa;function Ug(e,n,t,i,r){if(e=te(e),Array.isArray(e))for(let o=0;o>20;if(zo(e)||!e.multi){const v=new Tn(l,r,C),y=Wg(a,n,r?f:f+m,p);-1===y?(Ir(Go(u,s),o,a),Gg(o,e,n.length),n.push(a),u.directiveStart++,u.directiveEnd++,r&&(u.providerIndexes+=1048576),t.push(v),s.push(v)):(t[y]=v,s[y]=v)}else{const v=Wg(a,n,f+m,p),y=Wg(a,n,f,f+m),D=v>=0&&t[v],w=y>=0&&t[y];if(r&&!w||!r&&!D){Ir(Go(u,s),o,a);const M=function Lk(e,n,t,i,r){const o=new Tn(e,t,C);return o.multi=[],o.index=n,o.componentProviders=0,WD(o,r,i&&!t),o}(r?Pk:Fk,t.length,r,i,l);!r&&w&&(t[y].providerFactory=M),Gg(o,e,n.length,0),n.push(a),u.directiveStart++,u.directiveEnd++,r&&(u.providerIndexes+=1048576),t.push(M),s.push(M)}else Gg(o,e,v>-1?v:y,WD(t[r?y:v],l,!r&&i));!r&&i&&w&&t[y].componentProviders++}}}function Gg(e,n,t,i){const r=zo(n),o=function yT(e){return!!e.useClass}(n);if(r||o){const l=(o?te(n.useClass):n).prototype.ngOnDestroy;if(l){const u=e.destroyHooks||(e.destroyHooks=[]);if(!r&&n.multi){const f=u.indexOf(t);-1===f?u.push(t,[i,l]):u[f+1].push(i,l)}else u.push(t,l)}}}function WD(e,n,t){return t&&e.componentProviders++,e.multi.push(n)-1}function Wg(e,n,t,i){for(let r=t;r{t.providersResolver=(i,r)=> +let bD=Ia;function Ug(e,n,t,i,r){if(e=te(e),Array.isArray(e))for(let o=0;o>20;if(Yo(e)||!e.multi){const v=new Tn(l,r,C),y=Wg(a,n,r?f:f+m,p);-1===y?(Ar(Go(u,s),o,a),Gg(o,e,n.length),n.push(a),u.directiveStart++,u.directiveEnd++,r&&(u.providerIndexes+=1048576),t.push(v),s.push(v)):(t[y]=v,s[y]=v)}else{const v=Wg(a,n,f+m,p),y=Wg(a,n,f,f+m),D=v>=0&&t[v],w=y>=0&&t[y];if(r&&!w||!r&&!D){Ar(Go(u,s),o,a);const N=function LO(e,n,t,i,r){const o=new Tn(e,t,C);return o.multi=[],o.index=n,o.componentProviders=0,WD(o,r,i&&!t),o}(r?FO:PO,t.length,r,i,l);!r&&w&&(t[y].providerFactory=N),Gg(o,e,n.length,0),n.push(a),u.directiveStart++,u.directiveEnd++,r&&(u.providerIndexes+=1048576),t.push(N),s.push(N)}else Gg(o,e,v>-1?v:y,WD(t[r?y:v],l,!r&&i));!r&&i&&w&&t[y].componentProviders++}}}function Gg(e,n,t,i){const r=Yo(n),o=function yT(e){return!!e.useClass}(n);if(r||o){const l=(o?te(n.useClass):n).prototype.ngOnDestroy;if(l){const u=e.destroyHooks||(e.destroyHooks=[]);if(!r&&n.multi){const f=u.indexOf(t);-1===f?u.push(t,[i,l]):u[f+1].push(i,l)}else u.push(t,l)}}}function WD(e,n,t){return t&&e.componentProviders++,e.multi.push(n)-1}function Wg(e,n,t,i){for(let r=t;r{t.providersResolver=(i,r)=> /** * @license * Copyright Google LLC All Rights Reserved. @@ -803,35 +803,35 @@ let bD=Aa;function Ug(e,n,t,i,r){if(e=te(e),Array.isArray(e))for(let o=0;ot()),this.destroyCbs=null}onDestroy(n){this.destroyCbs.push(n)}}class zg extends KD{constructor(n){super(),this.moduleType=n}create(n){return new zD(this.moduleType,n)}}class Hk extends Xo{constructor(n,t,i){super(),this.componentFactoryResolver=new Tg(this),this.instance=null;const r=new Wy([...n,{provide:Xo,useValue:this},{provide:Gl,useValue:this.componentFactoryResolver}],t||Qu(),i,new Set(["environment"]));this.injector=r,r.resolveInjectorInitializers()}destroy(){this.injector.destroy()}onDestroy(n){this.injector.onDestroy(n)}}function bd(e,n,t=null){return new Hk(e,n,t).injector} + */class YD extends Xo{constructor(n,t){super(),this._parent=t,this._bootstrapComponents=[],this.destroyCbs=[],this.componentFactoryResolver=new Tg(this);const i=Mn(n);this._bootstrapComponents=xr(i.bootstrap),this._r3Injector=P0(n,t,[{provide:Xo,useValue:this},{provide:Gl,useValue:this.componentFactoryResolver}],Ve(n),new Set(["environment"])),this._r3Injector.resolveInjectorInitializers(),this.instance=this._r3Injector.get(n)}get injector(){return this._r3Injector}destroy(){const n=this._r3Injector;!n.destroyed&&n.destroy(),this.destroyCbs.forEach(t=>t()),this.destroyCbs=null}onDestroy(n){this.destroyCbs.push(n)}}class Yg extends zD{constructor(n){super(),this.moduleType=n}create(n){return new YD(this.moduleType,n)}}class BO extends Xo{constructor(n,t,i){super(),this.componentFactoryResolver=new Tg(this),this.instance=null;const r=new Wy([...n,{provide:Xo,useValue:this},{provide:Gl,useValue:this.componentFactoryResolver}],t||Qu(),i,new Set(["environment"]));this.injector=r,r.resolveInjectorInitializers()}destroy(){this.injector.destroy()}onDestroy(n){this.injector.onDestroy(n)}}function bd(e,n,t=null){return new BO(e,n,t).injector} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */let Bk=(()=>{class e{constructor(t){this._injector=t,this.cachedInjectors=new Map}getOrCreateStandaloneInjector(t){if(!t.standalone)return null;if(!this.cachedInjectors.has(t.id)){const i=jy(0,t.type),r=i.length>0?bd([i],this._injector,`Standalone[${t.type.name}]`):null;this.cachedInjectors.set(t.id,r)}return this.cachedInjectors.get(t.id)}ngOnDestroy(){try{for(const t of this.cachedInjectors.values())null!==t&&t.destroy()}finally{this.cachedInjectors.clear()}}}return e.\u0275prov=G({token:e,providedIn:"environment",factory:()=>new e(L(lo))}),e})();function YD(e){e.getStandaloneInjector=n=>n.get(Bk).getOrCreateStandaloneInjector(e)} + */let HO=(()=>{class e{constructor(t){this._injector=t,this.cachedInjectors=new Map}getOrCreateStandaloneInjector(t){if(!t.standalone)return null;if(!this.cachedInjectors.has(t.id)){const i=jy(0,t.type),r=i.length>0?bd([i],this._injector,`Standalone[${t.type.name}]`):null;this.cachedInjectors.set(t.id,r)}return this.cachedInjectors.get(t.id)}ngOnDestroy(){try{for(const t of this.cachedInjectors.values())null!==t&&t.destroy()}finally{this.cachedInjectors.clear()}}}return e.\u0275prov=G({token:e,providedIn:"environment",factory:()=>new e(L(lo))}),e})();function KD(e){e.getStandaloneInjector=n=>n.get(HO).getOrCreateStandaloneInjector(e)} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */function Cd(e,n,t,i,r,o){return function r1(e,n,t,i,r,o,s,a){const l=n+t;return function hd(e,n,t,i,r){const o=Jo(e,n,t,i);return mn(e,n+2,r)||o}(e,l,r,o,s)?or(e,l+3,a?i.call(a,r,o,s):i(r,o,s)):ac(e,l+3)}(k(),rn(),e,n,t,i,r,o)}function ac(e,n){const t=e[n];return t===ae?void 0:t} + */function Cd(e,n,t,i,r,o){return function r1(e,n,t,i,r,o,s,a){const l=n+t;return function hd(e,n,t,i,r){const o=Zo(e,n,t,i);return mn(e,n+2,r)||o}(e,l,r,o,s)?or(e,l+3,a?i.call(a,r,o,s):i(r,o,s)):ac(e,l+3)}(O(),rn(),e,n,t,i,r,o)}function ac(e,n){const t=e[n];return t===ae?void 0:t} /** * @license * Copyright Google LLC All Rights Reserved. @@ -839,56 +839,56 @@ function xk(e,n,t){const i=be();if(i.firstCreatePass){const r=Jn(e);Ug(t,i.data, * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -function wd(e,n){const t=be();let i;const r=e+22;t.firstCreatePass?(i=function tR(e,n){if(n)for(let t=n.length-1;t>=0;t--){const i=n[t];if(e===i.name)return i}}(n,t.pipeRegistry),t.data[r]=i,i.onDestroy&&(t.destroyHooks||(t.destroyHooks=[])).push(r,i.onDestroy)):i=t.data[r];const o=i.factory||(i.factory=Nr(i.type)),s=Hn(C);try{const a=ea(!1),l=o();return ea(a),function eO(e,n,t,i){t>=e.data.length&&(e.data[t]=null,e.blueprint[t]=null),n[t]=i}(t,k(),r,l),l}finally{Hn(s)}}function Sd(e,n,t,i){const r=e+22,o=k(),s=io(o,r);return function lc(e,n){return e[1].data[n].pure} +function wd(e,n){const t=be();let i;const r=e+22;t.firstCreatePass?(i=function tx(e,n){if(n)for(let t=n.length-1;t>=0;t--){const i=n[t];if(e===i.name)return i}}(n,t.pipeRegistry),t.data[r]=i,i.onDestroy&&(t.destroyHooks||(t.destroyHooks=[])).push(r,i.onDestroy)):i=t.data[r];const o=i.factory||(i.factory=Er(i.type)),s=Bn(C);try{const a=ea(!1),l=o();return ea(a),function ek(e,n,t,i){t>=e.data.length&&(e.data[t]=null,e.blueprint[t]=null),n[t]=i}(t,O(),r,l),l}finally{Bn(s)}}function Sd(e,n,t,i){const r=e+22,o=O(),s=io(o,r);return function lc(e,n){return e[1].data[n].pure} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */(o,r)?function i1(e,n,t,i,r,o,s){const a=n+t;return Jo(e,a,r,o)?or(e,a+2,s?i.call(s,r,o):i(r,o)):ac(e,a+2)}(o,rn(),n,s.transform,t,i,s):s.transform(t,i)}function qg(e){return n=>{setTimeout(e,void 0,n)}}const ue=class sR extends Ue{constructor(n=!1){super(),this.__isAsync=n}emit(n){super.next(n)}subscribe(n,t,i){let r=n,o=t||(()=>null),s=i;if(n&&"object"==typeof n){const l=n;r=l.next?.bind(l),o=l.error?.bind(l),s=l.complete?.bind(l)}this.__isAsync&&(o=qg(o),r&&(r=qg(r)),s&&(s=qg(s)));const a=super.subscribe({next:r,error:o,complete:s});return n instanceof Ct&&n.add(a),a}}; + */(o,r)?function i1(e,n,t,i,r,o,s){const a=n+t;return Zo(e,a,r,o)?or(e,a+2,s?i.call(s,r,o):i(r,o)):ac(e,a+2)}(o,rn(),n,s.transform,t,i,s):s.transform(t,i)}function qg(e){return n=>{setTimeout(e,void 0,n)}}const ue=class sx extends Ue{constructor(n=!1){super(),this.__isAsync=n}emit(n){super.next(n)}subscribe(n,t,i){let r=n,o=t||(()=>null),s=i;if(n&&"object"==typeof n){const l=n;r=l.next?.bind(l),o=l.error?.bind(l),s=l.complete?.bind(l)}this.__isAsync&&(o=qg(o),r&&(r=qg(r)),s&&(s=qg(s)));const a=super.subscribe({next:r,error:o,complete:s});return n instanceof Ct&&n.add(a),a}}; /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */function aR(){return this._results[qo()]()}class Jg{constructor(n=!1){this._emitDistinctChangesOnly=n,this.dirty=!0,this._results=[],this._changesDetected=!1,this._changes=null,this.length=0,this.first=void 0,this.last=void 0;const t=qo(),i=Jg.prototype;i[t]||(i[t]=aR)}get changes(){return this._changes||(this._changes=new ue)}get(n){return this._results[n]}map(n){return this._results.map(n)}filter(n){return this._results.filter(n)}find(n){return this._results.find(n)}reduce(n,t){return this._results.reduce(n,t)}forEach(n){this._results.forEach(n)}some(n){return this._results.some(n)}toArray(){return this._results.slice()}toString(){return this._results.toString()}reset(n,t){const i=this;i.dirty=!1;const r=Zn(n);(this._changesDetected=!function bN(e,n,t){if(e.length!==n.length)return!1;for(let i=0;i{class e{}return e.__NG_ELEMENT_ID__=uR,e})();const lR=bt,cR=class extends lR{constructor(n,t,i){super(),this._declarationLView=n,this._declarationTContainer=t,this.elementRef=i}createEmbeddedView(n,t){const i=this._declarationTContainer.tViews,r=sd(this._declarationLView,i,n,16,null,i.declTNode,null,null,null,null,t||null);r[17]=this._declarationLView[this._declarationTContainer.index];const s=this._declarationLView[19];return null!==s&&(r[19]=s.createEmbeddedView(i)),vg(i,r,n),new ql(r)}};function uR(){return Ed(wt(),k())}function Ed(e,n){return 4&e.type?new cR(n,e,ua(e,n)):null} + */let bt=(()=>{class e{}return e.__NG_ELEMENT_ID__=ux,e})();const lx=bt,cx=class extends lx{constructor(n,t,i){super(),this._declarationLView=n,this._declarationTContainer=t,this.elementRef=i}createEmbeddedView(n,t){const i=this._declarationTContainer.tViews,r=sd(this._declarationLView,i,n,16,null,i.declTNode,null,null,null,null,t||null);r[17]=this._declarationLView[this._declarationTContainer.index];const s=this._declarationLView[19];return null!==s&&(r[19]=s.createEmbeddedView(i)),vg(i,r,n),new ql(r)}};function ux(){return Md(wt(),O())}function Md(e,n){return 4&e.type?new cx(n,e,ua(e,n)):null} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */let Bi=(()=>{class e{}return e.__NG_ELEMENT_ID__=dR,e})();function dR(){return c1(wt(),k())}const fR=Bi,a1=class extends fR{constructor(n,t,i){super(),this._lContainer=n,this._hostTNode=t,this._hostLView=i}get element(){return ua(this._hostTNode,this._hostLView)}get injector(){return new vt(this._hostTNode,this._hostLView)}get parentInjector(){const n=ki(this._hostTNode,this._hostLView);if($u(n)){const t=so(n,this._hostLView),i=oo(n);return new vt(t[1].data[i+8],t)}return new vt(null,this._hostLView)}clear(){for(;this.length>0;)this.remove(this.length-1)}get(n){const t=l1(this._lContainer);return null!==t&&t[n]||null}get length(){return this._lContainer.length-10}createEmbeddedView(n,t,i){let r,o;"number"==typeof i?r=i:null!=i&&(r=i.index,o=i.injector);const s=n.createEmbeddedView(t||{},o);return this.insert(s,r),s}createComponent(n,t,i,r,o){const s=n&&!function kl(e){return"function"==typeof e} + */let Hi=(()=>{class e{}return e.__NG_ELEMENT_ID__=dx,e})();function dx(){return c1(wt(),O())}const fx=Hi,a1=class extends fx{constructor(n,t,i){super(),this._lContainer=n,this._hostTNode=t,this._hostLView=i}get element(){return ua(this._hostTNode,this._hostLView)}get injector(){return new vt(this._hostTNode,this._hostLView)}get parentInjector(){const n=Oi(this._hostTNode,this._hostLView);if($u(n)){const t=so(n,this._hostLView),i=oo(n);return new vt(t[1].data[i+8],t)}return new vt(null,this._hostLView)}clear(){for(;this.length>0;)this.remove(this.length-1)}get(n){const t=l1(this._lContainer);return null!==t&&t[n]||null}get length(){return this._lContainer.length-10}createEmbeddedView(n,t,i){let r,o;"number"==typeof i?r=i:null!=i&&(r=i.index,o=i.injector);const s=n.createEmbeddedView(t||{},o);return this.insert(s,r),s}createComponent(n,t,i,r,o){const s=n&&!function Ol(e){return"function"==typeof e} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */(n);let a;if(s)a=t;else{const p=t||{};a=p.index,i=p.injector,r=p.projectableNodes,o=p.environmentInjector||p.ngModuleRef}const l=s?n:new Jl(Re(n)),u=i||this.parentInjector;if(!o&&null==l.ngModule){const m=(s?u:this.parentInjector).get(lo,null);m&&(o=m)}const f=l.create(u,r,void 0,o);return this.insert(f.hostView,a),f}insert(n,t){const i=n._lView,r=i[1];if(function $h(e){return qn(e[3])}(i)){const f=this.indexOf(n);if(-1!==f)this.detach(f);else{const p=i[3],m=new a1(p,p[6],p[3]);m.detach(m.indexOf(n))}}const o=this._adjustIndex(t),s=this._lContainer;!function _A(e,n,t,i){const r=10+i,o=t.length;i>0&&(t[r-1][4]=n),i0&&(t[r-1][4]=n),i0)i.push(s[a/2]);else{const u=o[a+1],f=n[-l];for(let p=10;p0)i.push(s[a/2]);else{const u=o[a+1],f=n[-l];for(let p=10;p{class e{constructor(t){this.appInits=t,this.resolve=Td,this.reject=Td,this.initialized=!1,this.done=!1,this.donePromise=new Promise((i,r)=>{this.resolve=i,this.reject=r})}runInitializers(){if(this.initialized)return;const t=[],i=()=>{this.done=!0,this.resolve()};if(this.appInits)for(let r=0;r{o.subscribe({complete:a,error:l})});t.push(s)}}Promise.all(t).then(()=>{i()}).catch(r=>{this.reject(r)}),0===t.length&&i(),this.initialized=!0}}return e.\u0275fac=function(t){return new(t||e)(L(Ad,8))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(); + */const Id=new q("Application Initializer");let Ad=(()=>{class e{constructor(t){this.appInits=t,this.resolve=Td,this.reject=Td,this.initialized=!1,this.done=!1,this.donePromise=new Promise((i,r)=>{this.resolve=i,this.reject=r})}runInitializers(){if(this.initialized)return;const t=[],i=()=>{this.done=!0,this.resolve()};if(this.appInits)for(let r=0;r{o.subscribe({complete:a,error:l})});t.push(s)}}Promise.all(t).then(()=>{i()}).catch(r=>{this.reject(r)}),0===t.length&&i(),this.initialized=!0}}return e.\u0275fac=function(t){return new(t||e)(L(Id,8))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(); /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */const uc=new q("AppId",{providedIn:"root",factory:function R1(){return`${am()}${am()}${am()}`}});function am(){return String.fromCharCode(97+Math.floor(25*Math.random()))}const x1=new q("Platform Initializer"),dc=new q("Platform ID",{providedIn:"platform",factory:()=>"unknown"}),F1=new q("appBootstrapListener"); + */const uc=new q("AppId",{providedIn:"root",factory:function x1(){return`${am()}${am()}${am()}`}});function am(){return String.fromCharCode(97+Math.floor(25*Math.random()))}const R1=new q("Platform Initializer"),dc=new q("Platform ID",{providedIn:"platform",factory:()=>"unknown"}),P1=new q("appBootstrapListener"); /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */let BR=(()=>{class e{log(t){console.log(t)}warn(t){console.warn(t)}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"platform"}),e})(); + */let Hx=(()=>{class e{log(t){console.log(t)}warn(t){console.warn(t)}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"platform"}),e})(); /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */const Pr=new q("LocaleId",{providedIn:"root",factory:()=>St(Pr,X.Optional|X.SkipSelf)||function jR(){return typeof $localize<"u"&&$localize.locale||Aa}()}); + */const Fr=new q("LocaleId",{providedIn:"root",factory:()=>St(Fr,X.Optional|X.SkipSelf)||function jx(){return typeof $localize<"u"&&$localize.locale||Ia}()}); /** * @license * Copyright Google LLC All Rights Reserved. @@ -960,7 +960,7 @@ function Td(...e){} * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -class UR{constructor(n,t){this.ngModuleFactory=n,this.componentFactories=t}}let lm=(()=>{class e{compileModuleSync(t){return new zg(t)}compileModuleAsync(t){return Promise.resolve(this.compileModuleSync(t))}compileModuleAndAllComponentsSync(t){const i=this.compileModuleSync(t),o=Rr(En(t).declarations).reduce((s,a)=>{const l=Re(a);return l&&s.push(new Jl(l)),s},[]);return new UR(i,o)}compileModuleAndAllComponentsAsync(t){return Promise.resolve(this.compileModuleAndAllComponentsSync(t))}clearCache(){}clearCacheFor(t){}getModuleId(t){}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(); +class Ux{constructor(n,t){this.ngModuleFactory=n,this.componentFactories=t}}let lm=(()=>{class e{compileModuleSync(t){return new Yg(t)}compileModuleAsync(t){return Promise.resolve(this.compileModuleSync(t))}compileModuleAndAllComponentsSync(t){const i=this.compileModuleSync(t),o=xr(Mn(t).declarations).reduce((s,a)=>{const l=xe(a);return l&&s.push(new Zl(l)),s},[]);return new Ux(i,o)}compileModuleAndAllComponentsAsync(t){return Promise.resolve(this.compileModuleAndAllComponentsSync(t))}clearCache(){}clearCacheFor(t){}getModuleId(t){}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(); /** * @license * Copyright Google LLC All Rights Reserved. @@ -968,7 +968,7 @@ class UR{constructor(n,t){this.ngModuleFactory=n,this.componentFactories=t}}let * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -const KR=(()=>Promise.resolve(0))();function cm(e){typeof Zone>"u"?KR.then(()=>{e&&e.apply(null,null)}):Zone.current.scheduleMicroTask("scheduleMicrotask",e)} +const zx=(()=>Promise.resolve(0))();function cm(e){typeof Zone>"u"?zx.then(()=>{e&&e.apply(null,null)}):Zone.current.scheduleMicroTask("scheduleMicrotask",e)} /** * @license * Copyright Google LLC All Rights Reserved. @@ -983,14 +983,14 @@ const KR=(()=>Promise.resolve(0))();function cm(e){typeof Zone>"u"?KR.then(()=>{ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -class ze{constructor({enableLongStackTrace:n=!1,shouldCoalesceEventChangeDetection:t=!1,shouldCoalesceRunChangeDetection:i=!1}){if(this.hasPendingMacrotasks=!1,this.hasPendingMicrotasks=!1,this.isStable=!0,this.onUnstable=new ue(!1),this.onMicrotaskEmpty=new ue(!1),this.onStable=new ue(!1),this.onError=new ue(!1),typeof Zone>"u")throw new P(908,!1);Zone.assertZonePatched();const r=this;if(r._nesting=0,r._outer=r._inner=Zone.current,Zone.AsyncStackTaggingZoneSpec){const o=Zone.AsyncStackTaggingZoneSpec;r._inner=r._inner.fork(new o("Angular"))}Zone.TaskTrackingZoneSpec&&(r._inner=r._inner.fork(new Zone.TaskTrackingZoneSpec)),n&&Zone.longStackTraceZoneSpec&&(r._inner=r._inner.fork(Zone.longStackTraceZoneSpec)),r.shouldCoalesceEventChangeDetection=!i&&t,r.shouldCoalesceRunChangeDetection=i,r.lastRequestAnimationFrameId=-1,r.nativeRequestAnimationFrame=function zR(){let e=We.requestAnimationFrame,n=We.cancelAnimationFrame;if(typeof Zone<"u"&&e&&n){const t=e[Zone.__symbol__("OriginalDelegate")];t&&(e=t);const i=n[Zone.__symbol__("OriginalDelegate")];i&&(n=i)}return{nativeRequestAnimationFrame:e,nativeCancelAnimationFrame:n}}().nativeRequestAnimationFrame,function JR(e){const n=()=>{!function qR(e){e.isCheckStableRunning||-1!==e.lastRequestAnimationFrameId||(e.lastRequestAnimationFrameId=e.nativeRequestAnimationFrame.call(We,()=>{e.fakeTopEventTask||(e.fakeTopEventTask=Zone.root.scheduleEventTask("fakeTopEventTask",()=>{e.lastRequestAnimationFrameId=-1,dm(e),e.isCheckStableRunning=!0,um(e),e.isCheckStableRunning=!1},void 0,()=>{},()=>{})),e.fakeTopEventTask.invoke()}),dm(e))}(e)};e._inner=e._inner.fork({name:"angular",properties:{isAngularZone:!0},onInvokeTask:(t,i,r,o,s,a)=>{try{return V1(e),t.invokeTask(r,o,s,a)}finally{(e.shouldCoalesceEventChangeDetection&&"eventTask"===o.type||e.shouldCoalesceRunChangeDetection)&&n(),H1(e)}},onInvoke:(t,i,r,o,s,a,l)=>{try{return V1(e),t.invoke(r,o,s,a,l)}finally{e.shouldCoalesceRunChangeDetection&&n(),H1(e)}},onHasTask:(t,i,r,o)=>{t.hasTask(r,o),i===r&&("microTask"==o.change?(e._hasPendingMicrotasks=o.microTask,dm(e),um(e)):"macroTask"==o.change&&(e.hasPendingMacrotasks=o.macroTask))},onHandleError:(t,i,r,o)=>(t.handleError(r,o),e.runOutsideAngular(()=>e.onError.emit(o)),!1)})}(r)}static isInAngularZone(){return typeof Zone<"u"&&!0===Zone.current.get("isAngularZone")}static assertInAngularZone(){if(!ze.isInAngularZone())throw new P(909,!1)}static assertNotInAngularZone(){if(ze.isInAngularZone())throw new P(909,!1)}run(n,t,i){return this._inner.run(n,t,i)}runTask(n,t,i,r){const o=this._inner,s=o.scheduleEventTask("NgZoneEvent: "+r,n,YR,Td,Td);try{return o.runTask(s,t,i)}finally{o.cancelTask(s)}}runGuarded(n,t,i){return this._inner.runGuarded(n,t,i)}runOutsideAngular(n){return this._outer.run(n)}}const YR={};function um(e){if(0==e._nesting&&!e.hasPendingMicrotasks&&!e.isStable)try{e._nesting++,e.onMicrotaskEmpty.emit(null)}finally{if(e._nesting--,!e.hasPendingMicrotasks)try{e.runOutsideAngular(()=>e.onStable.emit(null))}finally{e.isStable=!0}}}function dm(e){e.hasPendingMicrotasks=!!(e._hasPendingMicrotasks||(e.shouldCoalesceEventChangeDetection||e.shouldCoalesceRunChangeDetection)&&-1!==e.lastRequestAnimationFrameId)}function V1(e){e._nesting++,e.isStable&&(e.isStable=!1,e.onUnstable.emit(null))}function H1(e){e._nesting--,um(e)}class ZR{constructor(){this.hasPendingMicrotasks=!1,this.hasPendingMacrotasks=!1,this.isStable=!0,this.onUnstable=new ue,this.onMicrotaskEmpty=new ue,this.onStable=new ue,this.onError=new ue}run(n,t,i){return n.apply(t,i)}runGuarded(n,t,i){return n.apply(t,i)}runOutsideAngular(n){return n()}runTask(n,t,i,r){return n.apply(t,i)}} +class Ye{constructor({enableLongStackTrace:n=!1,shouldCoalesceEventChangeDetection:t=!1,shouldCoalesceRunChangeDetection:i=!1}){if(this.hasPendingMacrotasks=!1,this.hasPendingMicrotasks=!1,this.isStable=!0,this.onUnstable=new ue(!1),this.onMicrotaskEmpty=new ue(!1),this.onStable=new ue(!1),this.onError=new ue(!1),typeof Zone>"u")throw new F(908,!1);Zone.assertZonePatched();const r=this;if(r._nesting=0,r._outer=r._inner=Zone.current,Zone.AsyncStackTaggingZoneSpec){const o=Zone.AsyncStackTaggingZoneSpec;r._inner=r._inner.fork(new o("Angular"))}Zone.TaskTrackingZoneSpec&&(r._inner=r._inner.fork(new Zone.TaskTrackingZoneSpec)),n&&Zone.longStackTraceZoneSpec&&(r._inner=r._inner.fork(Zone.longStackTraceZoneSpec)),r.shouldCoalesceEventChangeDetection=!i&&t,r.shouldCoalesceRunChangeDetection=i,r.lastRequestAnimationFrameId=-1,r.nativeRequestAnimationFrame=function Yx(){let e=We.requestAnimationFrame,n=We.cancelAnimationFrame;if(typeof Zone<"u"&&e&&n){const t=e[Zone.__symbol__("OriginalDelegate")];t&&(e=t);const i=n[Zone.__symbol__("OriginalDelegate")];i&&(n=i)}return{nativeRequestAnimationFrame:e,nativeCancelAnimationFrame:n}}().nativeRequestAnimationFrame,function Zx(e){const n=()=>{!function qx(e){e.isCheckStableRunning||-1!==e.lastRequestAnimationFrameId||(e.lastRequestAnimationFrameId=e.nativeRequestAnimationFrame.call(We,()=>{e.fakeTopEventTask||(e.fakeTopEventTask=Zone.root.scheduleEventTask("fakeTopEventTask",()=>{e.lastRequestAnimationFrameId=-1,dm(e),e.isCheckStableRunning=!0,um(e),e.isCheckStableRunning=!1},void 0,()=>{},()=>{})),e.fakeTopEventTask.invoke()}),dm(e))}(e)};e._inner=e._inner.fork({name:"angular",properties:{isAngularZone:!0},onInvokeTask:(t,i,r,o,s,a)=>{try{return V1(e),t.invokeTask(r,o,s,a)}finally{(e.shouldCoalesceEventChangeDetection&&"eventTask"===o.type||e.shouldCoalesceRunChangeDetection)&&n(),B1(e)}},onInvoke:(t,i,r,o,s,a,l)=>{try{return V1(e),t.invoke(r,o,s,a,l)}finally{e.shouldCoalesceRunChangeDetection&&n(),B1(e)}},onHasTask:(t,i,r,o)=>{t.hasTask(r,o),i===r&&("microTask"==o.change?(e._hasPendingMicrotasks=o.microTask,dm(e),um(e)):"macroTask"==o.change&&(e.hasPendingMacrotasks=o.macroTask))},onHandleError:(t,i,r,o)=>(t.handleError(r,o),e.runOutsideAngular(()=>e.onError.emit(o)),!1)})}(r)}static isInAngularZone(){return typeof Zone<"u"&&!0===Zone.current.get("isAngularZone")}static assertInAngularZone(){if(!Ye.isInAngularZone())throw new F(909,!1)}static assertNotInAngularZone(){if(Ye.isInAngularZone())throw new F(909,!1)}run(n,t,i){return this._inner.run(n,t,i)}runTask(n,t,i,r){const o=this._inner,s=o.scheduleEventTask("NgZoneEvent: "+r,n,Kx,Td,Td);try{return o.runTask(s,t,i)}finally{o.cancelTask(s)}}runGuarded(n,t,i){return this._inner.runGuarded(n,t,i)}runOutsideAngular(n){return this._outer.run(n)}}const Kx={};function um(e){if(0==e._nesting&&!e.hasPendingMicrotasks&&!e.isStable)try{e._nesting++,e.onMicrotaskEmpty.emit(null)}finally{if(e._nesting--,!e.hasPendingMicrotasks)try{e.runOutsideAngular(()=>e.onStable.emit(null))}finally{e.isStable=!0}}}function dm(e){e.hasPendingMicrotasks=!!(e._hasPendingMicrotasks||(e.shouldCoalesceEventChangeDetection||e.shouldCoalesceRunChangeDetection)&&-1!==e.lastRequestAnimationFrameId)}function V1(e){e._nesting++,e.isStable&&(e.isStable=!1,e.onUnstable.emit(null))}function B1(e){e._nesting--,um(e)}class Jx{constructor(){this.hasPendingMicrotasks=!1,this.hasPendingMacrotasks=!1,this.isStable=!0,this.onUnstable=new ue,this.onMicrotaskEmpty=new ue,this.onStable=new ue,this.onError=new ue}run(n,t,i){return n.apply(t,i)}runGuarded(n,t,i){return n.apply(t,i)}runOutsideAngular(n){return n()}runTask(n,t,i,r){return n.apply(t,i)}} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */const B1=new q(""),Od=new q("");let pm,fm=(()=>{class e{constructor(t,i,r){this._ngZone=t,this.registry=i,this._pendingCount=0,this._isZoneStable=!0,this._didWork=!1,this._callbacks=[],this.taskTrackingZone=null,pm||(function QR(e){pm=e}(r),r.addToWindow(i)),this._watchAngularEvents(),t.run(()=>{this.taskTrackingZone=typeof Zone>"u"?null:Zone.current.get("TaskTrackingZone")})}_watchAngularEvents(){this._ngZone.onUnstable.subscribe({next:()=>{this._didWork=!0,this._isZoneStable=!1}}),this._ngZone.runOutsideAngular(()=>{this._ngZone.onStable.subscribe({next:()=>{ze.assertNotInAngularZone(),cm(()=>{this._isZoneStable=!0,this._runCallbacksIfReady()})}})})}increasePendingRequestCount(){return this._pendingCount+=1,this._didWork=!0,this._pendingCount}decreasePendingRequestCount(){if(this._pendingCount-=1,this._pendingCount<0)throw new Error("pending async requests below zero");return this._runCallbacksIfReady(),this._pendingCount}isStable(){return this._isZoneStable&&0===this._pendingCount&&!this._ngZone.hasPendingMacrotasks}_runCallbacksIfReady(){if(this.isStable())cm(()=>{for(;0!==this._callbacks.length;){let t=this._callbacks.pop();clearTimeout(t.timeoutId),t.doneCb(this._didWork)}this._didWork=!1});else{let t=this.getPendingTasks();this._callbacks=this._callbacks.filter(i=>!i.updateCb||!i.updateCb(t)||(clearTimeout(i.timeoutId),!1)),this._didWork=!0}}getPendingTasks(){return this.taskTrackingZone?this.taskTrackingZone.macroTasks.map(t=>({source:t.source,creationLocation:t.creationLocation,data:t.data})):[]}addCallback(t,i,r){let o=-1;i&&i>0&&(o=setTimeout(()=>{this._callbacks=this._callbacks.filter(s=>s.timeoutId!==o),t(this._didWork,this.getPendingTasks())},i)),this._callbacks.push({doneCb:t,timeoutId:o,updateCb:r})}whenStable(t,i,r){if(r&&!this.taskTrackingZone)throw new Error('Task tracking zone is required when passing an update callback to whenStable(). Is "zone.js/plugins/task-tracking" loaded?');this.addCallback(t,i,r),this._runCallbacksIfReady()}getPendingRequestCount(){return this._pendingCount}registerApplication(t){this.registry.registerApplication(t,this)}unregisterApplication(t){this.registry.unregisterApplication(t)}findProviders(t,i,r){return[]}}return e.\u0275fac=function(t){return new(t||e)(L(ze),L(hm),L(Od))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(),hm=(()=>{class e{constructor(){this._applications=new Map}registerApplication(t,i){this._applications.set(t,i)}unregisterApplication(t){this._applications.delete(t)}unregisterAllApplications(){this._applications.clear()}getTestability(t){return this._applications.get(t)||null}getAllTestabilities(){return Array.from(this._applications.values())}getAllRootElements(){return Array.from(this._applications.keys())}findTestabilityInTree(t,i=!0){return pm?.findTestabilityInTree(this,t,i)??null}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"platform"}),e})(),po=null;const j1=new q("AllowMultipleToken"),gm=new q("PlatformDestroyListeners");class $1{constructor(n,t){this.name=n,this.token=t}}function G1(e,n,t=[]){const i=`Platform: ${n}`,r=new q(i);return(o=[])=>{let s=mm();if(!s||s.injector.get(j1,!1)){const a=[...t,...o,{provide:r,useValue:!0}];e?e(a):function tx(e){if(po&&!po.get(j1,!1))throw new P(400,!1);po=e;const n=e.get(K1);(function U1(e){const n=e.get(x1,null);n&&n.forEach(t=>t())})(e)}(function W1(e=[],n){return gn.create({name:n,providers:[{provide:Ip,useValue:"platform"},{provide:gm,useValue:new Set([()=>po=null])},...e]})}(a,i))}return function ix(e){const n=mm();if(!n)throw new P(401,!1);return n}()}}function mm(){return po?.get(K1)??null}let K1=(()=>{class e{constructor(t){this._injector=t,this._modules=[],this._destroyListeners=[],this._destroyed=!1}bootstrapModuleFactory(t,i){const r=function Y1(e,n){let t;return t="noop"===e?new ZR:("zone.js"===e?void 0:e)||new ze(n),t}(i?.ngZone,function z1(e){return{enableLongStackTrace:!1,shouldCoalesceEventChangeDetection:!(!e||!e.ngZoneEventCoalescing)||!1,shouldCoalesceRunChangeDetection:!(!e||!e.ngZoneRunCoalescing)||!1}}(i)),o=[{provide:ze,useValue:r}];return r.run(()=>{const s=gn.create({providers:o,parent:this.injector,name:t.moduleType.name}),a=t.create(s),l=a.injector.get(da,null);if(!l)throw new P(402,!1);return r.runOutsideAngular(()=>{const u=r.onError.subscribe({next:f=>{l.handleError(f)}});a.onDestroy(()=>{kd(this._modules,a),u.unsubscribe()})}),function q1(e,n,t){try{const i=t();return Xl(i)?i.catch(r=>{throw n.runOutsideAngular(()=>e.handleError(r)),r}):i}catch(i){throw n.runOutsideAngular(()=>e.handleError(i)),i}}(l,r,()=>{const u=a.injector.get(Id);return u.runInitializers(),u.donePromise.then(()=>(function DD(e){Sn(e,"Expected localeId to be defined"),"string"==typeof e&&(bD=e.toLowerCase().replace(/_/g,"-"))}(a.injector.get(Pr,Aa)||Aa),this._moduleDoBootstrap(a),a))})})}bootstrapModule(t,i=[]){const r=J1({},i);return function XR(e,n,t){const i=new zg(t);return Promise.resolve(i)}(0,0,t).then(o=>this.bootstrapModuleFactory(o,r))}_moduleDoBootstrap(t){const i=t.injector.get(fc);if(t._bootstrapComponents.length>0)t._bootstrapComponents.forEach(r=>i.bootstrap(r));else{if(!t.instance.ngDoBootstrap)throw new P(403,!1);t.instance.ngDoBootstrap(i)}this._modules.push(t)}onDestroy(t){this._destroyListeners.push(t)}get injector(){return this._injector}destroy(){if(this._destroyed)throw new P(404,!1);this._modules.slice().forEach(i=>i.destroy()),this._destroyListeners.forEach(i=>i());const t=this._injector.get(gm,null);t&&(t.forEach(i=>i()),t.clear()),this._destroyed=!0}get destroyed(){return this._destroyed}}return e.\u0275fac=function(t){return new(t||e)(L(gn))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"platform"}),e})();function J1(e,n){return Array.isArray(n)?n.reduce(J1,e):{...e,...n}}let fc=(()=>{class e{constructor(t,i,r){this._zone=t,this._injector=i,this._exceptionHandler=r,this._bootstrapListeners=[],this._views=[],this._runningTick=!1,this._stable=!0,this._destroyed=!1,this._destroyListeners=[],this.componentTypes=[],this.components=[],this._onMicrotaskEmptySubscription=this._zone.onMicrotaskEmpty.subscribe({next:()=>{this._zone.run(()=>{this.tick()})}});const o=new je(a=>{this._stable=this._zone.isStable&&!this._zone.hasPendingMacrotasks&&!this._zone.hasPendingMicrotasks,this._zone.runOutsideAngular(()=>{a.next(this._stable),a.complete()})}),s=new je(a=>{let l;this._zone.runOutsideAngular(()=>{l=this._zone.onStable.subscribe(()=>{ze.assertNotInAngularZone(),cm(()=>{!this._stable&&!this._zone.hasPendingMacrotasks&&!this._zone.hasPendingMicrotasks&&(this._stable=!0,a.next(!0))})})});const u=this._zone.onUnstable.subscribe(()=>{ze.assertInAngularZone(),this._stable&&(this._stable=!1,this._zone.runOutsideAngular(()=>{a.next(!1)}))});return()=>{l.unsubscribe(),u.unsubscribe()}});this.isStable=function fh(...e){const n=en(e),t=function Si(e,n){return"number"==typeof Ln(e)?e.pop():n}(e,1/0),i=e;return i.length?1===i.length?ut(i[0]):Se(t)(gt(i,n)):Xt}(o,s.pipe(function hh(e={}){const{connector:n=(()=>new Ue),resetOnError:t=!0,resetOnComplete:i=!0,resetOnRefCountZero:r=!0}=e;return o=>{let s,a,l,u=0,f=!1,p=!1;const m=()=>{a?.unsubscribe(),a=void 0},v=()=>{m(),s=l=void 0,f=p=!1},y=()=>{const D=s;v(),D?.unsubscribe()};return qe((D,w)=>{u++,!p&&!f&&m();const M=l=l??n();w.add(()=>{u--,0===u&&!p&&!f&&(a=il(y,r))}),M.subscribe(w),!s&&u>0&&(s=new vr({next:I=>M.next(I),error:I=>{p=!0,m(),a=il(v,t,I),M.error(I)},complete:()=>{f=!0,m(),a=il(v,i),M.complete()}}),ut(D).subscribe(s))})(o)}}()))}get destroyed(){return this._destroyed}get injector(){return this._injector}bootstrap(t,i){const r=t instanceof zy;if(!this._injector.get(Id).done)throw!r&&function zn(e){const n=Re(e)||Ut(e)||nn(e);return null!==n&&n.standalone}(t),new P(405,false);let s;s=r?t:this._injector.get(Gl).resolveComponentFactory(t),this.componentTypes.push(s.componentType);const a=function ex(e){return e.isBoundToModule}(s)?void 0:this._injector.get(Xo),u=s.create(gn.NULL,[],i||s.selector,a),f=u.location.nativeElement,p=u.injector.get(B1,null);return p?.registerApplication(f),u.onDestroy(()=>{this.detachView(u.hostView),kd(this.components,u),p?.unregisterApplication(f)}),this._loadComponent(u),u}tick(){if(this._runningTick)throw new P(101,!1);try{this._runningTick=!0;for(let t of this._views)t.detectChanges()}catch(t){this._zone.runOutsideAngular(()=>this._exceptionHandler.handleError(t))}finally{this._runningTick=!1}}attachView(t){const i=t;this._views.push(i),i.attachToAppRef(this)}detachView(t){const i=t;kd(this._views,i),i.detachFromAppRef()}_loadComponent(t){this.attachView(t.hostView),this.tick(),this.components.push(t),this._injector.get(F1,[]).concat(this._bootstrapListeners).forEach(r=>r(t))}ngOnDestroy(){if(!this._destroyed)try{this._destroyListeners.forEach(t=>t()),this._views.slice().forEach(t=>t.destroy()),this._onMicrotaskEmptySubscription.unsubscribe()}finally{this._destroyed=!0,this._views=[],this._bootstrapListeners=[],this._destroyListeners=[]}}onDestroy(t){return this._destroyListeners.push(t),()=>kd(this._destroyListeners,t)}destroy(){if(this._destroyed)throw new P(406,!1);const t=this._injector;t.destroy&&!t.destroyed&&t.destroy()}get viewCount(){return this._views.length}warnIfDestroyed(){}}return e.\u0275fac=function(t){return new(t||e)(L(ze),L(lo),L(da))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})();function kd(e,n){const t=e.indexOf(n);t>-1&&e.splice(t,1)} + */const H1=new q(""),kd=new q("");let pm,fm=(()=>{class e{constructor(t,i,r){this._ngZone=t,this.registry=i,this._pendingCount=0,this._isZoneStable=!0,this._didWork=!1,this._callbacks=[],this.taskTrackingZone=null,pm||(function Qx(e){pm=e}(r),r.addToWindow(i)),this._watchAngularEvents(),t.run(()=>{this.taskTrackingZone=typeof Zone>"u"?null:Zone.current.get("TaskTrackingZone")})}_watchAngularEvents(){this._ngZone.onUnstable.subscribe({next:()=>{this._didWork=!0,this._isZoneStable=!1}}),this._ngZone.runOutsideAngular(()=>{this._ngZone.onStable.subscribe({next:()=>{Ye.assertNotInAngularZone(),cm(()=>{this._isZoneStable=!0,this._runCallbacksIfReady()})}})})}increasePendingRequestCount(){return this._pendingCount+=1,this._didWork=!0,this._pendingCount}decreasePendingRequestCount(){if(this._pendingCount-=1,this._pendingCount<0)throw new Error("pending async requests below zero");return this._runCallbacksIfReady(),this._pendingCount}isStable(){return this._isZoneStable&&0===this._pendingCount&&!this._ngZone.hasPendingMacrotasks}_runCallbacksIfReady(){if(this.isStable())cm(()=>{for(;0!==this._callbacks.length;){let t=this._callbacks.pop();clearTimeout(t.timeoutId),t.doneCb(this._didWork)}this._didWork=!1});else{let t=this.getPendingTasks();this._callbacks=this._callbacks.filter(i=>!i.updateCb||!i.updateCb(t)||(clearTimeout(i.timeoutId),!1)),this._didWork=!0}}getPendingTasks(){return this.taskTrackingZone?this.taskTrackingZone.macroTasks.map(t=>({source:t.source,creationLocation:t.creationLocation,data:t.data})):[]}addCallback(t,i,r){let o=-1;i&&i>0&&(o=setTimeout(()=>{this._callbacks=this._callbacks.filter(s=>s.timeoutId!==o),t(this._didWork,this.getPendingTasks())},i)),this._callbacks.push({doneCb:t,timeoutId:o,updateCb:r})}whenStable(t,i,r){if(r&&!this.taskTrackingZone)throw new Error('Task tracking zone is required when passing an update callback to whenStable(). Is "zone.js/plugins/task-tracking" loaded?');this.addCallback(t,i,r),this._runCallbacksIfReady()}getPendingRequestCount(){return this._pendingCount}registerApplication(t){this.registry.registerApplication(t,this)}unregisterApplication(t){this.registry.unregisterApplication(t)}findProviders(t,i,r){return[]}}return e.\u0275fac=function(t){return new(t||e)(L(Ye),L(hm),L(kd))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(),hm=(()=>{class e{constructor(){this._applications=new Map}registerApplication(t,i){this._applications.set(t,i)}unregisterApplication(t){this._applications.delete(t)}unregisterAllApplications(){this._applications.clear()}getTestability(t){return this._applications.get(t)||null}getAllTestabilities(){return Array.from(this._applications.values())}getAllRootElements(){return Array.from(this._applications.keys())}findTestabilityInTree(t,i=!0){return pm?.findTestabilityInTree(this,t,i)??null}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"platform"}),e})(),po=null;const j1=new q("AllowMultipleToken"),gm=new q("PlatformDestroyListeners");class $1{constructor(n,t){this.name=n,this.token=t}}function G1(e,n,t=[]){const i=`Platform: ${n}`,r=new q(i);return(o=[])=>{let s=mm();if(!s||s.injector.get(j1,!1)){const a=[...t,...o,{provide:r,useValue:!0}];e?e(a):function tR(e){if(po&&!po.get(j1,!1))throw new F(400,!1);po=e;const n=e.get(z1);(function U1(e){const n=e.get(R1,null);n&&n.forEach(t=>t())})(e)}(function W1(e=[],n){return gn.create({name:n,providers:[{provide:Ap,useValue:"platform"},{provide:gm,useValue:new Set([()=>po=null])},...e]})}(a,i))}return function iR(e){const n=mm();if(!n)throw new F(401,!1);return n}()}}function mm(){return po?.get(z1)??null}let z1=(()=>{class e{constructor(t){this._injector=t,this._modules=[],this._destroyListeners=[],this._destroyed=!1}bootstrapModuleFactory(t,i){const r=function K1(e,n){let t;return t="noop"===e?new Jx:("zone.js"===e?void 0:e)||new Ye(n),t}(i?.ngZone,function Y1(e){return{enableLongStackTrace:!1,shouldCoalesceEventChangeDetection:!(!e||!e.ngZoneEventCoalescing)||!1,shouldCoalesceRunChangeDetection:!(!e||!e.ngZoneRunCoalescing)||!1}}(i)),o=[{provide:Ye,useValue:r}];return r.run(()=>{const s=gn.create({providers:o,parent:this.injector,name:t.moduleType.name}),a=t.create(s),l=a.injector.get(da,null);if(!l)throw new F(402,!1);return r.runOutsideAngular(()=>{const u=r.onError.subscribe({next:f=>{l.handleError(f)}});a.onDestroy(()=>{Od(this._modules,a),u.unsubscribe()})}),function q1(e,n,t){try{const i=t();return Xl(i)?i.catch(r=>{throw n.runOutsideAngular(()=>e.handleError(r)),r}):i}catch(i){throw n.runOutsideAngular(()=>e.handleError(i)),i}}(l,r,()=>{const u=a.injector.get(Ad);return u.runInitializers(),u.donePromise.then(()=>(function DD(e){Sn(e,"Expected localeId to be defined"),"string"==typeof e&&(bD=e.toLowerCase().replace(/_/g,"-"))}(a.injector.get(Fr,Ia)||Ia),this._moduleDoBootstrap(a),a))})})}bootstrapModule(t,i=[]){const r=Z1({},i);return function Xx(e,n,t){const i=new Yg(t);return Promise.resolve(i)}(0,0,t).then(o=>this.bootstrapModuleFactory(o,r))}_moduleDoBootstrap(t){const i=t.injector.get(fc);if(t._bootstrapComponents.length>0)t._bootstrapComponents.forEach(r=>i.bootstrap(r));else{if(!t.instance.ngDoBootstrap)throw new F(403,!1);t.instance.ngDoBootstrap(i)}this._modules.push(t)}onDestroy(t){this._destroyListeners.push(t)}get injector(){return this._injector}destroy(){if(this._destroyed)throw new F(404,!1);this._modules.slice().forEach(i=>i.destroy()),this._destroyListeners.forEach(i=>i());const t=this._injector.get(gm,null);t&&(t.forEach(i=>i()),t.clear()),this._destroyed=!0}get destroyed(){return this._destroyed}}return e.\u0275fac=function(t){return new(t||e)(L(gn))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"platform"}),e})();function Z1(e,n){return Array.isArray(n)?n.reduce(Z1,e):{...e,...n}}let fc=(()=>{class e{constructor(t,i,r){this._zone=t,this._injector=i,this._exceptionHandler=r,this._bootstrapListeners=[],this._views=[],this._runningTick=!1,this._stable=!0,this._destroyed=!1,this._destroyListeners=[],this.componentTypes=[],this.components=[],this._onMicrotaskEmptySubscription=this._zone.onMicrotaskEmpty.subscribe({next:()=>{this._zone.run(()=>{this.tick()})}});const o=new je(a=>{this._stable=this._zone.isStable&&!this._zone.hasPendingMacrotasks&&!this._zone.hasPendingMicrotasks,this._zone.runOutsideAngular(()=>{a.next(this._stable),a.complete()})}),s=new je(a=>{let l;this._zone.runOutsideAngular(()=>{l=this._zone.onStable.subscribe(()=>{Ye.assertNotInAngularZone(),cm(()=>{!this._stable&&!this._zone.hasPendingMacrotasks&&!this._zone.hasPendingMicrotasks&&(this._stable=!0,a.next(!0))})})});const u=this._zone.onUnstable.subscribe(()=>{Ye.assertInAngularZone(),this._stable&&(this._stable=!1,this._zone.runOutsideAngular(()=>{a.next(!1)}))});return()=>{l.unsubscribe(),u.unsubscribe()}});this.isStable=function fh(...e){const n=en(e),t=function Si(e,n){return"number"==typeof Ln(e)?e.pop():n}(e,1/0),i=e;return i.length?1===i.length?ut(i[0]):Se(t)(gt(i,n)):Xt}(o,s.pipe(function hh(e={}){const{connector:n=(()=>new Ue),resetOnError:t=!0,resetOnComplete:i=!0,resetOnRefCountZero:r=!0}=e;return o=>{let s,a,l,u=0,f=!1,p=!1;const m=()=>{a?.unsubscribe(),a=void 0},v=()=>{m(),s=l=void 0,f=p=!1},y=()=>{const D=s;v(),D?.unsubscribe()};return qe((D,w)=>{u++,!p&&!f&&m();const N=l=l??n();w.add(()=>{u--,0===u&&!p&&!f&&(a=il(y,r))}),N.subscribe(w),!s&&u>0&&(s=new vr({next:A=>N.next(A),error:A=>{p=!0,m(),a=il(v,t,A),N.error(A)},complete:()=>{f=!0,m(),a=il(v,i),N.complete()}}),ut(D).subscribe(s))})(o)}}()))}get destroyed(){return this._destroyed}get injector(){return this._injector}bootstrap(t,i){const r=t instanceof Yy;if(!this._injector.get(Ad).done)throw!r&&function Yn(e){const n=xe(e)||Ut(e)||nn(e);return null!==n&&n.standalone}(t),new F(405,false);let s;s=r?t:this._injector.get(Gl).resolveComponentFactory(t),this.componentTypes.push(s.componentType);const a=function eR(e){return e.isBoundToModule}(s)?void 0:this._injector.get(Xo),u=s.create(gn.NULL,[],i||s.selector,a),f=u.location.nativeElement,p=u.injector.get(H1,null);return p?.registerApplication(f),u.onDestroy(()=>{this.detachView(u.hostView),Od(this.components,u),p?.unregisterApplication(f)}),this._loadComponent(u),u}tick(){if(this._runningTick)throw new F(101,!1);try{this._runningTick=!0;for(let t of this._views)t.detectChanges()}catch(t){this._zone.runOutsideAngular(()=>this._exceptionHandler.handleError(t))}finally{this._runningTick=!1}}attachView(t){const i=t;this._views.push(i),i.attachToAppRef(this)}detachView(t){const i=t;Od(this._views,i),i.detachFromAppRef()}_loadComponent(t){this.attachView(t.hostView),this.tick(),this.components.push(t),this._injector.get(P1,[]).concat(this._bootstrapListeners).forEach(r=>r(t))}ngOnDestroy(){if(!this._destroyed)try{this._destroyListeners.forEach(t=>t()),this._views.slice().forEach(t=>t.destroy()),this._onMicrotaskEmptySubscription.unsubscribe()}finally{this._destroyed=!0,this._views=[],this._bootstrapListeners=[],this._destroyListeners=[]}}onDestroy(t){return this._destroyListeners.push(t),()=>Od(this._destroyListeners,t)}destroy(){if(this._destroyed)throw new F(406,!1);const t=this._injector;t.destroy&&!t.destroyed&&t.destroy()}get viewCount(){return this._views.length}warnIfDestroyed(){}}return e.\u0275fac=function(t){return new(t||e)(L(Ye),L(lo),L(da))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})();function Od(e,n){const t=e.indexOf(n);t>-1&&e.splice(t,1)} /** * @license * Copyright Google LLC All Rights Reserved. @@ -998,14 +998,14 @@ class ze{constructor({enableLongStackTrace:n=!1,shouldCoalesceEventChangeDetecti * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -let Q1=!0,Vr=(()=>{class e{}return e.__NG_ELEMENT_ID__=sx,e})();function sx(e){return function ax(e,n,t){if($s(e)&&!t){const i=Nn(e.index,n);return new ql(i,i)}return 47&e.type?new ql(n[16],n):null} +let Q1=!0,Vr=(()=>{class e{}return e.__NG_ELEMENT_ID__=sR,e})();function sR(e){return function aR(e,n,t){if($s(e)&&!t){const i=En(e.index,n);return new ql(i,i)}return 47&e.type?new ql(n[16],n):null} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */(wt(),k(),16==(16&e))} + */(wt(),O(),16==(16&e))} /** * @license * Copyright Google LLC All Rights Reserved. @@ -1013,21 +1013,21 @@ let Q1=!0,Vr=(()=>{class e{}return e.__NG_ELEMENT_ID__=sx,e})();function sx(e){r * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -class iC{constructor(){}supports(n){return Zl(n)}create(n){return new hx(n)}}const fx=(e,n)=>n;class hx{constructor(n){this.length=0,this._linkedRecords=null,this._unlinkedRecords=null,this._previousItHead=null,this._itHead=null,this._itTail=null,this._additionsHead=null,this._additionsTail=null,this._movesHead=null,this._movesTail=null,this._removalsHead=null,this._removalsTail=null,this._identityChangesHead=null,this._identityChangesTail=null,this._trackByFn=n||fx}forEachItem(n){let t;for(t=this._itHead;null!==t;t=t._next)n(t)}forEachOperation(n){let t=this._itHead,i=this._removalsHead,r=0,o=null;for(;t||i;){const s=!i||t&&t.currentIndex{s=this._trackByFn(r,a),null!==t&&Object.is(t.trackById,s)?(i&&(t=this._verifyReinsertion(t,a,s,r)),Object.is(t.item,a)||this._addIdentityChange(t,a)):(t=this._mismatch(t,a,s,r),i=!0),t=t._next,r++}),this.length=r;return this._truncate(t),this.collection=n,this.isDirty}get isDirty(){return null!==this._additionsHead||null!==this._movesHead||null!==this._removalsHead||null!==this._identityChangesHead}_reset(){if(this.isDirty){let n;for(n=this._previousItHead=this._itHead;null!==n;n=n._next)n._nextPrevious=n._next;for(n=this._additionsHead;null!==n;n=n._nextAdded)n.previousIndex=n.currentIndex;for(this._additionsHead=this._additionsTail=null,n=this._movesHead;null!==n;n=n._nextMoved)n.previousIndex=n.currentIndex;this._movesHead=this._movesTail=null,this._removalsHead=this._removalsTail=null,this._identityChangesHead=this._identityChangesTail=null}}_mismatch(n,t,i,r){let o;return null===n?o=this._itTail:(o=n._prev,this._remove(n)),null!==(n=null===this._unlinkedRecords?null:this._unlinkedRecords.get(i,null))?(Object.is(n.item,t)||this._addIdentityChange(n,t),this._reinsertAfter(n,o,r)):null!==(n=null===this._linkedRecords?null:this._linkedRecords.get(i,r))?(Object.is(n.item,t)||this._addIdentityChange(n,t),this._moveAfter(n,o,r)):n=this._addAfter(new px(t,i),o,r),n}_verifyReinsertion(n,t,i,r){let o=null===this._unlinkedRecords?null:this._unlinkedRecords.get(i,null);return null!==o?n=this._reinsertAfter(o,n._prev,r):n.currentIndex!=r&&(n.currentIndex=r,this._addToMoves(n,r)),n}_truncate(n){for(;null!==n;){const t=n._next;this._addToRemovals(this._unlink(n)),n=t}null!==this._unlinkedRecords&&this._unlinkedRecords.clear(),null!==this._additionsTail&&(this._additionsTail._nextAdded=null),null!==this._movesTail&&(this._movesTail._nextMoved=null),null!==this._itTail&&(this._itTail._next=null),null!==this._removalsTail&&(this._removalsTail._nextRemoved=null),null!==this._identityChangesTail&&(this._identityChangesTail._nextIdentityChange=null)}_reinsertAfter(n,t,i){null!==this._unlinkedRecords&&this._unlinkedRecords.remove(n);const r=n._prevRemoved,o=n._nextRemoved;return null===r?this._removalsHead=o:r._nextRemoved=o,null===o?this._removalsTail=r:o._prevRemoved=r,this._insertAfter(n,t,i),this._addToMoves(n,i),n}_moveAfter(n,t,i){return this._unlink(n),this._insertAfter(n,t,i),this._addToMoves(n,i),n}_addAfter(n,t,i){return this._insertAfter(n,t,i),this._additionsTail=null===this._additionsTail?this._additionsHead=n:this._additionsTail._nextAdded=n,n}_insertAfter(n,t,i){const r=null===t?this._itHead:t._next;return n._next=r,n._prev=t,null===r?this._itTail=n:r._prev=n,null===t?this._itHead=n:t._next=n,null===this._linkedRecords&&(this._linkedRecords=new rC),this._linkedRecords.put(n),n.currentIndex=i,n}_remove(n){return this._addToRemovals(this._unlink(n))}_unlink(n){null!==this._linkedRecords&&this._linkedRecords.remove(n);const t=n._prev,i=n._next;return null===t?this._itHead=i:t._next=i,null===i?this._itTail=t:i._prev=t,n}_addToMoves(n,t){return n.previousIndex===t||(this._movesTail=null===this._movesTail?this._movesHead=n:this._movesTail._nextMoved=n),n}_addToRemovals(n){return null===this._unlinkedRecords&&(this._unlinkedRecords=new rC),this._unlinkedRecords.put(n),n.currentIndex=null,n._nextRemoved=null,null===this._removalsTail?(this._removalsTail=this._removalsHead=n,n._prevRemoved=null):(n._prevRemoved=this._removalsTail,this._removalsTail=this._removalsTail._nextRemoved=n),n}_addIdentityChange(n,t){return n.item=t,this._identityChangesTail=null===this._identityChangesTail?this._identityChangesHead=n:this._identityChangesTail._nextIdentityChange=n,n}}class px{constructor(n,t){this.item=n,this.trackById=t,this.currentIndex=null,this.previousIndex=null,this._nextPrevious=null,this._prev=null,this._next=null,this._prevDup=null,this._nextDup=null,this._prevRemoved=null,this._nextRemoved=null,this._nextAdded=null,this._nextMoved=null,this._nextIdentityChange=null}}class gx{constructor(){this._head=null,this._tail=null}add(n){null===this._head?(this._head=this._tail=n,n._nextDup=null,n._prevDup=null):(this._tail._nextDup=n,n._prevDup=this._tail,n._nextDup=null,this._tail=n)}get(n,t){let i;for(i=this._head;null!==i;i=i._nextDup)if((null===t||t<=i.currentIndex)&&Object.is(i.trackById,n))return i;return null}remove(n){const t=n._prevDup,i=n._nextDup;return null===t?this._head=i:t._nextDup=i,null===i?this._tail=t:i._prevDup=t,null===this._head}}class rC{constructor(){this.map=new Map}put(n){const t=n.trackById;let i=this.map.get(t);i||(i=new gx,this.map.set(t,i)),i.add(n)}get(n,t){const r=this.map.get(n);return r?r.get(n,t):null}remove(n){const t=n.trackById;return this.map.get(t).remove(n)&&this.map.delete(t),n}get isEmpty(){return 0===this.map.size}clear(){this.map.clear()}}function oC(e,n,t){const i=e.previousIndex;if(null===i)return i;let r=0;return t&&in;class hR{constructor(n){this.length=0,this._linkedRecords=null,this._unlinkedRecords=null,this._previousItHead=null,this._itHead=null,this._itTail=null,this._additionsHead=null,this._additionsTail=null,this._movesHead=null,this._movesTail=null,this._removalsHead=null,this._removalsTail=null,this._identityChangesHead=null,this._identityChangesTail=null,this._trackByFn=n||fR}forEachItem(n){let t;for(t=this._itHead;null!==t;t=t._next)n(t)}forEachOperation(n){let t=this._itHead,i=this._removalsHead,r=0,o=null;for(;t||i;){const s=!i||t&&t.currentIndex{s=this._trackByFn(r,a),null!==t&&Object.is(t.trackById,s)?(i&&(t=this._verifyReinsertion(t,a,s,r)),Object.is(t.item,a)||this._addIdentityChange(t,a)):(t=this._mismatch(t,a,s,r),i=!0),t=t._next,r++}),this.length=r;return this._truncate(t),this.collection=n,this.isDirty}get isDirty(){return null!==this._additionsHead||null!==this._movesHead||null!==this._removalsHead||null!==this._identityChangesHead}_reset(){if(this.isDirty){let n;for(n=this._previousItHead=this._itHead;null!==n;n=n._next)n._nextPrevious=n._next;for(n=this._additionsHead;null!==n;n=n._nextAdded)n.previousIndex=n.currentIndex;for(this._additionsHead=this._additionsTail=null,n=this._movesHead;null!==n;n=n._nextMoved)n.previousIndex=n.currentIndex;this._movesHead=this._movesTail=null,this._removalsHead=this._removalsTail=null,this._identityChangesHead=this._identityChangesTail=null}}_mismatch(n,t,i,r){let o;return null===n?o=this._itTail:(o=n._prev,this._remove(n)),null!==(n=null===this._unlinkedRecords?null:this._unlinkedRecords.get(i,null))?(Object.is(n.item,t)||this._addIdentityChange(n,t),this._reinsertAfter(n,o,r)):null!==(n=null===this._linkedRecords?null:this._linkedRecords.get(i,r))?(Object.is(n.item,t)||this._addIdentityChange(n,t),this._moveAfter(n,o,r)):n=this._addAfter(new pR(t,i),o,r),n}_verifyReinsertion(n,t,i,r){let o=null===this._unlinkedRecords?null:this._unlinkedRecords.get(i,null);return null!==o?n=this._reinsertAfter(o,n._prev,r):n.currentIndex!=r&&(n.currentIndex=r,this._addToMoves(n,r)),n}_truncate(n){for(;null!==n;){const t=n._next;this._addToRemovals(this._unlink(n)),n=t}null!==this._unlinkedRecords&&this._unlinkedRecords.clear(),null!==this._additionsTail&&(this._additionsTail._nextAdded=null),null!==this._movesTail&&(this._movesTail._nextMoved=null),null!==this._itTail&&(this._itTail._next=null),null!==this._removalsTail&&(this._removalsTail._nextRemoved=null),null!==this._identityChangesTail&&(this._identityChangesTail._nextIdentityChange=null)}_reinsertAfter(n,t,i){null!==this._unlinkedRecords&&this._unlinkedRecords.remove(n);const r=n._prevRemoved,o=n._nextRemoved;return null===r?this._removalsHead=o:r._nextRemoved=o,null===o?this._removalsTail=r:o._prevRemoved=r,this._insertAfter(n,t,i),this._addToMoves(n,i),n}_moveAfter(n,t,i){return this._unlink(n),this._insertAfter(n,t,i),this._addToMoves(n,i),n}_addAfter(n,t,i){return this._insertAfter(n,t,i),this._additionsTail=null===this._additionsTail?this._additionsHead=n:this._additionsTail._nextAdded=n,n}_insertAfter(n,t,i){const r=null===t?this._itHead:t._next;return n._next=r,n._prev=t,null===r?this._itTail=n:r._prev=n,null===t?this._itHead=n:t._next=n,null===this._linkedRecords&&(this._linkedRecords=new rC),this._linkedRecords.put(n),n.currentIndex=i,n}_remove(n){return this._addToRemovals(this._unlink(n))}_unlink(n){null!==this._linkedRecords&&this._linkedRecords.remove(n);const t=n._prev,i=n._next;return null===t?this._itHead=i:t._next=i,null===i?this._itTail=t:i._prev=t,n}_addToMoves(n,t){return n.previousIndex===t||(this._movesTail=null===this._movesTail?this._movesHead=n:this._movesTail._nextMoved=n),n}_addToRemovals(n){return null===this._unlinkedRecords&&(this._unlinkedRecords=new rC),this._unlinkedRecords.put(n),n.currentIndex=null,n._nextRemoved=null,null===this._removalsTail?(this._removalsTail=this._removalsHead=n,n._prevRemoved=null):(n._prevRemoved=this._removalsTail,this._removalsTail=this._removalsTail._nextRemoved=n),n}_addIdentityChange(n,t){return n.item=t,this._identityChangesTail=null===this._identityChangesTail?this._identityChangesHead=n:this._identityChangesTail._nextIdentityChange=n,n}}class pR{constructor(n,t){this.item=n,this.trackById=t,this.currentIndex=null,this.previousIndex=null,this._nextPrevious=null,this._prev=null,this._next=null,this._prevDup=null,this._nextDup=null,this._prevRemoved=null,this._nextRemoved=null,this._nextAdded=null,this._nextMoved=null,this._nextIdentityChange=null}}class gR{constructor(){this._head=null,this._tail=null}add(n){null===this._head?(this._head=this._tail=n,n._nextDup=null,n._prevDup=null):(this._tail._nextDup=n,n._prevDup=this._tail,n._nextDup=null,this._tail=n)}get(n,t){let i;for(i=this._head;null!==i;i=i._nextDup)if((null===t||t<=i.currentIndex)&&Object.is(i.trackById,n))return i;return null}remove(n){const t=n._prevDup,i=n._nextDup;return null===t?this._head=i:t._nextDup=i,null===i?this._tail=t:i._prevDup=t,null===this._head}}class rC{constructor(){this.map=new Map}put(n){const t=n.trackById;let i=this.map.get(t);i||(i=new gR,this.map.set(t,i)),i.add(n)}get(n,t){const r=this.map.get(n);return r?r.get(n,t):null}remove(n){const t=n.trackById;return this.map.get(t).remove(n)&&this.map.delete(t),n}get isEmpty(){return 0===this.map.size}clear(){this.map.clear()}}function oC(e,n,t){const i=e.previousIndex;if(null===i)return i;let r=0;return t&&i{if(t&&t.key===r)this._maybeAddToChanges(t,i),this._appendAfter=t,t=t._next;else{const o=this._getOrCreateRecordForKey(r,i);t=this._insertBeforeOrAppend(t,o)}}),t){t._prev&&(t._prev._next=null),this._removalsHead=t;for(let i=t;null!==i;i=i._nextRemoved)i===this._mapHead&&(this._mapHead=null),this._records.delete(i.key),i._nextRemoved=i._next,i.previousValue=i.currentValue,i.currentValue=null,i._prev=null,i._next=null}return this._changesTail&&(this._changesTail._nextChanged=null),this._additionsTail&&(this._additionsTail._nextAdded=null),this.isDirty}_insertBeforeOrAppend(n,t){if(n){const i=n._prev;return t._next=n,t._prev=i,n._prev=t,i&&(i._next=t),n===this._mapHead&&(this._mapHead=t),this._appendAfter=n,n}return this._appendAfter?(this._appendAfter._next=t,t._prev=this._appendAfter):this._mapHead=t,this._appendAfter=t,null}_getOrCreateRecordForKey(n,t){if(this._records.has(n)){const r=this._records.get(n);this._maybeAddToChanges(r,t);const o=r._prev,s=r._next;return o&&(o._next=s),s&&(s._prev=o),r._next=null,r._prev=null,r}const i=new _x(n);return this._records.set(n,i),i.currentValue=t,this._addToAdditions(i),i}_reset(){if(this.isDirty){let n;for(this._previousMapHead=this._mapHead,n=this._previousMapHead;null!==n;n=n._next)n._nextPrevious=n._next;for(n=this._changesHead;null!==n;n=n._nextChanged)n.previousValue=n.currentValue;for(n=this._additionsHead;null!=n;n=n._nextAdded)n.previousValue=n.currentValue;this._changesHead=this._changesTail=null,this._additionsHead=this._additionsTail=null,this._removalsHead=null}}_maybeAddToChanges(n,t){Object.is(t,n.currentValue)||(n.previousValue=n.currentValue,n.currentValue=t,this._addToChanges(n))}_addToAdditions(n){null===this._additionsHead?this._additionsHead=this._additionsTail=n:(this._additionsTail._nextAdded=n,this._additionsTail=n)}_addToChanges(n){null===this._changesHead?this._changesHead=this._changesTail=n:(this._changesTail._nextChanged=n,this._changesTail=n)}_forEach(n,t){n instanceof Map?n.forEach(t):Object.keys(n).forEach(i=>t(n[i],i))}}class _x{constructor(n){this.key=n,this.previousValue=null,this.currentValue=null,this._nextPrevious=null,this._next=null,this._prev=null,this._nextAdded=null,this._nextRemoved=null,this._nextChanged=null}} + */}class sC{constructor(){}supports(n){return n instanceof Map||Ag(n)}create(){return new mR}}class mR{constructor(){this._records=new Map,this._mapHead=null,this._appendAfter=null,this._previousMapHead=null,this._changesHead=null,this._changesTail=null,this._additionsHead=null,this._additionsTail=null,this._removalsHead=null,this._removalsTail=null}get isDirty(){return null!==this._additionsHead||null!==this._changesHead||null!==this._removalsHead}forEachItem(n){let t;for(t=this._mapHead;null!==t;t=t._next)n(t)}forEachPreviousItem(n){let t;for(t=this._previousMapHead;null!==t;t=t._nextPrevious)n(t)}forEachChangedItem(n){let t;for(t=this._changesHead;null!==t;t=t._nextChanged)n(t)}forEachAddedItem(n){let t;for(t=this._additionsHead;null!==t;t=t._nextAdded)n(t)}forEachRemovedItem(n){let t;for(t=this._removalsHead;null!==t;t=t._nextRemoved)n(t)}diff(n){if(n){if(!(n instanceof Map||Ag(n)))throw new F(900,!1)}else n=new Map;return this.check(n)?this:null}onDestroy(){}check(n){this._reset();let t=this._mapHead;if(this._appendAfter=null,this._forEach(n,(i,r)=>{if(t&&t.key===r)this._maybeAddToChanges(t,i),this._appendAfter=t,t=t._next;else{const o=this._getOrCreateRecordForKey(r,i);t=this._insertBeforeOrAppend(t,o)}}),t){t._prev&&(t._prev._next=null),this._removalsHead=t;for(let i=t;null!==i;i=i._nextRemoved)i===this._mapHead&&(this._mapHead=null),this._records.delete(i.key),i._nextRemoved=i._next,i.previousValue=i.currentValue,i.currentValue=null,i._prev=null,i._next=null}return this._changesTail&&(this._changesTail._nextChanged=null),this._additionsTail&&(this._additionsTail._nextAdded=null),this.isDirty}_insertBeforeOrAppend(n,t){if(n){const i=n._prev;return t._next=n,t._prev=i,n._prev=t,i&&(i._next=t),n===this._mapHead&&(this._mapHead=t),this._appendAfter=n,n}return this._appendAfter?(this._appendAfter._next=t,t._prev=this._appendAfter):this._mapHead=t,this._appendAfter=t,null}_getOrCreateRecordForKey(n,t){if(this._records.has(n)){const r=this._records.get(n);this._maybeAddToChanges(r,t);const o=r._prev,s=r._next;return o&&(o._next=s),s&&(s._prev=o),r._next=null,r._prev=null,r}const i=new _R(n);return this._records.set(n,i),i.currentValue=t,this._addToAdditions(i),i}_reset(){if(this.isDirty){let n;for(this._previousMapHead=this._mapHead,n=this._previousMapHead;null!==n;n=n._next)n._nextPrevious=n._next;for(n=this._changesHead;null!==n;n=n._nextChanged)n.previousValue=n.currentValue;for(n=this._additionsHead;null!=n;n=n._nextAdded)n.previousValue=n.currentValue;this._changesHead=this._changesTail=null,this._additionsHead=this._additionsTail=null,this._removalsHead=null}}_maybeAddToChanges(n,t){Object.is(t,n.currentValue)||(n.previousValue=n.currentValue,n.currentValue=t,this._addToChanges(n))}_addToAdditions(n){null===this._additionsHead?this._additionsHead=this._additionsTail=n:(this._additionsTail._nextAdded=n,this._additionsTail=n)}_addToChanges(n){null===this._changesHead?this._changesHead=this._changesTail=n:(this._changesTail._nextChanged=n,this._changesTail=n)}_forEach(n,t){n instanceof Map?n.forEach(t):Object.keys(n).forEach(i=>t(n[i],i))}}class _R{constructor(n){this.key=n,this.previousValue=null,this.currentValue=null,this._nextPrevious=null,this._next=null,this._prev=null,this._nextAdded=null,this._nextRemoved=null,this._nextChanged=null}} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */function aC(){return new Fd([new iC])}let Fd=(()=>{class e{constructor(t){this.factories=t}static create(t,i){if(null!=i){const r=i.factories.slice();t=t.concat(r)}return new e(t)}static extend(t){return{provide:e,useFactory:i=>e.create(t,i||aC()),deps:[[e,new Vl,new Ll]]}}find(t){const i=this.factories.find(r=>r.supports(t));if(null!=i)return i;throw new P(901,!1)}}return e.\u0275prov=G({token:e,providedIn:"root",factory:aC}),e})(); + */function aC(){return new Pd([new iC])}let Pd=(()=>{class e{constructor(t){this.factories=t}static create(t,i){if(null!=i){const r=i.factories.slice();t=t.concat(r)}return new e(t)}static extend(t){return{provide:e,useFactory:i=>e.create(t,i||aC()),deps:[[e,new Vl,new Ll]]}}find(t){const i=this.factories.find(r=>r.supports(t));if(null!=i)return i;throw new F(901,!1)}}return e.\u0275prov=G({token:e,providedIn:"root",factory:aC}),e})(); /** * @license * Copyright Google LLC All Rights Reserved. @@ -1035,7 +1035,7 @@ class iC{constructor(){}supports(n){return Zl(n)}create(n){return new hx(n)}}con * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -function lC(){return new hc([new sC])}let hc=(()=>{class e{constructor(t){this.factories=t}static create(t,i){if(i){const r=i.factories.slice();t=t.concat(r)}return new e(t)}static extend(t){return{provide:e,useFactory:i=>e.create(t,i||lC()),deps:[[e,new Vl,new Ll]]}}find(t){const i=this.factories.find(r=>r.supports(t));if(i)return i;throw new P(901,!1)}} +function lC(){return new hc([new sC])}let hc=(()=>{class e{constructor(t){this.factories=t}static create(t,i){if(i){const r=i.factories.slice();t=t.concat(r)}return new e(t)}static extend(t){return{provide:e,useFactory:i=>e.create(t,i||lC()),deps:[[e,new Vl,new Ll]]}}find(t){const i=this.factories.find(r=>r.supports(t));if(i)return i;throw new F(901,!1)}} /** * @license * Copyright Google LLC All Rights Reserved. @@ -1043,7 +1043,7 @@ function lC(){return new hc([new sC])}let hc=(()=>{class e{constructor(t){this.f * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -return e.\u0275prov=G({token:e,providedIn:"root",factory:lC}),e})();const bx=G1(null,"core",[]); +return e.\u0275prov=G({token:e,providedIn:"root",factory:lC}),e})();const bR=G1(null,"core",[]); /** * @license * Copyright Google LLC All Rights Reserved. @@ -1065,7 +1065,7 @@ return e.\u0275prov=G({token:e,providedIn:"root",factory:lC}),e})();const bx=G1( * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -let Dx=(()=>{class e{constructor(t){}}return e.\u0275fac=function(t){return new(t||e)(L(fc))},e.\u0275mod=Ne({type:e}),e.\u0275inj=Me({}),e})(); +let DR=(()=>{class e{constructor(t){}}return e.\u0275fac=function(t){return new(t||e)(L(fc))},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({}),e})(); /** * @license * Copyright Google LLC All Rights Reserved. @@ -1087,7 +1087,7 @@ let Dx=(()=>{class e{constructor(t){}}return e.\u0275fac=function(t){return new( * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -function Dm(e,n){const t=Re(e),i=n.elementInjector||Qu();return new Jl(t).create(i,n.projectableNodes,n.hostElement,n.environmentInjector)} +function Dm(e,n){const t=xe(e),i=n.elementInjector||Qu();return new Zl(t).create(i,n.projectableNodes,n.hostElement,n.environmentInjector)} /** * @license * Copyright Google LLC All Rights Reserved. @@ -1121,7 +1121,7 @@ function Dm(e,n){const t=Re(e),i=n.elementInjector||Qu();return new Jl(t).create * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -let Pd=null;function lr(){return Pd} +let Fd=null;function lr(){return Fd} /** * @license * Copyright Google LLC All Rights Reserved. @@ -1136,7 +1136,7 @@ const Dt=new q("DocumentToken"); * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */let Cm=(()=>{class e{historyGo(t){throw new Error("Not implemented")}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:function(){return function Ex(){return L(cC)}()},providedIn:"platform"}),e})();const Mx=new q("Location Initialized");let cC=(()=>{class e extends Cm{constructor(t){super(),this._doc=t,this._init()}_init(){this.location=window.location,this._history=window.history}getBaseHrefFromDOM(){return lr().getBaseHref(this._doc)}onPopState(t){const i=lr().getGlobalEventTarget(this._doc,"window");return i.addEventListener("popstate",t,!1),()=>i.removeEventListener("popstate",t)}onHashChange(t){const i=lr().getGlobalEventTarget(this._doc,"window");return i.addEventListener("hashchange",t,!1),()=>i.removeEventListener("hashchange",t)}get href(){return this.location.href}get protocol(){return this.location.protocol}get hostname(){return this.location.hostname}get port(){return this.location.port}get pathname(){return this.location.pathname}get search(){return this.location.search}get hash(){return this.location.hash}set pathname(t){this.location.pathname=t}pushState(t,i,r){uC()?this._history.pushState(t,i,r):this.location.hash=r}replaceState(t,i,r){uC()?this._history.replaceState(t,i,r):this.location.hash=r}forward(){this._history.forward()}back(){this._history.back()}historyGo(t=0){this._history.go(t)}getState(){return this._history.state}}return e.\u0275fac=function(t){return new(t||e)(L(Dt))},e.\u0275prov=G({token:e,factory:function(){return function Nx(){return new cC(L(Dt))} + */let Cm=(()=>{class e{historyGo(t){throw new Error("Not implemented")}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:function(){return function MR(){return L(cC)}()},providedIn:"platform"}),e})();const NR=new q("Location Initialized");let cC=(()=>{class e extends Cm{constructor(t){super(),this._doc=t,this._init()}_init(){this.location=window.location,this._history=window.history}getBaseHrefFromDOM(){return lr().getBaseHref(this._doc)}onPopState(t){const i=lr().getGlobalEventTarget(this._doc,"window");return i.addEventListener("popstate",t,!1),()=>i.removeEventListener("popstate",t)}onHashChange(t){const i=lr().getGlobalEventTarget(this._doc,"window");return i.addEventListener("hashchange",t,!1),()=>i.removeEventListener("hashchange",t)}get href(){return this.location.href}get protocol(){return this.location.protocol}get hostname(){return this.location.hostname}get port(){return this.location.port}get pathname(){return this.location.pathname}get search(){return this.location.search}get hash(){return this.location.hash}set pathname(t){this.location.pathname=t}pushState(t,i,r){uC()?this._history.pushState(t,i,r):this.location.hash=r}replaceState(t,i,r){uC()?this._history.replaceState(t,i,r):this.location.hash=r}forward(){this._history.forward()}back(){this._history.back()}historyGo(t=0){this._history.go(t)}getState(){return this._history.state}}return e.\u0275fac=function(t){return new(t||e)(L(Dt))},e.\u0275prov=G({token:e,factory:function(){return function ER(){return new cC(L(Dt))} /** * @license * Copyright Google LLC All Rights Reserved. @@ -1150,14 +1150,14 @@ const Dt=new q("DocumentToken"); * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */()},providedIn:"platform"}),e})();function uC(){return!!window.history.pushState}function wm(e,n){if(0==e.length)return n;if(0==n.length)return e;let t=0;return e.endsWith("/")&&t++,n.startsWith("/")&&t++,2==t?e+n.substring(1):1==t?e+n:e+"/"+n}function dC(e){const n=e.match(/#|\?|$/),t=n&&n.index||e.length;return e.slice(0,t-("/"===e[t-1]?1:0))+e.slice(t)}function Br(e){return e&&"?"!==e[0]?"?"+e:e} + */()},providedIn:"platform"}),e})();function uC(){return!!window.history.pushState}function wm(e,n){if(0==e.length)return n;if(0==n.length)return e;let t=0;return e.endsWith("/")&&t++,n.startsWith("/")&&t++,2==t?e+n.substring(1):1==t?e+n:e+"/"+n}function dC(e){const n=e.match(/#|\?|$/),t=n&&n.index||e.length;return e.slice(0,t-("/"===e[t-1]?1:0))+e.slice(t)}function Hr(e){return e&&"?"!==e[0]?"?"+e:e} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */let ts=(()=>{class e{historyGo(t){throw new Error("Not implemented")}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:function(){return St(hC)},providedIn:"root"}),e})();const fC=new q("appBaseHref");let hC=(()=>{class e extends ts{constructor(t,i){super(),this._platformLocation=t,this._removeListenerFns=[],this._baseHref=i??this._platformLocation.getBaseHrefFromDOM()??St(Dt).location?.origin??""}ngOnDestroy(){for(;this._removeListenerFns.length;)this._removeListenerFns.pop()()}onPopState(t){this._removeListenerFns.push(this._platformLocation.onPopState(t),this._platformLocation.onHashChange(t))}getBaseHref(){return this._baseHref}prepareExternalUrl(t){return wm(this._baseHref,t)}path(t=!1){const i=this._platformLocation.pathname+Br(this._platformLocation.search),r=this._platformLocation.hash;return r&&t?`${i}${r}`:i}pushState(t,i,r,o){const s=this.prepareExternalUrl(r+Br(o));this._platformLocation.pushState(t,i,s)}replaceState(t,i,r,o){const s=this.prepareExternalUrl(r+Br(o));this._platformLocation.replaceState(t,i,s)}forward(){this._platformLocation.forward()}back(){this._platformLocation.back()}getState(){return this._platformLocation.getState()}historyGo(t=0){this._platformLocation.historyGo?.(t)}}return e.\u0275fac=function(t){return new(t||e)(L(Cm),L(fC,8))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(),Tx=(()=>{class e extends ts{constructor(t,i){super(),this._platformLocation=t,this._baseHref="",this._removeListenerFns=[],null!=i&&(this._baseHref=i)}ngOnDestroy(){for(;this._removeListenerFns.length;)this._removeListenerFns.pop()()}onPopState(t){this._removeListenerFns.push(this._platformLocation.onPopState(t),this._platformLocation.onHashChange(t))}getBaseHref(){return this._baseHref}path(t=!1){let i=this._platformLocation.hash;return null==i&&(i="#"),i.length>0?i.substring(1):i}prepareExternalUrl(t){const i=wm(this._baseHref,t);return i.length>0?"#"+i:i}pushState(t,i,r,o){let s=this.prepareExternalUrl(r+Br(o));0==s.length&&(s=this._platformLocation.pathname),this._platformLocation.pushState(t,i,s)}replaceState(t,i,r,o){let s=this.prepareExternalUrl(r+Br(o));0==s.length&&(s=this._platformLocation.pathname),this._platformLocation.replaceState(t,i,s)}forward(){this._platformLocation.forward()}back(){this._platformLocation.back()}getState(){return this._platformLocation.getState()}historyGo(t=0){this._platformLocation.historyGo?.(t)}}return e.\u0275fac=function(t){return new(t||e)(L(Cm),L(fC,8))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(),Sm=(()=>{class e{constructor(t){this._subject=new ue,this._urlChangeListeners=[],this._urlChangeSubscription=null,this._locationStrategy=t;const i=this._locationStrategy.getBaseHref();this._baseHref=dC(pC(i)),this._locationStrategy.onPopState(r=>{this._subject.emit({url:this.path(!0),pop:!0,state:r.state,type:r.type})})}ngOnDestroy(){this._urlChangeSubscription?.unsubscribe(),this._urlChangeListeners=[]}path(t=!1){return this.normalize(this._locationStrategy.path(t))}getState(){return this._locationStrategy.getState()}isCurrentPathEqualTo(t,i=""){return this.path()==this.normalize(t+Br(i))}normalize(t){return e.stripTrailingSlash(function Ix(e,n){return e&&n.startsWith(e)?n.substring(e.length):n}(this._baseHref,pC(t)))}prepareExternalUrl(t){return t&&"/"!==t[0]&&(t="/"+t),this._locationStrategy.prepareExternalUrl(t)}go(t,i="",r=null){this._locationStrategy.pushState(r,"",t,i),this._notifyUrlChangeListeners(this.prepareExternalUrl(t+Br(i)),r)}replaceState(t,i="",r=null){this._locationStrategy.replaceState(r,"",t,i),this._notifyUrlChangeListeners(this.prepareExternalUrl(t+Br(i)),r)}forward(){this._locationStrategy.forward()}back(){this._locationStrategy.back()}historyGo(t=0){this._locationStrategy.historyGo?.(t)}onUrlChange(t){return this._urlChangeListeners.push(t),this._urlChangeSubscription||(this._urlChangeSubscription=this.subscribe(i=>{this._notifyUrlChangeListeners(i.url,i.state)})),()=>{const i=this._urlChangeListeners.indexOf(t);this._urlChangeListeners.splice(i,1),0===this._urlChangeListeners.length&&(this._urlChangeSubscription?.unsubscribe(),this._urlChangeSubscription=null)}}_notifyUrlChangeListeners(t="",i){this._urlChangeListeners.forEach(r=>r(t,i))}subscribe(t,i,r){return this._subject.subscribe({next:t,error:i,complete:r})}}return e.normalizeQueryParams=Br,e.joinWithSlash=wm,e.stripTrailingSlash=dC,e.\u0275fac=function(t){return new(t||e)(L(ts))},e.\u0275prov=G({token:e,factory:function(){return function Ax(){return new Sm(L(ts))}()},providedIn:"root"}),e})(); + */let ts=(()=>{class e{historyGo(t){throw new Error("Not implemented")}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:function(){return St(hC)},providedIn:"root"}),e})();const fC=new q("appBaseHref");let hC=(()=>{class e extends ts{constructor(t,i){super(),this._platformLocation=t,this._removeListenerFns=[],this._baseHref=i??this._platformLocation.getBaseHrefFromDOM()??St(Dt).location?.origin??""}ngOnDestroy(){for(;this._removeListenerFns.length;)this._removeListenerFns.pop()()}onPopState(t){this._removeListenerFns.push(this._platformLocation.onPopState(t),this._platformLocation.onHashChange(t))}getBaseHref(){return this._baseHref}prepareExternalUrl(t){return wm(this._baseHref,t)}path(t=!1){const i=this._platformLocation.pathname+Hr(this._platformLocation.search),r=this._platformLocation.hash;return r&&t?`${i}${r}`:i}pushState(t,i,r,o){const s=this.prepareExternalUrl(r+Hr(o));this._platformLocation.pushState(t,i,s)}replaceState(t,i,r,o){const s=this.prepareExternalUrl(r+Hr(o));this._platformLocation.replaceState(t,i,s)}forward(){this._platformLocation.forward()}back(){this._platformLocation.back()}getState(){return this._platformLocation.getState()}historyGo(t=0){this._platformLocation.historyGo?.(t)}}return e.\u0275fac=function(t){return new(t||e)(L(Cm),L(fC,8))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(),TR=(()=>{class e extends ts{constructor(t,i){super(),this._platformLocation=t,this._baseHref="",this._removeListenerFns=[],null!=i&&(this._baseHref=i)}ngOnDestroy(){for(;this._removeListenerFns.length;)this._removeListenerFns.pop()()}onPopState(t){this._removeListenerFns.push(this._platformLocation.onPopState(t),this._platformLocation.onHashChange(t))}getBaseHref(){return this._baseHref}path(t=!1){let i=this._platformLocation.hash;return null==i&&(i="#"),i.length>0?i.substring(1):i}prepareExternalUrl(t){const i=wm(this._baseHref,t);return i.length>0?"#"+i:i}pushState(t,i,r,o){let s=this.prepareExternalUrl(r+Hr(o));0==s.length&&(s=this._platformLocation.pathname),this._platformLocation.pushState(t,i,s)}replaceState(t,i,r,o){let s=this.prepareExternalUrl(r+Hr(o));0==s.length&&(s=this._platformLocation.pathname),this._platformLocation.replaceState(t,i,s)}forward(){this._platformLocation.forward()}back(){this._platformLocation.back()}getState(){return this._platformLocation.getState()}historyGo(t=0){this._platformLocation.historyGo?.(t)}}return e.\u0275fac=function(t){return new(t||e)(L(Cm),L(fC,8))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(),Sm=(()=>{class e{constructor(t){this._subject=new ue,this._urlChangeListeners=[],this._urlChangeSubscription=null,this._locationStrategy=t;const i=this._locationStrategy.getBaseHref();this._baseHref=dC(pC(i)),this._locationStrategy.onPopState(r=>{this._subject.emit({url:this.path(!0),pop:!0,state:r.state,type:r.type})})}ngOnDestroy(){this._urlChangeSubscription?.unsubscribe(),this._urlChangeListeners=[]}path(t=!1){return this.normalize(this._locationStrategy.path(t))}getState(){return this._locationStrategy.getState()}isCurrentPathEqualTo(t,i=""){return this.path()==this.normalize(t+Hr(i))}normalize(t){return e.stripTrailingSlash(function AR(e,n){return e&&n.startsWith(e)?n.substring(e.length):n}(this._baseHref,pC(t)))}prepareExternalUrl(t){return t&&"/"!==t[0]&&(t="/"+t),this._locationStrategy.prepareExternalUrl(t)}go(t,i="",r=null){this._locationStrategy.pushState(r,"",t,i),this._notifyUrlChangeListeners(this.prepareExternalUrl(t+Hr(i)),r)}replaceState(t,i="",r=null){this._locationStrategy.replaceState(r,"",t,i),this._notifyUrlChangeListeners(this.prepareExternalUrl(t+Hr(i)),r)}forward(){this._locationStrategy.forward()}back(){this._locationStrategy.back()}historyGo(t=0){this._locationStrategy.historyGo?.(t)}onUrlChange(t){return this._urlChangeListeners.push(t),this._urlChangeSubscription||(this._urlChangeSubscription=this.subscribe(i=>{this._notifyUrlChangeListeners(i.url,i.state)})),()=>{const i=this._urlChangeListeners.indexOf(t);this._urlChangeListeners.splice(i,1),0===this._urlChangeListeners.length&&(this._urlChangeSubscription?.unsubscribe(),this._urlChangeSubscription=null)}}_notifyUrlChangeListeners(t="",i){this._urlChangeListeners.forEach(r=>r(t,i))}subscribe(t,i,r){return this._subject.subscribe({next:t,error:i,complete:r})}}return e.normalizeQueryParams=Hr,e.joinWithSlash=wm,e.stripTrailingSlash=dC,e.\u0275fac=function(t){return new(t||e)(L(ts))},e.\u0275prov=G({token:e,factory:function(){return function IR(){return new Sm(L(ts))}()},providedIn:"root"}),e})(); /** * @license * Copyright Google LLC All Rights Reserved. @@ -1186,7 +1186,7 @@ const Dt=new q("DocumentToken"); * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -var Mt=(()=>((Mt=Mt||{})[Mt.Format=0]="Format",Mt[Mt.Standalone=1]="Standalone",Mt))(),ve=(()=>((ve=ve||{})[ve.Narrow=0]="Narrow",ve[ve.Abbreviated=1]="Abbreviated",ve[ve.Wide=2]="Wide",ve[ve.Short=3]="Short",ve))(),pt=(()=>((pt=pt||{})[pt.Short=0]="Short",pt[pt.Medium=1]="Medium",pt[pt.Long=2]="Long",pt[pt.Full=3]="Full",pt))(),ee=(()=>((ee=ee||{})[ee.Decimal=0]="Decimal",ee[ee.Group=1]="Group",ee[ee.List=2]="List",ee[ee.PercentSign=3]="PercentSign",ee[ee.PlusSign=4]="PlusSign",ee[ee.MinusSign=5]="MinusSign",ee[ee.Exponential=6]="Exponential",ee[ee.SuperscriptingExponent=7]="SuperscriptingExponent",ee[ee.PerMille=8]="PerMille",ee[ee.Infinity=9]="Infinity",ee[ee.NaN=10]="NaN",ee[ee.TimeSeparator=11]="TimeSeparator",ee[ee.CurrencyDecimal=12]="CurrencyDecimal",ee[ee.CurrencyGroup=13]="CurrencyGroup",ee))();function Ld(e,n){return _i(In(e)[j.DateFormat],n)}function Vd(e,n){return _i(In(e)[j.TimeFormat],n)}function Hd(e,n){return _i(In(e)[j.DateTimeFormat],n)}function mi(e,n){const t=In(e),i=t[j.NumberSymbols][n];if(typeof i>"u"){if(n===ee.CurrencyDecimal)return t[j.NumberSymbols][ee.Decimal];if(n===ee.CurrencyGroup)return t[j.NumberSymbols][ee.Group]}return i}function mC(e){if(!e[j.ExtraData])throw new Error(`Missing extra locale data for the locale "${e[j.LocaleId]}". Use "registerLocaleData" to load new data. See the "I18n guide" on angular.io to know more.`)}function _i(e,n){for(let t=n;t>-1;t--)if(typeof e[t]<"u")return e[t];throw new Error("Locale data API: locale data undefined")}function Mm(e){const[n,t]=e.split(":");return{hours:+n,minutes:+t}} +var Nt=(()=>((Nt=Nt||{})[Nt.Format=0]="Format",Nt[Nt.Standalone=1]="Standalone",Nt))(),ve=(()=>((ve=ve||{})[ve.Narrow=0]="Narrow",ve[ve.Abbreviated=1]="Abbreviated",ve[ve.Wide=2]="Wide",ve[ve.Short=3]="Short",ve))(),pt=(()=>((pt=pt||{})[pt.Short=0]="Short",pt[pt.Medium=1]="Medium",pt[pt.Long=2]="Long",pt[pt.Full=3]="Full",pt))(),ee=(()=>((ee=ee||{})[ee.Decimal=0]="Decimal",ee[ee.Group=1]="Group",ee[ee.List=2]="List",ee[ee.PercentSign=3]="PercentSign",ee[ee.PlusSign=4]="PlusSign",ee[ee.MinusSign=5]="MinusSign",ee[ee.Exponential=6]="Exponential",ee[ee.SuperscriptingExponent=7]="SuperscriptingExponent",ee[ee.PerMille=8]="PerMille",ee[ee.Infinity=9]="Infinity",ee[ee.NaN=10]="NaN",ee[ee.TimeSeparator=11]="TimeSeparator",ee[ee.CurrencyDecimal=12]="CurrencyDecimal",ee[ee.CurrencyGroup=13]="CurrencyGroup",ee))();function Ld(e,n){return _i(An(e)[j.DateFormat],n)}function Vd(e,n){return _i(An(e)[j.TimeFormat],n)}function Bd(e,n){return _i(An(e)[j.DateTimeFormat],n)}function mi(e,n){const t=An(e),i=t[j.NumberSymbols][n];if(typeof i>"u"){if(n===ee.CurrencyDecimal)return t[j.NumberSymbols][ee.Decimal];if(n===ee.CurrencyGroup)return t[j.NumberSymbols][ee.Group]}return i}function mC(e){if(!e[j.ExtraData])throw new Error(`Missing extra locale data for the locale "${e[j.LocaleId]}". Use "registerLocaleData" to load new data. See the "I18n guide" on angular.io to know more.`)}function _i(e,n){for(let t=n;t>-1;t--)if(typeof e[t]<"u")return e[t];throw new Error("Locale data API: locale data undefined")}function Nm(e){const[n,t]=e.split(":");return{hours:+n,minutes:+t}} /** * @license * Copyright Google LLC All Rights Reserved. @@ -1194,7 +1194,7 @@ var Mt=(()=>((Mt=Mt||{})[Mt.Format=0]="Format",Mt[Mt.Standalone=1]="Standalone", * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -const Ux=/^(\d{4,})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/,pc={},Gx=/((?:[^BEGHLMOSWYZabcdhmswyz']+)|(?:'(?:[^']|'')*')|(?:G{1,5}|y{1,4}|Y{1,4}|M{1,5}|L{1,5}|w{1,2}|W{1}|d{1,2}|E{1,6}|c{1,6}|a{1,5}|b{1,5}|B{1,5}|h{1,2}|H{1,2}|m{1,2}|s{1,2}|S{1,3}|z{1,4}|Z{1,5}|O{1,4}))([\s\S]*)/;var Lt=(()=>((Lt=Lt||{})[Lt.Short=0]="Short",Lt[Lt.ShortGMT=1]="ShortGMT",Lt[Lt.Long=2]="Long",Lt[Lt.Extended=3]="Extended",Lt))(),ie=(()=>((ie=ie||{})[ie.FullYear=0]="FullYear",ie[ie.Month=1]="Month",ie[ie.Date=2]="Date",ie[ie.Hours=3]="Hours",ie[ie.Minutes=4]="Minutes",ie[ie.Seconds=5]="Seconds",ie[ie.FractionalSeconds=6]="FractionalSeconds",ie[ie.Day=7]="Day",ie))(),fe=(()=>((fe=fe||{})[fe.DayPeriods=0]="DayPeriods",fe[fe.Days=1]="Days",fe[fe.Months=2]="Months",fe[fe.Eras=3]="Eras",fe))();function Wx(e,n,t,i){let r=function eF(e){if(yC(e))return e;if("number"==typeof e&&!isNaN(e))return new Date(e);if("string"==typeof e){if(e=e.trim(),/^(\d{4}(-\d{1,2}(-\d{1,2})?)?)$/.test(e)){const[r,o=1,s=1]=e.split("-").map(a=>+a);return Bd(r,o-1,s)}const t=parseFloat(e);if(!isNaN(e-t))return new Date(t);let i;if(i=e.match(Ux))return function tF(e){const n=new Date(0);let t=0,i=0;const r=e[8]?n.setUTCFullYear:n.setFullYear,o=e[8]?n.setUTCHours:n.setHours;e[9]&&(t=Number(e[9]+e[10]),i=Number(e[9]+e[11])),r.call(n,Number(e[1]),Number(e[2])-1,Number(e[3]));const s=Number(e[4]||0)-t,a=Number(e[5]||0)-i,l=Number(e[6]||0),u=Math.floor(1e3*parseFloat("0."+(e[7]||0)));return o.call(n,s,a,l,u),n}(i)}const n=new Date(e);if(!yC(n))throw new Error(`Unable to convert "${e}" into a date`);return n}(e);n=jr(t,n)||n;let a,s=[];for(;n;){if(a=Gx.exec(n),!a){s.push(n);break}{s=s.concat(a.slice(1));const f=s.pop();if(!f)break;n=f}}let l=r.getTimezoneOffset();i&&(l=vC(i,l),r=function Xx(e,n,t){const i=t?-1:1,r=e.getTimezoneOffset();return function Qx(e,n){return(e=new Date(e.getTime())).setMinutes(e.getMinutes()+n),e}(e,i*(vC(n,r)-r))}(r,i,!0));let u="";return s.forEach(f=>{const p=function Zx(e){if(Tm[e])return Tm[e];let n;switch(e){case"G":case"GG":case"GGG":n=Qe(fe.Eras,ve.Abbreviated);break;case"GGGG":n=Qe(fe.Eras,ve.Wide);break;case"GGGGG":n=Qe(fe.Eras,ve.Narrow);break;case"y":n=Ot(ie.FullYear,1,0,!1,!0);break;case"yy":n=Ot(ie.FullYear,2,0,!0,!0);break;case"yyy":n=Ot(ie.FullYear,3,0,!1,!0);break;case"yyyy":n=Ot(ie.FullYear,4,0,!1,!0);break;case"Y":n=Gd(1);break;case"YY":n=Gd(2,!0);break;case"YYY":n=Gd(3);break;case"YYYY":n=Gd(4);break;case"M":case"L":n=Ot(ie.Month,1,1);break;case"MM":case"LL":n=Ot(ie.Month,2,1);break;case"MMM":n=Qe(fe.Months,ve.Abbreviated);break;case"MMMM":n=Qe(fe.Months,ve.Wide);break;case"MMMMM":n=Qe(fe.Months,ve.Narrow);break;case"LLL":n=Qe(fe.Months,ve.Abbreviated,Mt.Standalone);break;case"LLLL":n=Qe(fe.Months,ve.Wide,Mt.Standalone);break;case"LLLLL":n=Qe(fe.Months,ve.Narrow,Mt.Standalone);break;case"w":n=Nm(1);break;case"ww":n=Nm(2);break;case"W":n=Nm(1,!0);break;case"d":n=Ot(ie.Date,1);break;case"dd":n=Ot(ie.Date,2);break;case"c":case"cc":n=Ot(ie.Day,1);break;case"ccc":n=Qe(fe.Days,ve.Abbreviated,Mt.Standalone);break;case"cccc":n=Qe(fe.Days,ve.Wide,Mt.Standalone);break;case"ccccc":n=Qe(fe.Days,ve.Narrow,Mt.Standalone);break;case"cccccc":n=Qe(fe.Days,ve.Short,Mt.Standalone);break;case"E":case"EE":case"EEE":n=Qe(fe.Days,ve.Abbreviated);break;case"EEEE":n=Qe(fe.Days,ve.Wide);break;case"EEEEE":n=Qe(fe.Days,ve.Narrow);break;case"EEEEEE":n=Qe(fe.Days,ve.Short);break;case"a":case"aa":case"aaa":n=Qe(fe.DayPeriods,ve.Abbreviated);break;case"aaaa":n=Qe(fe.DayPeriods,ve.Wide);break;case"aaaaa":n=Qe(fe.DayPeriods,ve.Narrow);break;case"b":case"bb":case"bbb":n=Qe(fe.DayPeriods,ve.Abbreviated,Mt.Standalone,!0);break;case"bbbb":n=Qe(fe.DayPeriods,ve.Wide,Mt.Standalone,!0);break;case"bbbbb":n=Qe(fe.DayPeriods,ve.Narrow,Mt.Standalone,!0);break;case"B":case"BB":case"BBB":n=Qe(fe.DayPeriods,ve.Abbreviated,Mt.Format,!0);break;case"BBBB":n=Qe(fe.DayPeriods,ve.Wide,Mt.Format,!0);break;case"BBBBB":n=Qe(fe.DayPeriods,ve.Narrow,Mt.Format,!0);break;case"h":n=Ot(ie.Hours,1,-12);break;case"hh":n=Ot(ie.Hours,2,-12);break;case"H":n=Ot(ie.Hours,1);break;case"HH":n=Ot(ie.Hours,2);break;case"m":n=Ot(ie.Minutes,1);break;case"mm":n=Ot(ie.Minutes,2);break;case"s":n=Ot(ie.Seconds,1);break;case"ss":n=Ot(ie.Seconds,2);break;case"S":n=Ot(ie.FractionalSeconds,1);break;case"SS":n=Ot(ie.FractionalSeconds,2);break;case"SSS":n=Ot(ie.FractionalSeconds,3);break;case"Z":case"ZZ":case"ZZZ":n=$d(Lt.Short);break;case"ZZZZZ":n=$d(Lt.Extended);break;case"O":case"OO":case"OOO":case"z":case"zz":case"zzz":n=$d(Lt.ShortGMT);break;case"OOOO":case"ZZZZ":case"zzzz":n=$d(Lt.Long);break;default:return null}return Tm[e]=n,n}(f);u+=p?p(r,t,l):"''"===f?"'":f.replace(/(^'|'$)/g,"").replace(/''/g,"'")}),u}function Bd(e,n,t){const i=new Date(0);return i.setFullYear(e,n,t),i.setHours(0,0,0),i}function jr(e,n){const t=function Ox(e){return In(e)[j.LocaleId]}(e);if(pc[t]=pc[t]||{},pc[t][n])return pc[t][n];let i="";switch(n){case"shortDate":i=Ld(e,pt.Short);break;case"mediumDate":i=Ld(e,pt.Medium);break;case"longDate":i=Ld(e,pt.Long);break;case"fullDate":i=Ld(e,pt.Full);break;case"shortTime":i=Vd(e,pt.Short);break;case"mediumTime":i=Vd(e,pt.Medium);break;case"longTime":i=Vd(e,pt.Long);break;case"fullTime":i=Vd(e,pt.Full);break;case"short":const r=jr(e,"shortTime"),o=jr(e,"shortDate");i=jd(Hd(e,pt.Short),[r,o]);break;case"medium":const s=jr(e,"mediumTime"),a=jr(e,"mediumDate");i=jd(Hd(e,pt.Medium),[s,a]);break;case"long":const l=jr(e,"longTime"),u=jr(e,"longDate");i=jd(Hd(e,pt.Long),[l,u]);break;case"full":const f=jr(e,"fullTime"),p=jr(e,"fullDate");i=jd(Hd(e,pt.Full),[f,p])}return i&&(pc[t][n]=i),i}function jd(e,n){return n&&(e=e.replace(/\{([^}]+)}/g,function(t,i){return null!=n&&i in n?n[i]:t})),e}function Ui(e,n,t="-",i,r){let o="";(e<0||r&&e<=0)&&(r?e=1-e:(e=-e,o=t));let s=String(e);for(;s.length0||a>-t)&&(a+=t),e===ie.Hours)0===a&&-12===t&&(a=12);else if(e===ie.FractionalSeconds)return function Kx(e,n){return Ui(e,3).substring(0,n)}(a,n);const l=mi(s,ee.MinusSign);return Ui(a,n,l,i,r)}}function Qe(e,n,t=Mt.Format,i=!1){return function(r,o){return function Yx(e,n,t,i,r,o){switch(t){case fe.Months:return function xx(e,n,t){const i=In(e),o=_i([i[j.MonthsFormat],i[j.MonthsStandalone]],n);return _i(o,t)}(n,r,i)[e.getMonth()];case fe.Days:return function Rx(e,n,t){const i=In(e),o=_i([i[j.DaysFormat],i[j.DaysStandalone]],n);return _i(o,t)}(n,r,i)[e.getDay()];case fe.DayPeriods:const s=e.getHours(),a=e.getMinutes();if(o){const u=function Vx(e){const n=In(e);return mC(n),(n[j.ExtraData][2]||[]).map(i=>"string"==typeof i?Mm(i):[Mm(i[0]),Mm(i[1])])}(n),f=function Hx(e,n,t){const i=In(e);mC(i);const o=_i([i[j.ExtraData][0],i[j.ExtraData][1]],n)||[];return _i(o,t)||[]}(n,r,i),p=u.findIndex(m=>{if(Array.isArray(m)){const[v,y]=m,D=s>=v.hours&&a>=v.minutes,w=s0?Math.floor(r/60):Math.ceil(r/60);switch(e){case Lt.Short:return(r>=0?"+":"")+Ui(s,2,o)+Ui(Math.abs(r%60),2,o);case Lt.ShortGMT:return"GMT"+(r>=0?"+":"")+Ui(s,1,o);case Lt.Long:return"GMT"+(r>=0?"+":"")+Ui(s,2,o)+":"+Ui(Math.abs(r%60),2,o);case Lt.Extended:return 0===i?"Z":(r>=0?"+":"")+Ui(s,2,o)+":"+Ui(Math.abs(r%60),2,o);default:throw new Error(`Unknown zone width "${e}"`)}}}function _C(e){return Bd(e.getFullYear(),e.getMonth(),e.getDate()+(4-e.getDay()))}function Nm(e,n=!1){return function(t,i){let r;if(n){const o=new Date(t.getFullYear(),t.getMonth(),1).getDay()-1,s=t.getDate();r=1+Math.floor((s+o)/7)}else{const o=_C(t),s=function Jx(e){const n=Bd(e,0,1).getDay();return Bd(e,0,1+(n<=4?4:11)-n)}(o.getFullYear()),a=o.getTime()-s.getTime();r=1+Math.round(a/6048e5)}return Ui(r,e,mi(i,ee.MinusSign))}}function Gd(e,n=!1){return function(t,i){return Ui(_C(t).getFullYear(),e,mi(i,ee.MinusSign),n)}}const Tm={};function vC(e,n){e=e.replace(/:/g,"");const t=Date.parse("Jan 01, 1970 00:00:00 "+e)/6e4;return isNaN(t)?n:t}function yC(e){return e instanceof Date&&!isNaN(e.valueOf())} +const UR=/^(\d{4,})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/,pc={},GR=/((?:[^BEGHLMOSWYZabcdhmswyz']+)|(?:'(?:[^']|'')*')|(?:G{1,5}|y{1,4}|Y{1,4}|M{1,5}|L{1,5}|w{1,2}|W{1}|d{1,2}|E{1,6}|c{1,6}|a{1,5}|b{1,5}|B{1,5}|h{1,2}|H{1,2}|m{1,2}|s{1,2}|S{1,3}|z{1,4}|Z{1,5}|O{1,4}))([\s\S]*)/;var Lt=(()=>((Lt=Lt||{})[Lt.Short=0]="Short",Lt[Lt.ShortGMT=1]="ShortGMT",Lt[Lt.Long=2]="Long",Lt[Lt.Extended=3]="Extended",Lt))(),ie=(()=>((ie=ie||{})[ie.FullYear=0]="FullYear",ie[ie.Month=1]="Month",ie[ie.Date=2]="Date",ie[ie.Hours=3]="Hours",ie[ie.Minutes=4]="Minutes",ie[ie.Seconds=5]="Seconds",ie[ie.FractionalSeconds=6]="FractionalSeconds",ie[ie.Day=7]="Day",ie))(),fe=(()=>((fe=fe||{})[fe.DayPeriods=0]="DayPeriods",fe[fe.Days=1]="Days",fe[fe.Months=2]="Months",fe[fe.Eras=3]="Eras",fe))();function WR(e,n,t,i){let r=function eP(e){if(yC(e))return e;if("number"==typeof e&&!isNaN(e))return new Date(e);if("string"==typeof e){if(e=e.trim(),/^(\d{4}(-\d{1,2}(-\d{1,2})?)?)$/.test(e)){const[r,o=1,s=1]=e.split("-").map(a=>+a);return Hd(r,o-1,s)}const t=parseFloat(e);if(!isNaN(e-t))return new Date(t);let i;if(i=e.match(UR))return function tP(e){const n=new Date(0);let t=0,i=0;const r=e[8]?n.setUTCFullYear:n.setFullYear,o=e[8]?n.setUTCHours:n.setHours;e[9]&&(t=Number(e[9]+e[10]),i=Number(e[9]+e[11])),r.call(n,Number(e[1]),Number(e[2])-1,Number(e[3]));const s=Number(e[4]||0)-t,a=Number(e[5]||0)-i,l=Number(e[6]||0),u=Math.floor(1e3*parseFloat("0."+(e[7]||0)));return o.call(n,s,a,l,u),n}(i)}const n=new Date(e);if(!yC(n))throw new Error(`Unable to convert "${e}" into a date`);return n}(e);n=jr(t,n)||n;let a,s=[];for(;n;){if(a=GR.exec(n),!a){s.push(n);break}{s=s.concat(a.slice(1));const f=s.pop();if(!f)break;n=f}}let l=r.getTimezoneOffset();i&&(l=vC(i,l),r=function XR(e,n,t){const i=t?-1:1,r=e.getTimezoneOffset();return function QR(e,n){return(e=new Date(e.getTime())).setMinutes(e.getMinutes()+n),e}(e,i*(vC(n,r)-r))}(r,i,!0));let u="";return s.forEach(f=>{const p=function JR(e){if(Tm[e])return Tm[e];let n;switch(e){case"G":case"GG":case"GGG":n=Qe(fe.Eras,ve.Abbreviated);break;case"GGGG":n=Qe(fe.Eras,ve.Wide);break;case"GGGGG":n=Qe(fe.Eras,ve.Narrow);break;case"y":n=kt(ie.FullYear,1,0,!1,!0);break;case"yy":n=kt(ie.FullYear,2,0,!0,!0);break;case"yyy":n=kt(ie.FullYear,3,0,!1,!0);break;case"yyyy":n=kt(ie.FullYear,4,0,!1,!0);break;case"Y":n=Gd(1);break;case"YY":n=Gd(2,!0);break;case"YYY":n=Gd(3);break;case"YYYY":n=Gd(4);break;case"M":case"L":n=kt(ie.Month,1,1);break;case"MM":case"LL":n=kt(ie.Month,2,1);break;case"MMM":n=Qe(fe.Months,ve.Abbreviated);break;case"MMMM":n=Qe(fe.Months,ve.Wide);break;case"MMMMM":n=Qe(fe.Months,ve.Narrow);break;case"LLL":n=Qe(fe.Months,ve.Abbreviated,Nt.Standalone);break;case"LLLL":n=Qe(fe.Months,ve.Wide,Nt.Standalone);break;case"LLLLL":n=Qe(fe.Months,ve.Narrow,Nt.Standalone);break;case"w":n=Em(1);break;case"ww":n=Em(2);break;case"W":n=Em(1,!0);break;case"d":n=kt(ie.Date,1);break;case"dd":n=kt(ie.Date,2);break;case"c":case"cc":n=kt(ie.Day,1);break;case"ccc":n=Qe(fe.Days,ve.Abbreviated,Nt.Standalone);break;case"cccc":n=Qe(fe.Days,ve.Wide,Nt.Standalone);break;case"ccccc":n=Qe(fe.Days,ve.Narrow,Nt.Standalone);break;case"cccccc":n=Qe(fe.Days,ve.Short,Nt.Standalone);break;case"E":case"EE":case"EEE":n=Qe(fe.Days,ve.Abbreviated);break;case"EEEE":n=Qe(fe.Days,ve.Wide);break;case"EEEEE":n=Qe(fe.Days,ve.Narrow);break;case"EEEEEE":n=Qe(fe.Days,ve.Short);break;case"a":case"aa":case"aaa":n=Qe(fe.DayPeriods,ve.Abbreviated);break;case"aaaa":n=Qe(fe.DayPeriods,ve.Wide);break;case"aaaaa":n=Qe(fe.DayPeriods,ve.Narrow);break;case"b":case"bb":case"bbb":n=Qe(fe.DayPeriods,ve.Abbreviated,Nt.Standalone,!0);break;case"bbbb":n=Qe(fe.DayPeriods,ve.Wide,Nt.Standalone,!0);break;case"bbbbb":n=Qe(fe.DayPeriods,ve.Narrow,Nt.Standalone,!0);break;case"B":case"BB":case"BBB":n=Qe(fe.DayPeriods,ve.Abbreviated,Nt.Format,!0);break;case"BBBB":n=Qe(fe.DayPeriods,ve.Wide,Nt.Format,!0);break;case"BBBBB":n=Qe(fe.DayPeriods,ve.Narrow,Nt.Format,!0);break;case"h":n=kt(ie.Hours,1,-12);break;case"hh":n=kt(ie.Hours,2,-12);break;case"H":n=kt(ie.Hours,1);break;case"HH":n=kt(ie.Hours,2);break;case"m":n=kt(ie.Minutes,1);break;case"mm":n=kt(ie.Minutes,2);break;case"s":n=kt(ie.Seconds,1);break;case"ss":n=kt(ie.Seconds,2);break;case"S":n=kt(ie.FractionalSeconds,1);break;case"SS":n=kt(ie.FractionalSeconds,2);break;case"SSS":n=kt(ie.FractionalSeconds,3);break;case"Z":case"ZZ":case"ZZZ":n=$d(Lt.Short);break;case"ZZZZZ":n=$d(Lt.Extended);break;case"O":case"OO":case"OOO":case"z":case"zz":case"zzz":n=$d(Lt.ShortGMT);break;case"OOOO":case"ZZZZ":case"zzzz":n=$d(Lt.Long);break;default:return null}return Tm[e]=n,n}(f);u+=p?p(r,t,l):"''"===f?"'":f.replace(/(^'|'$)/g,"").replace(/''/g,"'")}),u}function Hd(e,n,t){const i=new Date(0);return i.setFullYear(e,n,t),i.setHours(0,0,0),i}function jr(e,n){const t=function kR(e){return An(e)[j.LocaleId]}(e);if(pc[t]=pc[t]||{},pc[t][n])return pc[t][n];let i="";switch(n){case"shortDate":i=Ld(e,pt.Short);break;case"mediumDate":i=Ld(e,pt.Medium);break;case"longDate":i=Ld(e,pt.Long);break;case"fullDate":i=Ld(e,pt.Full);break;case"shortTime":i=Vd(e,pt.Short);break;case"mediumTime":i=Vd(e,pt.Medium);break;case"longTime":i=Vd(e,pt.Long);break;case"fullTime":i=Vd(e,pt.Full);break;case"short":const r=jr(e,"shortTime"),o=jr(e,"shortDate");i=jd(Bd(e,pt.Short),[r,o]);break;case"medium":const s=jr(e,"mediumTime"),a=jr(e,"mediumDate");i=jd(Bd(e,pt.Medium),[s,a]);break;case"long":const l=jr(e,"longTime"),u=jr(e,"longDate");i=jd(Bd(e,pt.Long),[l,u]);break;case"full":const f=jr(e,"fullTime"),p=jr(e,"fullDate");i=jd(Bd(e,pt.Full),[f,p])}return i&&(pc[t][n]=i),i}function jd(e,n){return n&&(e=e.replace(/\{([^}]+)}/g,function(t,i){return null!=n&&i in n?n[i]:t})),e}function Ui(e,n,t="-",i,r){let o="";(e<0||r&&e<=0)&&(r?e=1-e:(e=-e,o=t));let s=String(e);for(;s.length0||a>-t)&&(a+=t),e===ie.Hours)0===a&&-12===t&&(a=12);else if(e===ie.FractionalSeconds)return function zR(e,n){return Ui(e,3).substring(0,n)}(a,n);const l=mi(s,ee.MinusSign);return Ui(a,n,l,i,r)}}function Qe(e,n,t=Nt.Format,i=!1){return function(r,o){return function KR(e,n,t,i,r,o){switch(t){case fe.Months:return function RR(e,n,t){const i=An(e),o=_i([i[j.MonthsFormat],i[j.MonthsStandalone]],n);return _i(o,t)}(n,r,i)[e.getMonth()];case fe.Days:return function xR(e,n,t){const i=An(e),o=_i([i[j.DaysFormat],i[j.DaysStandalone]],n);return _i(o,t)}(n,r,i)[e.getDay()];case fe.DayPeriods:const s=e.getHours(),a=e.getMinutes();if(o){const u=function VR(e){const n=An(e);return mC(n),(n[j.ExtraData][2]||[]).map(i=>"string"==typeof i?Nm(i):[Nm(i[0]),Nm(i[1])])}(n),f=function BR(e,n,t){const i=An(e);mC(i);const o=_i([i[j.ExtraData][0],i[j.ExtraData][1]],n)||[];return _i(o,t)||[]}(n,r,i),p=u.findIndex(m=>{if(Array.isArray(m)){const[v,y]=m,D=s>=v.hours&&a>=v.minutes,w=s0?Math.floor(r/60):Math.ceil(r/60);switch(e){case Lt.Short:return(r>=0?"+":"")+Ui(s,2,o)+Ui(Math.abs(r%60),2,o);case Lt.ShortGMT:return"GMT"+(r>=0?"+":"")+Ui(s,1,o);case Lt.Long:return"GMT"+(r>=0?"+":"")+Ui(s,2,o)+":"+Ui(Math.abs(r%60),2,o);case Lt.Extended:return 0===i?"Z":(r>=0?"+":"")+Ui(s,2,o)+":"+Ui(Math.abs(r%60),2,o);default:throw new Error(`Unknown zone width "${e}"`)}}}function _C(e){return Hd(e.getFullYear(),e.getMonth(),e.getDate()+(4-e.getDay()))}function Em(e,n=!1){return function(t,i){let r;if(n){const o=new Date(t.getFullYear(),t.getMonth(),1).getDay()-1,s=t.getDate();r=1+Math.floor((s+o)/7)}else{const o=_C(t),s=function ZR(e){const n=Hd(e,0,1).getDay();return Hd(e,0,1+(n<=4?4:11)-n)}(o.getFullYear()),a=o.getTime()-s.getTime();r=1+Math.round(a/6048e5)}return Ui(r,e,mi(i,ee.MinusSign))}}function Gd(e,n=!1){return function(t,i){return Ui(_C(t).getFullYear(),e,mi(i,ee.MinusSign),n)}}const Tm={};function vC(e,n){e=e.replace(/:/g,"");const t=Date.parse("Jan 01, 1970 00:00:00 "+e)/6e4;return isNaN(t)?n:t}function yC(e){return e instanceof Date&&!isNaN(e.valueOf())} /** * @license * Copyright Google LLC All Rights Reserved. @@ -1216,14 +1216,14 @@ function wC(e,n){n=encodeURIComponent(n);for(const t of e.split(";")){const i=t. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */let SC=(()=>{class e{constructor(t,i,r,o){this._iterableDiffers=t,this._keyValueDiffers=i,this._ngEl=r,this._renderer=o,this._iterableDiffer=null,this._keyValueDiffer=null,this._initialClasses=[],this._rawClass=null}set klass(t){this._removeClasses(this._initialClasses),this._initialClasses="string"==typeof t?t.split(/\s+/):[],this._applyClasses(this._initialClasses),this._applyClasses(this._rawClass)}set ngClass(t){this._removeClasses(this._rawClass),this._applyClasses(this._initialClasses),this._iterableDiffer=null,this._keyValueDiffer=null,this._rawClass="string"==typeof t?t.split(/\s+/):t,this._rawClass&&(Zl(this._rawClass)?this._iterableDiffer=this._iterableDiffers.find(this._rawClass).create():this._keyValueDiffer=this._keyValueDiffers.find(this._rawClass).create())}ngDoCheck(){if(this._iterableDiffer){const t=this._iterableDiffer.diff(this._rawClass);t&&this._applyIterableChanges(t)}else if(this._keyValueDiffer){const t=this._keyValueDiffer.diff(this._rawClass);t&&this._applyKeyValueChanges(t)}}_applyKeyValueChanges(t){t.forEachAddedItem(i=>this._toggleClass(i.key,i.currentValue)),t.forEachChangedItem(i=>this._toggleClass(i.key,i.currentValue)),t.forEachRemovedItem(i=>{i.previousValue&&this._toggleClass(i.key,!1)})}_applyIterableChanges(t){t.forEachAddedItem(i=>{if("string"!=typeof i.item)throw new Error(`NgClass can only toggle CSS classes expressed as strings, got ${Ve(i.item)}`);this._toggleClass(i.item,!0)}),t.forEachRemovedItem(i=>this._toggleClass(i.item,!1))}_applyClasses(t){t&&(Array.isArray(t)||t instanceof Set?t.forEach(i=>this._toggleClass(i,!0)):Object.keys(t).forEach(i=>this._toggleClass(i,!!t[i])))}_removeClasses(t){t&&(Array.isArray(t)||t instanceof Set?t.forEach(i=>this._toggleClass(i,!1)):Object.keys(t).forEach(i=>this._toggleClass(i,!1)))}_toggleClass(t,i){(t=t.trim())&&t.split(/\s+/g).forEach(r=>{i?this._renderer.addClass(this._ngEl.nativeElement,r):this._renderer.removeClass(this._ngEl.nativeElement,r)})}}return e.\u0275fac=function(t){return new(t||e)(C(Fd),C(hc),C(Ze),C(pi))},e.\u0275dir=H({type:e,selectors:[["","ngClass",""]],inputs:{klass:["class","klass"],ngClass:"ngClass"},standalone:!0}),e})(); + */let SC=(()=>{class e{constructor(t,i,r,o){this._iterableDiffers=t,this._keyValueDiffers=i,this._ngEl=r,this._renderer=o,this._iterableDiffer=null,this._keyValueDiffer=null,this._initialClasses=[],this._rawClass=null}set klass(t){this._removeClasses(this._initialClasses),this._initialClasses="string"==typeof t?t.split(/\s+/):[],this._applyClasses(this._initialClasses),this._applyClasses(this._rawClass)}set ngClass(t){this._removeClasses(this._rawClass),this._applyClasses(this._initialClasses),this._iterableDiffer=null,this._keyValueDiffer=null,this._rawClass="string"==typeof t?t.split(/\s+/):t,this._rawClass&&(Jl(this._rawClass)?this._iterableDiffer=this._iterableDiffers.find(this._rawClass).create():this._keyValueDiffer=this._keyValueDiffers.find(this._rawClass).create())}ngDoCheck(){if(this._iterableDiffer){const t=this._iterableDiffer.diff(this._rawClass);t&&this._applyIterableChanges(t)}else if(this._keyValueDiffer){const t=this._keyValueDiffer.diff(this._rawClass);t&&this._applyKeyValueChanges(t)}}_applyKeyValueChanges(t){t.forEachAddedItem(i=>this._toggleClass(i.key,i.currentValue)),t.forEachChangedItem(i=>this._toggleClass(i.key,i.currentValue)),t.forEachRemovedItem(i=>{i.previousValue&&this._toggleClass(i.key,!1)})}_applyIterableChanges(t){t.forEachAddedItem(i=>{if("string"!=typeof i.item)throw new Error(`NgClass can only toggle CSS classes expressed as strings, got ${Ve(i.item)}`);this._toggleClass(i.item,!0)}),t.forEachRemovedItem(i=>this._toggleClass(i.item,!1))}_applyClasses(t){t&&(Array.isArray(t)||t instanceof Set?t.forEach(i=>this._toggleClass(i,!0)):Object.keys(t).forEach(i=>this._toggleClass(i,!!t[i])))}_removeClasses(t){t&&(Array.isArray(t)||t instanceof Set?t.forEach(i=>this._toggleClass(i,!1)):Object.keys(t).forEach(i=>this._toggleClass(i,!1)))}_toggleClass(t,i){(t=t.trim())&&t.split(/\s+/g).forEach(r=>{i?this._renderer.addClass(this._ngEl.nativeElement,r):this._renderer.removeClass(this._ngEl.nativeElement,r)})}}return e.\u0275fac=function(t){return new(t||e)(C(Pd),C(hc),C(Je),C(pi))},e.\u0275dir=B({type:e,selectors:[["","ngClass",""]],inputs:{klass:["class","klass"],ngClass:"ngClass"},standalone:!0}),e})(); /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */class pF{constructor(n,t,i,r){this.$implicit=n,this.ngForOf=t,this.index=i,this.count=r}get first(){return 0===this.index}get last(){return this.index===this.count-1}get even(){return this.index%2==0}get odd(){return!this.even}}let ka=(()=>{class e{constructor(t,i,r){this._viewContainer=t,this._template=i,this._differs=r,this._ngForOf=null,this._ngForOfDirty=!0,this._differ=null}set ngForOf(t){this._ngForOf=t,this._ngForOfDirty=!0}set ngForTrackBy(t){this._trackByFn=t}get ngForTrackBy(){return this._trackByFn}set ngForTemplate(t){t&&(this._template=t)}ngDoCheck(){if(this._ngForOfDirty){this._ngForOfDirty=!1;const t=this._ngForOf;!this._differ&&t&&(this._differ=this._differs.find(t).create(this.ngForTrackBy))}if(this._differ){const t=this._differ.diff(this._ngForOf);t&&this._applyChanges(t)}}_applyChanges(t){const i=this._viewContainer;t.forEachOperation((r,o,s)=>{if(null==r.previousIndex)i.createEmbeddedView(this._template,new pF(r.item,this._ngForOf,-1,-1),null===s?void 0:s);else if(null==s)i.remove(null===o?void 0:o);else if(null!==o){const a=i.get(o);i.move(a,s),NC(a,r)}});for(let r=0,o=i.length;r{NC(i.get(r.currentIndex),r)})}static ngTemplateContextGuard(t,i){return!0}}return e.\u0275fac=function(t){return new(t||e)(C(Bi),C(bt),C(Fd))},e.\u0275dir=H({type:e,selectors:[["","ngFor","","ngForOf",""]],inputs:{ngForOf:"ngForOf",ngForTrackBy:"ngForTrackBy",ngForTemplate:"ngForTemplate"},standalone:!0}),e})();function NC(e,n){e.context.$implicit=n.item} + */class pP{constructor(n,t,i,r){this.$implicit=n,this.ngForOf=t,this.index=i,this.count=r}get first(){return 0===this.index}get last(){return this.index===this.count-1}get even(){return this.index%2==0}get odd(){return!this.even}}let Oa=(()=>{class e{constructor(t,i,r){this._viewContainer=t,this._template=i,this._differs=r,this._ngForOf=null,this._ngForOfDirty=!0,this._differ=null}set ngForOf(t){this._ngForOf=t,this._ngForOfDirty=!0}set ngForTrackBy(t){this._trackByFn=t}get ngForTrackBy(){return this._trackByFn}set ngForTemplate(t){t&&(this._template=t)}ngDoCheck(){if(this._ngForOfDirty){this._ngForOfDirty=!1;const t=this._ngForOf;!this._differ&&t&&(this._differ=this._differs.find(t).create(this.ngForTrackBy))}if(this._differ){const t=this._differ.diff(this._ngForOf);t&&this._applyChanges(t)}}_applyChanges(t){const i=this._viewContainer;t.forEachOperation((r,o,s)=>{if(null==r.previousIndex)i.createEmbeddedView(this._template,new pP(r.item,this._ngForOf,-1,-1),null===s?void 0:s);else if(null==s)i.remove(null===o?void 0:o);else if(null!==o){const a=i.get(o);i.move(a,s),EC(a,r)}});for(let r=0,o=i.length;r{EC(i.get(r.currentIndex),r)})}static ngTemplateContextGuard(t,i){return!0}}return e.\u0275fac=function(t){return new(t||e)(C(Hi),C(bt),C(Pd))},e.\u0275dir=B({type:e,selectors:[["","ngFor","","ngForOf",""]],inputs:{ngForOf:"ngForOf",ngForTrackBy:"ngForTrackBy",ngForTemplate:"ngForTemplate"},standalone:!0}),e})();function EC(e,n){e.context.$implicit=n.item} /** * @license * Copyright Google LLC All Rights Reserved. @@ -1231,7 +1231,7 @@ function wC(e,n){n=encodeURIComponent(n);for(const t of e.split(";")){const i=t. * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -let ns=(()=>{class e{constructor(t,i){this._viewContainer=t,this._context=new mF,this._thenTemplateRef=null,this._elseTemplateRef=null,this._thenViewRef=null,this._elseViewRef=null,this._thenTemplateRef=i}set ngIf(t){this._context.$implicit=this._context.ngIf=t,this._updateView()}set ngIfThen(t){TC("ngIfThen",t),this._thenTemplateRef=t,this._thenViewRef=null,this._updateView()}set ngIfElse(t){TC("ngIfElse",t),this._elseTemplateRef=t,this._elseViewRef=null,this._updateView()}_updateView(){this._context.$implicit?this._thenViewRef||(this._viewContainer.clear(),this._elseViewRef=null,this._thenTemplateRef&&(this._thenViewRef=this._viewContainer.createEmbeddedView(this._thenTemplateRef,this._context))):this._elseViewRef||(this._viewContainer.clear(),this._thenViewRef=null,this._elseTemplateRef&&(this._elseViewRef=this._viewContainer.createEmbeddedView(this._elseTemplateRef,this._context)))}static ngTemplateContextGuard(t,i){return!0}}return e.\u0275fac=function(t){return new(t||e)(C(Bi),C(bt))},e.\u0275dir=H({type:e,selectors:[["","ngIf",""]],inputs:{ngIf:"ngIf",ngIfThen:"ngIfThen",ngIfElse:"ngIfElse"},standalone:!0}),e})();class mF{constructor(){this.$implicit=null,this.ngIf=null}}function TC(e,n){if(n&&!n.createEmbeddedView)throw new Error(`${e} must be a TemplateRef, but received '${Ve(n)}'.`)} +let ns=(()=>{class e{constructor(t,i){this._viewContainer=t,this._context=new mP,this._thenTemplateRef=null,this._elseTemplateRef=null,this._thenViewRef=null,this._elseViewRef=null,this._thenTemplateRef=i}set ngIf(t){this._context.$implicit=this._context.ngIf=t,this._updateView()}set ngIfThen(t){TC("ngIfThen",t),this._thenTemplateRef=t,this._thenViewRef=null,this._updateView()}set ngIfElse(t){TC("ngIfElse",t),this._elseTemplateRef=t,this._elseViewRef=null,this._updateView()}_updateView(){this._context.$implicit?this._thenViewRef||(this._viewContainer.clear(),this._elseViewRef=null,this._thenTemplateRef&&(this._thenViewRef=this._viewContainer.createEmbeddedView(this._thenTemplateRef,this._context))):this._elseViewRef||(this._viewContainer.clear(),this._thenViewRef=null,this._elseTemplateRef&&(this._elseViewRef=this._viewContainer.createEmbeddedView(this._elseTemplateRef,this._context)))}static ngTemplateContextGuard(t,i){return!0}}return e.\u0275fac=function(t){return new(t||e)(C(Hi),C(bt))},e.\u0275dir=B({type:e,selectors:[["","ngIf",""]],inputs:{ngIf:"ngIf",ngIfThen:"ngIfThen",ngIfElse:"ngIfElse"},standalone:!0}),e})();class mP{constructor(){this.$implicit=null,this.ngIf=null}}function TC(e,n){if(n&&!n.createEmbeddedView)throw new Error(`${e} must be a TemplateRef, but received '${Ve(n)}'.`)} /** * @license * Copyright Google LLC All Rights Reserved. @@ -1246,7 +1246,7 @@ let ns=(()=>{class e{constructor(t,i){this._viewContainer=t,this._context=new mF * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -const IF=new q("DATE_PIPE_DEFAULT_TIMEZONE");let IC=(()=>{class e{constructor(t,i){this.locale=t,this.defaultTimezone=i}transform(t,i="mediumDate",r,o){if(null==t||""===t||t!=t)return null;try{return Wx(t,i,o||this.locale,r??this.defaultTimezone??void 0)}catch(s){ +const AP=new q("DATE_PIPE_DEFAULT_TIMEZONE");let AC=(()=>{class e{constructor(t,i){this.locale=t,this.defaultTimezone=i}transform(t,i="mediumDate",r,o){if(null==t||""===t||t!=t)return null;try{return WR(t,i,o||this.locale,r??this.defaultTimezone??void 0)}catch(s){ /** * @license * Copyright Google LLC All Rights Reserved. @@ -1254,14 +1254,14 @@ const IF=new q("DATE_PIPE_DEFAULT_TIMEZONE");let IC=(()=>{class e{constructor(t, * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -throw function Gi(e,n){return new P(2100,!1)} +throw function Gi(e,n){return new F(2100,!1)} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */()}}}return e.\u0275fac=function(t){return new(t||e)(C(Pr,16),C(IF,24))},e.\u0275pipe=$t({name:"date",type:e,pure:!0,standalone:!0}),e})(),ei=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ne({type:e}),e.\u0275inj=Me({}),e})(); + */()}}}return e.\u0275fac=function(t){return new(t||e)(C(Fr,16),C(AP,24))},e.\u0275pipe=$t({name:"date",type:e,pure:!0,standalone:!0}),e})(),ei=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({}),e})(); /** * @license * Copyright Google LLC All Rights Reserved. @@ -1276,7 +1276,7 @@ throw function Gi(e,n){return new P(2100,!1)} * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -const kC="browser"; +const OC="browser"; /** * @license * Copyright Google LLC All Rights Reserved. @@ -1284,7 +1284,7 @@ const kC="browser"; * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -let GF=(()=>{class e{}return e.\u0275prov=G({token:e,providedIn:"root",factory:()=>new WF(L(Dt),window)}),e})();class WF{constructor(n,t){this.document=n,this.window=t,this.offset=()=>[0,0]}setOffset(n){this.offset=Array.isArray(n)?()=>n:n}getScrollPosition(){return this.supportsScrolling()?[this.window.pageXOffset,this.window.pageYOffset]:[0,0]}scrollToPosition(n){this.supportsScrolling()&&this.window.scrollTo(n[0],n[1])}scrollToAnchor(n){if(!this.supportsScrolling())return;const t=function KF(e,n){const t=e.getElementById(n)||e.getElementsByName(n)[0];if(t)return t;if("function"==typeof e.createTreeWalker&&e.body&&(e.body.createShadowRoot||e.body.attachShadow)){const i=e.createTreeWalker(e.body,NodeFilter.SHOW_ELEMENT);let r=i.currentNode;for(;r;){const o=r.shadowRoot;if(o){const s=o.getElementById(n)||o.querySelector(`[name="${n}"]`);if(s)return s}r=i.nextNode()}}return null}(this.document,n);t&&(this.scrollToElement(t),t.focus())}setHistoryScrollRestoration(n){if(this.supportScrollRestoration()){const t=this.window.history;t&&t.scrollRestoration&&(t.scrollRestoration=n)}}scrollToElement(n){const t=n.getBoundingClientRect(),i=t.left+this.window.pageXOffset,r=t.top+this.window.pageYOffset,o=this.offset();this.window.scrollTo(i-o[0],r-o[1])}supportScrollRestoration(){try{if(!this.supportsScrolling())return!1;const n=xC(this.window.history)||xC(Object.getPrototypeOf(this.window.history));return!(!n||!n.writable&&!n.set)}catch{return!1}}supportsScrolling(){try{return!!this.window&&!!this.window.scrollTo&&"pageXOffset"in this.window}catch{return!1}}}function xC(e){return Object.getOwnPropertyDescriptor(e,"scrollRestoration")} +let GP=(()=>{class e{}return e.\u0275prov=G({token:e,providedIn:"root",factory:()=>new WP(L(Dt),window)}),e})();class WP{constructor(n,t){this.document=n,this.window=t,this.offset=()=>[0,0]}setOffset(n){this.offset=Array.isArray(n)?()=>n:n}getScrollPosition(){return this.supportsScrolling()?[this.window.pageXOffset,this.window.pageYOffset]:[0,0]}scrollToPosition(n){this.supportsScrolling()&&this.window.scrollTo(n[0],n[1])}scrollToAnchor(n){if(!this.supportsScrolling())return;const t=function zP(e,n){const t=e.getElementById(n)||e.getElementsByName(n)[0];if(t)return t;if("function"==typeof e.createTreeWalker&&e.body&&(e.body.createShadowRoot||e.body.attachShadow)){const i=e.createTreeWalker(e.body,NodeFilter.SHOW_ELEMENT);let r=i.currentNode;for(;r;){const o=r.shadowRoot;if(o){const s=o.getElementById(n)||o.querySelector(`[name="${n}"]`);if(s)return s}r=i.nextNode()}}return null}(this.document,n);t&&(this.scrollToElement(t),t.focus())}setHistoryScrollRestoration(n){if(this.supportScrollRestoration()){const t=this.window.history;t&&t.scrollRestoration&&(t.scrollRestoration=n)}}scrollToElement(n){const t=n.getBoundingClientRect(),i=t.left+this.window.pageXOffset,r=t.top+this.window.pageYOffset,o=this.offset();this.window.scrollTo(i-o[0],r-o[1])}supportScrollRestoration(){try{if(!this.supportsScrolling())return!1;const n=RC(this.window.history)||RC(Object.getPrototypeOf(this.window.history));return!(!n||!n.writable&&!n.set)}catch{return!1}}supportsScrolling(){try{return!!this.window&&!!this.window.scrollTo&&"pageXOffset"in this.window}catch{return!1}}}function RC(e){return Object.getOwnPropertyDescriptor(e,"scrollRestoration")} /** * @license * Copyright Google LLC All Rights Reserved. @@ -1292,7 +1292,7 @@ let GF=(()=>{class e{}return e.\u0275prov=G({token:e,providedIn:"root",factory:( * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -class FC{} +class PC{} /** * @license * Copyright Google LLC All Rights Reserved. @@ -1307,7 +1307,7 @@ class FC{} * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -class Bm extends +class Hm extends /** * @license * Copyright Google LLC All Rights Reserved. @@ -1348,21 +1348,21 @@ class Bm extends * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -class uP extends class Sx{}{constructor(){super(...arguments),this.supportsDOMEvents=!0}}{static makeCurrent(){!function wx(e){Pd||(Pd=e)}(new Bm)}onAndCancel(n,t,i){return n.addEventListener(t,i,!1),()=>{n.removeEventListener(t,i,!1)}}dispatchEvent(n,t){n.dispatchEvent(t)}remove(n){n.parentNode&&n.parentNode.removeChild(n)}createElement(n,t){return(t=t||this.getDefaultDocument()).createElement(n)}createHtmlDocument(){return document.implementation.createHTMLDocument("fakeTitle")}getDefaultDocument(){return document}isElementNode(n){return n.nodeType===Node.ELEMENT_NODE}isShadowRoot(n){return n instanceof DocumentFragment}getGlobalEventTarget(n,t){return"window"===t?window:"document"===t?n:"body"===t?n.body:null}getBaseHref(n){const t=function dP(){return vc=vc||document.querySelector("base"),vc?vc.getAttribute("href"):null}();return null==t?null:function fP(e){zd=zd||document.createElement("a"),zd.setAttribute("href",e);const n=zd.pathname;return"/"===n.charAt(0)?n:`/${n}`} +class uF extends class SR{}{constructor(){super(...arguments),this.supportsDOMEvents=!0}}{static makeCurrent(){!function wR(e){Fd||(Fd=e)}(new Hm)}onAndCancel(n,t,i){return n.addEventListener(t,i,!1),()=>{n.removeEventListener(t,i,!1)}}dispatchEvent(n,t){n.dispatchEvent(t)}remove(n){n.parentNode&&n.parentNode.removeChild(n)}createElement(n,t){return(t=t||this.getDefaultDocument()).createElement(n)}createHtmlDocument(){return document.implementation.createHTMLDocument("fakeTitle")}getDefaultDocument(){return document}isElementNode(n){return n.nodeType===Node.ELEMENT_NODE}isShadowRoot(n){return n instanceof DocumentFragment}getGlobalEventTarget(n,t){return"window"===t?window:"document"===t?n:"body"===t?n.body:null}getBaseHref(n){const t=function dF(){return vc=vc||document.querySelector("base"),vc?vc.getAttribute("href"):null}();return null==t?null:function fF(e){Yd=Yd||document.createElement("a"),Yd.setAttribute("href",e);const n=Yd.pathname;return"/"===n.charAt(0)?n:`/${n}`} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */(t)}resetBaseElement(){vc=null}getUserAgent(){return window.navigator.userAgent}getCookie(n){return wC(document.cookie,n)}}let zd,vc=null;const HC=new q("TRANSITION_ID"),pP=[{provide:Ad,useFactory:function hP(e,n,t){return()=>{t.get(Id).donePromise.then(()=>{const i=lr(),r=n.querySelectorAll(`style[ng-transition="${e}"]`);for(let o=0;o{class e{build(){return new XMLHttpRequest}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(); + */(t)}resetBaseElement(){vc=null}getUserAgent(){return window.navigator.userAgent}getCookie(n){return wC(document.cookie,n)}}let Yd,vc=null;const BC=new q("TRANSITION_ID"),pF=[{provide:Id,useFactory:function hF(e,n,t){return()=>{t.get(Ad).donePromise.then(()=>{const i=lr(),r=n.querySelectorAll(`style[ng-transition="${e}"]`);for(let o=0;o{class e{build(){return new XMLHttpRequest}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(); /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */const Yd=new q("EventManagerPlugins");let qd=(()=>{class e{constructor(t,i){this._zone=i,this._eventNameToPlugin=new Map,t.forEach(r=>r.manager=this),this._plugins=t.slice().reverse()}addEventListener(t,i,r){return this._findPluginFor(i).addEventListener(t,i,r)}addGlobalEventListener(t,i,r){return this._findPluginFor(i).addGlobalEventListener(t,i,r)}getZone(){return this._zone}_findPluginFor(t){const i=this._eventNameToPlugin.get(t);if(i)return i;const r=this._plugins;for(let o=0;o{class e{constructor(t,i){this._zone=i,this._eventNameToPlugin=new Map,t.forEach(r=>r.manager=this),this._plugins=t.slice().reverse()}addEventListener(t,i,r){return this._findPluginFor(i).addEventListener(t,i,r)}addGlobalEventListener(t,i,r){return this._findPluginFor(i).addGlobalEventListener(t,i,r)}getZone(){return this._zone}_findPluginFor(t){const i=this._eventNameToPlugin.get(t);if(i)return i;const r=this._plugins;for(let o=0;o{if("__ngUnwrap__"===n)return e;!1===e(n)&&(n.preventDefault(),n.returnValue=!1)}}let Um=(()=>{class e{constructor(t,i,r){this.eventManager=t,this.sharedStylesHost=i,this.appId=r,this.rendererByCompId=new Map,this.defaultRenderer=new Gm(t)}createRenderer(t,i){if(!t||!i)return this.defaultRenderer;switch(i.encapsulation){case ai.Emulated:{let r=this.rendererByCompId.get(i.id);return r||(r=new CP(this.eventManager,this.sharedStylesHost,i,this.appId),this.rendererByCompId.set(i.id,r)),r.applyToHost(t),r}case 1:case ai.ShadowDom:return new wP(this.eventManager,this.sharedStylesHost,t,i);default:if(!this.rendererByCompId.has(i.id)){const r=Jd(i.id,i.styles,[]);this.sharedStylesHost.addStyles(r),this.rendererByCompId.set(i.id,this.defaultRenderer)}return this.defaultRenderer}}begin(){}end(){}}return e.\u0275fac=function(t){return new(t||e)(L(qd),L(yc),L(uc))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})();class Gm{constructor(n){this.eventManager=n,this.data=Object.create(null),this.destroyNode=null}destroy(){}createElement(n,t){return t?document.createElementNS(jm[t]||t,n):document.createElement(n)}createComment(n){return document.createComment(n)}createText(n){return document.createTextNode(n)}appendChild(n,t){(zC(n)?n.content:n).appendChild(t)}insertBefore(n,t,i){n&&(zC(n)?n.content:n).insertBefore(t,i)}removeChild(n,t){n&&n.removeChild(t)}selectRootElement(n,t){let i="string"==typeof n?document.querySelector(n):n;if(!i)throw new Error(`The selector "${n}" did not match any elements`);return t||(i.textContent=""),i}parentNode(n){return n.parentNode}nextSibling(n){return n.nextSibling}setAttribute(n,t,i,r){if(r){t=r+":"+t;const o=jm[r];o?n.setAttributeNS(o,t,i):n.setAttribute(t,i)}else n.setAttribute(t,i)}removeAttribute(n,t,i){if(i){const r=jm[i];r?n.removeAttributeNS(r,t):n.removeAttribute(`${i}:${t}`)}else n.removeAttribute(t)}addClass(n,t){n.classList.add(t)}removeClass(n,t){n.classList.remove(t)}setStyle(n,t,i,r){r&(Un.DashCase|Un.Important)?n.style.setProperty(t,i,r&Un.Important?"important":""):n.style[t]=i}removeStyle(n,t,i){i&Un.DashCase?n.style.removeProperty(t):n.style[t]=""}setProperty(n,t,i){n[t]=i}setValue(n,t){n.nodeValue=t}listen(n,t,i){return"string"==typeof n?this.eventManager.addGlobalEventListener(n,t,WC(i)):this.eventManager.addEventListener(n,t,WC(i))}}function zC(e){return"TEMPLATE"===e.tagName&&void 0!==e.content}class CP extends Gm{constructor(n,t,i,r){super(n),this.component=i;const o=Jd(r+"-"+i.id,i.styles,[]);t.addStyles(o),this.contentAttr=function yP(e){return"_ngcontent-%COMP%".replace($m,e)}(r+"-"+i.id),this.hostAttr=function bP(e){return"_nghost-%COMP%".replace($m,e)}(r+"-"+i.id)}applyToHost(n){super.setAttribute(n,this.hostAttr,"")}createElement(n,t){const i=super.createElement(n,t);return super.setAttribute(i,this.contentAttr,""),i}}class wP extends Gm{constructor(n,t,i,r){super(n),this.sharedStylesHost=t,this.hostEl=i,this.shadowRoot=i.attachShadow({mode:"open"}),this.sharedStylesHost.addHost(this.shadowRoot);const o=Jd(r.id,r.styles,[]);for(let s=0;s{if("__ngUnwrap__"===n)return e;!1===e(n)&&(n.preventDefault(),n.returnValue=!1)}}let Um=(()=>{class e{constructor(t,i,r){this.eventManager=t,this.sharedStylesHost=i,this.appId=r,this.rendererByCompId=new Map,this.defaultRenderer=new Gm(t)}createRenderer(t,i){if(!t||!i)return this.defaultRenderer;switch(i.encapsulation){case ai.Emulated:{let r=this.rendererByCompId.get(i.id);return r||(r=new CF(this.eventManager,this.sharedStylesHost,i,this.appId),this.rendererByCompId.set(i.id,r)),r.applyToHost(t),r}case 1:case ai.ShadowDom:return new wF(this.eventManager,this.sharedStylesHost,t,i);default:if(!this.rendererByCompId.has(i.id)){const r=Zd(i.id,i.styles,[]);this.sharedStylesHost.addStyles(r),this.rendererByCompId.set(i.id,this.defaultRenderer)}return this.defaultRenderer}}begin(){}end(){}}return e.\u0275fac=function(t){return new(t||e)(L(qd),L(yc),L(uc))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})();class Gm{constructor(n){this.eventManager=n,this.data=Object.create(null),this.destroyNode=null}destroy(){}createElement(n,t){return t?document.createElementNS(jm[t]||t,n):document.createElement(n)}createComment(n){return document.createComment(n)}createText(n){return document.createTextNode(n)}appendChild(n,t){(YC(n)?n.content:n).appendChild(t)}insertBefore(n,t,i){n&&(YC(n)?n.content:n).insertBefore(t,i)}removeChild(n,t){n&&n.removeChild(t)}selectRootElement(n,t){let i="string"==typeof n?document.querySelector(n):n;if(!i)throw new Error(`The selector "${n}" did not match any elements`);return t||(i.textContent=""),i}parentNode(n){return n.parentNode}nextSibling(n){return n.nextSibling}setAttribute(n,t,i,r){if(r){t=r+":"+t;const o=jm[r];o?n.setAttributeNS(o,t,i):n.setAttribute(t,i)}else n.setAttribute(t,i)}removeAttribute(n,t,i){if(i){const r=jm[i];r?n.removeAttributeNS(r,t):n.removeAttribute(`${i}:${t}`)}else n.removeAttribute(t)}addClass(n,t){n.classList.add(t)}removeClass(n,t){n.classList.remove(t)}setStyle(n,t,i,r){r&(Un.DashCase|Un.Important)?n.style.setProperty(t,i,r&Un.Important?"important":""):n.style[t]=i}removeStyle(n,t,i){i&Un.DashCase?n.style.removeProperty(t):n.style[t]=""}setProperty(n,t,i){n[t]=i}setValue(n,t){n.nodeValue=t}listen(n,t,i){return"string"==typeof n?this.eventManager.addGlobalEventListener(n,t,WC(i)):this.eventManager.addEventListener(n,t,WC(i))}}function YC(e){return"TEMPLATE"===e.tagName&&void 0!==e.content}class CF extends Gm{constructor(n,t,i,r){super(n),this.component=i;const o=Zd(r+"-"+i.id,i.styles,[]);t.addStyles(o),this.contentAttr=function yF(e){return"_ngcontent-%COMP%".replace($m,e)}(r+"-"+i.id),this.hostAttr=function bF(e){return"_nghost-%COMP%".replace($m,e)}(r+"-"+i.id)}applyToHost(n){super.setAttribute(n,this.hostAttr,"")}createElement(n,t){const i=super.createElement(n,t);return super.setAttribute(i,this.contentAttr,""),i}}class wF extends Gm{constructor(n,t,i,r){super(n),this.sharedStylesHost=t,this.hostEl=i,this.shadowRoot=i.attachShadow({mode:"open"}),this.sharedStylesHost.addHost(this.shadowRoot);const o=Zd(r.id,r.styles,[]);for(let s=0;s{class e extends BC{constructor(t){super(t)}supports(t){return!0}addEventListener(t,i,r){return t.addEventListener(i,r,!1),()=>this.removeEventListener(t,i,r)}removeEventListener(t,i,r){return t.removeEventListener(i,r)}}return e.\u0275fac=function(t){return new(t||e)(L(Dt))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(); + */let SF=(()=>{class e extends HC{constructor(t){super(t)}supports(t){return!0}addEventListener(t,i,r){return t.addEventListener(i,r,!1),()=>this.removeEventListener(t,i,r)}removeEventListener(t,i,r){return t.removeEventListener(i,r)}}return e.\u0275fac=function(t){return new(t||e)(L(Dt))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(); /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */const YC=["alt","control","meta","shift"],EP={"\b":"Backspace","\t":"Tab","\x7f":"Delete","\x1b":"Escape",Del:"Delete",Esc:"Escape",Left:"ArrowLeft",Right:"ArrowRight",Up:"ArrowUp",Down:"ArrowDown",Menu:"ContextMenu",Scroll:"ScrollLock",Win:"OS"},MP={alt:e=>e.altKey,control:e=>e.ctrlKey,meta:e=>e.metaKey,shift:e=>e.shiftKey};let NP=(()=>{class e extends BC{constructor(t){super(t)}supports(t){return null!=e.parseEventName(t)}addEventListener(t,i,r){const o=e.parseEventName(i),s=e.eventCallback(o.fullKey,r,this.manager.getZone());return this.manager.getZone().runOutsideAngular(()=>lr().onAndCancel(t,o.domEventName,s))}static parseEventName(t){const i=t.toLowerCase().split("."),r=i.shift();if(0===i.length||"keydown"!==r&&"keyup"!==r)return null;const o=e._normalizeKey(i.pop());let s="",a=i.indexOf("code");if(a>-1&&(i.splice(a,1),s="code."),YC.forEach(u=>{const f=i.indexOf(u);f>-1&&(i.splice(f,1),s+=u+".")}),s+=o,0!=i.length||0===o.length)return null;const l={};return l.domEventName=r,l.fullKey=s,l}static matchEventFullKeyCode(t,i){let r=EP[t.key]||t.key,o="";return i.indexOf("code.")>-1&&(r=t.code,o="code."),!(null==r||!r)&&(r=r.toLowerCase()," "===r?r="space":"."===r&&(r="dot"),YC.forEach(s=>{s!==r&&(0,MP[s])(t)&&(o+=s+".")}),o+=r,o===i)}static eventCallback(t,i,r){return o=>{e.matchEventFullKeyCode(o,t)&&r.runGuarded(()=>i(o))}}static _normalizeKey(t){return"esc"===t?"escape":t}}return e.\u0275fac=function(t){return new(t||e)(L(Dt))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(); + */const KC=["alt","control","meta","shift"],MF={"\b":"Backspace","\t":"Tab","\x7f":"Delete","\x1b":"Escape",Del:"Delete",Esc:"Escape",Left:"ArrowLeft",Right:"ArrowRight",Up:"ArrowUp",Down:"ArrowDown",Menu:"ContextMenu",Scroll:"ScrollLock",Win:"OS"},NF={alt:e=>e.altKey,control:e=>e.ctrlKey,meta:e=>e.metaKey,shift:e=>e.shiftKey};let EF=(()=>{class e extends HC{constructor(t){super(t)}supports(t){return null!=e.parseEventName(t)}addEventListener(t,i,r){const o=e.parseEventName(i),s=e.eventCallback(o.fullKey,r,this.manager.getZone());return this.manager.getZone().runOutsideAngular(()=>lr().onAndCancel(t,o.domEventName,s))}static parseEventName(t){const i=t.toLowerCase().split("."),r=i.shift();if(0===i.length||"keydown"!==r&&"keyup"!==r)return null;const o=e._normalizeKey(i.pop());let s="",a=i.indexOf("code");if(a>-1&&(i.splice(a,1),s="code."),KC.forEach(u=>{const f=i.indexOf(u);f>-1&&(i.splice(f,1),s+=u+".")}),s+=o,0!=i.length||0===o.length)return null;const l={};return l.domEventName=r,l.fullKey=s,l}static matchEventFullKeyCode(t,i){let r=MF[t.key]||t.key,o="";return i.indexOf("code.")>-1&&(r=t.code,o="code."),!(null==r||!r)&&(r=r.toLowerCase()," "===r?r="space":"."===r&&(r="dot"),KC.forEach(s=>{s!==r&&(0,NF[s])(t)&&(o+=s+".")}),o+=r,o===i)}static eventCallback(t,i,r){return o=>{e.matchEventFullKeyCode(o,t)&&r.runGuarded(()=>i(o))}}static _normalizeKey(t){return"esc"===t?"escape":t}}return e.\u0275fac=function(t){return new(t||e)(L(Dt))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(); /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */const OP=G1(bx,"browser",[{provide:dc,useValue:kC},{provide:x1,useValue:function TP(){Bm.makeCurrent()},multi:!0},{provide:Dt,useFactory:function IP(){return function WN(e){yp=e}(document),document},deps:[]}]),ZC=new q(""),QC=[{provide:Od,useClass: + */const kF=G1(bR,"browser",[{provide:dc,useValue:OC},{provide:R1,useValue:function TF(){Hm.makeCurrent()},multi:!0},{provide:Dt,useFactory:function AF(){return function WE(e){yp=e}(document),document},deps:[]}]),JC=new q(""),QC=[{provide:kd,useClass: /** * @license * Copyright Google LLC All Rights Reserved. @@ -1405,7 +1405,7 @@ class uP extends class Sx{}{constructor(){super(...arguments),this.supportsDOMEv * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -class gP{addToWindow(n){We.getAngularTestability=(i,r=!0)=>{const o=n.findTestabilityInTree(i,r);if(null==o)throw new Error("Could not find testability for element.");return o},We.getAllAngularTestabilities=()=>n.getAllTestabilities(),We.getAllAngularRootElements=()=>n.getAllRootElements(),We.frameworkStabilizers||(We.frameworkStabilizers=[]),We.frameworkStabilizers.push(i=>{const r=We.getAllAngularTestabilities();let o=r.length,s=!1;const a=function(l){s=s||l,o--,0==o&&i(s)};r.forEach(function(l){l.whenStable(a)})})}findTestabilityInTree(n,t,i){return null==t?null:n.getTestability(t)??(i?lr().isShadowRoot(t)?this.findTestabilityInTree(n,t.host,!0):this.findTestabilityInTree(n,t.parentElement,!0):null)}},deps:[]},{provide:B1,useClass:fm,deps:[ze,hm,Od]},{provide:fm,useClass:fm,deps:[ze,hm,Od]}],XC=[{provide:Ip,useValue:"root"},{provide:da,useFactory:function AP(){return new da},deps:[]},{provide:Yd,useClass:SP,multi:!0,deps:[Dt,ze,dc]},{provide:Yd,useClass:NP,multi:!0,deps:[Dt]},{provide:Um,useClass:Um,deps:[qd,yc,uc]},{provide:xp,useExisting:Um},{provide:jC,useExisting:yc},{provide:yc,useClass:yc,deps:[Dt]},{provide:qd,useClass:qd,deps:[Yd,ze]},{provide:FC,useClass:mP,deps:[]},[]];let kP=(()=>{class e{constructor(t){}static withServerTransition(t){return{ngModule:e,providers:[{provide:uc,useValue:t.appId},{provide:HC,useExisting:uc},pP]}}}return e.\u0275fac=function(t){return new(t||e)(L(ZC,12))},e.\u0275mod=Ne({type:e}),e.\u0275inj=Me({providers:[...XC,...QC],imports:[ei,Dx]}),e})(),ew=(()=>{class e{constructor(t){this._doc=t}getTitle(){return this._doc.title}setTitle(t){this._doc.title=t||""}}return e.\u0275fac=function(t){return new(t||e)(L(Dt))},e.\u0275prov=G({token:e,factory:function(t){let i=null;return i=t?new t: +class gF{addToWindow(n){We.getAngularTestability=(i,r=!0)=>{const o=n.findTestabilityInTree(i,r);if(null==o)throw new Error("Could not find testability for element.");return o},We.getAllAngularTestabilities=()=>n.getAllTestabilities(),We.getAllAngularRootElements=()=>n.getAllRootElements(),We.frameworkStabilizers||(We.frameworkStabilizers=[]),We.frameworkStabilizers.push(i=>{const r=We.getAllAngularTestabilities();let o=r.length,s=!1;const a=function(l){s=s||l,o--,0==o&&i(s)};r.forEach(function(l){l.whenStable(a)})})}findTestabilityInTree(n,t,i){return null==t?null:n.getTestability(t)??(i?lr().isShadowRoot(t)?this.findTestabilityInTree(n,t.host,!0):this.findTestabilityInTree(n,t.parentElement,!0):null)}},deps:[]},{provide:H1,useClass:fm,deps:[Ye,hm,kd]},{provide:fm,useClass:fm,deps:[Ye,hm,kd]}],XC=[{provide:Ap,useValue:"root"},{provide:da,useFactory:function IF(){return new da},deps:[]},{provide:Kd,useClass:SF,multi:!0,deps:[Dt,Ye,dc]},{provide:Kd,useClass:EF,multi:!0,deps:[Dt]},{provide:Um,useClass:Um,deps:[qd,yc,uc]},{provide:Rp,useExisting:Um},{provide:jC,useExisting:yc},{provide:yc,useClass:yc,deps:[Dt]},{provide:qd,useClass:qd,deps:[Kd,Ye]},{provide:PC,useClass:mF,deps:[]},[]];let OF=(()=>{class e{constructor(t){}static withServerTransition(t){return{ngModule:e,providers:[{provide:uc,useValue:t.appId},{provide:BC,useExisting:uc},pF]}}}return e.\u0275fac=function(t){return new(t||e)(L(JC,12))},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({providers:[...XC,...QC],imports:[ei,DR]}),e})(),ew=(()=>{class e{constructor(t){this._doc=t}getTitle(){return this._doc.title}setTitle(t){this._doc.title=t||""}}return e.\u0275fac=function(t){return new(t||e)(L(Dt))},e.\u0275prov=G({token:e,factory:function(t){let i=null;return i=t?new t: /** * @license * Copyright Google LLC All Rights Reserved. @@ -1413,7 +1413,7 @@ class gP{addToWindow(n){We.getAngularTestability=(i,r=!0)=>{const o=n.findTestab * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -function xP(){return new ew(L(Dt))}(),i},providedIn:"root"}),e})(); +function RF(){return new ew(L(Dt))}(),i},providedIn:"root"}),e})(); /** * @license * Copyright Google LLC All Rights Reserved. @@ -1442,7 +1442,7 @@ function xP(){return new ew(L(Dt))}(),i},providedIn:"root"}),e})(); * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -function Z(...e){return gt(e,en(e))}typeof window<"u"&&window;class zt extends Ue{constructor(n){super(),this._value=n}get value(){return this.getValue()}_subscribe(n){const t=super._subscribe(n);return!t.closed&&n.next(this._value),t}getValue(){const{hasError:n,thrownError:t,_value:i}=this;if(n)throw t;return this._throwIfClosed(),i}next(n){super.next(this._value=n)}}const bc=V(e=>function(){e(this),this.name="EmptyError",this.message="no elements in sequence"}),{isArray:$P}=Array,{getPrototypeOf:UP,prototype:GP,keys:WP}=Object;function iw(e){if(1===e.length){const n=e[0];if($P(n))return{args:n,keys:null};if(function KP(e){return e&&"object"==typeof e&&UP(e)===GP}(n)){const t=WP(n);return{args:t.map(i=>n[i]),keys:t}}}return{args:e,keys:null}}const{isArray:zP}=Array;function zm(e){return ne(n=>function YP(e,n){return zP(n)?e(...n):e(n)}(e,n))}function rw(e,n){return e.reduce((t,i,r)=>(t[i]=n[r],t),{})}function Zd(...e){const n=en(e),t=rt(e),{args:i,keys:r}=iw(e);if(0===i.length)return gt([],n);const o=new je(function qP(e,n,t=xn){return i=>{ow(n,()=>{const{length:r}=e,o=new Array(r);let s=r,a=r;for(let l=0;l{const u=gt(e[l],n);let f=!1;u.subscribe(ke(i,p=>{o[l]=p,f||(f=!0,a--),a||i.next(t(o.slice()))},()=>{--s||i.complete()}))},i)},i)}}(i,n,r?s=>rw(r,s):xn));return t?o.pipe(zm(t)):o}function ow(e,n,t){e?wi(t,e,n):n()}function Dc(...e){return function JP(){return Se(1)}()(gt(e,en(e)))}function sw(e){return new je(n=>{ut(e()).subscribe(n)})}function Ra(e,n){const t=ye(e)?e:()=>e,i=r=>r.error(t());return new je(n?r=>n.schedule(i,0,r):i)}function Ym(){return qe((e,n)=>{let t=null;e._refCount++;const i=ke(n,void 0,void 0,void 0,()=>{if(!e||e._refCount<=0||0<--e._refCount)return void(t=null);const r=e._connection,o=t;t=null,r&&(!o||r===o)&&r.unsubscribe(),n.unsubscribe()});e.subscribe(i),i.closed||(t=e.connect())})}class aw extends je{constructor(n,t){super(),this.source=n,this.subjectFactory=t,this._subject=null,this._refCount=0,this._connection=null,z(n)&&(this.lift=n.lift)}_subscribe(n){return this.getSubject().subscribe(n)}getSubject(){const n=this._subject;return(!n||n.isStopped)&&(this._subject=this.subjectFactory()),this._subject}_teardown(){this._refCount=0;const{_connection:n}=this;this._subject=this._connection=null,n?.unsubscribe()}connect(){let n=this._connection;if(!n){n=this._connection=new Ct;const t=this.getSubject();n.add(this.source.subscribe(ke(t,void 0,()=>{this._teardown(),t.complete()},i=>{this._teardown(),t.error(i)},()=>this._teardown()))),n.closed&&(this._connection=null,n=Ct.EMPTY)}return n}refCount(){return Ym()(this)}}function vi(e,n){return qe((t,i)=>{let r=null,o=0,s=!1;const a=()=>s&&!r&&i.complete();t.subscribe(ke(i,l=>{r?.unsubscribe();let u=0;const f=o++;ut(e(l,f)).subscribe(r=ke(i,p=>i.next(n?n(l,p,f,u++):p),()=>{r=null,a()}))},()=>{s=!0,a()}))})}function sn(e){return e<=0?()=>Xt:qe((n,t)=>{let i=0;n.subscribe(ke(t,r=>{++i<=e&&(t.next(r),e<=i&&t.complete())}))})}function vn(e,n){return qe((t,i)=>{let r=0;t.subscribe(ke(i,o=>e.call(n,o,r++)&&i.next(o)))})}function Xd(e){return qe((n,t)=>{let i=!1;n.subscribe(ke(t,r=>{i=!0,t.next(r)},()=>{i||t.next(e),t.complete()}))})}function lw(e=ZP){return qe((n,t)=>{let i=!1;n.subscribe(ke(t,r=>{i=!0,t.next(r)},()=>i?t.complete():t.error(e())))})}function ZP(){return new bc}function mo(e,n){const t=arguments.length>=2;return i=>i.pipe(e?vn((r,o)=>e(r,o,i)):xn,sn(1),t?Xd(n):lw(()=>new bc))}function _o(e,n){return ye(n)?dt(e,n,1):dt(e,1)}function Yt(e,n,t){const i=ye(e)||n||t?{next:e,error:n,complete:t}:e;return i?qe((r,o)=>{var s;null===(s=i.subscribe)||void 0===s||s.call(i);let a=!0;r.subscribe(ke(o,l=>{var u;null===(u=i.next)||void 0===u||u.call(i,l),o.next(l)},()=>{var l;a=!1,null===(l=i.complete)||void 0===l||l.call(i),o.complete()},l=>{var u;a=!1,null===(u=i.error)||void 0===u||u.call(i,l),o.error(l)},()=>{var l,u;a&&(null===(l=i.unsubscribe)||void 0===l||l.call(i)),null===(u=i.finalize)||void 0===u||u.call(i)}))}):xn}function $r(e){return qe((n,t)=>{let o,i=null,r=!1;i=n.subscribe(ke(t,void 0,void 0,s=>{o=ut(e(s,$r(e)(n))),i?(i.unsubscribe(),i=null,o.subscribe(t)):r=!0})),r&&(i.unsubscribe(),i=null,o.subscribe(t))})}function QP(e,n,t,i,r){return(o,s)=>{let a=t,l=n,u=0;o.subscribe(ke(s,f=>{const p=u++;l=a?e(l,f,p):(a=!0,f),i&&s.next(l)},r&&(()=>{a&&s.next(l),s.complete()})))}}function cw(e,n){return qe(QP(e,n,arguments.length>=2,!0))}function qm(e){return e<=0?()=>Xt:qe((n,t)=>{let i=[];n.subscribe(ke(t,r=>{i.push(r),e{for(const r of i)t.next(r);t.complete()},void 0,()=>{i=null}))})}function uw(e,n){const t=arguments.length>=2;return i=>i.pipe(e?vn((r,o)=>e(r,o,i)):xn,qm(1),t?Xd(n):lw(()=>new bc))}function Jm(e){return qe((n,t)=>{try{n.subscribe(t)}finally{t.add(e)}})} +function J(...e){return gt(e,en(e))}typeof window<"u"&&window;class Yt extends Ue{constructor(n){super(),this._value=n}get value(){return this.getValue()}_subscribe(n){const t=super._subscribe(n);return!t.closed&&n.next(this._value),t}getValue(){const{hasError:n,thrownError:t,_value:i}=this;if(n)throw t;return this._throwIfClosed(),i}next(n){super.next(this._value=n)}}const bc=V(e=>function(){e(this),this.name="EmptyError",this.message="no elements in sequence"}),{isArray:$F}=Array,{getPrototypeOf:UF,prototype:GF,keys:WF}=Object;function iw(e){if(1===e.length){const n=e[0];if($F(n))return{args:n,keys:null};if(function zF(e){return e&&"object"==typeof e&&UF(e)===GF}(n)){const t=WF(n);return{args:t.map(i=>n[i]),keys:t}}}return{args:e,keys:null}}const{isArray:YF}=Array;function Ym(e){return ne(n=>function KF(e,n){return YF(n)?e(...n):e(n)}(e,n))}function rw(e,n){return e.reduce((t,i,r)=>(t[i]=n[r],t),{})}function Jd(...e){const n=en(e),t=rt(e),{args:i,keys:r}=iw(e);if(0===i.length)return gt([],n);const o=new je(function qF(e,n,t=Rn){return i=>{ow(n,()=>{const{length:r}=e,o=new Array(r);let s=r,a=r;for(let l=0;l{const u=gt(e[l],n);let f=!1;u.subscribe(Oe(i,p=>{o[l]=p,f||(f=!0,a--),a||i.next(t(o.slice()))},()=>{--s||i.complete()}))},i)},i)}}(i,n,r?s=>rw(r,s):Rn));return t?o.pipe(Ym(t)):o}function ow(e,n,t){e?wi(t,e,n):n()}function Dc(...e){return function ZF(){return Se(1)}()(gt(e,en(e)))}function sw(e){return new je(n=>{ut(e()).subscribe(n)})}function xa(e,n){const t=ye(e)?e:()=>e,i=r=>r.error(t());return new je(n?r=>n.schedule(i,0,r):i)}function Km(){return qe((e,n)=>{let t=null;e._refCount++;const i=Oe(n,void 0,void 0,void 0,()=>{if(!e||e._refCount<=0||0<--e._refCount)return void(t=null);const r=e._connection,o=t;t=null,r&&(!o||r===o)&&r.unsubscribe(),n.unsubscribe()});e.subscribe(i),i.closed||(t=e.connect())})}class aw extends je{constructor(n,t){super(),this.source=n,this.subjectFactory=t,this._subject=null,this._refCount=0,this._connection=null,Y(n)&&(this.lift=n.lift)}_subscribe(n){return this.getSubject().subscribe(n)}getSubject(){const n=this._subject;return(!n||n.isStopped)&&(this._subject=this.subjectFactory()),this._subject}_teardown(){this._refCount=0;const{_connection:n}=this;this._subject=this._connection=null,n?.unsubscribe()}connect(){let n=this._connection;if(!n){n=this._connection=new Ct;const t=this.getSubject();n.add(this.source.subscribe(Oe(t,void 0,()=>{this._teardown(),t.complete()},i=>{this._teardown(),t.error(i)},()=>this._teardown()))),n.closed&&(this._connection=null,n=Ct.EMPTY)}return n}refCount(){return Km()(this)}}function vi(e,n){return qe((t,i)=>{let r=null,o=0,s=!1;const a=()=>s&&!r&&i.complete();t.subscribe(Oe(i,l=>{r?.unsubscribe();let u=0;const f=o++;ut(e(l,f)).subscribe(r=Oe(i,p=>i.next(n?n(l,p,f,u++):p),()=>{r=null,a()}))},()=>{s=!0,a()}))})}function sn(e){return e<=0?()=>Xt:qe((n,t)=>{let i=0;n.subscribe(Oe(t,r=>{++i<=e&&(t.next(r),e<=i&&t.complete())}))})}function vn(e,n){return qe((t,i)=>{let r=0;t.subscribe(Oe(i,o=>e.call(n,o,r++)&&i.next(o)))})}function Xd(e){return qe((n,t)=>{let i=!1;n.subscribe(Oe(t,r=>{i=!0,t.next(r)},()=>{i||t.next(e),t.complete()}))})}function lw(e=JF){return qe((n,t)=>{let i=!1;n.subscribe(Oe(t,r=>{i=!0,t.next(r)},()=>i?t.complete():t.error(e())))})}function JF(){return new bc}function mo(e,n){const t=arguments.length>=2;return i=>i.pipe(e?vn((r,o)=>e(r,o,i)):Rn,sn(1),t?Xd(n):lw(()=>new bc))}function _o(e,n){return ye(n)?dt(e,n,1):dt(e,1)}function Kt(e,n,t){const i=ye(e)||n||t?{next:e,error:n,complete:t}:e;return i?qe((r,o)=>{var s;null===(s=i.subscribe)||void 0===s||s.call(i);let a=!0;r.subscribe(Oe(o,l=>{var u;null===(u=i.next)||void 0===u||u.call(i,l),o.next(l)},()=>{var l;a=!1,null===(l=i.complete)||void 0===l||l.call(i),o.complete()},l=>{var u;a=!1,null===(u=i.error)||void 0===u||u.call(i,l),o.error(l)},()=>{var l,u;a&&(null===(l=i.unsubscribe)||void 0===l||l.call(i)),null===(u=i.finalize)||void 0===u||u.call(i)}))}):Rn}function $r(e){return qe((n,t)=>{let o,i=null,r=!1;i=n.subscribe(Oe(t,void 0,void 0,s=>{o=ut(e(s,$r(e)(n))),i?(i.unsubscribe(),i=null,o.subscribe(t)):r=!0})),r&&(i.unsubscribe(),i=null,o.subscribe(t))})}function QF(e,n,t,i,r){return(o,s)=>{let a=t,l=n,u=0;o.subscribe(Oe(s,f=>{const p=u++;l=a?e(l,f,p):(a=!0,f),i&&s.next(l)},r&&(()=>{a&&s.next(l),s.complete()})))}}function cw(e,n){return qe(QF(e,n,arguments.length>=2,!0))}function qm(e){return e<=0?()=>Xt:qe((n,t)=>{let i=[];n.subscribe(Oe(t,r=>{i.push(r),e{for(const r of i)t.next(r);t.complete()},void 0,()=>{i=null}))})}function uw(e,n){const t=arguments.length>=2;return i=>i.pipe(e?vn((r,o)=>e(r,o,i)):Rn,qm(1),t?Xd(n):lw(()=>new bc))}function Zm(e){return qe((n,t)=>{try{n.subscribe(t)}finally{t.add(e)}})} /** * @license Angular v14.2.9 * (c) 2010-2022 Google LLC. https://angular.io/ @@ -1454,35 +1454,35 @@ function Z(...e){return gt(e,en(e))}typeof window<"u"&&window;class zt extends U * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */const pe="primary",Cc=Symbol("RouteTitle");class eL{constructor(n){this.params=n||{}}has(n){return Object.prototype.hasOwnProperty.call(this.params,n)}get(n){if(this.has(n)){const t=this.params[n];return Array.isArray(t)?t[0]:t}return null}getAll(n){if(this.has(n)){const t=this.params[n];return Array.isArray(t)?t:[t]}return[]}get keys(){return Object.keys(this.params)}}function xa(e){return new eL(e)}function tL(e,n,t){const i=t.path.split("/");if(i.length>e.length||"full"===t.pathMatch&&(n.hasChildren()||i.lengthe.length||"full"===t.pathMatch&&(n.hasChildren()||i.lengthi[o]===r)}return e===n}function hw(e){return Array.prototype.concat.apply([],e)}function pw(e){return e.length>0?e[e.length-1]:null}function an(e,n){for(const t in e)e.hasOwnProperty(t)&&n(e[t],t)}function vo(e){return xg(e)?e:Xl(e)?gt(Promise.resolve(e)):Z(e)} + */function cr(e,n){const t=e?Object.keys(e):void 0,i=n?Object.keys(n):void 0;if(!t||!i||t.length!=i.length)return!1;let r;for(let o=0;oi[o]===r)}return e===n}function hw(e){return Array.prototype.concat.apply([],e)}function pw(e){return e.length>0?e[e.length-1]:null}function an(e,n){for(const t in e)e.hasOwnProperty(t)&&n(e[t],t)}function vo(e){return Rg(e)?e:Xl(e)?gt(Promise.resolve(e)):J(e)} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */const rL={exact:function _w(e,n,t){if(!rs(e.segments,n.segments)||!ef(e.segments,n.segments,t)||e.numberOfChildren!==n.numberOfChildren)return!1;for(const i in n.children)if(!e.children[i]||!_w(e.children[i],n.children[i],t))return!1;return!0},subset:vw},gw={exact:function oL(e,n){return cr(e,n)},subset:function sL(e,n){return Object.keys(n).length<=Object.keys(e).length&&Object.keys(n).every(t=>fw(e[t],n[t]))},ignored:()=>!0};function mw(e,n,t){return rL[t.paths](e.root,n.root,t.matrixParams)&&gw[t.queryParams](e.queryParams,n.queryParams)&&!("exact"===t.fragment&&e.fragment!==n.fragment)}function vw(e,n,t){return yw(e,n,n.segments,t)}function yw(e,n,t,i){if(e.segments.length>t.length){const r=e.segments.slice(0,t.length);return!(!rs(r,t)||n.hasChildren()||!ef(r,t,i))}if(e.segments.length===t.length){if(!rs(e.segments,t)||!ef(e.segments,t,i))return!1;for(const r in n.children)if(!e.children[r]||!vw(e.children[r],n.children[r],i))return!1;return!0}{const r=t.slice(0,e.segments.length),o=t.slice(e.segments.length);return!!(rs(e.segments,r)&&ef(e.segments,r,i)&&e.children[pe])&&yw(e.children[pe],n,o,i)}}function ef(e,n,t){return n.every((i,r)=>gw[t](e[r].parameters,i.parameters))}class is{constructor(n,t,i){this.root=n,this.queryParams=t,this.fragment=i}get queryParamMap(){return this._queryParamMap||(this._queryParamMap=xa(this.queryParams)),this._queryParamMap}toString(){return cL.serialize(this)}}class me{constructor(n,t){this.segments=n,this.children=t,this.parent=null,an(t,(i,r)=>i.parent=this)}hasChildren(){return this.numberOfChildren>0}get numberOfChildren(){return Object.keys(this.children).length}toString(){return tf(this)}}class wc{constructor(n,t){this.path=n,this.parameters=t}get parameterMap(){return this._parameterMap||(this._parameterMap=xa(this.parameters)),this._parameterMap}toString(){return ww(this)}}function rs(e,n){return e.length===n.length&&e.every((t,i)=>t.path===n[i].path)}let bw=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:function(){return new Qm},providedIn:"root"}),e})();class Qm{parse(n){const t=new vL(n);return new is(t.parseRootSegment(),t.parseQueryParams(),t.parseFragment())}serialize(n){const t=`/${Sc(n.root,!0)}`,i=function fL(e){const n=Object.keys(e).map(t=>{const i=e[t];return Array.isArray(i)?i.map(r=>`${nf(t)}=${nf(r)}`).join("&"):`${nf(t)}=${nf(i)}`}).filter(t=>!!t);return n.length?`?${n.join("&")}`:""}(n.queryParams);return`${t}${i}${"string"==typeof n.fragment?`#${function uL(e){return encodeURI(e)}(n.fragment)}`:""}`}}const cL=new Qm;function tf(e){return e.segments.map(n=>ww(n)).join("/")}function Sc(e,n){if(!e.hasChildren())return tf(e);if(n){const t=e.children[pe]?Sc(e.children[pe],!1):"",i=[];return an(e.children,(r,o)=>{o!==pe&&i.push(`${o}:${Sc(r,!1)}`)}),i.length>0?`${t}(${i.join("//")})`:t}{const t=function lL(e,n){let t=[];return an(e.children,(i,r)=>{r===pe&&(t=t.concat(n(i,r)))}),an(e.children,(i,r)=>{r!==pe&&(t=t.concat(n(i,r)))}),t}(e,(i,r)=>r===pe?[Sc(e.children[pe],!1)]:[`${r}:${Sc(i,!1)}`]);return 1===Object.keys(e.children).length&&null!=e.children[pe]?`${tf(e)}/${t[0]}`:`${tf(e)}/(${t.join("//")})`}}function Dw(e){return encodeURIComponent(e).replace(/%40/g,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",")}function nf(e){return Dw(e).replace(/%3B/gi,";")}function Xm(e){return Dw(e).replace(/\(/g,"%28").replace(/\)/g,"%29").replace(/%26/gi,"&")}function rf(e){return decodeURIComponent(e)}function Cw(e){return rf(e.replace(/\+/g,"%20"))}function ww(e){return`${Xm(e.path)}${function dL(e){return Object.keys(e).map(n=>`;${Xm(n)}=${Xm(e[n])}`).join("")}(e.parameters)}`}const hL=/^[^\/()?;=#]+/;function sf(e){const n=e.match(hL);return n?n[0]:""}const pL=/^[^=?&#]+/,mL=/^[^&#]+/;class vL{constructor(n){this.url=n,this.remaining=n}parseRootSegment(){return this.consumeOptional("/"),""===this.remaining||this.peekStartsWith("?")||this.peekStartsWith("#")?new me([],{}):new me([],this.parseChildren())}parseQueryParams(){const n={};if(this.consumeOptional("?"))do{this.parseQueryParam(n)}while(this.consumeOptional("&"));return n}parseFragment(){return this.consumeOptional("#")?decodeURIComponent(this.remaining):null}parseChildren(){if(""===this.remaining)return{};this.consumeOptional("/");const n=[];for(this.peekStartsWith("(")||n.push(this.parseSegment());this.peekStartsWith("/")&&!this.peekStartsWith("//")&&!this.peekStartsWith("/(");)this.capture("/"),n.push(this.parseSegment());let t={};this.peekStartsWith("/(")&&(this.capture("/"),t=this.parseParens(!0));let i={};return this.peekStartsWith("(")&&(i=this.parseParens(!1)),(n.length>0||Object.keys(t).length>0)&&(i[pe]=new me(n,t)),i}parseSegment(){const n=sf(this.remaining);if(""===n&&this.peekStartsWith(";"))throw new P(4009,!1);return this.capture(n),new wc(rf(n),this.parseMatrixParams())}parseMatrixParams(){const n={};for(;this.consumeOptional(";");)this.parseParam(n);return n}parseParam(n){const t=sf(this.remaining);if(!t)return;this.capture(t);let i="";if(this.consumeOptional("=")){const r=sf(this.remaining);r&&(i=r,this.capture(i))}n[rf(t)]=rf(i)}parseQueryParam(n){const t=function gL(e){const n=e.match(pL);return n?n[0]:""}(this.remaining);if(!t)return;this.capture(t);let i="";if(this.consumeOptional("=")){const s=function _L(e){const n=e.match(mL);return n?n[0]:""}(this.remaining);s&&(i=s,this.capture(i))}const r=Cw(t),o=Cw(i);if(n.hasOwnProperty(r)){let s=n[r];Array.isArray(s)||(s=[s],n[r]=s),s.push(o)}else n[r]=o}parseParens(n){const t={};for(this.capture("(");!this.consumeOptional(")")&&this.remaining.length>0;){const i=sf(this.remaining),r=this.remaining[i.length];if("/"!==r&&")"!==r&&";"!==r)throw new P(4010,!1);let o;i.indexOf(":")>-1?(o=i.slice(0,i.indexOf(":")),this.capture(o),this.capture(":")):n&&(o=pe);const s=this.parseChildren();t[o]=1===Object.keys(s).length?s[pe]:new me([],s),this.consumeOptional("//")}return t}peekStartsWith(n){return this.remaining.startsWith(n)}consumeOptional(n){return!!this.peekStartsWith(n)&&(this.remaining=this.remaining.substring(n.length),!0)}capture(n){if(!this.consumeOptional(n))throw new P(4011,!1)}}function e_(e){return e.segments.length>0?new me([],{[pe]:e}):e}function af(e){const n={};for(const i of Object.keys(e.children)){const o=af(e.children[i]);(o.segments.length>0||o.hasChildren())&&(n[i]=o)}return function yL(e){if(1===e.numberOfChildren&&e.children[pe]){const n=e.children[pe];return new me(e.segments.concat(n.segments),n.children)}return e}(new me(e.segments,n))}function os(e){return e instanceof is} + */const rL={exact:function _w(e,n,t){if(!rs(e.segments,n.segments)||!ef(e.segments,n.segments,t)||e.numberOfChildren!==n.numberOfChildren)return!1;for(const i in n.children)if(!e.children[i]||!_w(e.children[i],n.children[i],t))return!1;return!0},subset:vw},gw={exact:function oL(e,n){return cr(e,n)},subset:function sL(e,n){return Object.keys(n).length<=Object.keys(e).length&&Object.keys(n).every(t=>fw(e[t],n[t]))},ignored:()=>!0};function mw(e,n,t){return rL[t.paths](e.root,n.root,t.matrixParams)&&gw[t.queryParams](e.queryParams,n.queryParams)&&!("exact"===t.fragment&&e.fragment!==n.fragment)}function vw(e,n,t){return yw(e,n,n.segments,t)}function yw(e,n,t,i){if(e.segments.length>t.length){const r=e.segments.slice(0,t.length);return!(!rs(r,t)||n.hasChildren()||!ef(r,t,i))}if(e.segments.length===t.length){if(!rs(e.segments,t)||!ef(e.segments,t,i))return!1;for(const r in n.children)if(!e.children[r]||!vw(e.children[r],n.children[r],i))return!1;return!0}{const r=t.slice(0,e.segments.length),o=t.slice(e.segments.length);return!!(rs(e.segments,r)&&ef(e.segments,r,i)&&e.children[pe])&&yw(e.children[pe],n,o,i)}}function ef(e,n,t){return n.every((i,r)=>gw[t](e[r].parameters,i.parameters))}class is{constructor(n,t,i){this.root=n,this.queryParams=t,this.fragment=i}get queryParamMap(){return this._queryParamMap||(this._queryParamMap=Ra(this.queryParams)),this._queryParamMap}toString(){return cL.serialize(this)}}class me{constructor(n,t){this.segments=n,this.children=t,this.parent=null,an(t,(i,r)=>i.parent=this)}hasChildren(){return this.numberOfChildren>0}get numberOfChildren(){return Object.keys(this.children).length}toString(){return tf(this)}}class wc{constructor(n,t){this.path=n,this.parameters=t}get parameterMap(){return this._parameterMap||(this._parameterMap=Ra(this.parameters)),this._parameterMap}toString(){return ww(this)}}function rs(e,n){return e.length===n.length&&e.every((t,i)=>t.path===n[i].path)}let bw=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:function(){return new Qm},providedIn:"root"}),e})();class Qm{parse(n){const t=new vL(n);return new is(t.parseRootSegment(),t.parseQueryParams(),t.parseFragment())}serialize(n){const t=`/${Sc(n.root,!0)}`,i=function fL(e){const n=Object.keys(e).map(t=>{const i=e[t];return Array.isArray(i)?i.map(r=>`${nf(t)}=${nf(r)}`).join("&"):`${nf(t)}=${nf(i)}`}).filter(t=>!!t);return n.length?`?${n.join("&")}`:""}(n.queryParams);return`${t}${i}${"string"==typeof n.fragment?`#${function uL(e){return encodeURI(e)}(n.fragment)}`:""}`}}const cL=new Qm;function tf(e){return e.segments.map(n=>ww(n)).join("/")}function Sc(e,n){if(!e.hasChildren())return tf(e);if(n){const t=e.children[pe]?Sc(e.children[pe],!1):"",i=[];return an(e.children,(r,o)=>{o!==pe&&i.push(`${o}:${Sc(r,!1)}`)}),i.length>0?`${t}(${i.join("//")})`:t}{const t=function lL(e,n){let t=[];return an(e.children,(i,r)=>{r===pe&&(t=t.concat(n(i,r)))}),an(e.children,(i,r)=>{r!==pe&&(t=t.concat(n(i,r)))}),t}(e,(i,r)=>r===pe?[Sc(e.children[pe],!1)]:[`${r}:${Sc(i,!1)}`]);return 1===Object.keys(e.children).length&&null!=e.children[pe]?`${tf(e)}/${t[0]}`:`${tf(e)}/(${t.join("//")})`}}function Dw(e){return encodeURIComponent(e).replace(/%40/g,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",")}function nf(e){return Dw(e).replace(/%3B/gi,";")}function Xm(e){return Dw(e).replace(/\(/g,"%28").replace(/\)/g,"%29").replace(/%26/gi,"&")}function rf(e){return decodeURIComponent(e)}function Cw(e){return rf(e.replace(/\+/g,"%20"))}function ww(e){return`${Xm(e.path)}${function dL(e){return Object.keys(e).map(n=>`;${Xm(n)}=${Xm(e[n])}`).join("")}(e.parameters)}`}const hL=/^[^\/()?;=#]+/;function sf(e){const n=e.match(hL);return n?n[0]:""}const pL=/^[^=?&#]+/,mL=/^[^&#]+/;class vL{constructor(n){this.url=n,this.remaining=n}parseRootSegment(){return this.consumeOptional("/"),""===this.remaining||this.peekStartsWith("?")||this.peekStartsWith("#")?new me([],{}):new me([],this.parseChildren())}parseQueryParams(){const n={};if(this.consumeOptional("?"))do{this.parseQueryParam(n)}while(this.consumeOptional("&"));return n}parseFragment(){return this.consumeOptional("#")?decodeURIComponent(this.remaining):null}parseChildren(){if(""===this.remaining)return{};this.consumeOptional("/");const n=[];for(this.peekStartsWith("(")||n.push(this.parseSegment());this.peekStartsWith("/")&&!this.peekStartsWith("//")&&!this.peekStartsWith("/(");)this.capture("/"),n.push(this.parseSegment());let t={};this.peekStartsWith("/(")&&(this.capture("/"),t=this.parseParens(!0));let i={};return this.peekStartsWith("(")&&(i=this.parseParens(!1)),(n.length>0||Object.keys(t).length>0)&&(i[pe]=new me(n,t)),i}parseSegment(){const n=sf(this.remaining);if(""===n&&this.peekStartsWith(";"))throw new F(4009,!1);return this.capture(n),new wc(rf(n),this.parseMatrixParams())}parseMatrixParams(){const n={};for(;this.consumeOptional(";");)this.parseParam(n);return n}parseParam(n){const t=sf(this.remaining);if(!t)return;this.capture(t);let i="";if(this.consumeOptional("=")){const r=sf(this.remaining);r&&(i=r,this.capture(i))}n[rf(t)]=rf(i)}parseQueryParam(n){const t=function gL(e){const n=e.match(pL);return n?n[0]:""}(this.remaining);if(!t)return;this.capture(t);let i="";if(this.consumeOptional("=")){const s=function _L(e){const n=e.match(mL);return n?n[0]:""}(this.remaining);s&&(i=s,this.capture(i))}const r=Cw(t),o=Cw(i);if(n.hasOwnProperty(r)){let s=n[r];Array.isArray(s)||(s=[s],n[r]=s),s.push(o)}else n[r]=o}parseParens(n){const t={};for(this.capture("(");!this.consumeOptional(")")&&this.remaining.length>0;){const i=sf(this.remaining),r=this.remaining[i.length];if("/"!==r&&")"!==r&&";"!==r)throw new F(4010,!1);let o;i.indexOf(":")>-1?(o=i.slice(0,i.indexOf(":")),this.capture(o),this.capture(":")):n&&(o=pe);const s=this.parseChildren();t[o]=1===Object.keys(s).length?s[pe]:new me([],s),this.consumeOptional("//")}return t}peekStartsWith(n){return this.remaining.startsWith(n)}consumeOptional(n){return!!this.peekStartsWith(n)&&(this.remaining=this.remaining.substring(n.length),!0)}capture(n){if(!this.consumeOptional(n))throw new F(4011,!1)}}function e_(e){return e.segments.length>0?new me([],{[pe]:e}):e}function af(e){const n={};for(const i of Object.keys(e.children)){const o=af(e.children[i]);(o.segments.length>0||o.hasChildren())&&(n[i]=o)}return function yL(e){if(1===e.numberOfChildren&&e.children[pe]){const n=e.children[pe];return new me(e.segments.concat(n.segments),n.children)}return e}(new me(e.segments,n))}function os(e){return e instanceof is} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */function CL(e,n,t,i,r){if(0===t.length)return Fa(n.root,n.root,n.root,i,r);const o=function Mw(e){if("string"==typeof e[0]&&1===e.length&&"/"===e[0])return new Ew(!0,0,e);let n=0,t=!1;const i=e.reduce((r,o,s)=>{if("object"==typeof o&&null!=o){if(o.outlets){const a={};return an(o.outlets,(l,u)=>{a[u]="string"==typeof l?l.split("/"):l}),[...r,{outlets:a}]}if(o.segmentPath)return[...r,o.segmentPath]}return"string"!=typeof o?[...r,o]:0===s?(o.split("/").forEach((a,l)=>{0==l&&"."===a||(0==l&&""===a?t=!0:".."===a?n++:""!=a&&r.push(a))}),r):[...r,o]},[]);return new Ew(t,n,i)}(t);return o.toRoot()?Fa(n.root,n.root,new me([],{}),i,r):function s(l){const u=function SL(e,n,t,i){if(e.isAbsolute)return new Pa(n.root,!0,0);if(-1===i)return new Pa(t,t===n.root,0);return function Nw(e,n,t){let i=e,r=n,o=t;for(;o>r;){if(o-=r,i=i.parent,!i)throw new P(4005,!1);r=i.segments.length}return new Pa(i,!1,r-o)}(t,i+(Ec(e.commands[0])?0:1),e.numberOfDoubleDots)}(o,n,e.snapshot?._urlSegment,l),f=u.processChildren?Nc(u.segmentGroup,u.index,o.commands):n_(u.segmentGroup,u.index,o.commands);return Fa(n.root,u.segmentGroup,f,i,r)}(e.snapshot?._lastPathIndex)}function Ec(e){return"object"==typeof e&&null!=e&&!e.outlets&&!e.segmentPath}function Mc(e){return"object"==typeof e&&null!=e&&e.outlets}function Fa(e,n,t,i,r){let s,o={};i&&an(i,(l,u)=>{o[u]=Array.isArray(l)?l.map(f=>`${f}`):`${l}`}),s=e===n?t:Sw(e,n,t);const a=e_(af(s));return new is(a,o,r)}function Sw(e,n,t){const i={};return an(e.children,(r,o)=>{i[o]=r===n?t:Sw(r,n,t)}),new me(e.segments,i)}class Ew{constructor(n,t,i){if(this.isAbsolute=n,this.numberOfDoubleDots=t,this.commands=i,n&&i.length>0&&Ec(i[0]))throw new P(4003,!1);const r=i.find(Mc);if(r&&r!==pw(i))throw new P(4004,!1)}toRoot(){return this.isAbsolute&&1===this.commands.length&&"/"==this.commands[0]}}class Pa{constructor(n,t,i){this.segmentGroup=n,this.processChildren=t,this.index=i}}function n_(e,n,t){if(e||(e=new me([],{})),0===e.segments.length&&e.hasChildren())return Nc(e,n,t);const i=function ML(e,n,t){let i=0,r=n;const o={match:!1,pathIndex:0,commandIndex:0};for(;r=t.length)return o;const s=e.segments[r],a=t[i];if(Mc(a))break;const l=`${a}`,u=i0&&void 0===l)break;if(l&&u&&"object"==typeof u&&void 0===u.outlets){if(!Aw(l,u,s))return o;i+=2}else{if(!Aw(l,{},s))return o;i++}r++}return{match:!0,pathIndex:r,commandIndex:i}}(e,n,t),r=t.slice(i.commandIndex);if(i.match&&i.pathIndex{"string"==typeof o&&(o=[o]),null!==o&&(r[s]=n_(e.children[s],n,o))}),an(e.children,(o,s)=>{void 0===i[s]&&(r[s]=o)}),new me(e.segments,r)}}function i_(e,n,t){const i=e.segments.slice(0,n);let r=0;for(;r{"string"==typeof t&&(t=[t]),null!==t&&(n[i]=i_(new me([],{}),0,t))}),n}function Tw(e){const n={};return an(e,(t,i)=>n[i]=`${t}`),n}function Aw(e,n,t){return e==t.path&&cr(n,t.parameters)} + */function CL(e,n,t,i,r){if(0===t.length)return Pa(n.root,n.root,n.root,i,r);const o=function Nw(e){if("string"==typeof e[0]&&1===e.length&&"/"===e[0])return new Mw(!0,0,e);let n=0,t=!1;const i=e.reduce((r,o,s)=>{if("object"==typeof o&&null!=o){if(o.outlets){const a={};return an(o.outlets,(l,u)=>{a[u]="string"==typeof l?l.split("/"):l}),[...r,{outlets:a}]}if(o.segmentPath)return[...r,o.segmentPath]}return"string"!=typeof o?[...r,o]:0===s?(o.split("/").forEach((a,l)=>{0==l&&"."===a||(0==l&&""===a?t=!0:".."===a?n++:""!=a&&r.push(a))}),r):[...r,o]},[]);return new Mw(t,n,i)}(t);return o.toRoot()?Pa(n.root,n.root,new me([],{}),i,r):function s(l){const u=function SL(e,n,t,i){if(e.isAbsolute)return new Fa(n.root,!0,0);if(-1===i)return new Fa(t,t===n.root,0);return function Ew(e,n,t){let i=e,r=n,o=t;for(;o>r;){if(o-=r,i=i.parent,!i)throw new F(4005,!1);r=i.segments.length}return new Fa(i,!1,r-o)}(t,i+(Mc(e.commands[0])?0:1),e.numberOfDoubleDots)}(o,n,e.snapshot?._urlSegment,l),f=u.processChildren?Ec(u.segmentGroup,u.index,o.commands):n_(u.segmentGroup,u.index,o.commands);return Pa(n.root,u.segmentGroup,f,i,r)}(e.snapshot?._lastPathIndex)}function Mc(e){return"object"==typeof e&&null!=e&&!e.outlets&&!e.segmentPath}function Nc(e){return"object"==typeof e&&null!=e&&e.outlets}function Pa(e,n,t,i,r){let s,o={};i&&an(i,(l,u)=>{o[u]=Array.isArray(l)?l.map(f=>`${f}`):`${l}`}),s=e===n?t:Sw(e,n,t);const a=e_(af(s));return new is(a,o,r)}function Sw(e,n,t){const i={};return an(e.children,(r,o)=>{i[o]=r===n?t:Sw(r,n,t)}),new me(e.segments,i)}class Mw{constructor(n,t,i){if(this.isAbsolute=n,this.numberOfDoubleDots=t,this.commands=i,n&&i.length>0&&Mc(i[0]))throw new F(4003,!1);const r=i.find(Nc);if(r&&r!==pw(i))throw new F(4004,!1)}toRoot(){return this.isAbsolute&&1===this.commands.length&&"/"==this.commands[0]}}class Fa{constructor(n,t,i){this.segmentGroup=n,this.processChildren=t,this.index=i}}function n_(e,n,t){if(e||(e=new me([],{})),0===e.segments.length&&e.hasChildren())return Ec(e,n,t);const i=function NL(e,n,t){let i=0,r=n;const o={match:!1,pathIndex:0,commandIndex:0};for(;r=t.length)return o;const s=e.segments[r],a=t[i];if(Nc(a))break;const l=`${a}`,u=i0&&void 0===l)break;if(l&&u&&"object"==typeof u&&void 0===u.outlets){if(!Iw(l,u,s))return o;i+=2}else{if(!Iw(l,{},s))return o;i++}r++}return{match:!0,pathIndex:r,commandIndex:i}}(e,n,t),r=t.slice(i.commandIndex);if(i.match&&i.pathIndex{"string"==typeof o&&(o=[o]),null!==o&&(r[s]=n_(e.children[s],n,o))}),an(e.children,(o,s)=>{void 0===i[s]&&(r[s]=o)}),new me(e.segments,r)}}function i_(e,n,t){const i=e.segments.slice(0,n);let r=0;for(;r{"string"==typeof t&&(t=[t]),null!==t&&(n[i]=i_(new me([],{}),0,t))}),n}function Tw(e){const n={};return an(e,(t,i)=>n[i]=`${t}`),n}function Iw(e,n,t){return e==t.path&&cr(n,t.parameters)} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */class Ur{constructor(n,t){this.id=n,this.url=t}}class r_ extends Ur{constructor(n,t,i="imperative",r=null){super(n,t),this.type=0,this.navigationTrigger=i,this.restoredState=r}toString(){return`NavigationStart(id: ${this.id}, url: '${this.url}')`}}class ss extends Ur{constructor(n,t,i){super(n,t),this.urlAfterRedirects=i,this.type=1}toString(){return`NavigationEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}')`}}class lf extends Ur{constructor(n,t,i,r){super(n,t),this.reason=i,this.code=r,this.type=2}toString(){return`NavigationCancel(id: ${this.id}, url: '${this.url}')`}}class Iw extends Ur{constructor(n,t,i,r){super(n,t),this.error=i,this.target=r,this.type=3}toString(){return`NavigationError(id: ${this.id}, url: '${this.url}', error: ${this.error})`}}class TL extends Ur{constructor(n,t,i,r){super(n,t),this.urlAfterRedirects=i,this.state=r,this.type=4}toString(){return`RoutesRecognized(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`}}class AL extends Ur{constructor(n,t,i,r){super(n,t),this.urlAfterRedirects=i,this.state=r,this.type=7}toString(){return`GuardsCheckStart(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`}}class IL extends Ur{constructor(n,t,i,r,o){super(n,t),this.urlAfterRedirects=i,this.state=r,this.shouldActivate=o,this.type=8}toString(){return`GuardsCheckEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state}, shouldActivate: ${this.shouldActivate})`}}class OL extends Ur{constructor(n,t,i,r){super(n,t),this.urlAfterRedirects=i,this.state=r,this.type=5}toString(){return`ResolveStart(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`}}class kL extends Ur{constructor(n,t,i,r){super(n,t),this.urlAfterRedirects=i,this.state=r,this.type=6}toString(){return`ResolveEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`}}class RL{constructor(n){this.route=n,this.type=9}toString(){return`RouteConfigLoadStart(path: ${this.route.path})`}}class xL{constructor(n){this.route=n,this.type=10}toString(){return`RouteConfigLoadEnd(path: ${this.route.path})`}}class FL{constructor(n){this.snapshot=n,this.type=11}toString(){return`ChildActivationStart(path: '${this.snapshot.routeConfig&&this.snapshot.routeConfig.path||""}')`}}class PL{constructor(n){this.snapshot=n,this.type=12}toString(){return`ChildActivationEnd(path: '${this.snapshot.routeConfig&&this.snapshot.routeConfig.path||""}')`}}class LL{constructor(n){this.snapshot=n,this.type=13}toString(){return`ActivationStart(path: '${this.snapshot.routeConfig&&this.snapshot.routeConfig.path||""}')`}}class VL{constructor(n){this.snapshot=n,this.type=14}toString(){return`ActivationEnd(path: '${this.snapshot.routeConfig&&this.snapshot.routeConfig.path||""}')`}}class Ow{constructor(n,t,i){this.routerEvent=n,this.position=t,this.anchor=i,this.type=15}toString(){return`Scroll(anchor: '${this.anchor}', position: '${this.position?`${this.position[0]}, ${this.position[1]}`:null}')`}} + */class Ur{constructor(n,t){this.id=n,this.url=t}}class r_ extends Ur{constructor(n,t,i="imperative",r=null){super(n,t),this.type=0,this.navigationTrigger=i,this.restoredState=r}toString(){return`NavigationStart(id: ${this.id}, url: '${this.url}')`}}class ss extends Ur{constructor(n,t,i){super(n,t),this.urlAfterRedirects=i,this.type=1}toString(){return`NavigationEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}')`}}class lf extends Ur{constructor(n,t,i,r){super(n,t),this.reason=i,this.code=r,this.type=2}toString(){return`NavigationCancel(id: ${this.id}, url: '${this.url}')`}}class Aw extends Ur{constructor(n,t,i,r){super(n,t),this.error=i,this.target=r,this.type=3}toString(){return`NavigationError(id: ${this.id}, url: '${this.url}', error: ${this.error})`}}class TL extends Ur{constructor(n,t,i,r){super(n,t),this.urlAfterRedirects=i,this.state=r,this.type=4}toString(){return`RoutesRecognized(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`}}class IL extends Ur{constructor(n,t,i,r){super(n,t),this.urlAfterRedirects=i,this.state=r,this.type=7}toString(){return`GuardsCheckStart(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`}}class AL extends Ur{constructor(n,t,i,r,o){super(n,t),this.urlAfterRedirects=i,this.state=r,this.shouldActivate=o,this.type=8}toString(){return`GuardsCheckEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state}, shouldActivate: ${this.shouldActivate})`}}class kL extends Ur{constructor(n,t,i,r){super(n,t),this.urlAfterRedirects=i,this.state=r,this.type=5}toString(){return`ResolveStart(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`}}class OL extends Ur{constructor(n,t,i,r){super(n,t),this.urlAfterRedirects=i,this.state=r,this.type=6}toString(){return`ResolveEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`}}class xL{constructor(n){this.route=n,this.type=9}toString(){return`RouteConfigLoadStart(path: ${this.route.path})`}}class RL{constructor(n){this.route=n,this.type=10}toString(){return`RouteConfigLoadEnd(path: ${this.route.path})`}}class PL{constructor(n){this.snapshot=n,this.type=11}toString(){return`ChildActivationStart(path: '${this.snapshot.routeConfig&&this.snapshot.routeConfig.path||""}')`}}class FL{constructor(n){this.snapshot=n,this.type=12}toString(){return`ChildActivationEnd(path: '${this.snapshot.routeConfig&&this.snapshot.routeConfig.path||""}')`}}class LL{constructor(n){this.snapshot=n,this.type=13}toString(){return`ActivationStart(path: '${this.snapshot.routeConfig&&this.snapshot.routeConfig.path||""}')`}}class VL{constructor(n){this.snapshot=n,this.type=14}toString(){return`ActivationEnd(path: '${this.snapshot.routeConfig&&this.snapshot.routeConfig.path||""}')`}}class kw{constructor(n,t,i){this.routerEvent=n,this.position=t,this.anchor=i,this.type=15}toString(){return`Scroll(anchor: '${this.anchor}', position: '${this.position?`${this.position[0]}, ${this.position[1]}`:null}')`}} /** * @license * Copyright Google LLC All Rights Reserved. @@ -1490,91 +1490,91 @@ function Z(...e){return gt(e,en(e))}typeof window<"u"&&window;class zt extends U * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -class kw{constructor(n){this._root=n}get root(){return this._root.value}parent(n){const t=this.pathFromRoot(n);return t.length>1?t[t.length-2]:null}children(n){const t=o_(n,this._root);return t?t.children.map(i=>i.value):[]}firstChild(n){const t=o_(n,this._root);return t&&t.children.length>0?t.children[0].value:null}siblings(n){const t=s_(n,this._root);return t.length<2?[]:t[t.length-2].children.map(r=>r.value).filter(r=>r!==n)}pathFromRoot(n){return s_(n,this._root).map(t=>t.value)}}function o_(e,n){if(e===n.value)return n;for(const t of n.children){const i=o_(e,t);if(i)return i}return null}function s_(e,n){if(e===n.value)return[n];for(const t of n.children){const i=s_(e,t);if(i.length)return i.unshift(n),i}return[]}class Gr{constructor(n,t){this.value=n,this.children=t}toString(){return`TreeNode(${this.value})`}}function La(e){const n={};return e&&e.children.forEach(t=>n[t.value.outlet]=t),n +class Ow{constructor(n){this._root=n}get root(){return this._root.value}parent(n){const t=this.pathFromRoot(n);return t.length>1?t[t.length-2]:null}children(n){const t=o_(n,this._root);return t?t.children.map(i=>i.value):[]}firstChild(n){const t=o_(n,this._root);return t&&t.children.length>0?t.children[0].value:null}siblings(n){const t=s_(n,this._root);return t.length<2?[]:t[t.length-2].children.map(r=>r.value).filter(r=>r!==n)}pathFromRoot(n){return s_(n,this._root).map(t=>t.value)}}function o_(e,n){if(e===n.value)return n;for(const t of n.children){const i=o_(e,t);if(i)return i}return null}function s_(e,n){if(e===n.value)return[n];for(const t of n.children){const i=s_(e,t);if(i.length)return i.unshift(n),i}return[]}class Gr{constructor(n,t){this.value=n,this.children=t}toString(){return`TreeNode(${this.value})`}}function La(e){const n={};return e&&e.children.forEach(t=>n[t.value.outlet]=t),n /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */}class Rw extends kw{constructor(n,t){super(n),this.snapshot=t,a_(this,n)}toString(){return this.snapshot.toString()}}function xw(e,n){const t=function BL(e,n){const s=new cf([],{},{},"",{},pe,n,null,e.root,-1,{});return new Pw("",new Gr(s,[]))}(e,n),i=new zt([new wc("",{})]),r=new zt({}),o=new zt({}),s=new zt({}),a=new zt(""),l=new as(i,r,s,a,o,pe,n,t.root);return l.snapshot=t.root,new Rw(new Gr(l,[]),t)}class as{constructor(n,t,i,r,o,s,a,l){this.url=n,this.params=t,this.queryParams=i,this.fragment=r,this.data=o,this.outlet=s,this.component=a,this.title=this.data?.pipe(ne(u=>u[Cc]))??Z(void 0),this._futureSnapshot=l}get routeConfig(){return this._futureSnapshot.routeConfig}get root(){return this._routerState.root}get parent(){return this._routerState.parent(this)}get firstChild(){return this._routerState.firstChild(this)}get children(){return this._routerState.children(this)}get pathFromRoot(){return this._routerState.pathFromRoot(this)}get paramMap(){return this._paramMap||(this._paramMap=this.params.pipe(ne(n=>xa(n)))),this._paramMap}get queryParamMap(){return this._queryParamMap||(this._queryParamMap=this.queryParams.pipe(ne(n=>xa(n)))),this._queryParamMap}toString(){return this.snapshot?this.snapshot.toString():`Future(${this._futureSnapshot})`}}function Fw(e,n="emptyOnly"){const t=e.pathFromRoot;let i=0;if("always"!==n)for(i=t.length-1;i>=1;){const r=t[i],o=t[i-1];if(r.routeConfig&&""===r.routeConfig.path)i--;else{if(o.component)break;i--}}return function jL(e){return e.reduce((n,t)=>({params:{...n.params,...t.params},data:{...n.data,...t.data},resolve:{...t.data,...n.resolve,...t.routeConfig?.data,...t._resolvedData}}),{params:{},data:{},resolve:{}})}(t.slice(i))}class cf{constructor(n,t,i,r,o,s,a,l,u,f,p,m){this.url=n,this.params=t,this.queryParams=i,this.fragment=r,this.data=o,this.outlet=s,this.component=a,this.title=this.data?.[Cc],this.routeConfig=l,this._urlSegment=u,this._lastPathIndex=f,this._correctedLastPathIndex=m??f,this._resolve=p}get root(){return this._routerState.root}get parent(){return this._routerState.parent(this)}get firstChild(){return this._routerState.firstChild(this)}get children(){return this._routerState.children(this)}get pathFromRoot(){return this._routerState.pathFromRoot(this)}get paramMap(){return this._paramMap||(this._paramMap=xa(this.params)),this._paramMap}get queryParamMap(){return this._queryParamMap||(this._queryParamMap=xa(this.queryParams)),this._queryParamMap}toString(){return`Route(url:'${this.url.map(i=>i.toString()).join("/")}', path:'${this.routeConfig?this.routeConfig.path:""}')`}}class Pw extends kw{constructor(n,t){super(t),this.url=n,a_(this,t)}toString(){return Lw(this._root)}}function a_(e,n){n.value._routerState=e,n.children.forEach(t=>a_(e,t))}function Lw(e){const n=e.children.length>0?` { ${e.children.map(Lw).join(", ")} } `:"";return`${e.value}${n}`}function l_(e){if(e.snapshot){const n=e.snapshot,t=e._futureSnapshot;e.snapshot=t,cr(n.queryParams,t.queryParams)||e.queryParams.next(t.queryParams),n.fragment!==t.fragment&&e.fragment.next(t.fragment),cr(n.params,t.params)||e.params.next(t.params),function nL(e,n){if(e.length!==n.length)return!1;for(let t=0;tcr(t.parameters,n[i].parameters))}(e.url,n.url);return t&&!(!e.parent!=!n.parent)&&(!e.parent||c_(e.parent,n.parent))} + */}class xw extends Ow{constructor(n,t){super(n),this.snapshot=t,a_(this,n)}toString(){return this.snapshot.toString()}}function Rw(e,n){const t=function HL(e,n){const s=new cf([],{},{},"",{},pe,n,null,e.root,-1,{});return new Fw("",new Gr(s,[]))}(e,n),i=new Yt([new wc("",{})]),r=new Yt({}),o=new Yt({}),s=new Yt({}),a=new Yt(""),l=new as(i,r,s,a,o,pe,n,t.root);return l.snapshot=t.root,new xw(new Gr(l,[]),t)}class as{constructor(n,t,i,r,o,s,a,l){this.url=n,this.params=t,this.queryParams=i,this.fragment=r,this.data=o,this.outlet=s,this.component=a,this.title=this.data?.pipe(ne(u=>u[Cc]))??J(void 0),this._futureSnapshot=l}get routeConfig(){return this._futureSnapshot.routeConfig}get root(){return this._routerState.root}get parent(){return this._routerState.parent(this)}get firstChild(){return this._routerState.firstChild(this)}get children(){return this._routerState.children(this)}get pathFromRoot(){return this._routerState.pathFromRoot(this)}get paramMap(){return this._paramMap||(this._paramMap=this.params.pipe(ne(n=>Ra(n)))),this._paramMap}get queryParamMap(){return this._queryParamMap||(this._queryParamMap=this.queryParams.pipe(ne(n=>Ra(n)))),this._queryParamMap}toString(){return this.snapshot?this.snapshot.toString():`Future(${this._futureSnapshot})`}}function Pw(e,n="emptyOnly"){const t=e.pathFromRoot;let i=0;if("always"!==n)for(i=t.length-1;i>=1;){const r=t[i],o=t[i-1];if(r.routeConfig&&""===r.routeConfig.path)i--;else{if(o.component)break;i--}}return function jL(e){return e.reduce((n,t)=>({params:{...n.params,...t.params},data:{...n.data,...t.data},resolve:{...t.data,...n.resolve,...t.routeConfig?.data,...t._resolvedData}}),{params:{},data:{},resolve:{}})}(t.slice(i))}class cf{constructor(n,t,i,r,o,s,a,l,u,f,p,m){this.url=n,this.params=t,this.queryParams=i,this.fragment=r,this.data=o,this.outlet=s,this.component=a,this.title=this.data?.[Cc],this.routeConfig=l,this._urlSegment=u,this._lastPathIndex=f,this._correctedLastPathIndex=m??f,this._resolve=p}get root(){return this._routerState.root}get parent(){return this._routerState.parent(this)}get firstChild(){return this._routerState.firstChild(this)}get children(){return this._routerState.children(this)}get pathFromRoot(){return this._routerState.pathFromRoot(this)}get paramMap(){return this._paramMap||(this._paramMap=Ra(this.params)),this._paramMap}get queryParamMap(){return this._queryParamMap||(this._queryParamMap=Ra(this.queryParams)),this._queryParamMap}toString(){return`Route(url:'${this.url.map(i=>i.toString()).join("/")}', path:'${this.routeConfig?this.routeConfig.path:""}')`}}class Fw extends Ow{constructor(n,t){super(t),this.url=n,a_(this,t)}toString(){return Lw(this._root)}}function a_(e,n){n.value._routerState=e,n.children.forEach(t=>a_(e,t))}function Lw(e){const n=e.children.length>0?` { ${e.children.map(Lw).join(", ")} } `:"";return`${e.value}${n}`}function l_(e){if(e.snapshot){const n=e.snapshot,t=e._futureSnapshot;e.snapshot=t,cr(n.queryParams,t.queryParams)||e.queryParams.next(t.queryParams),n.fragment!==t.fragment&&e.fragment.next(t.fragment),cr(n.params,t.params)||e.params.next(t.params),function nL(e,n){if(e.length!==n.length)return!1;for(let t=0;tcr(t.parameters,n[i].parameters))}(e.url,n.url);return t&&!(!e.parent!=!n.parent)&&(!e.parent||c_(e.parent,n.parent))} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */function Tc(e,n,t){if(t&&e.shouldReuseRoute(n.value,t.value.snapshot)){const i=t.value;i._futureSnapshot=n.value;const r=function UL(e,n,t){return n.children.map(i=>{for(const r of t.children)if(e.shouldReuseRoute(i.value,r.value.snapshot))return Tc(e,i,r);return Tc(e,i)})}(e,n,t);return new Gr(i,r)}{if(e.shouldAttach(n.value)){const o=e.retrieve(n.value);if(null!==o){const s=o.route;return s.value._futureSnapshot=n.value,s.children=n.children.map(a=>Tc(e,a)),s}}const i=function GL(e){return new as(new zt(e.url),new zt(e.params),new zt(e.queryParams),new zt(e.fragment),new zt(e.data),e.outlet,e.component,e)} + */function Tc(e,n,t){if(t&&e.shouldReuseRoute(n.value,t.value.snapshot)){const i=t.value;i._futureSnapshot=n.value;const r=function UL(e,n,t){return n.children.map(i=>{for(const r of t.children)if(e.shouldReuseRoute(i.value,r.value.snapshot))return Tc(e,i,r);return Tc(e,i)})}(e,n,t);return new Gr(i,r)}{if(e.shouldAttach(n.value)){const o=e.retrieve(n.value);if(null!==o){const s=o.route;return s.value._futureSnapshot=n.value,s.children=n.children.map(a=>Tc(e,a)),s}}const i=function GL(e){return new as(new Yt(e.url),new Yt(e.params),new Yt(e.queryParams),new Yt(e.fragment),new Yt(e.data),e.outlet,e.component,e)} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */(n.value),r=n.children.map(o=>Tc(e,o));return new Gr(i,r)}}const u_="ngNavigationCancelingError";function Vw(e,n){const{redirectTo:t,navigationBehaviorOptions:i}=os(n)?{redirectTo:n,navigationBehaviorOptions:void 0}:n,r=Hw(!1,0,n);return r.url=t,r.navigationBehaviorOptions=i,r}function Hw(e,n,t){const i=new Error("NavigationCancelingError: "+(e||""));return i[u_]=!0,i.cancellationCode=n,t&&(i.url=t),i}function Bw(e){return jw(e)&&os(e.url)}function jw(e){return e&&e[u_]} + */(n.value),r=n.children.map(o=>Tc(e,o));return new Gr(i,r)}}const u_="ngNavigationCancelingError";function Vw(e,n){const{redirectTo:t,navigationBehaviorOptions:i}=os(n)?{redirectTo:n,navigationBehaviorOptions:void 0}:n,r=Bw(!1,0,n);return r.url=t,r.navigationBehaviorOptions=i,r}function Bw(e,n,t){const i=new Error("NavigationCancelingError: "+(e||""));return i[u_]=!0,i.cancellationCode=n,t&&(i.url=t),i}function Hw(e){return jw(e)&&os(e.url)}function jw(e){return e&&e[u_]} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */class WL{constructor(){this.outlet=null,this.route=null,this.resolver=null,this.injector=null,this.children=new Ac,this.attachRef=null}}let Ac=(()=>{class e{constructor(){this.contexts=new Map}onChildOutletCreated(t,i){const r=this.getOrCreateContext(t);r.outlet=i,this.contexts.set(t,r)}onChildOutletDestroyed(t){const i=this.getContext(t);i&&(i.outlet=null,i.attachRef=null)}onOutletDeactivated(){const t=this.contexts;return this.contexts=new Map,t}onOutletReAttached(t){this.contexts=t}getOrCreateContext(t){let i=this.getContext(t);return i||(i=new WL,this.contexts.set(t,i)),i}getContext(t){return this.contexts.get(t)||null}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(); + */class WL{constructor(){this.outlet=null,this.route=null,this.resolver=null,this.injector=null,this.children=new Ic,this.attachRef=null}}let Ic=(()=>{class e{constructor(){this.contexts=new Map}onChildOutletCreated(t,i){const r=this.getOrCreateContext(t);r.outlet=i,this.contexts.set(t,r)}onChildOutletDestroyed(t){const i=this.getContext(t);i&&(i.outlet=null,i.attachRef=null)}onOutletDeactivated(){const t=this.contexts;return this.contexts=new Map,t}onOutletReAttached(t){this.contexts=t}getOrCreateContext(t){let i=this.getContext(t);return i||(i=new WL,this.contexts.set(t,i)),i}getContext(t){return this.contexts.get(t)||null}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(); /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */const uf=!1;let d_=(()=>{class e{constructor(t,i,r,o,s){this.parentContexts=t,this.location=i,this.changeDetector=o,this.environmentInjector=s,this.activated=null,this._activatedRoute=null,this.activateEvents=new ue,this.deactivateEvents=new ue,this.attachEvents=new ue,this.detachEvents=new ue,this.name=r||pe,t.onChildOutletCreated(this.name,this)}ngOnDestroy(){this.parentContexts.getContext(this.name)?.outlet===this&&this.parentContexts.onChildOutletDestroyed(this.name)}ngOnInit(){if(!this.activated){const t=this.parentContexts.getContext(this.name);t&&t.route&&(t.attachRef?this.attach(t.attachRef,t.route):this.activateWith(t.route,t.injector))}}get isActivated(){return!!this.activated}get component(){if(!this.activated)throw new P(4012,uf);return this.activated.instance}get activatedRoute(){if(!this.activated)throw new P(4012,uf);return this._activatedRoute}get activatedRouteData(){return this._activatedRoute?this._activatedRoute.snapshot.data:{}}detach(){if(!this.activated)throw new P(4012,uf);this.location.detach();const t=this.activated;return this.activated=null,this._activatedRoute=null,this.detachEvents.emit(t.instance),t}attach(t,i){this.activated=t,this._activatedRoute=i,this.location.insert(t.hostView),this.attachEvents.emit(t.instance)}deactivate(){if(this.activated){const t=this.component;this.activated.destroy(),this.activated=null,this._activatedRoute=null,this.deactivateEvents.emit(t)}}activateWith(t,i){if(this.isActivated)throw new P(4013,uf);this._activatedRoute=t;const r=this.location,s=t._futureSnapshot.component,a=this.parentContexts.getOrCreateContext(this.name).children,l=new KL(t,a,r.injector);if(i&&function zL(e){return!!e.resolveComponentFactory} + */const uf=!1;let d_=(()=>{class e{constructor(t,i,r,o,s){this.parentContexts=t,this.location=i,this.changeDetector=o,this.environmentInjector=s,this.activated=null,this._activatedRoute=null,this.activateEvents=new ue,this.deactivateEvents=new ue,this.attachEvents=new ue,this.detachEvents=new ue,this.name=r||pe,t.onChildOutletCreated(this.name,this)}ngOnDestroy(){this.parentContexts.getContext(this.name)?.outlet===this&&this.parentContexts.onChildOutletDestroyed(this.name)}ngOnInit(){if(!this.activated){const t=this.parentContexts.getContext(this.name);t&&t.route&&(t.attachRef?this.attach(t.attachRef,t.route):this.activateWith(t.route,t.injector))}}get isActivated(){return!!this.activated}get component(){if(!this.activated)throw new F(4012,uf);return this.activated.instance}get activatedRoute(){if(!this.activated)throw new F(4012,uf);return this._activatedRoute}get activatedRouteData(){return this._activatedRoute?this._activatedRoute.snapshot.data:{}}detach(){if(!this.activated)throw new F(4012,uf);this.location.detach();const t=this.activated;return this.activated=null,this._activatedRoute=null,this.detachEvents.emit(t.instance),t}attach(t,i){this.activated=t,this._activatedRoute=i,this.location.insert(t.hostView),this.attachEvents.emit(t.instance)}deactivate(){if(this.activated){const t=this.component;this.activated.destroy(),this.activated=null,this._activatedRoute=null,this.deactivateEvents.emit(t)}}activateWith(t,i){if(this.isActivated)throw new F(4013,uf);this._activatedRoute=t;const r=this.location,s=t._futureSnapshot.component,a=this.parentContexts.getOrCreateContext(this.name).children,l=new zL(t,a,r.injector);if(i&&function YL(e){return!!e.resolveComponentFactory} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */(i)){const u=i.resolveComponentFactory(s);this.activated=r.createComponent(u,r.length,l)}else this.activated=r.createComponent(s,{index:r.length,injector:l,environmentInjector:i??this.environmentInjector});this.changeDetector.markForCheck(),this.activateEvents.emit(this.activated.instance)}}return e.\u0275fac=function(t){return new(t||e)(C(Ac),C(Bi),function Ko(e){return function De(e,n){if("class"===n)return e.classes;if("style"===n)return e.styles;const t=e.attrs;if(t){const i=t.length;let r=0;for(;r{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275cmp=et({type:e,selectors:[["ng-component"]],standalone:!0,features:[YD],decls:1,vars:0,template:function(t,i){1&t&&Li(0,"router-outlet")},dependencies:[d_],encapsulation:2}),e})(); + */(i)){const u=i.resolveComponentFactory(s);this.activated=r.createComponent(u,r.length,l)}else this.activated=r.createComponent(s,{index:r.length,injector:l,environmentInjector:i??this.environmentInjector});this.changeDetector.markForCheck(),this.activateEvents.emit(this.activated.instance)}}return e.\u0275fac=function(t){return new(t||e)(C(Ic),C(Hi),function zo(e){return function De(e,n){if("class"===n)return e.classes;if("style"===n)return e.styles;const t=e.attrs;if(t){const i=t.length;let r=0;for(;r{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275cmp=et({type:e,selectors:[["ng-component"]],standalone:!0,features:[KD],decls:1,vars:0,template:function(t,i){1&t&&Li(0,"router-outlet")},dependencies:[d_],encapsulation:2}),e})(); /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */function $w(e,n){return e.providers&&!e._injector&&(e._injector=bd(e.providers,n,`Route: ${e.path}`)),e._injector??n}function p_(e){const n=e.children&&e.children.map(p_),t=n?{...e,children:n}:{...e};return!t.component&&!t.loadComponent&&(n||t.loadChildren)&&t.outlet&&t.outlet!==pe&&(t.component=f_),t}function yi(e){return e.outlet||pe}function Uw(e,n){const t=e.filter(i=>yi(i)===n);return t.push(...e.filter(i=>yi(i)!==n)),t}function Ic(e){if(!e)return null;if(e.routeConfig?._injector)return e.routeConfig._injector;for(let n=e.parent;n;n=n.parent){const t=n.routeConfig;if(t?._loadedInjector)return t._loadedInjector;if(t?._injector)return t._injector}return null} + */function $w(e,n){return e.providers&&!e._injector&&(e._injector=bd(e.providers,n,`Route: ${e.path}`)),e._injector??n}function p_(e){const n=e.children&&e.children.map(p_),t=n?{...e,children:n}:{...e};return!t.component&&!t.loadComponent&&(n||t.loadChildren)&&t.outlet&&t.outlet!==pe&&(t.component=f_),t}function yi(e){return e.outlet||pe}function Uw(e,n){const t=e.filter(i=>yi(i)===n);return t.push(...e.filter(i=>yi(i)!==n)),t}function Ac(e){if(!e)return null;if(e.routeConfig?._injector)return e.routeConfig._injector;for(let n=e.parent;n;n=n.parent){const t=n.routeConfig;if(t?._loadedInjector)return t._loadedInjector;if(t?._injector)return t._injector}return null} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */class QL{constructor(n,t,i,r){this.routeReuseStrategy=n,this.futureState=t,this.currState=i,this.forwardEvent=r}activate(n){const t=this.futureState._root,i=this.currState?this.currState._root:null;this.deactivateChildRoutes(t,i,n),l_(this.futureState.root),this.activateChildRoutes(t,i,n)}deactivateChildRoutes(n,t,i){const r=La(t);n.children.forEach(o=>{const s=o.value.outlet;this.deactivateRoutes(o,r[s],i),delete r[s]}),an(r,(o,s)=>{this.deactivateRouteAndItsChildren(o,i)})}deactivateRoutes(n,t,i){const r=n.value,o=t?t.value:null;if(r===o)if(r.component){const s=i.getContext(r.outlet);s&&this.deactivateChildRoutes(n,t,s.children)}else this.deactivateChildRoutes(n,t,i);else o&&this.deactivateRouteAndItsChildren(t,i)}deactivateRouteAndItsChildren(n,t){n.value.component&&this.routeReuseStrategy.shouldDetach(n.value.snapshot)?this.detachAndStoreRouteSubtree(n,t):this.deactivateRouteAndOutlet(n,t)}detachAndStoreRouteSubtree(n,t){const i=t.getContext(n.value.outlet),r=i&&n.value.component?i.children:t,o=La(n);for(const s of Object.keys(o))this.deactivateRouteAndItsChildren(o[s],r);if(i&&i.outlet){const s=i.outlet.detach(),a=i.children.onOutletDeactivated();this.routeReuseStrategy.store(n.value.snapshot,{componentRef:s,route:n,contexts:a})}}deactivateRouteAndOutlet(n,t){const i=t.getContext(n.value.outlet),r=i&&n.value.component?i.children:t,o=La(n);for(const s of Object.keys(o))this.deactivateRouteAndItsChildren(o[s],r);i&&i.outlet&&(i.outlet.deactivate(),i.children.onOutletDeactivated(),i.attachRef=null,i.resolver=null,i.route=null)}activateChildRoutes(n,t,i){const r=La(t);n.children.forEach(o=>{this.activateRoutes(o,r[o.value.outlet],i),this.forwardEvent(new VL(o.value.snapshot))}),n.children.length&&this.forwardEvent(new PL(n.value.snapshot))}activateRoutes(n,t,i){const r=n.value,o=t?t.value:null;if(l_(r),r===o)if(r.component){const s=i.getOrCreateContext(r.outlet);this.activateChildRoutes(n,t,s.children)}else this.activateChildRoutes(n,t,i);else if(r.component){const s=i.getOrCreateContext(r.outlet);if(this.routeReuseStrategy.shouldAttach(r.snapshot)){const a=this.routeReuseStrategy.retrieve(r.snapshot);this.routeReuseStrategy.store(r.snapshot,null),s.children.onOutletReAttached(a.contexts),s.attachRef=a.componentRef,s.route=a.route.value,s.outlet&&s.outlet.attach(a.componentRef,a.route.value),l_(a.route.value),this.activateChildRoutes(n,null,s.children)}else{const a=Ic(r.snapshot),l=a?.get(Gl)??null;s.attachRef=null,s.route=r,s.resolver=l,s.injector=a,s.outlet&&s.outlet.activateWith(r,s.injector),this.activateChildRoutes(n,null,s.children)}}else this.activateChildRoutes(n,null,i)}} + */class QL{constructor(n,t,i,r){this.routeReuseStrategy=n,this.futureState=t,this.currState=i,this.forwardEvent=r}activate(n){const t=this.futureState._root,i=this.currState?this.currState._root:null;this.deactivateChildRoutes(t,i,n),l_(this.futureState.root),this.activateChildRoutes(t,i,n)}deactivateChildRoutes(n,t,i){const r=La(t);n.children.forEach(o=>{const s=o.value.outlet;this.deactivateRoutes(o,r[s],i),delete r[s]}),an(r,(o,s)=>{this.deactivateRouteAndItsChildren(o,i)})}deactivateRoutes(n,t,i){const r=n.value,o=t?t.value:null;if(r===o)if(r.component){const s=i.getContext(r.outlet);s&&this.deactivateChildRoutes(n,t,s.children)}else this.deactivateChildRoutes(n,t,i);else o&&this.deactivateRouteAndItsChildren(t,i)}deactivateRouteAndItsChildren(n,t){n.value.component&&this.routeReuseStrategy.shouldDetach(n.value.snapshot)?this.detachAndStoreRouteSubtree(n,t):this.deactivateRouteAndOutlet(n,t)}detachAndStoreRouteSubtree(n,t){const i=t.getContext(n.value.outlet),r=i&&n.value.component?i.children:t,o=La(n);for(const s of Object.keys(o))this.deactivateRouteAndItsChildren(o[s],r);if(i&&i.outlet){const s=i.outlet.detach(),a=i.children.onOutletDeactivated();this.routeReuseStrategy.store(n.value.snapshot,{componentRef:s,route:n,contexts:a})}}deactivateRouteAndOutlet(n,t){const i=t.getContext(n.value.outlet),r=i&&n.value.component?i.children:t,o=La(n);for(const s of Object.keys(o))this.deactivateRouteAndItsChildren(o[s],r);i&&i.outlet&&(i.outlet.deactivate(),i.children.onOutletDeactivated(),i.attachRef=null,i.resolver=null,i.route=null)}activateChildRoutes(n,t,i){const r=La(t);n.children.forEach(o=>{this.activateRoutes(o,r[o.value.outlet],i),this.forwardEvent(new VL(o.value.snapshot))}),n.children.length&&this.forwardEvent(new FL(n.value.snapshot))}activateRoutes(n,t,i){const r=n.value,o=t?t.value:null;if(l_(r),r===o)if(r.component){const s=i.getOrCreateContext(r.outlet);this.activateChildRoutes(n,t,s.children)}else this.activateChildRoutes(n,t,i);else if(r.component){const s=i.getOrCreateContext(r.outlet);if(this.routeReuseStrategy.shouldAttach(r.snapshot)){const a=this.routeReuseStrategy.retrieve(r.snapshot);this.routeReuseStrategy.store(r.snapshot,null),s.children.onOutletReAttached(a.contexts),s.attachRef=a.componentRef,s.route=a.route.value,s.outlet&&s.outlet.attach(a.componentRef,a.route.value),l_(a.route.value),this.activateChildRoutes(n,null,s.children)}else{const a=Ac(r.snapshot),l=a?.get(Gl)??null;s.attachRef=null,s.route=r,s.resolver=l,s.injector=a,s.outlet&&s.outlet.activateWith(r,s.injector),this.activateChildRoutes(n,null,s.children)}}else this.activateChildRoutes(n,null,i)}} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */class Gw{constructor(n){this.path=n,this.route=this.path[this.path.length-1]}}class df{constructor(n,t){this.component=n,this.route=t}}function XL(e,n,t){const i=e._root;return Oc(i,n?n._root:null,t,[i.value])}function Va(e,n){const t=Symbol(),i=n.get(e,t);return i===t?"function"!=typeof e||function bh(e){return null!==Vs(e)}(e)?n.get(e):e:i}function Oc(e,n,t,i,r={canDeactivateChecks:[],canActivateChecks:[]}){const o=La(n);return e.children.forEach(s=>{(function t2(e,n,t,i,r={canDeactivateChecks:[],canActivateChecks:[]}){const o=e.value,s=n?n.value:null,a=t?t.getContext(e.value.outlet):null;if(s&&o.routeConfig===s.routeConfig){const l=function n2(e,n,t){if("function"==typeof t)return t(e,n);switch(t){case"pathParamsChange":return!rs(e.url,n.url);case"pathParamsOrQueryParamsChange":return!rs(e.url,n.url)||!cr(e.queryParams,n.queryParams);case"always":return!0;case"paramsOrQueryParamsChange":return!c_(e,n)||!cr(e.queryParams,n.queryParams);default:return!c_(e,n)}}(s,o,o.routeConfig.runGuardsAndResolvers);l?r.canActivateChecks.push(new Gw(i)):(o.data=s.data,o._resolvedData=s._resolvedData),Oc(e,n,o.component?a?a.children:null:t,i,r),l&&a&&a.outlet&&a.outlet.isActivated&&r.canDeactivateChecks.push(new df(a.outlet.component,s))}else s&&kc(n,a,r),r.canActivateChecks.push(new Gw(i)),Oc(e,null,o.component?a?a.children:null:t,i,r)})(s,o[s.value.outlet],t,i.concat([s.value]),r),delete o[s.value.outlet]}),an(o,(s,a)=>kc(s,t.getContext(a),r)),r}function kc(e,n,t){const i=La(e),r=e.value;an(i,(o,s)=>{kc(o,r.component?n?n.children.getContext(s):null:n,t)}),t.canDeactivateChecks.push(new df(r.component&&n&&n.outlet&&n.outlet.isActivated?n.outlet.component:null,r))} + */class Gw{constructor(n){this.path=n,this.route=this.path[this.path.length-1]}}class df{constructor(n,t){this.component=n,this.route=t}}function XL(e,n,t){const i=e._root;return kc(i,n?n._root:null,t,[i.value])}function Va(e,n){const t=Symbol(),i=n.get(e,t);return i===t?"function"!=typeof e||function bh(e){return null!==Vs(e)}(e)?n.get(e):e:i}function kc(e,n,t,i,r={canDeactivateChecks:[],canActivateChecks:[]}){const o=La(n);return e.children.forEach(s=>{(function t2(e,n,t,i,r={canDeactivateChecks:[],canActivateChecks:[]}){const o=e.value,s=n?n.value:null,a=t?t.getContext(e.value.outlet):null;if(s&&o.routeConfig===s.routeConfig){const l=function n2(e,n,t){if("function"==typeof t)return t(e,n);switch(t){case"pathParamsChange":return!rs(e.url,n.url);case"pathParamsOrQueryParamsChange":return!rs(e.url,n.url)||!cr(e.queryParams,n.queryParams);case"always":return!0;case"paramsOrQueryParamsChange":return!c_(e,n)||!cr(e.queryParams,n.queryParams);default:return!c_(e,n)}}(s,o,o.routeConfig.runGuardsAndResolvers);l?r.canActivateChecks.push(new Gw(i)):(o.data=s.data,o._resolvedData=s._resolvedData),kc(e,n,o.component?a?a.children:null:t,i,r),l&&a&&a.outlet&&a.outlet.isActivated&&r.canDeactivateChecks.push(new df(a.outlet.component,s))}else s&&Oc(n,a,r),r.canActivateChecks.push(new Gw(i)),kc(e,null,o.component?a?a.children:null:t,i,r)})(s,o[s.value.outlet],t,i.concat([s.value]),r),delete o[s.value.outlet]}),an(o,(s,a)=>Oc(s,t.getContext(a),r)),r}function Oc(e,n,t){const i=La(e),r=e.value;an(i,(o,s)=>{Oc(o,r.component?n?n.children.getContext(s):null:n,t)}),t.canDeactivateChecks.push(new df(r.component&&n&&n.outlet&&n.outlet.isActivated?n.outlet.component:null,r))} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */function Rc(e){return"function"==typeof e}function g_(e){return e instanceof bc||"EmptyError"===e?.name} + */function xc(e){return"function"==typeof e}function g_(e){return e instanceof bc||"EmptyError"===e?.name} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */const ff=Symbol("INITIAL_VALUE");function Ha(){return vi(e=>Zd(e.map(n=>n.pipe(sn(1),function Qd(...e){const n=en(e);return qe((t,i)=>{(n?Dc(e,t,n):Dc(e,t)).subscribe(i)})}(ff)))).pipe(ne(n=>{for(const t of n)if(!0!==t){if(t===ff)return ff;if(!1===t||t instanceof is)return t}return!0}),vn(n=>n!==ff),sn(1)))} + */const ff=Symbol("INITIAL_VALUE");function Ba(){return vi(e=>Jd(e.map(n=>n.pipe(sn(1),function Qd(...e){const n=en(e);return qe((t,i)=>{(n?Dc(e,t,n):Dc(e,t)).subscribe(i)})}(ff)))).pipe(ne(n=>{for(const t of n)if(!0!==t){if(t===ff)return ff;if(!1===t||t instanceof is)return t}return!0}),vn(n=>n!==ff),sn(1)))} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */function Ww(e){return function Xa(...e){return Cs(e)}(Yt(n=>{if(os(n))throw Vw(0,n)}),ne(n=>!0===n))} + */function Ww(e){return function Xa(...e){return Cs(e)}(Kt(n=>{if(os(n))throw Vw(0,n)}),ne(n=>!0===n))} /** * @license * Copyright Google LLC All Rights Reserved. @@ -1582,21 +1582,21 @@ class kw{constructor(n){this._root=n}get root(){return this._root.value}parent(n * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -const m_={matched:!1,consumedSegments:[],remainingSegments:[],parameters:{},positionalParamSegments:{}};function Kw(e,n,t,i,r){const o=__(e,n,t);return o.matched?function b2(e,n,t,i){const r=n.canMatch;return r&&0!==r.length?Z(r.map(s=>{const a=Va(s,e);return vo(function c2(e){return e&&Rc(e.canMatch)}(a)?a.canMatch(n,t):e.runInContext(()=>a(n,t)))})).pipe(Ha(),Ww()):Z(!0)}(i=$w(n,i),n,t).pipe(ne(s=>!0===s?o:{...m_})):Z(o)}function __(e,n,t){if(""===n.path)return"full"===n.pathMatch&&(e.hasChildren()||t.length>0)?{...m_}:{matched:!0,consumedSegments:[],remainingSegments:t,parameters:{},positionalParamSegments:{}};const r=(n.matcher||tL)(t,e,n);if(!r)return{...m_};const o={};an(r.posParams,(a,l)=>{o[l]=a.path});const s=r.consumed.length>0?{...o,...r.consumed[r.consumed.length-1].parameters}:o;return{matched:!0,consumedSegments:r.consumed,remainingSegments:t.slice(r.consumed.length),parameters:s,positionalParamSegments:r.posParams??{}}}function hf(e,n,t,i,r="corrected"){if(t.length>0&&function w2(e,n,t){return t.some(i=>pf(e,n,i)&&yi(i)!==pe)}(e,t,i)){const s=new me(n,function C2(e,n,t,i){const r={};r[pe]=i,i._sourceSegment=e,i._segmentIndexShift=n.length;for(const o of t)if(""===o.path&&yi(o)!==pe){const s=new me([],{});s._sourceSegment=e,s._segmentIndexShift=n.length,r[yi(o)]=s}return r}(e,n,i,new me(t,e.children)));return s._sourceSegment=e,s._segmentIndexShift=n.length,{segmentGroup:s,slicedSegments:[]}}if(0===t.length&&function S2(e,n,t){return t.some(i=>pf(e,n,i))}(e,t,i)){const s=new me(e.segments,function D2(e,n,t,i,r,o){const s={};for(const a of i)if(pf(e,t,a)&&!r[yi(a)]){const l=new me([],{});l._sourceSegment=e,l._segmentIndexShift="legacy"===o?e.segments.length:n.length,s[yi(a)]=l}return{...r,...s}}(e,n,t,i,e.children,r));return s._sourceSegment=e,s._segmentIndexShift=n.length,{segmentGroup:s,slicedSegments:t}}const o=new me(e.segments,e.children);return o._sourceSegment=e,o._segmentIndexShift=n.length,{segmentGroup:o,slicedSegments:t}}function pf(e,n,t){return(!(e.hasChildren()||n.length>0)||"full"!==t.pathMatch)&&""===t.path}function zw(e,n,t,i){return!!(yi(e)===i||i!==pe&&pf(n,t,e))&&("**"===e.path||__(n,e,t).matched)}function Yw(e,n,t){return 0===n.length&&!e.children[t]} +const m_={matched:!1,consumedSegments:[],remainingSegments:[],parameters:{},positionalParamSegments:{}};function zw(e,n,t,i,r){const o=__(e,n,t);return o.matched?function b2(e,n,t,i){const r=n.canMatch;return r&&0!==r.length?J(r.map(s=>{const a=Va(s,e);return vo(function c2(e){return e&&xc(e.canMatch)}(a)?a.canMatch(n,t):e.runInContext(()=>a(n,t)))})).pipe(Ba(),Ww()):J(!0)}(i=$w(n,i),n,t).pipe(ne(s=>!0===s?o:{...m_})):J(o)}function __(e,n,t){if(""===n.path)return"full"===n.pathMatch&&(e.hasChildren()||t.length>0)?{...m_}:{matched:!0,consumedSegments:[],remainingSegments:t,parameters:{},positionalParamSegments:{}};const r=(n.matcher||tL)(t,e,n);if(!r)return{...m_};const o={};an(r.posParams,(a,l)=>{o[l]=a.path});const s=r.consumed.length>0?{...o,...r.consumed[r.consumed.length-1].parameters}:o;return{matched:!0,consumedSegments:r.consumed,remainingSegments:t.slice(r.consumed.length),parameters:s,positionalParamSegments:r.posParams??{}}}function hf(e,n,t,i,r="corrected"){if(t.length>0&&function w2(e,n,t){return t.some(i=>pf(e,n,i)&&yi(i)!==pe)}(e,t,i)){const s=new me(n,function C2(e,n,t,i){const r={};r[pe]=i,i._sourceSegment=e,i._segmentIndexShift=n.length;for(const o of t)if(""===o.path&&yi(o)!==pe){const s=new me([],{});s._sourceSegment=e,s._segmentIndexShift=n.length,r[yi(o)]=s}return r}(e,n,i,new me(t,e.children)));return s._sourceSegment=e,s._segmentIndexShift=n.length,{segmentGroup:s,slicedSegments:[]}}if(0===t.length&&function S2(e,n,t){return t.some(i=>pf(e,n,i))}(e,t,i)){const s=new me(e.segments,function D2(e,n,t,i,r,o){const s={};for(const a of i)if(pf(e,t,a)&&!r[yi(a)]){const l=new me([],{});l._sourceSegment=e,l._segmentIndexShift="legacy"===o?e.segments.length:n.length,s[yi(a)]=l}return{...r,...s}}(e,n,t,i,e.children,r));return s._sourceSegment=e,s._segmentIndexShift=n.length,{segmentGroup:s,slicedSegments:t}}const o=new me(e.segments,e.children);return o._sourceSegment=e,o._segmentIndexShift=n.length,{segmentGroup:o,slicedSegments:t}}function pf(e,n,t){return(!(e.hasChildren()||n.length>0)||"full"!==t.pathMatch)&&""===t.path}function Yw(e,n,t,i){return!!(yi(e)===i||i!==pe&&pf(n,t,e))&&("**"===e.path||__(n,e,t).matched)}function Kw(e,n,t){return 0===n.length&&!e.children[t]} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */const gf=!1;class mf{constructor(n){this.segmentGroup=n||null}}class qw{constructor(n){this.urlTree=n}}function xc(e){return Ra(new mf(e))}function Jw(e){return Ra(new qw(e))}class T2{constructor(n,t,i,r,o){this.injector=n,this.configLoader=t,this.urlSerializer=i,this.urlTree=r,this.config=o,this.allowRedirects=!0}apply(){const n=hf(this.urlTree.root,[],[],this.config).segmentGroup,t=new me(n.segments,n.children);return this.expandSegmentGroup(this.injector,this.config,t,pe).pipe(ne(o=>this.createUrlTree(af(o),this.urlTree.queryParams,this.urlTree.fragment))).pipe($r(o=>{if(o instanceof qw)return this.allowRedirects=!1,this.match(o.urlTree);throw o instanceof mf?this.noMatchError(o):o}))}match(n){return this.expandSegmentGroup(this.injector,this.config,n.root,pe).pipe(ne(r=>this.createUrlTree(af(r),n.queryParams,n.fragment))).pipe($r(r=>{throw r instanceof mf?this.noMatchError(r):r}))}noMatchError(n){return new P(4002,gf)}createUrlTree(n,t,i){const r=e_(n);return new is(r,t,i)}expandSegmentGroup(n,t,i,r){return 0===i.segments.length&&i.hasChildren()?this.expandChildren(n,t,i).pipe(ne(o=>new me([],o))):this.expandSegment(n,i,t,i.segments,r,!0)}expandChildren(n,t,i){const r=[];for(const o of Object.keys(i.children))"primary"===o?r.unshift(o):r.push(o);return gt(r).pipe(_o(o=>{const s=i.children[o],a=Uw(t,o);return this.expandSegmentGroup(n,a,s,o).pipe(ne(l=>({segment:l,outlet:o})))}),cw((o,s)=>(o[s.outlet]=s.segment,o),{}),uw())}expandSegment(n,t,i,r,o,s){return gt(i).pipe(_o(a=>this.expandSegmentAgainstRoute(n,t,i,a,r,o,s).pipe($r(u=>{if(u instanceof mf)return Z(null);throw u}))),mo(a=>!!a),$r((a,l)=>{if(g_(a))return Yw(t,r,o)?Z(new me([],{})):xc(t);throw a}))}expandSegmentAgainstRoute(n,t,i,r,o,s,a){return zw(r,t,o,s)?void 0===r.redirectTo?this.matchSegmentAgainstRoute(n,t,r,o,s):a&&this.allowRedirects?this.expandSegmentAgainstRouteUsingRedirect(n,t,i,r,o,s):xc(t):xc(t)}expandSegmentAgainstRouteUsingRedirect(n,t,i,r,o,s){return"**"===r.path?this.expandWildCardWithParamsAgainstRouteUsingRedirect(n,i,r,s):this.expandRegularSegmentAgainstRouteUsingRedirect(n,t,i,r,o,s)}expandWildCardWithParamsAgainstRouteUsingRedirect(n,t,i,r){const o=this.applyRedirectCommands([],i.redirectTo,{});return i.redirectTo.startsWith("/")?Jw(o):this.lineralizeSegments(i,o).pipe(dt(s=>{const a=new me(s,{});return this.expandSegment(n,a,t,s,r,!1)}))}expandRegularSegmentAgainstRouteUsingRedirect(n,t,i,r,o,s){const{matched:a,consumedSegments:l,remainingSegments:u,positionalParamSegments:f}=__(t,r,o);if(!a)return xc(t);const p=this.applyRedirectCommands(l,r.redirectTo,f);return r.redirectTo.startsWith("/")?Jw(p):this.lineralizeSegments(r,p).pipe(dt(m=>this.expandSegment(n,t,i,m.concat(u),s,!1)))}matchSegmentAgainstRoute(n,t,i,r,o){return"**"===i.path?(n=$w(i,n),i.loadChildren?(i._loadedRoutes?Z({routes:i._loadedRoutes,injector:i._loadedInjector}):this.configLoader.loadChildren(n,i)).pipe(ne(a=>(i._loadedRoutes=a.routes,i._loadedInjector=a.injector,new me(r,{})))):Z(new me(r,{}))):Kw(t,i,r,n).pipe(vi(({matched:s,consumedSegments:a,remainingSegments:l})=>s?this.getChildConfig(n=i._injector??n,i,r).pipe(dt(f=>{const p=f.injector??n,m=f.routes,{segmentGroup:v,slicedSegments:y}=hf(t,a,l,m),D=new me(v.segments,v.children);if(0===y.length&&D.hasChildren())return this.expandChildren(p,m,D).pipe(ne(S=>new me(a,S)));if(0===m.length&&0===y.length)return Z(new me(a,{}));const w=yi(i)===o;return this.expandSegment(p,D,m,y,w?pe:o,!0).pipe(ne(I=>new me(a.concat(I.segments),I.children)))})):xc(t)))}getChildConfig(n,t,i){return t.children?Z({routes:t.children,injector:n}):t.loadChildren?void 0!==t._loadedRoutes?Z({routes:t._loadedRoutes,injector:t._loadedInjector}):function y2(e,n,t,i){const r=n.canLoad;return void 0===r||0===r.length?Z(!0):Z(r.map(s=>{const a=Va(s,e);return vo(function o2(e){return e&&Rc(e.canLoad)}(a)?a.canLoad(n,t):e.runInContext(()=>a(n,t)))})).pipe(Ha(),Ww())}(n,t,i).pipe(dt(r=>r?this.configLoader.loadChildren(n,t).pipe(Yt(o=>{t._loadedRoutes=o.routes,t._loadedInjector=o.injector})):function M2(e){return Ra(Hw(gf,3))}())):Z({routes:[],injector:n})}lineralizeSegments(n,t){let i=[],r=t.root;for(;;){if(i=i.concat(r.segments),0===r.numberOfChildren)return Z(i);if(r.numberOfChildren>1||!r.children[pe])return Ra(new P(4e3,gf));r=r.children[pe]}}applyRedirectCommands(n,t,i){return this.applyRedirectCreateUrlTree(t,this.urlSerializer.parse(t),n,i)}applyRedirectCreateUrlTree(n,t,i,r){const o=this.createSegmentGroup(n,t.root,i,r);return new is(o,this.createQueryParams(t.queryParams,this.urlTree.queryParams),t.fragment)}createQueryParams(n,t){const i={};return an(n,(r,o)=>{if("string"==typeof r&&r.startsWith(":")){const a=r.substring(1);i[o]=t[a]}else i[o]=r}),i}createSegmentGroup(n,t,i,r){const o=this.createSegments(n,t.segments,i,r);let s={};return an(t.children,(a,l)=>{s[l]=this.createSegmentGroup(n,a,i,r)}),new me(o,s)}createSegments(n,t,i,r){return t.map(o=>o.path.startsWith(":")?this.findPosParam(n,o,r):this.findOrReturn(o,i))}findPosParam(n,t,i){const r=i[t.path.substring(1)];if(!r)throw new P(4001,gf);return r}findOrReturn(n,t){let i=0;for(const r of t){if(r.path===n.path)return t.splice(i),r;i++}return n}} + */const gf=!1;class mf{constructor(n){this.segmentGroup=n||null}}class qw{constructor(n){this.urlTree=n}}function Rc(e){return xa(new mf(e))}function Zw(e){return xa(new qw(e))}class T2{constructor(n,t,i,r,o){this.injector=n,this.configLoader=t,this.urlSerializer=i,this.urlTree=r,this.config=o,this.allowRedirects=!0}apply(){const n=hf(this.urlTree.root,[],[],this.config).segmentGroup,t=new me(n.segments,n.children);return this.expandSegmentGroup(this.injector,this.config,t,pe).pipe(ne(o=>this.createUrlTree(af(o),this.urlTree.queryParams,this.urlTree.fragment))).pipe($r(o=>{if(o instanceof qw)return this.allowRedirects=!1,this.match(o.urlTree);throw o instanceof mf?this.noMatchError(o):o}))}match(n){return this.expandSegmentGroup(this.injector,this.config,n.root,pe).pipe(ne(r=>this.createUrlTree(af(r),n.queryParams,n.fragment))).pipe($r(r=>{throw r instanceof mf?this.noMatchError(r):r}))}noMatchError(n){return new F(4002,gf)}createUrlTree(n,t,i){const r=e_(n);return new is(r,t,i)}expandSegmentGroup(n,t,i,r){return 0===i.segments.length&&i.hasChildren()?this.expandChildren(n,t,i).pipe(ne(o=>new me([],o))):this.expandSegment(n,i,t,i.segments,r,!0)}expandChildren(n,t,i){const r=[];for(const o of Object.keys(i.children))"primary"===o?r.unshift(o):r.push(o);return gt(r).pipe(_o(o=>{const s=i.children[o],a=Uw(t,o);return this.expandSegmentGroup(n,a,s,o).pipe(ne(l=>({segment:l,outlet:o})))}),cw((o,s)=>(o[s.outlet]=s.segment,o),{}),uw())}expandSegment(n,t,i,r,o,s){return gt(i).pipe(_o(a=>this.expandSegmentAgainstRoute(n,t,i,a,r,o,s).pipe($r(u=>{if(u instanceof mf)return J(null);throw u}))),mo(a=>!!a),$r((a,l)=>{if(g_(a))return Kw(t,r,o)?J(new me([],{})):Rc(t);throw a}))}expandSegmentAgainstRoute(n,t,i,r,o,s,a){return Yw(r,t,o,s)?void 0===r.redirectTo?this.matchSegmentAgainstRoute(n,t,r,o,s):a&&this.allowRedirects?this.expandSegmentAgainstRouteUsingRedirect(n,t,i,r,o,s):Rc(t):Rc(t)}expandSegmentAgainstRouteUsingRedirect(n,t,i,r,o,s){return"**"===r.path?this.expandWildCardWithParamsAgainstRouteUsingRedirect(n,i,r,s):this.expandRegularSegmentAgainstRouteUsingRedirect(n,t,i,r,o,s)}expandWildCardWithParamsAgainstRouteUsingRedirect(n,t,i,r){const o=this.applyRedirectCommands([],i.redirectTo,{});return i.redirectTo.startsWith("/")?Zw(o):this.lineralizeSegments(i,o).pipe(dt(s=>{const a=new me(s,{});return this.expandSegment(n,a,t,s,r,!1)}))}expandRegularSegmentAgainstRouteUsingRedirect(n,t,i,r,o,s){const{matched:a,consumedSegments:l,remainingSegments:u,positionalParamSegments:f}=__(t,r,o);if(!a)return Rc(t);const p=this.applyRedirectCommands(l,r.redirectTo,f);return r.redirectTo.startsWith("/")?Zw(p):this.lineralizeSegments(r,p).pipe(dt(m=>this.expandSegment(n,t,i,m.concat(u),s,!1)))}matchSegmentAgainstRoute(n,t,i,r,o){return"**"===i.path?(n=$w(i,n),i.loadChildren?(i._loadedRoutes?J({routes:i._loadedRoutes,injector:i._loadedInjector}):this.configLoader.loadChildren(n,i)).pipe(ne(a=>(i._loadedRoutes=a.routes,i._loadedInjector=a.injector,new me(r,{})))):J(new me(r,{}))):zw(t,i,r,n).pipe(vi(({matched:s,consumedSegments:a,remainingSegments:l})=>s?this.getChildConfig(n=i._injector??n,i,r).pipe(dt(f=>{const p=f.injector??n,m=f.routes,{segmentGroup:v,slicedSegments:y}=hf(t,a,l,m),D=new me(v.segments,v.children);if(0===y.length&&D.hasChildren())return this.expandChildren(p,m,D).pipe(ne(S=>new me(a,S)));if(0===m.length&&0===y.length)return J(new me(a,{}));const w=yi(i)===o;return this.expandSegment(p,D,m,y,w?pe:o,!0).pipe(ne(A=>new me(a.concat(A.segments),A.children)))})):Rc(t)))}getChildConfig(n,t,i){return t.children?J({routes:t.children,injector:n}):t.loadChildren?void 0!==t._loadedRoutes?J({routes:t._loadedRoutes,injector:t._loadedInjector}):function y2(e,n,t,i){const r=n.canLoad;return void 0===r||0===r.length?J(!0):J(r.map(s=>{const a=Va(s,e);return vo(function o2(e){return e&&xc(e.canLoad)}(a)?a.canLoad(n,t):e.runInContext(()=>a(n,t)))})).pipe(Ba(),Ww())}(n,t,i).pipe(dt(r=>r?this.configLoader.loadChildren(n,t).pipe(Kt(o=>{t._loadedRoutes=o.routes,t._loadedInjector=o.injector})):function N2(e){return xa(Bw(gf,3))}())):J({routes:[],injector:n})}lineralizeSegments(n,t){let i=[],r=t.root;for(;;){if(i=i.concat(r.segments),0===r.numberOfChildren)return J(i);if(r.numberOfChildren>1||!r.children[pe])return xa(new F(4e3,gf));r=r.children[pe]}}applyRedirectCommands(n,t,i){return this.applyRedirectCreateUrlTree(t,this.urlSerializer.parse(t),n,i)}applyRedirectCreateUrlTree(n,t,i,r){const o=this.createSegmentGroup(n,t.root,i,r);return new is(o,this.createQueryParams(t.queryParams,this.urlTree.queryParams),t.fragment)}createQueryParams(n,t){const i={};return an(n,(r,o)=>{if("string"==typeof r&&r.startsWith(":")){const a=r.substring(1);i[o]=t[a]}else i[o]=r}),i}createSegmentGroup(n,t,i,r){const o=this.createSegments(n,t.segments,i,r);let s={};return an(t.children,(a,l)=>{s[l]=this.createSegmentGroup(n,a,i,r)}),new me(o,s)}createSegments(n,t,i,r){return t.map(o=>o.path.startsWith(":")?this.findPosParam(n,o,r):this.findOrReturn(o,i))}findPosParam(n,t,i){const r=i[t.path.substring(1)];if(!r)throw new F(4001,gf);return r}findOrReturn(n,t){let i=0;for(const r of t){if(r.path===n.path)return t.splice(i),r;i++}return n}} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */class I2{}class R2{constructor(n,t,i,r,o,s,a,l){this.injector=n,this.rootComponentType=t,this.config=i,this.urlTree=r,this.url=o,this.paramsInheritanceStrategy=s,this.relativeLinkResolution=a,this.urlSerializer=l}recognize(){const n=hf(this.urlTree.root,[],[],this.config.filter(t=>void 0===t.redirectTo),this.relativeLinkResolution).segmentGroup;return this.processSegmentGroup(this.injector,this.config,n,pe).pipe(ne(t=>{if(null===t)return null;const i=new cf([],Object.freeze({}),Object.freeze({...this.urlTree.queryParams}),this.urlTree.fragment,{},pe,this.rootComponentType,null,this.urlTree.root,-1,{}),r=new Gr(i,t),o=new Pw(this.url,r);return this.inheritParamsAndData(o._root),o}))}inheritParamsAndData(n){const t=n.value,i=Fw(t,this.paramsInheritanceStrategy);t.params=Object.freeze(i.params),t.data=Object.freeze(i.data),n.children.forEach(r=>this.inheritParamsAndData(r))}processSegmentGroup(n,t,i,r){return 0===i.segments.length&&i.hasChildren()?this.processChildren(n,t,i):this.processSegment(n,t,i,i.segments,r)}processChildren(n,t,i){return gt(Object.keys(i.children)).pipe(_o(r=>{const o=i.children[r],s=Uw(t,r);return this.processSegmentGroup(n,s,o,r)}),cw((r,o)=>r&&o?(r.push(...o),r):null),function XP(e,n=!1){return qe((t,i)=>{let r=0;t.subscribe(ke(i,o=>{const s=e(o,r++);(s||n)&&i.next(o),!s&&i.complete()}))})}(r=>null!==r),Xd(null),uw(),ne(r=>{if(null===r)return null;const o=Zw(r);return function x2(e){e.sort((n,t)=>n.value.outlet===pe?-1:t.value.outlet===pe?1:n.value.outlet.localeCompare(t.value.outlet))}(o),o}))}processSegment(n,t,i,r,o){return gt(t).pipe(_o(s=>this.processSegmentAgainstRoute(s._injector??n,s,i,r,o)),mo(s=>!!s),$r(s=>{if(g_(s))return Yw(i,r,o)?Z([]):Z(null);throw s}))}processSegmentAgainstRoute(n,t,i,r,o){if(t.redirectTo||!zw(t,i,r,o))return Z(null);let s;if("**"===t.path){const a=r.length>0?pw(r).parameters:{},l=Xw(i)+r.length;s=Z({snapshot:new cf(r,a,Object.freeze({...this.urlTree.queryParams}),this.urlTree.fragment,tS(t),yi(t),t.component??t._loadedComponent??null,t,Qw(i),l,nS(t),l),consumedSegments:[],remainingSegments:[]})}else s=Kw(i,t,r,n).pipe(ne(({matched:a,consumedSegments:l,remainingSegments:u,parameters:f})=>{if(!a)return null;const p=Xw(i)+l.length;return{snapshot:new cf(l,f,Object.freeze({...this.urlTree.queryParams}),this.urlTree.fragment,tS(t),yi(t),t.component??t._loadedComponent??null,t,Qw(i),p,nS(t),p),consumedSegments:l,remainingSegments:u}}));return s.pipe(vi(a=>{if(null===a)return Z(null);const{snapshot:l,consumedSegments:u,remainingSegments:f}=a;n=t._injector??n;const p=t._loadedInjector??n,m=function F2(e){return e.children?e.children:e.loadChildren?e._loadedRoutes:[]}(t),{segmentGroup:v,slicedSegments:y}=hf(i,u,f,m.filter(w=>void 0===w.redirectTo),this.relativeLinkResolution);if(0===y.length&&v.hasChildren())return this.processChildren(p,m,v).pipe(ne(w=>null===w?null:[new Gr(l,w)]));if(0===m.length&&0===y.length)return Z([new Gr(l,[])]);const D=yi(t)===o;return this.processSegment(p,m,v,y,D?pe:o).pipe(ne(w=>null===w?null:[new Gr(l,w)]))}))}}function P2(e){const n=e.value.routeConfig;return n&&""===n.path&&void 0===n.redirectTo}function Zw(e){const n=[],t=new Set;for(const i of e){if(!P2(i)){n.push(i);continue}const r=n.find(o=>i.value.routeConfig===o.value.routeConfig);void 0!==r?(r.children.push(...i.children),t.add(r)):n.push(i)}for(const i of t){const r=Zw(i.children);n.push(new Gr(i.value,r))}return n.filter(i=>!t.has(i))}function Qw(e){let n=e;for(;n._sourceSegment;)n=n._sourceSegment;return n}function Xw(e){let n=e,t=n._segmentIndexShift??0;for(;n._sourceSegment;)n=n._sourceSegment,t+=n._segmentIndexShift??0;return t-1}function tS(e){return e.data||{}}function nS(e){return e.resolve||{}} + */class A2{}class x2{constructor(n,t,i,r,o,s,a,l){this.injector=n,this.rootComponentType=t,this.config=i,this.urlTree=r,this.url=o,this.paramsInheritanceStrategy=s,this.relativeLinkResolution=a,this.urlSerializer=l}recognize(){const n=hf(this.urlTree.root,[],[],this.config.filter(t=>void 0===t.redirectTo),this.relativeLinkResolution).segmentGroup;return this.processSegmentGroup(this.injector,this.config,n,pe).pipe(ne(t=>{if(null===t)return null;const i=new cf([],Object.freeze({}),Object.freeze({...this.urlTree.queryParams}),this.urlTree.fragment,{},pe,this.rootComponentType,null,this.urlTree.root,-1,{}),r=new Gr(i,t),o=new Fw(this.url,r);return this.inheritParamsAndData(o._root),o}))}inheritParamsAndData(n){const t=n.value,i=Pw(t,this.paramsInheritanceStrategy);t.params=Object.freeze(i.params),t.data=Object.freeze(i.data),n.children.forEach(r=>this.inheritParamsAndData(r))}processSegmentGroup(n,t,i,r){return 0===i.segments.length&&i.hasChildren()?this.processChildren(n,t,i):this.processSegment(n,t,i,i.segments,r)}processChildren(n,t,i){return gt(Object.keys(i.children)).pipe(_o(r=>{const o=i.children[r],s=Uw(t,r);return this.processSegmentGroup(n,s,o,r)}),cw((r,o)=>r&&o?(r.push(...o),r):null),function XF(e,n=!1){return qe((t,i)=>{let r=0;t.subscribe(Oe(i,o=>{const s=e(o,r++);(s||n)&&i.next(o),!s&&i.complete()}))})}(r=>null!==r),Xd(null),uw(),ne(r=>{if(null===r)return null;const o=Jw(r);return function R2(e){e.sort((n,t)=>n.value.outlet===pe?-1:t.value.outlet===pe?1:n.value.outlet.localeCompare(t.value.outlet))}(o),o}))}processSegment(n,t,i,r,o){return gt(t).pipe(_o(s=>this.processSegmentAgainstRoute(s._injector??n,s,i,r,o)),mo(s=>!!s),$r(s=>{if(g_(s))return Kw(i,r,o)?J([]):J(null);throw s}))}processSegmentAgainstRoute(n,t,i,r,o){if(t.redirectTo||!Yw(t,i,r,o))return J(null);let s;if("**"===t.path){const a=r.length>0?pw(r).parameters:{},l=Xw(i)+r.length;s=J({snapshot:new cf(r,a,Object.freeze({...this.urlTree.queryParams}),this.urlTree.fragment,tS(t),yi(t),t.component??t._loadedComponent??null,t,Qw(i),l,nS(t),l),consumedSegments:[],remainingSegments:[]})}else s=zw(i,t,r,n).pipe(ne(({matched:a,consumedSegments:l,remainingSegments:u,parameters:f})=>{if(!a)return null;const p=Xw(i)+l.length;return{snapshot:new cf(l,f,Object.freeze({...this.urlTree.queryParams}),this.urlTree.fragment,tS(t),yi(t),t.component??t._loadedComponent??null,t,Qw(i),p,nS(t),p),consumedSegments:l,remainingSegments:u}}));return s.pipe(vi(a=>{if(null===a)return J(null);const{snapshot:l,consumedSegments:u,remainingSegments:f}=a;n=t._injector??n;const p=t._loadedInjector??n,m=function P2(e){return e.children?e.children:e.loadChildren?e._loadedRoutes:[]}(t),{segmentGroup:v,slicedSegments:y}=hf(i,u,f,m.filter(w=>void 0===w.redirectTo),this.relativeLinkResolution);if(0===y.length&&v.hasChildren())return this.processChildren(p,m,v).pipe(ne(w=>null===w?null:[new Gr(l,w)]));if(0===m.length&&0===y.length)return J([new Gr(l,[])]);const D=yi(t)===o;return this.processSegment(p,m,v,y,D?pe:o).pipe(ne(w=>null===w?null:[new Gr(l,w)]))}))}}function F2(e){const n=e.value.routeConfig;return n&&""===n.path&&void 0===n.redirectTo}function Jw(e){const n=[],t=new Set;for(const i of e){if(!F2(i)){n.push(i);continue}const r=n.find(o=>i.value.routeConfig===o.value.routeConfig);void 0!==r?(r.children.push(...i.children),t.add(r)):n.push(i)}for(const i of t){const r=Jw(i.children);n.push(new Gr(i.value,r))}return n.filter(i=>!t.has(i))}function Qw(e){let n=e;for(;n._sourceSegment;)n=n._sourceSegment;return n}function Xw(e){let n=e,t=n._segmentIndexShift??0;for(;n._sourceSegment;)n=n._sourceSegment,t+=n._segmentIndexShift??0;return t-1}function tS(e){return e.data||{}}function nS(e){return e.resolve||{}} /** * @license * Copyright Google LLC All Rights Reserved. @@ -1611,14 +1611,14 @@ const m_={matched:!1,consumedSegments:[],remainingSegments:[],parameters:{},posi * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -function H2(e,n){return dt(t=>{const{targetSnapshot:i,guards:{canActivateChecks:r}}=t;if(!r.length)return Z(t);let o=0;return gt(r).pipe(_o(s=>function B2(e,n,t,i){const r=e.routeConfig,o=e._resolve;return void 0!==r?.title&&!iS(r)&&(o[Cc]=r.title),function j2(e,n,t,i){const r=function $2(e){return[...Object.keys(e),...Object.getOwnPropertySymbols(e)]}(e);if(0===r.length)return Z({});const o={};return gt(r).pipe(dt(s=>function U2(e,n,t,i){const r=Ic(n)??i,o=Va(e,r);return vo(o.resolve?o.resolve(n,t):r.runInContext(()=>o(n,t)))}(e[s],n,t,i).pipe(mo(),Yt(a=>{o[s]=a}))),qm(1),function dw(e){return ne(()=>e)}(o),$r(s=>g_(s)?Xt:Ra(s)))}(o,e,n,i).pipe(ne(s=>(e._resolvedData=s,e.data=Fw(e,t).resolve,r&&iS(r)&&(e.data[Cc]=r.title),null)))}(s.route,i,e,n)),Yt(()=>o++),qm(1),dt(s=>o===r.length?Z(t):Xt))})}function iS(e){return"string"==typeof e.title||null===e.title} +function B2(e,n){return dt(t=>{const{targetSnapshot:i,guards:{canActivateChecks:r}}=t;if(!r.length)return J(t);let o=0;return gt(r).pipe(_o(s=>function H2(e,n,t,i){const r=e.routeConfig,o=e._resolve;return void 0!==r?.title&&!iS(r)&&(o[Cc]=r.title),function j2(e,n,t,i){const r=function $2(e){return[...Object.keys(e),...Object.getOwnPropertySymbols(e)]}(e);if(0===r.length)return J({});const o={};return gt(r).pipe(dt(s=>function U2(e,n,t,i){const r=Ac(n)??i,o=Va(e,r);return vo(o.resolve?o.resolve(n,t):r.runInContext(()=>o(n,t)))}(e[s],n,t,i).pipe(mo(),Kt(a=>{o[s]=a}))),qm(1),function dw(e){return ne(()=>e)}(o),$r(s=>g_(s)?Xt:xa(s)))}(o,e,n,i).pipe(ne(s=>(e._resolvedData=s,e.data=Pw(e,t).resolve,r&&iS(r)&&(e.data[Cc]=r.title),null)))}(s.route,i,e,n)),Kt(()=>o++),qm(1),dt(s=>o===r.length?J(t):Xt))})}function iS(e){return"string"==typeof e.title||null===e.title} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */function v_(e){return vi(n=>{const t=e(n);return t?gt(t).pipe(ne(()=>n)):Z(n)})} + */function v_(e){return vi(n=>{const t=e(n);return t?gt(t).pipe(ne(()=>n)):J(n)})} /** * @license * Copyright Google LLC All Rights Reserved. @@ -1640,7 +1640,7 @@ function H2(e,n){return dt(t=>{const{targetSnapshot:i,guards:{canActivateChecks: * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -class G2{}class K2 extends class W2{shouldDetach(n){return!1}store(n,t){}shouldAttach(n){return!1}retrieve(n){return null}shouldReuseRoute(n,t){return n.routeConfig===t.routeConfig}}{} +class G2{}class z2 extends class W2{shouldDetach(n){return!1}store(n,t){}shouldAttach(n){return!1}retrieve(n){return null}shouldReuseRoute(n,t){return n.routeConfig===t.routeConfig}}{} /** * @license * Copyright Google LLC All Rights Reserved. @@ -1654,28 +1654,28 @@ class G2{}class K2 extends class W2{shouldDetach(n){return!1}store(n,t){}shouldA * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */let b_=(()=>{class e{constructor(t,i){this.injector=t,this.compiler=i,this.componentLoaders=new WeakMap,this.childrenLoaders=new WeakMap}loadComponent(t){if(this.componentLoaders.get(t))return this.componentLoaders.get(t);if(t._loadedComponent)return Z(t._loadedComponent);this.onLoadStartListener&&this.onLoadStartListener(t);const i=vo(t.loadComponent()).pipe(Yt(o=>{this.onLoadEndListener&&this.onLoadEndListener(t),t._loadedComponent=o}),Jm(()=>{this.componentLoaders.delete(t)})),r=new aw(i,()=>new Ue).pipe(Ym());return this.componentLoaders.set(t,r),r}loadChildren(t,i){if(this.childrenLoaders.get(i))return this.childrenLoaders.get(i);if(i._loadedRoutes)return Z({routes:i._loadedRoutes,injector:i._loadedInjector});this.onLoadStartListener&&this.onLoadStartListener(i);const o=this.loadModuleFactoryOrRoutes(i.loadChildren).pipe(ne(a=>{this.onLoadEndListener&&this.onLoadEndListener(i);let l,u,f=!1;Array.isArray(a)?u=a:(l=a.create(t).injector,u=hw(l.get(y_,[],X.Self|X.Optional)));return{routes:u.map(p_),injector:l}}),Jm(()=>{this.childrenLoaders.delete(i)})),s=new aw(o,()=>new Ue).pipe(Ym());return this.childrenLoaders.set(i,s),s}loadModuleFactoryOrRoutes(t){return vo(t()).pipe(dt(i=>i instanceof KD||Array.isArray(i)?Z(i):gt(this.compiler.compileModuleAsync(i))))}}return e.\u0275fac=function(t){return new(t||e)(L(gn),L(lm))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(); + */let b_=(()=>{class e{constructor(t,i){this.injector=t,this.compiler=i,this.componentLoaders=new WeakMap,this.childrenLoaders=new WeakMap}loadComponent(t){if(this.componentLoaders.get(t))return this.componentLoaders.get(t);if(t._loadedComponent)return J(t._loadedComponent);this.onLoadStartListener&&this.onLoadStartListener(t);const i=vo(t.loadComponent()).pipe(Kt(o=>{this.onLoadEndListener&&this.onLoadEndListener(t),t._loadedComponent=o}),Zm(()=>{this.componentLoaders.delete(t)})),r=new aw(i,()=>new Ue).pipe(Km());return this.componentLoaders.set(t,r),r}loadChildren(t,i){if(this.childrenLoaders.get(i))return this.childrenLoaders.get(i);if(i._loadedRoutes)return J({routes:i._loadedRoutes,injector:i._loadedInjector});this.onLoadStartListener&&this.onLoadStartListener(i);const o=this.loadModuleFactoryOrRoutes(i.loadChildren).pipe(ne(a=>{this.onLoadEndListener&&this.onLoadEndListener(i);let l,u,f=!1;Array.isArray(a)?u=a:(l=a.create(t).injector,u=hw(l.get(y_,[],X.Self|X.Optional)));return{routes:u.map(p_),injector:l}}),Zm(()=>{this.childrenLoaders.delete(i)})),s=new aw(o,()=>new Ue).pipe(Km());return this.childrenLoaders.set(i,s),s}loadModuleFactoryOrRoutes(t){return vo(t()).pipe(dt(i=>i instanceof zD||Array.isArray(i)?J(i):gt(this.compiler.compileModuleAsync(i))))}}return e.\u0275fac=function(t){return new(t||e)(L(gn),L(lm))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(); /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */class Y2{}class q2{shouldProcessUrl(n){return!0}extract(n){return n}merge(n,t){return n}} + */class K2{}class q2{shouldProcessUrl(n){return!0}extract(n){return n}merge(n,t){return n}} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */function J2(e){throw e}function Z2(e,n,t){return n.parse("/")}const Q2={paths:"exact",fragment:"ignored",matrixParams:"ignored",queryParams:"exact"},X2={paths:"subset",fragment:"ignored",matrixParams:"ignored",queryParams:"subset"};function aS(){const e=St(bw),n=St(Ac),t=St(Sm),i=St(gn),r=St(lm),o=St(y_,{optional:!0})??[],s=St(vf,{optional:!0})??{},a=St(oS),l=St(rS,{optional:!0}),u=St(Y2,{optional:!0}),f=St(G2,{optional:!0}),p=new ln(null,e,n,t,i,r,hw(o));return u&&(p.urlHandlingStrategy=u),f&&(p.routeReuseStrategy=f),p.titleStrategy=l??a,function eV(e,n){e.errorHandler&&(n.errorHandler=e.errorHandler),e.malformedUriErrorHandler&&(n.malformedUriErrorHandler=e.malformedUriErrorHandler),e.onSameUrlNavigation&&(n.onSameUrlNavigation=e.onSameUrlNavigation),e.paramsInheritanceStrategy&&(n.paramsInheritanceStrategy=e.paramsInheritanceStrategy),e.relativeLinkResolution&&(n.relativeLinkResolution=e.relativeLinkResolution),e.urlUpdateStrategy&&(n.urlUpdateStrategy=e.urlUpdateStrategy),e.canceledNavigationResolution&&(n.canceledNavigationResolution=e.canceledNavigationResolution)}(s,p),p}let ln=(()=>{class e{constructor(t,i,r,o,s,a,l){this.rootComponentType=t,this.urlSerializer=i,this.rootContexts=r,this.location=o,this.config=l,this.lastSuccessfulNavigation=null,this.currentNavigation=null,this.disposed=!1,this.navigationId=0,this.currentPageId=0,this.isNgZoneEnabled=!1,this.events=new Ue,this.errorHandler=J2,this.malformedUriErrorHandler=Z2,this.navigated=!1,this.lastSuccessfulId=-1,this.afterPreactivation=()=>Z(void 0),this.urlHandlingStrategy=new q2,this.routeReuseStrategy=new K2,this.onSameUrlNavigation="ignore",this.paramsInheritanceStrategy="emptyOnly",this.urlUpdateStrategy="deferred",this.relativeLinkResolution="corrected",this.canceledNavigationResolution="replace",this.configLoader=s.get(b_),this.configLoader.onLoadEndListener=m=>this.triggerEvent(new xL(m)),this.configLoader.onLoadStartListener=m=>this.triggerEvent(new RL(m)),this.ngModule=s.get(Xo),this.console=s.get(BR);const p=s.get(ze);this.isNgZoneEnabled=p instanceof ze&&ze.isInAngularZone(),this.resetConfig(l),this.currentUrlTree=function iL(){return new is(new me([],{}),{},null)}(),this.rawUrlTree=this.currentUrlTree,this.browserUrlTree=this.currentUrlTree,this.routerState=xw(this.currentUrlTree,this.rootComponentType),this.transitions=new zt({id:0,targetPageId:0,currentUrlTree:this.currentUrlTree,currentRawUrl:this.currentUrlTree,extractedUrl:this.urlHandlingStrategy.extract(this.currentUrlTree),urlAfterRedirects:this.urlHandlingStrategy.extract(this.currentUrlTree),rawUrl:this.currentUrlTree,extras:{},resolve:null,reject:null,promise:Promise.resolve(!0),source:"imperative",restoredState:null,currentSnapshot:this.routerState.snapshot,targetSnapshot:null,currentRouterState:this.routerState,targetRouterState:null,guards:{canActivateChecks:[],canDeactivateChecks:[]},guardsResult:null}),this.navigations=this.setupNavigations(this.transitions),this.processNavigations()}get browserPageId(){return this.location.getState()?.\u0275routerPageId}setupNavigations(t){const i=this.events;return t.pipe(vn(r=>0!==r.id),ne(r=>({...r,extractedUrl:this.urlHandlingStrategy.extract(r.rawUrl)})),vi(r=>{let o=!1,s=!1;return Z(r).pipe(Yt(a=>{this.currentNavigation={id:a.id,initialUrl:a.rawUrl,extractedUrl:a.extractedUrl,trigger:a.source,extras:a.extras,previousNavigation:this.lastSuccessfulNavigation?{...this.lastSuccessfulNavigation,previousNavigation:null}:null}}),vi(a=>{const l=this.browserUrlTree.toString(),u=!this.navigated||a.extractedUrl.toString()!==l||l!==this.currentUrlTree.toString();if(("reload"===this.onSameUrlNavigation||u)&&this.urlHandlingStrategy.shouldProcessUrl(a.rawUrl))return lS(a.source)&&(this.browserUrlTree=a.extractedUrl),Z(a).pipe(vi(p=>{const m=this.transitions.getValue();return i.next(new r_(p.id,this.serializeUrl(p.extractedUrl),p.source,p.restoredState)),m!==this.transitions.getValue()?Xt:Promise.resolve(p)}),function A2(e,n,t,i){return vi(r=>function N2(e,n,t,i,r){return new T2(e,n,t,i,r).apply()}(e,n,t,r.extractedUrl,i).pipe(ne(o=>({...r,urlAfterRedirects:o}))))} + */function Z2(e){throw e}function J2(e,n,t){return n.parse("/")}const Q2={paths:"exact",fragment:"ignored",matrixParams:"ignored",queryParams:"exact"},X2={paths:"subset",fragment:"ignored",matrixParams:"ignored",queryParams:"subset"};function aS(){const e=St(bw),n=St(Ic),t=St(Sm),i=St(gn),r=St(lm),o=St(y_,{optional:!0})??[],s=St(vf,{optional:!0})??{},a=St(oS),l=St(rS,{optional:!0}),u=St(K2,{optional:!0}),f=St(G2,{optional:!0}),p=new ln(null,e,n,t,i,r,hw(o));return u&&(p.urlHandlingStrategy=u),f&&(p.routeReuseStrategy=f),p.titleStrategy=l??a,function eV(e,n){e.errorHandler&&(n.errorHandler=e.errorHandler),e.malformedUriErrorHandler&&(n.malformedUriErrorHandler=e.malformedUriErrorHandler),e.onSameUrlNavigation&&(n.onSameUrlNavigation=e.onSameUrlNavigation),e.paramsInheritanceStrategy&&(n.paramsInheritanceStrategy=e.paramsInheritanceStrategy),e.relativeLinkResolution&&(n.relativeLinkResolution=e.relativeLinkResolution),e.urlUpdateStrategy&&(n.urlUpdateStrategy=e.urlUpdateStrategy),e.canceledNavigationResolution&&(n.canceledNavigationResolution=e.canceledNavigationResolution)}(s,p),p}let ln=(()=>{class e{constructor(t,i,r,o,s,a,l){this.rootComponentType=t,this.urlSerializer=i,this.rootContexts=r,this.location=o,this.config=l,this.lastSuccessfulNavigation=null,this.currentNavigation=null,this.disposed=!1,this.navigationId=0,this.currentPageId=0,this.isNgZoneEnabled=!1,this.events=new Ue,this.errorHandler=Z2,this.malformedUriErrorHandler=J2,this.navigated=!1,this.lastSuccessfulId=-1,this.afterPreactivation=()=>J(void 0),this.urlHandlingStrategy=new q2,this.routeReuseStrategy=new z2,this.onSameUrlNavigation="ignore",this.paramsInheritanceStrategy="emptyOnly",this.urlUpdateStrategy="deferred",this.relativeLinkResolution="corrected",this.canceledNavigationResolution="replace",this.configLoader=s.get(b_),this.configLoader.onLoadEndListener=m=>this.triggerEvent(new RL(m)),this.configLoader.onLoadStartListener=m=>this.triggerEvent(new xL(m)),this.ngModule=s.get(Xo),this.console=s.get(Hx);const p=s.get(Ye);this.isNgZoneEnabled=p instanceof Ye&&Ye.isInAngularZone(),this.resetConfig(l),this.currentUrlTree=function iL(){return new is(new me([],{}),{},null)}(),this.rawUrlTree=this.currentUrlTree,this.browserUrlTree=this.currentUrlTree,this.routerState=Rw(this.currentUrlTree,this.rootComponentType),this.transitions=new Yt({id:0,targetPageId:0,currentUrlTree:this.currentUrlTree,currentRawUrl:this.currentUrlTree,extractedUrl:this.urlHandlingStrategy.extract(this.currentUrlTree),urlAfterRedirects:this.urlHandlingStrategy.extract(this.currentUrlTree),rawUrl:this.currentUrlTree,extras:{},resolve:null,reject:null,promise:Promise.resolve(!0),source:"imperative",restoredState:null,currentSnapshot:this.routerState.snapshot,targetSnapshot:null,currentRouterState:this.routerState,targetRouterState:null,guards:{canActivateChecks:[],canDeactivateChecks:[]},guardsResult:null}),this.navigations=this.setupNavigations(this.transitions),this.processNavigations()}get browserPageId(){return this.location.getState()?.\u0275routerPageId}setupNavigations(t){const i=this.events;return t.pipe(vn(r=>0!==r.id),ne(r=>({...r,extractedUrl:this.urlHandlingStrategy.extract(r.rawUrl)})),vi(r=>{let o=!1,s=!1;return J(r).pipe(Kt(a=>{this.currentNavigation={id:a.id,initialUrl:a.rawUrl,extractedUrl:a.extractedUrl,trigger:a.source,extras:a.extras,previousNavigation:this.lastSuccessfulNavigation?{...this.lastSuccessfulNavigation,previousNavigation:null}:null}}),vi(a=>{const l=this.browserUrlTree.toString(),u=!this.navigated||a.extractedUrl.toString()!==l||l!==this.currentUrlTree.toString();if(("reload"===this.onSameUrlNavigation||u)&&this.urlHandlingStrategy.shouldProcessUrl(a.rawUrl))return lS(a.source)&&(this.browserUrlTree=a.extractedUrl),J(a).pipe(vi(p=>{const m=this.transitions.getValue();return i.next(new r_(p.id,this.serializeUrl(p.extractedUrl),p.source,p.restoredState)),m!==this.transitions.getValue()?Xt:Promise.resolve(p)}),function I2(e,n,t,i){return vi(r=>function E2(e,n,t,i,r){return new T2(e,n,t,i,r).apply()}(e,n,t,r.extractedUrl,i).pipe(ne(o=>({...r,urlAfterRedirects:o}))))} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */(this.ngModule.injector,this.configLoader,this.urlSerializer,this.config),Yt(p=>{this.currentNavigation={...this.currentNavigation,finalUrl:p.urlAfterRedirects},r.urlAfterRedirects=p.urlAfterRedirects}),function V2(e,n,t,i,r,o){return dt(s=>function k2(e,n,t,i,r,o,s="emptyOnly",a="legacy"){return new R2(e,n,t,i,r,s,a,o).recognize().pipe(vi(l=>null===l?function O2(e){return new je(n=>n.error(e))}(new I2):Z(l)))}(e,n,t,s.urlAfterRedirects,i.serialize(s.urlAfterRedirects),i,r,o).pipe(ne(a=>({...s,targetSnapshot:a}))))}(this.ngModule.injector,this.rootComponentType,this.config,this.urlSerializer,this.paramsInheritanceStrategy,this.relativeLinkResolution),Yt(p=>{if(r.targetSnapshot=p.targetSnapshot,"eager"===this.urlUpdateStrategy){if(!p.extras.skipLocationChange){const v=this.urlHandlingStrategy.merge(p.urlAfterRedirects,p.rawUrl);this.setBrowserUrl(v,p)}this.browserUrlTree=p.urlAfterRedirects}const m=new TL(p.id,this.serializeUrl(p.extractedUrl),this.serializeUrl(p.urlAfterRedirects),p.targetSnapshot);i.next(m)}));if(u&&this.rawUrlTree&&this.urlHandlingStrategy.shouldProcessUrl(this.rawUrlTree)){const{id:m,extractedUrl:v,source:y,restoredState:D,extras:w}=a,M=new r_(m,this.serializeUrl(v),y,D);i.next(M);const I=xw(v,this.rootComponentType).snapshot;return Z(r={...a,targetSnapshot:I,urlAfterRedirects:v,extras:{...w,skipLocationChange:!1,replaceUrl:!1}})}return this.rawUrlTree=a.rawUrl,a.resolve(null),Xt}),Yt(a=>{const l=new AL(a.id,this.serializeUrl(a.extractedUrl),this.serializeUrl(a.urlAfterRedirects),a.targetSnapshot);this.triggerEvent(l)}),ne(a=>r={...a,guards:XL(a.targetSnapshot,a.currentSnapshot,this.rootContexts)}),function d2(e,n){return dt(t=>{const{targetSnapshot:i,currentSnapshot:r,guards:{canActivateChecks:o,canDeactivateChecks:s}}=t;return 0===s.length&&0===o.length?Z({...t,guardsResult:!0}):function f2(e,n,t,i){return gt(e).pipe(dt(r=>function v2(e,n,t,i,r){const o=n&&n.routeConfig?n.routeConfig.canDeactivate:null;return o&&0!==o.length?Z(o.map(a=>{const l=Ic(n)??r,u=Va(a,l);return vo(function l2(e){return e&&Rc(e.canDeactivate)}(u)?u.canDeactivate(e,n,t,i):l.runInContext(()=>u(e,n,t,i))).pipe(mo())})).pipe(Ha()):Z(!0)}(r.component,r.route,t,n,i)),mo(r=>!0!==r,!0))}(s,i,r,e).pipe(dt(a=>a&&function r2(e){return"boolean"==typeof e}(a)?function h2(e,n,t,i){return gt(n).pipe(_o(r=>Dc(function g2(e,n){return null!==e&&n&&n(new FL(e)),Z(!0)}(r.route.parent,i),function p2(e,n){return null!==e&&n&&n(new LL(e)),Z(!0)}(r.route,i),function _2(e,n,t){const i=n[n.length-1],o=n.slice(0,n.length-1).reverse().map(s=>function e2(e){const n=e.routeConfig?e.routeConfig.canActivateChild:null;return n&&0!==n.length?{node:e,guards:n}:null}(s)).filter(s=>null!==s).map(s=>sw(()=>Z(s.guards.map(l=>{const u=Ic(s.node)??t,f=Va(l,u);return vo(function a2(e){return e&&Rc(e.canActivateChild)}(f)?f.canActivateChild(i,e):u.runInContext(()=>f(i,e))).pipe(mo())})).pipe(Ha())));return Z(o).pipe(Ha())}(e,r.path,t),function m2(e,n,t){const i=n.routeConfig?n.routeConfig.canActivate:null;if(!i||0===i.length)return Z(!0);const r=i.map(o=>sw(()=>{const s=Ic(n)??t,a=Va(o,s);return vo(function s2(e){return e&&Rc(e.canActivate)}(a)?a.canActivate(n,e):s.runInContext(()=>a(n,e))).pipe(mo())}));return Z(r).pipe(Ha())}(e,r.route,t))),mo(r=>!0!==r,!0))}(i,o,e,n):Z(a)),ne(a=>({...t,guardsResult:a})))})}(this.ngModule.injector,a=>this.triggerEvent(a)),Yt(a=>{if(r.guardsResult=a.guardsResult,os(a.guardsResult))throw Vw(0,a.guardsResult);const l=new IL(a.id,this.serializeUrl(a.extractedUrl),this.serializeUrl(a.urlAfterRedirects),a.targetSnapshot,!!a.guardsResult);this.triggerEvent(l)}),vn(a=>!!a.guardsResult||(this.restoreHistory(a),this.cancelNavigationTransition(a,"",3),!1)),v_(a=>{if(a.guards.canActivateChecks.length)return Z(a).pipe(Yt(l=>{const u=new OL(l.id,this.serializeUrl(l.extractedUrl),this.serializeUrl(l.urlAfterRedirects),l.targetSnapshot);this.triggerEvent(u)}),vi(l=>{let u=!1;return Z(l).pipe(H2(this.paramsInheritanceStrategy,this.ngModule.injector),Yt({next:()=>u=!0,complete:()=>{u||(this.restoreHistory(l),this.cancelNavigationTransition(l,"",2))}}))}),Yt(l=>{const u=new kL(l.id,this.serializeUrl(l.extractedUrl),this.serializeUrl(l.urlAfterRedirects),l.targetSnapshot);this.triggerEvent(u)}))}),v_(a=>{const l=u=>{const f=[];u.routeConfig?.loadComponent&&!u.routeConfig._loadedComponent&&f.push(this.configLoader.loadComponent(u.routeConfig).pipe(Yt(p=>{u.component=p}),ne(()=>{})));for(const p of u.children)f.push(...l(p));return f};return Zd(l(a.targetSnapshot.root)).pipe(Xd(),sn(1))}),v_(()=>this.afterPreactivation()),ne(a=>{const l=function $L(e,n,t){const i=Tc(e,n._root,t?t._root:void 0);return new Rw(i,n)}(this.routeReuseStrategy,a.targetSnapshot,a.currentRouterState);return r={...a,targetRouterState:l}}),Yt(a=>{this.currentUrlTree=a.urlAfterRedirects,this.rawUrlTree=this.urlHandlingStrategy.merge(a.urlAfterRedirects,a.rawUrl),this.routerState=a.targetRouterState,"deferred"===this.urlUpdateStrategy&&(a.extras.skipLocationChange||this.setBrowserUrl(this.rawUrlTree,a),this.browserUrlTree=a.urlAfterRedirects)}),((e,n,t)=>ne(i=>(new QL(n,i.targetRouterState,i.currentRouterState,t).activate(e),i)))(this.rootContexts,this.routeReuseStrategy,a=>this.triggerEvent(a)),Yt({next(){o=!0},complete(){o=!0}}),Jm(()=>{o||s||this.cancelNavigationTransition(r,"",1),this.currentNavigation?.id===r.id&&(this.currentNavigation=null)}),$r(a=>{if(s=!0,jw(a)){Bw(a)||(this.navigated=!0,this.restoreHistory(r,!0));const l=new lf(r.id,this.serializeUrl(r.extractedUrl),a.message,a.cancellationCode);if(i.next(l),Bw(a)){const u=this.urlHandlingStrategy.merge(a.url,this.rawUrlTree),f={skipLocationChange:r.extras.skipLocationChange,replaceUrl:"eager"===this.urlUpdateStrategy||lS(r.source)};this.scheduleNavigation(u,"imperative",null,f,{resolve:r.resolve,reject:r.reject,promise:r.promise})}else r.resolve(!1)}else{this.restoreHistory(r,!0);const l=new Iw(r.id,this.serializeUrl(r.extractedUrl),a,r.targetSnapshot??void 0);i.next(l);try{r.resolve(this.errorHandler(a))}catch(u){r.reject(u)}}return Xt}))}))}resetRootComponentType(t){this.rootComponentType=t,this.routerState.root.component=this.rootComponentType}setTransition(t){this.transitions.next({...this.transitions.value,...t})}initialNavigation(){this.setUpLocationChangeListener(),0===this.navigationId&&this.navigateByUrl(this.location.path(!0),{replaceUrl:!0})}setUpLocationChangeListener(){this.locationSubscription||(this.locationSubscription=this.location.subscribe(t=>{const i="popstate"===t.type?"popstate":"hashchange";"popstate"===i&&setTimeout(()=>{const r={replaceUrl:!0},o=t.state?.navigationId?t.state:null;if(o){const a={...o};delete a.navigationId,delete a.\u0275routerPageId,0!==Object.keys(a).length&&(r.state=a)}const s=this.parseUrl(t.url);this.scheduleNavigation(s,i,o,r)},0)}))}get url(){return this.serializeUrl(this.currentUrlTree)}getCurrentNavigation(){return this.currentNavigation}triggerEvent(t){this.events.next(t)}resetConfig(t){this.config=t.map(p_),this.navigated=!1,this.lastSuccessfulId=-1}ngOnDestroy(){this.dispose()}dispose(){this.transitions.complete(),this.locationSubscription&&(this.locationSubscription.unsubscribe(),this.locationSubscription=void 0),this.disposed=!0}createUrlTree(t,i={}){const{relativeTo:r,queryParams:o,fragment:s,queryParamsHandling:a,preserveFragment:l}=i,u=r||this.routerState.root,f=l?this.currentUrlTree.fragment:s;let p=null;switch(a){case"merge":p={...this.currentUrlTree.queryParams,...o};break;case"preserve":p=this.currentUrlTree.queryParams;break;default:p=o||null}return null!==p&&(p=this.removeEmptyProps(p)),CL(u,this.currentUrlTree,t,p,f??null)}navigateByUrl(t,i={skipLocationChange:!1}){const r=os(t)?t:this.parseUrl(t),o=this.urlHandlingStrategy.merge(r,this.rawUrlTree);return this.scheduleNavigation(o,"imperative",null,i)}navigate(t,i={skipLocationChange:!1}){return function tV(e){for(let n=0;n{const o=t[r];return null!=o&&(i[r]=o),i},{})}processNavigations(){this.navigations.subscribe(t=>{this.navigated=!0,this.lastSuccessfulId=t.id,this.currentPageId=t.targetPageId,this.events.next(new ss(t.id,this.serializeUrl(t.extractedUrl),this.serializeUrl(this.currentUrlTree))),this.lastSuccessfulNavigation=this.currentNavigation,this.titleStrategy?.updateTitle(this.routerState.snapshot),t.resolve(!0)},t=>{this.console.warn(`Unhandled Navigation Error: ${t}`)})}scheduleNavigation(t,i,r,o,s){if(this.disposed)return Promise.resolve(!1);let a,l,u;s?(a=s.resolve,l=s.reject,u=s.promise):u=new Promise((m,v)=>{a=m,l=v});const f=++this.navigationId;let p;return"computed"===this.canceledNavigationResolution?(0===this.currentPageId&&(r=this.location.getState()),p=r&&r.\u0275routerPageId?r.\u0275routerPageId:o.replaceUrl||o.skipLocationChange?this.browserPageId??0:(this.browserPageId??0)+1):p=0,this.setTransition({id:f,targetPageId:p,source:i,restoredState:r,currentUrlTree:this.currentUrlTree,currentRawUrl:this.rawUrlTree,rawUrl:t,extras:o,resolve:a,reject:l,promise:u,currentSnapshot:this.routerState.snapshot,currentRouterState:this.routerState}),u.catch(m=>Promise.reject(m))}setBrowserUrl(t,i){const r=this.urlSerializer.serialize(t),o={...i.extras.state,...this.generateNgRouterState(i.id,i.targetPageId)};this.location.isCurrentPathEqualTo(r)||i.extras.replaceUrl?this.location.replaceState(r,"",o):this.location.go(r,"",o)}restoreHistory(t,i=!1){if("computed"===this.canceledNavigationResolution){const r=this.currentPageId-t.targetPageId;"popstate"!==t.source&&"eager"!==this.urlUpdateStrategy&&this.currentUrlTree!==this.currentNavigation?.finalUrl||0===r?this.currentUrlTree===this.currentNavigation?.finalUrl&&0===r&&(this.resetState(t),this.browserUrlTree=t.currentUrlTree,this.resetUrlToCurrentUrlTree()):this.location.historyGo(r)}else"replace"===this.canceledNavigationResolution&&(i&&this.resetState(t),this.resetUrlToCurrentUrlTree())}resetState(t){this.routerState=t.currentRouterState,this.currentUrlTree=t.currentUrlTree,this.rawUrlTree=this.urlHandlingStrategy.merge(this.currentUrlTree,t.rawUrl)}resetUrlToCurrentUrlTree(){this.location.replaceState(this.urlSerializer.serialize(this.rawUrlTree),"",this.generateNgRouterState(this.lastSuccessfulId,this.currentPageId))}cancelNavigationTransition(t,i,r){const o=new lf(t.id,this.serializeUrl(t.extractedUrl),i,r);this.triggerEvent(o),t.resolve(!1)}generateNgRouterState(t,i){return"computed"===this.canceledNavigationResolution?{navigationId:t,\u0275routerPageId:i}:{navigationId:t}}}return e.\u0275fac=function(t){sg()},e.\u0275prov=G({token:e,factory:function(){return aS()},providedIn:"root"}),e})();function lS(e){return"imperative"!==e} + */(this.ngModule.injector,this.configLoader,this.urlSerializer,this.config),Kt(p=>{this.currentNavigation={...this.currentNavigation,finalUrl:p.urlAfterRedirects},r.urlAfterRedirects=p.urlAfterRedirects}),function V2(e,n,t,i,r,o){return dt(s=>function O2(e,n,t,i,r,o,s="emptyOnly",a="legacy"){return new x2(e,n,t,i,r,s,a,o).recognize().pipe(vi(l=>null===l?function k2(e){return new je(n=>n.error(e))}(new A2):J(l)))}(e,n,t,s.urlAfterRedirects,i.serialize(s.urlAfterRedirects),i,r,o).pipe(ne(a=>({...s,targetSnapshot:a}))))}(this.ngModule.injector,this.rootComponentType,this.config,this.urlSerializer,this.paramsInheritanceStrategy,this.relativeLinkResolution),Kt(p=>{if(r.targetSnapshot=p.targetSnapshot,"eager"===this.urlUpdateStrategy){if(!p.extras.skipLocationChange){const v=this.urlHandlingStrategy.merge(p.urlAfterRedirects,p.rawUrl);this.setBrowserUrl(v,p)}this.browserUrlTree=p.urlAfterRedirects}const m=new TL(p.id,this.serializeUrl(p.extractedUrl),this.serializeUrl(p.urlAfterRedirects),p.targetSnapshot);i.next(m)}));if(u&&this.rawUrlTree&&this.urlHandlingStrategy.shouldProcessUrl(this.rawUrlTree)){const{id:m,extractedUrl:v,source:y,restoredState:D,extras:w}=a,N=new r_(m,this.serializeUrl(v),y,D);i.next(N);const A=Rw(v,this.rootComponentType).snapshot;return J(r={...a,targetSnapshot:A,urlAfterRedirects:v,extras:{...w,skipLocationChange:!1,replaceUrl:!1}})}return this.rawUrlTree=a.rawUrl,a.resolve(null),Xt}),Kt(a=>{const l=new IL(a.id,this.serializeUrl(a.extractedUrl),this.serializeUrl(a.urlAfterRedirects),a.targetSnapshot);this.triggerEvent(l)}),ne(a=>r={...a,guards:XL(a.targetSnapshot,a.currentSnapshot,this.rootContexts)}),function d2(e,n){return dt(t=>{const{targetSnapshot:i,currentSnapshot:r,guards:{canActivateChecks:o,canDeactivateChecks:s}}=t;return 0===s.length&&0===o.length?J({...t,guardsResult:!0}):function f2(e,n,t,i){return gt(e).pipe(dt(r=>function v2(e,n,t,i,r){const o=n&&n.routeConfig?n.routeConfig.canDeactivate:null;return o&&0!==o.length?J(o.map(a=>{const l=Ac(n)??r,u=Va(a,l);return vo(function l2(e){return e&&xc(e.canDeactivate)}(u)?u.canDeactivate(e,n,t,i):l.runInContext(()=>u(e,n,t,i))).pipe(mo())})).pipe(Ba()):J(!0)}(r.component,r.route,t,n,i)),mo(r=>!0!==r,!0))}(s,i,r,e).pipe(dt(a=>a&&function r2(e){return"boolean"==typeof e}(a)?function h2(e,n,t,i){return gt(n).pipe(_o(r=>Dc(function g2(e,n){return null!==e&&n&&n(new PL(e)),J(!0)}(r.route.parent,i),function p2(e,n){return null!==e&&n&&n(new LL(e)),J(!0)}(r.route,i),function _2(e,n,t){const i=n[n.length-1],o=n.slice(0,n.length-1).reverse().map(s=>function e2(e){const n=e.routeConfig?e.routeConfig.canActivateChild:null;return n&&0!==n.length?{node:e,guards:n}:null}(s)).filter(s=>null!==s).map(s=>sw(()=>J(s.guards.map(l=>{const u=Ac(s.node)??t,f=Va(l,u);return vo(function a2(e){return e&&xc(e.canActivateChild)}(f)?f.canActivateChild(i,e):u.runInContext(()=>f(i,e))).pipe(mo())})).pipe(Ba())));return J(o).pipe(Ba())}(e,r.path,t),function m2(e,n,t){const i=n.routeConfig?n.routeConfig.canActivate:null;if(!i||0===i.length)return J(!0);const r=i.map(o=>sw(()=>{const s=Ac(n)??t,a=Va(o,s);return vo(function s2(e){return e&&xc(e.canActivate)}(a)?a.canActivate(n,e):s.runInContext(()=>a(n,e))).pipe(mo())}));return J(r).pipe(Ba())}(e,r.route,t))),mo(r=>!0!==r,!0))}(i,o,e,n):J(a)),ne(a=>({...t,guardsResult:a})))})}(this.ngModule.injector,a=>this.triggerEvent(a)),Kt(a=>{if(r.guardsResult=a.guardsResult,os(a.guardsResult))throw Vw(0,a.guardsResult);const l=new AL(a.id,this.serializeUrl(a.extractedUrl),this.serializeUrl(a.urlAfterRedirects),a.targetSnapshot,!!a.guardsResult);this.triggerEvent(l)}),vn(a=>!!a.guardsResult||(this.restoreHistory(a),this.cancelNavigationTransition(a,"",3),!1)),v_(a=>{if(a.guards.canActivateChecks.length)return J(a).pipe(Kt(l=>{const u=new kL(l.id,this.serializeUrl(l.extractedUrl),this.serializeUrl(l.urlAfterRedirects),l.targetSnapshot);this.triggerEvent(u)}),vi(l=>{let u=!1;return J(l).pipe(B2(this.paramsInheritanceStrategy,this.ngModule.injector),Kt({next:()=>u=!0,complete:()=>{u||(this.restoreHistory(l),this.cancelNavigationTransition(l,"",2))}}))}),Kt(l=>{const u=new OL(l.id,this.serializeUrl(l.extractedUrl),this.serializeUrl(l.urlAfterRedirects),l.targetSnapshot);this.triggerEvent(u)}))}),v_(a=>{const l=u=>{const f=[];u.routeConfig?.loadComponent&&!u.routeConfig._loadedComponent&&f.push(this.configLoader.loadComponent(u.routeConfig).pipe(Kt(p=>{u.component=p}),ne(()=>{})));for(const p of u.children)f.push(...l(p));return f};return Jd(l(a.targetSnapshot.root)).pipe(Xd(),sn(1))}),v_(()=>this.afterPreactivation()),ne(a=>{const l=function $L(e,n,t){const i=Tc(e,n._root,t?t._root:void 0);return new xw(i,n)}(this.routeReuseStrategy,a.targetSnapshot,a.currentRouterState);return r={...a,targetRouterState:l}}),Kt(a=>{this.currentUrlTree=a.urlAfterRedirects,this.rawUrlTree=this.urlHandlingStrategy.merge(a.urlAfterRedirects,a.rawUrl),this.routerState=a.targetRouterState,"deferred"===this.urlUpdateStrategy&&(a.extras.skipLocationChange||this.setBrowserUrl(this.rawUrlTree,a),this.browserUrlTree=a.urlAfterRedirects)}),((e,n,t)=>ne(i=>(new QL(n,i.targetRouterState,i.currentRouterState,t).activate(e),i)))(this.rootContexts,this.routeReuseStrategy,a=>this.triggerEvent(a)),Kt({next(){o=!0},complete(){o=!0}}),Zm(()=>{o||s||this.cancelNavigationTransition(r,"",1),this.currentNavigation?.id===r.id&&(this.currentNavigation=null)}),$r(a=>{if(s=!0,jw(a)){Hw(a)||(this.navigated=!0,this.restoreHistory(r,!0));const l=new lf(r.id,this.serializeUrl(r.extractedUrl),a.message,a.cancellationCode);if(i.next(l),Hw(a)){const u=this.urlHandlingStrategy.merge(a.url,this.rawUrlTree),f={skipLocationChange:r.extras.skipLocationChange,replaceUrl:"eager"===this.urlUpdateStrategy||lS(r.source)};this.scheduleNavigation(u,"imperative",null,f,{resolve:r.resolve,reject:r.reject,promise:r.promise})}else r.resolve(!1)}else{this.restoreHistory(r,!0);const l=new Aw(r.id,this.serializeUrl(r.extractedUrl),a,r.targetSnapshot??void 0);i.next(l);try{r.resolve(this.errorHandler(a))}catch(u){r.reject(u)}}return Xt}))}))}resetRootComponentType(t){this.rootComponentType=t,this.routerState.root.component=this.rootComponentType}setTransition(t){this.transitions.next({...this.transitions.value,...t})}initialNavigation(){this.setUpLocationChangeListener(),0===this.navigationId&&this.navigateByUrl(this.location.path(!0),{replaceUrl:!0})}setUpLocationChangeListener(){this.locationSubscription||(this.locationSubscription=this.location.subscribe(t=>{const i="popstate"===t.type?"popstate":"hashchange";"popstate"===i&&setTimeout(()=>{const r={replaceUrl:!0},o=t.state?.navigationId?t.state:null;if(o){const a={...o};delete a.navigationId,delete a.\u0275routerPageId,0!==Object.keys(a).length&&(r.state=a)}const s=this.parseUrl(t.url);this.scheduleNavigation(s,i,o,r)},0)}))}get url(){return this.serializeUrl(this.currentUrlTree)}getCurrentNavigation(){return this.currentNavigation}triggerEvent(t){this.events.next(t)}resetConfig(t){this.config=t.map(p_),this.navigated=!1,this.lastSuccessfulId=-1}ngOnDestroy(){this.dispose()}dispose(){this.transitions.complete(),this.locationSubscription&&(this.locationSubscription.unsubscribe(),this.locationSubscription=void 0),this.disposed=!0}createUrlTree(t,i={}){const{relativeTo:r,queryParams:o,fragment:s,queryParamsHandling:a,preserveFragment:l}=i,u=r||this.routerState.root,f=l?this.currentUrlTree.fragment:s;let p=null;switch(a){case"merge":p={...this.currentUrlTree.queryParams,...o};break;case"preserve":p=this.currentUrlTree.queryParams;break;default:p=o||null}return null!==p&&(p=this.removeEmptyProps(p)),CL(u,this.currentUrlTree,t,p,f??null)}navigateByUrl(t,i={skipLocationChange:!1}){const r=os(t)?t:this.parseUrl(t),o=this.urlHandlingStrategy.merge(r,this.rawUrlTree);return this.scheduleNavigation(o,"imperative",null,i)}navigate(t,i={skipLocationChange:!1}){return function tV(e){for(let n=0;n{const o=t[r];return null!=o&&(i[r]=o),i},{})}processNavigations(){this.navigations.subscribe(t=>{this.navigated=!0,this.lastSuccessfulId=t.id,this.currentPageId=t.targetPageId,this.events.next(new ss(t.id,this.serializeUrl(t.extractedUrl),this.serializeUrl(this.currentUrlTree))),this.lastSuccessfulNavigation=this.currentNavigation,this.titleStrategy?.updateTitle(this.routerState.snapshot),t.resolve(!0)},t=>{this.console.warn(`Unhandled Navigation Error: ${t}`)})}scheduleNavigation(t,i,r,o,s){if(this.disposed)return Promise.resolve(!1);let a,l,u;s?(a=s.resolve,l=s.reject,u=s.promise):u=new Promise((m,v)=>{a=m,l=v});const f=++this.navigationId;let p;return"computed"===this.canceledNavigationResolution?(0===this.currentPageId&&(r=this.location.getState()),p=r&&r.\u0275routerPageId?r.\u0275routerPageId:o.replaceUrl||o.skipLocationChange?this.browserPageId??0:(this.browserPageId??0)+1):p=0,this.setTransition({id:f,targetPageId:p,source:i,restoredState:r,currentUrlTree:this.currentUrlTree,currentRawUrl:this.rawUrlTree,rawUrl:t,extras:o,resolve:a,reject:l,promise:u,currentSnapshot:this.routerState.snapshot,currentRouterState:this.routerState}),u.catch(m=>Promise.reject(m))}setBrowserUrl(t,i){const r=this.urlSerializer.serialize(t),o={...i.extras.state,...this.generateNgRouterState(i.id,i.targetPageId)};this.location.isCurrentPathEqualTo(r)||i.extras.replaceUrl?this.location.replaceState(r,"",o):this.location.go(r,"",o)}restoreHistory(t,i=!1){if("computed"===this.canceledNavigationResolution){const r=this.currentPageId-t.targetPageId;"popstate"!==t.source&&"eager"!==this.urlUpdateStrategy&&this.currentUrlTree!==this.currentNavigation?.finalUrl||0===r?this.currentUrlTree===this.currentNavigation?.finalUrl&&0===r&&(this.resetState(t),this.browserUrlTree=t.currentUrlTree,this.resetUrlToCurrentUrlTree()):this.location.historyGo(r)}else"replace"===this.canceledNavigationResolution&&(i&&this.resetState(t),this.resetUrlToCurrentUrlTree())}resetState(t){this.routerState=t.currentRouterState,this.currentUrlTree=t.currentUrlTree,this.rawUrlTree=this.urlHandlingStrategy.merge(this.currentUrlTree,t.rawUrl)}resetUrlToCurrentUrlTree(){this.location.replaceState(this.urlSerializer.serialize(this.rawUrlTree),"",this.generateNgRouterState(this.lastSuccessfulId,this.currentPageId))}cancelNavigationTransition(t,i,r){const o=new lf(t.id,this.serializeUrl(t.extractedUrl),i,r);this.triggerEvent(o),t.resolve(!1)}generateNgRouterState(t,i){return"computed"===this.canceledNavigationResolution?{navigationId:t,\u0275routerPageId:i}:{navigationId:t}}}return e.\u0275fac=function(t){sg()},e.\u0275prov=G({token:e,factory:function(){return aS()},providedIn:"root"}),e})();function lS(e){return"imperative"!==e} /** * @license * Copyright Google LLC All Rights Reserved. @@ -1690,21 +1690,21 @@ class G2{}class K2 extends class W2{shouldDetach(n){return!1}store(n,t){}shouldA * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -class cS{}let rV=(()=>{class e{constructor(t,i,r,o,s){this.router=t,this.injector=r,this.preloadingStrategy=o,this.loader=s}setUpPreloading(){this.subscription=this.router.events.pipe(vn(t=>t instanceof ss),_o(()=>this.preload())).subscribe(()=>{})}preload(){return this.processRoutes(this.injector,this.router.config)}ngOnDestroy(){this.subscription&&this.subscription.unsubscribe()}processRoutes(t,i){const r=[];for(const o of i){o.providers&&!o._injector&&(o._injector=bd(o.providers,t,`Route: ${o.path}`));const s=o._injector??t,a=o._loadedInjector??s;o.loadChildren&&!o._loadedRoutes&&void 0===o.canLoad||o.loadComponent&&!o._loadedComponent?r.push(this.preloadConfig(s,o)):(o.children||o._loadedRoutes)&&r.push(this.processRoutes(a,o.children??o._loadedRoutes))}return gt(r).pipe(Se())}preloadConfig(t,i){return this.preloadingStrategy.preload(i,()=>{let r;r=i.loadChildren&&void 0===i.canLoad?this.loader.loadChildren(t,i):Z(null);const o=r.pipe(dt(s=>null===s?Z(void 0):(i._loadedRoutes=s.routes,i._loadedInjector=s.injector,this.processRoutes(s.injector??t,s.routes))));return i.loadComponent&&!i._loadedComponent?gt([o,this.loader.loadComponent(i)]).pipe(Se()):o})}}return e.\u0275fac=function(t){return new(t||e)(L(ln),L(lm),L(lo),L(cS),L(b_))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(); +class cS{}let rV=(()=>{class e{constructor(t,i,r,o,s){this.router=t,this.injector=r,this.preloadingStrategy=o,this.loader=s}setUpPreloading(){this.subscription=this.router.events.pipe(vn(t=>t instanceof ss),_o(()=>this.preload())).subscribe(()=>{})}preload(){return this.processRoutes(this.injector,this.router.config)}ngOnDestroy(){this.subscription&&this.subscription.unsubscribe()}processRoutes(t,i){const r=[];for(const o of i){o.providers&&!o._injector&&(o._injector=bd(o.providers,t,`Route: ${o.path}`));const s=o._injector??t,a=o._loadedInjector??s;o.loadChildren&&!o._loadedRoutes&&void 0===o.canLoad||o.loadComponent&&!o._loadedComponent?r.push(this.preloadConfig(s,o)):(o.children||o._loadedRoutes)&&r.push(this.processRoutes(a,o.children??o._loadedRoutes))}return gt(r).pipe(Se())}preloadConfig(t,i){return this.preloadingStrategy.preload(i,()=>{let r;r=i.loadChildren&&void 0===i.canLoad?this.loader.loadChildren(t,i):J(null);const o=r.pipe(dt(s=>null===s?J(void 0):(i._loadedRoutes=s.routes,i._loadedInjector=s.injector,this.processRoutes(s.injector??t,s.routes))));return i.loadComponent&&!i._loadedComponent?gt([o,this.loader.loadComponent(i)]).pipe(Se()):o})}}return e.\u0275fac=function(t){return new(t||e)(L(ln),L(lm),L(lo),L(cS),L(b_))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(); /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */const w_=new q("");let uS=(()=>{class e{constructor(t,i,r={}){this.router=t,this.viewportScroller=i,this.options=r,this.lastId=0,this.lastSource="imperative",this.restoredId=0,this.store={},r.scrollPositionRestoration=r.scrollPositionRestoration||"disabled",r.anchorScrolling=r.anchorScrolling||"disabled"}init(){"disabled"!==this.options.scrollPositionRestoration&&this.viewportScroller.setHistoryScrollRestoration("manual"),this.routerEventsSubscription=this.createScrollEvents(),this.scrollEventsSubscription=this.consumeScrollEvents()}createScrollEvents(){return this.router.events.subscribe(t=>{t instanceof r_?(this.store[this.lastId]=this.viewportScroller.getScrollPosition(),this.lastSource=t.navigationTrigger,this.restoredId=t.restoredState?t.restoredState.navigationId:0):t instanceof ss&&(this.lastId=t.id,this.scheduleScrollEvent(t,this.router.parseUrl(t.urlAfterRedirects).fragment))})}consumeScrollEvents(){return this.router.events.subscribe(t=>{t instanceof Ow&&(t.position?"top"===this.options.scrollPositionRestoration?this.viewportScroller.scrollToPosition([0,0]):"enabled"===this.options.scrollPositionRestoration&&this.viewportScroller.scrollToPosition(t.position):t.anchor&&"enabled"===this.options.anchorScrolling?this.viewportScroller.scrollToAnchor(t.anchor):"disabled"!==this.options.scrollPositionRestoration&&this.viewportScroller.scrollToPosition([0,0]))})}scheduleScrollEvent(t,i){this.router.triggerEvent(new Ow(t,"popstate"===this.lastSource?this.store[this.restoredId]:null,i))}ngOnDestroy(){this.routerEventsSubscription&&this.routerEventsSubscription.unsubscribe(),this.scrollEventsSubscription&&this.scrollEventsSubscription.unsubscribe()}}return e.\u0275fac=function(t){sg()},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(); + */const w_=new q("");let uS=(()=>{class e{constructor(t,i,r={}){this.router=t,this.viewportScroller=i,this.options=r,this.lastId=0,this.lastSource="imperative",this.restoredId=0,this.store={},r.scrollPositionRestoration=r.scrollPositionRestoration||"disabled",r.anchorScrolling=r.anchorScrolling||"disabled"}init(){"disabled"!==this.options.scrollPositionRestoration&&this.viewportScroller.setHistoryScrollRestoration("manual"),this.routerEventsSubscription=this.createScrollEvents(),this.scrollEventsSubscription=this.consumeScrollEvents()}createScrollEvents(){return this.router.events.subscribe(t=>{t instanceof r_?(this.store[this.lastId]=this.viewportScroller.getScrollPosition(),this.lastSource=t.navigationTrigger,this.restoredId=t.restoredState?t.restoredState.navigationId:0):t instanceof ss&&(this.lastId=t.id,this.scheduleScrollEvent(t,this.router.parseUrl(t.urlAfterRedirects).fragment))})}consumeScrollEvents(){return this.router.events.subscribe(t=>{t instanceof kw&&(t.position?"top"===this.options.scrollPositionRestoration?this.viewportScroller.scrollToPosition([0,0]):"enabled"===this.options.scrollPositionRestoration&&this.viewportScroller.scrollToPosition(t.position):t.anchor&&"enabled"===this.options.anchorScrolling?this.viewportScroller.scrollToAnchor(t.anchor):"disabled"!==this.options.scrollPositionRestoration&&this.viewportScroller.scrollToPosition([0,0]))})}scheduleScrollEvent(t,i){this.router.triggerEvent(new kw(t,"popstate"===this.lastSource?this.store[this.restoredId]:null,i))}ngOnDestroy(){this.routerEventsSubscription&&this.routerEventsSubscription.unsubscribe(),this.scrollEventsSubscription&&this.scrollEventsSubscription.unsubscribe()}}return e.\u0275fac=function(t){sg()},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(); /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */function Ba(e,n){return{\u0275kind:e,\u0275providers:n}}function S_(e){return[{provide:y_,multi:!0,useValue:e}]}function fS(){const e=St(gn);return n=>{const t=e.get(fc);if(n!==t.components[0])return;const i=e.get(ln),r=e.get(hS);1===e.get(E_)&&i.initialNavigation(),e.get(pS,null,X.Optional)?.setUpPreloading(),e.get(w_,null,X.Optional)?.init(),i.resetRootComponentType(t.componentTypes[0]),r.next(),r.complete()}}const hS=new q("",{factory:()=>new Ue}),E_=new q("",{providedIn:"root",factory:()=>1});const pS=new q("");function lV(e){return Ba(0,[{provide:pS,useExisting:rV},{provide:cS,useExisting:e}])} + */function Ha(e,n){return{\u0275kind:e,\u0275providers:n}}function S_(e){return[{provide:y_,multi:!0,useValue:e}]}function fS(){const e=St(gn);return n=>{const t=e.get(fc);if(n!==t.components[0])return;const i=e.get(ln),r=e.get(hS);1===e.get(M_)&&i.initialNavigation(),e.get(pS,null,X.Optional)?.setUpPreloading(),e.get(w_,null,X.Optional)?.init(),i.resetRootComponentType(t.componentTypes[0]),r.next(),r.complete()}}const hS=new q("",{factory:()=>new Ue}),M_=new q("",{providedIn:"root",factory:()=>1});const pS=new q("");function lV(e){return Ha(0,[{provide:pS,useExisting:rV},{provide:cS,useExisting:e}])} /** * @license * Copyright Google LLC All Rights Reserved. @@ -1712,7 +1712,7 @@ class cS{}let rV=(()=>{class e{constructor(t,i,r,o,s){this.router=t,this.injecto * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -const gS=new q("ROUTER_FORROOT_GUARD"),cV=[Sm,{provide:bw,useClass:Qm},{provide:ln,useFactory:aS},Ac,{provide:as,useFactory:function dS(e){return e.routerState.root},deps:[ln]},b_];function uV(){return new $1("Router",ln)}let Cf=(()=>{class e{constructor(t){}static forRoot(t,i){return{ngModule:e,providers:[cV,[],S_(t),{provide:gS,useFactory:pV,deps:[[ln,new Ll,new Vl]]},{provide:vf,useValue:i||{}},i?.useHash?{provide:ts,useClass:Tx}:{provide:ts,useClass:hC},{provide:w_,useFactory:()=>{const e=St(ln),n=St(GF),t=St(vf);return t.scrollOffset&&n.setOffset(t.scrollOffset),new uS(e,n,t)}},i?.preloadingStrategy?lV(i.preloadingStrategy).\u0275providers:[],{provide:$1,multi:!0,useFactory:uV},i?.initialNavigation?gV(i):[],[{provide:mS,useFactory:fS},{provide:F1,multi:!0,useExisting:mS}]]}}static forChild(t){return{ngModule:e,providers:[S_(t)]}}}return e.\u0275fac=function(t){return new(t||e)(L(gS,8))},e.\u0275mod=Ne({type:e}),e.\u0275inj=Me({imports:[f_]}),e})();function pV(e){return"guarded"}function gV(e){return["disabled"===e.initialNavigation?Ba(3,[{provide:Ad,multi:!0,useFactory:()=>{const n=St(ln);return()=>{n.setUpLocationChangeListener()}}},{provide:E_,useValue:2}]).\u0275providers:[],"enabledBlocking"===e.initialNavigation?Ba(2,[{provide:E_,useValue:0},{provide:Ad,multi:!0,deps:[gn],useFactory:n=>{const t=n.get(Mx,Promise.resolve());let i=!1;return()=>t.then(()=>new Promise(o=>{const s=n.get(ln),a=n.get(hS);(function r(o){n.get(ln).events.pipe(vn(a=>a instanceof ss||a instanceof lf||a instanceof Iw),ne(a=>a instanceof ss||a instanceof lf&&(0===a.code||1===a.code)&&null),vn(a=>null!==a),sn(1)).subscribe(()=>{o()})})(()=>{o(!0),i=!0}),s.afterPreactivation=()=>(o(!0),i||a.closed?Z(void 0):a),s.initialNavigation()}))}}]).\u0275providers:[]]}const mS=new q(""); +const gS=new q("ROUTER_FORROOT_GUARD"),cV=[Sm,{provide:bw,useClass:Qm},{provide:ln,useFactory:aS},Ic,{provide:as,useFactory:function dS(e){return e.routerState.root},deps:[ln]},b_];function uV(){return new $1("Router",ln)}let Cf=(()=>{class e{constructor(t){}static forRoot(t,i){return{ngModule:e,providers:[cV,[],S_(t),{provide:gS,useFactory:pV,deps:[[ln,new Ll,new Vl]]},{provide:vf,useValue:i||{}},i?.useHash?{provide:ts,useClass:TR}:{provide:ts,useClass:hC},{provide:w_,useFactory:()=>{const e=St(ln),n=St(GP),t=St(vf);return t.scrollOffset&&n.setOffset(t.scrollOffset),new uS(e,n,t)}},i?.preloadingStrategy?lV(i.preloadingStrategy).\u0275providers:[],{provide:$1,multi:!0,useFactory:uV},i?.initialNavigation?gV(i):[],[{provide:mS,useFactory:fS},{provide:P1,multi:!0,useExisting:mS}]]}}static forChild(t){return{ngModule:e,providers:[S_(t)]}}}return e.\u0275fac=function(t){return new(t||e)(L(gS,8))},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[f_]}),e})();function pV(e){return"guarded"}function gV(e){return["disabled"===e.initialNavigation?Ha(3,[{provide:Id,multi:!0,useFactory:()=>{const n=St(ln);return()=>{n.setUpLocationChangeListener()}}},{provide:M_,useValue:2}]).\u0275providers:[],"enabledBlocking"===e.initialNavigation?Ha(2,[{provide:M_,useValue:0},{provide:Id,multi:!0,deps:[gn],useFactory:n=>{const t=n.get(NR,Promise.resolve());let i=!1;return()=>t.then(()=>new Promise(o=>{const s=n.get(ln),a=n.get(hS);(function r(o){n.get(ln).events.pipe(vn(a=>a instanceof ss||a instanceof lf||a instanceof Aw),ne(a=>a instanceof ss||a instanceof lf&&(0===a.code||1===a.code)&&null),vn(a=>null!==a),sn(1)).subscribe(()=>{o()})})(()=>{o(!0),i=!0}),s.afterPreactivation=()=>(o(!0),i||a.closed?J(void 0):a),s.initialNavigation()}))}}]).\u0275providers:[]]}const mS=new q(""); /** * @license Angular v14.2.9 * (c) 2010-2022 Google LLC. https://angular.io/ @@ -1725,21 +1725,21 @@ const gS=new q("ROUTER_FORROOT_GUARD"),cV=[Sm,{provide:bw,useClass:Qm},{provide: * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -let _S=(()=>{class e{constructor(t,i){this._renderer=t,this._elementRef=i,this.onChange=r=>{},this.onTouched=()=>{}}setProperty(t,i){this._renderer.setProperty(this._elementRef.nativeElement,t,i)}registerOnTouched(t){this.onTouched=t}registerOnChange(t){this.onChange=t}setDisabledState(t){this.setProperty("disabled",t)}}return e.\u0275fac=function(t){return new(t||e)(C(pi),C(Ze))},e.\u0275dir=H({type:e}),e})(),ls=(()=>{class e extends _S{}return e.\u0275fac=function(){let n;return function(i){return(n||(n=nt(e)))(i||e)}}(),e.\u0275dir=H({type:e,features:[He]}),e})();const ur=new q("NgValueAccessor"),yV={provide:ur,useExisting:Te(()=>Fc),multi:!0},DV=new q("CompositionEventMode"); +let _S=(()=>{class e{constructor(t,i){this._renderer=t,this._elementRef=i,this.onChange=r=>{},this.onTouched=()=>{}}setProperty(t,i){this._renderer.setProperty(this._elementRef.nativeElement,t,i)}registerOnTouched(t){this.onTouched=t}registerOnChange(t){this.onChange=t}setDisabledState(t){this.setProperty("disabled",t)}}return e.\u0275fac=function(t){return new(t||e)(C(pi),C(Je))},e.\u0275dir=B({type:e}),e})(),ls=(()=>{class e extends _S{}return e.\u0275fac=function(){let n;return function(i){return(n||(n=nt(e)))(i||e)}}(),e.\u0275dir=B({type:e,features:[Be]}),e})();const ur=new q("NgValueAccessor"),yV={provide:ur,useExisting:Te(()=>Pc),multi:!0},DV=new q("CompositionEventMode"); /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */let Fc=(()=>{class e extends _S{constructor(t,i,r){super(t,i),this._compositionMode=r,this._composing=!1,null==this._compositionMode&&(this._compositionMode=!function bV(){const e=lr()?lr().getUserAgent():"";return/android (\d+)/.test(e.toLowerCase())}())}writeValue(t){this.setProperty("value",t??"")}_handleInput(t){(!this._compositionMode||this._compositionMode&&!this._composing)&&this.onChange(t)}_compositionStart(){this._composing=!0}_compositionEnd(t){this._composing=!1,this._compositionMode&&this.onChange(t)}}return e.\u0275fac=function(t){return new(t||e)(C(pi),C(Ze),C(DV,8))},e.\u0275dir=H({type:e,selectors:[["input","formControlName","",3,"type","checkbox"],["textarea","formControlName",""],["input","formControl","",3,"type","checkbox"],["textarea","formControl",""],["input","ngModel","",3,"type","checkbox"],["textarea","ngModel",""],["","ngDefaultControl",""]],hostBindings:function(t,i){1&t&&W("input",function(o){return i._handleInput(o.target.value)})("blur",function(){return i.onTouched()})("compositionstart",function(){return i._compositionStart()})("compositionend",function(o){return i._compositionEnd(o.target.value)})},features:[it([yV]),He]}),e})(); + */let Pc=(()=>{class e extends _S{constructor(t,i,r){super(t,i),this._compositionMode=r,this._composing=!1,null==this._compositionMode&&(this._compositionMode=!function bV(){const e=lr()?lr().getUserAgent():"";return/android (\d+)/.test(e.toLowerCase())}())}writeValue(t){this.setProperty("value",t??"")}_handleInput(t){(!this._compositionMode||this._compositionMode&&!this._composing)&&this.onChange(t)}_compositionStart(){this._composing=!0}_compositionEnd(t){this._composing=!1,this._compositionMode&&this.onChange(t)}}return e.\u0275fac=function(t){return new(t||e)(C(pi),C(Je),C(DV,8))},e.\u0275dir=B({type:e,selectors:[["input","formControlName","",3,"type","checkbox"],["textarea","formControlName",""],["input","formControl","",3,"type","checkbox"],["textarea","formControl",""],["input","ngModel","",3,"type","checkbox"],["textarea","ngModel",""],["","ngDefaultControl",""]],hostBindings:function(t,i){1&t&&W("input",function(o){return i._handleInput(o.target.value)})("blur",function(){return i.onTouched()})("compositionstart",function(){return i._compositionStart()})("compositionend",function(o){return i._compositionEnd(o.target.value)})},features:[it([yV]),Be]}),e})(); /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */const yn=new q("NgValidators"),bo=new q("NgAsyncValidators");function TS(e){return null!=e}function AS(e){return Xl(e)?gt(e):e}function IS(e){let n={};return e.forEach(t=>{n=null!=t?{...n,...t}:n}),0===Object.keys(n).length?null:n}function OS(e,n){return n.map(t=>t(e))}function kS(e){return e.map(n=>function SV(e){return!e.validate}(n)?n:t=>n.validate(t))}function M_(e){return null!=e?function RS(e){if(!e)return null;const n=e.filter(TS);return 0==n.length?null:function(t){return IS(OS(t,n))}}(kS(e)):null}function N_(e){return null!=e?function xS(e){if(!e)return null;const n=e.filter(TS);return 0==n.length?null:function(t){ + */const yn=new q("NgValidators"),bo=new q("NgAsyncValidators");function TS(e){return null!=e}function IS(e){return Xl(e)?gt(e):e}function AS(e){let n={};return e.forEach(t=>{n=null!=t?{...n,...t}:n}),0===Object.keys(n).length?null:n}function kS(e,n){return n.map(t=>t(e))}function OS(e){return e.map(n=>function SV(e){return!e.validate}(n)?n:t=>n.validate(t))}function N_(e){return null!=e?function xS(e){if(!e)return null;const n=e.filter(TS);return 0==n.length?null:function(t){return AS(kS(t,n))}}(OS(e)):null}function E_(e){return null!=e?function RS(e){if(!e)return null;const n=e.filter(TS);return 0==n.length?null:function(t){ /** * @license * Copyright Google LLC All Rights Reserved. @@ -1768,35 +1768,35 @@ let _S=(()=>{class e{constructor(t,i){this._renderer=t,this._elementRef=i,this.o * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -return function _V(...e){const n=rt(e),{args:t,keys:i}=iw(e),r=new je(o=>{const{length:s}=t;if(!s)return void o.complete();const a=new Array(s);let l=s,u=s;for(let f=0;f{p||(p=!0,u--),a[f]=m},()=>l--,void 0,()=>{(!l||!p)&&(u||o.next(i?rw(i,a):a),o.complete())}))}});return n?r.pipe(zm(n)):r}(OS(t,n).map(AS)).pipe(ne(IS))}}(kS(e)):null}function FS(e,n){return null===e?[n]:Array.isArray(e)?[...e,n]:[e,n]}function T_(e){return e?Array.isArray(e)?e:[e]:[]}function Sf(e,n){return Array.isArray(e)?e.includes(n):e===n}function VS(e,n){const t=T_(n);return T_(e).forEach(r=>{Sf(t,r)||t.push(r)}),t}function HS(e,n){return T_(n).filter(t=>!Sf(e,t))} +return function _V(...e){const n=rt(e),{args:t,keys:i}=iw(e),r=new je(o=>{const{length:s}=t;if(!s)return void o.complete();const a=new Array(s);let l=s,u=s;for(let f=0;f{p||(p=!0,u--),a[f]=m},()=>l--,void 0,()=>{(!l||!p)&&(u||o.next(i?rw(i,a):a),o.complete())}))}});return n?r.pipe(Ym(n)):r}(kS(t,n).map(IS)).pipe(ne(AS))}}(OS(e)):null}function PS(e,n){return null===e?[n]:Array.isArray(e)?[...e,n]:[e,n]}function T_(e){return e?Array.isArray(e)?e:[e]:[]}function Sf(e,n){return Array.isArray(e)?e.includes(n):e===n}function VS(e,n){const t=T_(n);return T_(e).forEach(r=>{Sf(t,r)||t.push(r)}),t}function BS(e,n){return T_(n).filter(t=>!Sf(e,t))} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */class BS{constructor(){this._rawValidators=[],this._rawAsyncValidators=[],this._onDestroyCallbacks=[]}get value(){return this.control?this.control.value:null}get valid(){return this.control?this.control.valid:null}get invalid(){return this.control?this.control.invalid:null}get pending(){return this.control?this.control.pending:null}get disabled(){return this.control?this.control.disabled:null}get enabled(){return this.control?this.control.enabled:null}get errors(){return this.control?this.control.errors:null}get pristine(){return this.control?this.control.pristine:null}get dirty(){return this.control?this.control.dirty:null}get touched(){return this.control?this.control.touched:null}get status(){return this.control?this.control.status:null}get untouched(){return this.control?this.control.untouched:null}get statusChanges(){return this.control?this.control.statusChanges:null}get valueChanges(){return this.control?this.control.valueChanges:null}get path(){return null}_setValidators(n){this._rawValidators=n||[],this._composedValidatorFn=M_(this._rawValidators)}_setAsyncValidators(n){this._rawAsyncValidators=n||[],this._composedAsyncValidatorFn=N_(this._rawAsyncValidators)}get validator(){return this._composedValidatorFn||null}get asyncValidator(){return this._composedAsyncValidatorFn||null}_registerOnDestroy(n){this._onDestroyCallbacks.push(n)}_invokeOnDestroyCallbacks(){this._onDestroyCallbacks.forEach(n=>n()),this._onDestroyCallbacks=[]}reset(n){this.control&&this.control.reset(n)}hasError(n,t){return!!this.control&&this.control.hasError(n,t)}getError(n,t){return this.control?this.control.getError(n,t):null}} + */class HS{constructor(){this._rawValidators=[],this._rawAsyncValidators=[],this._onDestroyCallbacks=[]}get value(){return this.control?this.control.value:null}get valid(){return this.control?this.control.valid:null}get invalid(){return this.control?this.control.invalid:null}get pending(){return this.control?this.control.pending:null}get disabled(){return this.control?this.control.disabled:null}get enabled(){return this.control?this.control.enabled:null}get errors(){return this.control?this.control.errors:null}get pristine(){return this.control?this.control.pristine:null}get dirty(){return this.control?this.control.dirty:null}get touched(){return this.control?this.control.touched:null}get status(){return this.control?this.control.status:null}get untouched(){return this.control?this.control.untouched:null}get statusChanges(){return this.control?this.control.statusChanges:null}get valueChanges(){return this.control?this.control.valueChanges:null}get path(){return null}_setValidators(n){this._rawValidators=n||[],this._composedValidatorFn=N_(this._rawValidators)}_setAsyncValidators(n){this._rawAsyncValidators=n||[],this._composedAsyncValidatorFn=E_(this._rawAsyncValidators)}get validator(){return this._composedValidatorFn||null}get asyncValidator(){return this._composedAsyncValidatorFn||null}_registerOnDestroy(n){this._onDestroyCallbacks.push(n)}_invokeOnDestroyCallbacks(){this._onDestroyCallbacks.forEach(n=>n()),this._onDestroyCallbacks=[]}reset(n){this.control&&this.control.reset(n)}hasError(n,t){return!!this.control&&this.control.hasError(n,t)}getError(n,t){return this.control?this.control.getError(n,t):null}} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */class kn extends BS{get formDirective(){return null}get path(){return null}} + */class On extends HS{get formDirective(){return null}get path(){return null}} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */class Do extends BS{constructor(){super(...arguments),this._parent=null,this.name=null,this.valueAccessor=null}} + */class Do extends HS{constructor(){super(...arguments),this._parent=null,this.name=null,this.valueAccessor=null}} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */let A_=(()=>{class e extends class jS{constructor(n){this._cd=n}get isTouched(){return!!this._cd?.control?.touched}get isUntouched(){return!!this._cd?.control?.untouched}get isPristine(){return!!this._cd?.control?.pristine}get isDirty(){return!!this._cd?.control?.dirty}get isValid(){return!!this._cd?.control?.valid}get isInvalid(){return!!this._cd?.control?.invalid}get isPending(){return!!this._cd?.control?.pending}get isSubmitted(){return!!this._cd?.submitted}}{constructor(t){super(t)}}return e.\u0275fac=function(t){return new(t||e)(C(Do,2))},e.\u0275dir=H({type:e,selectors:[["","formControlName",""],["","ngModel",""],["","formControl",""]],hostVars:14,hostBindings:function(t,i){2&t&&ht("ng-untouched",i.isUntouched)("ng-touched",i.isTouched)("ng-pristine",i.isPristine)("ng-dirty",i.isDirty)("ng-valid",i.isValid)("ng-invalid",i.isInvalid)("ng-pending",i.isPending)},features:[He]}),e})(); + */let I_=(()=>{class e extends class jS{constructor(n){this._cd=n}get isTouched(){return!!this._cd?.control?.touched}get isUntouched(){return!!this._cd?.control?.untouched}get isPristine(){return!!this._cd?.control?.pristine}get isDirty(){return!!this._cd?.control?.dirty}get isValid(){return!!this._cd?.control?.valid}get isInvalid(){return!!this._cd?.control?.invalid}get isPending(){return!!this._cd?.control?.pending}get isSubmitted(){return!!this._cd?.submitted}}{constructor(t){super(t)}}return e.\u0275fac=function(t){return new(t||e)(C(Do,2))},e.\u0275dir=B({type:e,selectors:[["","formControlName",""],["","ngModel",""],["","formControl",""]],hostVars:14,hostBindings:function(t,i){2&t&&ht("ng-untouched",i.isUntouched)("ng-touched",i.isTouched)("ng-pristine",i.isPristine)("ng-dirty",i.isDirty)("ng-valid",i.isValid)("ng-invalid",i.isInvalid)("ng-pending",i.isPending)},features:[Be]}),e})(); /** * @license * Copyright Google LLC All Rights Reserved. @@ -1811,7 +1811,7 @@ return function _V(...e){const n=rt(e),{args:t,keys:i}=iw(e),r=new je(o=>{const{ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -const Pc="VALID",Mf="INVALID",ja="PENDING",Lc="DISABLED";function US(e){return Array.isArray(e)?M_(e):e||null}function GS(e){return Array.isArray(e)?N_(e):e||null}function Nf(e){return null!=e&&!Array.isArray(e)&&"object"==typeof e}function Vc(e,n){(function P_(e,n){const t=function PS(e){return e._rawValidators}(e);null!==n.validator?e.setValidators(FS(t,n.validator)):"function"==typeof t&&e.setValidators([t]);const i=function LS(e){return e._rawAsyncValidators}(e);null!==n.asyncValidator?e.setAsyncValidators(FS(i,n.asyncValidator)):"function"==typeof i&&e.setAsyncValidators([i]);const r=()=>e.updateValueAndValidity();If(n._rawValidators,r),If(n._rawAsyncValidators,r)})(e,n),n.valueAccessor.writeValue(e.value),e.disabled&&n.valueAccessor.setDisabledState?.(!0),function xV(e,n){n.valueAccessor.registerOnChange(t=>{e._pendingValue=t,e._pendingChange=!0,e._pendingDirty=!0,"change"===e.updateOn&&YS(e,n)})}(e,n),function PV(e,n){const t=(i,r)=>{n.valueAccessor.writeValue(i),r&&n.viewToModelUpdate(i)};e.registerOnChange(t),n._registerOnDestroy(()=>{e._unregisterOnChange(t)})}(e,n),function FV(e,n){n.valueAccessor.registerOnTouched(()=>{e._pendingTouched=!0,"blur"===e.updateOn&&e._pendingChange&&YS(e,n),"submit"!==e.updateOn&&e.markAsTouched()})}(e,n),function RV(e,n){if(n.valueAccessor.setDisabledState){const t=i=>{n.valueAccessor.setDisabledState(i)};e.registerOnDisabledChange(t),n._registerOnDestroy(()=>{e._unregisterOnDisabledChange(t)})}}(e,n)}function If(e,n){e.forEach(t=>{t.registerOnValidatorChange&&t.registerOnValidatorChange(n)})}function YS(e,n){e._pendingDirty&&e.markAsDirty(),e.setValue(e._pendingValue,{emitModelToViewChange:!1}),n.viewToModelUpdate(e._pendingValue),e._pendingChange=!1} +const Fc="VALID",Nf="INVALID",ja="PENDING",Lc="DISABLED";function US(e){return Array.isArray(e)?N_(e):e||null}function GS(e){return Array.isArray(e)?E_(e):e||null}function Ef(e){return null!=e&&!Array.isArray(e)&&"object"==typeof e}function Vc(e,n){(function F_(e,n){const t=function FS(e){return e._rawValidators}(e);null!==n.validator?e.setValidators(PS(t,n.validator)):"function"==typeof t&&e.setValidators([t]);const i=function LS(e){return e._rawAsyncValidators}(e);null!==n.asyncValidator?e.setAsyncValidators(PS(i,n.asyncValidator)):"function"==typeof i&&e.setAsyncValidators([i]);const r=()=>e.updateValueAndValidity();Af(n._rawValidators,r),Af(n._rawAsyncValidators,r)})(e,n),n.valueAccessor.writeValue(e.value),e.disabled&&n.valueAccessor.setDisabledState?.(!0),function RV(e,n){n.valueAccessor.registerOnChange(t=>{e._pendingValue=t,e._pendingChange=!0,e._pendingDirty=!0,"change"===e.updateOn&&KS(e,n)})}(e,n),function FV(e,n){const t=(i,r)=>{n.valueAccessor.writeValue(i),r&&n.viewToModelUpdate(i)};e.registerOnChange(t),n._registerOnDestroy(()=>{e._unregisterOnChange(t)})}(e,n),function PV(e,n){n.valueAccessor.registerOnTouched(()=>{e._pendingTouched=!0,"blur"===e.updateOn&&e._pendingChange&&KS(e,n),"submit"!==e.updateOn&&e.markAsTouched()})}(e,n),function xV(e,n){if(n.valueAccessor.setDisabledState){const t=i=>{n.valueAccessor.setDisabledState(i)};e.registerOnDisabledChange(t),n._registerOnDestroy(()=>{e._unregisterOnDisabledChange(t)})}}(e,n)}function Af(e,n){e.forEach(t=>{t.registerOnValidatorChange&&t.registerOnValidatorChange(n)})}function KS(e,n){e._pendingDirty&&e.markAsDirty(),e.setValue(e._pendingValue,{emitModelToViewChange:!1}),n.viewToModelUpdate(e._pendingValue),e._pendingChange=!1} /** * @license * Copyright Google LLC All Rights Reserved. @@ -1826,28 +1826,28 @@ function QS(e,n){const t=e.indexOf(n);t>-1&&e.splice(t,1)} * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */function XS(e){return"object"==typeof e&&null!==e&&2===Object.keys(e).length&&"value"in e&&"disabled"in e}const GV={provide:Do,useExisting:Te(()=>kf)},iE=(()=>Promise.resolve())(); + */function XS(e){return"object"==typeof e&&null!==e&&2===Object.keys(e).length&&"value"in e&&"disabled"in e}const GV={provide:Do,useExisting:Te(()=>Of)},iM=(()=>Promise.resolve())(); /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */let kf=(()=>{class e extends Do{constructor(t,i,r,o,s){super(),this._changeDetectorRef=s,this.control=new class extends class zS{constructor(n,t){this._pendingDirty=!1,this._hasOwnPendingAsyncValidator=!1,this._pendingTouched=!1,this._onCollectionChange=()=>{},this._parent=null,this.pristine=!0,this.touched=!1,this._onDisabledChange=[],this._rawValidators=n,this._rawAsyncValidators=t,this._composedValidatorFn=US(this._rawValidators),this._composedAsyncValidatorFn=GS(this._rawAsyncValidators)}get validator(){return this._composedValidatorFn}set validator(n){this._rawValidators=this._composedValidatorFn=n}get asyncValidator(){return this._composedAsyncValidatorFn}set asyncValidator(n){this._rawAsyncValidators=this._composedAsyncValidatorFn=n}get parent(){return this._parent}get valid(){return this.status===Pc}get invalid(){return this.status===Mf}get pending(){return this.status==ja}get disabled(){return this.status===Lc}get enabled(){return this.status!==Lc}get dirty(){return!this.pristine}get untouched(){return!this.touched}get updateOn(){return this._updateOn?this._updateOn:this.parent?this.parent.updateOn:"change"}setValidators(n){this._rawValidators=n,this._composedValidatorFn=US(n)}setAsyncValidators(n){this._rawAsyncValidators=n,this._composedAsyncValidatorFn=GS(n)}addValidators(n){this.setValidators(VS(n,this._rawValidators))}addAsyncValidators(n){this.setAsyncValidators(VS(n,this._rawAsyncValidators))}removeValidators(n){this.setValidators(HS(n,this._rawValidators))}removeAsyncValidators(n){this.setAsyncValidators(HS(n,this._rawAsyncValidators))}hasValidator(n){return Sf(this._rawValidators,n)}hasAsyncValidator(n){return Sf(this._rawAsyncValidators,n)}clearValidators(){this.validator=null}clearAsyncValidators(){this.asyncValidator=null}markAsTouched(n={}){this.touched=!0,this._parent&&!n.onlySelf&&this._parent.markAsTouched(n)}markAllAsTouched(){this.markAsTouched({onlySelf:!0}),this._forEachChild(n=>n.markAllAsTouched())}markAsUntouched(n={}){this.touched=!1,this._pendingTouched=!1,this._forEachChild(t=>{t.markAsUntouched({onlySelf:!0})}),this._parent&&!n.onlySelf&&this._parent._updateTouched(n)}markAsDirty(n={}){this.pristine=!1,this._parent&&!n.onlySelf&&this._parent.markAsDirty(n)}markAsPristine(n={}){this.pristine=!0,this._pendingDirty=!1,this._forEachChild(t=>{t.markAsPristine({onlySelf:!0})}),this._parent&&!n.onlySelf&&this._parent._updatePristine(n)}markAsPending(n={}){this.status=ja,!1!==n.emitEvent&&this.statusChanges.emit(this.status),this._parent&&!n.onlySelf&&this._parent.markAsPending(n)}disable(n={}){const t=this._parentMarkedDirty(n.onlySelf);this.status=Lc,this.errors=null,this._forEachChild(i=>{i.disable({...n,onlySelf:!0})}),this._updateValue(),!1!==n.emitEvent&&(this.valueChanges.emit(this.value),this.statusChanges.emit(this.status)),this._updateAncestors({...n,skipPristineCheck:t}),this._onDisabledChange.forEach(i=>i(!0))}enable(n={}){const t=this._parentMarkedDirty(n.onlySelf);this.status=Pc,this._forEachChild(i=>{i.enable({...n,onlySelf:!0})}),this.updateValueAndValidity({onlySelf:!0,emitEvent:n.emitEvent}),this._updateAncestors({...n,skipPristineCheck:t}),this._onDisabledChange.forEach(i=>i(!1))}_updateAncestors(n){this._parent&&!n.onlySelf&&(this._parent.updateValueAndValidity(n),n.skipPristineCheck||this._parent._updatePristine(),this._parent._updateTouched())}setParent(n){this._parent=n}getRawValue(){return this.value}updateValueAndValidity(n={}){this._setInitialStatus(),this._updateValue(),this.enabled&&(this._cancelExistingSubscription(),this.errors=this._runValidator(),this.status=this._calculateStatus(),(this.status===Pc||this.status===ja)&&this._runAsyncValidator(n.emitEvent)),!1!==n.emitEvent&&(this.valueChanges.emit(this.value),this.statusChanges.emit(this.status)),this._parent&&!n.onlySelf&&this._parent.updateValueAndValidity(n)}_updateTreeValidity(n={emitEvent:!0}){this._forEachChild(t=>t._updateTreeValidity(n)),this.updateValueAndValidity({onlySelf:!0,emitEvent:n.emitEvent})}_setInitialStatus(){this.status=this._allControlsDisabled()?Lc:Pc}_runValidator(){return this.validator?this.validator(this):null}_runAsyncValidator(n){if(this.asyncValidator){this.status=ja,this._hasOwnPendingAsyncValidator=!0;const t=AS(this.asyncValidator(this));this._asyncValidationSubscription=t.subscribe(i=>{this._hasOwnPendingAsyncValidator=!1,this.setErrors(i,{emitEvent:n})})}}_cancelExistingSubscription(){this._asyncValidationSubscription&&(this._asyncValidationSubscription.unsubscribe(),this._hasOwnPendingAsyncValidator=!1)}setErrors(n,t={}){this.errors=n,this._updateControlsErrors(!1!==t.emitEvent)}get(n){let t=n;return null==t||(Array.isArray(t)||(t=t.split(".")),0===t.length)?null:t.reduce((i,r)=>i&&i._find(r),this)}getError(n,t){const i=t?this.get(t):this;return i&&i.errors?i.errors[n]:null}hasError(n,t){return!!this.getError(n,t)}get root(){let n=this;for(;n._parent;)n=n._parent;return n}_updateControlsErrors(n){this.status=this._calculateStatus(),n&&this.statusChanges.emit(this.status),this._parent&&this._parent._updateControlsErrors(n)}_initObservables(){this.valueChanges=new ue,this.statusChanges=new ue}_calculateStatus(){return this._allControlsDisabled()?Lc:this.errors?Mf:this._hasOwnPendingAsyncValidator||this._anyControlsHaveStatus(ja)?ja:this._anyControlsHaveStatus(Mf)?Mf:Pc}_anyControlsHaveStatus(n){return this._anyControls(t=>t.status===n)}_anyControlsDirty(){return this._anyControls(n=>n.dirty)}_anyControlsTouched(){return this._anyControls(n=>n.touched)}_updatePristine(n={}){this.pristine=!this._anyControlsDirty(),this._parent&&!n.onlySelf&&this._parent._updatePristine(n)}_updateTouched(n={}){this.touched=this._anyControlsTouched(),this._parent&&!n.onlySelf&&this._parent._updateTouched(n)}_registerOnCollectionChange(n){this._onCollectionChange=n}_setUpdateStrategy(n){Nf(n)&&null!=n.updateOn&&(this._updateOn=n.updateOn)}_parentMarkedDirty(n){return!n&&!(!this._parent||!this._parent.dirty)&&!this._parent._anyControlsDirty()}_find(n){return null}} + */let Of=(()=>{class e extends Do{constructor(t,i,r,o,s){super(),this._changeDetectorRef=s,this.control=new class extends class YS{constructor(n,t){this._pendingDirty=!1,this._hasOwnPendingAsyncValidator=!1,this._pendingTouched=!1,this._onCollectionChange=()=>{},this._parent=null,this.pristine=!0,this.touched=!1,this._onDisabledChange=[],this._rawValidators=n,this._rawAsyncValidators=t,this._composedValidatorFn=US(this._rawValidators),this._composedAsyncValidatorFn=GS(this._rawAsyncValidators)}get validator(){return this._composedValidatorFn}set validator(n){this._rawValidators=this._composedValidatorFn=n}get asyncValidator(){return this._composedAsyncValidatorFn}set asyncValidator(n){this._rawAsyncValidators=this._composedAsyncValidatorFn=n}get parent(){return this._parent}get valid(){return this.status===Fc}get invalid(){return this.status===Nf}get pending(){return this.status==ja}get disabled(){return this.status===Lc}get enabled(){return this.status!==Lc}get dirty(){return!this.pristine}get untouched(){return!this.touched}get updateOn(){return this._updateOn?this._updateOn:this.parent?this.parent.updateOn:"change"}setValidators(n){this._rawValidators=n,this._composedValidatorFn=US(n)}setAsyncValidators(n){this._rawAsyncValidators=n,this._composedAsyncValidatorFn=GS(n)}addValidators(n){this.setValidators(VS(n,this._rawValidators))}addAsyncValidators(n){this.setAsyncValidators(VS(n,this._rawAsyncValidators))}removeValidators(n){this.setValidators(BS(n,this._rawValidators))}removeAsyncValidators(n){this.setAsyncValidators(BS(n,this._rawAsyncValidators))}hasValidator(n){return Sf(this._rawValidators,n)}hasAsyncValidator(n){return Sf(this._rawAsyncValidators,n)}clearValidators(){this.validator=null}clearAsyncValidators(){this.asyncValidator=null}markAsTouched(n={}){this.touched=!0,this._parent&&!n.onlySelf&&this._parent.markAsTouched(n)}markAllAsTouched(){this.markAsTouched({onlySelf:!0}),this._forEachChild(n=>n.markAllAsTouched())}markAsUntouched(n={}){this.touched=!1,this._pendingTouched=!1,this._forEachChild(t=>{t.markAsUntouched({onlySelf:!0})}),this._parent&&!n.onlySelf&&this._parent._updateTouched(n)}markAsDirty(n={}){this.pristine=!1,this._parent&&!n.onlySelf&&this._parent.markAsDirty(n)}markAsPristine(n={}){this.pristine=!0,this._pendingDirty=!1,this._forEachChild(t=>{t.markAsPristine({onlySelf:!0})}),this._parent&&!n.onlySelf&&this._parent._updatePristine(n)}markAsPending(n={}){this.status=ja,!1!==n.emitEvent&&this.statusChanges.emit(this.status),this._parent&&!n.onlySelf&&this._parent.markAsPending(n)}disable(n={}){const t=this._parentMarkedDirty(n.onlySelf);this.status=Lc,this.errors=null,this._forEachChild(i=>{i.disable({...n,onlySelf:!0})}),this._updateValue(),!1!==n.emitEvent&&(this.valueChanges.emit(this.value),this.statusChanges.emit(this.status)),this._updateAncestors({...n,skipPristineCheck:t}),this._onDisabledChange.forEach(i=>i(!0))}enable(n={}){const t=this._parentMarkedDirty(n.onlySelf);this.status=Fc,this._forEachChild(i=>{i.enable({...n,onlySelf:!0})}),this.updateValueAndValidity({onlySelf:!0,emitEvent:n.emitEvent}),this._updateAncestors({...n,skipPristineCheck:t}),this._onDisabledChange.forEach(i=>i(!1))}_updateAncestors(n){this._parent&&!n.onlySelf&&(this._parent.updateValueAndValidity(n),n.skipPristineCheck||this._parent._updatePristine(),this._parent._updateTouched())}setParent(n){this._parent=n}getRawValue(){return this.value}updateValueAndValidity(n={}){this._setInitialStatus(),this._updateValue(),this.enabled&&(this._cancelExistingSubscription(),this.errors=this._runValidator(),this.status=this._calculateStatus(),(this.status===Fc||this.status===ja)&&this._runAsyncValidator(n.emitEvent)),!1!==n.emitEvent&&(this.valueChanges.emit(this.value),this.statusChanges.emit(this.status)),this._parent&&!n.onlySelf&&this._parent.updateValueAndValidity(n)}_updateTreeValidity(n={emitEvent:!0}){this._forEachChild(t=>t._updateTreeValidity(n)),this.updateValueAndValidity({onlySelf:!0,emitEvent:n.emitEvent})}_setInitialStatus(){this.status=this._allControlsDisabled()?Lc:Fc}_runValidator(){return this.validator?this.validator(this):null}_runAsyncValidator(n){if(this.asyncValidator){this.status=ja,this._hasOwnPendingAsyncValidator=!0;const t=IS(this.asyncValidator(this));this._asyncValidationSubscription=t.subscribe(i=>{this._hasOwnPendingAsyncValidator=!1,this.setErrors(i,{emitEvent:n})})}}_cancelExistingSubscription(){this._asyncValidationSubscription&&(this._asyncValidationSubscription.unsubscribe(),this._hasOwnPendingAsyncValidator=!1)}setErrors(n,t={}){this.errors=n,this._updateControlsErrors(!1!==t.emitEvent)}get(n){let t=n;return null==t||(Array.isArray(t)||(t=t.split(".")),0===t.length)?null:t.reduce((i,r)=>i&&i._find(r),this)}getError(n,t){const i=t?this.get(t):this;return i&&i.errors?i.errors[n]:null}hasError(n,t){return!!this.getError(n,t)}get root(){let n=this;for(;n._parent;)n=n._parent;return n}_updateControlsErrors(n){this.status=this._calculateStatus(),n&&this.statusChanges.emit(this.status),this._parent&&this._parent._updateControlsErrors(n)}_initObservables(){this.valueChanges=new ue,this.statusChanges=new ue}_calculateStatus(){return this._allControlsDisabled()?Lc:this.errors?Nf:this._hasOwnPendingAsyncValidator||this._anyControlsHaveStatus(ja)?ja:this._anyControlsHaveStatus(Nf)?Nf:Fc}_anyControlsHaveStatus(n){return this._anyControls(t=>t.status===n)}_anyControlsDirty(){return this._anyControls(n=>n.dirty)}_anyControlsTouched(){return this._anyControls(n=>n.touched)}_updatePristine(n={}){this.pristine=!this._anyControlsDirty(),this._parent&&!n.onlySelf&&this._parent._updatePristine(n)}_updateTouched(n={}){this.touched=this._anyControlsTouched(),this._parent&&!n.onlySelf&&this._parent._updateTouched(n)}_registerOnCollectionChange(n){this._onCollectionChange=n}_setUpdateStrategy(n){Ef(n)&&null!=n.updateOn&&(this._updateOn=n.updateOn)}_parentMarkedDirty(n){return!n&&!(!this._parent||!this._parent.dirty)&&!this._parent._anyControlsDirty()}_find(n){return null}} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */{constructor(n=null,t,i){super(function R_(e){return(Nf(e)?e.validators:e)||null}(t),function x_(e,n){return(Nf(n)?n.asyncValidators:e)||null}(i,t)),this.defaultValue=null,this._onChange=[],this._pendingChange=!1,this._applyFormState(n),this._setUpdateStrategy(t),this._initObservables(),this.updateValueAndValidity({onlySelf:!0,emitEvent:!!this.asyncValidator}),Nf(t)&&(t.nonNullable||t.initialValueIsDefault)&&(this.defaultValue=XS(n)?n.value:n)}setValue(n,t={}){this.value=this._pendingValue=n,this._onChange.length&&!1!==t.emitModelToViewChange&&this._onChange.forEach(i=>i(this.value,!1!==t.emitViewToModelChange)),this.updateValueAndValidity(t)}patchValue(n,t={}){this.setValue(n,t)}reset(n=this.defaultValue,t={}){this._applyFormState(n),this.markAsPristine(t),this.markAsUntouched(t),this.setValue(this.value,t),this._pendingChange=!1}_updateValue(){}_anyControls(n){return!1}_allControlsDisabled(){return this.disabled}registerOnChange(n){this._onChange.push(n)}_unregisterOnChange(n){QS(this._onChange,n)}registerOnDisabledChange(n){this._onDisabledChange.push(n)}_unregisterOnDisabledChange(n){QS(this._onDisabledChange,n)}_forEachChild(n){}_syncPendingControls(){return!("submit"!==this.updateOn||(this._pendingDirty&&this.markAsDirty(),this._pendingTouched&&this.markAsTouched(),!this._pendingChange)||(this.setValue(this._pendingValue,{onlySelf:!0,emitModelToViewChange:!1}),0))}_applyFormState(n){XS(n)?(this.value=this._pendingValue=n.value,n.disabled?this.disable({onlySelf:!0,emitEvent:!1}):this.enable({onlySelf:!0,emitEvent:!1})):this.value=this._pendingValue=n}},this._registered=!1,this.update=new ue,this._parent=t,this._setValidators(i),this._setAsyncValidators(r),this.valueAccessor=function V_(e,n){if(!n)return null;let t,i,r;return Array.isArray(n),n.forEach(o=>{o.constructor===Fc?t=o:function HV(e){return Object.getPrototypeOf(e.constructor)===ls}(o)?i=o:r=o}),r||i||t||null}(0,o)}ngOnChanges(t){if(this._checkForErrors(),!this._registered||"name"in t){if(this._registered&&(this._checkName(),this.formDirective)){const i=t.name.previousValue;this.formDirective.removeControl({name:i,path:this._getPath(i)})}this._setUpControl()}"isDisabled"in t&&this._updateDisabled(t),function L_(e,n){if(!e.hasOwnProperty("model"))return!1;const t=e.model;return!!t.isFirstChange()||!Object.is(n,t.currentValue)}(t,this.viewModel)&&(this._updateValue(this.model),this.viewModel=this.model)}ngOnDestroy(){this.formDirective&&this.formDirective.removeControl(this)}get path(){return this._getPath(this.name)}get formDirective(){return this._parent?this._parent.formDirective:null}viewToModelUpdate(t){this.viewModel=t,this.update.emit(t)}_setUpControl(){this._setUpdateStrategy(),this._isStandalone()?this._setUpStandalone():this.formDirective.addControl(this),this._registered=!0}_setUpdateStrategy(){this.options&&null!=this.options.updateOn&&(this.control._updateOn=this.options.updateOn)}_isStandalone(){return!this._parent||!(!this.options||!this.options.standalone)}_setUpStandalone(){Vc(this.control,this),this.control.updateValueAndValidity({emitEvent:!1})}_checkForErrors(){this._isStandalone()||this._checkParentType(),this._checkName()}_checkParentType(){}_checkName(){this.options&&this.options.name&&(this.name=this.options.name),this._isStandalone()}_updateValue(t){iE.then(()=>{this.control.setValue(t,{emitViewToModelChange:!1}),this._changeDetectorRef?.markForCheck()})}_updateDisabled(t){const i=t.isDisabled.currentValue,r=0!==i&&function Hr(e){return"boolean"==typeof e?e:null!=e&&"false"!==e} + */{constructor(n=null,t,i){super(function x_(e){return(Ef(e)?e.validators:e)||null}(t),function R_(e,n){return(Ef(n)?n.asyncValidators:e)||null}(i,t)),this.defaultValue=null,this._onChange=[],this._pendingChange=!1,this._applyFormState(n),this._setUpdateStrategy(t),this._initObservables(),this.updateValueAndValidity({onlySelf:!0,emitEvent:!!this.asyncValidator}),Ef(t)&&(t.nonNullable||t.initialValueIsDefault)&&(this.defaultValue=XS(n)?n.value:n)}setValue(n,t={}){this.value=this._pendingValue=n,this._onChange.length&&!1!==t.emitModelToViewChange&&this._onChange.forEach(i=>i(this.value,!1!==t.emitViewToModelChange)),this.updateValueAndValidity(t)}patchValue(n,t={}){this.setValue(n,t)}reset(n=this.defaultValue,t={}){this._applyFormState(n),this.markAsPristine(t),this.markAsUntouched(t),this.setValue(this.value,t),this._pendingChange=!1}_updateValue(){}_anyControls(n){return!1}_allControlsDisabled(){return this.disabled}registerOnChange(n){this._onChange.push(n)}_unregisterOnChange(n){QS(this._onChange,n)}registerOnDisabledChange(n){this._onDisabledChange.push(n)}_unregisterOnDisabledChange(n){QS(this._onDisabledChange,n)}_forEachChild(n){}_syncPendingControls(){return!("submit"!==this.updateOn||(this._pendingDirty&&this.markAsDirty(),this._pendingTouched&&this.markAsTouched(),!this._pendingChange)||(this.setValue(this._pendingValue,{onlySelf:!0,emitModelToViewChange:!1}),0))}_applyFormState(n){XS(n)?(this.value=this._pendingValue=n.value,n.disabled?this.disable({onlySelf:!0,emitEvent:!1}):this.enable({onlySelf:!0,emitEvent:!1})):this.value=this._pendingValue=n}},this._registered=!1,this.update=new ue,this._parent=t,this._setValidators(i),this._setAsyncValidators(r),this.valueAccessor=function V_(e,n){if(!n)return null;let t,i,r;return Array.isArray(n),n.forEach(o=>{o.constructor===Pc?t=o:function BV(e){return Object.getPrototypeOf(e.constructor)===ls}(o)?i=o:r=o}),r||i||t||null}(0,o)}ngOnChanges(t){if(this._checkForErrors(),!this._registered||"name"in t){if(this._registered&&(this._checkName(),this.formDirective)){const i=t.name.previousValue;this.formDirective.removeControl({name:i,path:this._getPath(i)})}this._setUpControl()}"isDisabled"in t&&this._updateDisabled(t),function L_(e,n){if(!e.hasOwnProperty("model"))return!1;const t=e.model;return!!t.isFirstChange()||!Object.is(n,t.currentValue)}(t,this.viewModel)&&(this._updateValue(this.model),this.viewModel=this.model)}ngOnDestroy(){this.formDirective&&this.formDirective.removeControl(this)}get path(){return this._getPath(this.name)}get formDirective(){return this._parent?this._parent.formDirective:null}viewToModelUpdate(t){this.viewModel=t,this.update.emit(t)}_setUpControl(){this._setUpdateStrategy(),this._isStandalone()?this._setUpStandalone():this.formDirective.addControl(this),this._registered=!0}_setUpdateStrategy(){this.options&&null!=this.options.updateOn&&(this.control._updateOn=this.options.updateOn)}_isStandalone(){return!this._parent||!(!this.options||!this.options.standalone)}_setUpStandalone(){Vc(this.control,this),this.control.updateValueAndValidity({emitEvent:!1})}_checkForErrors(){this._isStandalone()||this._checkParentType(),this._checkName()}_checkParentType(){}_checkName(){this.options&&this.options.name&&(this.name=this.options.name),this._isStandalone()}_updateValue(t){iM.then(()=>{this.control.setValue(t,{emitViewToModelChange:!1}),this._changeDetectorRef?.markForCheck()})}_updateDisabled(t){const i=t.isDisabled.currentValue,r=0!==i&&function Br(e){return"boolean"==typeof e?e:null!=e&&"false"!==e} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */(i);iE.then(()=>{r&&!this.control.disabled?this.control.disable():!r&&this.control.disabled&&this.control.enable(),this._changeDetectorRef?.markForCheck()})}_getPath(t){return this._parent? + */(i);iM.then(()=>{r&&!this.control.disabled?this.control.disable():!r&&this.control.disabled&&this.control.enable(),this._changeDetectorRef?.markForCheck()})}_getPath(t){return this._parent? /** * @license * Copyright Google LLC All Rights Reserved. @@ -1855,7 +1855,7 @@ function QS(e,n){const t=e.indexOf(n);t>-1&&e.splice(t,1)} * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -function Tf(e,n){return[...n.path,e]}(t,this._parent):[t]}}return e.\u0275fac=function(t){return new(t||e)(C(kn,9),C(yn,10),C(bo,10),C(ur,10),C(Vr,8))},e.\u0275dir=H({type:e,selectors:[["","ngModel","",3,"formControlName","",3,"formControl",""]],inputs:{name:"name",isDisabled:["disabled","isDisabled"],model:["ngModel","model"],options:["ngModelOptions","options"]},outputs:{update:"ngModelChange"},exportAs:["ngModel"],features:[it([GV]),He,Kt]}),e})(); +function Tf(e,n){return[...n.path,e]}(t,this._parent):[t]}}return e.\u0275fac=function(t){return new(t||e)(C(On,9),C(yn,10),C(bo,10),C(ur,10),C(Vr,8))},e.\u0275dir=B({type:e,selectors:[["","ngModel","",3,"formControlName","",3,"formControl",""]],inputs:{name:"name",isDisabled:["disabled","isDisabled"],model:["ngModel","model"],options:["ngModelOptions","options"]},outputs:{update:"ngModelChange"},exportAs:["ngModel"],features:[it([GV]),Be,zt]}),e})(); /** * @license * Copyright Google LLC All Rights Reserved. @@ -1870,7 +1870,7 @@ function Tf(e,n){return[...n.path,e]}(t,this._parent):[t]}}return e.\u0275fac=fu * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -const KV={provide:ur,useExisting:Te(()=>B_),multi:!0};let B_=(()=>{class e extends ls{writeValue(t){this.setProperty("value",t??"")}registerOnChange(t){this.onChange=i=>{t(""==i?null:parseFloat(i))}}}return e.\u0275fac=function(){let n;return function(i){return(n||(n=nt(e)))(i||e)}}(),e.\u0275dir=H({type:e,selectors:[["input","type","number","formControlName",""],["input","type","number","formControl",""],["input","type","number","ngModel",""]],hostBindings:function(t,i){1&t&&W("input",function(o){return i.onChange(o.target.value)})("blur",function(){return i.onTouched()})},features:[it([KV]),He]}),e})(),rE=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ne({type:e}),e.\u0275inj=Me({}),e})(),gH=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ne({type:e}),e.\u0275inj=Me({imports:[rE]}),e})(),CE=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ne({type:e}),e.\u0275inj=Me({imports:[gH]}),e})(); +const zV={provide:ur,useExisting:Te(()=>H_),multi:!0};let H_=(()=>{class e extends ls{writeValue(t){this.setProperty("value",t??"")}registerOnChange(t){this.onChange=i=>{t(""==i?null:parseFloat(i))}}}return e.\u0275fac=function(){let n;return function(i){return(n||(n=nt(e)))(i||e)}}(),e.\u0275dir=B({type:e,selectors:[["input","type","number","formControlName",""],["input","type","number","formControl",""],["input","type","number","ngModel",""]],hostBindings:function(t,i){1&t&&W("input",function(o){return i.onChange(o.target.value)})("blur",function(){return i.onTouched()})},features:[it([zV]),Be]}),e})(),rM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({}),e})(),gB=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[rM]}),e})(),CM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[gB]}),e})(); /** * @license * Copyright Google LLC All Rights Reserved. @@ -1885,7 +1885,7 @@ const KV={provide:ur,useExisting:Te(()=>B_),multi:!0};let B_=(()=>{class e exten * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -const wE=new q("ngx-mask config"),SE=new q("new ngx-mask config"),EE=new q("initial ngx-mask config"),_H={suffix:"",prefix:"",thousandSeparator:" ",decimalMarker:[".",","],clearIfNotMatch:!1,showTemplate:!1,showMaskTyped:!1,placeHolderCharacter:"_",dropSpecialCharacters:!0,hiddenInput:void 0,shownMaskExpression:"",separatorLimit:"",allowNegativeNumbers:!1,validation:!0,specialCharacters:["-","/","(",")",".",":"," ","+",",","@","[","]",'"',"'"],leadZeroDateTime:!1,triggerOnMaskChange:!1,maskFilled:new ue,patterns:{0:{pattern:new RegExp("\\d")},9:{pattern:new RegExp("\\d"),optional:!0},X:{pattern:new RegExp("\\d"),symbol:"*"},A:{pattern:new RegExp("[a-zA-Z0-9]")},S:{pattern:new RegExp("[a-zA-Z]")},U:{pattern:new RegExp("[A-Z]")},L:{pattern:new RegExp("[a-z]")},d:{pattern:new RegExp("\\d")},m:{pattern:new RegExp("\\d")},M:{pattern:new RegExp("\\d")},H:{pattern:new RegExp("\\d")},h:{pattern:new RegExp("\\d")},s:{pattern:new RegExp("\\d")}}}; +const wM=new q("ngx-mask config"),SM=new q("new ngx-mask config"),MM=new q("initial ngx-mask config"),_B={suffix:"",prefix:"",thousandSeparator:" ",decimalMarker:[".",","],clearIfNotMatch:!1,showTemplate:!1,showMaskTyped:!1,placeHolderCharacter:"_",dropSpecialCharacters:!0,hiddenInput:void 0,shownMaskExpression:"",separatorLimit:"",allowNegativeNumbers:!1,validation:!0,specialCharacters:["-","/","(",")",".",":"," ","+",",","@","[","]",'"',"'"],leadZeroDateTime:!1,triggerOnMaskChange:!1,maskFilled:new ue,patterns:{0:{pattern:new RegExp("\\d")},9:{pattern:new RegExp("\\d"),optional:!0},X:{pattern:new RegExp("\\d"),symbol:"*"},A:{pattern:new RegExp("[a-zA-Z0-9]")},S:{pattern:new RegExp("[a-zA-Z]")},U:{pattern:new RegExp("[A-Z]")},L:{pattern:new RegExp("[a-z]")},d:{pattern:new RegExp("\\d")},m:{pattern:new RegExp("\\d")},M:{pattern:new RegExp("\\d")},H:{pattern:new RegExp("\\d")},h:{pattern:new RegExp("\\d")},s:{pattern:new RegExp("\\d")}}}; /** * @license * Copyright Google LLC All Rights Reserved. @@ -1906,7 +1906,7 @@ const wE=new q("ngx-mask config"),SE=new q("new ngx-mask config"),EE=new q("init * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */let vH=(()=>{class e{constructor(t){this._config=t,this.maskExpression="",this.actualValue="",this.shownMaskExpression="",this._formatWithSeparators=(i,r,o,s)=>{let a=[],l="";if(Array.isArray(o)){const v=new RegExp(o.map(y=>"[\\^$.|?*+()".indexOf(y)>=0?`\\${y}`:y).join("|"));a=i.split(v),l=i.match(v)?.[0]??""}else a=i.split(o),l=o;const u=a.length>1?`${l}${a[1]}`:"";let f=a[0]??"";const p=this.separatorLimit.replace(/\s/g,"");p&&+p&&(f="-"===f[0]?`-${f.slice(1,f.length).slice(0,p.length)}`:f.slice(0,p.length));const m=/(\d+)(\d{3})/;for(;r&&m.test(f);)f=f.replace(m,"$1"+r+"$2");return void 0===s?f+u:0===s?f:f+u.substring(0,s+1)},this.percentage=i=>Number(i)>=0&&Number(i)<=100,this.getPrecision=i=>{const r=i.split(".");return r.length>1?Number(r[r.length-1]):1/0},this.checkAndRemoveSuffix=i=>{for(let r=this.suffix?.length-1;r>=0;r--){const o=this.suffix.substring(r,this.suffix?.length);if(i.includes(o)&&r!==this.suffix?.length-1&&(r-1<0||!i.includes(this.suffix.substring(r-1,this.suffix?.length))))return i.replace(o,"")}return i},this.checkInputPrecision=(i,r,o)=>{if(r<1/0){if(Array.isArray(o)){const u=o.find(f=>f!==this.thousandSeparator);o=u||o[0]}const s=new RegExp(this._charToRegExpExpression(o)+`\\d{${r}}.*$`),l=(i.match(s)??[])[0]?.length??0;l-1>r&&(i=i.substring(0,i.length-(l-1-r))),0===r&&this._compareOrIncludes(i[i.length-1],o,this.thousandSeparator)&&(i=i.substring(0,i.length-1))}return i},this._shift=new Set,this.clearIfNotMatch=this._config.clearIfNotMatch,this.dropSpecialCharacters=this._config.dropSpecialCharacters,this.maskSpecialCharacters=this._config.specialCharacters,this.maskAvailablePatterns=this._config.patterns,this.prefix=this._config.prefix,this.suffix=this._config.suffix,this.thousandSeparator=this._config.thousandSeparator,this.decimalMarker=this._config.decimalMarker,this.hiddenInput=this._config.hiddenInput,this.showMaskTyped=this._config.showMaskTyped,this.placeHolderCharacter=this._config.placeHolderCharacter,this.validation=this._config.validation,this.separatorLimit=this._config.separatorLimit,this.allowNegativeNumbers=this._config.allowNegativeNumbers,this.leadZeroDateTime=this._config.leadZeroDateTime}applyMaskWithPattern(t,i){const[r,o]=i;return this.customPattern=o,this.applyMask(t,r)}applyMask(t,i,r=0,o=!1,s=!1,a=(()=>{})){if(!i||"string"!=typeof t)return"";let l=0,u="",f=!1,p=!1,m=1,v=!1;t.slice(0,this.prefix.length)===this.prefix&&(t=t.slice(this.prefix.length,t.length)),this.suffix&&t?.length>0&&(t=this.checkAndRemoveSuffix(t));const y=t.toString().split("");if("IP"===i){const O=t.split(".");this.ipError=this._validIP(O),i="099.099.099.099"}const D=[];for(let O=0;O11?"00.000.000/0000-00":"000.000.000-00"),i.startsWith("percent")){if(t.match("[a-z]|[A-Z]")||t.match(/[-!$%^&*()_+|~=`{}\[\]:";'<>?,\/.]/)){t=this._stripToDecimal(t);const O=this.getPrecision(i);t=this.checkInputPrecision(t,O,this.decimalMarker)}t.indexOf(".")>0&&!this.percentage(t.substring(0,t.indexOf(".")))&&(t=`${t.substring(0,t.indexOf(".")-1)}${t.substring(t.indexOf("."),t.length)}`),u=this.percentage(t)?t:t.substring(0,t.length-1)}else if(i.startsWith("separator")){(t.match("[w\u0430-\u044f\u0410-\u042f]")||t.match("[\u0401\u0451\u0410-\u044f]")||t.match("[a-z]|[A-Z]")||t.match(/[-@#!$%\\^&*()_\xa3\xac'+|~=`{}\]:";<>.?/]/)||t.match("[^A-Za-z0-9,]"))&&(t=this._stripToDecimal(t)),t=t.length>1&&"0"===t[0]&&t[1]!==this.thousandSeparator&&!this._compareOrIncludes(t[1],this.decimalMarker,this.thousandSeparator)&&!s?t.slice(0,t.length-1):t,s&&(t=this._compareOrIncludes(t[t.length-1],this.decimalMarker,this.thousandSeparator)?t.slice(0,t.length-1):t);const O=this._charToRegExpExpression(this.thousandSeparator);let R='@#!$%^&*()_+|~=`{}\\[\\]:\\s,\\.";<>?\\/'.replace(O,"");if(Array.isArray(this.decimalMarker))for(const Ie of this.decimalMarker)R=R.replace(this._charToRegExpExpression(Ie),"");else R=R.replace(this._charToRegExpExpression(this.decimalMarker),"");const U=new RegExp("["+R+"]");(t.match(U)||1===t.length&&this._compareOrIncludes(t,this.decimalMarker,this.thousandSeparator))&&(t=t.substring(0,t.length-1));const ge=this.getPrecision(i),Ce=(t=this.checkInputPrecision(t,ge,this.decimalMarker)).replace(new RegExp(O,"g"),"");u=this._formatWithSeparators(Ce,this.thousandSeparator,this.decimalMarker,ge);const Ye=u.indexOf(",")-t.indexOf(","),Le=u.length-t.length;if(Le>0&&","!==u[r]){p=!0;let Ie=0;do{this._shift.add(r+Ie),Ie++}while(Ie0&&!(u.indexOf(",")>=r&&r>3)||!(u.indexOf(".")>=r&&r>3)&&Le<=0?(this._shift.clear(),p=!0,m=Le,this._shift.add(r+=Le)):this._shift.clear()}else for(let O=0,R=y[0];O2){l+=1,this._shiftStep(i,l,y.length),O--,this.leadZeroDateTime&&(u+="0");continue}if("h"===i[l]&&"2"===u&&Number(R)>3){l+=1,O--;continue}if("m"===i[l]&&Number(R)>5){l+=1,this._shiftStep(i,l,y.length),O--,this.leadZeroDateTime&&(u+="0");continue}if("s"===i[l]&&Number(R)>5){l+=1,this._shiftStep(i,l,y.length),O--,this.leadZeroDateTime&&(u+="0");continue}const U=31;if("d"===i[l]&&(Number(R)>3&&this.leadZeroDateTime||Number(t.slice(l,l+2))>U||"/"===t[l+1])){l+=1,this._shiftStep(i,l,y.length),O--,this.leadZeroDateTime&&(u+="0");continue}if("M"===i[l]){const Ce=0===l&&(Number(R)>2||Number(t.slice(l,l+2))>12||"/"===t[l+1]),Ye=t.slice(l-3,l-1).includes("/")&&("/"===t[l-2]&&Number(t.slice(l-1,l+1))>12&&"/"!==t[l]||"/"===t[l]||"/"===t[l-3]&&Number(t.slice(l-2,l))>12&&"/"!==t[l-1]||"/"===t[l-1]),Le=Number(t.slice(l-3,l-1))<=U&&!t.slice(l-3,l-1).includes("/")&&"/"===t[l-1]&&(Number(t.slice(l,l+2))>12||"/"===t[l+1]),Ie=Number(t.slice(l-3,l-1))>U&&!t.slice(l-3,l-1).includes("/")&&!t.slice(l-2,l).includes("/")&&Number(t.slice(l-2,l))>12,cn=Number(t.slice(l-3,l-1))<=U&&!t.slice(l-3,l-1).includes("/")&&"/"!==t[l-1]&&Number(t.slice(l-1,l+1))>12;if(Number(R)>1&&this.leadZeroDateTime||Ce||Ye||Le||Ie||cn){l+=1,this._shiftStep(i,l,y.length),O--,this.leadZeroDateTime&&(u+="0");continue}}u+=R,l++}else" "===R&&" "===i[l]?(u+=R,l++):-1!==this.maskSpecialCharacters.indexOf(i[l]??"")?(u+=i[l],l++,this._shiftStep(i,l,y.length),O--):this.maskSpecialCharacters.indexOf(R)>-1&&this.maskAvailablePatterns[i[l]??""]&&this.maskAvailablePatterns[i[l]??""]?.optional?(!!y[l]&&"099.099.099.099"!==i&&"000.000.000-00"!==i&&"00.000.000/0000-00"!==i&&!i.match(/^9+\.0+$/)&&(u+=y[l]),l++,O--):"*"===this.maskExpression[l+1]&&this._findSpecialChar(this.maskExpression[l+2]??"")&&this._findSpecialChar(R)===this.maskExpression[l+2]&&f||"?"===this.maskExpression[l+1]&&this._findSpecialChar(this.maskExpression[l+2]??"")&&this._findSpecialChar(R)===this.maskExpression[l+2]&&f?(l+=3,u+=R):this.showMaskTyped&&this.maskSpecialCharacters.indexOf(R)<0&&R!==this.placeHolderCharacter&&(v=!0);u.length+1===i.length&&-1!==this.maskSpecialCharacters.indexOf(i[i.length-1]??"")&&(u+=i[i.length-1]);let w=r+1;for(;this._shift.has(w);)m++,w++;let M=o&&!i.startsWith("separator")?l:this._shift.has(r)?m:0;v&&M--,a(M,p),m<0&&this._shift.clear();let I=!1;s&&(I=y.every(O=>this.maskSpecialCharacters.includes(O)));let S=`${this.prefix}${I?"":u}${this.suffix}`;return 0===u.length&&(S=`${this.prefix}${u}`),S}_findSpecialChar(t){return this.maskSpecialCharacters.find(i=>i===t)}_checkSymbolMask(t,i){return this.maskAvailablePatterns=this.customPattern?this.customPattern:this.maskAvailablePatterns,(this.maskAvailablePatterns[i]?.pattern&&this.maskAvailablePatterns[i]?.pattern.test(t))??!1}_stripToDecimal(t){return t.split("").filter((i,r)=>{const o="string"==typeof this.decimalMarker?i===this.decimalMarker:this.decimalMarker.includes(i);return i.match("^-?\\d")||i===this.thousandSeparator||o||"-"===i&&0===r&&this.allowNegativeNumbers}).join("")}_charToRegExpExpression(t){return t&&(" "===t?"\\s":"[\\^$.|?*+()".indexOf(t)>=0?`\\${t}`:t)}_shiftStep(t,i,r){const o=/[*?]/g.test(t.slice(0,i))?r:i;this._shift.add(o+this.prefix.length||0)}_compareOrIncludes(t,i,r){return Array.isArray(i)?i.filter(o=>o!==r).includes(t):t===i}_validIP(t){return!(4===t.length&&!t.some((i,r)=>t.length!==r+1?""===i||Number(i)>255:""===i||Number(i.substring(0,3))>255))}}return e.\u0275fac=function(t){return new(t||e)(L(wE))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})();function yH(e,n){return n instanceof Function?{...e,...n()}:{...e,...n}}let bH=(()=>{class e{static forRoot(t){return{ngModule:e,providers:[{provide:SE,useValue:t},{provide:EE,useValue:_H},{provide:wE,useFactory:yH,deps:[EE,SE]},vH]}}static forChild(){return{ngModule:e}}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ne({type:e}),e.\u0275inj=Me({}),e})();const ME=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};ME.KeyboardEvent||(ME.KeyboardEvent=function(e,n){});let NE=(()=>{class e{constructor(t,i){this.document=t,this.platformId=i,this.documentIsAccessible=function RC(e){return e===kC}(this.platformId)}static getCookieRegExp(t){const i=t.replace(/([\[\]\{\}\(\)\|\=\;\+\?\,\.\*\^\$])/gi,"\\$1");return new RegExp("(?:^"+i+"|;\\s*"+i+")=(.*?)(?:;|$)","g")}static safeDecodeURIComponent(t){try{return decodeURIComponent(t)}catch{return t}}check(t){return!!this.documentIsAccessible&&(t=encodeURIComponent(t),e.getCookieRegExp(t).test(this.document.cookie))}get(t){if(this.documentIsAccessible&&this.check(t)){t=encodeURIComponent(t);const r=e.getCookieRegExp(t).exec(this.document.cookie);return r[1]?e.safeDecodeURIComponent(r[1]):""}return""}getAll(){if(!this.documentIsAccessible)return{};const t={},i=this.document;return i.cookie&&""!==i.cookie&&i.cookie.split(";").forEach(r=>{const[o,s]=r.split("=");t[e.safeDecodeURIComponent(o.replace(/^ /,""))]=e.safeDecodeURIComponent(s)}),t}set(t,i,r,o,s,a,l){if(!this.documentIsAccessible)return;if("number"==typeof r||r instanceof Date||o||s||a||l)return void this.set(t,i,{expires:r,path:o,domain:s,secure:a,sameSite:l||"Lax"});let u=encodeURIComponent(t)+"="+encodeURIComponent(i)+";";const f=r||{};f.expires&&(u+="number"==typeof f.expires?"expires="+new Date((new Date).getTime()+1e3*f.expires*60*60*24).toUTCString()+";":"expires="+f.expires.toUTCString()+";"),f.path&&(u+="path="+f.path+";"),f.domain&&(u+="domain="+f.domain+";"),!1===f.secure&&"None"===f.sameSite&&(f.secure=!0,console.warn(`[ngx-cookie-service] Cookie ${t} was forced with secure flag because sameSite=None.More details : https://github.com/stevermeister/ngx-cookie-service/issues/86#issuecomment-597720130`)),f.secure&&(u+="secure;"),f.sameSite||(f.sameSite="Lax"),u+="sameSite="+f.sameSite+";",this.document.cookie=u}delete(t,i,r,o,s="Lax"){if(!this.documentIsAccessible)return;const a=new Date("Thu, 01 Jan 1970 00:00:01 GMT");this.set(t,"",{expires:a,path:i,domain:r,secure:o,sameSite:s})}deleteAll(t,i,r,o="Lax"){if(!this.documentIsAccessible)return;const s=this.getAll();for(const a in s)s.hasOwnProperty(a)&&this.delete(a,t,i,r,o)}}return e.\u0275fac=function(t){return new(t||e)(L(Dt),L(dc))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})();const DH=[];let CH=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ne({type:e}),e.\u0275inj=Me({imports:[Cf.forRoot(DH),Cf]}),e})(),wH=(()=>{class e{constructor(){this.title="dashboard"}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275cmp=et({type:e,selectors:[["app-root"]],decls:1,vars:0,template:function(t,i){1&t&&Li(0,"router-outlet")},dependencies:[d_],encapsulation:2}),e})();const SH=["addListener","removeListener"],EH=["addEventListener","removeEventListener"],MH=["on","off"];function Rn(e,n,t,i){if(ye(t)&&(i=t,t=void 0),i)return Rn(e,n,t).pipe(zm(i));const[r,o]=function AH(e){return ye(e.addEventListener)&&ye(e.removeEventListener)}(e)?EH.map(s=>a=>e[s](n,a,t)):function NH(e){return ye(e.addListener)&&ye(e.removeListener)}(e)?SH.map(TE(e,n)):function TH(e){return ye(e.on)&&ye(e.off)}(e)?MH.map(TE(e,n)):[];if(!r&&Ts(e))return dt(s=>Rn(s,n,t))(ut(e));if(!r)throw new TypeError("Invalid event target");return new je(s=>{const a=(...l)=>s.next(1o(a)})}function TE(e,n){return t=>i=>e[t](n,i)}class IH extends Ct{constructor(n,t){super()}schedule(n,t=0){return this}}const Rf={setInterval(e,n,...t){const{delegate:i}=Rf;return i?.setInterval?i.setInterval(e,n,...t):setInterval(e,n,...t)},clearInterval(e){const{delegate:n}=Rf;return(n?.clearInterval||clearInterval)(e)},delegate:void 0},AE={now:()=>(AE.delegate||Date).now(),delegate:void 0};class Bc{constructor(n,t=Bc.now){this.schedulerActionCtor=n,this.now=t}schedule(n,t=0,i){return new this.schedulerActionCtor(this,n).schedule(i,t)}}Bc.now=AE.now;const xf=new class kH extends Bc{constructor(n,t=Bc.now){super(n,t),this.actions=[],this._active=!1}flush(n){const{actions:t}=this;if(this._active)return void t.push(n);let i;this._active=!0;do{if(i=n.execute(n.state,n.delay))break}while(n=t.shift());if(this._active=!1,i){for(;n=t.shift();)n.unsubscribe();throw i}}}(class OH extends IH{constructor(n,t){super(n,t),this.scheduler=n,this.work=t,this.pending=!1}schedule(n,t=0){var i;if(this.closed)return this;this.state=n;const r=this.id,o=this.scheduler;return null!=r&&(this.id=this.recycleAsyncId(o,r,t)),this.pending=!0,this.delay=t,this.id=null!==(i=this.id)&&void 0!==i?i:this.requestAsyncId(o,this.id,t),this}requestAsyncId(n,t,i=0){return Rf.setInterval(n.flush.bind(n,this),i)}recycleAsyncId(n,t,i=0){if(null!=i&&this.delay===i&&!1===this.pending)return t;null!=t&&Rf.clearInterval(t)}execute(n,t){if(this.closed)return new Error("executing a cancelled action");this.pending=!1;const i=this._execute(n,t);if(i)return i;!1===this.pending&&null!=this.id&&(this.id=this.recycleAsyncId(this.scheduler,this.id,null))}_execute(n,t){let r,i=!1;try{this.work(n)}catch(o){i=!0,r=o||new Error("Scheduled action threw falsy error")}if(i)return this.unsubscribe(),r}unsubscribe(){if(!this.closed){const{id:n,scheduler:t}=this,{actions:i}=t;this.work=this.state=this.scheduler=null,this.pending=!1,dn(i,this),null!=n&&(this.id=this.recycleAsyncId(t,n,null)),this.delay=null,super.unsubscribe()}}}),RH=xf;function jc(e=0,n,t=RH){let i=-1;return null!=n&&(si(n)?t=n:i=n),new je(r=>{let o=function xH(e){return e instanceof Date&&!isNaN(e)}(e)?+e-t.now():e;o<0&&(o=0);let s=0;return t.schedule(function(){r.closed||(r.next(s++),0<=i?this.schedule(void 0,i):r.complete())},o)})}const{isArray:FH}=Array;function IE(e){return 1===e.length&&FH(e[0])?e[0]:e}function Ff(...e){const n=rt(e),t=IE(e);return t.length?new je(i=>{let r=t.map(()=>[]),o=t.map(()=>!1);i.add(()=>{r=o=null});for(let s=0;!i.closed&&s{if(r[s].push(a),r.every(l=>l.length)){const l=r.map(u=>u.shift());i.next(n?n(...l):l),r.some((u,f)=>!u.length&&o[f])&&i.complete()}},()=>{o[s]=!0,!r[s].length&&i.complete()}));return()=>{r=o=null}}):Xt}function Vt(e){return qe((n,t)=>{ut(e).subscribe(ke(t,()=>t.complete(),Dn)),!t.closed&&n.subscribe(t)})}function Y_(...e){const n=rt(e);return qe((t,i)=>{const r=e.length,o=new Array(r);let s=e.map(()=>!1),a=!1;for(let l=0;l{o[l]=u,!a&&!s[l]&&(s[l]=!0,(a=s.every(xn))&&(s=null))},Dn));t.subscribe(ke(i,l=>{if(a){const u=[l,...o];i.next(n?n(...u):u)}}))})}function QB(e,n){if(1&e){const t=At();E(0,"button",1),W("click",function(){return mt(t),_t(K().close())}),T()}}new je(Dn),Math,Math,Math;const JE=["*"],mj=["dialog"];function sv(e){return"string"==typeof e}function fs(e){return null!=e}function Ka(e){return(e||document.body).getBoundingClientRect()}const QE={animation:!0,transitionTimerDelayMs:5},u$=()=>{},{transitionTimerDelayMs:d$}=QE,Yc=new Map,bn=(e,n,t,i)=>{let r=i.context||{};const o=Yc.get(n);if(o)switch(i.runningTransition){case"continue":return Xt;case"stop":e.run(()=>o.transition$.complete()),r=Object.assign(o.context,r),Yc.delete(n)}const s=t(n,i.animation,r)||u$;if(!i.animation||"none"===window.getComputedStyle(n).transitionProperty)return e.run(()=>s()),Z(void 0).pipe(function l$(e){return n=>new je(t=>n.subscribe({next:s=>e.run(()=>t.next(s)),error:s=>e.run(()=>t.error(s)),complete:()=>e.run(()=>t.complete())}))}(e));const a=new Ue,l=new Ue,u=a.pipe(function LH(...e){return n=>Dc(n,Z(...e))}(!0));Yc.set(n,{transition$:a,complete:()=>{l.next(),l.complete()},context:r});const f=function c$(e){const{transitionDelay:n,transitionDuration:t}=window.getComputedStyle(e);return 1e3*(parseFloat(n)+parseFloat(t))}(n);return e.runOutsideAngular(()=>{const p=Rn(n,"transitionend").pipe(Vt(u),vn(({target:v})=>v===n));(function OE(...e){return 1===(e=IE(e)).length?ut(e[0]):new je(function PH(e){return n=>{let t=[];for(let i=0;t&&!n.closed&&i{if(t){for(let o=0;o{Yc.delete(n),e.run(()=>{s(),a.next(),a.complete()})})}),a.asObservable()};let qc=(()=>{class e{constructor(){this.animation=QE.animation}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(),rM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ne({type:e}),e.\u0275inj=Me({imports:[ei]}),e})();const _$=({classList:e})=>{e.remove("show")};let v$=(()=>{class e{constructor(t){this._ngbConfig=t,this.dismissible=!0,this.type="warning"}get animation(){return void 0===this._animation?this._ngbConfig.animation:this._animation}set animation(t){this._animation=t}}return e.\u0275fac=function(t){return new(t||e)(L(qc))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(),y$=(()=>{class e{constructor(t,i,r,o){this._renderer=i,this._element=r,this._zone=o,this.closed=new ue,this.dismissible=t.dismissible,this.type=t.type,this.animation=t.animation}close(){const t=bn(this._zone,this._element.nativeElement,_$,{animation:this.animation,runningTransition:"continue"});return t.subscribe(()=>this.closed.emit()),t}ngOnChanges(t){const i=t.type;i&&!i.firstChange&&(this._renderer.removeClass(this._element.nativeElement,`alert-${i.previousValue}`),this._renderer.addClass(this._element.nativeElement,`alert-${i.currentValue}`))}ngOnInit(){this._renderer.addClass(this._element.nativeElement,`alert-${this.type}`)}}return e.\u0275fac=function(t){return new(t||e)(C(v$),C(pi),C(Ze),C(ze))},e.\u0275cmp=et({type:e,selectors:[["ngb-alert"]],hostAttrs:["role","alert",1,"alert","show"],hostVars:4,hostBindings:function(t,i){2&t&&ht("fade",i.animation)("alert-dismissible",i.dismissible)},inputs:{animation:"animation",dismissible:"dismissible",type:"type"},outputs:{closed:"closed"},exportAs:["ngbAlert"],features:[Kt],ngContentSelectors:JE,decls:2,vars:1,consts:function(){let n;return n=$localize`:@@ngb.alert.close:Close`,[["type","button","class","btn-close","aria-label",n,3,"click",4,"ngIf"],["type","button","aria-label",n,1,"btn-close",3,"click"]]},template:function(t,i){1&t&&(Fg(),Pg(0),J(1,QB,1,0,"button",0)),2&t&&(F(1),Q("ngIf",i.dismissible))},dependencies:[ns],styles:["ngb-alert{display:block}\n"],encapsulation:2,changeDetection:0}),e})(),oM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ne({type:e}),e.\u0275inj=Me({imports:[ei]}),e})(),lM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ne({type:e}),e.\u0275inj=Me({imports:[ei]}),e})(),cM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ne({type:e}),e.\u0275inj=Me({}),e})();var Ht=(()=>{return(e=Ht||(Ht={}))[e.Tab=9]="Tab",e[e.Enter=13]="Enter",e[e.Escape=27]="Escape",e[e.Space=32]="Space",e[e.PageUp=33]="PageUp",e[e.PageDown=34]="PageDown",e[e.End=35]="End",e[e.Home=36]="Home",e[e.ArrowLeft=37]="ArrowLeft",e[e.ArrowUp=38]="ArrowUp",e[e.ArrowRight=39]="ArrowRight",e[e.ArrowDown=40]="ArrowDown",Ht;var e})();typeof navigator<"u"&&navigator.userAgent&&(/iPad|iPhone|iPod/.test(navigator.userAgent)||/Macintosh/.test(navigator.userAgent)&&navigator.maxTouchPoints&&navigator.maxTouchPoints>2||/Android/.test(navigator.userAgent));const dM=["a[href]","button:not([disabled])",'input:not([disabled]):not([type="hidden"])',"select:not([disabled])","textarea:not([disabled])","[contenteditable]",'[tabindex]:not([tabindex="-1"])'].join(", ");function fM(e){const n=Array.from(e.querySelectorAll(dM)).filter(t=>-1!==t.tabIndex);return[n[0],n[n.length-1]]}new Date(1882,10,12),new Date(2174,10,25);let bM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ne({type:e}),e.\u0275inj=Me({imports:[ei,CE]}),e})(),hv=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275dir=H({type:e,selectors:[["",8,"navbar"]]}),e})(),wM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ne({type:e}),e.\u0275inj=Me({}),e})();class ms{constructor(n,t,i){this.nodes=n,this.viewRef=t,this.componentRef=i}}let iU=(()=>{class e{constructor(t,i){this._el=t,this._zone=i}ngOnInit(){this._zone.onStable.asObservable().pipe(sn(1)).subscribe(()=>{bn(this._zone,this._el.nativeElement,(t,i)=>{i&&Ka(t),t.classList.add("show")},{animation:this.animation,runningTransition:"continue"})})}hide(){return bn(this._zone,this._el.nativeElement,({classList:t})=>t.remove("show"),{animation:this.animation,runningTransition:"stop"})}}return e.\u0275fac=function(t){return new(t||e)(C(Ze),C(ze))},e.\u0275cmp=et({type:e,selectors:[["ngb-modal-backdrop"]],hostAttrs:[2,"z-index","1055"],hostVars:6,hostBindings:function(t,i){2&t&&(Zo("modal-backdrop"+(i.backdropClass?" "+i.backdropClass:"")),ht("show",!i.animation)("fade",i.animation))},inputs:{animation:"animation",backdropClass:"backdropClass"},decls:0,vars:0,template:function(t,i){},encapsulation:2}),e})();class pr{close(n){}dismiss(n){}}class rU{constructor(n,t,i,r){this._windowCmptRef=n,this._contentRef=t,this._backdropCmptRef=i,this._beforeDismiss=r,this._closed=new Ue,this._dismissed=new Ue,this._hidden=new Ue,n.instance.dismissEvent.subscribe(o=>{this.dismiss(o)}),this.result=new Promise((o,s)=>{this._resolve=o,this._reject=s}),this.result.then(null,()=>{})}get componentInstance(){if(this._contentRef&&this._contentRef.componentRef)return this._contentRef.componentRef.instance}get closed(){return this._closed.asObservable().pipe(Vt(this._hidden))}get dismissed(){return this._dismissed.asObservable().pipe(Vt(this._hidden))}get hidden(){return this._hidden.asObservable()}get shown(){return this._windowCmptRef.instance.shown.asObservable()}close(n){this._windowCmptRef&&(this._closed.next(n),this._resolve(n),this._removeModalElements())}_dismiss(n){this._dismissed.next(n),this._reject(n),this._removeModalElements()}dismiss(n){if(this._windowCmptRef)if(this._beforeDismiss){const t=this._beforeDismiss();!function ZE(e){return e&&e.then}(t)?!1!==t&&this._dismiss(n):t.then(i=>{!1!==i&&this._dismiss(n)},()=>{})}else this._dismiss(n)}_removeModalElements(){const n=this._windowCmptRef.instance.hide(),t=this._backdropCmptRef?this._backdropCmptRef.instance.hide():Z(void 0);n.subscribe(()=>{const{nativeElement:i}=this._windowCmptRef.location;i.parentNode.removeChild(i),this._windowCmptRef.destroy(),this._contentRef&&this._contentRef.viewRef&&this._contentRef.viewRef.destroy(),this._windowCmptRef=null,this._contentRef=null}),t.subscribe(()=>{if(this._backdropCmptRef){const{nativeElement:i}=this._backdropCmptRef.location;i.parentNode.removeChild(i),this._backdropCmptRef.destroy(),this._backdropCmptRef=null}}),Ff(n,t).subscribe(()=>{this._hidden.next(),this._hidden.complete()})}}var Xc=(()=>{return(e=Xc||(Xc={}))[e.BACKDROP_CLICK=0]="BACKDROP_CLICK",e[e.ESC=1]="ESC",Xc;var e})();let oU=(()=>{class e{constructor(t,i,r){this._document=t,this._elRef=i,this._zone=r,this._closed$=new Ue,this._elWithFocus=null,this.backdrop=!0,this.keyboard=!0,this.dismissEvent=new ue,this.shown=new Ue,this.hidden=new Ue}get fullscreenClass(){return!0===this.fullscreen?" modal-fullscreen":sv(this.fullscreen)?` modal-fullscreen-${this.fullscreen}-down`:""}dismiss(t){this.dismissEvent.emit(t)}ngOnInit(){this._elWithFocus=this._document.activeElement,this._zone.onStable.asObservable().pipe(sn(1)).subscribe(()=>{this._show()})}ngOnDestroy(){this._disableEventHandling()}hide(){const{nativeElement:t}=this._elRef,i={animation:this.animation,runningTransition:"stop"},s=Ff(bn(this._zone,t,()=>t.classList.remove("show"),i),bn(this._zone,this._dialogEl.nativeElement,()=>{},i));return s.subscribe(()=>{this.hidden.next(),this.hidden.complete()}),this._disableEventHandling(),this._restoreFocus(),s}_show(){const t={animation:this.animation,runningTransition:"continue"};Ff(bn(this._zone,this._elRef.nativeElement,(o,s)=>{s&&Ka(o),o.classList.add("show")},t),bn(this._zone,this._dialogEl.nativeElement,()=>{},t)).subscribe(()=>{this.shown.next(),this.shown.complete()}),this._enableEventHandling(),this._setFocus()}_enableEventHandling(){const{nativeElement:t}=this._elRef;this._zone.runOutsideAngular(()=>{Rn(t,"keydown").pipe(Vt(this._closed$),vn(r=>r.which===Ht.Escape)).subscribe(r=>{this.keyboard?requestAnimationFrame(()=>{r.defaultPrevented||this._zone.run(()=>this.dismiss(Xc.ESC))}):"static"===this.backdrop&&this._bumpBackdrop()});let i=!1;Rn(this._dialogEl.nativeElement,"mousedown").pipe(Vt(this._closed$),Yt(()=>i=!1),vi(()=>Rn(t,"mouseup").pipe(Vt(this._closed$),sn(1))),vn(({target:r})=>t===r)).subscribe(()=>{i=!0}),Rn(t,"click").pipe(Vt(this._closed$)).subscribe(({target:r})=>{t===r&&("static"===this.backdrop?this._bumpBackdrop():!0===this.backdrop&&!i&&this._zone.run(()=>this.dismiss(Xc.BACKDROP_CLICK))),i=!1})})}_disableEventHandling(){this._closed$.next()}_setFocus(){const{nativeElement:t}=this._elRef;if(!t.contains(document.activeElement)){const i=t.querySelector("[ngbAutofocus]"),r=fM(t)[0];(i||r||t).focus()}}_restoreFocus(){const t=this._document.body,i=this._elWithFocus;let r;r=i&&i.focus&&t.contains(i)?i:t,this._zone.runOutsideAngular(()=>{setTimeout(()=>r.focus()),this._elWithFocus=null})}_bumpBackdrop(){"static"===this.backdrop&&bn(this._zone,this._elRef.nativeElement,({classList:t})=>(t.add("modal-static"),()=>t.remove("modal-static")),{animation:this.animation,runningTransition:"continue"})}}return e.\u0275fac=function(t){return new(t||e)(C(Dt),C(Ze),C(ze))},e.\u0275cmp=et({type:e,selectors:[["ngb-modal-window"]],viewQuery:function(t,i){if(1&t&&Md(mj,7),2&t){let r;at(r=lt())&&(i._dialogEl=r.first)}},hostAttrs:["role","dialog","tabindex","-1"],hostVars:7,hostBindings:function(t,i){2&t&&(Ke("aria-modal",!0)("aria-labelledby",i.ariaLabelledBy)("aria-describedby",i.ariaDescribedBy),Zo("modal d-block"+(i.windowClass?" "+i.windowClass:"")),ht("fade",i.animation))},inputs:{animation:"animation",ariaLabelledBy:"ariaLabelledBy",ariaDescribedBy:"ariaDescribedBy",backdrop:"backdrop",centered:"centered",fullscreen:"fullscreen",keyboard:"keyboard",scrollable:"scrollable",size:"size",windowClass:"windowClass",modalDialogClass:"modalDialogClass"},outputs:{dismissEvent:"dismiss"},ngContentSelectors:JE,decls:4,vars:2,consts:[["role","document"],["dialog",""],[1,"modal-content"]],template:function(t,i){1&t&&(Fg(),E(0,"div",0,1)(2,"div",2),Pg(3),T()()),2&t&&Zo("modal-dialog"+(i.size?" modal-"+i.size:"")+(i.centered?" modal-dialog-centered":"")+i.fullscreenClass+(i.scrollable?" modal-dialog-scrollable":"")+(i.modalDialogClass?" "+i.modalDialogClass:""))},styles:["ngb-modal-window .component-host-scrollable{display:flex;flex-direction:column;overflow:hidden}\n"],encapsulation:2}),e})(),sU=(()=>{class e{constructor(t){this._document=t}hide(){const t=Math.abs(window.innerWidth-this._document.documentElement.clientWidth),i=this._document.body,r=i.style,{overflow:o,paddingRight:s}=r;if(t>0){const a=parseFloat(window.getComputedStyle(i).paddingRight);r.paddingRight=`${a+t}px`}return r.overflow="hidden",()=>{t>0&&(r.paddingRight=s),r.overflow=o}}}return e.\u0275fac=function(t){return new(t||e)(L(Dt))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(),aU=(()=>{class e{constructor(t,i,r,o,s,a){this._applicationRef=t,this._injector=i,this._document=r,this._scrollBar=o,this._rendererFactory=s,this._ngZone=a,this._activeWindowCmptHasChanged=new Ue,this._ariaHiddenValues=new Map,this._scrollBarRestoreFn=null,this._backdropAttributes=["animation","backdropClass"],this._modalRefs=[],this._windowAttributes=["animation","ariaLabelledBy","ariaDescribedBy","backdrop","centered","fullscreen","keyboard","scrollable","size","windowClass","modalDialogClass"],this._windowCmpts=[],this._activeInstances=new ue,this._activeWindowCmptHasChanged.subscribe(()=>{if(this._windowCmpts.length){const l=this._windowCmpts[this._windowCmpts.length-1];((e,n,t,i=!1)=>{this._ngZone.runOutsideAngular(()=>{const r=Rn(n,"focusin").pipe(Vt(t),ne(o=>o.target));Rn(n,"keydown").pipe(Vt(t),vn(o=>o.which===Ht.Tab),Y_(r)).subscribe(([o,s])=>{const[a,l]=fM(n);(s===a||s===n)&&o.shiftKey&&(l.focus(),o.preventDefault()),s===l&&!o.shiftKey&&(a.focus(),o.preventDefault())}),i&&Rn(n,"click").pipe(Vt(t),Y_(r),ne(o=>o[1])).subscribe(o=>o.focus())})})(0,l.location.nativeElement,this._activeWindowCmptHasChanged),this._revertAriaHidden(),this._setAriaHidden(l.location.nativeElement)}})}_restoreScrollBar(){const t=this._scrollBarRestoreFn;t&&(this._scrollBarRestoreFn=null,t())}_hideScrollBar(){this._scrollBarRestoreFn||(this._scrollBarRestoreFn=this._scrollBar.hide())}open(t,i,r){const o=r.container instanceof HTMLElement?r.container:fs(r.container)?this._document.querySelector(r.container):this._document.body,s=this._rendererFactory.createRenderer(null,null);if(!o)throw new Error(`The specified modal container "${r.container||"body"}" was not found in the DOM.`);this._hideScrollBar();const a=new pr,l=this._getContentRef(r.injector||t,i,a,r);let u=!1!==r.backdrop?this._attachBackdrop(o):void 0,f=this._attachWindowComponent(o,l.nodes),p=new rU(f,l,u,r.beforeDismiss);return this._registerModalRef(p),this._registerWindowCmpt(f),p.hidden.pipe(sn(1)).subscribe(()=>Promise.resolve(!0).then(()=>{this._modalRefs.length||(s.removeClass(this._document.body,"modal-open"),this._restoreScrollBar(),this._revertAriaHidden())})),a.close=m=>{p.close(m)},a.dismiss=m=>{p.dismiss(m)},this._applyWindowOptions(f.instance,r),1===this._modalRefs.length&&s.addClass(this._document.body,"modal-open"),u&&u.instance&&(this._applyBackdropOptions(u.instance,r),u.changeDetectorRef.detectChanges()),f.changeDetectorRef.detectChanges(),p}get activeInstances(){return this._activeInstances}dismissAll(t){this._modalRefs.forEach(i=>i.dismiss(t))}hasOpenModals(){return this._modalRefs.length>0}_attachBackdrop(t){let i=Dm(iU,{environmentInjector:this._applicationRef.injector,elementInjector:this._injector});return this._applicationRef.attachView(i.hostView),t.appendChild(i.location.nativeElement),i}_attachWindowComponent(t,i){let r=Dm(oU,{environmentInjector:this._applicationRef.injector,elementInjector:this._injector,projectableNodes:i});return this._applicationRef.attachView(r.hostView),t.appendChild(r.location.nativeElement),r}_applyWindowOptions(t,i){this._windowAttributes.forEach(r=>{fs(i[r])&&(t[r]=i[r])})}_applyBackdropOptions(t,i){this._backdropAttributes.forEach(r=>{fs(i[r])&&(t[r]=i[r])})}_getContentRef(t,i,r,o){return i?i instanceof bt?this._createFromTemplateRef(i,r):sv(i)?this._createFromString(i):this._createFromComponent(t,i,r,o):new ms([])}_createFromTemplateRef(t,i){const o=t.createEmbeddedView({$implicit:i,close(s){i.close(s)},dismiss(s){i.dismiss(s)}});return this._applicationRef.attachView(o),new ms([o.rootNodes],o)}_createFromString(t){const i=this._document.createTextNode(`${t}`);return new ms([[i]])}_createFromComponent(t,i,r,o){const s=gn.create({providers:[{provide:pr,useValue:r}],parent:t}),a=Dm(i,{environmentInjector:this._applicationRef.injector,elementInjector:s}),l=a.location.nativeElement;return o.scrollable&&l.classList.add("component-host-scrollable"),this._applicationRef.attachView(a.hostView),new ms([[l]],a.hostView,a)}_setAriaHidden(t){const i=t.parentElement;i&&t!==this._document.body&&(Array.from(i.children).forEach(r=>{r!==t&&"SCRIPT"!==r.nodeName&&(this._ariaHiddenValues.set(r,r.getAttribute("aria-hidden")),r.setAttribute("aria-hidden","true"))}),this._setAriaHidden(i))}_revertAriaHidden(){this._ariaHiddenValues.forEach((t,i)=>{t?i.setAttribute("aria-hidden",t):i.removeAttribute("aria-hidden")}),this._ariaHiddenValues.clear()}_registerModalRef(t){const i=()=>{const r=this._modalRefs.indexOf(t);r>-1&&(this._modalRefs.splice(r,1),this._activeInstances.emit(this._modalRefs))};this._modalRefs.push(t),this._activeInstances.emit(this._modalRefs),t.result.then(i,i)}_registerWindowCmpt(t){this._windowCmpts.push(t),this._activeWindowCmptHasChanged.next(),t.onDestroy(()=>{const i=this._windowCmpts.indexOf(t);i>-1&&(this._windowCmpts.splice(i,1),this._activeWindowCmptHasChanged.next())})}}return e.\u0275fac=function(t){return new(t||e)(L(fc),L(gn),L(Dt),L(sU),L(xp),L(ze))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(),lU=(()=>{class e{constructor(t){this._ngbConfig=t,this.backdrop=!0,this.fullscreen=!1,this.keyboard=!0}get animation(){return void 0===this._animation?this._ngbConfig.animation:this._animation}set animation(t){this._animation=t}}return e.\u0275fac=function(t){return new(t||e)(L(qc))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(),SM=(()=>{class e{constructor(t,i,r){this._injector=t,this._modalStack=i,this._config=r}open(t,i={}){const r={...this._config,animation:this._config.animation,...i};return this._modalStack.open(this._injector,t,r)}get activeInstances(){return this._modalStack.activeInstances}dismissAll(t){this._modalStack.dismissAll(t)}hasOpenModals(){return this._modalStack.hasOpenModals()}}return e.\u0275fac=function(t){return new(t||e)(L(gn),L(aU),L(lU))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(),EM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ne({type:e}),e.\u0275inj=Me({providers:[SM]}),e})(),AM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ne({type:e}),e.\u0275inj=Me({imports:[ei]}),e})(),LM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ne({type:e}),e.\u0275inj=Me({imports:[ei]}),e})(),HM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ne({type:e}),e.\u0275inj=Me({imports:[ei]}),e})(),BM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ne({type:e}),e.\u0275inj=Me({imports:[ei]}),e})(),jM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ne({type:e}),e.\u0275inj=Me({imports:[ei]}),e})(),$M=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ne({type:e}),e.\u0275inj=Me({imports:[ei]}),e})(),UM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ne({type:e}),e.\u0275inj=Me({imports:[ei]}),e})(),GM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ne({type:e}),e.\u0275inj=Me({}),e})();new q("live announcer delay",{providedIn:"root",factory:function DU(){return 100}});let WM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ne({type:e}),e.\u0275inj=Me({imports:[ei]}),e})(),KM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ne({type:e}),e.\u0275inj=Me({}),e})();const CU=[rM,oM,lM,cM,bM,wM,EM,AM,KM,LM,HM,BM,jM,$M,UM,GM,WM];let wU=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ne({type:e}),e.\u0275inj=Me({imports:[CU,rM,oM,lM,cM,bM,wM,EM,AM,KM,LM,HM,BM,jM,$M,UM,GM,WM]}),e})(),MU=(()=>{class e{constructor(t){this.activeModal=t,this.save=()=>{this.activeModal.close(this.rewindDate)}}}return e.\u0275fac=function(t){return new(t||e)(C(pr))},e.\u0275cmp=et({type:e,selectors:[["app-rewind-modal"]],inputs:{groupId:"groupId",consumerName:"consumerName",topic:"topic"},decls:26,vars:4,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],["for","rewindDate"],[1,"input-group"],["id","rewindDate","placeholder","yyyy-mm-dd hh:MM:ss","type","datetime-local",1,"form-control",3,"ngModel","ngModelChange"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(E(0,"div",0)(1,"h4",1),A(2,"Rewind consumers offset"),T(),E(3,"button",2),W("click",function(){return i.activeModal.dismiss()}),E(4,"span",3),A(5,"\xd7"),T()()(),E(6,"div",4)(7,"div",5)(8,"label",6),A(9,"Select the datetime to rewind all the partition-offsets of the topic "),E(10,"b"),A(11),T(),A(12," from consumers "),E(13,"b"),A(14),T(),A(15," with group id "),E(16,"b"),A(17),T(),A(18,"' "),T(),E(19,"div",7)(20,"input",8),W("ngModelChange",function(o){return i.rewindDate=o}),T()()()(),E(21,"div",9)(22,"button",10),W("click",function(){return i.activeModal.dismiss()}),A(23,"Cancel"),T(),E(24,"button",11),W("click",function(){return i.save()}),A(25,"OK"),T()()),2&t&&(F(11),Be("'",i.topic,"'"),F(3),Be("'",i.consumerName,"'"),F(3),Be("'",i.groupId,""),F(3),Q("ngModel",i.rewindDate))},dependencies:[Fc,A_,kf],encapsulation:2}),e})(),NU=(()=>{class e{constructor(t){this.activeModal=t,this.save=()=>{this.activeModal.close(this.workersCount)}}ngOnInit(){this.oldWorkersCount=this.workersCount}}return e.\u0275fac=function(t){return new(t||e)(C(pr))},e.\u0275cmp=et({type:e,selectors:[["app-workers-count-modal"]],inputs:{workersCount:"workersCount",groupId:"groupId",consumerName:"consumerName"},decls:28,vars:4,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],["for","oldWorkersCount"],[1,"input-group","mb-2"],["id","oldWorkersCount","type","number","readonly","",1,"form-control",3,"ngModel","ngModelChange"],["for","workersCount"],[1,"input-group"],["id","workersCount","type","number",1,"form-control",3,"ngModel","ngModelChange"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(E(0,"div",0)(1,"h4",1),A(2,"Consumer workers running"),T(),E(3,"button",2),W("click",function(){return i.activeModal.dismiss()}),E(4,"span",3),A(5,"\xd7"),T()()(),E(6,"div",4)(7,"div",5)(8,"label"),A(9,"Update the number of workers in consumers "),E(10,"b"),A(11),T(),A(12," from group id "),E(13,"b"),A(14),T()(),E(15,"label",6),A(16,"Current Value"),T(),E(17,"div",7)(18,"input",8),W("ngModelChange",function(o){return i.oldWorkersCount=o}),T()(),E(19,"label",9),A(20,"New Value"),T(),E(21,"div",10)(22,"input",11),W("ngModelChange",function(o){return i.workersCount=o}),T()()()(),E(23,"div",12)(24,"button",13),W("click",function(){return i.activeModal.dismiss()}),A(25,"Cancel"),T(),E(26,"button",14),W("click",function(){return i.save()}),A(27,"OK"),T()()),2&t&&(F(11),Be("'",i.consumerName,"'"),F(3),Be("'",i.groupId,"'"),F(4),Q("ngModel",i.oldWorkersCount),F(4),Q("ngModel",i.workersCount))},dependencies:[Fc,B_,A_,kf],encapsulation:2}),e})(),TU=(()=>{class e{constructor(t){this.activeModal=t}}return e.\u0275fac=function(t){return new(t||e)(C(pr))},e.\u0275cmp=et({type:e,selectors:[["app-reset-modal"]],inputs:{groupId:"groupId",consumerName:"consumerName",topic:"topic"},decls:26,vars:3,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],[1,"mt-3"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(E(0,"div",0)(1,"h4",1),A(2,"Reset consumers offset"),T(),E(3,"button",2),W("click",function(){return i.activeModal.dismiss()}),E(4,"span",3),A(5,"\xd7"),T()()(),E(6,"div",4)(7,"div",5)(8,"span"),A(9,"Reset the partition-offsets can generate a huge lag at the topic "),E(10,"b"),A(11),T(),A(12," to consumers "),E(13,"b"),A(14),T(),A(15," with group id "),E(16,"b"),A(17),T(),A(18,"'. "),T(),E(19,"h5",6),A(20,"Are you really sure about it?"),T()()(),E(21,"div",7)(22,"button",8),W("click",function(){return i.activeModal.dismiss()}),A(23,"No, cancel"),T(),E(24,"button",9),W("click",function(){return i.activeModal.close()}),A(25,"Yes"),T()()),2&t&&(F(11),Be("'",i.topic,"'"),F(3),Be("'",i.consumerName,"'"),F(3),Be("'",i.groupId,""))},encapsulation:2}),e})(),AU=(()=>{class e{constructor(t){this.activeModal=t}}return e.\u0275fac=function(t){return new(t||e)(C(pr))},e.\u0275cmp=et({type:e,selectors:[["app-pause-modal"]],inputs:{groupId:"groupId",consumerName:"consumerName",topic:"topic"},decls:26,vars:3,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],[1,"mt-3"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(E(0,"div",0)(1,"h4",1),A(2,"Pause consumers"),T(),E(3,"button",2),W("click",function(){return i.activeModal.dismiss()}),E(4,"span",3),A(5,"\xd7"),T()()(),E(6,"div",4)(7,"div",5)(8,"span"),A(9,"Pause all the partitions of the topic "),E(10,"b"),A(11),T(),A(12," from consumers "),E(13,"b"),A(14),T(),A(15," with group id "),E(16,"b"),A(17),T(),A(18,"' will interrupt the kafka data processing and, probably, generate lag. "),T(),E(19,"h5",6),A(20,"Are you really sure about it?"),T()()(),E(21,"div",7)(22,"button",8),W("click",function(){return i.activeModal.dismiss()}),A(23,"No, cancel"),T(),E(24,"button",9),W("click",function(){return i.activeModal.close()}),A(25,"Yes"),T()()),2&t&&(F(11),Be("'",i.topic,"'"),F(3),Be("'",i.consumerName,"'"),F(3),Be("'",i.groupId,""))},encapsulation:2}),e})(),IU=(()=>{class e{constructor(t){this.activeModal=t}}return e.\u0275fac=function(t){return new(t||e)(C(pr))},e.\u0275cmp=et({type:e,selectors:[["app-resume-modal"]],inputs:{groupId:"groupId",consumerName:"consumerName",topic:"topic"},decls:26,vars:3,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],[1,"mt-3"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(E(0,"div",0)(1,"h4",1),A(2,"Resume consumers"),T(),E(3,"button",2),W("click",function(){return i.activeModal.dismiss()}),E(4,"span",3),A(5,"\xd7"),T()()(),E(6,"div",4)(7,"div",5)(8,"span"),A(9,"Resume all the partitions of the topic "),E(10,"b"),A(11),T(),A(12," from consumers "),E(13,"b"),A(14),T(),A(15," with group id "),E(16,"b"),A(17),T(),A(18,"' will restart to process the messages. "),T(),E(19,"h5",6),A(20,"Are you really sure about it?"),T()()(),E(21,"div",7)(22,"button",8),W("click",function(){return i.activeModal.dismiss()}),A(23,"No, cancel"),T(),E(24,"button",9),W("click",function(){return i.activeModal.close()}),A(25,"Yes"),T()()),2&t&&(F(11),Be("'",i.topic,"'"),F(3),Be("'",i.consumerName,"'"),F(3),Be("'",i.groupId,""))},encapsulation:2}),e})(),OU=(()=>{class e{constructor(t){this.activeModal=t}}return e.\u0275fac=function(t){return new(t||e)(C(pr))},e.\u0275cmp=et({type:e,selectors:[["app-restart-modal"]],inputs:{groupId:"groupId",consumerName:"consumerName"},decls:23,vars:2,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],[1,"mt-3"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(E(0,"div",0)(1,"h4",1),A(2,"Restart consumers"),T(),E(3,"button",2),W("click",function(){return i.activeModal.dismiss()}),E(4,"span",3),A(5,"\xd7"),T()()(),E(6,"div",4)(7,"div",5)(8,"span"),A(9,"Restart the consumers "),E(10,"b"),A(11),T(),A(12," from group id "),E(13,"b"),A(14),T(),A(15,"' will can generate a temporary instability in your system. "),T(),E(16,"h5",6),A(17,"Are you really sure about it?"),T()()(),E(18,"div",7)(19,"button",8),W("click",function(){return i.activeModal.dismiss()}),A(20,"No, cancel"),T(),E(21,"button",9),W("click",function(){return i.activeModal.close()}),A(22,"Yes"),T()()),2&t&&(F(11),Be("'",i.consumerName,"'"),F(3),Be("'",i.groupId,""))},encapsulation:2}),e})(),kU=(()=>{class e{constructor(t){this.activeModal=t}}return e.\u0275fac=function(t){return new(t||e)(C(pr))},e.\u0275cmp=et({type:e,selectors:[["app-start-modal"]],inputs:{groupId:"groupId",consumerName:"consumerName"},decls:22,vars:2,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],[1,"mt-3"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(E(0,"div",0)(1,"h4",1),A(2,"Start consumers"),T(),E(3,"button",2),W("click",function(){return i.activeModal.dismiss()}),E(4,"span",3),A(5,"\xd7"),T()()(),E(6,"div",4)(7,"div",5)(8,"span"),A(9,"Start the consumer "),E(10,"b"),A(11),T(),A(12," from group id "),E(13,"b"),A(14),T()(),E(15,"h5",6),A(16,"Are you really sure about it?"),T()()(),E(17,"div",7)(18,"button",8),W("click",function(){return i.activeModal.dismiss()}),A(19,"No, cancel"),T(),E(20,"button",9),W("click",function(){return i.activeModal.close()}),A(21,"Yes"),T()()),2&t&&(F(11),Be("'",i.consumerName,"'"),F(3),Be("'",i.groupId,"'"))},encapsulation:2}),e})(),RU=(()=>{class e{constructor(t){this.activeModal=t}}return e.\u0275fac=function(t){return new(t||e)(C(pr))},e.\u0275cmp=et({type:e,selectors:[["app-stop-modal"]],inputs:{groupId:"groupId",consumerName:"consumerName"},decls:22,vars:2,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],[1,"mt-3"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(E(0,"div",0)(1,"h4",1),A(2,"Stop consumer"),T(),E(3,"button",2),W("click",function(){return i.activeModal.dismiss()}),E(4,"span",3),A(5,"\xd7"),T()()(),E(6,"div",4)(7,"div",5)(8,"span"),A(9,"Stop the consumer "),E(10,"b"),A(11),T(),A(12," from group id "),E(13,"b"),A(14),T()(),E(15,"h5",6),A(16,"Are you really sure about it?"),T()()(),E(17,"div",7)(18,"button",8),W("click",function(){return i.activeModal.dismiss()}),A(19,"No, cancel"),T(),E(20,"button",9),W("click",function(){return i.activeModal.close()}),A(21,"Yes"),T()()),2&t&&(F(11),Be("'",i.consumerName,"'"),F(3),Be("'",i.groupId,"'"))},encapsulation:2}),e})();var zM=iu(439);function YM(e,n,t,i,r,o,s){try{var a=e[o](s),l=a.value}catch(u){return void t(u)}a.done?n(l):Promise.resolve(l).then(i,r)}function zr(e){return function(){var n=this,t=arguments;return new Promise(function(i,r){var o=e.apply(n,t);function s(l){YM(o,i,r,s,a,"next",l)}function a(l){YM(o,i,r,s,a,"throw",l)}s(void 0)})}}function Yr(e,n){const t="object"==typeof n;return new Promise((i,r)=>{const o=new vr({next:s=>{i(s),o.unsubscribe()},error:r,complete:()=>{t?i(n.defaultValue):r(new bc)}});e.subscribe(o)})}let JM=(()=>{class e{constructor(){this.rootUrl="/kafka-flow"}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(); + */let vB=(()=>{class e{constructor(t){this._config=t,this.maskExpression="",this.actualValue="",this.shownMaskExpression="",this._formatWithSeparators=(i,r,o,s)=>{let a=[],l="";if(Array.isArray(o)){const v=new RegExp(o.map(y=>"[\\^$.|?*+()".indexOf(y)>=0?`\\${y}`:y).join("|"));a=i.split(v),l=i.match(v)?.[0]??""}else a=i.split(o),l=o;const u=a.length>1?`${l}${a[1]}`:"";let f=a[0]??"";const p=this.separatorLimit.replace(/\s/g,"");p&&+p&&(f="-"===f[0]?`-${f.slice(1,f.length).slice(0,p.length)}`:f.slice(0,p.length));const m=/(\d+)(\d{3})/;for(;r&&m.test(f);)f=f.replace(m,"$1"+r+"$2");return void 0===s?f+u:0===s?f:f+u.substring(0,s+1)},this.percentage=i=>Number(i)>=0&&Number(i)<=100,this.getPrecision=i=>{const r=i.split(".");return r.length>1?Number(r[r.length-1]):1/0},this.checkAndRemoveSuffix=i=>{for(let r=this.suffix?.length-1;r>=0;r--){const o=this.suffix.substring(r,this.suffix?.length);if(i.includes(o)&&r!==this.suffix?.length-1&&(r-1<0||!i.includes(this.suffix.substring(r-1,this.suffix?.length))))return i.replace(o,"")}return i},this.checkInputPrecision=(i,r,o)=>{if(r<1/0){if(Array.isArray(o)){const u=o.find(f=>f!==this.thousandSeparator);o=u||o[0]}const s=new RegExp(this._charToRegExpExpression(o)+`\\d{${r}}.*$`),l=(i.match(s)??[])[0]?.length??0;l-1>r&&(i=i.substring(0,i.length-(l-1-r))),0===r&&this._compareOrIncludes(i[i.length-1],o,this.thousandSeparator)&&(i=i.substring(0,i.length-1))}return i},this._shift=new Set,this.clearIfNotMatch=this._config.clearIfNotMatch,this.dropSpecialCharacters=this._config.dropSpecialCharacters,this.maskSpecialCharacters=this._config.specialCharacters,this.maskAvailablePatterns=this._config.patterns,this.prefix=this._config.prefix,this.suffix=this._config.suffix,this.thousandSeparator=this._config.thousandSeparator,this.decimalMarker=this._config.decimalMarker,this.hiddenInput=this._config.hiddenInput,this.showMaskTyped=this._config.showMaskTyped,this.placeHolderCharacter=this._config.placeHolderCharacter,this.validation=this._config.validation,this.separatorLimit=this._config.separatorLimit,this.allowNegativeNumbers=this._config.allowNegativeNumbers,this.leadZeroDateTime=this._config.leadZeroDateTime}applyMaskWithPattern(t,i){const[r,o]=i;return this.customPattern=o,this.applyMask(t,r)}applyMask(t,i,r=0,o=!1,s=!1,a=(()=>{})){if(!i||"string"!=typeof t)return"";let l=0,u="",f=!1,p=!1,m=1,v=!1;t.slice(0,this.prefix.length)===this.prefix&&(t=t.slice(this.prefix.length,t.length)),this.suffix&&t?.length>0&&(t=this.checkAndRemoveSuffix(t));const y=t.toString().split("");if("IP"===i){const k=t.split(".");this.ipError=this._validIP(k),i="099.099.099.099"}const D=[];for(let k=0;k11?"00.000.000/0000-00":"000.000.000-00"),i.startsWith("percent")){if(t.match("[a-z]|[A-Z]")||t.match(/[-!$%^&*()_+|~=`{}\[\]:";'<>?,\/.]/)){t=this._stripToDecimal(t);const k=this.getPrecision(i);t=this.checkInputPrecision(t,k,this.decimalMarker)}t.indexOf(".")>0&&!this.percentage(t.substring(0,t.indexOf(".")))&&(t=`${t.substring(0,t.indexOf(".")-1)}${t.substring(t.indexOf("."),t.length)}`),u=this.percentage(t)?t:t.substring(0,t.length-1)}else if(i.startsWith("separator")){(t.match("[w\u0430-\u044f\u0410-\u042f]")||t.match("[\u0401\u0451\u0410-\u044f]")||t.match("[a-z]|[A-Z]")||t.match(/[-@#!$%\\^&*()_\xa3\xac'+|~=`{}\]:";<>.?/]/)||t.match("[^A-Za-z0-9,]"))&&(t=this._stripToDecimal(t)),t=t.length>1&&"0"===t[0]&&t[1]!==this.thousandSeparator&&!this._compareOrIncludes(t[1],this.decimalMarker,this.thousandSeparator)&&!s?t.slice(0,t.length-1):t,s&&(t=this._compareOrIncludes(t[t.length-1],this.decimalMarker,this.thousandSeparator)?t.slice(0,t.length-1):t);const k=this._charToRegExpExpression(this.thousandSeparator);let x='@#!$%^&*()_+|~=`{}\\[\\]:\\s,\\.";<>?\\/'.replace(k,"");if(Array.isArray(this.decimalMarker))for(const Ae of this.decimalMarker)x=x.replace(this._charToRegExpExpression(Ae),"");else x=x.replace(this._charToRegExpExpression(this.decimalMarker),"");const U=new RegExp("["+x+"]");(t.match(U)||1===t.length&&this._compareOrIncludes(t,this.decimalMarker,this.thousandSeparator))&&(t=t.substring(0,t.length-1));const ge=this.getPrecision(i),Ce=(t=this.checkInputPrecision(t,ge,this.decimalMarker)).replace(new RegExp(k,"g"),"");u=this._formatWithSeparators(Ce,this.thousandSeparator,this.decimalMarker,ge);const Ke=u.indexOf(",")-t.indexOf(","),Le=u.length-t.length;if(Le>0&&","!==u[r]){p=!0;let Ae=0;do{this._shift.add(r+Ae),Ae++}while(Ae0&&!(u.indexOf(",")>=r&&r>3)||!(u.indexOf(".")>=r&&r>3)&&Le<=0?(this._shift.clear(),p=!0,m=Le,this._shift.add(r+=Le)):this._shift.clear()}else for(let k=0,x=y[0];k2){l+=1,this._shiftStep(i,l,y.length),k--,this.leadZeroDateTime&&(u+="0");continue}if("h"===i[l]&&"2"===u&&Number(x)>3){l+=1,k--;continue}if("m"===i[l]&&Number(x)>5){l+=1,this._shiftStep(i,l,y.length),k--,this.leadZeroDateTime&&(u+="0");continue}if("s"===i[l]&&Number(x)>5){l+=1,this._shiftStep(i,l,y.length),k--,this.leadZeroDateTime&&(u+="0");continue}const U=31;if("d"===i[l]&&(Number(x)>3&&this.leadZeroDateTime||Number(t.slice(l,l+2))>U||"/"===t[l+1])){l+=1,this._shiftStep(i,l,y.length),k--,this.leadZeroDateTime&&(u+="0");continue}if("M"===i[l]){const Ce=0===l&&(Number(x)>2||Number(t.slice(l,l+2))>12||"/"===t[l+1]),Ke=t.slice(l-3,l-1).includes("/")&&("/"===t[l-2]&&Number(t.slice(l-1,l+1))>12&&"/"!==t[l]||"/"===t[l]||"/"===t[l-3]&&Number(t.slice(l-2,l))>12&&"/"!==t[l-1]||"/"===t[l-1]),Le=Number(t.slice(l-3,l-1))<=U&&!t.slice(l-3,l-1).includes("/")&&"/"===t[l-1]&&(Number(t.slice(l,l+2))>12||"/"===t[l+1]),Ae=Number(t.slice(l-3,l-1))>U&&!t.slice(l-3,l-1).includes("/")&&!t.slice(l-2,l).includes("/")&&Number(t.slice(l-2,l))>12,cn=Number(t.slice(l-3,l-1))<=U&&!t.slice(l-3,l-1).includes("/")&&"/"!==t[l-1]&&Number(t.slice(l-1,l+1))>12;if(Number(x)>1&&this.leadZeroDateTime||Ce||Ke||Le||Ae||cn){l+=1,this._shiftStep(i,l,y.length),k--,this.leadZeroDateTime&&(u+="0");continue}}u+=x,l++}else" "===x&&" "===i[l]?(u+=x,l++):-1!==this.maskSpecialCharacters.indexOf(i[l]??"")?(u+=i[l],l++,this._shiftStep(i,l,y.length),k--):this.maskSpecialCharacters.indexOf(x)>-1&&this.maskAvailablePatterns[i[l]??""]&&this.maskAvailablePatterns[i[l]??""]?.optional?(!!y[l]&&"099.099.099.099"!==i&&"000.000.000-00"!==i&&"00.000.000/0000-00"!==i&&!i.match(/^9+\.0+$/)&&(u+=y[l]),l++,k--):"*"===this.maskExpression[l+1]&&this._findSpecialChar(this.maskExpression[l+2]??"")&&this._findSpecialChar(x)===this.maskExpression[l+2]&&f||"?"===this.maskExpression[l+1]&&this._findSpecialChar(this.maskExpression[l+2]??"")&&this._findSpecialChar(x)===this.maskExpression[l+2]&&f?(l+=3,u+=x):this.showMaskTyped&&this.maskSpecialCharacters.indexOf(x)<0&&x!==this.placeHolderCharacter&&(v=!0);u.length+1===i.length&&-1!==this.maskSpecialCharacters.indexOf(i[i.length-1]??"")&&(u+=i[i.length-1]);let w=r+1;for(;this._shift.has(w);)m++,w++;let N=o&&!i.startsWith("separator")?l:this._shift.has(r)?m:0;v&&N--,a(N,p),m<0&&this._shift.clear();let A=!1;s&&(A=y.every(k=>this.maskSpecialCharacters.includes(k)));let S=`${this.prefix}${A?"":u}${this.suffix}`;return 0===u.length&&(S=`${this.prefix}${u}`),S}_findSpecialChar(t){return this.maskSpecialCharacters.find(i=>i===t)}_checkSymbolMask(t,i){return this.maskAvailablePatterns=this.customPattern?this.customPattern:this.maskAvailablePatterns,(this.maskAvailablePatterns[i]?.pattern&&this.maskAvailablePatterns[i]?.pattern.test(t))??!1}_stripToDecimal(t){return t.split("").filter((i,r)=>{const o="string"==typeof this.decimalMarker?i===this.decimalMarker:this.decimalMarker.includes(i);return i.match("^-?\\d")||i===this.thousandSeparator||o||"-"===i&&0===r&&this.allowNegativeNumbers}).join("")}_charToRegExpExpression(t){return t&&(" "===t?"\\s":"[\\^$.|?*+()".indexOf(t)>=0?`\\${t}`:t)}_shiftStep(t,i,r){const o=/[*?]/g.test(t.slice(0,i))?r:i;this._shift.add(o+this.prefix.length||0)}_compareOrIncludes(t,i,r){return Array.isArray(i)?i.filter(o=>o!==r).includes(t):t===i}_validIP(t){return!(4===t.length&&!t.some((i,r)=>t.length!==r+1?""===i||Number(i)>255:""===i||Number(i.substring(0,3))>255))}}return e.\u0275fac=function(t){return new(t||e)(L(wM))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})();function yB(e,n){return n instanceof Function?{...e,...n()}:{...e,...n}}let bB=(()=>{class e{static forRoot(t){return{ngModule:e,providers:[{provide:SM,useValue:t},{provide:MM,useValue:_B},{provide:wM,useFactory:yB,deps:[MM,SM]},vB]}}static forChild(){return{ngModule:e}}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({}),e})();const NM=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};NM.KeyboardEvent||(NM.KeyboardEvent=function(e,n){});let EM=(()=>{class e{constructor(t,i){this.document=t,this.platformId=i,this.documentIsAccessible=function xC(e){return e===OC}(this.platformId)}static getCookieRegExp(t){const i=t.replace(/([\[\]\{\}\(\)\|\=\;\+\?\,\.\*\^\$])/gi,"\\$1");return new RegExp("(?:^"+i+"|;\\s*"+i+")=(.*?)(?:;|$)","g")}static safeDecodeURIComponent(t){try{return decodeURIComponent(t)}catch{return t}}check(t){return!!this.documentIsAccessible&&(t=encodeURIComponent(t),e.getCookieRegExp(t).test(this.document.cookie))}get(t){if(this.documentIsAccessible&&this.check(t)){t=encodeURIComponent(t);const r=e.getCookieRegExp(t).exec(this.document.cookie);return r[1]?e.safeDecodeURIComponent(r[1]):""}return""}getAll(){if(!this.documentIsAccessible)return{};const t={},i=this.document;return i.cookie&&""!==i.cookie&&i.cookie.split(";").forEach(r=>{const[o,s]=r.split("=");t[e.safeDecodeURIComponent(o.replace(/^ /,""))]=e.safeDecodeURIComponent(s)}),t}set(t,i,r,o,s,a,l){if(!this.documentIsAccessible)return;if("number"==typeof r||r instanceof Date||o||s||a||l)return void this.set(t,i,{expires:r,path:o,domain:s,secure:a,sameSite:l||"Lax"});let u=encodeURIComponent(t)+"="+encodeURIComponent(i)+";";const f=r||{};f.expires&&(u+="number"==typeof f.expires?"expires="+new Date((new Date).getTime()+1e3*f.expires*60*60*24).toUTCString()+";":"expires="+f.expires.toUTCString()+";"),f.path&&(u+="path="+f.path+";"),f.domain&&(u+="domain="+f.domain+";"),!1===f.secure&&"None"===f.sameSite&&(f.secure=!0,console.warn(`[ngx-cookie-service] Cookie ${t} was forced with secure flag because sameSite=None.More details : https://github.com/stevermeister/ngx-cookie-service/issues/86#issuecomment-597720130`)),f.secure&&(u+="secure;"),f.sameSite||(f.sameSite="Lax"),u+="sameSite="+f.sameSite+";",this.document.cookie=u}delete(t,i,r,o,s="Lax"){if(!this.documentIsAccessible)return;const a=new Date("Thu, 01 Jan 1970 00:00:01 GMT");this.set(t,"",{expires:a,path:i,domain:r,secure:o,sameSite:s})}deleteAll(t,i,r,o="Lax"){if(!this.documentIsAccessible)return;const s=this.getAll();for(const a in s)s.hasOwnProperty(a)&&this.delete(a,t,i,r,o)}}return e.\u0275fac=function(t){return new(t||e)(L(Dt),L(dc))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})();const DB=[];let CB=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[Cf.forRoot(DB),Cf]}),e})(),wB=(()=>{class e{constructor(){this.title="dashboard"}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275cmp=et({type:e,selectors:[["app-root"]],decls:1,vars:0,template:function(t,i){1&t&&Li(0,"router-outlet")},dependencies:[d_],encapsulation:2}),e})();const SB=["addListener","removeListener"],MB=["addEventListener","removeEventListener"],NB=["on","off"];function xn(e,n,t,i){if(ye(t)&&(i=t,t=void 0),i)return xn(e,n,t).pipe(Ym(i));const[r,o]=function IB(e){return ye(e.addEventListener)&&ye(e.removeEventListener)}(e)?MB.map(s=>a=>e[s](n,a,t)):function EB(e){return ye(e.addListener)&&ye(e.removeListener)}(e)?SB.map(TM(e,n)):function TB(e){return ye(e.on)&&ye(e.off)}(e)?NB.map(TM(e,n)):[];if(!r&&Ts(e))return dt(s=>xn(s,n,t))(ut(e));if(!r)throw new TypeError("Invalid event target");return new je(s=>{const a=(...l)=>s.next(1o(a)})}function TM(e,n){return t=>i=>e[t](n,i)}class AB extends Ct{constructor(n,t){super()}schedule(n,t=0){return this}}const xf={setInterval(e,n,...t){const{delegate:i}=xf;return i?.setInterval?i.setInterval(e,n,...t):setInterval(e,n,...t)},clearInterval(e){const{delegate:n}=xf;return(n?.clearInterval||clearInterval)(e)},delegate:void 0},IM={now:()=>(IM.delegate||Date).now(),delegate:void 0};class Hc{constructor(n,t=Hc.now){this.schedulerActionCtor=n,this.now=t}schedule(n,t=0,i){return new this.schedulerActionCtor(this,n).schedule(i,t)}}Hc.now=IM.now;const Rf=new class OB extends Hc{constructor(n,t=Hc.now){super(n,t),this.actions=[],this._active=!1}flush(n){const{actions:t}=this;if(this._active)return void t.push(n);let i;this._active=!0;do{if(i=n.execute(n.state,n.delay))break}while(n=t.shift());if(this._active=!1,i){for(;n=t.shift();)n.unsubscribe();throw i}}}(class kB extends AB{constructor(n,t){super(n,t),this.scheduler=n,this.work=t,this.pending=!1}schedule(n,t=0){var i;if(this.closed)return this;this.state=n;const r=this.id,o=this.scheduler;return null!=r&&(this.id=this.recycleAsyncId(o,r,t)),this.pending=!0,this.delay=t,this.id=null!==(i=this.id)&&void 0!==i?i:this.requestAsyncId(o,this.id,t),this}requestAsyncId(n,t,i=0){return xf.setInterval(n.flush.bind(n,this),i)}recycleAsyncId(n,t,i=0){if(null!=i&&this.delay===i&&!1===this.pending)return t;null!=t&&xf.clearInterval(t)}execute(n,t){if(this.closed)return new Error("executing a cancelled action");this.pending=!1;const i=this._execute(n,t);if(i)return i;!1===this.pending&&null!=this.id&&(this.id=this.recycleAsyncId(this.scheduler,this.id,null))}_execute(n,t){let r,i=!1;try{this.work(n)}catch(o){i=!0,r=o||new Error("Scheduled action threw falsy error")}if(i)return this.unsubscribe(),r}unsubscribe(){if(!this.closed){const{id:n,scheduler:t}=this,{actions:i}=t;this.work=this.state=this.scheduler=null,this.pending=!1,dn(i,this),null!=n&&(this.id=this.recycleAsyncId(t,n,null)),this.delay=null,super.unsubscribe()}}}),xB=Rf;function jc(e=0,n,t=xB){let i=-1;return null!=n&&(si(n)?t=n:i=n),new je(r=>{let o=function RB(e){return e instanceof Date&&!isNaN(e)}(e)?+e-t.now():e;o<0&&(o=0);let s=0;return t.schedule(function(){r.closed||(r.next(s++),0<=i?this.schedule(void 0,i):r.complete())},o)})}const{isArray:PB}=Array;function AM(e){return 1===e.length&&PB(e[0])?e[0]:e}function Pf(...e){const n=rt(e),t=AM(e);return t.length?new je(i=>{let r=t.map(()=>[]),o=t.map(()=>!1);i.add(()=>{r=o=null});for(let s=0;!i.closed&&s{if(r[s].push(a),r.every(l=>l.length)){const l=r.map(u=>u.shift());i.next(n?n(...l):l),r.some((u,f)=>!u.length&&o[f])&&i.complete()}},()=>{o[s]=!0,!r[s].length&&i.complete()}));return()=>{r=o=null}}):Xt}function Vt(e){return qe((n,t)=>{ut(e).subscribe(Oe(t,()=>t.complete(),Dn)),!t.closed&&n.subscribe(t)})}function K_(...e){const n=rt(e);return qe((t,i)=>{const r=e.length,o=new Array(r);let s=e.map(()=>!1),a=!1;for(let l=0;l{o[l]=u,!a&&!s[l]&&(s[l]=!0,(a=s.every(Rn))&&(s=null))},Dn));t.subscribe(Oe(i,l=>{if(a){const u=[l,...o];i.next(n?n(...u):u)}}))})}function QH(e,n){if(1&e){const t=It();M(0,"button",1),W("click",function(){return mt(t),_t(z().close())}),T()}}new je(Dn),Math,Math,Math;const ZM=["*"],mj=["dialog"];function sv(e){return"string"==typeof e}function fs(e){return null!=e}function za(e){return(e||document.body).getBoundingClientRect()}const QM={animation:!0,transitionTimerDelayMs:5},u$=()=>{},{transitionTimerDelayMs:d$}=QM,Kc=new Map,bn=(e,n,t,i)=>{let r=i.context||{};const o=Kc.get(n);if(o)switch(i.runningTransition){case"continue":return Xt;case"stop":e.run(()=>o.transition$.complete()),r=Object.assign(o.context,r),Kc.delete(n)}const s=t(n,i.animation,r)||u$;if(!i.animation||"none"===window.getComputedStyle(n).transitionProperty)return e.run(()=>s()),J(void 0).pipe(function l$(e){return n=>new je(t=>n.subscribe({next:s=>e.run(()=>t.next(s)),error:s=>e.run(()=>t.error(s)),complete:()=>e.run(()=>t.complete())}))}(e));const a=new Ue,l=new Ue,u=a.pipe(function LB(...e){return n=>Dc(n,J(...e))}(!0));Kc.set(n,{transition$:a,complete:()=>{l.next(),l.complete()},context:r});const f=function c$(e){const{transitionDelay:n,transitionDuration:t}=window.getComputedStyle(e);return 1e3*(parseFloat(n)+parseFloat(t))}(n);return e.runOutsideAngular(()=>{const p=xn(n,"transitionend").pipe(Vt(u),vn(({target:v})=>v===n));(function kM(...e){return 1===(e=AM(e)).length?ut(e[0]):new je(function FB(e){return n=>{let t=[];for(let i=0;t&&!n.closed&&i{if(t){for(let o=0;o{Kc.delete(n),e.run(()=>{s(),a.next(),a.complete()})})}),a.asObservable()};let qc=(()=>{class e{constructor(){this.animation=QM.animation}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(),rN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[ei]}),e})();const _$=({classList:e})=>{e.remove("show")};let v$=(()=>{class e{constructor(t){this._ngbConfig=t,this.dismissible=!0,this.type="warning"}get animation(){return void 0===this._animation?this._ngbConfig.animation:this._animation}set animation(t){this._animation=t}}return e.\u0275fac=function(t){return new(t||e)(L(qc))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(),y$=(()=>{class e{constructor(t,i,r,o){this._renderer=i,this._element=r,this._zone=o,this.closed=new ue,this.dismissible=t.dismissible,this.type=t.type,this.animation=t.animation}close(){const t=bn(this._zone,this._element.nativeElement,_$,{animation:this.animation,runningTransition:"continue"});return t.subscribe(()=>this.closed.emit()),t}ngOnChanges(t){const i=t.type;i&&!i.firstChange&&(this._renderer.removeClass(this._element.nativeElement,`alert-${i.previousValue}`),this._renderer.addClass(this._element.nativeElement,`alert-${i.currentValue}`))}ngOnInit(){this._renderer.addClass(this._element.nativeElement,`alert-${this.type}`)}}return e.\u0275fac=function(t){return new(t||e)(C(v$),C(pi),C(Je),C(Ye))},e.\u0275cmp=et({type:e,selectors:[["ngb-alert"]],hostAttrs:["role","alert",1,"alert","show"],hostVars:4,hostBindings:function(t,i){2&t&&ht("fade",i.animation)("alert-dismissible",i.dismissible)},inputs:{animation:"animation",dismissible:"dismissible",type:"type"},outputs:{closed:"closed"},exportAs:["ngbAlert"],features:[zt],ngContentSelectors:ZM,decls:2,vars:1,consts:function(){let n;return n=$localize`:@@ngb.alert.close:Close`,[["type","button","class","btn-close","aria-label",n,3,"click",4,"ngIf"],["type","button","aria-label",n,1,"btn-close",3,"click"]]},template:function(t,i){1&t&&(Pg(),Fg(0),Z(1,QH,1,0,"button",0)),2&t&&(P(1),Q("ngIf",i.dismissible))},dependencies:[ns],styles:["ngb-alert{display:block}\n"],encapsulation:2,changeDetection:0}),e})(),oN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[ei]}),e})(),lN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[ei]}),e})(),cN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({}),e})();var Bt=(()=>{return(e=Bt||(Bt={}))[e.Tab=9]="Tab",e[e.Enter=13]="Enter",e[e.Escape=27]="Escape",e[e.Space=32]="Space",e[e.PageUp=33]="PageUp",e[e.PageDown=34]="PageDown",e[e.End=35]="End",e[e.Home=36]="Home",e[e.ArrowLeft=37]="ArrowLeft",e[e.ArrowUp=38]="ArrowUp",e[e.ArrowRight=39]="ArrowRight",e[e.ArrowDown=40]="ArrowDown",Bt;var e})();typeof navigator<"u"&&navigator.userAgent&&(/iPad|iPhone|iPod/.test(navigator.userAgent)||/Macintosh/.test(navigator.userAgent)&&navigator.maxTouchPoints&&navigator.maxTouchPoints>2||/Android/.test(navigator.userAgent));const dN=["a[href]","button:not([disabled])",'input:not([disabled]):not([type="hidden"])',"select:not([disabled])","textarea:not([disabled])","[contenteditable]",'[tabindex]:not([tabindex="-1"])'].join(", ");function fN(e){const n=Array.from(e.querySelectorAll(dN)).filter(t=>-1!==t.tabIndex);return[n[0],n[n.length-1]]}new Date(1882,10,12),new Date(2174,10,25);let bN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[ei,CM]}),e})(),hv=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275dir=B({type:e,selectors:[["",8,"navbar"]]}),e})(),wN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({}),e})();class ms{constructor(n,t,i){this.nodes=n,this.viewRef=t,this.componentRef=i}}let iU=(()=>{class e{constructor(t,i){this._el=t,this._zone=i}ngOnInit(){this._zone.onStable.asObservable().pipe(sn(1)).subscribe(()=>{bn(this._zone,this._el.nativeElement,(t,i)=>{i&&za(t),t.classList.add("show")},{animation:this.animation,runningTransition:"continue"})})}hide(){return bn(this._zone,this._el.nativeElement,({classList:t})=>t.remove("show"),{animation:this.animation,runningTransition:"stop"})}}return e.\u0275fac=function(t){return new(t||e)(C(Je),C(Ye))},e.\u0275cmp=et({type:e,selectors:[["ngb-modal-backdrop"]],hostAttrs:[2,"z-index","1055"],hostVars:6,hostBindings:function(t,i){2&t&&(Jo("modal-backdrop"+(i.backdropClass?" "+i.backdropClass:"")),ht("show",!i.animation)("fade",i.animation))},inputs:{animation:"animation",backdropClass:"backdropClass"},decls:0,vars:0,template:function(t,i){},encapsulation:2}),e})();class pr{close(n){}dismiss(n){}}class rU{constructor(n,t,i,r){this._windowCmptRef=n,this._contentRef=t,this._backdropCmptRef=i,this._beforeDismiss=r,this._closed=new Ue,this._dismissed=new Ue,this._hidden=new Ue,n.instance.dismissEvent.subscribe(o=>{this.dismiss(o)}),this.result=new Promise((o,s)=>{this._resolve=o,this._reject=s}),this.result.then(null,()=>{})}get componentInstance(){if(this._contentRef&&this._contentRef.componentRef)return this._contentRef.componentRef.instance}get closed(){return this._closed.asObservable().pipe(Vt(this._hidden))}get dismissed(){return this._dismissed.asObservable().pipe(Vt(this._hidden))}get hidden(){return this._hidden.asObservable()}get shown(){return this._windowCmptRef.instance.shown.asObservable()}close(n){this._windowCmptRef&&(this._closed.next(n),this._resolve(n),this._removeModalElements())}_dismiss(n){this._dismissed.next(n),this._reject(n),this._removeModalElements()}dismiss(n){if(this._windowCmptRef)if(this._beforeDismiss){const t=this._beforeDismiss();!function JM(e){return e&&e.then}(t)?!1!==t&&this._dismiss(n):t.then(i=>{!1!==i&&this._dismiss(n)},()=>{})}else this._dismiss(n)}_removeModalElements(){const n=this._windowCmptRef.instance.hide(),t=this._backdropCmptRef?this._backdropCmptRef.instance.hide():J(void 0);n.subscribe(()=>{const{nativeElement:i}=this._windowCmptRef.location;i.parentNode.removeChild(i),this._windowCmptRef.destroy(),this._contentRef&&this._contentRef.viewRef&&this._contentRef.viewRef.destroy(),this._windowCmptRef=null,this._contentRef=null}),t.subscribe(()=>{if(this._backdropCmptRef){const{nativeElement:i}=this._backdropCmptRef.location;i.parentNode.removeChild(i),this._backdropCmptRef.destroy(),this._backdropCmptRef=null}}),Pf(n,t).subscribe(()=>{this._hidden.next(),this._hidden.complete()})}}var Xc=(()=>{return(e=Xc||(Xc={}))[e.BACKDROP_CLICK=0]="BACKDROP_CLICK",e[e.ESC=1]="ESC",Xc;var e})();let oU=(()=>{class e{constructor(t,i,r){this._document=t,this._elRef=i,this._zone=r,this._closed$=new Ue,this._elWithFocus=null,this.backdrop=!0,this.keyboard=!0,this.dismissEvent=new ue,this.shown=new Ue,this.hidden=new Ue}get fullscreenClass(){return!0===this.fullscreen?" modal-fullscreen":sv(this.fullscreen)?` modal-fullscreen-${this.fullscreen}-down`:""}dismiss(t){this.dismissEvent.emit(t)}ngOnInit(){this._elWithFocus=this._document.activeElement,this._zone.onStable.asObservable().pipe(sn(1)).subscribe(()=>{this._show()})}ngOnDestroy(){this._disableEventHandling()}hide(){const{nativeElement:t}=this._elRef,i={animation:this.animation,runningTransition:"stop"},s=Pf(bn(this._zone,t,()=>t.classList.remove("show"),i),bn(this._zone,this._dialogEl.nativeElement,()=>{},i));return s.subscribe(()=>{this.hidden.next(),this.hidden.complete()}),this._disableEventHandling(),this._restoreFocus(),s}_show(){const t={animation:this.animation,runningTransition:"continue"};Pf(bn(this._zone,this._elRef.nativeElement,(o,s)=>{s&&za(o),o.classList.add("show")},t),bn(this._zone,this._dialogEl.nativeElement,()=>{},t)).subscribe(()=>{this.shown.next(),this.shown.complete()}),this._enableEventHandling(),this._setFocus()}_enableEventHandling(){const{nativeElement:t}=this._elRef;this._zone.runOutsideAngular(()=>{xn(t,"keydown").pipe(Vt(this._closed$),vn(r=>r.which===Bt.Escape)).subscribe(r=>{this.keyboard?requestAnimationFrame(()=>{r.defaultPrevented||this._zone.run(()=>this.dismiss(Xc.ESC))}):"static"===this.backdrop&&this._bumpBackdrop()});let i=!1;xn(this._dialogEl.nativeElement,"mousedown").pipe(Vt(this._closed$),Kt(()=>i=!1),vi(()=>xn(t,"mouseup").pipe(Vt(this._closed$),sn(1))),vn(({target:r})=>t===r)).subscribe(()=>{i=!0}),xn(t,"click").pipe(Vt(this._closed$)).subscribe(({target:r})=>{t===r&&("static"===this.backdrop?this._bumpBackdrop():!0===this.backdrop&&!i&&this._zone.run(()=>this.dismiss(Xc.BACKDROP_CLICK))),i=!1})})}_disableEventHandling(){this._closed$.next()}_setFocus(){const{nativeElement:t}=this._elRef;if(!t.contains(document.activeElement)){const i=t.querySelector("[ngbAutofocus]"),r=fN(t)[0];(i||r||t).focus()}}_restoreFocus(){const t=this._document.body,i=this._elWithFocus;let r;r=i&&i.focus&&t.contains(i)?i:t,this._zone.runOutsideAngular(()=>{setTimeout(()=>r.focus()),this._elWithFocus=null})}_bumpBackdrop(){"static"===this.backdrop&&bn(this._zone,this._elRef.nativeElement,({classList:t})=>(t.add("modal-static"),()=>t.remove("modal-static")),{animation:this.animation,runningTransition:"continue"})}}return e.\u0275fac=function(t){return new(t||e)(C(Dt),C(Je),C(Ye))},e.\u0275cmp=et({type:e,selectors:[["ngb-modal-window"]],viewQuery:function(t,i){if(1&t&&Nd(mj,7),2&t){let r;at(r=lt())&&(i._dialogEl=r.first)}},hostAttrs:["role","dialog","tabindex","-1"],hostVars:7,hostBindings:function(t,i){2&t&&(ze("aria-modal",!0)("aria-labelledby",i.ariaLabelledBy)("aria-describedby",i.ariaDescribedBy),Jo("modal d-block"+(i.windowClass?" "+i.windowClass:"")),ht("fade",i.animation))},inputs:{animation:"animation",ariaLabelledBy:"ariaLabelledBy",ariaDescribedBy:"ariaDescribedBy",backdrop:"backdrop",centered:"centered",fullscreen:"fullscreen",keyboard:"keyboard",scrollable:"scrollable",size:"size",windowClass:"windowClass",modalDialogClass:"modalDialogClass"},outputs:{dismissEvent:"dismiss"},ngContentSelectors:ZM,decls:4,vars:2,consts:[["role","document"],["dialog",""],[1,"modal-content"]],template:function(t,i){1&t&&(Pg(),M(0,"div",0,1)(2,"div",2),Fg(3),T()()),2&t&&Jo("modal-dialog"+(i.size?" modal-"+i.size:"")+(i.centered?" modal-dialog-centered":"")+i.fullscreenClass+(i.scrollable?" modal-dialog-scrollable":"")+(i.modalDialogClass?" "+i.modalDialogClass:""))},styles:["ngb-modal-window .component-host-scrollable{display:flex;flex-direction:column;overflow:hidden}\n"],encapsulation:2}),e})(),sU=(()=>{class e{constructor(t){this._document=t}hide(){const t=Math.abs(window.innerWidth-this._document.documentElement.clientWidth),i=this._document.body,r=i.style,{overflow:o,paddingRight:s}=r;if(t>0){const a=parseFloat(window.getComputedStyle(i).paddingRight);r.paddingRight=`${a+t}px`}return r.overflow="hidden",()=>{t>0&&(r.paddingRight=s),r.overflow=o}}}return e.\u0275fac=function(t){return new(t||e)(L(Dt))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(),aU=(()=>{class e{constructor(t,i,r,o,s,a){this._applicationRef=t,this._injector=i,this._document=r,this._scrollBar=o,this._rendererFactory=s,this._ngZone=a,this._activeWindowCmptHasChanged=new Ue,this._ariaHiddenValues=new Map,this._scrollBarRestoreFn=null,this._backdropAttributes=["animation","backdropClass"],this._modalRefs=[],this._windowAttributes=["animation","ariaLabelledBy","ariaDescribedBy","backdrop","centered","fullscreen","keyboard","scrollable","size","windowClass","modalDialogClass"],this._windowCmpts=[],this._activeInstances=new ue,this._activeWindowCmptHasChanged.subscribe(()=>{if(this._windowCmpts.length){const l=this._windowCmpts[this._windowCmpts.length-1];((e,n,t,i=!1)=>{this._ngZone.runOutsideAngular(()=>{const r=xn(n,"focusin").pipe(Vt(t),ne(o=>o.target));xn(n,"keydown").pipe(Vt(t),vn(o=>o.which===Bt.Tab),K_(r)).subscribe(([o,s])=>{const[a,l]=fN(n);(s===a||s===n)&&o.shiftKey&&(l.focus(),o.preventDefault()),s===l&&!o.shiftKey&&(a.focus(),o.preventDefault())}),i&&xn(n,"click").pipe(Vt(t),K_(r),ne(o=>o[1])).subscribe(o=>o.focus())})})(0,l.location.nativeElement,this._activeWindowCmptHasChanged),this._revertAriaHidden(),this._setAriaHidden(l.location.nativeElement)}})}_restoreScrollBar(){const t=this._scrollBarRestoreFn;t&&(this._scrollBarRestoreFn=null,t())}_hideScrollBar(){this._scrollBarRestoreFn||(this._scrollBarRestoreFn=this._scrollBar.hide())}open(t,i,r){const o=r.container instanceof HTMLElement?r.container:fs(r.container)?this._document.querySelector(r.container):this._document.body,s=this._rendererFactory.createRenderer(null,null);if(!o)throw new Error(`The specified modal container "${r.container||"body"}" was not found in the DOM.`);this._hideScrollBar();const a=new pr,l=this._getContentRef(r.injector||t,i,a,r);let u=!1!==r.backdrop?this._attachBackdrop(o):void 0,f=this._attachWindowComponent(o,l.nodes),p=new rU(f,l,u,r.beforeDismiss);return this._registerModalRef(p),this._registerWindowCmpt(f),p.hidden.pipe(sn(1)).subscribe(()=>Promise.resolve(!0).then(()=>{this._modalRefs.length||(s.removeClass(this._document.body,"modal-open"),this._restoreScrollBar(),this._revertAriaHidden())})),a.close=m=>{p.close(m)},a.dismiss=m=>{p.dismiss(m)},this._applyWindowOptions(f.instance,r),1===this._modalRefs.length&&s.addClass(this._document.body,"modal-open"),u&&u.instance&&(this._applyBackdropOptions(u.instance,r),u.changeDetectorRef.detectChanges()),f.changeDetectorRef.detectChanges(),p}get activeInstances(){return this._activeInstances}dismissAll(t){this._modalRefs.forEach(i=>i.dismiss(t))}hasOpenModals(){return this._modalRefs.length>0}_attachBackdrop(t){let i=Dm(iU,{environmentInjector:this._applicationRef.injector,elementInjector:this._injector});return this._applicationRef.attachView(i.hostView),t.appendChild(i.location.nativeElement),i}_attachWindowComponent(t,i){let r=Dm(oU,{environmentInjector:this._applicationRef.injector,elementInjector:this._injector,projectableNodes:i});return this._applicationRef.attachView(r.hostView),t.appendChild(r.location.nativeElement),r}_applyWindowOptions(t,i){this._windowAttributes.forEach(r=>{fs(i[r])&&(t[r]=i[r])})}_applyBackdropOptions(t,i){this._backdropAttributes.forEach(r=>{fs(i[r])&&(t[r]=i[r])})}_getContentRef(t,i,r,o){return i?i instanceof bt?this._createFromTemplateRef(i,r):sv(i)?this._createFromString(i):this._createFromComponent(t,i,r,o):new ms([])}_createFromTemplateRef(t,i){const o=t.createEmbeddedView({$implicit:i,close(s){i.close(s)},dismiss(s){i.dismiss(s)}});return this._applicationRef.attachView(o),new ms([o.rootNodes],o)}_createFromString(t){const i=this._document.createTextNode(`${t}`);return new ms([[i]])}_createFromComponent(t,i,r,o){const s=gn.create({providers:[{provide:pr,useValue:r}],parent:t}),a=Dm(i,{environmentInjector:this._applicationRef.injector,elementInjector:s}),l=a.location.nativeElement;return o.scrollable&&l.classList.add("component-host-scrollable"),this._applicationRef.attachView(a.hostView),new ms([[l]],a.hostView,a)}_setAriaHidden(t){const i=t.parentElement;i&&t!==this._document.body&&(Array.from(i.children).forEach(r=>{r!==t&&"SCRIPT"!==r.nodeName&&(this._ariaHiddenValues.set(r,r.getAttribute("aria-hidden")),r.setAttribute("aria-hidden","true"))}),this._setAriaHidden(i))}_revertAriaHidden(){this._ariaHiddenValues.forEach((t,i)=>{t?i.setAttribute("aria-hidden",t):i.removeAttribute("aria-hidden")}),this._ariaHiddenValues.clear()}_registerModalRef(t){const i=()=>{const r=this._modalRefs.indexOf(t);r>-1&&(this._modalRefs.splice(r,1),this._activeInstances.emit(this._modalRefs))};this._modalRefs.push(t),this._activeInstances.emit(this._modalRefs),t.result.then(i,i)}_registerWindowCmpt(t){this._windowCmpts.push(t),this._activeWindowCmptHasChanged.next(),t.onDestroy(()=>{const i=this._windowCmpts.indexOf(t);i>-1&&(this._windowCmpts.splice(i,1),this._activeWindowCmptHasChanged.next())})}}return e.\u0275fac=function(t){return new(t||e)(L(fc),L(gn),L(Dt),L(sU),L(Rp),L(Ye))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(),lU=(()=>{class e{constructor(t){this._ngbConfig=t,this.backdrop=!0,this.fullscreen=!1,this.keyboard=!0}get animation(){return void 0===this._animation?this._ngbConfig.animation:this._animation}set animation(t){this._animation=t}}return e.\u0275fac=function(t){return new(t||e)(L(qc))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(),SN=(()=>{class e{constructor(t,i,r){this._injector=t,this._modalStack=i,this._config=r}open(t,i={}){const r={...this._config,animation:this._config.animation,...i};return this._modalStack.open(this._injector,t,r)}get activeInstances(){return this._modalStack.activeInstances}dismissAll(t){this._modalStack.dismissAll(t)}hasOpenModals(){return this._modalStack.hasOpenModals()}}return e.\u0275fac=function(t){return new(t||e)(L(gn),L(aU),L(lU))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(),MN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({providers:[SN]}),e})(),IN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[ei]}),e})(),LN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[ei]}),e})(),BN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[ei]}),e})(),HN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[ei]}),e})(),jN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[ei]}),e})(),$N=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[ei]}),e})(),UN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[ei]}),e})(),GN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({}),e})();new q("live announcer delay",{providedIn:"root",factory:function DU(){return 100}});let WN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[ei]}),e})(),zN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({}),e})();const CU=[rN,oN,lN,cN,bN,wN,MN,IN,zN,LN,BN,HN,jN,$N,UN,GN,WN];let wU=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[CU,rN,oN,lN,cN,bN,wN,MN,IN,zN,LN,BN,HN,jN,$N,UN,GN,WN]}),e})(),NU=(()=>{class e{constructor(t){this.activeModal=t,this.save=()=>{this.activeModal.close(this.rewindDate)}}}return e.\u0275fac=function(t){return new(t||e)(C(pr))},e.\u0275cmp=et({type:e,selectors:[["app-rewind-modal"]],inputs:{groupId:"groupId",consumerName:"consumerName",topic:"topic"},decls:26,vars:4,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],["for","rewindDate"],[1,"input-group"],["id","rewindDate","placeholder","yyyy-mm-dd hh:MM:ss","type","datetime-local",1,"form-control",3,"ngModel","ngModelChange"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(M(0,"div",0)(1,"h4",1),I(2,"Rewind consumers offset"),T(),M(3,"button",2),W("click",function(){return i.activeModal.dismiss()}),M(4,"span",3),I(5,"\xd7"),T()()(),M(6,"div",4)(7,"div",5)(8,"label",6),I(9,"Select the datetime to rewind all the partition-offsets of the topic "),M(10,"b"),I(11),T(),I(12," from consumers "),M(13,"b"),I(14),T(),I(15," with group id "),M(16,"b"),I(17),T(),I(18,"' "),T(),M(19,"div",7)(20,"input",8),W("ngModelChange",function(o){return i.rewindDate=o}),T()()()(),M(21,"div",9)(22,"button",10),W("click",function(){return i.activeModal.dismiss()}),I(23,"Cancel"),T(),M(24,"button",11),W("click",function(){return i.save()}),I(25,"OK"),T()()),2&t&&(P(11),He("'",i.topic,"'"),P(3),He("'",i.consumerName,"'"),P(3),He("'",i.groupId,""),P(3),Q("ngModel",i.rewindDate))},dependencies:[Pc,I_,Of],encapsulation:2}),e})(),EU=(()=>{class e{constructor(t){this.activeModal=t,this.save=()=>{this.activeModal.close(this.workersCount)}}ngOnInit(){this.oldWorkersCount=this.workersCount}}return e.\u0275fac=function(t){return new(t||e)(C(pr))},e.\u0275cmp=et({type:e,selectors:[["app-workers-count-modal"]],inputs:{workersCount:"workersCount",groupId:"groupId",consumerName:"consumerName"},decls:28,vars:4,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],["for","oldWorkersCount"],[1,"input-group","mb-2"],["id","oldWorkersCount","type","number","readonly","",1,"form-control",3,"ngModel","ngModelChange"],["for","workersCount"],[1,"input-group"],["id","workersCount","type","number",1,"form-control",3,"ngModel","ngModelChange"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(M(0,"div",0)(1,"h4",1),I(2,"Consumer workers running"),T(),M(3,"button",2),W("click",function(){return i.activeModal.dismiss()}),M(4,"span",3),I(5,"\xd7"),T()()(),M(6,"div",4)(7,"div",5)(8,"label"),I(9,"Update the number of workers in consumers "),M(10,"b"),I(11),T(),I(12," from group id "),M(13,"b"),I(14),T()(),M(15,"label",6),I(16,"Current Value"),T(),M(17,"div",7)(18,"input",8),W("ngModelChange",function(o){return i.oldWorkersCount=o}),T()(),M(19,"label",9),I(20,"New Value"),T(),M(21,"div",10)(22,"input",11),W("ngModelChange",function(o){return i.workersCount=o}),T()()()(),M(23,"div",12)(24,"button",13),W("click",function(){return i.activeModal.dismiss()}),I(25,"Cancel"),T(),M(26,"button",14),W("click",function(){return i.save()}),I(27,"OK"),T()()),2&t&&(P(11),He("'",i.consumerName,"'"),P(3),He("'",i.groupId,"'"),P(4),Q("ngModel",i.oldWorkersCount),P(4),Q("ngModel",i.workersCount))},dependencies:[Pc,H_,I_,Of],encapsulation:2}),e})(),TU=(()=>{class e{constructor(t){this.activeModal=t}}return e.\u0275fac=function(t){return new(t||e)(C(pr))},e.\u0275cmp=et({type:e,selectors:[["app-reset-modal"]],inputs:{groupId:"groupId",consumerName:"consumerName",topic:"topic"},decls:26,vars:3,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],[1,"mt-3"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(M(0,"div",0)(1,"h4",1),I(2,"Reset consumers offset"),T(),M(3,"button",2),W("click",function(){return i.activeModal.dismiss()}),M(4,"span",3),I(5,"\xd7"),T()()(),M(6,"div",4)(7,"div",5)(8,"span"),I(9,"Reset the partition-offsets can generate a huge lag at the topic "),M(10,"b"),I(11),T(),I(12," to consumers "),M(13,"b"),I(14),T(),I(15," with group id "),M(16,"b"),I(17),T(),I(18,"'. "),T(),M(19,"h5",6),I(20,"Are you really sure about it?"),T()()(),M(21,"div",7)(22,"button",8),W("click",function(){return i.activeModal.dismiss()}),I(23,"No, cancel"),T(),M(24,"button",9),W("click",function(){return i.activeModal.close()}),I(25,"Yes"),T()()),2&t&&(P(11),He("'",i.topic,"'"),P(3),He("'",i.consumerName,"'"),P(3),He("'",i.groupId,""))},encapsulation:2}),e})(),IU=(()=>{class e{constructor(t){this.activeModal=t}}return e.\u0275fac=function(t){return new(t||e)(C(pr))},e.\u0275cmp=et({type:e,selectors:[["app-pause-modal"]],inputs:{groupId:"groupId",consumerName:"consumerName",topic:"topic"},decls:26,vars:3,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],[1,"mt-3"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(M(0,"div",0)(1,"h4",1),I(2,"Pause consumers"),T(),M(3,"button",2),W("click",function(){return i.activeModal.dismiss()}),M(4,"span",3),I(5,"\xd7"),T()()(),M(6,"div",4)(7,"div",5)(8,"span"),I(9,"Pause all the partitions of the topic "),M(10,"b"),I(11),T(),I(12," from consumers "),M(13,"b"),I(14),T(),I(15," with group id "),M(16,"b"),I(17),T(),I(18,"' will interrupt the kafka data processing and, probably, generate lag. "),T(),M(19,"h5",6),I(20,"Are you really sure about it?"),T()()(),M(21,"div",7)(22,"button",8),W("click",function(){return i.activeModal.dismiss()}),I(23,"No, cancel"),T(),M(24,"button",9),W("click",function(){return i.activeModal.close()}),I(25,"Yes"),T()()),2&t&&(P(11),He("'",i.topic,"'"),P(3),He("'",i.consumerName,"'"),P(3),He("'",i.groupId,""))},encapsulation:2}),e})(),AU=(()=>{class e{constructor(t){this.activeModal=t}}return e.\u0275fac=function(t){return new(t||e)(C(pr))},e.\u0275cmp=et({type:e,selectors:[["app-resume-modal"]],inputs:{groupId:"groupId",consumerName:"consumerName",topic:"topic"},decls:26,vars:3,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],[1,"mt-3"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(M(0,"div",0)(1,"h4",1),I(2,"Resume consumers"),T(),M(3,"button",2),W("click",function(){return i.activeModal.dismiss()}),M(4,"span",3),I(5,"\xd7"),T()()(),M(6,"div",4)(7,"div",5)(8,"span"),I(9,"Resume all the partitions of the topic "),M(10,"b"),I(11),T(),I(12," from consumers "),M(13,"b"),I(14),T(),I(15," with group id "),M(16,"b"),I(17),T(),I(18,"' will restart to process the messages. "),T(),M(19,"h5",6),I(20,"Are you really sure about it?"),T()()(),M(21,"div",7)(22,"button",8),W("click",function(){return i.activeModal.dismiss()}),I(23,"No, cancel"),T(),M(24,"button",9),W("click",function(){return i.activeModal.close()}),I(25,"Yes"),T()()),2&t&&(P(11),He("'",i.topic,"'"),P(3),He("'",i.consumerName,"'"),P(3),He("'",i.groupId,""))},encapsulation:2}),e})(),kU=(()=>{class e{constructor(t){this.activeModal=t}}return e.\u0275fac=function(t){return new(t||e)(C(pr))},e.\u0275cmp=et({type:e,selectors:[["app-restart-modal"]],inputs:{groupId:"groupId",consumerName:"consumerName"},decls:23,vars:2,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],[1,"mt-3"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(M(0,"div",0)(1,"h4",1),I(2,"Restart consumers"),T(),M(3,"button",2),W("click",function(){return i.activeModal.dismiss()}),M(4,"span",3),I(5,"\xd7"),T()()(),M(6,"div",4)(7,"div",5)(8,"span"),I(9,"Restart the consumers "),M(10,"b"),I(11),T(),I(12," from group id "),M(13,"b"),I(14),T(),I(15,"' will can generate a temporary instability in your system. "),T(),M(16,"h5",6),I(17,"Are you really sure about it?"),T()()(),M(18,"div",7)(19,"button",8),W("click",function(){return i.activeModal.dismiss()}),I(20,"No, cancel"),T(),M(21,"button",9),W("click",function(){return i.activeModal.close()}),I(22,"Yes"),T()()),2&t&&(P(11),He("'",i.consumerName,"'"),P(3),He("'",i.groupId,""))},encapsulation:2}),e})(),OU=(()=>{class e{constructor(t){this.activeModal=t}}return e.\u0275fac=function(t){return new(t||e)(C(pr))},e.\u0275cmp=et({type:e,selectors:[["app-start-modal"]],inputs:{groupId:"groupId",consumerName:"consumerName"},decls:22,vars:2,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],[1,"mt-3"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(M(0,"div",0)(1,"h4",1),I(2,"Start consumers"),T(),M(3,"button",2),W("click",function(){return i.activeModal.dismiss()}),M(4,"span",3),I(5,"\xd7"),T()()(),M(6,"div",4)(7,"div",5)(8,"span"),I(9,"Start the consumer "),M(10,"b"),I(11),T(),I(12," from group id "),M(13,"b"),I(14),T()(),M(15,"h5",6),I(16,"Are you really sure about it?"),T()()(),M(17,"div",7)(18,"button",8),W("click",function(){return i.activeModal.dismiss()}),I(19,"No, cancel"),T(),M(20,"button",9),W("click",function(){return i.activeModal.close()}),I(21,"Yes"),T()()),2&t&&(P(11),He("'",i.consumerName,"'"),P(3),He("'",i.groupId,"'"))},encapsulation:2}),e})(),xU=(()=>{class e{constructor(t){this.activeModal=t}}return e.\u0275fac=function(t){return new(t||e)(C(pr))},e.\u0275cmp=et({type:e,selectors:[["app-stop-modal"]],inputs:{groupId:"groupId",consumerName:"consumerName"},decls:22,vars:2,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],[1,"mt-3"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(M(0,"div",0)(1,"h4",1),I(2,"Stop consumer"),T(),M(3,"button",2),W("click",function(){return i.activeModal.dismiss()}),M(4,"span",3),I(5,"\xd7"),T()()(),M(6,"div",4)(7,"div",5)(8,"span"),I(9,"Stop the consumer "),M(10,"b"),I(11),T(),I(12," from group id "),M(13,"b"),I(14),T()(),M(15,"h5",6),I(16,"Are you really sure about it?"),T()()(),M(17,"div",7)(18,"button",8),W("click",function(){return i.activeModal.dismiss()}),I(19,"No, cancel"),T(),M(20,"button",9),W("click",function(){return i.activeModal.close()}),I(21,"Yes"),T()()),2&t&&(P(11),He("'",i.consumerName,"'"),P(3),He("'",i.groupId,"'"))},encapsulation:2}),e})();var YN=iu(439);function KN(e,n,t,i,r,o,s){try{var a=e[o](s),l=a.value}catch(u){return void t(u)}a.done?n(l):Promise.resolve(l).then(i,r)}function Yr(e){return function(){var n=this,t=arguments;return new Promise(function(i,r){var o=e.apply(n,t);function s(l){KN(o,i,r,s,a,"next",l)}function a(l){KN(o,i,r,s,a,"throw",l)}s(void 0)})}}function Kr(e,n){const t="object"==typeof n;return new Promise((i,r)=>{const o=new vr({next:s=>{i(s),o.unsubscribe()},error:r,complete:()=>{t?i(n.defaultValue):r(new bc)}});e.subscribe(o)})}let ZN=(()=>{class e{constructor(){this.rootUrl="/kafkaflow"}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(); /** * @license Angular v14.2.9 * (c) 2010-2022 Google LLC. https://angular.io/ @@ -1918,7 +1918,7 @@ const wE=new q("ngx-mask config"),SE=new q("new ngx-mask config"),EE=new q("init * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */class ZM{}class QM{} + */class JN{}class QN{} /** * @license * Copyright Google LLC All Rights Reserved. @@ -1933,7 +1933,7 @@ const wE=new q("ngx-mask config"),SE=new q("new ngx-mask config"),EE=new q("init * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -class xU{encodeKey(n){return XM(n)}encodeValue(n){return XM(n)}decodeKey(n){return decodeURIComponent(n)}decodeValue(n){return decodeURIComponent(n)}}const PU=/%(\d[a-f0-9])/gi,LU={40:"@","3A":":",24:"$","2C":",","3B":";","3D":"=","3F":"?","2F":"/"};function XM(e){return encodeURIComponent(e).replace(PU,(n,t)=>LU[t]??n)}function Yf(e){return`${e}`}class So{constructor(n={}){if(this.updates=null,this.cloneFrom=null,this.encoder=n.encoder||new xU,n.fromString){if(n.fromObject)throw new Error("Cannot specify both fromString and fromObject.");this.map=function FU(e,n){const t=new Map;return e.length>0&&e.replace(/^\?/,"").split("&").forEach(r=>{const o=r.indexOf("="),[s,a]=-1==o?[n.decodeKey(r),""]:[n.decodeKey(r.slice(0,o)),n.decodeValue(r.slice(o+1))],l=t.get(s)||[];l.push(a),t.set(s,l)}),t}(n.fromString,this.encoder)}else n.fromObject?(this.map=new Map,Object.keys(n.fromObject).forEach(t=>{const i=n.fromObject[t],r=Array.isArray(i)?i.map(Yf):[Yf(i)];this.map.set(t,r)})):this.map=null}has(n){return this.init(),this.map.has(n)}get(n){this.init();const t=this.map.get(n);return t?t[0]:null}getAll(n){return this.init(),this.map.get(n)||null}keys(){return this.init(),Array.from(this.map.keys())}append(n,t){return this.clone({param:n,value:t,op:"a"})}appendAll(n){const t=[];return Object.keys(n).forEach(i=>{const r=n[i];Array.isArray(r)?r.forEach(o=>{t.push({param:i,value:o,op:"a"})}):t.push({param:i,value:r,op:"a"})}),this.clone(t)}set(n,t){return this.clone({param:n,value:t,op:"s"})}delete(n,t){return this.clone({param:n,value:t,op:"d"})}toString(){return this.init(),this.keys().map(n=>{const t=this.encoder.encodeKey(n);return this.map.get(n).map(i=>t+"="+this.encoder.encodeValue(i)).join("&")}).filter(n=>""!==n).join("&")}clone(n){const t=new So({encoder:this.encoder});return t.cloneFrom=this.cloneFrom||this,t.updates=(this.updates||[]).concat(n),t}init(){null===this.map&&(this.map=new Map),null!==this.cloneFrom&&(this.cloneFrom.init(),this.cloneFrom.keys().forEach(n=>this.map.set(n,this.cloneFrom.map.get(n))),this.updates.forEach(n=>{switch(n.op){case"a":case"s":const t=("a"===n.op?this.map.get(n.param):void 0)||[];t.push(Yf(n.value)),this.map.set(n.param,t);break;case"d":if(void 0===n.value){this.map.delete(n.param);break}{let i=this.map.get(n.param)||[];const r=i.indexOf(Yf(n.value));-1!==r&&i.splice(r,1),i.length>0?this.map.set(n.param,i):this.map.delete(n.param)}}}),this.cloneFrom=this.updates=null)}} +class RU{encodeKey(n){return XN(n)}encodeValue(n){return XN(n)}decodeKey(n){return decodeURIComponent(n)}decodeValue(n){return decodeURIComponent(n)}}const FU=/%(\d[a-f0-9])/gi,LU={40:"@","3A":":",24:"$","2C":",","3B":";","3D":"=","3F":"?","2F":"/"};function XN(e){return encodeURIComponent(e).replace(FU,(n,t)=>LU[t]??n)}function Kf(e){return`${e}`}class So{constructor(n={}){if(this.updates=null,this.cloneFrom=null,this.encoder=n.encoder||new RU,n.fromString){if(n.fromObject)throw new Error("Cannot specify both fromString and fromObject.");this.map=function PU(e,n){const t=new Map;return e.length>0&&e.replace(/^\?/,"").split("&").forEach(r=>{const o=r.indexOf("="),[s,a]=-1==o?[n.decodeKey(r),""]:[n.decodeKey(r.slice(0,o)),n.decodeValue(r.slice(o+1))],l=t.get(s)||[];l.push(a),t.set(s,l)}),t}(n.fromString,this.encoder)}else n.fromObject?(this.map=new Map,Object.keys(n.fromObject).forEach(t=>{const i=n.fromObject[t],r=Array.isArray(i)?i.map(Kf):[Kf(i)];this.map.set(t,r)})):this.map=null}has(n){return this.init(),this.map.has(n)}get(n){this.init();const t=this.map.get(n);return t?t[0]:null}getAll(n){return this.init(),this.map.get(n)||null}keys(){return this.init(),Array.from(this.map.keys())}append(n,t){return this.clone({param:n,value:t,op:"a"})}appendAll(n){const t=[];return Object.keys(n).forEach(i=>{const r=n[i];Array.isArray(r)?r.forEach(o=>{t.push({param:i,value:o,op:"a"})}):t.push({param:i,value:r,op:"a"})}),this.clone(t)}set(n,t){return this.clone({param:n,value:t,op:"s"})}delete(n,t){return this.clone({param:n,value:t,op:"d"})}toString(){return this.init(),this.keys().map(n=>{const t=this.encoder.encodeKey(n);return this.map.get(n).map(i=>t+"="+this.encoder.encodeValue(i)).join("&")}).filter(n=>""!==n).join("&")}clone(n){const t=new So({encoder:this.encoder});return t.cloneFrom=this.cloneFrom||this,t.updates=(this.updates||[]).concat(n),t}init(){null===this.map&&(this.map=new Map),null!==this.cloneFrom&&(this.cloneFrom.init(),this.cloneFrom.keys().forEach(n=>this.map.set(n,this.cloneFrom.map.get(n))),this.updates.forEach(n=>{switch(n.op){case"a":case"s":const t=("a"===n.op?this.map.get(n.param):void 0)||[];t.push(Kf(n.value)),this.map.set(n.param,t);break;case"d":if(void 0===n.value){this.map.delete(n.param);break}{let i=this.map.get(n.param)||[];const r=i.indexOf(Kf(n.value));-1!==r&&i.splice(r,1),i.length>0?this.map.set(n.param,i):this.map.delete(n.param)}}}),this.cloneFrom=this.updates=null)}} /** * @license * Copyright Google LLC All Rights Reserved. @@ -1947,28 +1947,28 @@ class xU{encodeKey(n){return XM(n)}encodeValue(n){return XM(n)}decodeKey(n){retu * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */function eN(e){return typeof ArrayBuffer<"u"&&e instanceof ArrayBuffer}function tN(e){return typeof Blob<"u"&&e instanceof Blob}function nN(e){return typeof FormData<"u"&&e instanceof FormData}class eu{constructor(n,t,i,r){let o;if(this.url=t,this.body=null,this.reportProgress=!1,this.withCredentials=!1,this.responseType="json",this.method=n.toUpperCase(),function HU(e){switch(e){case"DELETE":case"GET":case"HEAD":case"OPTIONS":case"JSONP":return!1;default:return!0}}(this.method)||r?(this.body=void 0!==i?i:null,o=r):o=i,o&&(this.reportProgress=!!o.reportProgress,this.withCredentials=!!o.withCredentials,o.responseType&&(this.responseType=o.responseType),o.headers&&(this.headers=o.headers),o.context&&(this.context=o.context),o.params&&(this.params=o.params)),this.headers||(this.headers=new qr),this.context||(this.context=new VU),this.params){const s=this.params.toString();if(0===s.length)this.urlWithParams=t;else{const a=t.indexOf("?");this.urlWithParams=t+(-1===a?"?":ap.set(m,n.setHeaders[m]),l)),n.setParams&&(u=Object.keys(n.setParams).reduce((p,m)=>p.set(m,n.setParams[m]),u)),new eu(t,i,o,{params:u,headers:l,context:f,reportProgress:a,responseType:r,withCredentials:s})}} + */function eE(e){return typeof ArrayBuffer<"u"&&e instanceof ArrayBuffer}function tE(e){return typeof Blob<"u"&&e instanceof Blob}function nE(e){return typeof FormData<"u"&&e instanceof FormData}class eu{constructor(n,t,i,r){let o;if(this.url=t,this.body=null,this.reportProgress=!1,this.withCredentials=!1,this.responseType="json",this.method=n.toUpperCase(),function BU(e){switch(e){case"DELETE":case"GET":case"HEAD":case"OPTIONS":case"JSONP":return!1;default:return!0}}(this.method)||r?(this.body=void 0!==i?i:null,o=r):o=i,o&&(this.reportProgress=!!o.reportProgress,this.withCredentials=!!o.withCredentials,o.responseType&&(this.responseType=o.responseType),o.headers&&(this.headers=o.headers),o.context&&(this.context=o.context),o.params&&(this.params=o.params)),this.headers||(this.headers=new qr),this.context||(this.context=new VU),this.params){const s=this.params.toString();if(0===s.length)this.urlWithParams=t;else{const a=t.indexOf("?");this.urlWithParams=t+(-1===a?"?":ap.set(m,n.setHeaders[m]),l)),n.setParams&&(u=Object.keys(n.setParams).reduce((p,m)=>p.set(m,n.setParams[m]),u)),new eu(t,i,o,{params:u,headers:l,context:f,reportProgress:a,responseType:r,withCredentials:s})}} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */var kt=(()=>((kt=kt||{})[kt.Sent=0]="Sent",kt[kt.UploadProgress=1]="UploadProgress",kt[kt.ResponseHeader=2]="ResponseHeader",kt[kt.DownloadProgress=3]="DownloadProgress",kt[kt.Response=4]="Response",kt[kt.User=5]="User",kt))();class _v{constructor(n,t=200,i="OK"){this.headers=n.headers||new qr,this.status=void 0!==n.status?n.status:t,this.statusText=n.statusText||i,this.url=n.url||null,this.ok=this.status>=200&&this.status<300}}class vv extends _v{constructor(n={}){super(n),this.type=kt.ResponseHeader}clone(n={}){return new vv({headers:n.headers||this.headers,status:void 0!==n.status?n.status:this.status,statusText:n.statusText||this.statusText,url:n.url||this.url||void 0})}}class qf extends _v{constructor(n={}){super(n),this.type=kt.Response,this.body=void 0!==n.body?n.body:null}clone(n={}){return new qf({body:void 0!==n.body?n.body:this.body,headers:n.headers||this.headers,status:void 0!==n.status?n.status:this.status,statusText:n.statusText||this.statusText,url:n.url||this.url||void 0})}}class iN extends _v{constructor(n){super(n,0,"Unknown Error"),this.name="HttpErrorResponse",this.ok=!1,this.message=this.status>=200&&this.status<300?`Http failure during parsing for ${n.url||"(unknown url)"}`:`Http failure response for ${n.url||"(unknown url)"}: ${n.status} ${n.statusText}`,this.error=n.error||null}} + */var Ot=(()=>((Ot=Ot||{})[Ot.Sent=0]="Sent",Ot[Ot.UploadProgress=1]="UploadProgress",Ot[Ot.ResponseHeader=2]="ResponseHeader",Ot[Ot.DownloadProgress=3]="DownloadProgress",Ot[Ot.Response=4]="Response",Ot[Ot.User=5]="User",Ot))();class _v{constructor(n,t=200,i="OK"){this.headers=n.headers||new qr,this.status=void 0!==n.status?n.status:t,this.statusText=n.statusText||i,this.url=n.url||null,this.ok=this.status>=200&&this.status<300}}class vv extends _v{constructor(n={}){super(n),this.type=Ot.ResponseHeader}clone(n={}){return new vv({headers:n.headers||this.headers,status:void 0!==n.status?n.status:this.status,statusText:n.statusText||this.statusText,url:n.url||this.url||void 0})}}class qf extends _v{constructor(n={}){super(n),this.type=Ot.Response,this.body=void 0!==n.body?n.body:null}clone(n={}){return new qf({body:void 0!==n.body?n.body:this.body,headers:n.headers||this.headers,status:void 0!==n.status?n.status:this.status,statusText:n.statusText||this.statusText,url:n.url||this.url||void 0})}}class iE extends _v{constructor(n){super(n,0,"Unknown Error"),this.name="HttpErrorResponse",this.ok=!1,this.message=this.status>=200&&this.status<300?`Http failure during parsing for ${n.url||"(unknown url)"}`:`Http failure response for ${n.url||"(unknown url)"}: ${n.status} ${n.statusText}`,this.error=n.error||null}} /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */function yv(e,n){return{body:n,headers:e.headers,context:e.context,observe:e.observe,params:e.params,reportProgress:e.reportProgress,responseType:e.responseType,withCredentials:e.withCredentials}}let rN=(()=>{class e{constructor(t){this.handler=t}request(t,i,r={}){let o;if(t instanceof eu)o=t;else{let l,u;l=r.headers instanceof qr?r.headers:new qr(r.headers),r.params&&(u=r.params instanceof So?r.params:new So({fromObject:r.params})),o=new eu(t,i,void 0!==r.body?r.body:null,{headers:l,context:r.context,params:u,reportProgress:r.reportProgress,responseType:r.responseType||"json",withCredentials:r.withCredentials})}const s=Z(o).pipe(_o(l=>this.handler.handle(l)));if(t instanceof eu||"events"===r.observe)return s;const a=s.pipe(vn(l=>l instanceof qf));switch(r.observe||"body"){case"body":switch(o.responseType){case"arraybuffer":return a.pipe(ne(l=>{if(null!==l.body&&!(l.body instanceof ArrayBuffer))throw new Error("Response is not an ArrayBuffer.");return l.body}));case"blob":return a.pipe(ne(l=>{if(null!==l.body&&!(l.body instanceof Blob))throw new Error("Response is not a Blob.");return l.body}));case"text":return a.pipe(ne(l=>{if(null!==l.body&&"string"!=typeof l.body)throw new Error("Response is not a string.");return l.body}));default:return a.pipe(ne(l=>l.body))}case"response":return a;default:throw new Error(`Unreachable: unhandled observe type ${r.observe}}`)}}delete(t,i={}){return this.request("DELETE",t,i)}get(t,i={}){return this.request("GET",t,i)}head(t,i={}){return this.request("HEAD",t,i)}jsonp(t,i){return this.request("JSONP",t,{params:(new So).append(i,"JSONP_CALLBACK"),observe:"body",responseType:"json"})}options(t,i={}){return this.request("OPTIONS",t,i)}patch(t,i,r={}){return this.request("PATCH",t,yv(r,i))}post(t,i,r={}){return this.request("POST",t,yv(r,i))}put(t,i,r={}){return this.request("PUT",t,yv(r,i))}}return e.\u0275fac=function(t){return new(t||e)(L(ZM))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(); + */function yv(e,n){return{body:n,headers:e.headers,context:e.context,observe:e.observe,params:e.params,reportProgress:e.reportProgress,responseType:e.responseType,withCredentials:e.withCredentials}}let rE=(()=>{class e{constructor(t){this.handler=t}request(t,i,r={}){let o;if(t instanceof eu)o=t;else{let l,u;l=r.headers instanceof qr?r.headers:new qr(r.headers),r.params&&(u=r.params instanceof So?r.params:new So({fromObject:r.params})),o=new eu(t,i,void 0!==r.body?r.body:null,{headers:l,context:r.context,params:u,reportProgress:r.reportProgress,responseType:r.responseType||"json",withCredentials:r.withCredentials})}const s=J(o).pipe(_o(l=>this.handler.handle(l)));if(t instanceof eu||"events"===r.observe)return s;const a=s.pipe(vn(l=>l instanceof qf));switch(r.observe||"body"){case"body":switch(o.responseType){case"arraybuffer":return a.pipe(ne(l=>{if(null!==l.body&&!(l.body instanceof ArrayBuffer))throw new Error("Response is not an ArrayBuffer.");return l.body}));case"blob":return a.pipe(ne(l=>{if(null!==l.body&&!(l.body instanceof Blob))throw new Error("Response is not a Blob.");return l.body}));case"text":return a.pipe(ne(l=>{if(null!==l.body&&"string"!=typeof l.body)throw new Error("Response is not a string.");return l.body}));default:return a.pipe(ne(l=>l.body))}case"response":return a;default:throw new Error(`Unreachable: unhandled observe type ${r.observe}}`)}}delete(t,i={}){return this.request("DELETE",t,i)}get(t,i={}){return this.request("GET",t,i)}head(t,i={}){return this.request("HEAD",t,i)}jsonp(t,i){return this.request("JSONP",t,{params:(new So).append(i,"JSONP_CALLBACK"),observe:"body",responseType:"json"})}options(t,i={}){return this.request("OPTIONS",t,i)}patch(t,i,r={}){return this.request("PATCH",t,yv(r,i))}post(t,i,r={}){return this.request("POST",t,yv(r,i))}put(t,i,r={}){return this.request("PUT",t,yv(r,i))}}return e.\u0275fac=function(t){return new(t||e)(L(JN))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(); /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */class oN{constructor(n,t){this.next=n,this.interceptor=t}handle(n){return this.interceptor.intercept(n,this.next)}}const bv=new q("HTTP_INTERCEPTORS");let jU=(()=>{class e{intercept(t,i){return i.handle(t)}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(); + */class oE{constructor(n,t){this.next=n,this.interceptor=t}handle(n){return this.interceptor.intercept(n,this.next)}}const bv=new q("HTTP_INTERCEPTORS");let jU=(()=>{class e{intercept(t,i){return i.handle(t)}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(); /** * @license * Copyright Google LLC All Rights Reserved. @@ -1983,21 +1983,21 @@ class xU{encodeKey(n){return XM(n)}encodeValue(n){return XM(n)}decodeKey(n){retu * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -const $U=/^\)\]\}',?\n/;let sN=(()=>{class e{constructor(t){this.xhrFactory=t}handle(t){if("JSONP"===t.method)throw new Error("Attempted to construct Jsonp request without HttpClientJsonpModule installed.");return new je(i=>{const r=this.xhrFactory.build();if(r.open(t.method,t.urlWithParams),t.withCredentials&&(r.withCredentials=!0),t.headers.forEach((v,y)=>r.setRequestHeader(v,y.join(","))),t.headers.has("Accept")||r.setRequestHeader("Accept","application/json, text/plain, */*"),!t.headers.has("Content-Type")){const v=t.detectContentTypeHeader();null!==v&&r.setRequestHeader("Content-Type",v)}if(t.responseType){const v=t.responseType.toLowerCase();r.responseType="json"!==v?v:"text"}const o=t.serializeBody();let s=null;const a=()=>{if(null!==s)return s;const v=r.statusText||"OK",y=new qr(r.getAllResponseHeaders()),D=function UU(e){return"responseURL"in e&&e.responseURL?e.responseURL:/^X-Request-URL:/m.test(e.getAllResponseHeaders())?e.getResponseHeader("X-Request-URL"):null}(r)||t.url;return s=new vv({headers:y,status:r.status,statusText:v,url:D}),s},l=()=>{let{headers:v,status:y,statusText:D,url:w}=a(),M=null;204!==y&&(M=typeof r.response>"u"?r.responseText:r.response),0===y&&(y=M?200:0);let I=y>=200&&y<300;if("json"===t.responseType&&"string"==typeof M){const S=M;M=M.replace($U,"");try{M=""!==M?JSON.parse(M):null}catch(O){M=S,I&&(I=!1,M={error:O,text:M})}}I?(i.next(new qf({body:M,headers:v,status:y,statusText:D,url:w||void 0})),i.complete()):i.error(new iN({error:M,headers:v,status:y,statusText:D,url:w||void 0}))},u=v=>{const{url:y}=a(),D=new iN({error:v,status:r.status||0,statusText:r.statusText||"Unknown Error",url:y||void 0});i.error(D)};let f=!1;const p=v=>{f||(i.next(a()),f=!0);let y={type:kt.DownloadProgress,loaded:v.loaded};v.lengthComputable&&(y.total=v.total),"text"===t.responseType&&!!r.responseText&&(y.partialText=r.responseText),i.next(y)},m=v=>{let y={type:kt.UploadProgress,loaded:v.loaded};v.lengthComputable&&(y.total=v.total),i.next(y)};return r.addEventListener("load",l),r.addEventListener("error",u),r.addEventListener("timeout",u),r.addEventListener("abort",u),t.reportProgress&&(r.addEventListener("progress",p),null!==o&&r.upload&&r.upload.addEventListener("progress",m)),r.send(o),i.next({type:kt.Sent}),()=>{r.removeEventListener("error",u),r.removeEventListener("abort",u),r.removeEventListener("load",l),r.removeEventListener("timeout",u),t.reportProgress&&(r.removeEventListener("progress",p),null!==o&&r.upload&&r.upload.removeEventListener("progress",m)),r.readyState!==r.DONE&&r.abort()}})}}return e.\u0275fac=function(t){return new(t||e)(L(FC))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(); +const $U=/^\)\]\}',?\n/;let sE=(()=>{class e{constructor(t){this.xhrFactory=t}handle(t){if("JSONP"===t.method)throw new Error("Attempted to construct Jsonp request without HttpClientJsonpModule installed.");return new je(i=>{const r=this.xhrFactory.build();if(r.open(t.method,t.urlWithParams),t.withCredentials&&(r.withCredentials=!0),t.headers.forEach((v,y)=>r.setRequestHeader(v,y.join(","))),t.headers.has("Accept")||r.setRequestHeader("Accept","application/json, text/plain, */*"),!t.headers.has("Content-Type")){const v=t.detectContentTypeHeader();null!==v&&r.setRequestHeader("Content-Type",v)}if(t.responseType){const v=t.responseType.toLowerCase();r.responseType="json"!==v?v:"text"}const o=t.serializeBody();let s=null;const a=()=>{if(null!==s)return s;const v=r.statusText||"OK",y=new qr(r.getAllResponseHeaders()),D=function UU(e){return"responseURL"in e&&e.responseURL?e.responseURL:/^X-Request-URL:/m.test(e.getAllResponseHeaders())?e.getResponseHeader("X-Request-URL"):null}(r)||t.url;return s=new vv({headers:y,status:r.status,statusText:v,url:D}),s},l=()=>{let{headers:v,status:y,statusText:D,url:w}=a(),N=null;204!==y&&(N=typeof r.response>"u"?r.responseText:r.response),0===y&&(y=N?200:0);let A=y>=200&&y<300;if("json"===t.responseType&&"string"==typeof N){const S=N;N=N.replace($U,"");try{N=""!==N?JSON.parse(N):null}catch(k){N=S,A&&(A=!1,N={error:k,text:N})}}A?(i.next(new qf({body:N,headers:v,status:y,statusText:D,url:w||void 0})),i.complete()):i.error(new iE({error:N,headers:v,status:y,statusText:D,url:w||void 0}))},u=v=>{const{url:y}=a(),D=new iE({error:v,status:r.status||0,statusText:r.statusText||"Unknown Error",url:y||void 0});i.error(D)};let f=!1;const p=v=>{f||(i.next(a()),f=!0);let y={type:Ot.DownloadProgress,loaded:v.loaded};v.lengthComputable&&(y.total=v.total),"text"===t.responseType&&!!r.responseText&&(y.partialText=r.responseText),i.next(y)},m=v=>{let y={type:Ot.UploadProgress,loaded:v.loaded};v.lengthComputable&&(y.total=v.total),i.next(y)};return r.addEventListener("load",l),r.addEventListener("error",u),r.addEventListener("timeout",u),r.addEventListener("abort",u),t.reportProgress&&(r.addEventListener("progress",p),null!==o&&r.upload&&r.upload.addEventListener("progress",m)),r.send(o),i.next({type:Ot.Sent}),()=>{r.removeEventListener("error",u),r.removeEventListener("abort",u),r.removeEventListener("load",l),r.removeEventListener("timeout",u),t.reportProgress&&(r.removeEventListener("progress",p),null!==o&&r.upload&&r.upload.removeEventListener("progress",m)),r.readyState!==r.DONE&&r.abort()}})}}return e.\u0275fac=function(t){return new(t||e)(L(PC))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(); /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */const Dv=new q("XSRF_COOKIE_NAME"),Cv=new q("XSRF_HEADER_NAME");class aN{}let GU=(()=>{class e{constructor(t,i,r){this.doc=t,this.platform=i,this.cookieName=r,this.lastCookieString="",this.lastToken=null,this.parseCount=0}getToken(){if("server"===this.platform)return null;const t=this.doc.cookie||"";return t!==this.lastCookieString&&(this.parseCount++,this.lastToken=wC(t,this.cookieName),this.lastCookieString=t),this.lastToken}}return e.\u0275fac=function(t){return new(t||e)(L(Dt),L(dc),L(Dv))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(),wv=(()=>{class e{constructor(t,i){this.tokenService=t,this.headerName=i}intercept(t,i){const r=t.url.toLowerCase();if("GET"===t.method||"HEAD"===t.method||r.startsWith("http://")||r.startsWith("https://"))return i.handle(t);const o=this.tokenService.getToken();return null!==o&&!t.headers.has(this.headerName)&&(t=t.clone({headers:t.headers.set(this.headerName,o)})),i.handle(t)}}return e.\u0275fac=function(t){return new(t||e)(L(aN),L(Cv))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(),WU=(()=>{class e{constructor(t,i){this.backend=t,this.injector=i,this.chain=null}handle(t){if(null===this.chain){const i=this.injector.get(bv,[]);this.chain=i.reduceRight((r,o)=>new oN(r,o),this.backend)}return this.chain.handle(t)}}return e.\u0275fac=function(t){return new(t||e)(L(QM),L(gn))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(),KU=(()=>{class e{static disable(){return{ngModule:e,providers:[{provide:wv,useClass:jU}]}}static withOptions(t={}){return{ngModule:e,providers:[t.cookieName?{provide:Dv,useValue:t.cookieName}:[],t.headerName?{provide:Cv,useValue:t.headerName}:[]]}}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ne({type:e}),e.\u0275inj=Me({providers:[wv,{provide:bv,useExisting:wv,multi:!0},{provide:aN,useClass:GU},{provide:Dv,useValue:"XSRF-TOKEN"},{provide:Cv,useValue:"X-XSRF-TOKEN"}]}),e})(),zU=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ne({type:e}),e.\u0275inj=Me({providers:[rN,{provide:ZM,useClass:WU},sN,{provide:QM,useExisting:sN}],imports:[KU.withOptions({cookieName:"XSRF-TOKEN",headerName:"X-XSRF-TOKEN"})]}),e})(),lN=(()=>{class e{constructor(t,i){this.config=t,this.http=i}pauseConsumerTopic(t,i){var r=this;return zr(function*(){yield Yr(r.http.put(r.config.rootUrl+`/consumers/${t}/topics/${i}/pause`,""))})()}resumeConsumerTopic(t,i){var r=this;return zr(function*(){yield Yr(r.http.put(r.config.rootUrl+`/consumers/${t}/topics/${i}/resume`,""))})()}resetConsumerTopic(t,i){var r=this;return zr(function*(){yield Yr(r.http.put(r.config.rootUrl+`/consumers/${t}/topics/${i}/reset`,""))})()}rewindConsumerTopic(t,i,r){var o=this;return zr(function*(){const s=zM(r).format("YYYY-MM-DD HH:mm:ss");yield Yr(o.http.put(o.config.rootUrl+`/consumers/${t}/topics/${i}/rewind/${s}`,""))})()}stopConsumer(t){var i=this;return zr(function*(){yield Yr(i.http.put(i.config.rootUrl+`/consumers/${t}/stop`,""))})()}startConsumer(t){var i=this;return zr(function*(){yield Yr(i.http.put(i.config.rootUrl+`/consumers/${t}/start`,""))})()}restartConsumer(t){var i=this;return zr(function*(){yield Yr(i.http.put(i.config.rootUrl+`/consumers/${t}/restart`,""))})()}changeWorkers(t,i){var r=this;return zr(function*(){yield Yr(r.http.put(r.config.rootUrl+`/consumers/${t}/changeWorkers/${i}`,""))})()}getTelemetry(){var t=this;return zr(function*(){return yield Yr(t.http.get(t.config.rootUrl+"/consumers/telemetry"))})()}}return e.\u0275fac=function(t){return new(t||e)(L(JM),L(rN))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(),YU=(()=>{class e{transform(t,i){if(!t)return null;const r=t.reduce((o,s)=>(o[s[i]]?o[s[i]].push(s):o[s[i]]=[s],o),{});return Object.keys(r).map(o=>({key:o,value:r[o]}))}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275pipe=$t({name:"groupBy",type:e,pure:!0}),e})(),qU=(()=>{class e{transform(t,i,r="asc"){return"asc"!==(r=r.toLowerCase())&&"desc"!==r?t:Array.isArray(t)?(t.sort((o,s)=>o[i]s[i]?"asc"===r?1:-1:0),t):null}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275pipe=$t({name:"sort",type:e,pure:!0}),e})(); + */const Dv=new q("XSRF_COOKIE_NAME"),Cv=new q("XSRF_HEADER_NAME");class aE{}let GU=(()=>{class e{constructor(t,i,r){this.doc=t,this.platform=i,this.cookieName=r,this.lastCookieString="",this.lastToken=null,this.parseCount=0}getToken(){if("server"===this.platform)return null;const t=this.doc.cookie||"";return t!==this.lastCookieString&&(this.parseCount++,this.lastToken=wC(t,this.cookieName),this.lastCookieString=t),this.lastToken}}return e.\u0275fac=function(t){return new(t||e)(L(Dt),L(dc),L(Dv))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(),wv=(()=>{class e{constructor(t,i){this.tokenService=t,this.headerName=i}intercept(t,i){const r=t.url.toLowerCase();if("GET"===t.method||"HEAD"===t.method||r.startsWith("http://")||r.startsWith("https://"))return i.handle(t);const o=this.tokenService.getToken();return null!==o&&!t.headers.has(this.headerName)&&(t=t.clone({headers:t.headers.set(this.headerName,o)})),i.handle(t)}}return e.\u0275fac=function(t){return new(t||e)(L(aE),L(Cv))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(),WU=(()=>{class e{constructor(t,i){this.backend=t,this.injector=i,this.chain=null}handle(t){if(null===this.chain){const i=this.injector.get(bv,[]);this.chain=i.reduceRight((r,o)=>new oE(r,o),this.backend)}return this.chain.handle(t)}}return e.\u0275fac=function(t){return new(t||e)(L(QN),L(gn))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(),zU=(()=>{class e{static disable(){return{ngModule:e,providers:[{provide:wv,useClass:jU}]}}static withOptions(t={}){return{ngModule:e,providers:[t.cookieName?{provide:Dv,useValue:t.cookieName}:[],t.headerName?{provide:Cv,useValue:t.headerName}:[]]}}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({providers:[wv,{provide:bv,useExisting:wv,multi:!0},{provide:aE,useClass:GU},{provide:Dv,useValue:"XSRF-TOKEN"},{provide:Cv,useValue:"X-XSRF-TOKEN"}]}),e})(),YU=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({providers:[rE,{provide:JN,useClass:WU},sE,{provide:QN,useExisting:sE}],imports:[zU.withOptions({cookieName:"XSRF-TOKEN",headerName:"X-XSRF-TOKEN"})]}),e})(),lE=(()=>{class e{constructor(t,i){this.config=t,this.http=i}pauseConsumerTopic(t,i){var r=this;return Yr(function*(){yield Kr(r.http.put(r.config.rootUrl+`/consumers/${t}/topics/${i}/pause`,""))})()}resumeConsumerTopic(t,i){var r=this;return Yr(function*(){yield Kr(r.http.put(r.config.rootUrl+`/consumers/${t}/topics/${i}/resume`,""))})()}resetConsumerTopic(t,i){var r=this;return Yr(function*(){yield Kr(r.http.put(r.config.rootUrl+`/consumers/${t}/topics/${i}/reset`,""))})()}rewindConsumerTopic(t,i,r){var o=this;return Yr(function*(){const s=YN(r).format("YYYY-MM-DD HH:mm:ss");yield Kr(o.http.put(o.config.rootUrl+`/consumers/${t}/topics/${i}/rewind/${s}`,""))})()}stopConsumer(t){var i=this;return Yr(function*(){yield Kr(i.http.put(i.config.rootUrl+`/consumers/${t}/stop`,""))})()}startConsumer(t){var i=this;return Yr(function*(){yield Kr(i.http.put(i.config.rootUrl+`/consumers/${t}/start`,""))})()}restartConsumer(t){var i=this;return Yr(function*(){yield Kr(i.http.put(i.config.rootUrl+`/consumers/${t}/restart`,""))})()}changeWorkers(t,i){var r=this;return Yr(function*(){yield Kr(r.http.put(r.config.rootUrl+`/consumers/${t}/changeWorkers/${i}`,""))})()}getTelemetry(){var t=this;return Yr(function*(){return yield Kr(t.http.get(t.config.rootUrl+"/consumers/telemetry"))})()}}return e.\u0275fac=function(t){return new(t||e)(L(ZN),L(rE))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(),KU=(()=>{class e{transform(t,i){if(!t)return null;const r=t.reduce((o,s)=>(o[s[i]]?o[s[i]].push(s):o[s[i]]=[s],o),{});return Object.keys(r).map(o=>({key:o,value:r[o]}))}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275pipe=$t({name:"groupBy",type:e,pure:!0}),e})(),qU=(()=>{class e{transform(t,i,r="asc"){return"asc"!==(r=r.toLowerCase())&&"desc"!==r?t:Array.isArray(t)?(t.sort((o,s)=>o[i]s[i]?"asc"===r?1:-1:0),t):null}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275pipe=$t({name:"sort",type:e,pure:!0}),e})(); /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */const JU=["successAlert"];function ZU(e,n){if(1&e){const t=At();E(0,"ngb-alert",2,3),W("closed",function(){return mt(t),_t(K().successMessage="")}),E(2,"div",4)(3,"b"),A(4,"Success! "),T(),E(5,"span",4),A(6),T()()()}if(2&e){const t=K();F(6),fo(t.successMessage)}}function QU(e,n){if(1&e){const t=At();E(0,"button",14),W("click",function(){mt(t);const r=K().$implicit,o=K().$implicit;return _t(K().openStartModal(o.groupId,r.name))}),A(1,"Start"),T()}}function XU(e,n){if(1&e){const t=At();E(0,"button",15),W("click",function(){mt(t);const r=K().$implicit,o=K().$implicit;return _t(K().openStopModal(o.groupId,r.name))}),A(1,"Stop"),T()}}function e3(e,n){if(1&e){const t=At();E(0,"button",15),W("click",function(){mt(t);const r=K().$implicit,o=K().$implicit;return _t(K().openRestartModal(o.groupId,r.name))}),A(1,"Restart"),T()}}function t3(e,n){if(1&e){const t=At();E(0,"button",16),W("click",function(){mt(t);const r=K().$implicit,o=K().$implicit;return _t(K().openWorkersCountModal(o.groupId,r.name,r.workersCount))}),A(1,"Change number of workers"),T()}}function n3(e,n){if(1&e){const t=At();E(0,"button",14),W("click",function(){mt(t);const r=K().$implicit,o=K().$implicit,s=K().$implicit;return _t(K().openResumeModal(s.groupId,o.name,r.key))}),A(1,"Resume"),T()}}function r3(e,n){if(1&e){const t=At();E(0,"button",15),W("click",function(){mt(t);const r=K().$implicit,o=K().$implicit,s=K().$implicit;return _t(K().openPauseModal(s.groupId,o.name,r.key))}),A(1,"Pause"),T()}}function o3(e,n){if(1&e){const t=At();E(0,"button",20),W("click",function(){mt(t);const r=K().$implicit,o=K().$implicit,s=K().$implicit;return _t(K().openRewindModal(s.groupId,o.name,r.key))}),A(1,"Rewind Offset"),T()}}function s3(e,n){if(1&e){const t=At();E(0,"button",21),W("click",function(){mt(t);const r=K().$implicit,o=K().$implicit,s=K().$implicit;return _t(K().openResetModal(s.groupId,o.name,r.key))}),A(1,"Reset Offset"),T()}}function a3(e,n){1&e&&Li(0,"div")}function l3(e,n){1&e&&(E(0,"span"),A(1,"Offline"),T())}function c3(e,n){1&e&&(E(0,"span",27),A(1,"Paused"),T())}function u3(e,n){1&e&&(E(0,"span",28),A(1,"Running"),T())}function d3(e,n){if(1&e&&(J(0,c3,2,0,"ng-template",26),J(1,u3,2,0,"ng-template",26)),2&e){const t=K().$implicit,i=K(4);Q("ngIf",i.hasPausedPartition(t)),F(1),Q("ngIf",i.hasRunningPartition(t))}}function f3(e,n){if(1&e&&(E(0,"tr")(1,"td",22),A(2),T(),E(3,"td",22),A(4),T(),E(5,"td",22),A(6),T(),E(7,"td",22),J(8,a3,1,0,"div",23),J(9,l3,2,0,"ng-template",null,24,ji),J(11,d3,2,2,"ng-template",null,25,ji),T(),E(13,"td",22)(14,"span",9),A(15),wd(16,"date"),T()()()),2&e){const t=n.$implicit,i=Pi(10),r=Pi(12),o=K(4);F(2),fo(t.instanceName),F(2),fo(o.hasRunningPartition(t)?t.runningPartitions:t.pausedPartitions),F(2),fo(t.lag),F(2),Q("ngIf",t.isLost)("ngIfThen",i)("ngIfElse",r),F(6),Q("ngClass",t.isLost?"text-secondary":"text-success"),F(1),fo(Sd(16,8,t.lastUpdate+"Z","medium"))}}function h3(e,n){if(1&e&&(Li(0,"hr"),E(1,"h5"),A(2),J(3,n3,2,0,"button",10),J(4,r3,2,0,"button",11),J(5,o3,2,0,"button",17),J(6,s3,2,0,"button",18),T(),E(7,"table",19)(8,"thead")(9,"tr")(10,"th"),A(11,"Consumer instance"),T(),E(12,"th"),A(13,"Partitions"),T(),E(14,"th"),A(15,"Lag"),T(),E(16,"th"),A(17,"Status"),T(),E(18,"th"),A(19,"LastUpdate"),T()()(),E(20,"tbody"),J(21,f3,17,11,"ng-template",13),wd(22,"sort"),T()()),2&e){const t=n.$implicit,i=K().$implicit,r=K(2);F(2),Be(" Topic: ",t.key," "),F(1),Q("ngIf",t.value.some(r.hasPausedPartition)),F(1),Q("ngIf",t.value.some(r.hasRunningPartition)),F(1),Q("ngIf","Running"===i.status),F(1),Q("ngIf","Running"===i.status),F(15),Q("ngForOf",Sd(22,6,t.value,"instanceName"))}}const p3=function(e,n,t){return{"text-success":e,"text-warning":n,"text-danger":t}},g3=function(){return[]};function m3(e,n){if(1&e&&(E(0,"div")(1,"h4"),A(2),T(),E(3,"h4"),A(4,"Status: "),E(5,"span",9),A(6),T(),J(7,QU,2,0,"button",10),J(8,XU,2,0,"button",11),J(9,e3,2,0,"button",11),T(),E(10,"h4"),A(11),T(),E(12,"h4"),A(13),J(14,t3,2,0,"button",12),T(),J(15,h3,23,9,"ng-template",13),wd(16,"groupBy"),Li(17,"hr"),T()),2&e){const t=n.$implicit;F(2),Be("Consumer: ",t.name,""),F(3),Q("ngClass",Cd(13,p3,"Running"===t.status,"Paused"===t.status,"Not Running"===t.status)),F(1),fo(t.status),F(1),Q("ngIf","Not Running"===t.status),F(1),Q("ngIf","Running"===t.status),F(1),Q("ngIf","Running"===t.status),F(2),Be("Lag: ",t.lag,""),F(2),Be("Workers: ",t.workersCount," "),F(1),Q("ngIf","Running"===t.status),F(1),Q("ngForOf",Sd(16,10,t.assignments|| + */const ZU=["successAlert"];function JU(e,n){if(1&e){const t=It();M(0,"ngb-alert",2,3),W("closed",function(){return mt(t),_t(z().successMessage="")}),M(2,"div",4)(3,"b"),I(4,"Success! "),T(),M(5,"span",4),I(6),T()()()}if(2&e){const t=z();P(6),fo(t.successMessage)}}function QU(e,n){if(1&e){const t=It();M(0,"button",14),W("click",function(){mt(t);const r=z().$implicit,o=z().$implicit;return _t(z().openStartModal(o.groupId,r.name))}),I(1,"Start"),T()}}function XU(e,n){if(1&e){const t=It();M(0,"button",15),W("click",function(){mt(t);const r=z().$implicit,o=z().$implicit;return _t(z().openStopModal(o.groupId,r.name))}),I(1,"Stop"),T()}}function e3(e,n){if(1&e){const t=It();M(0,"button",15),W("click",function(){mt(t);const r=z().$implicit,o=z().$implicit;return _t(z().openRestartModal(o.groupId,r.name))}),I(1,"Restart"),T()}}function t3(e,n){if(1&e){const t=It();M(0,"button",16),W("click",function(){mt(t);const r=z().$implicit,o=z().$implicit;return _t(z().openWorkersCountModal(o.groupId,r.name,r.workersCount))}),I(1,"Change number of workers"),T()}}function n3(e,n){if(1&e){const t=It();M(0,"button",14),W("click",function(){mt(t);const r=z().$implicit,o=z().$implicit,s=z().$implicit;return _t(z().openResumeModal(s.groupId,o.name,r.key))}),I(1,"Resume"),T()}}function r3(e,n){if(1&e){const t=It();M(0,"button",15),W("click",function(){mt(t);const r=z().$implicit,o=z().$implicit,s=z().$implicit;return _t(z().openPauseModal(s.groupId,o.name,r.key))}),I(1,"Pause"),T()}}function o3(e,n){if(1&e){const t=It();M(0,"button",20),W("click",function(){mt(t);const r=z().$implicit,o=z().$implicit,s=z().$implicit;return _t(z().openRewindModal(s.groupId,o.name,r.key))}),I(1,"Rewind Offset"),T()}}function s3(e,n){if(1&e){const t=It();M(0,"button",21),W("click",function(){mt(t);const r=z().$implicit,o=z().$implicit,s=z().$implicit;return _t(z().openResetModal(s.groupId,o.name,r.key))}),I(1,"Reset Offset"),T()}}function a3(e,n){1&e&&Li(0,"div")}function l3(e,n){1&e&&(M(0,"span"),I(1,"Offline"),T())}function c3(e,n){1&e&&(M(0,"span",27),I(1,"Paused"),T())}function u3(e,n){1&e&&(M(0,"span",28),I(1,"Running"),T())}function d3(e,n){if(1&e&&(Z(0,c3,2,0,"ng-template",26),Z(1,u3,2,0,"ng-template",26)),2&e){const t=z().$implicit,i=z(4);Q("ngIf",i.hasPausedPartition(t)),P(1),Q("ngIf",i.hasRunningPartition(t))}}function f3(e,n){if(1&e&&(M(0,"tr")(1,"td",22),I(2),T(),M(3,"td",22),I(4),T(),M(5,"td",22),I(6),T(),M(7,"td",22),Z(8,a3,1,0,"div",23),Z(9,l3,2,0,"ng-template",null,24,ji),Z(11,d3,2,2,"ng-template",null,25,ji),T(),M(13,"td",22)(14,"span",9),I(15),wd(16,"date"),T()()()),2&e){const t=n.$implicit,i=Fi(10),r=Fi(12),o=z(4);P(2),fo(t.instanceName),P(2),fo(o.hasRunningPartition(t)?t.runningPartitions:t.pausedPartitions),P(2),fo(t.lag),P(2),Q("ngIf",t.isLost)("ngIfThen",i)("ngIfElse",r),P(6),Q("ngClass",t.isLost?"text-secondary":"text-success"),P(1),fo(Sd(16,8,t.lastUpdate+"Z","medium"))}}function h3(e,n){if(1&e&&(Li(0,"hr"),M(1,"h5"),I(2),Z(3,n3,2,0,"button",10),Z(4,r3,2,0,"button",11),Z(5,o3,2,0,"button",17),Z(6,s3,2,0,"button",18),T(),M(7,"table",19)(8,"thead")(9,"tr")(10,"th"),I(11,"Consumer instance"),T(),M(12,"th"),I(13,"Partitions"),T(),M(14,"th"),I(15,"Lag"),T(),M(16,"th"),I(17,"Status"),T(),M(18,"th"),I(19,"LastUpdate"),T()()(),M(20,"tbody"),Z(21,f3,17,11,"ng-template",13),wd(22,"sort"),T()()),2&e){const t=n.$implicit,i=z().$implicit,r=z(2);P(2),He(" Topic: ",t.key," "),P(1),Q("ngIf",t.value.some(r.hasPausedPartition)),P(1),Q("ngIf",t.value.some(r.hasRunningPartition)),P(1),Q("ngIf","Running"===i.status),P(1),Q("ngIf","Running"===i.status),P(15),Q("ngForOf",Sd(22,6,t.value,"instanceName"))}}const p3=function(e,n,t){return{"text-success":e,"text-warning":n,"text-danger":t}},g3=function(){return[]};function m3(e,n){if(1&e&&(M(0,"div")(1,"h4"),I(2),T(),M(3,"h4"),I(4,"Status: "),M(5,"span",9),I(6),T(),Z(7,QU,2,0,"button",10),Z(8,XU,2,0,"button",11),Z(9,e3,2,0,"button",11),T(),M(10,"h4"),I(11),T(),M(12,"h4"),I(13),Z(14,t3,2,0,"button",12),T(),Z(15,h3,23,9,"ng-template",13),wd(16,"groupBy"),Li(17,"hr"),T()),2&e){const t=n.$implicit;P(2),He("Consumer: ",t.name,""),P(3),Q("ngClass",Cd(13,p3,"Running"===t.status,"Paused"===t.status,"Not Running"===t.status)),P(1),fo(t.status),P(1),Q("ngIf","Not Running"===t.status),P(1),Q("ngIf","Running"===t.status),P(1),Q("ngIf","Running"===t.status),P(2),He("Lag: ",t.lag,""),P(2),He("Workers: ",t.workersCount," "),P(1),Q("ngIf","Running"===t.status),P(1),Q("ngForOf",Sd(16,10,t.assignments|| /** * @license * Copyright Google LLC All Rights Reserved. @@ -2005,7 +2005,7 @@ const $U=/^\)\]\}',?\n/;let sN=(()=>{class e{constructor(t){this.xhrFactory=t}ha * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -function t1(e,n,t){const i=rn()+e,r=k();return r[i]===ae?or(r,i,t?n.call(t):n()):function Ql(e,n){return e[n]}(r,i)}(17,g3),"topicName"))}}function _3(e,n){if(1&e&&(E(0,"div",5)(1,"div",6)(2,"div",7)(3,"h3"),A(4),T(),J(5,m3,18,18,"div",8),T()()()),2&e){const t=n.$implicit;F(4),Be("Group Id: ",t.groupId,""),F(1),Q("ngForOf",t.consumers)}}let v3=(()=>{class e{constructor(t,i){this.modalService=t,this.gateway=i,this.successSubject=new Ue,this.delayMs=5e3,this.successMessage="",this.updateData=()=>{this.gateway.getTelemetry().then(r=>{this.telemetryResponse=this.updateConsumersStatus(r)})},this.hasRunningPartition=r=>r.runningPartitions?.length>0,this.hasPausedPartition=r=>r.pausedPartitions?.length>0,this.isActive=r=>Math.abs(((new Date).getTime()-new Date(r+"Z").getTime())/1e3)<30,this.openWorkersCountModal=(r,o,s)=>{const a=this.modalService.open(NU);a.componentInstance.groupId=r,a.componentInstance.consumerName=o,a.componentInstance.workersCount=s,a.result.then(l=>{this.gateway.changeWorkers(o,l).then(()=>this.successSubject.next("The number of workers was updated successfully"))})},this.openResetModal=(r,o,s)=>{const a=this.modalService.open(TU);a.componentInstance.groupId=r,a.componentInstance.consumerName=o,a.componentInstance.topic=s,a.result.then(()=>{this.gateway.resetConsumerTopic(o,s).then(()=>this.successSubject.next("The partition-offsets of your consumer were reseted successfully"))})},this.openPauseModal=(r,o,s)=>{const a=this.modalService.open(AU);a.componentInstance.groupId=r,a.componentInstance.topic=s,a.componentInstance.consumerName=o,a.result.then(()=>{this.gateway.pauseConsumerTopic(o,s).then(()=>this.successSubject.next("Your consumer was paused successfully"))})},this.openRestartModal=(r,o)=>{const s=this.modalService.open(OU);s.componentInstance.groupId=r,s.componentInstance.consumerName=o,s.result.then(()=>{this.gateway.restartConsumer(o).then(()=>this.successSubject.next("Your consumer was restarted successfully"))})},this.openStartModal=(r,o)=>{const s=this.modalService.open(kU);s.componentInstance.groupId=r,s.componentInstance.consumerName=o,s.result.then(()=>{this.gateway.startConsumer(o).then(()=>this.successSubject.next("Your consumer was started successfully"))})},this.openStopModal=(r,o)=>{const s=this.modalService.open(RU);s.componentInstance.groupId=r,s.componentInstance.consumerName=o,s.result.then(()=>{this.gateway.stopConsumer(o).then(()=>this.successSubject.next("Your consumer was stopped successfully"))})},this.openResumeModal=(r,o,s)=>{const a=this.modalService.open(IU);a.componentInstance.groupId=r,a.componentInstance.consumerName=o,a.componentInstance.topic=s,a.result.then(()=>{this.gateway.resumeConsumerTopic(o,s).then(()=>this.successSubject.next("Your consumer was resumed successfully"))})},this.openRewindModal=(r,o,s)=>{const a=this.modalService.open(MU);a.componentInstance.consumerName=o,a.componentInstance.groupId=r,a.componentInstance.topic=s,a.result.then(l=>{const u=zM(l,"YYYY-MM-DDTHH:mm").toDate();this.gateway.rewindConsumerTopic(o,s,u).then(()=>this.successSubject.next("The partition-offset of your consumer were rewound successfully"))})}}ngOnInit(){this.successSubject.subscribe(t=>this.successMessage=t),this.successSubject.pipe(function EU(e,n=xf){return qe((t,i)=>{let r=null,o=null,s=null;const a=()=>{if(r){r.unsubscribe(),r=null;const u=o;o=null,i.next(u)}};function l(){const u=s+e,f=n.now();if(f{o=u,s=n.now(),r||(r=n.schedule(l,e),i.add(r))},()=>{a(),i.complete()},void 0,()=>{o=r=null}))})}(5e3)).subscribe(()=>this.successAlert?.close()),this.updateData(),function SU(e=0,n=xf){return e<0&&(e=0),jc(e,e,n)}(this.delayMs).subscribe(this.updateData)}updateConsumersStatus(t){const i=this;return t.groups?.forEach(r=>{r.consumers?.forEach(o=>{o.status=o.assignments.some(s=>s.runningPartitions?.length>0&&i.isActive(s.lastUpdate))?"Running":o.assignments.some(s=>s.pausedPartitions?.length>0&&i.isActive(s.lastUpdate))?"Paused":"Not Running",o.lag=o.assignments.map(s=>s.lag).reduce((s,a)=>s+a),o.assignments.forEach(s=>s.isLost=!i.isActive(s.lastUpdate))})}),t}}return e.\u0275fac=function(t){return new(t||e)(C(SM),C(lN))},e.\u0275cmp=et({type:e,selectors:[["app-consumer"]],viewQuery:function(t,i){if(1&t&&Md(JU,5),2&t){let r;at(r=lt())&&(i.successAlert=r.first)}},decls:2,vars:2,consts:[["type","success",3,"closed",4,"ngIf"],["class","container",4,"ngFor","ngForOf"],["type","success",3,"closed"],["successAlert",""],[1,"text-center"],[1,"container"],[1,"card","my-3"],[1,"card-body"],[4,"ngFor","ngForOf"],[3,"ngClass"],["class","btn btn-sm btn-outline-success ml-2","type","button",3,"click",4,"ngIf"],["class","btn btn-sm btn-outline-warning ml-2","type","button",3,"click",4,"ngIf"],["class","btn btn-sm btn-outline-success ml-3","type","button",3,"click",4,"ngIf"],["ngFor","",3,"ngForOf"],["type","button",1,"btn","btn-sm","btn-outline-success","ml-2",3,"click"],["type","button",1,"btn","btn-sm","btn-outline-warning","ml-2",3,"click"],["type","button",1,"btn","btn-sm","btn-outline-success","ml-3",3,"click"],["class","btn btn-sm btn-outline-info ml-2","type","button",3,"click",4,"ngIf"],["class","btn btn-sm btn-outline-secondary ml-2","type","button",3,"click",4,"ngIf"],[1,"table","table-striped","table-hover","mt-1"],["type","button",1,"btn","btn-sm","btn-outline-info","ml-2",3,"click"],["type","button",1,"btn","btn-sm","btn-outline-secondary","ml-2",3,"click"],[1,"text-left"],[4,"ngIf","ngIfThen","ngIfElse"],["consumer_lost",""],["consumer_on",""],[3,"ngIf"],[1,"font-weight-bold","text-warning"],[1,"font-weight-bold","text-success"]],template:function(t,i){1&t&&(J(0,ZU,7,1,"ngb-alert",0),J(1,_3,6,2,"div",1)),2&t&&(Q("ngIf",i.successMessage),F(1),Q("ngForOf",null==i.telemetryResponse?null:i.telemetryResponse.groups))},dependencies:[SC,ka,ns,y$,IC,YU,qU],encapsulation:2}),e})(),y3=(()=>{class e{constructor(){}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275cmp=et({type:e,selectors:[["app-home"]],decls:12,vars:0,consts:[[1,"navbar","navbar-expand-lg","navbar-light","bg-light"],[1,"container-fluid"],["href","#",1,"navbar-brand"],["type","button","data-bs-toggle","collapse","data-bs-target","#navbarSupportedContent","aria-controls","navbarSupportedContent","aria-expanded","false","aria-label","Toggle navigation",1,"navbar-toggler"],[1,"navbar-toggler-icon"],["id","navbarSupportedContent",1,"collapse","navbar-collapse"],[1,"navbar-nav","me-auto","mb-2","mb-lg-0"],[1,"nav-item"],["aria-current","page","href","#",1,"nav-link","active"]],template:function(t,i){1&t&&(E(0,"nav",0)(1,"div",1)(2,"a",2),A(3,"KafkaFlow - Dashboard"),T(),E(4,"button",3),Li(5,"span",4),T(),E(6,"div",5)(7,"ul",6)(8,"li",7)(9,"a",8),A(10,"Consumers"),T()()()()()(),Li(11,"app-consumer"))},dependencies:[hv,v3],encapsulation:2}),e})(),D3=(()=>{class e{constructor(t){this.cookieService=t}intercept(t,i){return t=t.clone({setHeaders:this.cookieService.getAll()}),i.handle(t).pipe(function b3(e=1/0){let n;n=e&&"object"==typeof e?e:{count:e};const{count:t=1/0,delay:i,resetOnSuccess:r=!1}=n;return t<=0?xn:qe((o,s)=>{let l,a=0;const u=()=>{let f=!1;l=o.subscribe(ke(s,p=>{r&&(a=0),s.next(p)},void 0,p=>{if(a++{l?(l.unsubscribe(),l=null,u()):f=!0};if(null!=i){const v="number"==typeof i?jc(i):ut(i(p,a)),y=ke(s,()=>{y.unsubscribe(),m()},()=>{s.complete()});v.subscribe(y)}else m()}else s.error(p)})),f&&(l.unsubscribe(),l=null,u())};u()})}(1),$r(r=>{let o="";return o=r.error instanceof ErrorEvent?`Error: ${r.error.message}`:`Error Code: ${r.status}\nMessage: ${r.message}`,console.error(o),Ra(o)}))}}return e.\u0275fac=function(t){return new(t||e)(L(NE))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})();const C3={validation:!1},w3=[{path:"",component:y3}];let S3=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ne({type:e,bootstrap:[wH]}),e.\u0275inj=Me({providers:[JM,NE,lN,{provide:bv,useClass:D3,multi:!0}],imports:[kP,CH,Cf.forRoot(w3),zU,CE,wU,bH.forRoot(C3),Cf]}),e})();(function ox(){Q1=!1} +function t1(e,n,t){const i=rn()+e,r=O();return r[i]===ae?or(r,i,t?n.call(t):n()):function Ql(e,n){return e[n]}(r,i)}(17,g3),"topicName"))}}function _3(e,n){if(1&e&&(M(0,"div",5)(1,"div",6)(2,"div",7)(3,"h3"),I(4),T(),Z(5,m3,18,18,"div",8),T()()()),2&e){const t=n.$implicit;P(4),He("Group Id: ",t.groupId,""),P(1),Q("ngForOf",t.consumers)}}let v3=(()=>{class e{constructor(t,i){this.modalService=t,this.gateway=i,this.successSubject=new Ue,this.delayMs=5e3,this.successMessage="",this.updateData=()=>{this.gateway.getTelemetry().then(r=>{this.telemetryResponse=this.updateConsumersStatus(r)})},this.hasRunningPartition=r=>r.runningPartitions?.length>0,this.hasPausedPartition=r=>r.pausedPartitions?.length>0,this.isActive=r=>Math.abs(((new Date).getTime()-new Date(r+"Z").getTime())/1e3)<30,this.openWorkersCountModal=(r,o,s)=>{const a=this.modalService.open(EU);a.componentInstance.groupId=r,a.componentInstance.consumerName=o,a.componentInstance.workersCount=s,a.result.then(l=>{this.gateway.changeWorkers(o,l).then(()=>this.successSubject.next("The number of workers was updated successfully"))})},this.openResetModal=(r,o,s)=>{const a=this.modalService.open(TU);a.componentInstance.groupId=r,a.componentInstance.consumerName=o,a.componentInstance.topic=s,a.result.then(()=>{this.gateway.resetConsumerTopic(o,s).then(()=>this.successSubject.next("The partition-offsets of your consumer were reseted successfully"))})},this.openPauseModal=(r,o,s)=>{const a=this.modalService.open(IU);a.componentInstance.groupId=r,a.componentInstance.topic=s,a.componentInstance.consumerName=o,a.result.then(()=>{this.gateway.pauseConsumerTopic(o,s).then(()=>this.successSubject.next("Your consumer was paused successfully"))})},this.openRestartModal=(r,o)=>{const s=this.modalService.open(kU);s.componentInstance.groupId=r,s.componentInstance.consumerName=o,s.result.then(()=>{this.gateway.restartConsumer(o).then(()=>this.successSubject.next("Your consumer was restarted successfully"))})},this.openStartModal=(r,o)=>{const s=this.modalService.open(OU);s.componentInstance.groupId=r,s.componentInstance.consumerName=o,s.result.then(()=>{this.gateway.startConsumer(o).then(()=>this.successSubject.next("Your consumer was started successfully"))})},this.openStopModal=(r,o)=>{const s=this.modalService.open(xU);s.componentInstance.groupId=r,s.componentInstance.consumerName=o,s.result.then(()=>{this.gateway.stopConsumer(o).then(()=>this.successSubject.next("Your consumer was stopped successfully"))})},this.openResumeModal=(r,o,s)=>{const a=this.modalService.open(AU);a.componentInstance.groupId=r,a.componentInstance.consumerName=o,a.componentInstance.topic=s,a.result.then(()=>{this.gateway.resumeConsumerTopic(o,s).then(()=>this.successSubject.next("Your consumer was resumed successfully"))})},this.openRewindModal=(r,o,s)=>{const a=this.modalService.open(NU);a.componentInstance.consumerName=o,a.componentInstance.groupId=r,a.componentInstance.topic=s,a.result.then(l=>{const u=YN(l,"YYYY-MM-DDTHH:mm").toDate();this.gateway.rewindConsumerTopic(o,s,u).then(()=>this.successSubject.next("The partition-offset of your consumer were rewound successfully"))})}}ngOnInit(){this.successSubject.subscribe(t=>this.successMessage=t),this.successSubject.pipe(function MU(e,n=Rf){return qe((t,i)=>{let r=null,o=null,s=null;const a=()=>{if(r){r.unsubscribe(),r=null;const u=o;o=null,i.next(u)}};function l(){const u=s+e,f=n.now();if(f{o=u,s=n.now(),r||(r=n.schedule(l,e),i.add(r))},()=>{a(),i.complete()},void 0,()=>{o=r=null}))})}(5e3)).subscribe(()=>this.successAlert?.close()),this.updateData(),function SU(e=0,n=Rf){return e<0&&(e=0),jc(e,e,n)}(this.delayMs).subscribe(this.updateData)}updateConsumersStatus(t){const i=this;return t.groups?.forEach(r=>{r.consumers?.forEach(o=>{o.status=o.assignments.some(s=>s.runningPartitions?.length>0&&i.isActive(s.lastUpdate))?"Running":o.assignments.some(s=>s.pausedPartitions?.length>0&&i.isActive(s.lastUpdate))?"Paused":"Not Running",o.lag=o.assignments.map(s=>s.lag).reduce((s,a)=>s+a),o.assignments.forEach(s=>s.isLost=!i.isActive(s.lastUpdate))})}),t}}return e.\u0275fac=function(t){return new(t||e)(C(SN),C(lE))},e.\u0275cmp=et({type:e,selectors:[["app-consumer"]],viewQuery:function(t,i){if(1&t&&Nd(ZU,5),2&t){let r;at(r=lt())&&(i.successAlert=r.first)}},decls:2,vars:2,consts:[["type","success",3,"closed",4,"ngIf"],["class","container",4,"ngFor","ngForOf"],["type","success",3,"closed"],["successAlert",""],[1,"text-center"],[1,"container"],[1,"card","my-3"],[1,"card-body"],[4,"ngFor","ngForOf"],[3,"ngClass"],["class","btn btn-sm btn-outline-success ml-2","type","button",3,"click",4,"ngIf"],["class","btn btn-sm btn-outline-warning ml-2","type","button",3,"click",4,"ngIf"],["class","btn btn-sm btn-outline-success ml-3","type","button",3,"click",4,"ngIf"],["ngFor","",3,"ngForOf"],["type","button",1,"btn","btn-sm","btn-outline-success","ml-2",3,"click"],["type","button",1,"btn","btn-sm","btn-outline-warning","ml-2",3,"click"],["type","button",1,"btn","btn-sm","btn-outline-success","ml-3",3,"click"],["class","btn btn-sm btn-outline-info ml-2","type","button",3,"click",4,"ngIf"],["class","btn btn-sm btn-outline-secondary ml-2","type","button",3,"click",4,"ngIf"],[1,"table","table-striped","table-hover","mt-1"],["type","button",1,"btn","btn-sm","btn-outline-info","ml-2",3,"click"],["type","button",1,"btn","btn-sm","btn-outline-secondary","ml-2",3,"click"],[1,"text-left"],[4,"ngIf","ngIfThen","ngIfElse"],["consumer_lost",""],["consumer_on",""],[3,"ngIf"],[1,"font-weight-bold","text-warning"],[1,"font-weight-bold","text-success"]],template:function(t,i){1&t&&(Z(0,JU,7,1,"ngb-alert",0),Z(1,_3,6,2,"div",1)),2&t&&(Q("ngIf",i.successMessage),P(1),Q("ngForOf",null==i.telemetryResponse?null:i.telemetryResponse.groups))},dependencies:[SC,Oa,ns,y$,AC,KU,qU],encapsulation:2}),e})(),y3=(()=>{class e{constructor(){}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275cmp=et({type:e,selectors:[["app-home"]],decls:12,vars:0,consts:[[1,"navbar","navbar-expand-lg","navbar-light","bg-light"],[1,"container-fluid"],["href","#",1,"navbar-brand"],["type","button","data-bs-toggle","collapse","data-bs-target","#navbarSupportedContent","aria-controls","navbarSupportedContent","aria-expanded","false","aria-label","Toggle navigation",1,"navbar-toggler"],[1,"navbar-toggler-icon"],["id","navbarSupportedContent",1,"collapse","navbar-collapse"],[1,"navbar-nav","me-auto","mb-2","mb-lg-0"],[1,"nav-item"],["aria-current","page","href","#",1,"nav-link","active"]],template:function(t,i){1&t&&(M(0,"nav",0)(1,"div",1)(2,"a",2),I(3,"KafkaFlow - Dashboard"),T(),M(4,"button",3),Li(5,"span",4),T(),M(6,"div",5)(7,"ul",6)(8,"li",7)(9,"a",8),I(10,"Consumers"),T()()()()()(),Li(11,"app-consumer"))},dependencies:[hv,v3],encapsulation:2}),e})(),D3=(()=>{class e{constructor(t){this.cookieService=t}intercept(t,i){return t=t.clone({setHeaders:this.cookieService.getAll()}),i.handle(t).pipe(function b3(e=1/0){let n;n=e&&"object"==typeof e?e:{count:e};const{count:t=1/0,delay:i,resetOnSuccess:r=!1}=n;return t<=0?Rn:qe((o,s)=>{let l,a=0;const u=()=>{let f=!1;l=o.subscribe(Oe(s,p=>{r&&(a=0),s.next(p)},void 0,p=>{if(a++{l?(l.unsubscribe(),l=null,u()):f=!0};if(null!=i){const v="number"==typeof i?jc(i):ut(i(p,a)),y=Oe(s,()=>{y.unsubscribe(),m()},()=>{s.complete()});v.subscribe(y)}else m()}else s.error(p)})),f&&(l.unsubscribe(),l=null,u())};u()})}(1),$r(r=>{let o="";return o=r.error instanceof ErrorEvent?`Error: ${r.error.message}`:`Error Code: ${r.status}\nMessage: ${r.message}`,console.error(o),xa(o)}))}}return e.\u0275fac=function(t){return new(t||e)(L(EM))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})();const C3={validation:!1},w3=[{path:"",component:y3}];let S3=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e,bootstrap:[wB]}),e.\u0275inj=Ne({providers:[ZN,EM,lE,{provide:bv,useClass:D3,multi:!0}],imports:[OF,CB,Cf.forRoot(w3),YU,CM,wU,bB.forRoot(C3),Cf]}),e})();(function oR(){Q1=!1} /** * @license * Copyright Google LLC All Rights Reserved. @@ -2026,6 +2026,6 @@ function t1(e,n,t){const i=rn()+e,r=k();return r[i]===ae?or(r,i,t?n.call(t):n()) * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license - */)(),OP().bootstrapModule(S3).catch(e=>console.error(e))},439:function(gr,th,iu){(gr=iu.nmd(gr)).exports=function(){"use strict";var ye,Mo;function V(){return ye.apply(null,arguments)}function dn(c){return c instanceof Array||"[object Array]"===Object.prototype.toString.call(c)}function Ct(c){return null!=c&&"[object Object]"===Object.prototype.toString.call(c)}function we(c,d){return Object.prototype.hasOwnProperty.call(c,d)}function bs(c){if(Object.getOwnPropertyNames)return 0===Object.getOwnPropertyNames(c).length;var d;for(d in c)if(we(c,d))return!1;return!0}function qt(c){return void 0===c}function Jt(c){return"number"==typeof c||"[object Number]"===Object.prototype.toString.call(c)}function Zi(c){return c instanceof Date||"[object Date]"===Object.prototype.toString.call(c)}function Ja(c,d){var g,h=[],_=c.length;for(g=0;g<_;++g)h.push(d(c[g],g));return h}function Dn(c,d){for(var h in d)we(d,h)&&(c[h]=d[h]);return we(d,"toString")&&(c.toString=d.toString),we(d,"valueOf")&&(c.valueOf=d.valueOf),c}function ii(c,d,h,g){return Zr(c,d,h,g,!0).utc()}function le(c){return null==c._pf&&(c._pf={empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidEra:null,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1,parsedDateParts:[],era:null,meridiem:null,rfc2822:!1,weekdayMismatch:!1}),c._pf}function Ci(c){if(null==c._isValid){var d=le(c),h=Mo.call(d.parsedDateParts,function(_){return null!=_}),g=!isNaN(c._d.getTime())&&d.overflow<0&&!d.empty&&!d.invalidEra&&!d.invalidMonth&&!d.invalidWeekday&&!d.weekdayMismatch&&!d.nullInput&&!d.invalidFormat&&!d.userInvalidated&&(!d.meridiem||d.meridiem&&h);if(c._strict&&(g=g&&0===d.charsLeftOver&&0===d.unusedTokens.length&&void 0===d.bigHour),null!=Object.isFrozen&&Object.isFrozen(c))return g;c._isValid=g}return c._isValid}function mr(c){var d=ii(NaN);return null!=c?Dn(le(d),c):le(d).userInvalidated=!0,d}Mo=Array.prototype.some?Array.prototype.some:function(c){var g,d=Object(this),h=d.length>>>0;for(g=0;g0)for(h=0;h=0?h?"+":"":"-")+Math.pow(10,Math.max(0,d-g.length)).toString().substr(1)+g}var el=/(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|N{1,5}|YYYYYY|YYYYY|YYYY|YY|y{2,4}|yo?|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,ws=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,Ue={},yr={};function z(c,d,h,g){var _=g;"string"==typeof g&&(_=function(){return this[g]()}),c&&(yr[c]=_),d&&(yr[d[0]]=function(){return oi(_.apply(this,arguments),d[1],d[2])}),h&&(yr[h]=function(){return this.localeData().ordinal(_.apply(this,arguments),c)})}function qe(c){return c.match(/\[[\s\S]/)?c.replace(/^\[|\]$/g,""):c.replace(/\\/g,"")}function Ss(c,d){return c.isValid()?(d=ne(d,c.localeData()),Ue[d]=Ue[d]||function ke(c){var h,g,d=c.match(el);for(h=0,g=d.length;h=0&&ws.test(c);)c=c.replace(ws,g),ws.lastIndex=0,h-=1;return c}var Es={};function Rt(c,d){var h=c.toLowerCase();Es[h]=Es[h+"s"]=Es[d]=c}function Fn(c){return"string"==typeof c?Es[c]||Es[c.toLowerCase()]:void 0}function cu(c){var h,g,d={};for(g in c)we(c,g)&&(h=Fn(g))&&(d[h]=c[g]);return d}var rh={};function Qt(c,d){rh[c]=d}function Ms(c){return c%4==0&&c%100!=0||c%400==0}function Kn(c){return c<0?Math.ceil(c)||0:Math.floor(c)}function he(c){var d=+c,h=0;return 0!==d&&isFinite(d)&&(h=Kn(d)),h}function To(c,d){return function(h){return null!=h?(oh(this,c,h),V.updateOffset(this,d),this):Ns(this,c)}}function Ns(c,d){return c.isValid()?c._d["get"+(c._isUTC?"UTC":"")+d]():NaN}function oh(c,d,h){c.isValid()&&!isNaN(h)&&("FullYear"===d&&Ms(c.year())&&1===c.month()&&29===c.date()?(h=he(h),c._d["set"+(c._isUTC?"UTC":"")+d](h,c.month(),ks(h,c.month()))):c._d["set"+(c._isUTC?"UTC":"")+d](h))}var Ro,sh=/\d/,Pn=/\d\d/,Ts=/\d{3}/,As=/\d{4}/,Ao=/[+-]?\d{6}/,Ge=/\d\d?/,nl=/\d\d\d\d?/,uu=/\d\d\d\d\d\d?/,Io=/\d{1,3}/,Is=/\d{1,4}/,Oo=/[+-]?\d{1,6}/,Dr=/\d+/,ut=/[+-]?\d+/,ah=/Z|[+-]\d\d:?\d\d/gi,Os=/Z|[+-]\d\d(?::?\d\d)?/gi,ko=/[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i;function $(c,d,h){Ro[c]=ri(d)?d:function(g,_){return g&&h?h:d}}function ch(c,d){return we(Ro,c)?Ro[c](d._strict,d._locale):new RegExp(function wi(c){return Cn(c.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(d,h,g,_,b){return h||g||_||b}))}(c))}function Cn(c){return c.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}Ro={};var dt={};function Se(c,d){var h,_,g=d;for("string"==typeof c&&(c=[c]),Jt(d)&&(g=function(b,N){N[d]=he(b)}),_=c.length,h=0;h<_;h++)dt[c[h]]=g}function Xt(c,d){Se(c,function(h,g,_,b){_._w=_._w||{},d(h,_._w,_,b)})}function Pv(c,d,h){null!=d&&we(dt,c)&&dt[c](d,h._a,h,c)}var ft;function ks(c,d){if(isNaN(c)||isNaN(d))return NaN;var h=function dh(c,d){return(c%d+d)%d}(d,12);return c+=(d-h)/12,1===h?Ms(c)?29:28:31-h%7%2}ft=Array.prototype.indexOf?Array.prototype.indexOf:function(c){var d;for(d=0;d68?1900:2e3)};var P=To("FullYear",!0);function oe(c,d,h,g,_,b,N){var Y;return c<100&&c>=0?(Y=new Date(c+400,d,h,g,_,b,N),isFinite(Y.getFullYear())&&Y.setFullYear(c)):Y=new Date(c,d,h,g,_,b,N),Y}function _e(c){var d,h;return c<100&&c>=0?((h=Array.prototype.slice.call(arguments))[0]=c+400,d=new Date(Date.UTC.apply(null,h)),isFinite(d.getUTCFullYear())&&d.setUTCFullYear(c)):d=new Date(Date.UTC.apply(null,arguments)),d}function Ls(c,d,h){var g=7+d-h;return-(7+_e(c,0,g).getUTCDay()-d)%7+g-1}function gh(c,d,h,g,_){var ce,Pe,Y=1+7*(d-1)+(7+h-g)%7+Ls(c,g,_);return Y<=0?Pe=Fs(ce=c-1)+Y:Y>Fs(c)?(ce=c+1,Pe=Y-Fs(c)):(ce=c,Pe=Y),{year:ce,dayOfYear:Pe}}function xo(c,d,h){var b,N,g=Ls(c.year(),d,h),_=Math.floor((c.dayOfYear()-g-1)/7)+1;return _<1?b=_+Vn(N=c.year()-1,d,h):_>Vn(c.year(),d,h)?(b=_-Vn(c.year(),d,h),N=c.year()+1):(N=c.year(),b=_),{week:b,year:N}}function Vn(c,d,h){var g=Ls(c,d,h),_=Ls(c+1,d,h);return(Fs(c)-g+_)/7}z("w",["ww",2],"wo","week"),z("W",["WW",2],"Wo","isoWeek"),Rt("week","w"),Rt("isoWeek","W"),Qt("week",5),Qt("isoWeek",5),$("w",Ge),$("ww",Ge,Pn),$("W",Ge),$("WW",Ge,Pn),Xt(["w","ww","W","WW"],function(c,d,h,g){d[g.substr(0,1)]=he(c)});function gu(c,d){return c.slice(d,7).concat(c.slice(0,d))}z("d",0,"do","day"),z("dd",0,0,function(c){return this.localeData().weekdaysMin(this,c)}),z("ddd",0,0,function(c){return this.localeData().weekdaysShort(this,c)}),z("dddd",0,0,function(c){return this.localeData().weekdays(this,c)}),z("e",0,0,"weekday"),z("E",0,0,"isoWeekday"),Rt("day","d"),Rt("weekday","e"),Rt("isoWeekday","E"),Qt("day",11),Qt("weekday",11),Qt("isoWeekday",11),$("d",Ge),$("e",Ge),$("E",Ge),$("dd",function(c,d){return d.weekdaysMinRegex(c)}),$("ddd",function(c,d){return d.weekdaysShortRegex(c)}),$("dddd",function(c,d){return d.weekdaysRegex(c)}),Xt(["dd","ddd","dddd"],function(c,d,h,g){var _=h._locale.weekdaysParse(c,g,h._strict);null!=_?d.d=_:le(h).invalidWeekday=c}),Xt(["d","e","E"],function(c,d,h,g){d[g]=he(c)});var _h="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),vh="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),yh="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),$v=ko,Sn=ko,Oe=ko;function G(c,d,h){var g,_,b,N=c.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],g=0;g<7;++g)b=ii([2e3,1]).day(g),this._minWeekdaysParse[g]=this.weekdaysMin(b,"").toLocaleLowerCase(),this._shortWeekdaysParse[g]=this.weekdaysShort(b,"").toLocaleLowerCase(),this._weekdaysParse[g]=this.weekdays(b,"").toLocaleLowerCase();return h?"dddd"===d?-1!==(_=ft.call(this._weekdaysParse,N))?_:null:"ddd"===d?-1!==(_=ft.call(this._shortWeekdaysParse,N))?_:null:-1!==(_=ft.call(this._minWeekdaysParse,N))?_:null:"dddd"===d?-1!==(_=ft.call(this._weekdaysParse,N))||-1!==(_=ft.call(this._shortWeekdaysParse,N))||-1!==(_=ft.call(this._minWeekdaysParse,N))?_:null:"ddd"===d?-1!==(_=ft.call(this._shortWeekdaysParse,N))||-1!==(_=ft.call(this._weekdaysParse,N))||-1!==(_=ft.call(this._minWeekdaysParse,N))?_:null:-1!==(_=ft.call(this._minWeekdaysParse,N))||-1!==(_=ft.call(this._weekdaysParse,N))||-1!==(_=ft.call(this._shortWeekdaysParse,N))?_:null}function Hs(){function c(vt,Ri){return Ri.length-vt.length}var b,N,Y,ce,Pe,d=[],h=[],g=[],_=[];for(b=0;b<7;b++)N=ii([2e3,1]).day(b),Y=Cn(this.weekdaysMin(N,"")),ce=Cn(this.weekdaysShort(N,"")),Pe=Cn(this.weekdays(N,"")),d.push(Y),h.push(ce),g.push(Pe),_.push(Y),_.push(ce),_.push(Pe);d.sort(c),h.sort(c),g.sort(c),_.sort(c),this._weekdaysRegex=new RegExp("^("+_.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+g.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+h.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+d.join("|")+")","i")}function Jr(){return this.hours()%12||12}function sl(c,d){z(c,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),d)})}function _u(c,d){return d._meridiemParse}z("H",["HH",2],0,"hour"),z("h",["hh",2],0,Jr),z("k",["kk",2],0,function ol(){return this.hours()||24}),z("hmm",0,0,function(){return""+Jr.apply(this)+oi(this.minutes(),2)}),z("hmmss",0,0,function(){return""+Jr.apply(this)+oi(this.minutes(),2)+oi(this.seconds(),2)}),z("Hmm",0,0,function(){return""+this.hours()+oi(this.minutes(),2)}),z("Hmmss",0,0,function(){return""+this.hours()+oi(this.minutes(),2)+oi(this.seconds(),2)}),sl("a",!0),sl("A",!1),Rt("hour","h"),Qt("hour",13),$("a",_u),$("A",_u),$("H",Ge),$("h",Ge),$("k",Ge),$("HH",Ge,Pn),$("hh",Ge,Pn),$("kk",Ge,Pn),$("hmm",nl),$("hmmss",uu),$("Hmm",nl),$("Hmmss",uu),Se(["H","HH"],3),Se(["k","kk"],function(c,d,h){var g=he(c);d[3]=24===g?0:g}),Se(["a","A"],function(c,d,h){h._isPm=h._locale.isPM(c),h._meridiem=c}),Se(["h","hh"],function(c,d,h){d[3]=he(c),le(h).bigHour=!0}),Se("hmm",function(c,d,h){var g=c.length-2;d[3]=he(c.substr(0,g)),d[4]=he(c.substr(g)),le(h).bigHour=!0}),Se("hmmss",function(c,d,h){var g=c.length-4,_=c.length-2;d[3]=he(c.substr(0,g)),d[4]=he(c.substr(g,2)),d[5]=he(c.substr(_)),le(h).bigHour=!0}),Se("Hmm",function(c,d,h){var g=c.length-2;d[3]=he(c.substr(0,g)),d[4]=he(c.substr(g))}),Se("Hmmss",function(c,d,h){var g=c.length-4,_=c.length-2;d[3]=he(c.substr(0,g)),d[4]=he(c.substr(g,2)),d[5]=he(c.substr(_))});var wh=To("Hours",!0);var tn,ll={calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},longDateFormat:{LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},invalidDate:"Invalid date",ordinal:"%d",dayOfMonthOrdinalParse:/\d{1,2}/,relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",w:"a week",ww:"%d weeks",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},months:fu,monthsShort:hu,week:{dow:0,doy:6},weekdays:_h,weekdaysMin:yh,weekdaysShort:vh,meridiemParse:/[ap]\.?m?\.?/i},Xe={},Bn={};function zv(c,d){var h,g=Math.min(c.length,d.length);for(h=0;h0;){if(_=cl(b.slice(0,h).join("-")))return _;if(g&&g.length>=h&&zv(b,g)>=h-1)break;h--}d++}return tn}(c)}function Fo(c){var d,h=c._a;return h&&-2===le(c).overflow&&(d=h[1]<0||h[1]>11?1:h[2]<1||h[2]>ks(h[0],h[1])?2:h[3]<0||h[3]>24||24===h[3]&&(0!==h[4]||0!==h[5]||0!==h[6])?3:h[4]<0||h[4]>59?4:h[5]<0||h[5]>59?5:h[6]<0||h[6]>999?6:-1,le(c)._overflowDayOfYear&&(d<0||d>2)&&(d=2),le(c)._overflowWeeks&&-1===d&&(d=7),le(c)._overflowWeekday&&-1===d&&(d=8),le(c).overflow=d),c}var vu=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Mi=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d|))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Po=/Z|[+-]\d\d(?::?\d\d)?/,Bs=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/],["YYYYMM",/\d{6}/,!1],["YYYY",/\d{4}/,!1]],et=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],Eh=/^\/?Date\((-?\d+)/i,yu=/^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/,bu={UT:0,GMT:0,EDT:-240,EST:-300,CDT:-300,CST:-360,MDT:-360,MST:-420,PDT:-420,PST:-480};function Ne(c){var d,h,b,N,Y,ce,g=c._i,_=vu.exec(g)||Mi.exec(g),Pe=Bs.length,vt=et.length;if(_){for(le(c).iso=!0,d=0,h=Pe;d7)&&(ce=!0)):(b=c._locale._week.dow,N=c._locale._week.doy,Pe=xo(xe(),b,N),h=zn(d.gg,c._a[0],Pe.year),g=zn(d.w,Pe.week),null!=d.d?((_=d.d)<0||_>6)&&(ce=!0):null!=d.e?(_=d.e+b,(d.e<0||d.e>6)&&(ce=!0)):_=b),g<1||g>Vn(h,b,N)?le(c)._overflowWeeks=!0:null!=ce?le(c)._overflowWeekday=!0:(Y=gh(h,g,_,b,N),c._a[0]=Y.year,c._dayOfYear=Y.dayOfYear)}(c),null!=c._dayOfYear&&(N=zn(c._a[0],_[0]),(c._dayOfYear>Fs(N)||0===c._dayOfYear)&&(le(c)._overflowDayOfYear=!0),h=_e(N,0,c._dayOfYear),c._a[1]=h.getUTCMonth(),c._a[2]=h.getUTCDate()),d=0;d<3&&null==c._a[d];++d)c._a[d]=g[d]=_[d];for(;d<7;d++)c._a[d]=g[d]=c._a[d]??(2===d?1:0);24===c._a[3]&&0===c._a[4]&&0===c._a[5]&&0===c._a[6]&&(c._nextDay=!0,c._a[3]=0),c._d=(c._useUTC?_e:oe).apply(null,g),b=c._useUTC?c._d.getUTCDay():c._d.getDay(),null!=c._tzm&&c._d.setUTCMinutes(c._d.getUTCMinutes()-c._tzm),c._nextDay&&(c._a[3]=24),c._w&&typeof c._w.d<"u"&&c._w.d!==b&&(le(c).weekdayMismatch=!0)}}function se(c){if(c._f!==V.ISO_8601)if(c._f!==V.RFC_2822){c._a=[],le(c).empty=!0;var h,g,_,b,N,Pe,vt,d=""+c._i,Y=d.length,ce=0;for(vt=(_=ne(c._f,c._locale).match(el)||[]).length,h=0;h0&&le(c).unusedInput.push(N),d=d.slice(d.indexOf(g)+g.length),ce+=g.length),yr[b]?(g?le(c).empty=!1:le(c).unusedTokens.push(b),Pv(b,g,c)):c._strict&&!g&&le(c).unusedTokens.push(b);le(c).charsLeftOver=Y-ce,d.length>0&&le(c).unusedInput.push(d),c._a[3]<=12&&!0===le(c).bigHour&&c._a[3]>0&&(le(c).bigHour=void 0),le(c).parsedDateParts=c._a.slice(0),le(c).meridiem=c._meridiem,c._a[3]=function Je(c,d,h){var g;return null==h?d:null!=c.meridiemHour?c.meridiemHour(d,h):(null!=c.isPM&&((g=c.isPM(h))&&d<12&&(d+=12),!g&&12===d&&(d=0)),d)}(c._locale,c._a[3],c._meridiem),null!==(Pe=le(c).era)&&(c._a[0]=c._locale.erasConvertYear(Pe,c._a[0])),fn(c),Fo(c)}else Ut(c);else Ne(c)}function er(c){var d=c._i,h=c._f;return c._locale=c._locale||jn(c._l),null===d||void 0===h&&""===d?mr({nullInput:!0}):("string"==typeof d&&(c._i=d=c._locale.preparse(d)),Wn(d)?new _r(Fo(d)):(Zi(d)?c._d=d:dn(h)?function Mn(c){var d,h,g,_,b,N,Y=!1,ce=c._f.length;if(0===ce)return le(c).invalidFormat=!0,void(c._d=new Date(NaN));for(_=0;_this?this:c:mr()});function Sr(c,d){var h,g;if(1===d.length&&dn(d[0])&&(d=d[0]),!d.length)return xe();for(h=d[0],g=1;g=0?new Date(c+400,d,h)-Ho:new Date(c,d,h).valueOf()}function Ks(c,d,h){return c<100&&c>=0?Date.UTC(c+400,d,h)-Ho:Date.UTC(c,d,h)}function Ys(c,d){return d.erasAbbrRegex(c)}function jo(){var _,b,c=[],d=[],h=[],g=[],N=this.eras();for(_=0,b=N.length;_(b=Vn(c,g,_))&&(d=b),Ii.call(this,c,d,h,g,_))}function Ii(c,d,h,g,_){var b=gh(c,d,h,g,_),N=_e(b.year,0,b.dayOfYear);return this.year(N.getUTCFullYear()),this.month(N.getUTCMonth()),this.date(N.getUTCDate()),this}z("N",0,0,"eraAbbr"),z("NN",0,0,"eraAbbr"),z("NNN",0,0,"eraAbbr"),z("NNNN",0,0,"eraName"),z("NNNNN",0,0,"eraNarrow"),z("y",["y",1],"yo","eraYear"),z("y",["yy",2],0,"eraYear"),z("y",["yyy",3],0,"eraYear"),z("y",["yyyy",4],0,"eraYear"),$("N",Ys),$("NN",Ys),$("NNN",Ys),$("NNNN",function Bo(c,d){return d.erasNameRegex(c)}),$("NNNNN",function ci(c,d){return d.erasNarrowRegex(c)}),Se(["N","NN","NNN","NNNN","NNNNN"],function(c,d,h,g){var _=h._locale.erasParse(c,g,h._strict);_?le(h).era=_:le(h).invalidEra=c}),$("y",Dr),$("yy",Dr),$("yyy",Dr),$("yyyy",Dr),$("yo",function bl(c,d){return d._eraYearOrdinalRegex||Dr}),Se(["y","yy","yyy","yyyy"],0),Se(["yo"],function(c,d,h,g){var _;h._locale._eraYearOrdinalRegex&&(_=c.match(h._locale._eraYearOrdinalRegex)),d[0]=h._locale.eraYearOrdinalParse?h._locale.eraYearOrdinalParse(c,_):parseInt(c,10)}),z(0,["gg",2],0,function(){return this.weekYear()%100}),z(0,["GG",2],0,function(){return this.isoWeekYear()%100}),Dl("gggg","weekYear"),Dl("ggggg","weekYear"),Dl("GGGG","isoWeekYear"),Dl("GGGGG","isoWeekYear"),Rt("weekYear","gg"),Rt("isoWeekYear","GG"),Qt("weekYear",1),Qt("isoWeekYear",1),$("G",ut),$("g",ut),$("GG",Ge,Pn),$("gg",Ge,Pn),$("GGGG",Is,As),$("gggg",Is,As),$("GGGGG",Oo,Ao),$("ggggg",Oo,Ao),Xt(["gggg","ggggg","GGGG","GGGGG"],function(c,d,h,g){d[g.substr(0,2)]=he(c)}),Xt(["gg","GG"],function(c,d,h,g){d[g]=V.parseTwoDigitYear(c)}),z("Q",0,"Qo","quarter"),Rt("quarter","Q"),Qt("quarter",7),$("Q",sh),Se("Q",function(c,d){d[1]=3*(he(c)-1)}),z("D",["DD",2],"Do","date"),Rt("date","D"),Qt("date",9),$("D",Ge),$("DD",Ge,Pn),$("Do",function(c,d){return c?d._dayOfMonthOrdinalParse||d._ordinalParse:d._dayOfMonthOrdinalParseLenient}),Se(["D","DD"],2),Se("Do",function(c,d){d[2]=he(c.match(Ge)[0])});var Cl=To("Date",!0);z("DDD",["DDDD",3],"DDDo","dayOfYear"),Rt("dayOfYear","DDD"),Qt("dayOfYear",4),$("DDD",Io),$("DDDD",Ts),Se(["DDD","DDDD"],function(c,d,h){h._dayOfYear=he(c)}),z("m",["mm",2],0,"minute"),Rt("minute","m"),Qt("minute",14),$("m",Ge),$("mm",Ge,Pn),Se(["m","mm"],4);var Zh=To("Minutes",!1);z("s",["ss",2],0,"second"),Rt("second","s"),Qt("second",15),$("s",Ge),$("ss",Ge,Pn),Se(["s","ss"],5);var ui,Sl,wl=To("Seconds",!1);for(z("S",0,0,function(){return~~(this.millisecond()/100)}),z(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),z(0,["SSS",3],0,"millisecond"),z(0,["SSSS",4],0,function(){return 10*this.millisecond()}),z(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),z(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),z(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),z(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),z(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),Rt("millisecond","ms"),Qt("millisecond",16),$("S",Io,sh),$("SS",Io,Pn),$("SSS",Io,Ts),ui="SSSS";ui.length<=9;ui+="S")$(ui,Dr);function El(c,d){d[6]=he(1e3*("0."+c))}for(ui="S";ui.length<=9;ui+="S")Se(ui,El);Sl=To("Milliseconds",!1),z("z",0,0,"zoneAbbr"),z("zz",0,0,"zoneName");var x=_r.prototype;function Ml(c){return c}x.add=Zv,x.calendar=function gl(c,d){1===arguments.length&&(arguments[0]?Xv(arguments[0])?(c=arguments[0],d=void 0):ny(arguments[0])&&(d=arguments[0],c=void 0):(c=void 0,d=void 0));var h=c||xe(),g=eo(h,this).startOf("day"),_=V.calendarFormat(this,g)||"sameElse",b=d&&(ri(d[_])?d[_].call(this,h):d[_]);return this.format(b||this.localeData().calendar(_,this,xe(h)))},x.clone=function iy(){return new _r(this)},x.diff=function Ph(c,d,h){var g,_,b;if(!this.isValid())return NaN;if(!(g=eo(c,this)).isValid())return NaN;switch(_=6e4*(g.utcOffset()-this.utcOffset()),d=Fn(d)){case"year":b=Gs(this,g)/12;break;case"month":b=Gs(this,g);break;case"quarter":b=Gs(this,g)/3;break;case"second":b=(this-g)/1e3;break;case"minute":b=(this-g)/6e4;break;case"hour":b=(this-g)/36e5;break;case"day":b=(this-g-_)/864e5;break;case"week":b=(this-g-_)/6048e5;break;default:b=this-g}return h?b:Kn(b)},x.endOf=function Nn(c){var d,h;if(void 0===(c=Fn(c))||"millisecond"===c||!this.isValid())return this;switch(h=this._isUTC?Ks:Tu,c){case"year":d=h(this.year()+1,0,1)-1;break;case"quarter":d=h(this.year(),this.month()-this.month()%3+3,1)-1;break;case"month":d=h(this.year(),this.month()+1,1)-1;break;case"week":d=h(this.year(),this.month(),this.date()-this.weekday()+7)-1;break;case"isoWeek":d=h(this.year(),this.month(),this.date()-(this.isoWeekday()-1)+7)-1;break;case"day":case"date":d=h(this.year(),this.month(),this.date()+1)-1;break;case"hour":d=this._d.valueOf(),d+=vl-xt(d+(this._isUTC?0:this.utcOffset()*no),vl)-1;break;case"minute":d=this._d.valueOf(),d+=no-xt(d,no)-1;break;case"second":d=this._d.valueOf(),d+=1e3-xt(d,1e3)-1}return this._d.setTime(d),V.updateOffset(this,!0),this},x.format=function ml(c){c||(c=this.isUtc()?V.defaultFormatUtc:V.defaultFormat);var d=Ss(this,c);return this.localeData().postformat(d)},x.from=function Vh(c,d){return this.isValid()&&(Wn(c)&&c.isValid()||xe(c).isValid())?li({to:this,from:c}).locale(this.locale()).humanize(!d):this.localeData().invalidDate()},x.fromNow=function $n(c){return this.from(xe(),c)},x.to=function _l(c,d){return this.isValid()&&(Wn(c)&&c.isValid()||xe(c).isValid())?li({from:this,to:c}).locale(this.locale()).humanize(!d):this.localeData().invalidDate()},x.toNow=function Hh(c){return this.to(xe(),c)},x.get=function xv(c){return ri(this[c=Fn(c)])?this[c]():this},x.invalidAt=function sy(){return le(this).overflow},x.isAfter=function ry(c,d){var h=Wn(c)?c:xe(c);return!(!this.isValid()||!h.isValid())&&("millisecond"===(d=Fn(d)||"millisecond")?this.valueOf()>h.valueOf():h.valueOf()9999?Ss(h,d?"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYYYY-MM-DD[T]HH:mm:ss.SSSZ"):ri(Date.prototype.toISOString)?d?this.toDate().toISOString():new Date(this.valueOf()+60*this.utcOffset()*1e3).toISOString().replace("Z",Ss(h,"Z")):Ss(h,d?"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYY-MM-DD[T]HH:mm:ss.SSSZ")},x.inspect=function Lh(){if(!this.isValid())return"moment.invalid(/* "+this._i+" */)";var h,g,c="moment",d="";return this.isLocal()||(c=0===this.utcOffset()?"moment.utc":"moment.parseZone",d="Z"),h="["+c+'("]',g=0<=this.year()&&this.year()<=9999?"YYYY":"YYYYYY",this.format(h+g+"-MM-DD[T]HH:mm:ss.SSS"+d+'[")]')},typeof Symbol<"u"&&null!=Symbol.for&&(x[Symbol.for("nodejs.util.inspect.custom")]=function(){return"Moment<"+this.format()+">"}),x.toJSON=function yl(){return this.isValid()?this.toISOString():null},x.toString=function Eu(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},x.unix=function zs(){return Math.floor(this.valueOf()/1e3)},x.valueOf=function jh(){return this._d.valueOf()-6e4*(this._offset||0)},x.creationData=function Uh(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}},x.eraName=function Kh(){var c,d,h,g=this.localeData().eras();for(c=0,d=g.length;cthis.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()},x.isLocal=function Ah(){return!!this.isValid()&&!this._isUTC},x.isUtcOffset=function Yv(){return!!this.isValid()&&this._isUTC},x.isUtc=Cu,x.isUTC=Cu,x.zoneAbbr=function Qh(){return this._isUTC?"UTC":""},x.zoneName=function xu(){return this._isUTC?"Coordinated Universal Time":""},x.dates=Zt("dates accessor is deprecated. Use date instead.",Cl),x.months=Zt("months accessor is deprecated. Use month instead",Rs),x.years=Zt("years accessor is deprecated. Use year instead",P),x.zone=Zt("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",function Th(c,d){return null!=c?("string"!=typeof c&&(c=-c),this.utcOffset(c,d),this):-this.utcOffset()}),x.isDSTShifted=Zt("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",function Jn(){if(!qt(this._isDSTShifted))return this._isDSTShifted;var d,c={};return Za(c,this),(c=er(c))._a?(d=c._isUTC?ii(c._a):xe(c._a),this._isDSTShifted=this.isValid()&&function Nh(c,d,h){var N,g=Math.min(c.length,d.length),_=Math.abs(c.length-d.length),b=0;for(N=0;N0):this._isDSTShifted=!1,this._isDSTShifted});var Ee=Xa.prototype;function ro(c,d,h,g){var _=jn(),b=ii().set(g,d);return _[h](b,c)}function Lu(c,d,h){if(Jt(c)&&(d=c,c=void 0),c=c||"",null!=d)return ro(c,d,h,"month");var g,_=[];for(g=0;g<12;g++)_[g]=ro(c,g,h,"month");return _}function Nl(c,d,h,g){"boolean"==typeof c?(Jt(d)&&(h=d,d=void 0),d=d||""):(h=d=c,c=!1,Jt(d)&&(h=d,d=void 0),d=d||"");var N,_=jn(),b=c?_._week.dow:0,Y=[];if(null!=h)return ro(d,(h+b)%7,g,"day");for(N=0;N<7;N++)Y[N]=ro(d,(N+b)%7,g,"day");return Y}Ee.calendar=function su(c,d,h){var g=this._calendar[c]||this._calendar.sameElse;return ri(g)?g.call(d,h):g},Ee.longDateFormat=function Tv(c){var d=this._longDateFormat[c],h=this._longDateFormat[c.toUpperCase()];return d||!h?d:(this._longDateFormat[c]=h.match(el).map(function(g){return"MMMM"===g||"MM"===g||"DD"===g||"dddd"===g?g.slice(1):g}).join(""),this._longDateFormat[c])},Ee.invalidDate=function Av(){return this._invalidDate},Ee.ordinal=function kv(c){return this._ordinal.replace("%d",c)},Ee.preparse=Ml,Ee.postformat=Ml,Ee.relativeTime=function Rv(c,d,h,g){var _=this._relativeTime[h];return ri(_)?_(c,d,h,g):_.replace(/%d/i,c)},Ee.pastFuture=function lu(c,d){var h=this._relativeTime[c>0?"future":"past"];return ri(h)?h(d):h.replace(/%s/i,d)},Ee.set=function Qa(c){var d,h;for(h in c)we(c,h)&&(ri(d=c[h])?this[h]=d:this["_"+h]=d);this._config=c,this._dayOfMonthOrdinalParseLenient=new RegExp((this._dayOfMonthOrdinalParse.source||this._ordinalParse.source)+"|"+/\d{1,2}/.source)},Ee.eras=function Gh(c,d){var h,g,_,b=this._eras||jn("en")._eras;for(h=0,g=b.length;h=0)return b[g]},Ee.erasConvertYear=function Ou(c,d){var h=c.since<=c.until?1:-1;return void 0===d?V(c.since).year():V(c.since).year()+(d-c.offset)*h},Ee.erasAbbrRegex=function _t(c){return we(this,"_erasAbbrRegex")||jo.call(this),c?this._erasAbbrRegex:this._erasRegex},Ee.erasNameRegex=function mt(c){return we(this,"_erasNameRegex")||jo.call(this),c?this._erasNameRegex:this._erasRegex},Ee.erasNarrowRegex=function wt(c){return we(this,"_erasNarrowRegex")||jo.call(this),c?this._erasNarrowRegex:this._erasRegex},Ee.months=function hh(c,d){return c?dn(this._months)?this._months[c.month()]:this._months[(this._months.isFormat||pu).test(d)?"format":"standalone"][c.month()]:dn(this._months)?this._months:this._months.standalone},Ee.monthsShort=function il(c,d){return c?dn(this._monthsShort)?this._monthsShort[c.month()]:this._monthsShort[pu.test(d)?"format":"standalone"][c.month()]:dn(this._monthsShort)?this._monthsShort:this._monthsShort.standalone},Ee.monthsParse=function rl(c,d,h){var g,_,b;if(this._monthsParseExact)return $e.call(this,c,d,h);for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),g=0;g<12;g++){if(_=ii([2e3,g]),h&&!this._longMonthsParse[g]&&(this._longMonthsParse[g]=new RegExp("^"+this.months(_,"").replace(".","")+"$","i"),this._shortMonthsParse[g]=new RegExp("^"+this.monthsShort(_,"").replace(".","")+"$","i")),!h&&!this._monthsParse[g]&&(b="^"+this.months(_,"")+"|^"+this.monthsShort(_,""),this._monthsParse[g]=new RegExp(b.replace(".",""),"i")),h&&"MMMM"===d&&this._longMonthsParse[g].test(c))return g;if(h&&"MMM"===d&&this._shortMonthsParse[g].test(c))return g;if(!h&&this._monthsParse[g].test(c))return g}},Ee.monthsRegex=function te(c){return this._monthsParseExact?(we(this,"_monthsRegex")||xs.call(this),c?this._monthsStrictRegex:this._monthsRegex):(we(this,"_monthsRegex")||(this._monthsRegex=fh),this._monthsStrictRegex&&c?this._monthsStrictRegex:this._monthsRegex)},Ee.monthsShortRegex=function Te(c){return this._monthsParseExact?(we(this,"_monthsRegex")||xs.call(this),c?this._monthsShortStrictRegex:this._monthsShortRegex):(we(this,"_monthsShortRegex")||(this._monthsShortRegex=gt),this._monthsShortStrictRegex&&c?this._monthsShortStrictRegex:this._monthsShortRegex)},Ee.week=function wn(c){return xo(c,this._week.dow,this._week.doy).week},Ee.firstDayOfYear=function Vv(){return this._week.doy},Ee.firstDayOfWeek=function mh(){return this._week.dow},Ee.weekdays=function Uv(c,d){var h=dn(this._weekdays)?this._weekdays:this._weekdays[c&&!0!==c&&this._weekdays.isFormat.test(d)?"format":"standalone"];return!0===c?gu(h,this._week.dow):c?h[c.day()]:h},Ee.weekdaysMin=function Wv(c){return!0===c?gu(this._weekdaysMin,this._week.dow):c?this._weekdaysMin[c.day()]:this._weekdaysMin},Ee.weekdaysShort=function Gv(c){return!0===c?gu(this._weekdaysShort,this._week.dow):c?this._weekdaysShort[c.day()]:this._weekdaysShort},Ee.weekdaysParse=function Kv(c,d,h){var g,_,b;if(this._weekdaysParseExact)return G.call(this,c,d,h);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),g=0;g<7;g++){if(_=ii([2e3,1]).day(g),h&&!this._fullWeekdaysParse[g]&&(this._fullWeekdaysParse[g]=new RegExp("^"+this.weekdays(_,"").replace(".","\\.?")+"$","i"),this._shortWeekdaysParse[g]=new RegExp("^"+this.weekdaysShort(_,"").replace(".","\\.?")+"$","i"),this._minWeekdaysParse[g]=new RegExp("^"+this.weekdaysMin(_,"").replace(".","\\.?")+"$","i")),this._weekdaysParse[g]||(b="^"+this.weekdays(_,"")+"|^"+this.weekdaysShort(_,"")+"|^"+this.weekdaysMin(_,""),this._weekdaysParse[g]=new RegExp(b.replace(".",""),"i")),h&&"dddd"===d&&this._fullWeekdaysParse[g].test(c))return g;if(h&&"ddd"===d&&this._shortWeekdaysParse[g].test(c))return g;if(h&&"dd"===d&&this._minWeekdaysParse[g].test(c))return g;if(!h&&this._weekdaysParse[g].test(c))return g}},Ee.weekdaysRegex=function mu(c){return this._weekdaysParseExact?(we(this,"_weekdaysRegex")||Hs.call(this),c?this._weekdaysStrictRegex:this._weekdaysRegex):(we(this,"_weekdaysRegex")||(this._weekdaysRegex=$v),this._weekdaysStrictRegex&&c?this._weekdaysStrictRegex:this._weekdaysRegex)},Ee.weekdaysShortRegex=function Dh(c){return this._weekdaysParseExact?(we(this,"_weekdaysRegex")||Hs.call(this),c?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(we(this,"_weekdaysShortRegex")||(this._weekdaysShortRegex=Sn),this._weekdaysShortStrictRegex&&c?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)},Ee.weekdaysMinRegex=function Ch(c){return this._weekdaysParseExact?(we(this,"_weekdaysRegex")||Hs.call(this),c?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(we(this,"_weekdaysMinRegex")||(this._weekdaysMinRegex=Oe),this._weekdaysMinStrictRegex&&c?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)},Ee.isPM=function X(c){return"p"===(c+"").toLowerCase().charAt(0)},Ee.meridiem=function Hn(c,d,h){return c>11?h?"pm":"PM":h?"am":"AM"},Cr("en",{eras:[{since:"0001-01-01",until:1/0,offset:1,name:"Anno Domini",narrow:"AD",abbr:"AD"},{since:"0000-12-31",until:-1/0,offset:1,name:"Before Christ",narrow:"BC",abbr:"BC"}],dayOfMonthOrdinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(c){var d=c%10;return c+(1===he(c%100/10)?"th":1===d?"st":2===d?"nd":3===d?"rd":"th")}}),V.lang=Zt("moment.lang is deprecated. Use moment.locale instead.",Cr),V.langData=Zt("moment.langData is deprecated. Use moment.localeData instead.",jn);var Oi=Math.abs;function Vu(c,d,h,g){var _=li(d,h);return c._milliseconds+=g*_._milliseconds,c._days+=g*_._days,c._months+=g*_._months,c._bubble()}function $o(c){return c<0?Math.floor(c):Math.ceil(c)}function Zs(c){return 4800*c/146097}function Qs(c){return 146097*c/4800}function Tn(c){return function(){return this.as(c)}}var rp=Tn("ms"),op=Tn("s"),Uo=Tn("m"),Tl=Tn("h"),sp=Tn("d"),ap=Tn("w"),ly=Tn("M"),cy=Tn("Q"),Xs=Tn("y");function di(c){return function(){return this.isValid()?this._data[c]:NaN}}var ju=di("milliseconds"),$u=di("seconds"),oo=di("minutes"),lp=di("hours"),so=di("days"),Al=di("months"),ea=di("years");var fi=Math.round,Ar={ss:44,s:45,m:45,h:22,d:26,w:null,M:11};function cp(c,d,h,g,_){return _.relativeTime(d||1,!!h,c,g)}var Wo=Math.abs;function ki(c){return(c>0)-(c<0)||+c}function Ir(){if(!this.isValid())return this.localeData().invalidDate();var g,_,b,N,ce,Pe,vt,Ri,c=Wo(this._milliseconds)/1e3,d=Wo(this._days),h=Wo(this._months),Y=this.asSeconds();return Y?(g=Kn(c/60),_=Kn(g/60),c%=60,g%=60,b=Kn(h/12),h%=12,N=c?c.toFixed(3).replace(/\.?0+$/,""):"",ce=Y<0?"-":"",Pe=ki(this._months)!==ki(Y)?"-":"",vt=ki(this._days)!==ki(Y)?"-":"",Ri=ki(this._milliseconds)!==ki(Y)?"-":"",ce+"P"+(b?Pe+b+"Y":"")+(h?Pe+h+"M":"")+(d?vt+d+"D":"")+(_||g||c?"T":"")+(_?Ri+_+"H":"")+(g?Ri+g+"M":"")+(c?Ri+N+"S":"")):"P0D"}var De=Lo.prototype; + */)(),kF().bootstrapModule(S3).catch(e=>console.error(e))},439:function(gr,th,iu){(gr=iu.nmd(gr)).exports=function(){"use strict";var ye,No;function V(){return ye.apply(null,arguments)}function dn(c){return c instanceof Array||"[object Array]"===Object.prototype.toString.call(c)}function Ct(c){return null!=c&&"[object Object]"===Object.prototype.toString.call(c)}function we(c,d){return Object.prototype.hasOwnProperty.call(c,d)}function bs(c){if(Object.getOwnPropertyNames)return 0===Object.getOwnPropertyNames(c).length;var d;for(d in c)if(we(c,d))return!1;return!0}function qt(c){return void 0===c}function Zt(c){return"number"==typeof c||"[object Number]"===Object.prototype.toString.call(c)}function Ji(c){return c instanceof Date||"[object Date]"===Object.prototype.toString.call(c)}function Za(c,d){var g,h=[],_=c.length;for(g=0;g<_;++g)h.push(d(c[g],g));return h}function Dn(c,d){for(var h in d)we(d,h)&&(c[h]=d[h]);return we(d,"toString")&&(c.toString=d.toString),we(d,"valueOf")&&(c.valueOf=d.valueOf),c}function ii(c,d,h,g){return Jr(c,d,h,g,!0).utc()}function le(c){return null==c._pf&&(c._pf={empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidEra:null,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1,parsedDateParts:[],era:null,meridiem:null,rfc2822:!1,weekdayMismatch:!1}),c._pf}function Ci(c){if(null==c._isValid){var d=le(c),h=No.call(d.parsedDateParts,function(_){return null!=_}),g=!isNaN(c._d.getTime())&&d.overflow<0&&!d.empty&&!d.invalidEra&&!d.invalidMonth&&!d.invalidWeekday&&!d.weekdayMismatch&&!d.nullInput&&!d.invalidFormat&&!d.userInvalidated&&(!d.meridiem||d.meridiem&&h);if(c._strict&&(g=g&&0===d.charsLeftOver&&0===d.unusedTokens.length&&void 0===d.bigHour),null!=Object.isFrozen&&Object.isFrozen(c))return g;c._isValid=g}return c._isValid}function mr(c){var d=ii(NaN);return null!=c?Dn(le(d),c):le(d).userInvalidated=!0,d}No=Array.prototype.some?Array.prototype.some:function(c){var g,d=Object(this),h=d.length>>>0;for(g=0;g0)for(h=0;h=0?h?"+":"":"-")+Math.pow(10,Math.max(0,d-g.length)).toString().substr(1)+g}var el=/(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|N{1,5}|YYYYYY|YYYYY|YYYY|YY|y{2,4}|yo?|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,ws=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,Ue={},yr={};function Y(c,d,h,g){var _=g;"string"==typeof g&&(_=function(){return this[g]()}),c&&(yr[c]=_),d&&(yr[d[0]]=function(){return oi(_.apply(this,arguments),d[1],d[2])}),h&&(yr[h]=function(){return this.localeData().ordinal(_.apply(this,arguments),c)})}function qe(c){return c.match(/\[[\s\S]/)?c.replace(/^\[|\]$/g,""):c.replace(/\\/g,"")}function Ss(c,d){return c.isValid()?(d=ne(d,c.localeData()),Ue[d]=Ue[d]||function Oe(c){var h,g,d=c.match(el);for(h=0,g=d.length;h=0&&ws.test(c);)c=c.replace(ws,g),ws.lastIndex=0,h-=1;return c}var Ms={};function xt(c,d){var h=c.toLowerCase();Ms[h]=Ms[h+"s"]=Ms[d]=c}function Pn(c){return"string"==typeof c?Ms[c]||Ms[c.toLowerCase()]:void 0}function cu(c){var h,g,d={};for(g in c)we(c,g)&&(h=Pn(g))&&(d[h]=c[g]);return d}var rh={};function Qt(c,d){rh[c]=d}function Ns(c){return c%4==0&&c%100!=0||c%400==0}function zn(c){return c<0?Math.ceil(c)||0:Math.floor(c)}function he(c){var d=+c,h=0;return 0!==d&&isFinite(d)&&(h=zn(d)),h}function To(c,d){return function(h){return null!=h?(oh(this,c,h),V.updateOffset(this,d),this):Es(this,c)}}function Es(c,d){return c.isValid()?c._d["get"+(c._isUTC?"UTC":"")+d]():NaN}function oh(c,d,h){c.isValid()&&!isNaN(h)&&("FullYear"===d&&Ns(c.year())&&1===c.month()&&29===c.date()?(h=he(h),c._d["set"+(c._isUTC?"UTC":"")+d](h,c.month(),Os(h,c.month()))):c._d["set"+(c._isUTC?"UTC":"")+d](h))}var xo,sh=/\d/,Fn=/\d\d/,Ts=/\d{3}/,Is=/\d{4}/,Io=/[+-]?\d{6}/,Ge=/\d\d?/,nl=/\d\d\d\d?/,uu=/\d\d\d\d\d\d?/,Ao=/\d{1,3}/,As=/\d{1,4}/,ko=/[+-]?\d{1,6}/,Dr=/\d+/,ut=/[+-]?\d+/,ah=/Z|[+-]\d\d:?\d\d/gi,ks=/Z|[+-]\d\d(?::?\d\d)?/gi,Oo=/[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i;function $(c,d,h){xo[c]=ri(d)?d:function(g,_){return g&&h?h:d}}function ch(c,d){return we(xo,c)?xo[c](d._strict,d._locale):new RegExp(function wi(c){return Cn(c.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(d,h,g,_,b){return h||g||_||b}))}(c))}function Cn(c){return c.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}xo={};var dt={};function Se(c,d){var h,_,g=d;for("string"==typeof c&&(c=[c]),Zt(d)&&(g=function(b,E){E[d]=he(b)}),_=c.length,h=0;h<_;h++)dt[c[h]]=g}function Xt(c,d){Se(c,function(h,g,_,b){_._w=_._w||{},d(h,_._w,_,b)})}function Fv(c,d,h){null!=d&&we(dt,c)&&dt[c](d,h._a,h,c)}var ft;function Os(c,d){if(isNaN(c)||isNaN(d))return NaN;var h=function dh(c,d){return(c%d+d)%d}(d,12);return c+=(d-h)/12,1===h?Ns(c)?29:28:31-h%7%2}ft=Array.prototype.indexOf?Array.prototype.indexOf:function(c){var d;for(d=0;d68?1900:2e3)};var F=To("FullYear",!0);function oe(c,d,h,g,_,b,E){var K;return c<100&&c>=0?(K=new Date(c+400,d,h,g,_,b,E),isFinite(K.getFullYear())&&K.setFullYear(c)):K=new Date(c,d,h,g,_,b,E),K}function _e(c){var d,h;return c<100&&c>=0?((h=Array.prototype.slice.call(arguments))[0]=c+400,d=new Date(Date.UTC.apply(null,h)),isFinite(d.getUTCFullYear())&&d.setUTCFullYear(c)):d=new Date(Date.UTC.apply(null,arguments)),d}function Ls(c,d,h){var g=7+d-h;return-(7+_e(c,0,g).getUTCDay()-d)%7+g-1}function gh(c,d,h,g,_){var ce,Fe,K=1+7*(d-1)+(7+h-g)%7+Ls(c,g,_);return K<=0?Fe=Ps(ce=c-1)+K:K>Ps(c)?(ce=c+1,Fe=K-Ps(c)):(ce=c,Fe=K),{year:ce,dayOfYear:Fe}}function Ro(c,d,h){var b,E,g=Ls(c.year(),d,h),_=Math.floor((c.dayOfYear()-g-1)/7)+1;return _<1?b=_+Vn(E=c.year()-1,d,h):_>Vn(c.year(),d,h)?(b=_-Vn(c.year(),d,h),E=c.year()+1):(E=c.year(),b=_),{week:b,year:E}}function Vn(c,d,h){var g=Ls(c,d,h),_=Ls(c+1,d,h);return(Ps(c)-g+_)/7}Y("w",["ww",2],"wo","week"),Y("W",["WW",2],"Wo","isoWeek"),xt("week","w"),xt("isoWeek","W"),Qt("week",5),Qt("isoWeek",5),$("w",Ge),$("ww",Ge,Fn),$("W",Ge),$("WW",Ge,Fn),Xt(["w","ww","W","WW"],function(c,d,h,g){d[g.substr(0,1)]=he(c)});function gu(c,d){return c.slice(d,7).concat(c.slice(0,d))}Y("d",0,"do","day"),Y("dd",0,0,function(c){return this.localeData().weekdaysMin(this,c)}),Y("ddd",0,0,function(c){return this.localeData().weekdaysShort(this,c)}),Y("dddd",0,0,function(c){return this.localeData().weekdays(this,c)}),Y("e",0,0,"weekday"),Y("E",0,0,"isoWeekday"),xt("day","d"),xt("weekday","e"),xt("isoWeekday","E"),Qt("day",11),Qt("weekday",11),Qt("isoWeekday",11),$("d",Ge),$("e",Ge),$("E",Ge),$("dd",function(c,d){return d.weekdaysMinRegex(c)}),$("ddd",function(c,d){return d.weekdaysShortRegex(c)}),$("dddd",function(c,d){return d.weekdaysRegex(c)}),Xt(["dd","ddd","dddd"],function(c,d,h,g){var _=h._locale.weekdaysParse(c,g,h._strict);null!=_?d.d=_:le(h).invalidWeekday=c}),Xt(["d","e","E"],function(c,d,h,g){d[g]=he(c)});var _h="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),vh="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),yh="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),$v=Oo,Sn=Oo,ke=Oo;function G(c,d,h){var g,_,b,E=c.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],g=0;g<7;++g)b=ii([2e3,1]).day(g),this._minWeekdaysParse[g]=this.weekdaysMin(b,"").toLocaleLowerCase(),this._shortWeekdaysParse[g]=this.weekdaysShort(b,"").toLocaleLowerCase(),this._weekdaysParse[g]=this.weekdays(b,"").toLocaleLowerCase();return h?"dddd"===d?-1!==(_=ft.call(this._weekdaysParse,E))?_:null:"ddd"===d?-1!==(_=ft.call(this._shortWeekdaysParse,E))?_:null:-1!==(_=ft.call(this._minWeekdaysParse,E))?_:null:"dddd"===d?-1!==(_=ft.call(this._weekdaysParse,E))||-1!==(_=ft.call(this._shortWeekdaysParse,E))||-1!==(_=ft.call(this._minWeekdaysParse,E))?_:null:"ddd"===d?-1!==(_=ft.call(this._shortWeekdaysParse,E))||-1!==(_=ft.call(this._weekdaysParse,E))||-1!==(_=ft.call(this._minWeekdaysParse,E))?_:null:-1!==(_=ft.call(this._minWeekdaysParse,E))||-1!==(_=ft.call(this._weekdaysParse,E))||-1!==(_=ft.call(this._shortWeekdaysParse,E))?_:null}function Bs(){function c(vt,xi){return xi.length-vt.length}var b,E,K,ce,Fe,d=[],h=[],g=[],_=[];for(b=0;b<7;b++)E=ii([2e3,1]).day(b),K=Cn(this.weekdaysMin(E,"")),ce=Cn(this.weekdaysShort(E,"")),Fe=Cn(this.weekdays(E,"")),d.push(K),h.push(ce),g.push(Fe),_.push(K),_.push(ce),_.push(Fe);d.sort(c),h.sort(c),g.sort(c),_.sort(c),this._weekdaysRegex=new RegExp("^("+_.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+g.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+h.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+d.join("|")+")","i")}function Zr(){return this.hours()%12||12}function sl(c,d){Y(c,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),d)})}function _u(c,d){return d._meridiemParse}Y("H",["HH",2],0,"hour"),Y("h",["hh",2],0,Zr),Y("k",["kk",2],0,function ol(){return this.hours()||24}),Y("hmm",0,0,function(){return""+Zr.apply(this)+oi(this.minutes(),2)}),Y("hmmss",0,0,function(){return""+Zr.apply(this)+oi(this.minutes(),2)+oi(this.seconds(),2)}),Y("Hmm",0,0,function(){return""+this.hours()+oi(this.minutes(),2)}),Y("Hmmss",0,0,function(){return""+this.hours()+oi(this.minutes(),2)+oi(this.seconds(),2)}),sl("a",!0),sl("A",!1),xt("hour","h"),Qt("hour",13),$("a",_u),$("A",_u),$("H",Ge),$("h",Ge),$("k",Ge),$("HH",Ge,Fn),$("hh",Ge,Fn),$("kk",Ge,Fn),$("hmm",nl),$("hmmss",uu),$("Hmm",nl),$("Hmmss",uu),Se(["H","HH"],3),Se(["k","kk"],function(c,d,h){var g=he(c);d[3]=24===g?0:g}),Se(["a","A"],function(c,d,h){h._isPm=h._locale.isPM(c),h._meridiem=c}),Se(["h","hh"],function(c,d,h){d[3]=he(c),le(h).bigHour=!0}),Se("hmm",function(c,d,h){var g=c.length-2;d[3]=he(c.substr(0,g)),d[4]=he(c.substr(g)),le(h).bigHour=!0}),Se("hmmss",function(c,d,h){var g=c.length-4,_=c.length-2;d[3]=he(c.substr(0,g)),d[4]=he(c.substr(g,2)),d[5]=he(c.substr(_)),le(h).bigHour=!0}),Se("Hmm",function(c,d,h){var g=c.length-2;d[3]=he(c.substr(0,g)),d[4]=he(c.substr(g))}),Se("Hmmss",function(c,d,h){var g=c.length-4,_=c.length-2;d[3]=he(c.substr(0,g)),d[4]=he(c.substr(g,2)),d[5]=he(c.substr(_))});var wh=To("Hours",!0);var tn,ll={calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},longDateFormat:{LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},invalidDate:"Invalid date",ordinal:"%d",dayOfMonthOrdinalParse:/\d{1,2}/,relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",w:"a week",ww:"%d weeks",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},months:fu,monthsShort:hu,week:{dow:0,doy:6},weekdays:_h,weekdaysMin:yh,weekdaysShort:vh,meridiemParse:/[ap]\.?m?\.?/i},Xe={},Hn={};function Yv(c,d){var h,g=Math.min(c.length,d.length);for(h=0;h0;){if(_=cl(b.slice(0,h).join("-")))return _;if(g&&g.length>=h&&Yv(b,g)>=h-1)break;h--}d++}return tn}(c)}function Po(c){var d,h=c._a;return h&&-2===le(c).overflow&&(d=h[1]<0||h[1]>11?1:h[2]<1||h[2]>Os(h[0],h[1])?2:h[3]<0||h[3]>24||24===h[3]&&(0!==h[4]||0!==h[5]||0!==h[6])?3:h[4]<0||h[4]>59?4:h[5]<0||h[5]>59?5:h[6]<0||h[6]>999?6:-1,le(c)._overflowDayOfYear&&(d<0||d>2)&&(d=2),le(c)._overflowWeeks&&-1===d&&(d=7),le(c)._overflowWeekday&&-1===d&&(d=8),le(c).overflow=d),c}var vu=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Ni=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d|))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Fo=/Z|[+-]\d\d(?::?\d\d)?/,Hs=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/],["YYYYMM",/\d{6}/,!1],["YYYY",/\d{4}/,!1]],et=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],Mh=/^\/?Date\((-?\d+)/i,yu=/^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/,bu={UT:0,GMT:0,EDT:-240,EST:-300,CDT:-300,CST:-360,MDT:-360,MST:-420,PDT:-420,PST:-480};function Ee(c){var d,h,b,E,K,ce,g=c._i,_=vu.exec(g)||Ni.exec(g),Fe=Hs.length,vt=et.length;if(_){for(le(c).iso=!0,d=0,h=Fe;d7)&&(ce=!0)):(b=c._locale._week.dow,E=c._locale._week.doy,Fe=Ro(Re(),b,E),h=Yn(d.gg,c._a[0],Fe.year),g=Yn(d.w,Fe.week),null!=d.d?((_=d.d)<0||_>6)&&(ce=!0):null!=d.e?(_=d.e+b,(d.e<0||d.e>6)&&(ce=!0)):_=b),g<1||g>Vn(h,b,E)?le(c)._overflowWeeks=!0:null!=ce?le(c)._overflowWeekday=!0:(K=gh(h,g,_,b,E),c._a[0]=K.year,c._dayOfYear=K.dayOfYear)}(c),null!=c._dayOfYear&&(E=Yn(c._a[0],_[0]),(c._dayOfYear>Ps(E)||0===c._dayOfYear)&&(le(c)._overflowDayOfYear=!0),h=_e(E,0,c._dayOfYear),c._a[1]=h.getUTCMonth(),c._a[2]=h.getUTCDate()),d=0;d<3&&null==c._a[d];++d)c._a[d]=g[d]=_[d];for(;d<7;d++)c._a[d]=g[d]=c._a[d]??(2===d?1:0);24===c._a[3]&&0===c._a[4]&&0===c._a[5]&&0===c._a[6]&&(c._nextDay=!0,c._a[3]=0),c._d=(c._useUTC?_e:oe).apply(null,g),b=c._useUTC?c._d.getUTCDay():c._d.getDay(),null!=c._tzm&&c._d.setUTCMinutes(c._d.getUTCMinutes()-c._tzm),c._nextDay&&(c._a[3]=24),c._w&&typeof c._w.d<"u"&&c._w.d!==b&&(le(c).weekdayMismatch=!0)}}function se(c){if(c._f!==V.ISO_8601)if(c._f!==V.RFC_2822){c._a=[],le(c).empty=!0;var h,g,_,b,E,Fe,vt,d=""+c._i,K=d.length,ce=0;for(vt=(_=ne(c._f,c._locale).match(el)||[]).length,h=0;h0&&le(c).unusedInput.push(E),d=d.slice(d.indexOf(g)+g.length),ce+=g.length),yr[b]?(g?le(c).empty=!1:le(c).unusedTokens.push(b),Fv(b,g,c)):c._strict&&!g&&le(c).unusedTokens.push(b);le(c).charsLeftOver=K-ce,d.length>0&&le(c).unusedInput.push(d),c._a[3]<=12&&!0===le(c).bigHour&&c._a[3]>0&&(le(c).bigHour=void 0),le(c).parsedDateParts=c._a.slice(0),le(c).meridiem=c._meridiem,c._a[3]=function Ze(c,d,h){var g;return null==h?d:null!=c.meridiemHour?c.meridiemHour(d,h):(null!=c.isPM&&((g=c.isPM(h))&&d<12&&(d+=12),!g&&12===d&&(d=0)),d)}(c._locale,c._a[3],c._meridiem),null!==(Fe=le(c).era)&&(c._a[0]=c._locale.erasConvertYear(Fe,c._a[0])),fn(c),Po(c)}else Ut(c);else Ee(c)}function er(c){var d=c._i,h=c._f;return c._locale=c._locale||jn(c._l),null===d||void 0===h&&""===d?mr({nullInput:!0}):("string"==typeof d&&(c._i=d=c._locale.preparse(d)),Wn(d)?new _r(Po(d)):(Ji(d)?c._d=d:dn(h)?function Nn(c){var d,h,g,_,b,E,K=!1,ce=c._f.length;if(0===ce)return le(c).invalidFormat=!0,void(c._d=new Date(NaN));for(_=0;_this?this:c:mr()});function Sr(c,d){var h,g;if(1===d.length&&dn(d[0])&&(d=d[0]),!d.length)return Re();for(h=d[0],g=1;g=0?new Date(c+400,d,h)-Bo:new Date(c,d,h).valueOf()}function zs(c,d,h){return c<100&&c>=0?Date.UTC(c+400,d,h)-Bo:Date.UTC(c,d,h)}function Ks(c,d){return d.erasAbbrRegex(c)}function jo(){var _,b,c=[],d=[],h=[],g=[],E=this.eras();for(_=0,b=E.length;_(b=Vn(c,g,_))&&(d=b),Ai.call(this,c,d,h,g,_))}function Ai(c,d,h,g,_){var b=gh(c,d,h,g,_),E=_e(b.year,0,b.dayOfYear);return this.year(E.getUTCFullYear()),this.month(E.getUTCMonth()),this.date(E.getUTCDate()),this}Y("N",0,0,"eraAbbr"),Y("NN",0,0,"eraAbbr"),Y("NNN",0,0,"eraAbbr"),Y("NNNN",0,0,"eraName"),Y("NNNNN",0,0,"eraNarrow"),Y("y",["y",1],"yo","eraYear"),Y("y",["yy",2],0,"eraYear"),Y("y",["yyy",3],0,"eraYear"),Y("y",["yyyy",4],0,"eraYear"),$("N",Ks),$("NN",Ks),$("NNN",Ks),$("NNNN",function Ho(c,d){return d.erasNameRegex(c)}),$("NNNNN",function ci(c,d){return d.erasNarrowRegex(c)}),Se(["N","NN","NNN","NNNN","NNNNN"],function(c,d,h,g){var _=h._locale.erasParse(c,g,h._strict);_?le(h).era=_:le(h).invalidEra=c}),$("y",Dr),$("yy",Dr),$("yyy",Dr),$("yyyy",Dr),$("yo",function bl(c,d){return d._eraYearOrdinalRegex||Dr}),Se(["y","yy","yyy","yyyy"],0),Se(["yo"],function(c,d,h,g){var _;h._locale._eraYearOrdinalRegex&&(_=c.match(h._locale._eraYearOrdinalRegex)),d[0]=h._locale.eraYearOrdinalParse?h._locale.eraYearOrdinalParse(c,_):parseInt(c,10)}),Y(0,["gg",2],0,function(){return this.weekYear()%100}),Y(0,["GG",2],0,function(){return this.isoWeekYear()%100}),Dl("gggg","weekYear"),Dl("ggggg","weekYear"),Dl("GGGG","isoWeekYear"),Dl("GGGGG","isoWeekYear"),xt("weekYear","gg"),xt("isoWeekYear","GG"),Qt("weekYear",1),Qt("isoWeekYear",1),$("G",ut),$("g",ut),$("GG",Ge,Fn),$("gg",Ge,Fn),$("GGGG",As,Is),$("gggg",As,Is),$("GGGGG",ko,Io),$("ggggg",ko,Io),Xt(["gggg","ggggg","GGGG","GGGGG"],function(c,d,h,g){d[g.substr(0,2)]=he(c)}),Xt(["gg","GG"],function(c,d,h,g){d[g]=V.parseTwoDigitYear(c)}),Y("Q",0,"Qo","quarter"),xt("quarter","Q"),Qt("quarter",7),$("Q",sh),Se("Q",function(c,d){d[1]=3*(he(c)-1)}),Y("D",["DD",2],"Do","date"),xt("date","D"),Qt("date",9),$("D",Ge),$("DD",Ge,Fn),$("Do",function(c,d){return c?d._dayOfMonthOrdinalParse||d._ordinalParse:d._dayOfMonthOrdinalParseLenient}),Se(["D","DD"],2),Se("Do",function(c,d){d[2]=he(c.match(Ge)[0])});var Cl=To("Date",!0);Y("DDD",["DDDD",3],"DDDo","dayOfYear"),xt("dayOfYear","DDD"),Qt("dayOfYear",4),$("DDD",Ao),$("DDDD",Ts),Se(["DDD","DDDD"],function(c,d,h){h._dayOfYear=he(c)}),Y("m",["mm",2],0,"minute"),xt("minute","m"),Qt("minute",14),$("m",Ge),$("mm",Ge,Fn),Se(["m","mm"],4);var Jh=To("Minutes",!1);Y("s",["ss",2],0,"second"),xt("second","s"),Qt("second",15),$("s",Ge),$("ss",Ge,Fn),Se(["s","ss"],5);var ui,Sl,wl=To("Seconds",!1);for(Y("S",0,0,function(){return~~(this.millisecond()/100)}),Y(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),Y(0,["SSS",3],0,"millisecond"),Y(0,["SSSS",4],0,function(){return 10*this.millisecond()}),Y(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),Y(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),Y(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),Y(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),Y(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),xt("millisecond","ms"),Qt("millisecond",16),$("S",Ao,sh),$("SS",Ao,Fn),$("SSS",Ao,Ts),ui="SSSS";ui.length<=9;ui+="S")$(ui,Dr);function Ml(c,d){d[6]=he(1e3*("0."+c))}for(ui="S";ui.length<=9;ui+="S")Se(ui,Ml);Sl=To("Milliseconds",!1),Y("z",0,0,"zoneAbbr"),Y("zz",0,0,"zoneName");var R=_r.prototype;function Nl(c){return c}R.add=Jv,R.calendar=function gl(c,d){1===arguments.length&&(arguments[0]?Xv(arguments[0])?(c=arguments[0],d=void 0):ny(arguments[0])&&(d=arguments[0],c=void 0):(c=void 0,d=void 0));var h=c||Re(),g=eo(h,this).startOf("day"),_=V.calendarFormat(this,g)||"sameElse",b=d&&(ri(d[_])?d[_].call(this,h):d[_]);return this.format(b||this.localeData().calendar(_,this,Re(h)))},R.clone=function iy(){return new _r(this)},R.diff=function Fh(c,d,h){var g,_,b;if(!this.isValid())return NaN;if(!(g=eo(c,this)).isValid())return NaN;switch(_=6e4*(g.utcOffset()-this.utcOffset()),d=Pn(d)){case"year":b=Gs(this,g)/12;break;case"month":b=Gs(this,g);break;case"quarter":b=Gs(this,g)/3;break;case"second":b=(this-g)/1e3;break;case"minute":b=(this-g)/6e4;break;case"hour":b=(this-g)/36e5;break;case"day":b=(this-g-_)/864e5;break;case"week":b=(this-g-_)/6048e5;break;default:b=this-g}return h?b:zn(b)},R.endOf=function En(c){var d,h;if(void 0===(c=Pn(c))||"millisecond"===c||!this.isValid())return this;switch(h=this._isUTC?zs:Tu,c){case"year":d=h(this.year()+1,0,1)-1;break;case"quarter":d=h(this.year(),this.month()-this.month()%3+3,1)-1;break;case"month":d=h(this.year(),this.month()+1,1)-1;break;case"week":d=h(this.year(),this.month(),this.date()-this.weekday()+7)-1;break;case"isoWeek":d=h(this.year(),this.month(),this.date()-(this.isoWeekday()-1)+7)-1;break;case"day":case"date":d=h(this.year(),this.month(),this.date()+1)-1;break;case"hour":d=this._d.valueOf(),d+=vl-Rt(d+(this._isUTC?0:this.utcOffset()*no),vl)-1;break;case"minute":d=this._d.valueOf(),d+=no-Rt(d,no)-1;break;case"second":d=this._d.valueOf(),d+=1e3-Rt(d,1e3)-1}return this._d.setTime(d),V.updateOffset(this,!0),this},R.format=function ml(c){c||(c=this.isUtc()?V.defaultFormatUtc:V.defaultFormat);var d=Ss(this,c);return this.localeData().postformat(d)},R.from=function Vh(c,d){return this.isValid()&&(Wn(c)&&c.isValid()||Re(c).isValid())?li({to:this,from:c}).locale(this.locale()).humanize(!d):this.localeData().invalidDate()},R.fromNow=function $n(c){return this.from(Re(),c)},R.to=function _l(c,d){return this.isValid()&&(Wn(c)&&c.isValid()||Re(c).isValid())?li({from:this,to:c}).locale(this.locale()).humanize(!d):this.localeData().invalidDate()},R.toNow=function Bh(c){return this.to(Re(),c)},R.get=function Rv(c){return ri(this[c=Pn(c)])?this[c]():this},R.invalidAt=function sy(){return le(this).overflow},R.isAfter=function ry(c,d){var h=Wn(c)?c:Re(c);return!(!this.isValid()||!h.isValid())&&("millisecond"===(d=Pn(d)||"millisecond")?this.valueOf()>h.valueOf():h.valueOf()9999?Ss(h,d?"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYYYY-MM-DD[T]HH:mm:ss.SSSZ"):ri(Date.prototype.toISOString)?d?this.toDate().toISOString():new Date(this.valueOf()+60*this.utcOffset()*1e3).toISOString().replace("Z",Ss(h,"Z")):Ss(h,d?"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYY-MM-DD[T]HH:mm:ss.SSSZ")},R.inspect=function Lh(){if(!this.isValid())return"moment.invalid(/* "+this._i+" */)";var h,g,c="moment",d="";return this.isLocal()||(c=0===this.utcOffset()?"moment.utc":"moment.parseZone",d="Z"),h="["+c+'("]',g=0<=this.year()&&this.year()<=9999?"YYYY":"YYYYYY",this.format(h+g+"-MM-DD[T]HH:mm:ss.SSS"+d+'[")]')},typeof Symbol<"u"&&null!=Symbol.for&&(R[Symbol.for("nodejs.util.inspect.custom")]=function(){return"Moment<"+this.format()+">"}),R.toJSON=function yl(){return this.isValid()?this.toISOString():null},R.toString=function Mu(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},R.unix=function Ys(){return Math.floor(this.valueOf()/1e3)},R.valueOf=function jh(){return this._d.valueOf()-6e4*(this._offset||0)},R.creationData=function Uh(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}},R.eraName=function zh(){var c,d,h,g=this.localeData().eras();for(c=0,d=g.length;cthis.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()},R.isLocal=function Ih(){return!!this.isValid()&&!this._isUTC},R.isUtcOffset=function Kv(){return!!this.isValid()&&this._isUTC},R.isUtc=Cu,R.isUTC=Cu,R.zoneAbbr=function Qh(){return this._isUTC?"UTC":""},R.zoneName=function Ru(){return this._isUTC?"Coordinated Universal Time":""},R.dates=Jt("dates accessor is deprecated. Use date instead.",Cl),R.months=Jt("months accessor is deprecated. Use month instead",xs),R.years=Jt("years accessor is deprecated. Use year instead",F),R.zone=Jt("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",function Th(c,d){return null!=c?("string"!=typeof c&&(c=-c),this.utcOffset(c,d),this):-this.utcOffset()}),R.isDSTShifted=Jt("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",function Zn(){if(!qt(this._isDSTShifted))return this._isDSTShifted;var d,c={};return Ja(c,this),(c=er(c))._a?(d=c._isUTC?ii(c._a):Re(c._a),this._isDSTShifted=this.isValid()&&function Eh(c,d,h){var E,g=Math.min(c.length,d.length),_=Math.abs(c.length-d.length),b=0;for(E=0;E0):this._isDSTShifted=!1,this._isDSTShifted});var Me=Xa.prototype;function ro(c,d,h,g){var _=jn(),b=ii().set(g,d);return _[h](b,c)}function Lu(c,d,h){if(Zt(c)&&(d=c,c=void 0),c=c||"",null!=d)return ro(c,d,h,"month");var g,_=[];for(g=0;g<12;g++)_[g]=ro(c,g,h,"month");return _}function El(c,d,h,g){"boolean"==typeof c?(Zt(d)&&(h=d,d=void 0),d=d||""):(h=d=c,c=!1,Zt(d)&&(h=d,d=void 0),d=d||"");var E,_=jn(),b=c?_._week.dow:0,K=[];if(null!=h)return ro(d,(h+b)%7,g,"day");for(E=0;E<7;E++)K[E]=ro(d,(E+b)%7,g,"day");return K}Me.calendar=function su(c,d,h){var g=this._calendar[c]||this._calendar.sameElse;return ri(g)?g.call(d,h):g},Me.longDateFormat=function Tv(c){var d=this._longDateFormat[c],h=this._longDateFormat[c.toUpperCase()];return d||!h?d:(this._longDateFormat[c]=h.match(el).map(function(g){return"MMMM"===g||"MM"===g||"DD"===g||"dddd"===g?g.slice(1):g}).join(""),this._longDateFormat[c])},Me.invalidDate=function Iv(){return this._invalidDate},Me.ordinal=function Ov(c){return this._ordinal.replace("%d",c)},Me.preparse=Nl,Me.postformat=Nl,Me.relativeTime=function xv(c,d,h,g){var _=this._relativeTime[h];return ri(_)?_(c,d,h,g):_.replace(/%d/i,c)},Me.pastFuture=function lu(c,d){var h=this._relativeTime[c>0?"future":"past"];return ri(h)?h(d):h.replace(/%s/i,d)},Me.set=function Qa(c){var d,h;for(h in c)we(c,h)&&(ri(d=c[h])?this[h]=d:this["_"+h]=d);this._config=c,this._dayOfMonthOrdinalParseLenient=new RegExp((this._dayOfMonthOrdinalParse.source||this._ordinalParse.source)+"|"+/\d{1,2}/.source)},Me.eras=function Gh(c,d){var h,g,_,b=this._eras||jn("en")._eras;for(h=0,g=b.length;h=0)return b[g]},Me.erasConvertYear=function ku(c,d){var h=c.since<=c.until?1:-1;return void 0===d?V(c.since).year():V(c.since).year()+(d-c.offset)*h},Me.erasAbbrRegex=function _t(c){return we(this,"_erasAbbrRegex")||jo.call(this),c?this._erasAbbrRegex:this._erasRegex},Me.erasNameRegex=function mt(c){return we(this,"_erasNameRegex")||jo.call(this),c?this._erasNameRegex:this._erasRegex},Me.erasNarrowRegex=function wt(c){return we(this,"_erasNarrowRegex")||jo.call(this),c?this._erasNarrowRegex:this._erasRegex},Me.months=function hh(c,d){return c?dn(this._months)?this._months[c.month()]:this._months[(this._months.isFormat||pu).test(d)?"format":"standalone"][c.month()]:dn(this._months)?this._months:this._months.standalone},Me.monthsShort=function il(c,d){return c?dn(this._monthsShort)?this._monthsShort[c.month()]:this._monthsShort[pu.test(d)?"format":"standalone"][c.month()]:dn(this._monthsShort)?this._monthsShort:this._monthsShort.standalone},Me.monthsParse=function rl(c,d,h){var g,_,b;if(this._monthsParseExact)return $e.call(this,c,d,h);for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),g=0;g<12;g++){if(_=ii([2e3,g]),h&&!this._longMonthsParse[g]&&(this._longMonthsParse[g]=new RegExp("^"+this.months(_,"").replace(".","")+"$","i"),this._shortMonthsParse[g]=new RegExp("^"+this.monthsShort(_,"").replace(".","")+"$","i")),!h&&!this._monthsParse[g]&&(b="^"+this.months(_,"")+"|^"+this.monthsShort(_,""),this._monthsParse[g]=new RegExp(b.replace(".",""),"i")),h&&"MMMM"===d&&this._longMonthsParse[g].test(c))return g;if(h&&"MMM"===d&&this._shortMonthsParse[g].test(c))return g;if(!h&&this._monthsParse[g].test(c))return g}},Me.monthsRegex=function te(c){return this._monthsParseExact?(we(this,"_monthsRegex")||Rs.call(this),c?this._monthsStrictRegex:this._monthsRegex):(we(this,"_monthsRegex")||(this._monthsRegex=fh),this._monthsStrictRegex&&c?this._monthsStrictRegex:this._monthsRegex)},Me.monthsShortRegex=function Te(c){return this._monthsParseExact?(we(this,"_monthsRegex")||Rs.call(this),c?this._monthsShortStrictRegex:this._monthsShortRegex):(we(this,"_monthsShortRegex")||(this._monthsShortRegex=gt),this._monthsShortStrictRegex&&c?this._monthsShortStrictRegex:this._monthsShortRegex)},Me.week=function wn(c){return Ro(c,this._week.dow,this._week.doy).week},Me.firstDayOfYear=function Vv(){return this._week.doy},Me.firstDayOfWeek=function mh(){return this._week.dow},Me.weekdays=function Uv(c,d){var h=dn(this._weekdays)?this._weekdays:this._weekdays[c&&!0!==c&&this._weekdays.isFormat.test(d)?"format":"standalone"];return!0===c?gu(h,this._week.dow):c?h[c.day()]:h},Me.weekdaysMin=function Wv(c){return!0===c?gu(this._weekdaysMin,this._week.dow):c?this._weekdaysMin[c.day()]:this._weekdaysMin},Me.weekdaysShort=function Gv(c){return!0===c?gu(this._weekdaysShort,this._week.dow):c?this._weekdaysShort[c.day()]:this._weekdaysShort},Me.weekdaysParse=function zv(c,d,h){var g,_,b;if(this._weekdaysParseExact)return G.call(this,c,d,h);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),g=0;g<7;g++){if(_=ii([2e3,1]).day(g),h&&!this._fullWeekdaysParse[g]&&(this._fullWeekdaysParse[g]=new RegExp("^"+this.weekdays(_,"").replace(".","\\.?")+"$","i"),this._shortWeekdaysParse[g]=new RegExp("^"+this.weekdaysShort(_,"").replace(".","\\.?")+"$","i"),this._minWeekdaysParse[g]=new RegExp("^"+this.weekdaysMin(_,"").replace(".","\\.?")+"$","i")),this._weekdaysParse[g]||(b="^"+this.weekdays(_,"")+"|^"+this.weekdaysShort(_,"")+"|^"+this.weekdaysMin(_,""),this._weekdaysParse[g]=new RegExp(b.replace(".",""),"i")),h&&"dddd"===d&&this._fullWeekdaysParse[g].test(c))return g;if(h&&"ddd"===d&&this._shortWeekdaysParse[g].test(c))return g;if(h&&"dd"===d&&this._minWeekdaysParse[g].test(c))return g;if(!h&&this._weekdaysParse[g].test(c))return g}},Me.weekdaysRegex=function mu(c){return this._weekdaysParseExact?(we(this,"_weekdaysRegex")||Bs.call(this),c?this._weekdaysStrictRegex:this._weekdaysRegex):(we(this,"_weekdaysRegex")||(this._weekdaysRegex=$v),this._weekdaysStrictRegex&&c?this._weekdaysStrictRegex:this._weekdaysRegex)},Me.weekdaysShortRegex=function Dh(c){return this._weekdaysParseExact?(we(this,"_weekdaysRegex")||Bs.call(this),c?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(we(this,"_weekdaysShortRegex")||(this._weekdaysShortRegex=Sn),this._weekdaysShortStrictRegex&&c?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)},Me.weekdaysMinRegex=function Ch(c){return this._weekdaysParseExact?(we(this,"_weekdaysRegex")||Bs.call(this),c?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(we(this,"_weekdaysMinRegex")||(this._weekdaysMinRegex=ke),this._weekdaysMinStrictRegex&&c?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)},Me.isPM=function X(c){return"p"===(c+"").toLowerCase().charAt(0)},Me.meridiem=function Bn(c,d,h){return c>11?h?"pm":"PM":h?"am":"AM"},Cr("en",{eras:[{since:"0001-01-01",until:1/0,offset:1,name:"Anno Domini",narrow:"AD",abbr:"AD"},{since:"0000-12-31",until:-1/0,offset:1,name:"Before Christ",narrow:"BC",abbr:"BC"}],dayOfMonthOrdinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(c){var d=c%10;return c+(1===he(c%100/10)?"th":1===d?"st":2===d?"nd":3===d?"rd":"th")}}),V.lang=Jt("moment.lang is deprecated. Use moment.locale instead.",Cr),V.langData=Jt("moment.langData is deprecated. Use moment.localeData instead.",jn);var ki=Math.abs;function Vu(c,d,h,g){var _=li(d,h);return c._milliseconds+=g*_._milliseconds,c._days+=g*_._days,c._months+=g*_._months,c._bubble()}function $o(c){return c<0?Math.floor(c):Math.ceil(c)}function Js(c){return 4800*c/146097}function Qs(c){return 146097*c/4800}function Tn(c){return function(){return this.as(c)}}var rp=Tn("ms"),op=Tn("s"),Uo=Tn("m"),Tl=Tn("h"),sp=Tn("d"),ap=Tn("w"),ly=Tn("M"),cy=Tn("Q"),Xs=Tn("y");function di(c){return function(){return this.isValid()?this._data[c]:NaN}}var ju=di("milliseconds"),$u=di("seconds"),oo=di("minutes"),lp=di("hours"),so=di("days"),Il=di("months"),ea=di("years");var fi=Math.round,Ir={ss:44,s:45,m:45,h:22,d:26,w:null,M:11};function cp(c,d,h,g,_){return _.relativeTime(d||1,!!h,c,g)}var Wo=Math.abs;function Oi(c){return(c>0)-(c<0)||+c}function Ar(){if(!this.isValid())return this.localeData().invalidDate();var g,_,b,E,ce,Fe,vt,xi,c=Wo(this._milliseconds)/1e3,d=Wo(this._days),h=Wo(this._months),K=this.asSeconds();return K?(g=zn(c/60),_=zn(g/60),c%=60,g%=60,b=zn(h/12),h%=12,E=c?c.toFixed(3).replace(/\.?0+$/,""):"",ce=K<0?"-":"",Fe=Oi(this._months)!==Oi(K)?"-":"",vt=Oi(this._days)!==Oi(K)?"-":"",xi=Oi(this._milliseconds)!==Oi(K)?"-":"",ce+"P"+(b?Fe+b+"Y":"")+(h?Fe+h+"M":"")+(d?vt+d+"D":"")+(_||g||c?"T":"")+(_?xi+_+"H":"")+(g?xi+g+"M":"")+(c?xi+E+"S":"")):"P0D"}var De=Lo.prototype; //! moment.js -return De.isValid=function Yn(){return this._isValid},De.abs=function tp(){var c=this._data;return this._milliseconds=Oi(this._milliseconds),this._days=Oi(this._days),this._months=Oi(this._months),c.milliseconds=Oi(c.milliseconds),c.seconds=Oi(c.seconds),c.minutes=Oi(c.minutes),c.hours=Oi(c.hours),c.months=Oi(c.months),c.years=Oi(c.years),this},De.add=function np(c,d){return Vu(this,c,d,1)},De.subtract=function qs(c,d){return Vu(this,c,d,-1)},De.as=function ip(c){if(!this.isValid())return NaN;var d,h,g=this._milliseconds;if("month"===(c=Fn(c))||"quarter"===c||"year"===c)switch(d=this._days+g/864e5,h=this._months+Zs(d),c){case"month":return h;case"quarter":return h/3;case"year":return h/12}else switch(d=this._days+Math.round(Qs(this._months)),c){case"week":return d/7+g/6048e5;case"day":return d+g/864e5;case"hour":return 24*d+g/36e5;case"minute":return 1440*d+g/6e4;case"second":return 86400*d+g/1e3;case"millisecond":return Math.floor(864e5*d)+g;default:throw new Error("Unknown unit "+c)}},De.asMilliseconds=rp,De.asSeconds=op,De.asMinutes=Uo,De.asHours=Tl,De.asDays=sp,De.asWeeks=ap,De.asMonths=ly,De.asQuarters=cy,De.asYears=Xs,De.valueOf=function ir(){return this.isValid()?this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*he(this._months/12):NaN},De._bubble=function Js(){var _,b,N,Y,ce,c=this._milliseconds,d=this._days,h=this._months,g=this._data;return c>=0&&d>=0&&h>=0||c<=0&&d<=0&&h<=0||(c+=864e5*$o(Qs(h)+d),d=0,h=0),g.milliseconds=c%1e3,_=Kn(c/1e3),g.seconds=_%60,b=Kn(_/60),g.minutes=b%60,N=Kn(b/60),g.hours=N%24,d+=Kn(N/24),h+=ce=Kn(Zs(d)),d-=$o(Qs(ce)),Y=Kn(h/12),h%=12,g.days=d,g.months=h,g.years=Y,this},De.clone=function Hu(){return li(this)},De.get=function Bu(c){return c=Fn(c),this.isValid()?this[c+"s"]():NaN},De.milliseconds=ju,De.seconds=$u,De.minutes=oo,De.hours=lp,De.days=so,De.weeks=function uy(){return Kn(this.days()/7)},De.months=Al,De.years=ea,De.humanize=function Il(c,d){if(!this.isValid())return this.localeData().invalidDate();var _,b,h=!1,g=Ar;return"object"==typeof c&&(d=c,c=!1),"boolean"==typeof c&&(h=c),"object"==typeof d&&(g=Object.assign({},Ar,d),null!=d.s&&null==d.ss&&(g.ss=d.s-1)),b=function hi(c,d,h,g){var _=li(c).abs(),b=fi(_.as("s")),N=fi(_.as("m")),Y=fi(_.as("h")),ce=fi(_.as("d")),Pe=fi(_.as("M")),vt=fi(_.as("w")),Ri=fi(_.as("y")),nt=b<=h.ss&&["s",b]||b0,nt[4]=g,cp.apply(null,nt)}(this,!h,g,_=this.localeData()),h&&(b=_.pastFuture(+this,b)),_.postformat(b)},De.toISOString=Ir,De.toString=Ir,De.toJSON=Ir,De.locale=Ws,De.localeData=Bh,De.toIsoString=Zt("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",Ir),De.lang=Nu,z("X",0,0,"unix"),z("x",0,0,"valueOf"),$("x",ut),$("X",/[+-]?\d+(\.\d{1,3})?/),Se("X",function(c,d,h){h._d=new Date(1e3*parseFloat(c))}),Se("x",function(c,d,h){h._d=new Date(he(c))}),V.version="2.29.4",function qa(c){ye=c}(xe),V.fn=x,V.min=function dl(){return Sr("isBefore",[].slice.call(arguments,0))},V.max=function Er(){return Sr("isAfter",[].slice.call(arguments,0))},V.now=function(){return Date.now?Date.now():+new Date},V.utc=ii,V.unix=function Fu(c){return xe(1e3*c)},V.months=function on(c,d){return Lu(c,d,"months")},V.isDate=Zi,V.locale=Cr,V.invalid=mr,V.duration=li,V.isMoment=Wn,V.weekdays=function st(c,d,h){return Nl(c,d,h,"weekdays")},V.parseZone=function Pu(){return xe.apply(null,arguments).parseZone()},V.localeData=jn,V.isDuration=Fe,V.monthsShort=function nr(c,d){return Lu(c,d,"monthsShort")},V.weekdaysMin=function ep(c,d,h){return Nl(c,d,h,"weekdaysMin")},V.defineLocale=Xi,V.updateLocale=function Ae(c,d){if(null!=d){var h,g,_=ll;null!=Xe[c]&&null!=Xe[c].parentLocale?Xe[c].set(xn(Xe[c]._config,d)):(null!=(g=cl(c))&&(_=g._config),d=xn(_,d),null==g&&(d.abbr=c),(h=new Xa(d)).parentLocale=Xe[c],Xe[c]=h),Cr(c)}else null!=Xe[c]&&(null!=Xe[c].parentLocale?(Xe[c]=Xe[c].parentLocale,c===Cr()&&Cr(c)):null!=Xe[c]&&delete Xe[c]);return Xe[c]},V.locales=function ul(){return Cs(Xe)},V.weekdaysShort=function Xh(c,d,h){return Nl(c,d,h,"weekdaysShort")},V.normalizeUnits=Fn,V.relativeTimeRounding=function up(c){return void 0===c?fi:"function"==typeof c&&(fi=c,!0)},V.relativeTimeThreshold=function Go(c,d){return void 0!==Ar[c]&&(void 0===d?Ar[c]:(Ar[c]=d,"s"===c&&(Ar.ss=d-1),!0))},V.calendarFormat=function wu(c,d){var h=c.diff(d,"days",!0);return h<-6?"sameElse":h<-1?"lastWeek":h<0?"lastDay":h<1?"sameDay":h<2?"nextDay":h<7?"nextWeek":"sameElse"},V.prototype=x,V.HTML5_FMT={DATETIME_LOCAL:"YYYY-MM-DDTHH:mm",DATETIME_LOCAL_SECONDS:"YYYY-MM-DDTHH:mm:ss",DATETIME_LOCAL_MS:"YYYY-MM-DDTHH:mm:ss.SSS",DATE:"YYYY-MM-DD",TIME:"HH:mm",TIME_SECONDS:"HH:mm:ss",TIME_MS:"HH:mm:ss.SSS",WEEK:"GGGG-[W]WW",MONTH:"YYYY-MM"},V}()}},gr=>{gr(gr.s=381)}]); \ No newline at end of file +return De.isValid=function Kn(){return this._isValid},De.abs=function tp(){var c=this._data;return this._milliseconds=ki(this._milliseconds),this._days=ki(this._days),this._months=ki(this._months),c.milliseconds=ki(c.milliseconds),c.seconds=ki(c.seconds),c.minutes=ki(c.minutes),c.hours=ki(c.hours),c.months=ki(c.months),c.years=ki(c.years),this},De.add=function np(c,d){return Vu(this,c,d,1)},De.subtract=function qs(c,d){return Vu(this,c,d,-1)},De.as=function ip(c){if(!this.isValid())return NaN;var d,h,g=this._milliseconds;if("month"===(c=Pn(c))||"quarter"===c||"year"===c)switch(d=this._days+g/864e5,h=this._months+Js(d),c){case"month":return h;case"quarter":return h/3;case"year":return h/12}else switch(d=this._days+Math.round(Qs(this._months)),c){case"week":return d/7+g/6048e5;case"day":return d+g/864e5;case"hour":return 24*d+g/36e5;case"minute":return 1440*d+g/6e4;case"second":return 86400*d+g/1e3;case"millisecond":return Math.floor(864e5*d)+g;default:throw new Error("Unknown unit "+c)}},De.asMilliseconds=rp,De.asSeconds=op,De.asMinutes=Uo,De.asHours=Tl,De.asDays=sp,De.asWeeks=ap,De.asMonths=ly,De.asQuarters=cy,De.asYears=Xs,De.valueOf=function ir(){return this.isValid()?this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*he(this._months/12):NaN},De._bubble=function Zs(){var _,b,E,K,ce,c=this._milliseconds,d=this._days,h=this._months,g=this._data;return c>=0&&d>=0&&h>=0||c<=0&&d<=0&&h<=0||(c+=864e5*$o(Qs(h)+d),d=0,h=0),g.milliseconds=c%1e3,_=zn(c/1e3),g.seconds=_%60,b=zn(_/60),g.minutes=b%60,E=zn(b/60),g.hours=E%24,d+=zn(E/24),h+=ce=zn(Js(d)),d-=$o(Qs(ce)),K=zn(h/12),h%=12,g.days=d,g.months=h,g.years=K,this},De.clone=function Bu(){return li(this)},De.get=function Hu(c){return c=Pn(c),this.isValid()?this[c+"s"]():NaN},De.milliseconds=ju,De.seconds=$u,De.minutes=oo,De.hours=lp,De.days=so,De.weeks=function uy(){return zn(this.days()/7)},De.months=Il,De.years=ea,De.humanize=function Al(c,d){if(!this.isValid())return this.localeData().invalidDate();var _,b,h=!1,g=Ir;return"object"==typeof c&&(d=c,c=!1),"boolean"==typeof c&&(h=c),"object"==typeof d&&(g=Object.assign({},Ir,d),null!=d.s&&null==d.ss&&(g.ss=d.s-1)),b=function hi(c,d,h,g){var _=li(c).abs(),b=fi(_.as("s")),E=fi(_.as("m")),K=fi(_.as("h")),ce=fi(_.as("d")),Fe=fi(_.as("M")),vt=fi(_.as("w")),xi=fi(_.as("y")),nt=b<=h.ss&&["s",b]||b0,nt[4]=g,cp.apply(null,nt)}(this,!h,g,_=this.localeData()),h&&(b=_.pastFuture(+this,b)),_.postformat(b)},De.toISOString=Ar,De.toString=Ar,De.toJSON=Ar,De.locale=Ws,De.localeData=Hh,De.toIsoString=Jt("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",Ar),De.lang=Eu,Y("X",0,0,"unix"),Y("x",0,0,"valueOf"),$("x",ut),$("X",/[+-]?\d+(\.\d{1,3})?/),Se("X",function(c,d,h){h._d=new Date(1e3*parseFloat(c))}),Se("x",function(c,d,h){h._d=new Date(he(c))}),V.version="2.29.4",function qa(c){ye=c}(Re),V.fn=R,V.min=function dl(){return Sr("isBefore",[].slice.call(arguments,0))},V.max=function Mr(){return Sr("isAfter",[].slice.call(arguments,0))},V.now=function(){return Date.now?Date.now():+new Date},V.utc=ii,V.unix=function Pu(c){return Re(1e3*c)},V.months=function on(c,d){return Lu(c,d,"months")},V.isDate=Ji,V.locale=Cr,V.invalid=mr,V.duration=li,V.isMoment=Wn,V.weekdays=function st(c,d,h){return El(c,d,h,"weekdays")},V.parseZone=function Fu(){return Re.apply(null,arguments).parseZone()},V.localeData=jn,V.isDuration=Pe,V.monthsShort=function nr(c,d){return Lu(c,d,"monthsShort")},V.weekdaysMin=function ep(c,d,h){return El(c,d,h,"weekdaysMin")},V.defineLocale=Xi,V.updateLocale=function Ie(c,d){if(null!=d){var h,g,_=ll;null!=Xe[c]&&null!=Xe[c].parentLocale?Xe[c].set(Rn(Xe[c]._config,d)):(null!=(g=cl(c))&&(_=g._config),d=Rn(_,d),null==g&&(d.abbr=c),(h=new Xa(d)).parentLocale=Xe[c],Xe[c]=h),Cr(c)}else null!=Xe[c]&&(null!=Xe[c].parentLocale?(Xe[c]=Xe[c].parentLocale,c===Cr()&&Cr(c)):null!=Xe[c]&&delete Xe[c]);return Xe[c]},V.locales=function ul(){return Cs(Xe)},V.weekdaysShort=function Xh(c,d,h){return El(c,d,h,"weekdaysShort")},V.normalizeUnits=Pn,V.relativeTimeRounding=function up(c){return void 0===c?fi:"function"==typeof c&&(fi=c,!0)},V.relativeTimeThreshold=function Go(c,d){return void 0!==Ir[c]&&(void 0===d?Ir[c]:(Ir[c]=d,"s"===c&&(Ir.ss=d-1),!0))},V.calendarFormat=function wu(c,d){var h=c.diff(d,"days",!0);return h<-6?"sameElse":h<-1?"lastWeek":h<0?"lastDay":h<1?"sameDay":h<2?"nextDay":h<7?"nextWeek":"sameElse"},V.prototype=R,V.HTML5_FMT={DATETIME_LOCAL:"YYYY-MM-DDTHH:mm",DATETIME_LOCAL_SECONDS:"YYYY-MM-DDTHH:mm:ss",DATETIME_LOCAL_MS:"YYYY-MM-DDTHH:mm:ss.SSS",DATE:"YYYY-MM-DD",TIME:"HH:mm",TIME_SECONDS:"HH:mm:ss",TIME_MS:"HH:mm:ss.SSS",WEEK:"GGGG-[W]WW",MONTH:"YYYY-MM"},V}()}},gr=>{gr(gr.s=381)}]); \ No newline at end of file diff --git a/src/KafkaFlow.Admin.Dashboard/ClientApp/src/environments/environment.prod.ts b/src/KafkaFlow.Admin.Dashboard/ClientApp/src/environments/environment.prod.ts index 0ab556da1..6ed00f120 100644 --- a/src/KafkaFlow.Admin.Dashboard/ClientApp/src/environments/environment.prod.ts +++ b/src/KafkaFlow.Admin.Dashboard/ClientApp/src/environments/environment.prod.ts @@ -1,4 +1,4 @@ export const environment = { production: true, - apiUrl: "/kafka-flow" + apiUrl: "/kafkaflow" }; diff --git a/src/KafkaFlow.Admin.Dashboard/ClientApp/src/environments/environment.ts b/src/KafkaFlow.Admin.Dashboard/ClientApp/src/environments/environment.ts index 6d9afd161..9e53f6b4d 100644 --- a/src/KafkaFlow.Admin.Dashboard/ClientApp/src/environments/environment.ts +++ b/src/KafkaFlow.Admin.Dashboard/ClientApp/src/environments/environment.ts @@ -4,7 +4,7 @@ export const environment = { production: false, - apiUrl: 'http://localhost:5000/kafka-flow' + apiUrl: 'http://localhost:5000/kafkaflow' }; /* diff --git a/src/KafkaFlow.Admin.Dashboard/DashboardConfigurationBuilder.cs b/src/KafkaFlow.Admin.Dashboard/DashboardConfigurationBuilder.cs index 110acc4e4..4c0e1e61f 100644 --- a/src/KafkaFlow.Admin.Dashboard/DashboardConfigurationBuilder.cs +++ b/src/KafkaFlow.Admin.Dashboard/DashboardConfigurationBuilder.cs @@ -6,7 +6,7 @@ namespace KafkaFlow.Admin.Dashboard internal class DashboardConfigurationBuilder : IDashboardConfigurationBuilder { - private readonly PathString basePath = "/kafka-flow"; + private readonly PathString basePath = "/kafkaflow"; private Action requestHandler = _ => { }; private Action endpointHandler = _ => { }; diff --git a/src/KafkaFlow.Admin.WebApi/Controllers/ConsumersController.cs b/src/KafkaFlow.Admin.WebApi/Controllers/ConsumersController.cs index 959e36e0a..557645965 100644 --- a/src/KafkaFlow.Admin.WebApi/Controllers/ConsumersController.cs +++ b/src/KafkaFlow.Admin.WebApi/Controllers/ConsumersController.cs @@ -12,7 +12,7 @@ namespace KafkaFlow.Admin.WebApi.Controllers /// /// Consumers controller /// - [Route("kafka-flow/groups/{groupId}/consumers")] + [Route("kafkaflow/groups/{groupId}/consumers")] [ApiController] public class ConsumersController : ControllerBase { @@ -23,7 +23,7 @@ public class ConsumersController : ControllerBase /// Initializes a new instance of the class. /// /// The accessor class that provides access to the consumers - /// The producer to publish admin messages + /// The admin messages consumer public ConsumersController(IConsumerAccessor consumers, IConsumerAdmin consumerAdmin) { this.consumers = consumers; diff --git a/src/KafkaFlow.Admin.WebApi/Controllers/GroupsController.cs b/src/KafkaFlow.Admin.WebApi/Controllers/GroupsController.cs index 49886a54d..5424b5d31 100644 --- a/src/KafkaFlow.Admin.WebApi/Controllers/GroupsController.cs +++ b/src/KafkaFlow.Admin.WebApi/Controllers/GroupsController.cs @@ -12,7 +12,7 @@ namespace KafkaFlow.Admin.WebApi.Controllers /// /// Groups controller /// - [Route("kafka-flow/groups")] + [Route("kafkaflow/groups")] [ApiController] public class GroupsController : ControllerBase { @@ -23,7 +23,7 @@ public class GroupsController : ControllerBase /// Initializes a new instance of the class. /// /// The accessor class that provides access to the consumers - /// The producer to publish admin messages + /// The admin messages consumer public GroupsController(IConsumerAccessor consumers, IConsumerAdmin consumerAdmin) { this.consumers = consumers; diff --git a/src/KafkaFlow.Admin.WebApi/Controllers/TelemetryController.cs b/src/KafkaFlow.Admin.WebApi/Controllers/TelemetryController.cs index 763768546..2cc39ef3c 100644 --- a/src/KafkaFlow.Admin.WebApi/Controllers/TelemetryController.cs +++ b/src/KafkaFlow.Admin.WebApi/Controllers/TelemetryController.cs @@ -7,7 +7,7 @@ namespace KafkaFlow.Admin.WebApi.Controllers /// /// Telemetry controller /// - [Route("kafka-flow/telemetry")] + [Route("kafkaflow/telemetry")] [ApiController] public class TelemetryController : ControllerBase { diff --git a/src/KafkaFlow.Admin/Handlers/PauseConsumerByNameHandler.cs b/src/KafkaFlow.Admin/Handlers/PauseConsumerByNameHandler.cs index 317e8440d..c8bd71843 100644 --- a/src/KafkaFlow.Admin/Handlers/PauseConsumerByNameHandler.cs +++ b/src/KafkaFlow.Admin/Handlers/PauseConsumerByNameHandler.cs @@ -27,4 +27,4 @@ public Task Handle(IMessageContext context, PauseConsumerByName message) return Task.CompletedTask; } } -} \ No newline at end of file +} diff --git a/src/KafkaFlow.Admin/Handlers/RewindConsumerOffsetToDateTimeHandler.cs b/src/KafkaFlow.Admin/Handlers/RewindConsumerOffsetToDateTimeHandler.cs index 8ede7f638..83712ab40 100644 --- a/src/KafkaFlow.Admin/Handlers/RewindConsumerOffsetToDateTimeHandler.cs +++ b/src/KafkaFlow.Admin/Handlers/RewindConsumerOffsetToDateTimeHandler.cs @@ -4,7 +4,7 @@ namespace KafkaFlow.Admin.Handlers using System.Linq; using System.Threading.Tasks; using Confluent.Kafka; - using Extensions; + using KafkaFlow.Admin.Extensions; using KafkaFlow.Admin.Messages; using KafkaFlow.Consumers; using KafkaFlow.TypedHandler; diff --git a/src/KafkaFlow.IntegrationTests/ProducerTest.cs b/src/KafkaFlow.IntegrationTests/ProducerTest.cs index e1cce8c37..00f4e58db 100644 --- a/src/KafkaFlow.IntegrationTests/ProducerTest.cs +++ b/src/KafkaFlow.IntegrationTests/ProducerTest.cs @@ -23,7 +23,6 @@ public void Setup() MessageStorage.Clear(); } - [TestMethod] public async Task ProduceNullKeyTest() { diff --git a/src/KafkaFlow.UnitTests/Admin.WebApi/Controllers/ConsumersControllerTests.cs b/src/KafkaFlow.UnitTests/Admin.WebApi/Controllers/ConsumersControllerTests.cs new file mode 100644 index 000000000..25d018991 --- /dev/null +++ b/src/KafkaFlow.UnitTests/Admin.WebApi/Controllers/ConsumersControllerTests.cs @@ -0,0 +1,506 @@ +namespace KafkaFlow.UnitTests.Admin.WebApi.Controllers +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + using AutoFixture; + using FluentAssertions; + using KafkaFlow.Admin; + using KafkaFlow.Admin.WebApi.Contracts; + using KafkaFlow.Admin.WebApi.Controllers; + using KafkaFlow.Consumers; + using Microsoft.AspNetCore.Mvc; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + + [TestClass] + public class ConsumersControllerTests + { + private readonly Fixture fixture = new(); + private ConsumersController target; + private Mock mockConsumerAccessor; + private Mock mockConsumerAdmin; + + [TestInitialize] + public void TestSetup() + { + this.mockConsumerAccessor = this.fixture.Freeze>(); + this.mockConsumerAdmin = this.fixture.Freeze>(); + this.target = new ConsumersController(this.mockConsumerAccessor.Object, this.mockConsumerAdmin.Object); + } + + [TestMethod] + public void GetConsumersByGroupId_ValidGroupId_ReturnsOkResultWithConsumersResponse() + { + // Arrange + var groupId = "group1"; + + var consumers = new List + { + Mock.Of(c => c.GroupId == "group1" && c.ConsumerName == "consumer1"), + Mock.Of(c => c.GroupId == "group1" && c.ConsumerName == "consumer2"), + }; + + this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + + // Act + var result = this.target.GetConsumersByGroupId(groupId) as ObjectResult; + + // Assert + result.Should().NotBeNull(); + result.StatusCode.Should().Be(200); + + var response = result.Value.Should().BeOfType().Subject; + response.Consumers.Should().HaveCount(2); + response.Consumers.Select(c => c.ConsumerName).Should().Contain(new[] { "consumer1", "consumer2" }); + } + + [TestMethod] + public void GetConsumerByGroupIdName_ValidGroupIdAndExistingConsumer_ReturnsOkResultWithConsumerResponse() + { + // Arrange + var groupId = "group1"; + var consumerName = "consumer1"; + + var consumers = new List + { + Mock.Of(c => c.GroupId == groupId && c.ConsumerName == consumerName), + Mock.Of(c => c.GroupId == "group1" && c.ConsumerName == "consumer2"), + }; + + this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers.AsQueryable()); + + // Act + var result = this.target.GetConsumerByGroupIdName(groupId, consumerName) as ObjectResult; + + // Assert + result.Should().NotBeNull(); + result.StatusCode.Should().Be(200); + + var response = result.Value.Should().BeOfType().Subject; + response.GroupId.Should().Be(groupId); + response.ConsumerName.Should().Be(consumerName); + } + + [TestMethod] + public void GetConsumerByGroupIdName_ValidGroupIdAndNonExistingConsumer_ReturnsNotFoundResult() + { + // Arrange + var groupId = "group1"; + var consumerName = "nonExistingConsumer"; + + // Act + var result = this.target.GetConsumerByGroupIdName(groupId, consumerName) as NotFoundResult; + + // Assert + result.Should().NotBeNull(); + result.StatusCode.Should().Be(404); + } + + [TestMethod] + public async Task PauseConsumer_ValidGroupIdAndExistingConsumer_ReturnsAcceptedResult() + { + // Arrange + var groupId = "group1"; + var consumerName = "consumer1"; + var topics = new List { "topic1", "topic2" }; + + var consumers = new List + { + Mock.Of(c => c.GroupId == groupId && c.ConsumerName == consumerName), + }; + + this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + + // Act + var result = await this.target.PauseConsumer(groupId, consumerName, topics) as AcceptedResult; + + // Assert + result.Should().NotBeNull(); + result.StatusCode.Should().Be(202); + + this.mockConsumerAdmin.Verify(x => x.PauseConsumerAsync(consumerName, topics), Times.Once); + } + + [TestMethod] + public async Task PauseConsumer_ValidGroupIdAndNonExistingConsumer_ReturnsNotFoundResult() + { + // Arrange + var groupId = "group1"; + var consumerName = "consumer1"; + var topics = new List { "topic1", "topic2" }; + + var consumers = new List + { + Mock.Of(c => c.GroupId == groupId && c.ConsumerName == "consumer2"), + }; + + this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + + // Act + var result = await this.target.PauseConsumer(groupId, consumerName, topics) as NotFoundResult; + + // Assert + result.Should().NotBeNull(); + result.StatusCode.Should().Be(404); + } + + [TestMethod] + public async Task ResumeConsumer_ValidGroupIdAndNonExistingConsumer_ReturnsNotFoundResult() + { + // Arrange + var groupId = "group1"; + var consumerName = "nonExistingConsumer"; + var topics = new List { "topic1", "topic2" }; + + var consumers = new List + { + Mock.Of(c => c.GroupId == groupId && c.ConsumerName == "existingConsumer"), + }; + + this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + + // Act + var result = await this.target.ResumeConsumer(groupId, consumerName, topics) as NotFoundResult; + + // Assert + result.Should().NotBeNull(); + result.StatusCode.Should().Be(404); + + this.mockConsumerAdmin.Verify(x => x.ResumeConsumerAsync(consumerName, topics), Times.Never); + } + + [TestMethod] + public async Task StartConsumer_ValidGroupIdAndExistingConsumer_ReturnsAcceptedResult() + { + // Arrange + var groupId = "group1"; + var consumerName = "consumer1"; + + var consumers = new List + { + Mock.Of(c => c.GroupId == groupId && c.ConsumerName == consumerName), + }; + + this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + + // Act + var result = await this.target.StartConsumer(groupId, consumerName) as AcceptedResult; + + // Assert + result.Should().NotBeNull(); + result.StatusCode.Should().Be(202); + + this.mockConsumerAdmin.Verify(x => x.StartConsumerAsync(consumerName), Times.Once); + } + + [TestMethod] + public async Task StartConsumer_ValidGroupIdAndNonExistingConsumer_ReturnsNotFoundResult() + { + // Arrange + var groupId = "group1"; + var consumerName = "nonExistingConsumer"; + + var consumers = new List + { + Mock.Of(c => c.GroupId == groupId && c.ConsumerName == "consumer1"), + }; + + this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + + // Act + var result = await this.target.StartConsumer(groupId, consumerName) as NotFoundResult; + + // Assert + result.Should().NotBeNull(); + result.StatusCode.Should().Be(404); + + this.mockConsumerAdmin.Verify(x => x.StartConsumerAsync(consumerName), Times.Never); + } + + [TestMethod] + public async Task StopConsumer_ValidGroupIdAndExistingConsumer_ReturnsAcceptedResult() + { + // Arrange + var groupId = "group1"; + var consumerName = "consumer1"; + + var consumers = new List + { + Mock.Of(c => c.GroupId == groupId && c.ConsumerName == consumerName), + }; + + this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + + // Act + var result = await this.target.StopConsumer(groupId, consumerName) as AcceptedResult; + + // Assert + result.Should().NotBeNull(); + result.StatusCode.Should().Be(202); + + this.mockConsumerAdmin.Verify(x => x.StopConsumerAsync(consumerName), Times.Once); + } + + [TestMethod] + public async Task StopConsumer_ValidGroupIdAndNonExistingConsumer_ReturnsNotFoundResult() + { + // Arrange + var groupId = "group1"; + var consumerName = "nonExistingConsumer"; + + var consumers = new List + { + Mock.Of(c => c.GroupId == groupId && c.ConsumerName == "consumer1"), + }; + + this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + + // Act + var result = await this.target.StopConsumer(groupId, consumerName) as NotFoundResult; + + // Assert + result.Should().NotBeNull(); + result.StatusCode.Should().Be(404); + + this.mockConsumerAdmin.Verify(x => x.StopConsumerAsync(consumerName), Times.Never); + } + + [TestMethod] + public async Task RestartConsumer_ValidGroupIdAndExistingConsumer_ReturnsAcceptedResult() + { + // Arrange + var groupId = "group1"; + var consumerName = "consumer1"; + + var consumers = new List + { + Mock.Of(c => c.GroupId == groupId && c.ConsumerName == consumerName), + }; + + this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + + // Act + var result = await this.target.RestartConsumer(groupId, consumerName) as AcceptedResult; + + // Assert + result.Should().NotBeNull(); + result.StatusCode.Should().Be(202); + + this.mockConsumerAdmin.Verify(x => x.RestartConsumerAsync(consumerName), Times.Once); + } + + [TestMethod] + public async Task RestartConsumer_ValidGroupIdAndNonExistingConsumer_ReturnsNotFoundResult() + { + // Arrange + var groupId = "group1"; + var consumerName = "nonExistingConsumer"; + + var consumers = new List + { + Mock.Of(c => c.GroupId == groupId && c.ConsumerName == "consumer1"), + }; + + this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + + // Act + var result = await this.target.RestartConsumer(groupId, consumerName) as NotFoundResult; + + // Assert + result.Should().NotBeNull(); + result.StatusCode.Should().Be(404); + + this.mockConsumerAdmin.Verify(x => x.StopConsumerAsync(consumerName), Times.Never); + } + + [TestMethod] + public async Task ResetOffsets_ValidRequest_ReturnsAcceptedResult() + { + // Arrange + var groupId = "group1"; + var consumerName = "consumer1"; + var topics = new List { "topic1", "topic2" }; + var request = new ResetOffsetsRequest { Confirm = true }; + + var consumers = new List + { + Mock.Of(c => c.GroupId == groupId && c.ConsumerName == consumerName), + }; + + this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + + // Act + var result = await this.target.ResetOffsets(groupId, consumerName, topics, request) as AcceptedResult; + + // Assert + result.Should().NotBeNull(); + result.StatusCode.Should().Be(202); + + this.mockConsumerAdmin.Verify(x => x.ResetOffsetsAsync(consumerName, topics), Times.Once); + } + + [TestMethod] + public async Task ResetOffsets_InvalidConfirmValue_ReturnsBadRequestResult() + { + // Arrange + var groupId = "group1"; + var consumerName = "consumer1"; + var topics = new List { "topic1", "topic2" }; + var request = new ResetOffsetsRequest { Confirm = false }; // Invalid Confirm value + + var consumers = new List + { + Mock.Of(c => c.GroupId == groupId && c.ConsumerName == consumerName), + }; + + this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + + // Act + var result = await this.target.ResetOffsets(groupId, consumerName, topics, request) as BadRequestResult; + + // Assert + result.Should().NotBeNull(); + result.StatusCode.Should().Be(400); + + this.mockConsumerAdmin.Verify(x => x.ResetOffsetsAsync(consumerName, topics), Times.Never); + } + + [TestMethod] + public async Task RewindOffsets_ValidGroupIdAndNonExistingConsumer_ReturnsNotFoundResult() + { + // Arrange + var groupId = "group1"; + var consumerName = "nonExistingConsumer"; + var topics = new List { "topic1", "topic2" }; + var request = new RewindOffsetsToDateRequest { Date = this.fixture.Create() }; + + var consumers = new List + { + Mock.Of(c => c.GroupId == groupId && c.ConsumerName == "consumer1"), + }; + + this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + + // Act + var result = await this.target.RewindOffsets(groupId, consumerName, topics, request) as NotFoundResult; + + // Assert + result.Should().NotBeNull(); + result.StatusCode.Should().Be(404); + + this.mockConsumerAdmin.Verify(x => x.RewindOffsetsAsync(consumerName, request.Date, topics), Times.Never); + } + + [TestMethod] + public async Task RewindOffsets_ValidRequest_ReturnsAcceptedResult() + { + // Arrange + var groupId = "group1"; + var consumerName = "consumer1"; + var topics = new List { "topic1", "topic2" }; + var request = new RewindOffsetsToDateRequest { Date = this.fixture.Create() }; + + var consumers = new List + { + Mock.Of(c => c.GroupId == groupId && c.ConsumerName == consumerName), + }; + + this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + + // Act + var result = await this.target.RewindOffsets(groupId, consumerName, topics, request) as AcceptedResult; + + // Assert + result.Should().NotBeNull(); + result.StatusCode.Should().Be(202); + + this.mockConsumerAdmin.Verify(x => x.RewindOffsetsAsync(consumerName, request.Date, topics), Times.Once); + } + + [TestMethod] + public async Task RewindOffsets_InvalidRequest_ReturnsBadRequestResult() + { + // Arrange + var groupId = "group1"; + var consumerName = "consumer1"; + var topics = new List { "topic1", "topic2" }; + RewindOffsetsToDateRequest request = null; + + // Act + var result = await this.target.RewindOffsets(groupId, consumerName, topics, request) as BadRequestResult; + + // Assert + result.Should().NotBeNull(); + result.StatusCode.Should().Be(400); + + this.mockConsumerAdmin.Verify(x => x.RewindOffsetsAsync(consumerName, It.IsAny(), topics), Times.Never); + } + + [TestMethod] + public async Task ChangeWorkersCount_ValidRequest_ReturnsAcceptedResult() + { + // Arrange + var groupId = "group1"; + var consumerName = "consumer1"; + var topics = new List { "topic1", "topic2" }; + var request = new RewindOffsetsToDateRequest { Date = this.fixture.Create() }; + + var consumers = new List + { + Mock.Of(c => c.GroupId == groupId && c.ConsumerName == consumerName), + }; + + this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + + // Act + var result = await this.target.RewindOffsets(groupId, consumerName, topics, request) as AcceptedResult; + + // Assert + result.Should().NotBeNull(); + result.StatusCode.Should().Be(202); + + this.mockConsumerAdmin.Verify(x => x.RewindOffsetsAsync(consumerName, request.Date, topics), Times.Once); + } + + [TestMethod] + public async Task ChangeWorkersCount_NullRequest_ReturnsBadRequestResult() + { + // Arrange + var groupId = "group1"; + var consumerName = "consumer1"; + ChangeWorkersCountRequest request = null; + + // Act + var result = await this.target.ChangeWorkersCount(groupId, consumerName, request) as BadRequestResult; + + // Assert + result.Should().NotBeNull(); + result.StatusCode.Should().Be(400); + + this.mockConsumerAdmin.Verify(x => x.ChangeWorkersCountAsync(consumerName, It.IsAny()), Times.Never); + } + + [DataRow(0)] + [DataRow(-5)] + [DataRow(-100)] + [TestMethod] + public async Task ChangeWorkersCount_InvalidWorkerCount_ReturnsBadRequestResult(int workerCount) + { + // Arrange + var groupId = "group1"; + var consumerName = "consumer1"; + ChangeWorkersCountRequest request = new ChangeWorkersCountRequest { WorkersCount = workerCount }; + + // Act + var result = await this.target.ChangeWorkersCount(groupId, consumerName, request) as BadRequestResult; + + // Assert + result.Should().NotBeNull(); + result.StatusCode.Should().Be(400); + + this.mockConsumerAdmin.Verify(x => x.ChangeWorkersCountAsync(consumerName, It.IsAny()), Times.Never); + } + } +} diff --git a/src/KafkaFlow.UnitTests/Admin.WebApi/Controllers/GroupsControllerTests.cs b/src/KafkaFlow.UnitTests/Admin.WebApi/Controllers/GroupsControllerTests.cs new file mode 100644 index 000000000..91bbcdf18 --- /dev/null +++ b/src/KafkaFlow.UnitTests/Admin.WebApi/Controllers/GroupsControllerTests.cs @@ -0,0 +1,91 @@ +namespace KafkaFlow.UnitTests.Admin.WebApi.Controllers +{ + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + using AutoFixture; + using FluentAssertions; + using KafkaFlow.Admin; + using KafkaFlow.Admin.WebApi.Contracts; + using KafkaFlow.Admin.WebApi.Controllers; + using KafkaFlow.Consumers; + using Microsoft.AspNetCore.Mvc; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + + [TestClass] + public class GroupsControllerTests + { + private readonly Fixture fixture = new(); + private GroupsController target; + private Mock mockConsumerAccessor; + private Mock mockConsumerAdmin; + + [TestInitialize] + public void TestSetup() + { + this.mockConsumerAccessor = this.fixture.Freeze>(); + this.mockConsumerAdmin = this.fixture.Freeze>(); + this.target = new GroupsController(this.mockConsumerAccessor.Object, this.mockConsumerAdmin.Object); + } + + [TestMethod] + public void GetAllGroups_ReturnsOkResultWithGroupsResponse() + { + // Arrange + var consumers = new List + { + Mock.Of(), + Mock.Of(), + Mock.Of(), + }; + + this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + + // Act + var result = this.target.GetAllGroups() as ObjectResult; + + // Assert + result.Should().NotBeNull(); + result.StatusCode.Should().Be(200); + + var response = result.Value.Should().BeOfType().Subject; + response.Groups.Should().HaveCount(1); + response.Groups.First().Consumers.Should().HaveCount(3); + } + + [TestMethod] + public async Task PauseGroup_ValidGroupId_ReturnsAcceptedResult() + { + // Arrange + var groupId = "group1"; + var topics = new List { "topic1", "topic2" }; + + // Act + var result = await this.target.PauseGroup(groupId, topics) as AcceptedResult; + + // Assert + result.Should().NotBeNull(); + result.StatusCode.Should().Be(202); + + this.mockConsumerAdmin.Verify(x => x.PauseConsumerGroupAsync(groupId, topics), Times.Once); + } + + [TestMethod] + public async Task ResumeGroup_ValidGroupId_ReturnsAcceptedResult() + { + // Arrange + var groupId = "group1"; + var topics = new List { "topic1", "topic2" }; + + // Act + var result = await this.target.ResumeGroup(groupId, topics) as AcceptedResult; + + // Assert + result.Should().NotBeNull(); + result.StatusCode.Should().Be(202); + + this.mockConsumerAdmin.Verify(x => x.ResumeConsumerGroupAsync(groupId, topics), Times.Once); + } + } +} diff --git a/src/KafkaFlow.UnitTests/Admin.WebApi/Controllers/TelemetryControllerTests.cs b/src/KafkaFlow.UnitTests/Admin.WebApi/Controllers/TelemetryControllerTests.cs new file mode 100644 index 000000000..0a9d2bd0c --- /dev/null +++ b/src/KafkaFlow.UnitTests/Admin.WebApi/Controllers/TelemetryControllerTests.cs @@ -0,0 +1,130 @@ +namespace KafkaFlow.UnitTests.Admin.WebApi.Controllers +{ + using System; + using System.Collections.Generic; + using System.Linq; + using FluentAssertions; + using KafkaFlow.Admin; + using KafkaFlow.Admin.Messages; + using KafkaFlow.Admin.WebApi.Contracts; + using KafkaFlow.Admin.WebApi.Controllers; + using KafkaFlow.Consumers; + using Microsoft.AspNetCore.Mvc; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + + [TestClass] + public class TelemetryControllerTests + { + private Mock mockTelemetryStorage; + private TelemetryController target; + + [TestInitialize] + public void TestInitialize() + { + this.mockTelemetryStorage = new Mock(); + this.target = new TelemetryController(this.mockTelemetryStorage.Object); + } + + [TestMethod] + public void GetTelemetry_ReturnsOkResultWithTelemetryResponse() + { + // Arrange + var metrics = new List + { + new ConsumerTelemetryMetric + { + GroupId = "group1", + ConsumerName = "consumer1", + WorkersCount = 5, + SentAt = new DateTime(2023, 7, 28, 8, 20, 30), + Topic = "topic1", + Status = ConsumerStatus.Running, + PausedPartitions = new[] { 0 }, + RunningPartitions = new[] { 10 }, + Lag = 20, + InstanceName = "instanceName1", + }, + new ConsumerTelemetryMetric + { + GroupId = "group1", + ConsumerName = "consumer1", + WorkersCount = 5, + SentAt = new DateTime(2023, 7, 29, 1, 20, 30), + Topic = "topic2", + Status = ConsumerStatus.Paused, + PausedPartitions = new[] { 5 }, + RunningPartitions = new[] { 0 }, + Lag = 0, + InstanceName = "instanceName2", + }, + new ConsumerTelemetryMetric + { + GroupId = "group1", + ConsumerName = "consumer2", + WorkersCount = 3, + SentAt = new DateTime(2023, 6, 2, 10, 20, 30), + Topic = "topic3", + Status = ConsumerStatus.Stopped, + PausedPartitions = new[] { 5 }, + RunningPartitions = new[] { 0 }, + Lag = 15, + InstanceName = "instanceName3", + }, + }; + + this.mockTelemetryStorage.Setup(x => x.Get()).Returns(metrics); + + // Act + var result = this.target.GetTelemetry() as ObjectResult; + + // Assert + result.Should().NotBeNull(); + result.StatusCode.Should().Be(200); + + var response = result.Value.Should().BeOfType().Subject; + response.Groups.Should().HaveCount(1); + + var group = response.Groups.ElementAt(0); + group.GroupId.Should().Be("group1"); + group.Consumers.Should().HaveCount(2); + + var consumer1 = group.Consumers.ElementAt(0); + consumer1.Name.Should().Be("consumer1"); + consumer1.WorkersCount.Should().Be(5); + consumer1.Assignments.Should().HaveCount(2); + + var assignment1 = consumer1.Assignments.ElementAt(0); + assignment1.InstanceName.Should().NotBeNullOrEmpty(); + assignment1.TopicName.Should().Be("topic1"); + assignment1.Status.Should().Be("Running"); + assignment1.LastUpdate.Should().BeCloseTo(new DateTime(2023, 7, 28, 8, 20, 30), TimeSpan.FromSeconds(1)); + assignment1.PausedPartitions.Should().BeEquivalentTo(new[] { 0 }); + assignment1.RunningPartitions.Should().BeEquivalentTo(new[] { 10 }); + assignment1.Lag.Should().Be(20); + + var assignment2 = consumer1.Assignments.ElementAt(1); + assignment2.InstanceName.Should().NotBeNullOrEmpty(); + assignment2.TopicName.Should().Be("topic2"); + assignment2.Status.Should().Be("Paused"); + assignment2.LastUpdate.Should().BeCloseTo(new DateTime(2023, 7, 29, 1, 20, 30), TimeSpan.FromSeconds(1)); + assignment2.PausedPartitions.Should().BeEquivalentTo(new[] { 5 }); + assignment2.RunningPartitions.Should().BeEquivalentTo(new[] { 0 }); + assignment2.Lag.Should().Be(0); + + var consumer2 = group.Consumers.ElementAt(1); + consumer2.Name.Should().Be("consumer2"); + consumer2.WorkersCount.Should().Be(3); + consumer2.Assignments.Should().HaveCount(1); + + var assignment3 = consumer2.Assignments.ElementAt(0); + assignment3.InstanceName.Should().NotBeNullOrEmpty(); + assignment3.TopicName.Should().Be("topic3"); + assignment3.Status.Should().Be("Stopped"); + assignment3.LastUpdate.Should().BeCloseTo(new DateTime(2023, 6, 2, 10, 20, 30), TimeSpan.FromSeconds(1)); + assignment3.PausedPartitions.Should().BeEquivalentTo(new[] { 5 }); + assignment3.RunningPartitions.Should().BeEquivalentTo(new[] { 0 }); + assignment3.Lag.Should().Be(15); + } + } +} diff --git a/src/KafkaFlow.UnitTests/KafkaFlow.UnitTests.csproj b/src/KafkaFlow.UnitTests/KafkaFlow.UnitTests.csproj index cfba1c2c7..f8e053443 100644 --- a/src/KafkaFlow.UnitTests/KafkaFlow.UnitTests.csproj +++ b/src/KafkaFlow.UnitTests/KafkaFlow.UnitTests.csproj @@ -15,7 +15,8 @@ - + + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -28,6 +29,7 @@ + From 9c43c282e16c9f4e8698cd7de7ad499bcaa39ef1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sousa?= Date: Tue, 12 Sep 2023 22:29:45 +0100 Subject: [PATCH 03/20] feat!: async support on message type and schema registry resolvers --- ...ncSchemaRegistryTypeNameResolverWrapper.cs | 14 -- .../IAsyncSchemaRegistryTypeNameResolver.cs | 17 -- .../ISchemaRegistryTypeNameResolver.cs | 4 +- .../SchemaRegistryTypeResolver.cs | 17 +- .../AssemblyInfo.cs | 3 + .../ConfluentAvroTypeNameResolver.cs | 4 +- .../AssemblyInfo.cs | 3 + .../ConfluentProtobufTypeNameResolver.cs | 2 +- .../AsyncMessageTypeResolverWrapper.cs | 21 -- .../DefaultTypeResolver.cs | 13 +- .../IAsyncMessageTypeResolver.cs | 24 --- .../IMessageTypeResolver.cs | 5 +- .../KafkaFlow.Serializer.csproj | 1 + .../SerializerConsumerMiddleware.cs | 15 +- .../SerializerProducerMiddleware.cs | 14 +- .../SingleMessageTypeResolver.cs | 6 +- .../DummyObjects/DummyProtobufObject.cs | 201 ++++++++++++++++++ .../DummyObjects/DummyProtobufObject.proto | 11 + .../KafkaFlow.UnitTests.csproj | 3 + .../ConfluentAvroTypeNameResolverTests.cs | 47 ++++ .../ConfluentProtobufTypeNameResolverTests.cs | 49 +++++ .../SchemaRegistryTypeResolverTests.cs | 47 ++++ .../SerializerConsumerMiddlewareTests.cs | 12 +- .../SerializerProducerMiddlewareTests.cs | 2 +- .../UnityDependencyResolver.cs | 2 - 25 files changed, 399 insertions(+), 138 deletions(-) delete mode 100644 src/KafkaFlow.SchemaRegistry/AsyncSchemaRegistryTypeNameResolverWrapper.cs delete mode 100644 src/KafkaFlow.SchemaRegistry/IAsyncSchemaRegistryTypeNameResolver.cs create mode 100644 src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/AssemblyInfo.cs create mode 100644 src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/AssemblyInfo.cs delete mode 100644 src/KafkaFlow.Serializer/AsyncMessageTypeResolverWrapper.cs delete mode 100644 src/KafkaFlow.Serializer/IAsyncMessageTypeResolver.cs create mode 100644 src/KafkaFlow.UnitTests/DummyObjects/DummyProtobufObject.cs create mode 100644 src/KafkaFlow.UnitTests/DummyObjects/DummyProtobufObject.proto create mode 100644 src/KafkaFlow.UnitTests/Middlewares/Serialization/ConfluentAvroTypeNameResolverTests.cs create mode 100644 src/KafkaFlow.UnitTests/Middlewares/Serialization/ConfluentProtobufTypeNameResolverTests.cs create mode 100644 src/KafkaFlow.UnitTests/Middlewares/Serialization/SchemaRegistryTypeResolverTests.cs diff --git a/src/KafkaFlow.SchemaRegistry/AsyncSchemaRegistryTypeNameResolverWrapper.cs b/src/KafkaFlow.SchemaRegistry/AsyncSchemaRegistryTypeNameResolverWrapper.cs deleted file mode 100644 index d91fee9fc..000000000 --- a/src/KafkaFlow.SchemaRegistry/AsyncSchemaRegistryTypeNameResolverWrapper.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace KafkaFlow -{ - using System.Threading.Tasks; - - internal class AsyncSchemaRegistryTypeNameResolverWrapper : IAsyncSchemaRegistryTypeNameResolver - { - private readonly ISchemaRegistryTypeNameResolver typeNameResolver; - - public AsyncSchemaRegistryTypeNameResolverWrapper(ISchemaRegistryTypeNameResolver typeNameResolver) => - this.typeNameResolver = typeNameResolver; - - public Task ResolveAsync(int schemaId) => Task.FromResult(this.typeNameResolver.Resolve(schemaId)); - } -} diff --git a/src/KafkaFlow.SchemaRegistry/IAsyncSchemaRegistryTypeNameResolver.cs b/src/KafkaFlow.SchemaRegistry/IAsyncSchemaRegistryTypeNameResolver.cs deleted file mode 100644 index 497964faa..000000000 --- a/src/KafkaFlow.SchemaRegistry/IAsyncSchemaRegistryTypeNameResolver.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace KafkaFlow -{ - using System.Threading.Tasks; - - /// - /// An interface to implement a type name resolver to messages serialized with schema registry serializers - /// - public interface IAsyncSchemaRegistryTypeNameResolver - { - /// - /// Resolve the message type name of a schema - /// - /// Identifier of the schema - /// - Task ResolveAsync(int schemaId); - } -} diff --git a/src/KafkaFlow.SchemaRegistry/ISchemaRegistryTypeNameResolver.cs b/src/KafkaFlow.SchemaRegistry/ISchemaRegistryTypeNameResolver.cs index 6d4773156..17cc95c82 100644 --- a/src/KafkaFlow.SchemaRegistry/ISchemaRegistryTypeNameResolver.cs +++ b/src/KafkaFlow.SchemaRegistry/ISchemaRegistryTypeNameResolver.cs @@ -1,5 +1,7 @@ namespace KafkaFlow { + using System.Threading.Tasks; + /// /// An interface to implement a type name resolver to messages serialized with schema registry serializers /// @@ -10,6 +12,6 @@ public interface ISchemaRegistryTypeNameResolver /// /// Identifier of the schema /// - string Resolve(int schemaId); + Task ResolveAsync(int schemaId); } } diff --git a/src/KafkaFlow.SchemaRegistry/SchemaRegistryTypeResolver.cs b/src/KafkaFlow.SchemaRegistry/SchemaRegistryTypeResolver.cs index 20185edc4..f0dd56cd9 100644 --- a/src/KafkaFlow.SchemaRegistry/SchemaRegistryTypeResolver.cs +++ b/src/KafkaFlow.SchemaRegistry/SchemaRegistryTypeResolver.cs @@ -10,34 +10,25 @@ namespace KafkaFlow /// /// The message type resolver to be used with schema registry serializers /// - public class SchemaRegistryTypeResolver : IAsyncMessageTypeResolver + public class SchemaRegistryTypeResolver : IMessageTypeResolver { private static readonly ConcurrentDictionary Types = new(); private static readonly SemaphoreSlim Semaphore = new(1, 1); - private readonly IAsyncSchemaRegistryTypeNameResolver typeNameResolver; + private readonly ISchemaRegistryTypeNameResolver typeNameResolver; /// /// Initializes a new instance of the class. /// /// A instance of the interface. public SchemaRegistryTypeResolver(ISchemaRegistryTypeNameResolver typeNameResolver) - : this(new AsyncSchemaRegistryTypeNameResolverWrapper(typeNameResolver)) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// A instance of the interface. - public SchemaRegistryTypeResolver(IAsyncSchemaRegistryTypeNameResolver typeNameResolver) { this.typeNameResolver = typeNameResolver; } /// - public async Task OnConsumeAsync(IMessageContext context) + public async ValueTask OnConsumeAsync(IMessageContext context) { var schemaId = BinaryPrimitives.ReadInt32BigEndian( ((byte[]) context.Message.Value).AsSpan().Slice(1, 4)); @@ -70,6 +61,6 @@ public async Task OnConsumeAsync(IMessageContext context) } /// - public Task OnProduceAsync(IMessageContext context) => Task.CompletedTask; + public ValueTask OnProduceAsync(IMessageContext context) => default(ValueTask); } } diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/AssemblyInfo.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/AssemblyInfo.cs new file mode 100644 index 000000000..17459bd5a --- /dev/null +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("KafkaFlow.UnitTests")] diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConfluentAvroTypeNameResolver.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConfluentAvroTypeNameResolver.cs index 8a8af39e1..c0fc1c9a2 100644 --- a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConfluentAvroTypeNameResolver.cs +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConfluentAvroTypeNameResolver.cs @@ -1,10 +1,10 @@ -namespace KafkaFlow +namespace KafkaFlow.Serializer.SchemaRegistry { using System.Threading.Tasks; using Confluent.SchemaRegistry; using Newtonsoft.Json; - internal class ConfluentAvroTypeNameResolver : IAsyncSchemaRegistryTypeNameResolver + internal class ConfluentAvroTypeNameResolver : ISchemaRegistryTypeNameResolver { private readonly ISchemaRegistryClient client; diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/AssemblyInfo.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/AssemblyInfo.cs new file mode 100644 index 000000000..17459bd5a --- /dev/null +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("KafkaFlow.UnitTests")] diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConfluentProtobufTypeNameResolver.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConfluentProtobufTypeNameResolver.cs index f57f8fca7..8ae17ee63 100644 --- a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConfluentProtobufTypeNameResolver.cs +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConfluentProtobufTypeNameResolver.cs @@ -6,7 +6,7 @@ namespace KafkaFlow using Google.Protobuf; using Google.Protobuf.Reflection; - internal class ConfluentProtobufTypeNameResolver : IAsyncSchemaRegistryTypeNameResolver + internal class ConfluentProtobufTypeNameResolver : ISchemaRegistryTypeNameResolver { private readonly ISchemaRegistryClient client; diff --git a/src/KafkaFlow.Serializer/AsyncMessageTypeResolverWrapper.cs b/src/KafkaFlow.Serializer/AsyncMessageTypeResolverWrapper.cs deleted file mode 100644 index fac02e462..000000000 --- a/src/KafkaFlow.Serializer/AsyncMessageTypeResolverWrapper.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace KafkaFlow -{ - using System; - using System.Threading.Tasks; - - internal class AsyncMessageTypeResolverWrapper : IAsyncMessageTypeResolver - { - private readonly IMessageTypeResolver typeResolver; - - public AsyncMessageTypeResolverWrapper(IMessageTypeResolver typeResolver) => this.typeResolver = typeResolver; - - public Task OnConsumeAsync(IMessageContext context) => - Task.FromResult(this.typeResolver.OnConsume(context)); - - public Task OnProduceAsync(IMessageContext context) - { - this.typeResolver.OnProduce(context); - return Task.CompletedTask; - } - } -} diff --git a/src/KafkaFlow.Serializer/DefaultTypeResolver.cs b/src/KafkaFlow.Serializer/DefaultTypeResolver.cs index 31cba1dff..6613db2c9 100644 --- a/src/KafkaFlow.Serializer/DefaultTypeResolver.cs +++ b/src/KafkaFlow.Serializer/DefaultTypeResolver.cs @@ -1,25 +1,26 @@ namespace KafkaFlow { using System; + using System.Threading.Tasks; internal class DefaultTypeResolver : IMessageTypeResolver { private const string MessageType = "Message-Type"; - public Type OnConsume(IMessageContext context) + public ValueTask OnConsumeAsync(IMessageContext context) { var typeName = context.Headers.GetString(MessageType); return typeName is null ? - null : - Type.GetType(typeName); + new ValueTask((Type) null) : + new ValueTask(Type.GetType(typeName)); } - public void OnProduce(IMessageContext context) + public ValueTask OnProduceAsync(IMessageContext context) { if (context.Message.Value is null) { - return; + return default(ValueTask); } var messageType = context.Message.Value.GetType(); @@ -27,6 +28,8 @@ public void OnProduce(IMessageContext context) context.Headers.SetString( MessageType, $"{messageType.FullName}, {messageType.Assembly.GetName().Name}"); + + return default(ValueTask); } } } diff --git a/src/KafkaFlow.Serializer/IAsyncMessageTypeResolver.cs b/src/KafkaFlow.Serializer/IAsyncMessageTypeResolver.cs deleted file mode 100644 index ffe4626bd..000000000 --- a/src/KafkaFlow.Serializer/IAsyncMessageTypeResolver.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace KafkaFlow -{ - using System; - using System.Threading.Tasks; - - /// - /// Used by the serializer middleware to resolve the type when consuming and store it when producing - /// - public interface IAsyncMessageTypeResolver - { - /// - /// Returns the message type when consuming - /// - /// The containing the message and the metadata - /// - Task OnConsumeAsync(IMessageContext context); - - /// - /// Stores the message type somewhere when producing - /// - /// The containing the message and the metadata - Task OnProduceAsync(IMessageContext context); - } -} diff --git a/src/KafkaFlow.Serializer/IMessageTypeResolver.cs b/src/KafkaFlow.Serializer/IMessageTypeResolver.cs index 5d6d87551..a7b9190d8 100644 --- a/src/KafkaFlow.Serializer/IMessageTypeResolver.cs +++ b/src/KafkaFlow.Serializer/IMessageTypeResolver.cs @@ -1,6 +1,7 @@ namespace KafkaFlow { using System; + using System.Threading.Tasks; /// /// Used by the serializer middleware to resolve the type when consuming and store it when producing @@ -12,12 +13,12 @@ public interface IMessageTypeResolver /// /// The containing the message and the metadata /// - Type OnConsume(IMessageContext context); + ValueTask OnConsumeAsync(IMessageContext context); /// /// Stores the message type somewhere when producing /// /// The containing the message and the metadata - void OnProduce(IMessageContext context); + ValueTask OnProduceAsync(IMessageContext context); } } diff --git a/src/KafkaFlow.Serializer/KafkaFlow.Serializer.csproj b/src/KafkaFlow.Serializer/KafkaFlow.Serializer.csproj index d0e384d2f..2a0a1c219 100644 --- a/src/KafkaFlow.Serializer/KafkaFlow.Serializer.csproj +++ b/src/KafkaFlow.Serializer/KafkaFlow.Serializer.csproj @@ -13,6 +13,7 @@ + diff --git a/src/KafkaFlow.Serializer/SerializerConsumerMiddleware.cs b/src/KafkaFlow.Serializer/SerializerConsumerMiddleware.cs index e2bc353b1..a00a81d6b 100644 --- a/src/KafkaFlow.Serializer/SerializerConsumerMiddleware.cs +++ b/src/KafkaFlow.Serializer/SerializerConsumerMiddleware.cs @@ -10,8 +10,7 @@ public class SerializerConsumerMiddleware : IMessageMiddleware { private readonly ISerializer serializer; - - private readonly IAsyncMessageTypeResolver typeResolver; + private readonly IMessageTypeResolver typeResolver; /// /// Initializes a new instance of the class. @@ -21,18 +20,6 @@ public class SerializerConsumerMiddleware : IMessageMiddleware public SerializerConsumerMiddleware( ISerializer serializer, IMessageTypeResolver typeResolver) - : this(serializer, new AsyncMessageTypeResolverWrapper(typeResolver)) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// Instance of - /// Instance of - public SerializerConsumerMiddleware( - ISerializer serializer, - IAsyncMessageTypeResolver typeResolver) { this.serializer = serializer; this.typeResolver = typeResolver; diff --git a/src/KafkaFlow.Serializer/SerializerProducerMiddleware.cs b/src/KafkaFlow.Serializer/SerializerProducerMiddleware.cs index b7c0da7c8..2adf0f443 100644 --- a/src/KafkaFlow.Serializer/SerializerProducerMiddleware.cs +++ b/src/KafkaFlow.Serializer/SerializerProducerMiddleware.cs @@ -12,7 +12,7 @@ public class SerializerProducerMiddleware : IMessageMiddleware private readonly ISerializer serializer; - private readonly IAsyncMessageTypeResolver typeResolver; + private readonly IMessageTypeResolver typeResolver; /// /// Initializes a new instance of the class. @@ -22,18 +22,6 @@ public class SerializerProducerMiddleware : IMessageMiddleware public SerializerProducerMiddleware( ISerializer serializer, IMessageTypeResolver typeResolver) - : this(serializer, new AsyncMessageTypeResolverWrapper(typeResolver)) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// Instance of - /// Instance of - public SerializerProducerMiddleware( - ISerializer serializer, - IAsyncMessageTypeResolver typeResolver) { this.serializer = serializer; this.typeResolver = typeResolver; diff --git a/src/KafkaFlow.Serializer/SingleMessageTypeResolver.cs b/src/KafkaFlow.Serializer/SingleMessageTypeResolver.cs index b1d22d054..ee4cbc35c 100644 --- a/src/KafkaFlow.Serializer/SingleMessageTypeResolver.cs +++ b/src/KafkaFlow.Serializer/SingleMessageTypeResolver.cs @@ -1,6 +1,7 @@ namespace KafkaFlow { using System; + using System.Threading.Tasks; /// /// The message type resolver to be used when all messages are the same type @@ -19,12 +20,13 @@ public SingleMessageTypeResolver(Type messageType) } /// - public Type OnConsume(IMessageContext context) => this.messageType; + public ValueTask OnConsumeAsync(IMessageContext context) => new ValueTask(this.messageType); /// - public void OnProduce(IMessageContext context) + public ValueTask OnProduceAsync(IMessageContext context) { // Do nothing + return default(ValueTask); } } } diff --git a/src/KafkaFlow.UnitTests/DummyObjects/DummyProtobufObject.cs b/src/KafkaFlow.UnitTests/DummyObjects/DummyProtobufObject.cs new file mode 100644 index 000000000..1bc60a9b1 --- /dev/null +++ b/src/KafkaFlow.UnitTests/DummyObjects/DummyProtobufObject.cs @@ -0,0 +1,201 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: DummyProtobufObject.proto +// +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace KafkaFlow.UnitTests { + + /// Holder for reflection information generated from DummyProtobufObject.proto + public static partial class DummyProtobufObjectReflection { + + #region Descriptor + /// File descriptor for DummyProtobufObject.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static DummyProtobufObjectReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "ChlEdW1teVByb3RvYnVmT2JqZWN0LnByb3RvEhNLYWZrYUZsb3cuVW5pdFRl", + "c3RzIjUKE0R1bW15UHJvdG9idWZPYmplY3QSDgoGZmllbGQxGAEgASgJEg4K", + "BmZpZWxkMhgCIAEoBWIGcHJvdG8z")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { }, + new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::KafkaFlow.UnitTests.DummyProtobufObject), global::KafkaFlow.UnitTests.DummyProtobufObject.Parser, new[]{ "Field1", "Field2" }, null, null, null, null) + })); + } + #endregion + + } + #region Messages + public sealed partial class DummyProtobufObject : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DummyProtobufObject()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public static pbr::MessageDescriptor Descriptor { + get { return global::KafkaFlow.UnitTests.DummyProtobufObjectReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DummyProtobufObject() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DummyProtobufObject(DummyProtobufObject other) : this() { + field1_ = other.field1_; + field2_ = other.field2_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public DummyProtobufObject Clone() { + return new DummyProtobufObject(this); + } + + /// Field number for the "field1" field. + public const int Field1FieldNumber = 1; + private string field1_ = ""; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public string Field1 { + get { return field1_; } + set { + field1_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "field2" field. + public const int Field2FieldNumber = 2; + private int field2_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int Field2 { + get { return field2_; } + set { + field2_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override bool Equals(object other) { + return Equals(other as DummyProtobufObject); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public bool Equals(DummyProtobufObject other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Field1 != other.Field1) return false; + if (Field2 != other.Field2) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override int GetHashCode() { + int hash = 1; + if (Field1.Length != 0) hash ^= Field1.GetHashCode(); + if (Field2 != 0) hash ^= Field2.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void WriteTo(pb::CodedOutputStream output) { + if (Field1.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Field1); + } + if (Field2 != 0) { + output.WriteRawTag(16); + output.WriteInt32(Field2); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public int CalculateSize() { + int size = 0; + if (Field1.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Field1); + } + if (Field2 != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Field2); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(DummyProtobufObject other) { + if (other == null) { + return; + } + if (other.Field1.Length != 0) { + Field1 = other.Field1; + } + if (other.Field2 != 0) { + Field2 = other.Field2; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + Field1 = input.ReadString(); + break; + } + case 16: { + Field2 = input.ReadInt32(); + break; + } + } + } + } + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/src/KafkaFlow.UnitTests/DummyObjects/DummyProtobufObject.proto b/src/KafkaFlow.UnitTests/DummyObjects/DummyProtobufObject.proto new file mode 100644 index 000000000..7acea2bdb --- /dev/null +++ b/src/KafkaFlow.UnitTests/DummyObjects/DummyProtobufObject.proto @@ -0,0 +1,11 @@ +// can be generated using +// protoc --csharp_out=. DummyProtobufObject.proto + +syntax = "proto3"; + +package KafkaFlow.UnitTests; + +message DummyProtobufObject { + string field1 = 1; + int32 field2 = 2; +} diff --git a/src/KafkaFlow.UnitTests/KafkaFlow.UnitTests.csproj b/src/KafkaFlow.UnitTests/KafkaFlow.UnitTests.csproj index f8e053443..6e905e545 100644 --- a/src/KafkaFlow.UnitTests/KafkaFlow.UnitTests.csproj +++ b/src/KafkaFlow.UnitTests/KafkaFlow.UnitTests.csproj @@ -34,7 +34,10 @@ + + + diff --git a/src/KafkaFlow.UnitTests/Middlewares/Serialization/ConfluentAvroTypeNameResolverTests.cs b/src/KafkaFlow.UnitTests/Middlewares/Serialization/ConfluentAvroTypeNameResolverTests.cs new file mode 100644 index 000000000..5fdeb0921 --- /dev/null +++ b/src/KafkaFlow.UnitTests/Middlewares/Serialization/ConfluentAvroTypeNameResolverTests.cs @@ -0,0 +1,47 @@ +namespace KafkaFlow.UnitTests.Middlewares.Serialization +{ + using System.Threading.Tasks; + using Confluent.SchemaRegistry; + using FluentAssertions; + using KafkaFlow.Serializer.SchemaRegistry; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Newtonsoft.Json; + + [TestClass] + public class ConfluentAvroTypeNameResolverTests + { + private readonly Mock schemaRegistryClient; + private readonly ConfluentAvroTypeNameResolver schemaRegistryTypeResolver; + + public ConfluentAvroTypeNameResolverTests() + { + this.schemaRegistryClient = new Mock(); + this.schemaRegistryTypeResolver = new ConfluentAvroTypeNameResolver(this.schemaRegistryClient.Object); + } + + [TestMethod] + public async Task ResolveAsync_ValidSchemaObject_ReturnsAvroFieldsInCorrectFormat() + { + // Arrange + var schemaId = 420; + var type = typeof(ConfluentAvroTypeNameResolverTests); + var schemaObj = new + { + Name = type.Name, + NameSpace = type.Namespace, + }; + + var schema = new Schema(JsonConvert.SerializeObject(schemaObj), SchemaType.Avro); + + this.schemaRegistryClient.Setup(client => client.GetSchemaAsync(schemaId, null)) + .ReturnsAsync(schema); + + // Act + var avroFields = await this.schemaRegistryTypeResolver.ResolveAsync(schemaId); + + // Assert + avroFields.Should().Be($"{schemaObj.NameSpace}.{schemaObj.Name}"); + } + } +} diff --git a/src/KafkaFlow.UnitTests/Middlewares/Serialization/ConfluentProtobufTypeNameResolverTests.cs b/src/KafkaFlow.UnitTests/Middlewares/Serialization/ConfluentProtobufTypeNameResolverTests.cs new file mode 100644 index 000000000..cd6ec854f --- /dev/null +++ b/src/KafkaFlow.UnitTests/Middlewares/Serialization/ConfluentProtobufTypeNameResolverTests.cs @@ -0,0 +1,49 @@ +namespace KafkaFlow.UnitTests.Middlewares.Serialization +{ + using System; + using System.Threading.Tasks; + using Confluent.SchemaRegistry; + + using FluentAssertions; + + using Google.Protobuf; + using KafkaFlow.Serializer.SchemaRegistry; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + + [TestClass] + public class ConfluentProtobufTypeNameResolverTests + { + private readonly Mock schemaRegistryClient; + private readonly ConfluentProtobufTypeNameResolver schemaRegistryTypeResolver; + + public ConfluentProtobufTypeNameResolverTests() + { + this.schemaRegistryClient = new Mock(); + this.schemaRegistryTypeResolver = new ConfluentProtobufTypeNameResolver(this.schemaRegistryClient.Object); + } + + [TestMethod] + public async Task ResolveAsync_ValidProtobufObject_ReturnsProtoFields() + { + // Arrange + var schemaId = 420; + + var dummyProtobufObj = new DummyProtobufObject + { + Field1 = "Field1", + Field2 = 8, + }; + var base64Encoded = Convert.ToBase64String(dummyProtobufObj.ToByteArray()); + + this.schemaRegistryClient.Setup(client => client.GetSchemaAsync(schemaId, "serialized")) + .ReturnsAsync(new Schema(base64Encoded, SchemaType.Protobuf)); + + // Act + var protoFields = await this.schemaRegistryTypeResolver.ResolveAsync(schemaId); + + // Assert + protoFields.Should().NotBeNull(); + } + } +} diff --git a/src/KafkaFlow.UnitTests/Middlewares/Serialization/SchemaRegistryTypeResolverTests.cs b/src/KafkaFlow.UnitTests/Middlewares/Serialization/SchemaRegistryTypeResolverTests.cs new file mode 100644 index 000000000..38f720526 --- /dev/null +++ b/src/KafkaFlow.UnitTests/Middlewares/Serialization/SchemaRegistryTypeResolverTests.cs @@ -0,0 +1,47 @@ +namespace KafkaFlow.UnitTests.Middlewares.Serialization +{ + using System; + using System.Buffers.Binary; + using System.Threading.Tasks; + using FluentAssertions; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + + [TestClass] + public class SchemaRegistryTypeResolverTests + { + private readonly Mock messageContextMock; + private readonly Mock schemaRegistryTypeNameResolverMock; + private readonly SchemaRegistryTypeResolver schemaRegistryTypeResolver; + private readonly byte[] messageKey = new byte[] { 0x18, 0x19 }; + private readonly byte[] messageValue = new byte[] { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25 }; + + public SchemaRegistryTypeResolverTests() + { + this.messageContextMock = new Mock(); + this.messageContextMock.Setup(context => context.Message).Returns(new Message(messageKey, messageValue)); + this.schemaRegistryTypeNameResolverMock = new Mock(); + this.schemaRegistryTypeResolver = new SchemaRegistryTypeResolver(this.schemaRegistryTypeNameResolverMock.Object); + } + + [TestMethod] + public async Task OnConsumeAsync_WhenCalledTwice_TypeIsResolvedOnceThenTypeIsLoadedFromCache() + { + // Arrange + var expectedSchemaId = BinaryPrimitives.ReadInt32BigEndian( + this.messageValue.AsSpan().Slice(1, 4)); + + this.schemaRegistryTypeNameResolverMock.Setup( + resolver => resolver.ResolveAsync(expectedSchemaId)).ReturnsAsync(typeof(SchemaRegistryTypeResolverTests).FullName); + + // Act + await this.schemaRegistryTypeResolver.OnConsumeAsync(messageContextMock.Object); + var type = await this.schemaRegistryTypeResolver.OnConsumeAsync(messageContextMock.Object); + + // Assert + this.schemaRegistryTypeNameResolverMock.Verify(resolver => resolver.ResolveAsync(expectedSchemaId), Times.Once); + var expectedObject = (SchemaRegistryTypeResolverTests)Activator.CreateInstance(type); + expectedObject.Should().NotBeNull(); + } + } +} diff --git a/src/KafkaFlow.UnitTests/Serializers/SerializerConsumerMiddlewareTests.cs b/src/KafkaFlow.UnitTests/Serializers/SerializerConsumerMiddlewareTests.cs index 117cd9f50..cf0f1398b 100644 --- a/src/KafkaFlow.UnitTests/Serializers/SerializerConsumerMiddlewareTests.cs +++ b/src/KafkaFlow.UnitTests/Serializers/SerializerConsumerMiddlewareTests.cs @@ -39,8 +39,8 @@ public async Task Invoke_NullMessageType_ReturnWithoutCallingNext() .Returns(new Message(new byte[1], new byte[1])); this.typeResolverMock - .Setup(x => x.OnConsume(this.contextMock.Object)) - .Returns((Type)null); + .Setup(x => x.OnConsumeAsync(this.contextMock.Object)) + .ReturnsAsync((Type)null); // Act await this.target.Invoke(this.contextMock.Object, _ => this.SetNextCalled()); @@ -70,7 +70,7 @@ public async Task Invoke_NullMessage_CallNext() this.serializerMock.Verify( x => x.DeserializeAsync(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); - this.typeResolverMock.Verify(x => x.OnConsume(It.IsAny()), Times.Never); + this.typeResolverMock.Verify(x => x.OnConsumeAsync(It.IsAny()), Times.Never); } [TestMethod] @@ -91,7 +91,7 @@ public void Invoke_NotByteArrayMessage_ThrowsInvalidOperationException() this.serializerMock.Verify( x => x.DeserializeAsync(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); - this.typeResolverMock.Verify(x => x.OnConsume(It.IsAny()), Times.Never); + this.typeResolverMock.Verify(x => x.OnConsumeAsync(It.IsAny()), Times.Never); } [TestMethod] @@ -119,8 +119,8 @@ public async Task Invoke_ValidMessage_Deserialize() .Returns(transformedContextMock.Object); this.typeResolverMock - .Setup(x => x.OnConsume(this.contextMock.Object)) - .Returns(messageType); + .Setup(x => x.OnConsumeAsync(this.contextMock.Object)) + .ReturnsAsync(messageType); this.serializerMock .Setup(x => x.DeserializeAsync(It.IsAny(), messageType, It.IsAny())) diff --git a/src/KafkaFlow.UnitTests/Serializers/SerializerProducerMiddlewareTests.cs b/src/KafkaFlow.UnitTests/Serializers/SerializerProducerMiddlewareTests.cs index 0b45b7a1e..74030a595 100644 --- a/src/KafkaFlow.UnitTests/Serializers/SerializerProducerMiddlewareTests.cs +++ b/src/KafkaFlow.UnitTests/Serializers/SerializerProducerMiddlewareTests.cs @@ -48,7 +48,7 @@ public async Task Invoke_ValidMessage_Serialize() .SetupGet(x => x.Message) .Returns(deserializedMessage); - this.typeResolverMock.Setup(x => x.OnProduce(this.contextMock.Object)); + this.typeResolverMock.Setup(x => x.OnProduceAsync(this.contextMock.Object)); this.serializerMock .Setup( diff --git a/src/KafkaFlow.Unity/UnityDependencyResolver.cs b/src/KafkaFlow.Unity/UnityDependencyResolver.cs index ed3c8b3ad..35b06c43f 100644 --- a/src/KafkaFlow.Unity/UnityDependencyResolver.cs +++ b/src/KafkaFlow.Unity/UnityDependencyResolver.cs @@ -2,9 +2,7 @@ namespace KafkaFlow.Unity { using System; using System.Collections.Generic; - using System.Linq; using global::Unity; - using global::Unity.Resolution; /// /// Unity implementation of From ce607552dd41c583183e8ce9c21ec688a58ed587 Mon Sep 17 00:00:00 2001 From: Filipe Esch Date: Tue, 4 Jul 2023 18:50:47 +0100 Subject: [PATCH 04/20] feat: enable workers count calculation in runtime fix: change dependency injection lifetime management for worker and consumer/producer fix: create AdminClient without authentication perf: memory optimizations on MessageContext --- .../IConsumerConfigurationBuilder.cs | 19 + .../Configuration/WorkersCountContext.cs | 29 + .../IConsumerContext.cs | 15 + .../IDateTimeProvider.cs | 4 +- src/KafkaFlow.Abstractions/IMessageContext.cs | 8 + .../IProducerContext.cs | 40 +- .../MiddlewareLifetime.cs | 25 +- .../ClientApp/dist/index.html | 11 +- .../ClientApp/dist/main.js | 2032 +---------------- .../ClientApp/dist/polyfills.js | 198 +- .../ClientApp/dist/styles.css | 7 +- .../ClientApp/src/app/api/models/consumer.ts | 1 - .../api/models/topic-partition-assignment.ts | 1 + .../src/app/consumer/consumer.component.html | 6 +- .../src/app/consumer/consumer.component.ts | 3 +- .../workers-count-modal.component.html | 4 - .../workers-count-modal.component.ts | 8 +- .../TelemetryResponse.cs | 10 +- .../TelemetryResponseAdapter.cs | 5 +- src/KafkaFlow.Admin/MemoryTelemetryStorage.cs | 8 +- src/KafkaFlow.Admin/TelemetryScheduler.cs | 63 +- .../BatchConsumeMessageContext.cs | 9 +- .../ConfigurationBuilderExtensions.cs | 2 +- .../ConsumerConfigurationBuilderTests.cs | 4 +- .../Consumer/ConsumerManagerTests.cs | 54 +- .../MemoryTelemetryStorageTests.cs | 6 +- src/KafkaFlow/Clusters/ClusterManager.cs | 88 +- src/KafkaFlow/Clusters/IClusterManager.cs | 20 + .../Configuration/ConsumerConfiguration.cs | 22 +- .../ConsumerConfigurationBuilder.cs | 24 +- .../Configuration/IConsumerConfiguration.cs | 10 +- .../MiddlewareConfigurationBuilder.cs | 2 +- src/KafkaFlow/ConsumerManagerFactory.cs | 2 +- src/KafkaFlow/Consumers/Consumer.cs | 20 +- src/KafkaFlow/Consumers/ConsumerContext.cs | 27 +- src/KafkaFlow/Consumers/ConsumerManager.cs | 93 +- src/KafkaFlow/Consumers/ConsumerWorker.cs | 23 +- src/KafkaFlow/Consumers/ConsumerWorkerPool.cs | 113 +- .../BytesSumDistributionStrategy.cs | 11 +- .../Consumers/IConsumerWorkerPool.cs | 4 +- src/KafkaFlow/Consumers/IOffsetCommitter.cs | 2 + src/KafkaFlow/Consumers/MessageConsumer.cs | 6 +- .../Consumers/NullOffsetCommitter.cs | 5 + src/KafkaFlow/Consumers/OffsetCommitter.cs | 86 +- src/KafkaFlow/Consumers/OffsetManager.cs | 11 +- src/KafkaFlow/DateTimeProvider.cs | 2 +- .../ConfigurationBuilderExtensions.cs | 4 +- src/KafkaFlow/IMiddlewareExecutor.cs | 7 +- src/KafkaFlow/MessageContext.cs | 5 + src/KafkaFlow/MiddlewareExecutor.cs | 50 +- src/KafkaFlow/Producers/MessageProducer.cs | 72 +- src/KafkaFlow/Producers/ProducerContext.cs | 5 +- src/KafkaFlow/TopicMetadata.cs | 17 + src/KafkaFlow/TopicPartitionMetadata.cs | 12 + src/KafkaFlow/TopicPartitionOffset.cs | 36 + 55 files changed, 774 insertions(+), 2577 deletions(-) create mode 100644 src/KafkaFlow.Abstractions/Configuration/WorkersCountContext.cs create mode 100644 src/KafkaFlow/TopicMetadata.cs create mode 100644 src/KafkaFlow/TopicPartitionMetadata.cs create mode 100644 src/KafkaFlow/TopicPartitionOffset.cs diff --git a/src/KafkaFlow.Abstractions/Configuration/IConsumerConfigurationBuilder.cs b/src/KafkaFlow.Abstractions/Configuration/IConsumerConfigurationBuilder.cs index 00c04e422..472ee87ee 100644 --- a/src/KafkaFlow.Abstractions/Configuration/IConsumerConfigurationBuilder.cs +++ b/src/KafkaFlow.Abstractions/Configuration/IConsumerConfigurationBuilder.cs @@ -2,6 +2,7 @@ namespace KafkaFlow.Configuration { using System; using System.Collections.Generic; + using System.Threading.Tasks; /// /// Used to build the consumer configuration @@ -92,6 +93,24 @@ public interface IConsumerConfigurationBuilder /// IConsumerConfigurationBuilder WithWorkersCount(int workersCount); + /// + /// Configures a custom function to dynamically calculate the number of workers. + /// + /// A function that takes a WorkersCountContext object and returns a Task yielding the new workers count + /// The interval that the calculator will be called + /// The IConsumerConfigurationBuilder instance for method chaining + IConsumerConfigurationBuilder WithWorkersCount( + Func> calculator, + TimeSpan evaluationInterval); + + /// + /// Configures a custom function to dynamically calculate the number of workers. + /// By default, this function is called every 5 minutes. + /// + /// A function that takes a WorkersCountContext object and returns a Task yielding the new workers count + /// The IConsumerConfigurationBuilder instance for method chaining + IConsumerConfigurationBuilder WithWorkersCount(Func> calculator); + /// /// Sets how many messages will be buffered for each worker /// diff --git a/src/KafkaFlow.Abstractions/Configuration/WorkersCountContext.cs b/src/KafkaFlow.Abstractions/Configuration/WorkersCountContext.cs new file mode 100644 index 000000000..1a476f02f --- /dev/null +++ b/src/KafkaFlow.Abstractions/Configuration/WorkersCountContext.cs @@ -0,0 +1,29 @@ +namespace KafkaFlow.Configuration +{ + using System.Collections.Generic; + + /// + /// A metadata class with some context information help to calculate the number of workers + /// + public class WorkersCountContext + { + public WorkersCountContext( + string consumerName, + string consumerGroupId, + IReadOnlyCollection assignedTopicsPartitions) + { + this.ConsumerName = consumerName; + this.ConsumerGroupId = consumerGroupId; + this.AssignedTopicsPartitions = assignedTopicsPartitions; + } + + public string ConsumerName { get; } + + public string ConsumerGroupId { get; } + + /// + /// Gets the assigned partitions to the consumer + /// + public IReadOnlyCollection AssignedTopicsPartitions { get; } + } +} diff --git a/src/KafkaFlow.Abstractions/IConsumerContext.cs b/src/KafkaFlow.Abstractions/IConsumerContext.cs index 76733d147..bd7fafc98 100644 --- a/src/KafkaFlow.Abstractions/IConsumerContext.cs +++ b/src/KafkaFlow.Abstractions/IConsumerContext.cs @@ -53,6 +53,21 @@ public interface IConsumerContext /// bool ShouldStoreOffset { get; set; } + /// + /// Gets an instance of IDependencyResolver which provides methods to resolve dependencies. + /// This instance is tied to the consumer scope, meaning it is capable of resolving dependencies + /// that are scoped to the lifecycle of a single consumer. + /// + IDependencyResolver ConsumerDependencyResolver { get; } + + /// + /// Gets an instance of IDependencyResolver which provides methods to resolve dependencies. + /// This instance is tied to the worker scope, meaning it is capable of resolving dependencies + /// that are scoped to the lifecycle of a single worker. + /// + IDependencyResolver WorkerDependencyResolver { get; } + + /// /// Store the message offset when manual store option is used /// diff --git a/src/KafkaFlow.Abstractions/IDateTimeProvider.cs b/src/KafkaFlow.Abstractions/IDateTimeProvider.cs index 8439703e4..b235eeb4a 100644 --- a/src/KafkaFlow.Abstractions/IDateTimeProvider.cs +++ b/src/KafkaFlow.Abstractions/IDateTimeProvider.cs @@ -7,8 +7,8 @@ namespace KafkaFlow /// public interface IDateTimeProvider { - /// - DateTime Now { get; } + /// + DateTime UtcNow { get; } /// DateTime MinValue { get; } diff --git a/src/KafkaFlow.Abstractions/IMessageContext.cs b/src/KafkaFlow.Abstractions/IMessageContext.cs index da497840a..5661bb44b 100644 --- a/src/KafkaFlow.Abstractions/IMessageContext.cs +++ b/src/KafkaFlow.Abstractions/IMessageContext.cs @@ -33,6 +33,14 @@ public interface IMessageContext /// IDictionary Items { get; } + /// + /// Gets an instance of IDependencyResolver which provides methods to resolve dependencies. + /// This instance is tied to the message scope, meaning it is capable of resolving dependencies + /// that are scoped to the lifecycle of a single processed message. + /// + IDependencyResolver DependencyResolver { get; } + + /// /// Creates a new with the new message /// diff --git a/src/KafkaFlow.Abstractions/IProducerContext.cs b/src/KafkaFlow.Abstractions/IProducerContext.cs index 886e856e4..1f63af400 100644 --- a/src/KafkaFlow.Abstractions/IProducerContext.cs +++ b/src/KafkaFlow.Abstractions/IProducerContext.cs @@ -1,23 +1,29 @@ -namespace KafkaFlow +namespace KafkaFlow; + +/// +/// Some producer metadata +/// +public interface IProducerContext { /// - /// Some producer metadata + /// Gets the topic associated with the message + /// + string Topic { get; } + + /// + /// Gets the partition associated with the message /// - public interface IProducerContext - { - /// - /// Gets the topic associated with the message - /// - string Topic { get; } + int? Partition { get; } - /// - /// Gets the partition associated with the message - /// - int? Partition { get; } + /// + /// Gets the partition offset associated with the message + /// + long? Offset { get; } - /// - /// Gets the partition offset associated with the message - /// - long? Offset { get; } - } + /// + /// Gets an instance of IDependencyResolver which provides methods to resolve dependencies. + /// This instance is tied to the producer scope, meaning it is capable of resolving dependencies + /// that are scoped to the lifecycle of a single producer. + /// + IDependencyResolver DependencyResolver { get; } } diff --git a/src/KafkaFlow.Abstractions/MiddlewareLifetime.cs b/src/KafkaFlow.Abstractions/MiddlewareLifetime.cs index 4a17301ff..e17fa8de3 100644 --- a/src/KafkaFlow.Abstractions/MiddlewareLifetime.cs +++ b/src/KafkaFlow.Abstractions/MiddlewareLifetime.cs @@ -1,33 +1,46 @@ namespace KafkaFlow { + using System; + /// /// Specifies the lifetime of a middleware /// public enum MiddlewareLifetime { /// - /// Specifies that a single instance of the class will be created for the entire application + /// Denotes a single instance of the middleware to be maintained throughout the application's lifecycle. + /// This instance will not be disposed until the application is shut down. /// Singleton, /// - /// Specifies that a new instance of the class will be created for each scope + /// Obsolete. Please use Message instead. Indicates a new middleware instance is instantiated for each message scope. + /// This instance will be disposed when the message scope ends. /// + [Obsolete("Use Message lifetime instead")] Scoped, /// - /// Specifies that a new instance of the class will be created every time it is requested + /// Indicates a new middleware instance is instantiated for each individual message scope, ensuring isolated processing. + /// This instance will be disposed when the message scope ends. + /// + Message, + + /// + /// Signifies a new middleware instance is created every time a request is made, providing the highest level of isolation. + /// This instance will be disposed as soon as it goes out of scope. /// Transient, /// - /// Specifies that a new instance of the class will be created for each Consumer/Producer + /// Specifies a separate middleware instance for each Consumer/Producer, useful for maintaining context within the Consumer/Producer scope. + /// This instance will be disposed when the Consumer/Producer it belongs to is disposed. /// ConsumerOrProducer, /// - /// Specifies that a new instance of the class will be created for each Consumer Worker - /// For producers this setting will behave as + /// Specifies a unique middleware instance for each Consumer Worker. For Producers, this behaves as ConsumerOrProducer. This allows context preservation at a worker level. + /// This instance will be disposed when the Worker it belongs to is disposed. /// Worker, } diff --git a/src/KafkaFlow.Admin.Dashboard/ClientApp/dist/index.html b/src/KafkaFlow.Admin.Dashboard/ClientApp/dist/index.html index 71b0381c3..3d6e39aba 100644 --- a/src/KafkaFlow.Admin.Dashboard/ClientApp/dist/index.html +++ b/src/KafkaFlow.Admin.Dashboard/ClientApp/dist/index.html @@ -1,6 +1,4 @@ - - - + KafkaFlow - Dashboard @@ -9,8 +7,9 @@ - + - - + + + \ No newline at end of file diff --git a/src/KafkaFlow.Admin.Dashboard/ClientApp/dist/main.js b/src/KafkaFlow.Admin.Dashboard/ClientApp/dist/main.js index 4d471d3b3..5516a1654 100644 --- a/src/KafkaFlow.Admin.Dashboard/ClientApp/dist/main.js +++ b/src/KafkaFlow.Admin.Dashboard/ClientApp/dist/main.js @@ -1,2031 +1 @@ -(self.webpackChunkdashboard=self.webpackChunkdashboard||[]).push([[179],{381:(gr,th,iu)=>{"use strict";function ye(e){return"function"==typeof e}function V(e){const t=e(i=>{Error.call(i),i.stack=(new Error).stack});return t.prototype=Object.create(Error.prototype),t.prototype.constructor=t,t}const qa=V(e=>function(t){e(this),this.message=t?`${t.length} errors occurred during unsubscription:\n${t.map((i,r)=>`${r+1}) ${i.toString()}`).join("\n ")}`:"",this.name="UnsubscriptionError",this.errors=t});function dn(e,n){if(e){const t=e.indexOf(n);0<=t&&e.splice(t,1)}}class Ct{constructor(n){this.initialTeardown=n,this.closed=!1,this._parentage=null,this._finalizers=null}unsubscribe(){let n;if(!this.closed){this.closed=!0;const{_parentage:t}=this;if(t)if(this._parentage=null,Array.isArray(t))for(const o of t)o.remove(this);else t.remove(this);const{initialTeardown:i}=this;if(ye(i))try{i()}catch(o){n=o instanceof qa?o.errors:[o]}const{_finalizers:r}=this;if(r){this._finalizers=null;for(const o of r)try{qt(o)}catch(s){n=n??[],s instanceof qa?n=[...n,...s.errors]:n.push(s)}}if(n)throw new qa(n)}}add(n){var t;if(n&&n!==this)if(this.closed)qt(n);else{if(n instanceof Ct){if(n.closed||n._hasParent(this))return;n._addParent(this)}(this._finalizers=null!==(t=this._finalizers)&&void 0!==t?t:[]).push(n)}}_hasParent(n){const{_parentage:t}=this;return t===n||Array.isArray(t)&&t.includes(n)}_addParent(n){const{_parentage:t}=this;this._parentage=Array.isArray(t)?(t.push(n),t):t?[t,n]:n}_removeParent(n){const{_parentage:t}=this;t===n?this._parentage=null:Array.isArray(t)&&dn(t,n)}remove(n){const{_finalizers:t}=this;t&&dn(t,n),n instanceof Ct&&n._removeParent(this)}}Ct.EMPTY=(()=>{const e=new Ct;return e.closed=!0,e})();const we=Ct.EMPTY;function bs(e){return e instanceof Ct||e&&"closed"in e&&ye(e.remove)&&ye(e.add)&&ye(e.unsubscribe)}function qt(e){ye(e)?e():e.unsubscribe()}const Zt={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1},Ji={setTimeout(e,n,...t){const{delegate:i}=Ji;return i?.setTimeout?i.setTimeout(e,n,...t):setTimeout(e,n,...t)},clearTimeout(e){const{delegate:n}=Ji;return(n?.clearTimeout||clearTimeout)(e)},delegate:void 0};function Za(e){Ji.setTimeout(()=>{const{onUnhandledError:n}=Zt;if(!n)throw e;n(e)})}function Dn(){}const ii=No("C",void 0,void 0);function No(e,n,t){return{kind:e,value:n,error:t}}let Ci=null;function mr(e){if(Zt.useDeprecatedSynchronousErrorHandling){const n=!Ci;if(n&&(Ci={errorThrown:!1,error:null}),e(),n){const{errorThrown:t,error:i}=Ci;if(Ci=null,t)throw i}}else e()}class Eo extends Ct{constructor(n){super(),this.isStopped=!1,n?(this.destination=n,bs(n)&&n.add(this)):this.destination=ri}static create(n,t,i){return new vr(n,t,i)}next(n){this.isStopped?Ds(function le(e){return No("N",e,void 0)}(n),this):this._next(n)}error(n){this.isStopped?Ds(function nh(e){return No("E",void 0,e)}(n),this):(this.isStopped=!0,this._error(n))}complete(){this.isStopped?Ds(ii,this):(this.isStopped=!0,this._complete())}unsubscribe(){this.closed||(this.isStopped=!0,super.unsubscribe(),this.destination=null)}_next(n){this.destination.next(n)}_error(n){try{this.destination.error(n)}finally{this.unsubscribe()}}_complete(){try{this.destination.complete()}finally{this.unsubscribe()}}}const Ja=Function.prototype.bind;function _r(e,n){return Ja.call(e,n)}class Wn{constructor(n){this.partialObserver=n}next(n){const{partialObserver:t}=this;if(t.next)try{t.next(n)}catch(i){Jt(i)}}error(n){const{partialObserver:t}=this;if(t.error)try{t.error(n)}catch(i){Jt(i)}else Jt(n)}complete(){const{partialObserver:n}=this;if(n.complete)try{n.complete()}catch(t){Jt(t)}}}class vr extends Eo{constructor(n,t,i){let r;if(super(),ye(n)||!n)r={next:n??void 0,error:t??void 0,complete:i??void 0};else{let o;this&&Zt.useDeprecatedNextContext?(o=Object.create(n),o.unsubscribe=()=>this.unsubscribe(),r={next:n.next&&_r(n.next,o),error:n.error&&_r(n.error,o),complete:n.complete&&_r(n.complete,o)}):r=n}this.destination=new Wn(r)}}function Jt(e){Zt.useDeprecatedSynchronousErrorHandling?function ru(e){Zt.useDeprecatedSynchronousErrorHandling&&Ci&&(Ci.errorThrown=!0,Ci.error=e)}(e):Za(e)}function Ds(e,n){const{onStoppedNotification:t}=Zt;t&&Ji.setTimeout(()=>t(e,n))}const ri={closed:!0,next:Dn,error:function ou(e){throw e},complete:Dn},Qa="function"==typeof Symbol&&Symbol.observable||"@@observable";function Rn(e){return e}function Cs(e){return 0===e.length?Rn:1===e.length?e[0]:function(t){return e.reduce((i,r)=>r(i),t)}}let je=(()=>{class e{constructor(t){t&&(this._subscribe=t)}lift(t){const i=new e;return i.source=this,i.operator=t,i}subscribe(t,i,r){const o=function el(e){return e&&e instanceof Eo||function oi(e){return e&&ye(e.next)&&ye(e.error)&&ye(e.complete)}(e)&&bs(e)}(t)?t:new vr(t,i,r);return mr(()=>{const{operator:s,source:a}=this;o.add(s?s.call(o,a):a?this._subscribe(o):this._trySubscribe(o))}),o}_trySubscribe(t){try{return this._subscribe(t)}catch(i){t.error(i)}}forEach(t,i){return new(i=su(i))((r,o)=>{const s=new vr({next:a=>{try{t(a)}catch(l){o(l),s.unsubscribe()}},error:o,complete:r});this.subscribe(s)})}_subscribe(t){var i;return null===(i=this.source)||void 0===i?void 0:i.subscribe(t)}[Qa](){return this}pipe(...t){return Cs(t)(this)}toPromise(t){return new(t=su(t))((i,r)=>{let o;this.subscribe(s=>o=s,s=>r(s),()=>i(o))})}}return e.create=n=>new e(n),e})();function su(e){var n;return null!==(n=e??Zt.Promise)&&void 0!==n?n:Promise}const ws=V(e=>function(){e(this),this.name="ObjectUnsubscribedError",this.message="object unsubscribed"});let Ue=(()=>{class e extends je{constructor(){super(),this.closed=!1,this.currentObservers=null,this.observers=[],this.isStopped=!1,this.hasError=!1,this.thrownError=null}lift(t){const i=new yr(this,this);return i.operator=t,i}_throwIfClosed(){if(this.closed)throw new ws}next(t){mr(()=>{if(this._throwIfClosed(),!this.isStopped){this.currentObservers||(this.currentObservers=Array.from(this.observers));for(const i of this.currentObservers)i.next(t)}})}error(t){mr(()=>{if(this._throwIfClosed(),!this.isStopped){this.hasError=this.isStopped=!0,this.thrownError=t;const{observers:i}=this;for(;i.length;)i.shift().error(t)}})}complete(){mr(()=>{if(this._throwIfClosed(),!this.isStopped){this.isStopped=!0;const{observers:t}=this;for(;t.length;)t.shift().complete()}})}unsubscribe(){this.isStopped=this.closed=!0,this.observers=this.currentObservers=null}get observed(){var t;return(null===(t=this.observers)||void 0===t?void 0:t.length)>0}_trySubscribe(t){return this._throwIfClosed(),super._trySubscribe(t)}_subscribe(t){return this._throwIfClosed(),this._checkFinalizedStatuses(t),this._innerSubscribe(t)}_innerSubscribe(t){const{hasError:i,isStopped:r,observers:o}=this;return i||r?we:(this.currentObservers=null,o.push(t),new Ct(()=>{this.currentObservers=null,dn(o,t)}))}_checkFinalizedStatuses(t){const{hasError:i,thrownError:r,isStopped:o}=this;i?t.error(r):o&&t.complete()}asObservable(){const t=new je;return t.source=this,t}}return e.create=(n,t)=>new yr(n,t),e})();class yr extends Ue{constructor(n,t){super(),this.destination=n,this.source=t}next(n){var t,i;null===(i=null===(t=this.destination)||void 0===t?void 0:t.next)||void 0===i||i.call(t,n)}error(n){var t,i;null===(i=null===(t=this.destination)||void 0===t?void 0:t.error)||void 0===i||i.call(t,n)}complete(){var n,t;null===(t=null===(n=this.destination)||void 0===n?void 0:n.complete)||void 0===t||t.call(n)}_subscribe(n){var t,i;return null!==(i=null===(t=this.source)||void 0===t?void 0:t.subscribe(n))&&void 0!==i?i:we}}function Y(e){return ye(e?.lift)}function qe(e){return n=>{if(Y(n))return n.lift(function(t){try{return e(t,this)}catch(i){this.error(i)}});throw new TypeError("Unable to lift unknown Observable type")}}function Oe(e,n,t,i,r){return new Ss(e,n,t,i,r)}class Ss extends Eo{constructor(n,t,i,r,o,s){super(n),this.onFinalize=o,this.shouldUnsubscribe=s,this._next=t?function(a){try{t(a)}catch(l){n.error(l)}}:super._next,this._error=r?function(a){try{r(a)}catch(l){n.error(l)}finally{this.unsubscribe()}}:super._error,this._complete=i?function(){try{i()}catch(a){n.error(a)}finally{this.unsubscribe()}}:super._complete}unsubscribe(){var n;if(!this.shouldUnsubscribe||this.shouldUnsubscribe()){const{closed:t}=this;super.unsubscribe(),!t&&(null===(n=this.onFinalize)||void 0===n||n.call(this))}}}function ne(e,n){return qe((t,i)=>{let r=0;t.subscribe(Oe(i,o=>{i.next(e.call(n,o,r++))}))})}function br(e){return this instanceof br?(this.v=e,this):new br(e)}function Ns(e,n,t){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var r,i=t.apply(e,n||[]),o=[];return r={},s("next"),s("throw"),s("return"),r[Symbol.asyncIterator]=function(){return this},r;function s(m){i[m]&&(r[m]=function(v){return new Promise(function(y,D){o.push([m,v,y,D])>1||a(m,v)})})}function a(m,v){try{!function l(m){m.value instanceof br?Promise.resolve(m.value.v).then(u,f):p(o[0][2],m)}(i[m](v))}catch(y){p(o[0][3],y)}}function u(m){a("next",m)}function f(m){a("throw",m)}function p(m,v){m(v),o.shift(),o.length&&a(o[0][0],o[0][1])}}function he(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t,n=e[Symbol.asyncIterator];return n?n.call(e):(e=function xt(e){var n="function"==typeof Symbol&&Symbol.iterator,t=n&&e[n],i=0;if(t)return t.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&i>=e.length&&(e=void 0),{value:e&&e[i++],done:!e}}};throw new TypeError(n?"Object is not iterable.":"Symbol.iterator is not defined.")}(e),t={},i("next"),i("throw"),i("return"),t[Symbol.asyncIterator]=function(){return this},t);function i(o){t[o]=e[o]&&function(s){return new Promise(function(a,l){!function r(o,s,a,l){Promise.resolve(l).then(function(u){o({value:u,done:a})},s)}(a,l,(s=e[o](s)).done,s.value)})}}}const Ts=e=>e&&"number"==typeof e.length&&"function"!=typeof e;function Is(e){return ye(e?.then)}function Io(e){return ye(e[Qa])}function Ge(e){return Symbol.asyncIterator&&ye(e?.[Symbol.asyncIterator])}function nl(e){return new TypeError(`You provided ${null!==e&&"object"==typeof e?"an invalid object":`'${e}'`} where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.`)}const Ao=function uu(){return"function"==typeof Symbol&&Symbol.iterator?Symbol.iterator:"@@iterator"}();function As(e){return ye(e?.[Ao])}function ko(e){return Ns(this,arguments,function*(){const t=e.getReader();try{for(;;){const{value:i,done:r}=yield br(t.read());if(r)return yield br(void 0);yield yield br(i)}}finally{t.releaseLock()}})}function Dr(e){return ye(e?.getReader)}function ut(e){if(e instanceof je)return e;if(null!=e){if(Io(e))return function ah(e){return new je(n=>{const t=e[Qa]();if(ye(t.subscribe))return t.subscribe(n);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}(e);if(Ts(e))return function ks(e){return new je(n=>{for(let t=0;t{e.then(t=>{n.closed||(n.next(t),n.complete())},t=>n.error(t)).then(null,Za)})}(e);if(Ge(e))return xo(e);if(As(e))return function Oo(e){return new je(n=>{for(const t of e)if(n.next(t),n.closed)return;n.complete()})}(e);if(Dr(e))return function $(e){return xo(ko(e))}(e)}throw nl(e)}function xo(e){return new je(n=>{(function ch(e,n){var t,i,r,o;return function ih(e,n,t,i){return new(t||(t=Promise))(function(o,s){function a(f){try{u(i.next(f))}catch(p){s(p)}}function l(f){try{u(i.throw(f))}catch(p){s(p)}}function u(f){f.done?o(f.value):function r(o){return o instanceof t?o:new t(function(s){s(o)})}(f.value).then(a,l)}u((i=i.apply(e,n||[])).next())})}(this,void 0,void 0,function*(){try{for(t=he(e);!(i=yield t.next()).done;)if(n.next(i.value),n.closed)return}catch(s){r={error:s}}finally{try{i&&!i.done&&(o=t.return)&&(yield o.call(t))}finally{if(r)throw r.error}}n.complete()})})(e,n).catch(t=>n.error(t))})}function wi(e,n,t,i=0,r=!1){const o=n.schedule(function(){t(),r?e.add(this.schedule(null,i)):this.unsubscribe()},i);if(e.add(o),!r)return o}function dt(e,n,t=1/0){return ye(n)?dt((i,r)=>ne((o,s)=>n(i,o,r,s))(ut(e(i,r))),t):("number"==typeof n&&(t=n),qe((i,r)=>function Cn(e,n,t,i,r,o,s,a){const l=[];let u=0,f=0,p=!1;const m=()=>{p&&!l.length&&!u&&n.complete()},v=D=>u{o&&n.next(D),u++;let w=!1;ut(t(D,f++)).subscribe(Oe(n,N=>{r?.(N),o?v(N):n.next(N)},()=>{w=!0},void 0,()=>{if(w)try{for(u--;l.length&&uy(N)):y(N)}m()}catch(N){n.error(N)}}))};return e.subscribe(Oe(n,v,()=>{p=!0,m()})),()=>{a?.()}}(i,r,e,t)))}function Se(e=1/0){return dt(Rn,e)}const Xt=new je(e=>e.complete());function si(e){return e&&ye(e.schedule)}function Ln(e){return e[e.length-1]}function rt(e){return ye(Ln(e))?e.pop():void 0}function en(e){return si(Ln(e))?e.pop():void 0}function Qi(e,n=0){return qe((t,i)=>{t.subscribe(Oe(i,r=>wi(i,e,()=>i.next(r),n),()=>wi(i,e,()=>i.complete(),n),r=>wi(i,e,()=>i.error(r),n)))})}function du(e,n=0){return qe((t,i)=>{i.add(e.schedule(()=>t.subscribe(i),n))})}function fu(e,n){if(!e)throw new Error("Iterable cannot be null");return new je(t=>{wi(t,n,()=>{const i=e[Symbol.asyncIterator]();wi(t,n,()=>{i.next().then(r=>{r.done?t.complete():t.next(r.value)})},0,!0)})})}function gt(e,n){return n?function pu(e,n){if(null!=e){if(Io(e))return function uh(e,n){return ut(e).pipe(du(n),Qi(n))}(e,n);if(Ts(e))return function ft(e,n){return new je(t=>{let i=0;return n.schedule(function(){i===e.length?t.complete():(t.next(e[i++]),t.closed||this.schedule())})})}(e,n);if(Is(e))return function dh(e,n){return ut(e).pipe(du(n),Qi(n))}(e,n);if(Ge(e))return fu(e,n);if(As(e))return function Os(e,n){return new je(t=>{let i;return wi(t,n,()=>{i=e[Ao](),wi(t,n,()=>{let r,o;try{({value:r,done:o}=i.next())}catch(s){return void t.error(s)}o?t.complete():t.next(r)},0,!0)}),()=>ye(i?.return)&&i.return()})}(e,n);if(Dr(e))return function hu(e,n){return fu(ko(e),n)}(e,n)}throw nl(e)}(e,n):ut(e)}function il(e,n,...t){if(!0===n)return void e();if(!1===n)return;const i=new vr({next:()=>{i.unsubscribe(),e()}});return n(...t).subscribe(i)} -/** - * @license Angular v14.2.9 - * (c) 2010-2022 Google LLC. https://angular.io/ - * License: MIT - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */function $e(e){for(let n in e)if(e[n]===$e)return n;throw Error("Could not find renamed property on target object.")}function rl(e,n){for(const t in n)n.hasOwnProperty(t)&&!e.hasOwnProperty(t)&&(e[t]=n[t])} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */function Ve(e){if("string"==typeof e)return e;if(Array.isArray(e))return"["+e.map(Ve).join(", ")+"]";if(null==e)return""+e;if(e.overriddenName)return`${e.overriddenName}`;if(e.name)return`${e.name}`;const n=e.toString();if(null==n)return""+n;const t=n.indexOf("\n");return-1===t?n:n.substring(0,t)}function xs(e,n){return null==e||""===e?null===n?"":n:null==n||""===n?e:e+" "+n} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */const ph=$e({__forward_ref__:$e});function Te(e){return e.__forward_ref__=Te,e.toString=function(){return Ve(this())},e}function te(e){return Rs(e)?e():e}function Rs(e){return"function"==typeof e&&e.hasOwnProperty(ph)&&e.__forward_ref__===Te} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -class F extends Error{constructor(n,t){super(function Fs(e,n){return`NG0${Math.abs(e)}${n?": "+n.trim():""}`} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */(n,t)),this.code=n}}function oe(e){return"string"==typeof e?e:null==e?"":String(e)}function Vn(e,n){throw new F(-201,!1)} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */function Sn(e,n){null==e&&function ke(e,n,t,i){throw new Error(`ASSERTION ERROR: ${e}`+(null==i?"":` [Expected=> ${t} ${i} ${n} <=Actual]`))}(n,e,null,"!=")} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -function G(e){return{token:e.token,providedIn:e.providedIn||null,factory:e.factory,value:void 0}}function Ne(e){return{providers:e.providers||[],imports:e.imports||[]}}function Vs(e){return mu(e,Zr)||mu(e,sl)}function mu(e,n){return e.hasOwnProperty(n)?e[n]:null}function Bs(e){return e&&(e.hasOwnProperty(ol)||e.hasOwnProperty(_u))?e[ol]:null}const Zr=$e({\u0275prov:$e}),ol=$e({\u0275inj:$e}),sl=$e({ngInjectableDef:$e}),_u=$e({ngInjectorDef:$e}); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */var X=(()=>((X=X||{})[X.Default=0]="Default",X[X.Host=1]="Host",X[X.Self=2]="Self",X[X.SkipSelf=4]="SkipSelf",X[X.Optional=8]="Optional",X))(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */let al;function Bn(e){const n=al;return al=e,n}function ll(e,n,t){const i=Vs(e);return i&&"root"==i.providedIn?void 0===i.value?i.value=i.factory():i.value:t&X.Optional?null:void 0!==n?n:void Vn(Ve(e))} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -function Hn(e){return{toString:e}.toString()} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */var tn=(()=>((tn=tn||{})[tn.OnPush=0]="OnPush",tn[tn.Default=1]="Default",tn))(),ai=(()=>{return(e=ai||(ai={}))[e.Emulated=0]="Emulated",e[e.None=2]="None",e[e.ShadowDom=3]="ShadowDom",ai;var e})(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -const We=(()=>typeof globalThis<"u"&&globalThis||typeof global<"u"&&global||typeof window<"u"&&window||typeof self<"u"&&typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope&&self)(),Xi={},Ie=[],jn=$e({\u0275cmp:$e}),ul=$e({\u0275dir:$e}),Po=$e({\u0275pipe:$e}),vu=$e({\u0275mod:$e}),Ni=$e({\u0275fac:$e}),Fo=$e({__NG_ELEMENT_ID__:$e}); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -let Hs=0;function et(e){return Hn(()=>{const t=!0===e.standalone,i={},r={type:e.type,providersResolver:null,decls:e.decls,vars:e.vars,factory:null,template:e.template||null,consts:e.consts||null,ngContentSelectors:e.ngContentSelectors,hostBindings:e.hostBindings||null,hostVars:e.hostVars||0,hostAttrs:e.hostAttrs||null,contentQueries:e.contentQueries||null,declaredInputs:i,inputs:null,outputs:null,exportAs:e.exportAs||null,onPush:e.changeDetection===tn.OnPush,directiveDefs:null,pipeDefs:null,standalone:t,dependencies:t&&e.dependencies||null,getStandaloneInjector:null,selectors:e.selectors||Ie,viewQuery:e.viewQuery||null,features:e.features||null,data:e.data||{},encapsulation:e.encapsulation||ai.Emulated,id:"c"+Hs++,styles:e.styles||Ie,_:null,setInput:null,schemas:e.schemas||null,tView:null},o=e.dependencies,s=e.features;return r.inputs=Du(e.inputs,i),r.outputs=Du(e.outputs),s&&s.forEach(a=>a(r)),r.directiveDefs=o?()=>("function"==typeof o?o():o).map(yu).filter(bu):null,r.pipeDefs=o?()=>("function"==typeof o?o():o).map(nn).filter(bu):null,r})}function yu(e){return xe(e)||Ut(e)}function bu(e){return null!==e}function Ee(e){return Hn(()=>({type:e.type,bootstrap:e.bootstrap||Ie,declarations:e.declarations||Ie,imports:e.imports||Ie,exports:e.exports||Ie,transitiveCompileScopes:null,schemas:e.schemas||null,id:e.id||null}))}function Du(e,n){if(null==e)return Xi;const t={};for(const i in e)if(e.hasOwnProperty(i)){let r=e[i],o=r;Array.isArray(r)&&(o=r[1],r=r[0]),t[r]=i,n&&(n[r]=o)}return t}const B=et;function $t(e){return{type:e.type,name:e.name,factory:null,pure:!1!==e.pure,standalone:!0===e.standalone,onDestroy:e.type.prototype.ngOnDestroy||null}}function xe(e){return e[jn]||null}function Ut(e){return e[ul]||null}function nn(e){return e[Po]||null}function Mn(e,n){const t=e[vu]||null;if(!t&&!0===n)throw new Error(`Type ${Ve(e)} does not have '\u0275mod' property.`);return t} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -function hn(e){return Array.isArray(e)&&"object"==typeof e[1]}function qn(e){return Array.isArray(e)&&!0===e[1]}function pl(e){return 0!=(8&e.flags)}function $s(e){return 2==(2&e.flags)}function Us(e){return 1==(1&e.flags)}function Zn(e){return null!==e.template}function Ih(e){return 0!=(256&e[2])} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -function Er(e,n){return e.hasOwnProperty(Ni)?e[Ni]:null} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */class Ph{constructor(n,t,i){this.previousValue=n,this.currentValue=t,this.firstChange=i}isFirstChange(){return this.firstChange}} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */function zt(){return Su}function Su(e){return e.type.prototype.ngOnChanges&&(e.setInput=Gs),Fh}function Fh(){const e=Nu(this),n=e?.current;if(n){const t=e.previous;if(t===Xi)e.previous=n;else for(let i in n)t[i]=n[i];e.current=null,this.ngOnChanges(n)}}function Gs(e,n,t,i){const r=Nu(e)||function Lh(e,n){return e[Mu]=n} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */(e,{previous:Xi,current:null}),o=r.current||(r.current={}),s=r.previous,a=this.declaredInputs[t],l=s[a];o[a]=new Ph(l&&l.currentValue,n,s===Xi),e[i]=n}zt.ngInherit=!0;const Mu="__ngSimpleChanges__";function Nu(e){return e[Mu]||null} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -function tt(e){for(;Array.isArray(e);)e=e[0];return e}function Bo(e,n){return tt(n[e])}function Rt(e,n){return tt(n[e.index])}function zs(e,n){return e.data[n]}function io(e,n){return e[n]}function En(e,n){const t=n[e];return hn(t)?t:t[0]}function Ys(e){return 64==(64&e[2])}function tr(e,n){return null==n?null:e[n]}function Iu(e){e[18]=0}function yl(e,n){e[5]+=n;let t=e,i=e[3];for(;null!==i&&(1===n&&1===t[5]||-1===n&&0===t[5]);)i[5]+=n,t=i,i=i[3] -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */}const re={lFrame:Fu(null),bindingsEnabled:!0};function ku(){return re.bindingsEnabled}function O(){return re.lFrame.lView}function be(){return re.lFrame.tView}function mt(e){return re.lFrame.contextLView=e,e[8]}function _t(e){return re.lFrame.contextLView=null,e}function wt(){let e=Ks();for(;null!==e&&64===e.type;)e=e.parent;return e}function Ks(){return re.lFrame.currentTNode}function ci(e,n){const t=re.lFrame;t.currentTNode=e,t.isParent=n}function bl(){return re.lFrame.isParent}function jo(){re.lFrame.isParent=!1}function rn(){const e=re.lFrame;let n=e.bindingRootIndex;return-1===n&&(n=e.bindingRootIndex=e.tView.bindingStartIndex),n}function Tr(){return re.lFrame.bindingIndex++}function Ai(e){const n=re.lFrame,t=n.bindingIndex;return n.bindingIndex=n.bindingIndex+e,t}function Zh(e,n){const t=re.lFrame;t.bindingIndex=t.bindingRootIndex=e,wl(n)}function wl(e){re.lFrame.currentDirectiveIndex=e}function Sl(){return re.lFrame.currentQueryIndex}function Ml(e){re.lFrame.currentQueryIndex=e}function Qh(e){const n=e[1];return 2===n.type?n.declTNode:1===n.type?e[6]:null}function Ru(e,n,t){if(t&X.SkipSelf){let r=n,o=e;for(;!(r=r.parent,null!==r||t&X.Host||(r=Qh(o),null===r||(o=o[15],10&r.type))););if(null===r)return!1;n=r,e=o}const i=re.lFrame=Pu();return i.currentTNode=n,i.lView=e,!0}function R(e){const n=Pu(),t=e[1];re.lFrame=n,n.currentTNode=t.firstChild,n.lView=e,n.tView=t,n.contextLView=e,n.bindingIndex=t.bindingStartIndex,n.inI18n=!1}function Pu(){const e=re.lFrame,n=null===e?null:e.child;return null===n?Fu(e):n}function Fu(e){const n={currentTNode:null,isParent:!0,lView:null,tView:null,selectedIndex:-1,contextLView:null,elementDepthCount:0,currentNamespace:null,currentDirectiveIndex:-1,bindingRootIndex:-1,bindingIndex:-1,currentQueryIndex:0,parent:e,child:null,inI18n:!1};return null!==e&&(e.child=n),n}function Nl(){const e=re.lFrame;return re.lFrame=e.parent,e.currentTNode=null,e.lView=null,e}const Me=Nl;function ro(){const e=Nl();e.isParent=!0,e.tView=null,e.selectedIndex=-1,e.contextLView=null,e.elementDepthCount=0,e.currentDirectiveIndex=-1,e.currentNamespace=null,e.bindingRootIndex=-1,e.bindingIndex=-1,e.currentQueryIndex=0}function on(){return re.lFrame.selectedIndex}function nr(e){re.lFrame.selectedIndex=e}function st(){const e=re.lFrame;return zs(e.tView,e.selectedIndex)}function qs(e,n){for(let t=n.directiveStart,i=n.directiveEnd;t=i)break}else n[l]<0&&(e[18]+=65536),(a>11>16&&(3&e[2])===n){e[2]+=2048;try{o.call(a)}finally{}}}else try{o.call(a)}finally{}} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */class Tn{constructor(n,t,i){this.factory=n,this.resolving=!1,this.canSeeViewProviders=t,this.injectImpl=i}}function Xs(e,n,t){let i=0;for(;in){s=o-1;break}}}for(;o>16}(e),i=n;for(;t>0;)i=i[15],t--;return i} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */let Il=!0;function ea(e){const n=Il;return Il=e,n}let cp=0;const hi={};function Go(e,n){const t=Wo(e,n);if(-1!==t)return t;const i=n[1];i.firstCreatePass&&(e.injectorIndex=n.length,Al(i.data,e),Al(n,null),Al(i.blueprint,null));const r=Oi(e,n),o=e.injectorIndex;if($u(r)){const s=oo(r),a=so(r,n),l=a[1].data;for(let u=0;u<8;u++)n[o+u]=a[s+u]|l[s+u]}return n[o+8]=r,o}function Al(e,n){e.push(0,0,0,0,0,0,0,0,n)}function Wo(e,n){return-1===e.injectorIndex||e.parent&&e.parent.injectorIndex===e.injectorIndex||null===n[e.injectorIndex+8]?-1:e.injectorIndex}function Oi(e,n){if(e.parent&&-1!==e.parent.injectorIndex)return e.parent.injectorIndex;let t=0,i=null,r=n;for(;null!==r;){if(i=dy(r),null===i)return-1;if(t++,r=r[15],-1!==i.injectorIndex)return i.injectorIndex|t<<16}return-1}function Ar(e,n,t){!function up(e,n,t){let i;"string"==typeof t?i=t.charCodeAt(0)||0:t.hasOwnProperty(Fo)&&(i=t[Fo]),null==i&&(i=t[Fo]=cp++);const r=255&i;n.data[e+(r>>5)]|=1<=0?255&n:xi:n}(t);if("function"==typeof o){if(!Ru(n,e,i))return i&X.Host?c(r,0,i):d(n,t,i,r);try{const s=o(i);if(null!=s||i&X.Optional)return s;Vn()}finally{Me()}}else if("number"==typeof o){let s=null,a=Wo(e,n),l=-1,u=i&X.Host?n[16][6]:null;for((-1===a||i&X.SkipSelf)&&(l=-1===a?Oi(e,n):n[a+8],-1!==l&&Fe(i,!1)?(s=n[1],a=oo(l),n=so(l,n)):a=-1);-1!==a;){const f=n[1];if(ce(o,a,f.data)){const p=_(a,n,t,s,i,u);if(p!==hi)return p}l=n[a+8],-1!==l&&Fe(i,n[1].data[a+8]===u)&&ce(o,a,n)?(s=f,a=oo(l),n=so(l,n)):a=-1}}return r}function _(e,n,t,i,r,o){const s=n[1],a=s.data[e+8],f=b(a,s,t,null==i?$s(a)&&Il:i!=s&&0!=(3&a.type),r&X.Host&&o===a);return null!==f?E(n,s,f,a):hi}function b(e,n,t,i,r){const o=e.providerIndexes,s=n.data,a=1048575&o,l=e.directiveStart,f=o>>20,m=r?a+f:e.directiveEnd;for(let v=i?a:a+f;v=l&&y.type===t)return v}if(r){const v=s[l];if(v&&Zn(v)&&v.type===t)return l}return null}function E(e,n,t,i){let r=e[t];const o=n.data;if(function rp(e){return e instanceof Tn}(r)){const s=r;s.resolving&& -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -function Ls(e,n){const t=n?`. Dependency path: ${n.join(" > ")} > ${e}`:"";throw new F(-200,`Circular dependency in DI detected for ${e}${t}`)}(function _e(e){return"function"==typeof e?e.name||e.toString():"object"==typeof e&&null!=e&&"function"==typeof e.type?e.type.name||e.type.toString():oe(e)}(o[t]));const a=ea(s.canSeeViewProviders);s.resolving=!0;const l=s.injectImpl?Bn(s.injectImpl):null;Ru(e,i,X.Default);try{r=e[t]=s.factory(void 0,o,e,i),n.firstCreatePass&&t>=i.directiveStart&& -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -function np(e,n,t){const{ngOnChanges:i,ngOnInit:r,ngDoCheck:o}=n.type.prototype;if(i){const s=Su(n);(t.preOrderHooks||(t.preOrderHooks=[])).push(e,s),(t.preOrderCheckHooks||(t.preOrderCheckHooks=[])).push(e,s)}r&&(t.preOrderHooks||(t.preOrderHooks=[])).push(0-e,r),o&&((t.preOrderHooks||(t.preOrderHooks=[])).push(e,o),(t.preOrderCheckHooks||(t.preOrderCheckHooks=[])).push(e,o))}(t,o[t],n)}finally{null!==l&&Bn(l),ea(a),s.resolving=!1,Me()}}return r}function ce(e,n,t){return!!(t[n+(e>>5)]&1<{const n=e.prototype.constructor,t=n[Ni]||dp(n),i=Object.prototype;let r=Object.getPrototypeOf(e.prototype).constructor;for(;r&&r!==i;){const o=r[Ni]||dp(r);if(o&&o!==t)return o;r=Object.getPrototypeOf(r)}return o=>new o})}function dp(e){return Rs(e)?()=>{const n=dp(te(e));return n&&n()}:Er(e)}function dy(e){const n=e[1],t=n.type;return 2===t?n.declTNode:1===t?e[6]:null} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -const na="__parameters__";function ra(e,n,t){return Hn(()=>{const i=function fp(e){return function(...t){if(e){const i=e(...t);for(const r in i)this[r]=i[r]}}}(n);function r(...o){if(this instanceof r)return i.apply(this,o),this;const s=new r(...o);return a.annotation=s,a;function a(l,u,f){const p=l.hasOwnProperty(na)?l[na]:Object.defineProperty(l,na,{value:[]})[na];for(;p.length<=f;)p.push(null);return(p[f]=p[f]||[]).push(s),l}}return t&&(r.prototype=Object.create(t.prototype)),r.prototype.ngMetadataName=e,r.annotationCls=r,r})} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -class q{constructor(n,t){this._desc=n,this.ngMetadataName="InjectionToken",this.\u0275prov=void 0,"number"==typeof t?this.__NG_ELEMENT_ID__=t:void 0!==t&&(this.\u0275prov=G({token:this,providedIn:t.providedIn||"root",factory:t.factory}))}get multi(){return this}toString(){return`InjectionToken ${this._desc}`}} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */function Jn(e,n){void 0===n&&(n=e);for(let t=0;tArray.isArray(t)?kr(t,n):n(t))}function hy(e,n,t){n>=e.length?e.push(t):e.splice(n,0,t)}function Uu(e,n){return n>=e.length-1?e.pop():e.splice(n,1)[0]}function xl(e,n){const t=[];for(let i=0;i=0?e[1|i]=t:(i=~i,function CE(e,n,t,i){let r=e.length;if(r==n)e.push(t,i);else if(1===r)e.push(i,e[0]),e[0]=t;else{for(r--,e.push(e[r-1],e[r]);r>n;)e[r]=e[r-2],r--;e[n]=t,e[n+1]=i}}(e,i,n,t)),i}function pp(e,n){const t=oa(e,n);if(t>=0)return e[1|t]}function oa(e,n){return function my(e,n,t){let i=0,r=e.length>>t;for(;r!==i;){const o=i+(r-i>>1),s=e[o<n?r=o:i=o+1}return~(r<{const s=o;Tp(s,t,[],i)&&(r||(r=[]),r.push(s))}),void 0!==r&&$y(r,t),t}function $y(e,n){for(let t=0;t{n.push(o)})}}function Tp(e,n,t,i){if(!(e=te(e)))return!1;let r=null,o=Bs(e);const s=!o&&xe(e);if(o||s){if(s&&!s.standalone)return!1;r=e}else{const l=e.ngModule;if(o=Bs(l),!o)return!1;r=l}const a=i.has(r);if(s){if(a)return!1;if(i.add(r),s.dependencies){const l="function"==typeof s.dependencies?s.dependencies():s.dependencies;for(const u of l)Tp(u,n,t,i)}}else{if(!o)return!1;{if(null!=o.imports&&!a){let u;i.add(r);try{kr(o.imports,f=>{Tp(f,n,t,i)&&(u||(u=[]),u.push(f))})}finally{}void 0!==u&&$y(u,n)}if(!a){const u=Er(r)||(()=>new r);n.push({provide:r,useFactory:u,deps:Ie},{provide:By,useValue:r,multi:!0},{provide:Ep,useValue:()=>L(r),multi:!0})}const l=o.providers;null==l||a||kr(l,f=>{n.push(f)})}}return r!==e&&void 0!==e.providers}const vT=$e({provide:String,useValue:$e});function Ip(e){return null!==e&&"object"==typeof e&&vT in e}function Yo(e){return"function"==typeof e} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -const Ap=new q("Set Injector scope."),Ju={},bT={}; -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */let kp;function Qu(){return void 0===kp&&(kp=new Hy),kp}class lo{}class Wy extends lo{constructor(n,t,i,r){super(),this.parent=t,this.source=i,this.scopes=r,this.records=new Map,this._ngOnDestroyHooks=new Set,this._onDestroyHooks=[],this._destroyed=!1,xp(n,s=>this.processProvider(s)),this.records.set(Vy,ca(void 0,this)),r.has("environment")&&this.records.set(lo,ca(void 0,this));const o=this.records.get(Ap);null!=o&&"string"==typeof o.value&&this.scopes.add(o.value),this.injectorDefTypes=new Set(this.get(By.multi,Ie,X.Self))}get destroyed(){return this._destroyed}destroy(){this.assertNotDestroyed(),this._destroyed=!0;try{for(const n of this._ngOnDestroyHooks)n.ngOnDestroy();for(const n of this._onDestroyHooks)n()}finally{this.records.clear(),this._ngOnDestroyHooks.clear(),this.injectorDefTypes.clear(),this._onDestroyHooks.length=0}}onDestroy(n){this._onDestroyHooks.push(n)}runInContext(n){this.assertNotDestroyed();const t=sa(this),i=Bn(void 0);try{return n()}finally{sa(t),Bn(i)}}get(n,t=Rl,i=X.Default){this.assertNotDestroyed();const r=sa(this),o=Bn(void 0);try{if(!(i&X.SkipSelf)){let a=this.records.get(n);if(void 0===a){const l=function MT(e){return"function"==typeof e||"object"==typeof e&&e instanceof q}(n)&&Vs(n);a=l&&this.injectableDefInScope(l)?ca(Op(n),Ju):null,this.records.set(n,a)}if(null!=a)return this.hydrate(n,a)}return(i&X.Self?Qu():this.parent).get(n,t=i&X.Optional&&t===Rl?null:t)}catch(s){if("NullInjectorError"===s.name){if((s[Wu]=s[Wu]||[]).unshift(Ve(n)),r)throw s;return function RE(e,n,t,i){const r=e[Wu];throw n[_y]&&r.unshift(n[_y]),e.message=function PE(e,n,t,i=null){e=e&&"\n"===e.charAt(0)&&"\u0275"==e.charAt(1)?e.slice(2):e;let r=Ve(n);if(Array.isArray(n))r=n.map(Ve).join(" -> ");else if("object"==typeof n){let o=[];for(let s in n)if(n.hasOwnProperty(s)){let a=n[s];o.push(s+":"+("string"==typeof a?JSON.stringify(a):Ve(a)))}r=`{${o.join(", ")}}`}return`${t}${i?"("+i+")":""}[${r}]: ${e.replace(AE,"\n ")}`}("\n"+e.message,r,t,i),e.ngTokenPath=r,e[Wu]=null,e}(s,n,"R3InjectorError",this.source)}throw s}finally{Bn(o),sa(r)}}resolveInjectorInitializers(){const n=sa(this),t=Bn(void 0);try{const i=this.get(Ep.multi,Ie,X.Self);for(const r of i)r()}finally{sa(n),Bn(t)}}toString(){const n=[],t=this.records;for(const i of t.keys())n.push(Ve(i));return`R3Injector[${n.join(", ")}]`}assertNotDestroyed(){if(this._destroyed)throw new F(205,!1)}processProvider(n){let t=Yo(n=te(n))?n:te(n&&n.provide);const i=function CT(e){return Ip(e)?ca(void 0,e.useValue):ca(zy(e),Ju)}(n);if(Yo(n)||!0!==n.multi)this.records.get(t);else{let r=this.records.get(t);r||(r=ca(void 0,Ju,!0),r.factory=()=>_p(r.multi),this.records.set(t,r)),t=n,r.multi.push(n)}this.records.set(t,i)}hydrate(n,t){return t.value===Ju&&(t.value=bT,t.value=t.factory()),"object"==typeof t.value&&t.value&&function ST(e){return null!==e&&"object"==typeof e&&"function"==typeof e.ngOnDestroy}(t.value)&&this._ngOnDestroyHooks.add(t.value),t.value}injectableDefInScope(n){if(!n.providedIn)return!1;const t=te(n.providedIn);return"string"==typeof t?"any"===t||this.scopes.has(t):this.injectorDefTypes.has(t)}}function Op(e){const n=Vs(e),t=null!==n?n.factory:Er(e);if(null!==t)return t;if(e instanceof q)throw new F(204,!1);if(e instanceof Function)return function DT(e){const n=e.length;if(n>0)throw xl(n,"?"),new F(204,!1);const t=function Dh(e){const n=e&&(e[Zr]||e[sl]);if(n){const t=function Ch(e){if(e.hasOwnProperty("name"))return e.name;const n=(""+e).match(/^function\s*([^\s(]+)/);return null===n?"":n[1]}(e);return console.warn(`DEPRECATED: DI is instantiating a token "${t}" that inherits its @Injectable decorator but does not provide one itself.\nThis will become an error in a future version of Angular. Please add @Injectable() to the "${t}" class.`),n}return null}(e);return null!==t?()=>t.factory(e):()=>new e}(e);throw new F(204,!1)}function zy(e,n,t){let i;if(Yo(e)){const r=te(e);return Er(r)||Op(r)}if(Ip(e))i=()=>te(e.useValue);else if(function Gy(e){return!(!e||!e.useFactory)}(e))i=()=>e.useFactory(..._p(e.deps||[]));else if(function Uy(e){return!(!e||!e.useExisting)}(e))i=()=>L(te(e.useExisting));else{const r=te(e&&(e.useClass||e.provide));if(!function wT(e){return!!e.deps}(e))return Er(r)||Op(r);i=()=>new r(..._p(e.deps))}return i}function ca(e,n,t=!1){return{factory:e,value:n,multi:t?[]:void 0}}function NT(e){return!!e.\u0275providers}function xp(e,n){for(const t of e)Array.isArray(t)?xp(t,n):NT(t)?xp(t.\u0275providers,n):n(t)} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */class Yy{} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */class IT{resolveComponentFactory(n){throw function TT(e){const n=Error(`No component factory found for ${Ve(e)}. Did you add it to @NgModule.entryComponents?`);return n.ngComponent=e,n}(n)}}let Gl=(()=>{class e{} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -return e.NULL=new IT,e})();function AT(){return ua(wt(),O())}function ua(e,n){return new Je(Rt(e,n))}let Je=(()=>{class e{constructor(t){this.nativeElement=t}}return e.__NG_ELEMENT_ID__=AT,e})();function kT(e){return e instanceof Je?e.nativeElement:e} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */class Rp{}let pi=(()=>{class e{}return e.__NG_ELEMENT_ID__=()=>function OT(){const e=O(),t=En(wt().index,e);return(hn(t)?t:e)[11]} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */(),e})(),xT=(()=>{class e{} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -return e.\u0275prov=G({token:e,providedIn:"root",factory:()=>null}),e})();class Wl{constructor(n){this.full=n,this.major=n.split(".")[0],this.minor=n.split(".")[1],this.patch=n.split(".").slice(2).join(".")}}const RT=new Wl("14.2.9"),Pp={}; -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */function Hp(e){return e.ngOriginalError} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */class da{constructor(){this._console=console}handleError(n){const t=this._findOriginalError(n);this._console.error("ERROR",n),t&&this._console.error("ORIGINAL ERROR",t)}_findOriginalError(n){let t=n&&Hp(n);for(;t&&Hp(t);)t=Hp(t);return t||null}} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -const jp=new Map;let zT=0;const Up="__ngContext__";function pn(e,n){hn(n)?(e[Up]=n[20],function KT(e){jp.set(e[20],e)}(n)):e[Up]=n}function xr(e){return e instanceof Function?e():e} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -var Un=(()=>((Un=Un||{})[Un.Important=1]="Important",Un[Un.DashCase=2]="DashCase",Un))(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */function Wp(e,n){return undefined(e,n)} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -function Yl(e){const n=e[3];return qn(n)?n[3]:n}function zp(e){return c0(e[13])}function Yp(e){return c0(e[4])}function c0(e){for(;null!==e&&!qn(e);)e=e[4];return e} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */function ha(e,n,t,i,r){if(null!=i){let o,s=!1;qn(i)?o=i:hn(i)&&(s=!0,i=i[0]);const a=tt(i);0===e&&null!==t?null==r?g0(n,t,a):Ko(n,t,a,r||null,!0):1===e&&null!==t?Ko(n,t,a,r||null,!0):2===e?function C0(e,n,t){const i=Xu(e,n);i&&function DI(e,n,t,i){e.removeChild(n,t,i)}(e,i,n,t)}(n,a,s):3===e&&n.destroyNode(a),null!=o&&function SI(e,n,t,i,r){const o=t[7];o!==tt(t)&&ha(n,e,i,o,r);for(let a=10;a0&&(e[t-1][4]=i[4]);const o=Uu(e,10+n);!function hI(e,n){Kl(e,n,n[11],2,null,null),n[0]=null,n[6]=null}(i[1],i);const s=o[19];null!==s&&s.detachView(o[1]),i[3]=null,i[4]=null,i[2]&=-65}return i}function f0(e,n){if(!(128&n[2])){const t=n[11];t.destroyNode&&Kl(e,n,t,3,null,null),function mI(e){let n=e[13];if(!n)return Jp(e[1],e);for(;n;){let t=null;if(hn(n))t=n[13];else{const i=n[10];i&&(t=i)}if(!t){for(;n&&!n[4]&&n!==e;)hn(n)&&Jp(n[1],n),n=n[3];null===n&&(n=e),hn(n)&&Jp(n[1],n),t=n&&n[4]}n=t}}(n)}}function Jp(e,n){if(!(128&n[2])){n[2]&=-65,n[2]|=128,function bI(e,n){let t;if(null!=e&&null!=(t=e.destroyHooks))for(let i=0;i=0?i[r=u]():i[r=-u].unsubscribe(),o+=2}else{const s=i[r=t[o+1]];t[o].call(s)}if(null!==i){for(let o=r+1;oo?"":r[p+1].toLowerCase();const v=8&i?m:null;if(v&&-1!==M0(v,u,0)||2&i&&u!==m){if(Ri(i))return!1;s=!0}}}}else{if(!s&&!Ri(i)&&!Ri(l))return!1;if(s&&Ri(l))continue;s=!1,i=l|1&i}}return Ri(i)||s}function Ri(e){return 0==(1&e)}function II(e,n,t,i){if(null===n)return-1;let r=0;if(i||!t){let o=!1;for(;r-1)for(t++;t0?'="'+a+'"':"")+"]"}else 8&i?r+="."+s:4&i&&(r+=" "+s);else""!==r&&!Ri(s)&&(n+=I0(o,r),r=""),i=s,o=o||!Ri(i);t++}return""!==r&&(n+=I0(o,r)),n} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -const ae={}; -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */function P(e){A0(be(),O(),on()+e,!1)}function A0(e,n,t,i){if(!i)if(3==(3&n[2])){const o=e.preOrderCheckHooks;null!==o&&$o(n,o,t)}else{const o=e.preOrderHooks;null!==o&&Zs(n,o,0,t)}nr(t)} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -function R0(e,n=null,t=null,i){const r=P0(e,n,t,i);return r.resolveInjectorInitializers(),r}function P0(e,n=null,t=null,i,r=new Set){const o=[t||Ie,_T(e)];return i=i||("object"==typeof e?void 0:Ve(e)),new Wy(o,n||Qu(),i||null,r) -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */}let gn=(()=>{class e{static create(t,i){if(Array.isArray(t))return R0({name:""},i,t,"");{const r=t.name??"";return R0({name:r},t.parent,t.providers,r)}}} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -return e.THROW_IF_NOT_FOUND=Rl,e.NULL=new Hy,e.\u0275prov=G({token:e,providedIn:"any",factory:()=>L(Vy)}),e.__NG_ELEMENT_ID__=-1,e})(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -function C(e,n=X.Default){const t=O();return null===t?L(e,n):h(wt(),t,te(e),n)}function sg(){throw new Error("invalid")} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -function id(e,n){return e<<17|n<<2}function Pi(e){return e>>17&32767}function ag(e){return 2|e}function Rr(e){return(131068&e)>>2}function lg(e,n){return-131069&e|n<<2}function cg(e){return 1|e}function Q0(e,n){const t=e.contentQueries;if(null!==t)for(let i=0;i22&&A0(e,n,22,!1),t(i,r)}finally{nr(o)}}function yg(e,n,t){!ku()||(function DA(e,n,t,i){const r=t.directiveStart,o=t.directiveEnd;e.firstCreatePass||Go(t,n),pn(i,n);const s=t.initialInputs;for(let a=r;a0;){const t=e[--n];if("number"==typeof t&&t<0)return t}return 0})(a)!=l&&a.push(l),a.push(i,r,s)}}function ab(e,n){null!==e.hostBindings&&e.hostBindings(1,n)}function lb(e,n){n.flags|=2,(e.components||(e.components=[])).push(n.index)}function MA(e,n,t){if(t){if(n.exportAs)for(let i=0;i0&&Sg(t)}}function Sg(e){for(let i=zp(e);null!==i;i=Yp(i))for(let r=10;r0&&Sg(o)}const t=e[1].components;if(null!==t)for(let i=0;i0&&Sg(r)}}function OA(e,n){const t=En(n,e),i=t[1];(function xA(e,n){for(let t=n.length;t-1&&(Zp(n,i),Uu(t,i))}this._attachedToViewContainer=!1}f0(this._lView[1],this._lView)}onDestroy(n){nb(this._lView[1],this._lView,null,n)}markForCheck(){Mg(this._cdRefInjectingView||this._lView)}detach(){this._lView[2]&=-65}reattach(){this._lView[2]|=64}detectChanges(){cd(this._lView[1],this._lView,this.context)}checkNoChanges(){}attachToViewContainerRef(){if(this._appRef)throw new F(902,!1);this._attachedToViewContainer=!0}detachFromAppRef(){this._appRef=null,function gI(e,n){Kl(e,n,n[11],2,null,null)}(this._lView[1],this._lView)}attachToAppRef(n){if(this._attachedToViewContainer)throw new F(902,!1);this._appRef=n}}class RA extends ql{constructor(n){super(n),this._view=n}detectChanges(){const n=this._view;cd(n[1],n,n[8],!1)}checkNoChanges(){}get context(){return null}} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */class Tg extends Gl{constructor(n){super(),this.ngModule=n}resolveComponentFactory(n){const t=xe(n);return new Zl(t,this.ngModule)}}function mb(e){const n=[];for(let t in e)e.hasOwnProperty(t)&&n.push({propName:e[t],templateName:t});return n}class FA{constructor(n,t){this.injector=n,this.parentInjector=t}get(n,t,i){const r=this.injector.get(n,Pp,i);return r!==Pp||t===Pp?r:this.parentInjector.get(n,t,i)}}class Zl extends Yy{constructor(n,t){super(),this.componentDef=n,this.ngModule=t,this.componentType=n.type,this.selector=function PI(e){return e.map(RI).join(",")}(n.selectors),this.ngContentSelectors=n.ngContentSelectors?n.ngContentSelectors:[],this.isBoundToModule=!!t}get inputs(){return mb(this.componentDef.inputs)}get outputs(){return mb(this.componentDef.outputs)}create(n,t,i,r){let o=(r=r||this.ngModule)instanceof lo?r:r?.injector;o&&null!==this.componentDef.getStandaloneInjector&&(o=this.componentDef.getStandaloneInjector(o)||o);const s=o?new FA(n,o):n,a=s.get(Rp,null);if(null===a)throw new F(407,!1);const l=s.get(xT,null),u=a.createRenderer(null,this.componentDef),f=this.componentDef.selectors[0][0]||"div",p=i?function gA(e,n,t){return e.selectRootElement(n,t===ai.ShadowDom)}(u,i,this.componentDef.encapsulation):qp(a.createRenderer(null,this.componentDef),f,function PA(e){const n=e.toLowerCase();return"svg"===n?"svg":"math"===n?"math":null}(f)),m=this.componentDef.onPush?288:272,v=Dg(0,null,null,1,0,null,null,null,null,null),y=sd(null,v,null,m,null,null,a,u,l,s,null);let D,w;R(y);try{const N=function BA(e,n,t,i,r,o){const s=t[1];t[22]=e;const l=ga(s,22,2,"#host",null),u=l.mergedAttrs=n.hostAttrs;null!==u&&(ud(l,u,!0),null!==e&&(Xs(r,e,u),null!==l.classes&&tg(r,e,l.classes),null!==l.styles&&S0(r,e,l.styles)));const f=i.createRenderer(e,n),p=sd(t,tb(n),null,n.onPush?32:16,t[22],l,i,f,o||null,null,null);return s.firstCreatePass&&(Ar(Go(l,t),s,n.type),lb(s,l),cb(l,t.length,1)),ld(t,p),t[22]=p}(p,this.componentDef,y,a,u);if(p)if(i)Xs(u,p,["ng-version",RT.full]);else{const{attrs:A,classes:S}=function FI(e){const n=[],t=[];let i=1,r=2;for(;i0&&tg(u,p,S.join(" "))}if(w=zs(v,22),void 0!==t){const A=w.projection=[];for(let S=0;S=0;i--){const r=e[i];r.hostVars=n+=r.hostVars,r.hostAttrs=di(r.hostAttrs,t=di(t,r.hostAttrs))}}(i)}function Ig(e){return e===Xi?{}:e===Ie?[]:e}function UA(e,n){const t=e.viewQuery;e.viewQuery=t?(i,r)=>{n(i,r),t(i,r)}:n}function GA(e,n){const t=e.contentQueries;e.contentQueries=t?(i,r,o)=>{n(i,r,o),t(i,r,o)}:n}function WA(e,n){const t=e.hostBindings;e.hostBindings=t?(i,r)=>{n(i,r),t(i,r)}:n} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -let fd=null;function qo(){if(!fd){const e=We.Symbol;if(e&&e.iterator)fd=e.iterator;else{const n=Object.getOwnPropertyNames(Map.prototype);for(let t=0;ta(tt(x[i.index])):i.index;let k=null;if(!a&&l&&(k=function ik(e,n,t,i){const r=e.cleanup;if(null!=r)for(let o=0;ol?a[l]:null}"string"==typeof s&&(o+=2)}return null}(e,n,r,i.index)),null!==k)(k.__ngLastListenerFn__||k).__ngNextListenerFn__=o,k.__ngLastListenerFn__=o,v=!1;else{o=Ob(i,n,p,o,!1);const x=t.listen(N,r,o);m.push(o,x),f&&f.push(r,S,A,A+1)}}else o=Ob(i,n,p,o,!1);const y=i.outputs;let D;if(v&&null!==y&&(D=y[r])){const w=D.length;if(w)for(let N=0;N0;)n=n[15],e--;return n}(e,re.lFrame.contextLView))[8]}(e)} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */function rk(e,n){let t=null;const i=function AI(e){const n=e.attrs;if(null!=n){const t=n.indexOf(5);if(0==(1&t))return n[t+1]}return null}(e);for(let r=0;r=0} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */const Ft={textEnd:0,key:0,keyEnd:0,value:0,valueEnd:0};function $b(e){return e.substring(Ft.key,Ft.keyEnd)}function Ub(e,n){const t=Ft.textEnd;return t===n?-1:(n=Ft.keyEnd=function dk(e,n,t){for(;n32;)n++;return n}(e,Ft.key=n,t),Na(e,n,t))}function Na(e,n,t){for(;n=0;t=Ub(n,t))Qn(e,$b(n),!0)}function Kb(e,n){return n>=e.expandoStartIndex}function qb(e,n,t,i){const r=e.data;if(null===r[t+1]){const o=r[on()],s=Kb(e,t);Xb(o,i)&&null===n&&!s&&(n=!1),n=function gk(e,n,t,i){const r=function ui(e){const n=re.lFrame.currentDirectiveIndex;return-1===n?null:e[n]}(e);let o=i?n.residualClasses:n.residualStyles;if(null===r)0===(i?n.classBindings:n.styleBindings)&&(t=ec(t=Bg(null,e,n,t,i),n.attrs,i),o=null);else{const s=n.directiveStylingLast;if(-1===s||e[s]!==r)if(t=Bg(r,e,n,t,i),null===o){let l=function mk(e,n,t){const i=t?n.classBindings:n.styleBindings;if(0!==Rr(i))return e[Pi(i)]}(e,n,i);void 0!==l&&Array.isArray(l)&&(l=Bg(null,e,n,l[1],i),l=ec(l,n.attrs,i),function _k(e,n,t,i){e[Pi(t?n.classBindings:n.styleBindings)]=i}(e,n,i,l))}else o=function vk(e,n,t){let i;const r=n.directiveEnd;for(let o=1+n.directiveStylingLast;o0)&&(u=!0)}else f=t;if(r)if(0!==l){const m=Pi(e[a+1]);e[i+1]=id(m,a),0!==m&&(e[m+1]=lg(e[m+1],i)),e[a+1]=function tA(e,n){return 131071&e|n<<17}(e[a+1],i)}else e[i+1]=id(a,0),0!==a&&(e[a+1]=lg(e[a+1],i)),a=i;else e[i+1]=id(l,0),0===a?a=i:e[l+1]=lg(e[l+1],i),l=i;u&&(e[i+1]=ag(e[i+1])),jb(e,f,i,!0),jb(e,f,i,!1),function sk(e,n,t,i,r){const o=r?e.residualClasses:e.residualStyles;null!=o&&"string"==typeof n&&oa(o,n)>=0&&(t[i+1]=cg(t[i+1]))}(n,f,e,i,o),s=id(a,l),o?n.classBindings=s:n.styleBindings=s}(r,o,n,t,s,i)}}function Bg(e,n,t,i,r){let o=null;const s=t.directiveEnd;let a=t.directiveStylingLast;for(-1===a?a=t.directiveStart:a++;a0;){const l=e[r],u=Array.isArray(l),f=u?l[1]:l,p=null===f;let m=t[r+1];m===ae&&(m=p?Ie:void 0);let v=p?pp(m,i):f===i?m:void 0;if(u&&!gd(v)&&(v=pp(l,i)),gd(v)&&(a=v,s))return a;const y=e[r+1];r=s?Pi(y):Rr(y)}if(null!==n){let l=o?n.residualClasses:n.residualStyles;null!=l&&(a=pp(l,i))}return a}function gd(e){return void 0!==e}function Xb(e,n){return 0!=(e.flags&(n?16:32))} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */function I(e,n=""){const t=O(),i=be(),r=e+22,o=i.firstCreatePass?ga(i,r,1,n,null):i.data[r],s=t[r]=function Kp(e,n){return e.createText(n)}(t[11],n);ed(i,t,s,o),ci(o,!1)} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */function fo(e){return He("",e,""),fo}function He(e,n,t){const i=O(),r=function va(e,n,t,i){return mn(e,Tr(),t)?n+oe(t)+i:ae}(i,e,n,t);return r!==ae&&function Pr(e,n,t){const i=Bo(n,e);!function u0(e,n,t){e.setValue(n,t)}(e[11],i,t)}(i,on(),r),He} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -const Qo=void 0;var jk=["en",[["a","p"],["AM","PM"],Qo],[["AM","PM"],Qo,Qo],[["S","M","T","W","T","F","S"],["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],["Su","Mo","Tu","We","Th","Fr","Sa"]],Qo,[["J","F","M","A","M","J","J","A","S","O","N","D"],["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],["January","February","March","April","May","June","July","August","September","October","November","December"]],Qo,[["B","A"],["BC","AD"],["Before Christ","Anno Domini"]],0,[6,0],["M/d/yy","MMM d, y","MMMM d, y","EEEE, MMMM d, y"],["h:mm a","h:mm:ss a","h:mm:ss a z","h:mm:ss a zzzz"],["{1}, {0}",Qo,"{1} 'at' {0}",Qo],[".",",",";","%","+","-","E","\xd7","\u2030","\u221e","NaN",":"],["#,##0.###","#,##0%","\xa4#,##0.00","#E0"],"USD","$","US Dollar",{},"ltr",function Hk(e){const t=Math.floor(Math.abs(e)),i=e.toString().replace(/^[^.]*\.?/,"").length;return 1===t&&0===i?1:5}]; -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */let Ta={};function An(e){const n=function $k(e){return e.toLowerCase().replace(/_/g,"-")} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */(e);let t=yD(n);if(t)return t;const i=n.split("-")[0];if(t=yD(i),t)return t;if("en"===i)return jk;throw new F(701,!1)}function yD(e){return e in Ta||(Ta[e]=We.ng&&We.ng.common&&We.ng.common.locales&&We.ng.common.locales[e]),Ta[e]}var j=(()=>((j=j||{})[j.LocaleId=0]="LocaleId",j[j.DayPeriodsFormat=1]="DayPeriodsFormat",j[j.DayPeriodsStandalone=2]="DayPeriodsStandalone",j[j.DaysFormat=3]="DaysFormat",j[j.DaysStandalone=4]="DaysStandalone",j[j.MonthsFormat=5]="MonthsFormat",j[j.MonthsStandalone=6]="MonthsStandalone",j[j.Eras=7]="Eras",j[j.FirstDayOfWeek=8]="FirstDayOfWeek",j[j.WeekendRange=9]="WeekendRange",j[j.DateFormat=10]="DateFormat",j[j.TimeFormat=11]="TimeFormat",j[j.DateTimeFormat=12]="DateTimeFormat",j[j.NumberSymbols=13]="NumberSymbols",j[j.NumberFormats=14]="NumberFormats",j[j.CurrencyCode=15]="CurrencyCode",j[j.CurrencySymbol=16]="CurrencySymbol",j[j.CurrencyName=17]="CurrencyName",j[j.Currencies=18]="Currencies",j[j.Directionality=19]="Directionality",j[j.PluralCase=20]="PluralCase",j[j.ExtraData=21]="ExtraData",j))();const Ia="en-US"; -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -let bD=Ia;function Ug(e,n,t,i,r){if(e=te(e),Array.isArray(e))for(let o=0;o>20;if(Yo(e)||!e.multi){const v=new Tn(l,r,C),y=Wg(a,n,r?f:f+m,p);-1===y?(Ar(Go(u,s),o,a),Gg(o,e,n.length),n.push(a),u.directiveStart++,u.directiveEnd++,r&&(u.providerIndexes+=1048576),t.push(v),s.push(v)):(t[y]=v,s[y]=v)}else{const v=Wg(a,n,f+m,p),y=Wg(a,n,f,f+m),D=v>=0&&t[v],w=y>=0&&t[y];if(r&&!w||!r&&!D){Ar(Go(u,s),o,a);const N=function LO(e,n,t,i,r){const o=new Tn(e,t,C);return o.multi=[],o.index=n,o.componentProviders=0,WD(o,r,i&&!t),o}(r?FO:PO,t.length,r,i,l);!r&&w&&(t[y].providerFactory=N),Gg(o,e,n.length,0),n.push(a),u.directiveStart++,u.directiveEnd++,r&&(u.providerIndexes+=1048576),t.push(N),s.push(N)}else Gg(o,e,v>-1?v:y,WD(t[r?y:v],l,!r&&i));!r&&i&&w&&t[y].componentProviders++}}}function Gg(e,n,t,i){const r=Yo(n),o=function yT(e){return!!e.useClass}(n);if(r||o){const l=(o?te(n.useClass):n).prototype.ngOnDestroy;if(l){const u=e.destroyHooks||(e.destroyHooks=[]);if(!r&&n.multi){const f=u.indexOf(t);-1===f?u.push(t,[i,l]):u[f+1].push(i,l)}else u.push(t,l)}}}function WD(e,n,t){return t&&e.componentProviders++,e.multi.push(n)-1}function Wg(e,n,t,i){for(let r=t;r{t.providersResolver=(i,r)=> -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -function RO(e,n,t){const i=be();if(i.firstCreatePass){const r=Zn(e);Ug(t,i.data,i.blueprint,r,!0),Ug(n,i.data,i.blueprint,r,!1)}}(i,r?r(e):e,n)}} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */class Xo{}class zD{} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */class YD extends Xo{constructor(n,t){super(),this._parent=t,this._bootstrapComponents=[],this.destroyCbs=[],this.componentFactoryResolver=new Tg(this);const i=Mn(n);this._bootstrapComponents=xr(i.bootstrap),this._r3Injector=P0(n,t,[{provide:Xo,useValue:this},{provide:Gl,useValue:this.componentFactoryResolver}],Ve(n),new Set(["environment"])),this._r3Injector.resolveInjectorInitializers(),this.instance=this._r3Injector.get(n)}get injector(){return this._r3Injector}destroy(){const n=this._r3Injector;!n.destroyed&&n.destroy(),this.destroyCbs.forEach(t=>t()),this.destroyCbs=null}onDestroy(n){this.destroyCbs.push(n)}}class Yg extends zD{constructor(n){super(),this.moduleType=n}create(n){return new YD(this.moduleType,n)}}class BO extends Xo{constructor(n,t,i){super(),this.componentFactoryResolver=new Tg(this),this.instance=null;const r=new Wy([...n,{provide:Xo,useValue:this},{provide:Gl,useValue:this.componentFactoryResolver}],t||Qu(),i,new Set(["environment"]));this.injector=r,r.resolveInjectorInitializers()}destroy(){this.injector.destroy()}onDestroy(n){this.injector.onDestroy(n)}}function bd(e,n,t=null){return new BO(e,n,t).injector} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */let HO=(()=>{class e{constructor(t){this._injector=t,this.cachedInjectors=new Map}getOrCreateStandaloneInjector(t){if(!t.standalone)return null;if(!this.cachedInjectors.has(t.id)){const i=jy(0,t.type),r=i.length>0?bd([i],this._injector,`Standalone[${t.type.name}]`):null;this.cachedInjectors.set(t.id,r)}return this.cachedInjectors.get(t.id)}ngOnDestroy(){try{for(const t of this.cachedInjectors.values())null!==t&&t.destroy()}finally{this.cachedInjectors.clear()}}}return e.\u0275prov=G({token:e,providedIn:"environment",factory:()=>new e(L(lo))}),e})();function KD(e){e.getStandaloneInjector=n=>n.get(HO).getOrCreateStandaloneInjector(e)} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */function Cd(e,n,t,i,r,o){return function r1(e,n,t,i,r,o,s,a){const l=n+t;return function hd(e,n,t,i,r){const o=Zo(e,n,t,i);return mn(e,n+2,r)||o}(e,l,r,o,s)?or(e,l+3,a?i.call(a,r,o,s):i(r,o,s)):ac(e,l+3)}(O(),rn(),e,n,t,i,r,o)}function ac(e,n){const t=e[n];return t===ae?void 0:t} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -function wd(e,n){const t=be();let i;const r=e+22;t.firstCreatePass?(i=function tx(e,n){if(n)for(let t=n.length-1;t>=0;t--){const i=n[t];if(e===i.name)return i}}(n,t.pipeRegistry),t.data[r]=i,i.onDestroy&&(t.destroyHooks||(t.destroyHooks=[])).push(r,i.onDestroy)):i=t.data[r];const o=i.factory||(i.factory=Er(i.type)),s=Bn(C);try{const a=ea(!1),l=o();return ea(a),function ek(e,n,t,i){t>=e.data.length&&(e.data[t]=null,e.blueprint[t]=null),n[t]=i}(t,O(),r,l),l}finally{Bn(s)}}function Sd(e,n,t,i){const r=e+22,o=O(),s=io(o,r);return function lc(e,n){return e[1].data[n].pure} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */(o,r)?function i1(e,n,t,i,r,o,s){const a=n+t;return Zo(e,a,r,o)?or(e,a+2,s?i.call(s,r,o):i(r,o)):ac(e,a+2)}(o,rn(),n,s.transform,t,i,s):s.transform(t,i)}function qg(e){return n=>{setTimeout(e,void 0,n)}}const ue=class sx extends Ue{constructor(n=!1){super(),this.__isAsync=n}emit(n){super.next(n)}subscribe(n,t,i){let r=n,o=t||(()=>null),s=i;if(n&&"object"==typeof n){const l=n;r=l.next?.bind(l),o=l.error?.bind(l),s=l.complete?.bind(l)}this.__isAsync&&(o=qg(o),r&&(r=qg(r)),s&&(s=qg(s)));const a=super.subscribe({next:r,error:o,complete:s});return n instanceof Ct&&n.add(a),a}}; -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */function ax(){return this._results[qo()]()}class Zg{constructor(n=!1){this._emitDistinctChangesOnly=n,this.dirty=!0,this._results=[],this._changesDetected=!1,this._changes=null,this.length=0,this.first=void 0,this.last=void 0;const t=qo(),i=Zg.prototype;i[t]||(i[t]=ax)}get changes(){return this._changes||(this._changes=new ue)}get(n){return this._results[n]}map(n){return this._results.map(n)}filter(n){return this._results.filter(n)}find(n){return this._results.find(n)}reduce(n,t){return this._results.reduce(n,t)}forEach(n){this._results.forEach(n)}some(n){return this._results.some(n)}toArray(){return this._results.slice()}toString(){return this._results.toString()}reset(n,t){const i=this;i.dirty=!1;const r=Jn(n);(this._changesDetected=!function bE(e,n,t){if(e.length!==n.length)return!1;for(let i=0;i{class e{}return e.__NG_ELEMENT_ID__=ux,e})();const lx=bt,cx=class extends lx{constructor(n,t,i){super(),this._declarationLView=n,this._declarationTContainer=t,this.elementRef=i}createEmbeddedView(n,t){const i=this._declarationTContainer.tViews,r=sd(this._declarationLView,i,n,16,null,i.declTNode,null,null,null,null,t||null);r[17]=this._declarationLView[this._declarationTContainer.index];const s=this._declarationLView[19];return null!==s&&(r[19]=s.createEmbeddedView(i)),vg(i,r,n),new ql(r)}};function ux(){return Md(wt(),O())}function Md(e,n){return 4&e.type?new cx(n,e,ua(e,n)):null} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */let Hi=(()=>{class e{}return e.__NG_ELEMENT_ID__=dx,e})();function dx(){return c1(wt(),O())}const fx=Hi,a1=class extends fx{constructor(n,t,i){super(),this._lContainer=n,this._hostTNode=t,this._hostLView=i}get element(){return ua(this._hostTNode,this._hostLView)}get injector(){return new vt(this._hostTNode,this._hostLView)}get parentInjector(){const n=Oi(this._hostTNode,this._hostLView);if($u(n)){const t=so(n,this._hostLView),i=oo(n);return new vt(t[1].data[i+8],t)}return new vt(null,this._hostLView)}clear(){for(;this.length>0;)this.remove(this.length-1)}get(n){const t=l1(this._lContainer);return null!==t&&t[n]||null}get length(){return this._lContainer.length-10}createEmbeddedView(n,t,i){let r,o;"number"==typeof i?r=i:null!=i&&(r=i.index,o=i.injector);const s=n.createEmbeddedView(t||{},o);return this.insert(s,r),s}createComponent(n,t,i,r,o){const s=n&&!function Ol(e){return"function"==typeof e} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */(n);let a;if(s)a=t;else{const p=t||{};a=p.index,i=p.injector,r=p.projectableNodes,o=p.environmentInjector||p.ngModuleRef}const l=s?n:new Zl(xe(n)),u=i||this.parentInjector;if(!o&&null==l.ngModule){const m=(s?u:this.parentInjector).get(lo,null);m&&(o=m)}const f=l.create(u,r,void 0,o);return this.insert(f.hostView,a),f}insert(n,t){const i=n._lView,r=i[1];if(function $h(e){return qn(e[3])}(i)){const f=this.indexOf(n);if(-1!==f)this.detach(f);else{const p=i[3],m=new a1(p,p[6],p[3]);m.detach(m.indexOf(n))}}const o=this._adjustIndex(t),s=this._lContainer;!function _I(e,n,t,i){const r=10+i,o=t.length;i>0&&(t[r-1][4]=n),i0)i.push(s[a/2]);else{const u=o[a+1],f=n[-l];for(let p=10;p{class e{constructor(t){this.appInits=t,this.resolve=Td,this.reject=Td,this.initialized=!1,this.done=!1,this.donePromise=new Promise((i,r)=>{this.resolve=i,this.reject=r})}runInitializers(){if(this.initialized)return;const t=[],i=()=>{this.done=!0,this.resolve()};if(this.appInits)for(let r=0;r{o.subscribe({complete:a,error:l})});t.push(s)}}Promise.all(t).then(()=>{i()}).catch(r=>{this.reject(r)}),0===t.length&&i(),this.initialized=!0}}return e.\u0275fac=function(t){return new(t||e)(L(Id,8))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */const uc=new q("AppId",{providedIn:"root",factory:function x1(){return`${am()}${am()}${am()}`}});function am(){return String.fromCharCode(97+Math.floor(25*Math.random()))}const R1=new q("Platform Initializer"),dc=new q("Platform ID",{providedIn:"platform",factory:()=>"unknown"}),P1=new q("appBootstrapListener"); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */let Hx=(()=>{class e{log(t){console.log(t)}warn(t){console.warn(t)}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"platform"}),e})(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */const Fr=new q("LocaleId",{providedIn:"root",factory:()=>St(Fr,X.Optional|X.SkipSelf)||function jx(){return typeof $localize<"u"&&$localize.locale||Ia}()}); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -class Ux{constructor(n,t){this.ngModuleFactory=n,this.componentFactories=t}}let lm=(()=>{class e{compileModuleSync(t){return new Yg(t)}compileModuleAsync(t){return Promise.resolve(this.compileModuleSync(t))}compileModuleAndAllComponentsSync(t){const i=this.compileModuleSync(t),o=xr(Mn(t).declarations).reduce((s,a)=>{const l=xe(a);return l&&s.push(new Zl(l)),s},[]);return new Ux(i,o)}compileModuleAndAllComponentsAsync(t){return Promise.resolve(this.compileModuleAndAllComponentsSync(t))}clearCache(){}clearCacheFor(t){}getModuleId(t){}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -const zx=(()=>Promise.resolve(0))();function cm(e){typeof Zone>"u"?zx.then(()=>{e&&e.apply(null,null)}):Zone.current.scheduleMicroTask("scheduleMicrotask",e)} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -class Ye{constructor({enableLongStackTrace:n=!1,shouldCoalesceEventChangeDetection:t=!1,shouldCoalesceRunChangeDetection:i=!1}){if(this.hasPendingMacrotasks=!1,this.hasPendingMicrotasks=!1,this.isStable=!0,this.onUnstable=new ue(!1),this.onMicrotaskEmpty=new ue(!1),this.onStable=new ue(!1),this.onError=new ue(!1),typeof Zone>"u")throw new F(908,!1);Zone.assertZonePatched();const r=this;if(r._nesting=0,r._outer=r._inner=Zone.current,Zone.AsyncStackTaggingZoneSpec){const o=Zone.AsyncStackTaggingZoneSpec;r._inner=r._inner.fork(new o("Angular"))}Zone.TaskTrackingZoneSpec&&(r._inner=r._inner.fork(new Zone.TaskTrackingZoneSpec)),n&&Zone.longStackTraceZoneSpec&&(r._inner=r._inner.fork(Zone.longStackTraceZoneSpec)),r.shouldCoalesceEventChangeDetection=!i&&t,r.shouldCoalesceRunChangeDetection=i,r.lastRequestAnimationFrameId=-1,r.nativeRequestAnimationFrame=function Yx(){let e=We.requestAnimationFrame,n=We.cancelAnimationFrame;if(typeof Zone<"u"&&e&&n){const t=e[Zone.__symbol__("OriginalDelegate")];t&&(e=t);const i=n[Zone.__symbol__("OriginalDelegate")];i&&(n=i)}return{nativeRequestAnimationFrame:e,nativeCancelAnimationFrame:n}}().nativeRequestAnimationFrame,function Zx(e){const n=()=>{!function qx(e){e.isCheckStableRunning||-1!==e.lastRequestAnimationFrameId||(e.lastRequestAnimationFrameId=e.nativeRequestAnimationFrame.call(We,()=>{e.fakeTopEventTask||(e.fakeTopEventTask=Zone.root.scheduleEventTask("fakeTopEventTask",()=>{e.lastRequestAnimationFrameId=-1,dm(e),e.isCheckStableRunning=!0,um(e),e.isCheckStableRunning=!1},void 0,()=>{},()=>{})),e.fakeTopEventTask.invoke()}),dm(e))}(e)};e._inner=e._inner.fork({name:"angular",properties:{isAngularZone:!0},onInvokeTask:(t,i,r,o,s,a)=>{try{return V1(e),t.invokeTask(r,o,s,a)}finally{(e.shouldCoalesceEventChangeDetection&&"eventTask"===o.type||e.shouldCoalesceRunChangeDetection)&&n(),B1(e)}},onInvoke:(t,i,r,o,s,a,l)=>{try{return V1(e),t.invoke(r,o,s,a,l)}finally{e.shouldCoalesceRunChangeDetection&&n(),B1(e)}},onHasTask:(t,i,r,o)=>{t.hasTask(r,o),i===r&&("microTask"==o.change?(e._hasPendingMicrotasks=o.microTask,dm(e),um(e)):"macroTask"==o.change&&(e.hasPendingMacrotasks=o.macroTask))},onHandleError:(t,i,r,o)=>(t.handleError(r,o),e.runOutsideAngular(()=>e.onError.emit(o)),!1)})}(r)}static isInAngularZone(){return typeof Zone<"u"&&!0===Zone.current.get("isAngularZone")}static assertInAngularZone(){if(!Ye.isInAngularZone())throw new F(909,!1)}static assertNotInAngularZone(){if(Ye.isInAngularZone())throw new F(909,!1)}run(n,t,i){return this._inner.run(n,t,i)}runTask(n,t,i,r){const o=this._inner,s=o.scheduleEventTask("NgZoneEvent: "+r,n,Kx,Td,Td);try{return o.runTask(s,t,i)}finally{o.cancelTask(s)}}runGuarded(n,t,i){return this._inner.runGuarded(n,t,i)}runOutsideAngular(n){return this._outer.run(n)}}const Kx={};function um(e){if(0==e._nesting&&!e.hasPendingMicrotasks&&!e.isStable)try{e._nesting++,e.onMicrotaskEmpty.emit(null)}finally{if(e._nesting--,!e.hasPendingMicrotasks)try{e.runOutsideAngular(()=>e.onStable.emit(null))}finally{e.isStable=!0}}}function dm(e){e.hasPendingMicrotasks=!!(e._hasPendingMicrotasks||(e.shouldCoalesceEventChangeDetection||e.shouldCoalesceRunChangeDetection)&&-1!==e.lastRequestAnimationFrameId)}function V1(e){e._nesting++,e.isStable&&(e.isStable=!1,e.onUnstable.emit(null))}function B1(e){e._nesting--,um(e)}class Jx{constructor(){this.hasPendingMicrotasks=!1,this.hasPendingMacrotasks=!1,this.isStable=!0,this.onUnstable=new ue,this.onMicrotaskEmpty=new ue,this.onStable=new ue,this.onError=new ue}run(n,t,i){return n.apply(t,i)}runGuarded(n,t,i){return n.apply(t,i)}runOutsideAngular(n){return n()}runTask(n,t,i,r){return n.apply(t,i)}} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */const H1=new q(""),kd=new q("");let pm,fm=(()=>{class e{constructor(t,i,r){this._ngZone=t,this.registry=i,this._pendingCount=0,this._isZoneStable=!0,this._didWork=!1,this._callbacks=[],this.taskTrackingZone=null,pm||(function Qx(e){pm=e}(r),r.addToWindow(i)),this._watchAngularEvents(),t.run(()=>{this.taskTrackingZone=typeof Zone>"u"?null:Zone.current.get("TaskTrackingZone")})}_watchAngularEvents(){this._ngZone.onUnstable.subscribe({next:()=>{this._didWork=!0,this._isZoneStable=!1}}),this._ngZone.runOutsideAngular(()=>{this._ngZone.onStable.subscribe({next:()=>{Ye.assertNotInAngularZone(),cm(()=>{this._isZoneStable=!0,this._runCallbacksIfReady()})}})})}increasePendingRequestCount(){return this._pendingCount+=1,this._didWork=!0,this._pendingCount}decreasePendingRequestCount(){if(this._pendingCount-=1,this._pendingCount<0)throw new Error("pending async requests below zero");return this._runCallbacksIfReady(),this._pendingCount}isStable(){return this._isZoneStable&&0===this._pendingCount&&!this._ngZone.hasPendingMacrotasks}_runCallbacksIfReady(){if(this.isStable())cm(()=>{for(;0!==this._callbacks.length;){let t=this._callbacks.pop();clearTimeout(t.timeoutId),t.doneCb(this._didWork)}this._didWork=!1});else{let t=this.getPendingTasks();this._callbacks=this._callbacks.filter(i=>!i.updateCb||!i.updateCb(t)||(clearTimeout(i.timeoutId),!1)),this._didWork=!0}}getPendingTasks(){return this.taskTrackingZone?this.taskTrackingZone.macroTasks.map(t=>({source:t.source,creationLocation:t.creationLocation,data:t.data})):[]}addCallback(t,i,r){let o=-1;i&&i>0&&(o=setTimeout(()=>{this._callbacks=this._callbacks.filter(s=>s.timeoutId!==o),t(this._didWork,this.getPendingTasks())},i)),this._callbacks.push({doneCb:t,timeoutId:o,updateCb:r})}whenStable(t,i,r){if(r&&!this.taskTrackingZone)throw new Error('Task tracking zone is required when passing an update callback to whenStable(). Is "zone.js/plugins/task-tracking" loaded?');this.addCallback(t,i,r),this._runCallbacksIfReady()}getPendingRequestCount(){return this._pendingCount}registerApplication(t){this.registry.registerApplication(t,this)}unregisterApplication(t){this.registry.unregisterApplication(t)}findProviders(t,i,r){return[]}}return e.\u0275fac=function(t){return new(t||e)(L(Ye),L(hm),L(kd))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(),hm=(()=>{class e{constructor(){this._applications=new Map}registerApplication(t,i){this._applications.set(t,i)}unregisterApplication(t){this._applications.delete(t)}unregisterAllApplications(){this._applications.clear()}getTestability(t){return this._applications.get(t)||null}getAllTestabilities(){return Array.from(this._applications.values())}getAllRootElements(){return Array.from(this._applications.keys())}findTestabilityInTree(t,i=!0){return pm?.findTestabilityInTree(this,t,i)??null}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"platform"}),e})(),po=null;const j1=new q("AllowMultipleToken"),gm=new q("PlatformDestroyListeners");class $1{constructor(n,t){this.name=n,this.token=t}}function G1(e,n,t=[]){const i=`Platform: ${n}`,r=new q(i);return(o=[])=>{let s=mm();if(!s||s.injector.get(j1,!1)){const a=[...t,...o,{provide:r,useValue:!0}];e?e(a):function tR(e){if(po&&!po.get(j1,!1))throw new F(400,!1);po=e;const n=e.get(z1);(function U1(e){const n=e.get(R1,null);n&&n.forEach(t=>t())})(e)}(function W1(e=[],n){return gn.create({name:n,providers:[{provide:Ap,useValue:"platform"},{provide:gm,useValue:new Set([()=>po=null])},...e]})}(a,i))}return function iR(e){const n=mm();if(!n)throw new F(401,!1);return n}()}}function mm(){return po?.get(z1)??null}let z1=(()=>{class e{constructor(t){this._injector=t,this._modules=[],this._destroyListeners=[],this._destroyed=!1}bootstrapModuleFactory(t,i){const r=function K1(e,n){let t;return t="noop"===e?new Jx:("zone.js"===e?void 0:e)||new Ye(n),t}(i?.ngZone,function Y1(e){return{enableLongStackTrace:!1,shouldCoalesceEventChangeDetection:!(!e||!e.ngZoneEventCoalescing)||!1,shouldCoalesceRunChangeDetection:!(!e||!e.ngZoneRunCoalescing)||!1}}(i)),o=[{provide:Ye,useValue:r}];return r.run(()=>{const s=gn.create({providers:o,parent:this.injector,name:t.moduleType.name}),a=t.create(s),l=a.injector.get(da,null);if(!l)throw new F(402,!1);return r.runOutsideAngular(()=>{const u=r.onError.subscribe({next:f=>{l.handleError(f)}});a.onDestroy(()=>{Od(this._modules,a),u.unsubscribe()})}),function q1(e,n,t){try{const i=t();return Xl(i)?i.catch(r=>{throw n.runOutsideAngular(()=>e.handleError(r)),r}):i}catch(i){throw n.runOutsideAngular(()=>e.handleError(i)),i}}(l,r,()=>{const u=a.injector.get(Ad);return u.runInitializers(),u.donePromise.then(()=>(function DD(e){Sn(e,"Expected localeId to be defined"),"string"==typeof e&&(bD=e.toLowerCase().replace(/_/g,"-"))}(a.injector.get(Fr,Ia)||Ia),this._moduleDoBootstrap(a),a))})})}bootstrapModule(t,i=[]){const r=Z1({},i);return function Xx(e,n,t){const i=new Yg(t);return Promise.resolve(i)}(0,0,t).then(o=>this.bootstrapModuleFactory(o,r))}_moduleDoBootstrap(t){const i=t.injector.get(fc);if(t._bootstrapComponents.length>0)t._bootstrapComponents.forEach(r=>i.bootstrap(r));else{if(!t.instance.ngDoBootstrap)throw new F(403,!1);t.instance.ngDoBootstrap(i)}this._modules.push(t)}onDestroy(t){this._destroyListeners.push(t)}get injector(){return this._injector}destroy(){if(this._destroyed)throw new F(404,!1);this._modules.slice().forEach(i=>i.destroy()),this._destroyListeners.forEach(i=>i());const t=this._injector.get(gm,null);t&&(t.forEach(i=>i()),t.clear()),this._destroyed=!0}get destroyed(){return this._destroyed}}return e.\u0275fac=function(t){return new(t||e)(L(gn))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"platform"}),e})();function Z1(e,n){return Array.isArray(n)?n.reduce(Z1,e):{...e,...n}}let fc=(()=>{class e{constructor(t,i,r){this._zone=t,this._injector=i,this._exceptionHandler=r,this._bootstrapListeners=[],this._views=[],this._runningTick=!1,this._stable=!0,this._destroyed=!1,this._destroyListeners=[],this.componentTypes=[],this.components=[],this._onMicrotaskEmptySubscription=this._zone.onMicrotaskEmpty.subscribe({next:()=>{this._zone.run(()=>{this.tick()})}});const o=new je(a=>{this._stable=this._zone.isStable&&!this._zone.hasPendingMacrotasks&&!this._zone.hasPendingMicrotasks,this._zone.runOutsideAngular(()=>{a.next(this._stable),a.complete()})}),s=new je(a=>{let l;this._zone.runOutsideAngular(()=>{l=this._zone.onStable.subscribe(()=>{Ye.assertNotInAngularZone(),cm(()=>{!this._stable&&!this._zone.hasPendingMacrotasks&&!this._zone.hasPendingMicrotasks&&(this._stable=!0,a.next(!0))})})});const u=this._zone.onUnstable.subscribe(()=>{Ye.assertInAngularZone(),this._stable&&(this._stable=!1,this._zone.runOutsideAngular(()=>{a.next(!1)}))});return()=>{l.unsubscribe(),u.unsubscribe()}});this.isStable=function fh(...e){const n=en(e),t=function Si(e,n){return"number"==typeof Ln(e)?e.pop():n}(e,1/0),i=e;return i.length?1===i.length?ut(i[0]):Se(t)(gt(i,n)):Xt}(o,s.pipe(function hh(e={}){const{connector:n=(()=>new Ue),resetOnError:t=!0,resetOnComplete:i=!0,resetOnRefCountZero:r=!0}=e;return o=>{let s,a,l,u=0,f=!1,p=!1;const m=()=>{a?.unsubscribe(),a=void 0},v=()=>{m(),s=l=void 0,f=p=!1},y=()=>{const D=s;v(),D?.unsubscribe()};return qe((D,w)=>{u++,!p&&!f&&m();const N=l=l??n();w.add(()=>{u--,0===u&&!p&&!f&&(a=il(y,r))}),N.subscribe(w),!s&&u>0&&(s=new vr({next:A=>N.next(A),error:A=>{p=!0,m(),a=il(v,t,A),N.error(A)},complete:()=>{f=!0,m(),a=il(v,i),N.complete()}}),ut(D).subscribe(s))})(o)}}()))}get destroyed(){return this._destroyed}get injector(){return this._injector}bootstrap(t,i){const r=t instanceof Yy;if(!this._injector.get(Ad).done)throw!r&&function Yn(e){const n=xe(e)||Ut(e)||nn(e);return null!==n&&n.standalone}(t),new F(405,false);let s;s=r?t:this._injector.get(Gl).resolveComponentFactory(t),this.componentTypes.push(s.componentType);const a=function eR(e){return e.isBoundToModule}(s)?void 0:this._injector.get(Xo),u=s.create(gn.NULL,[],i||s.selector,a),f=u.location.nativeElement,p=u.injector.get(H1,null);return p?.registerApplication(f),u.onDestroy(()=>{this.detachView(u.hostView),Od(this.components,u),p?.unregisterApplication(f)}),this._loadComponent(u),u}tick(){if(this._runningTick)throw new F(101,!1);try{this._runningTick=!0;for(let t of this._views)t.detectChanges()}catch(t){this._zone.runOutsideAngular(()=>this._exceptionHandler.handleError(t))}finally{this._runningTick=!1}}attachView(t){const i=t;this._views.push(i),i.attachToAppRef(this)}detachView(t){const i=t;Od(this._views,i),i.detachFromAppRef()}_loadComponent(t){this.attachView(t.hostView),this.tick(),this.components.push(t),this._injector.get(P1,[]).concat(this._bootstrapListeners).forEach(r=>r(t))}ngOnDestroy(){if(!this._destroyed)try{this._destroyListeners.forEach(t=>t()),this._views.slice().forEach(t=>t.destroy()),this._onMicrotaskEmptySubscription.unsubscribe()}finally{this._destroyed=!0,this._views=[],this._bootstrapListeners=[],this._destroyListeners=[]}}onDestroy(t){return this._destroyListeners.push(t),()=>Od(this._destroyListeners,t)}destroy(){if(this._destroyed)throw new F(406,!1);const t=this._injector;t.destroy&&!t.destroyed&&t.destroy()}get viewCount(){return this._views.length}warnIfDestroyed(){}}return e.\u0275fac=function(t){return new(t||e)(L(Ye),L(lo),L(da))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})();function Od(e,n){const t=e.indexOf(n);t>-1&&e.splice(t,1)} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -let Q1=!0,Vr=(()=>{class e{}return e.__NG_ELEMENT_ID__=sR,e})();function sR(e){return function aR(e,n,t){if($s(e)&&!t){const i=En(e.index,n);return new ql(i,i)}return 47&e.type?new ql(n[16],n):null} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */(wt(),O(),16==(16&e))} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -class iC{constructor(){}supports(n){return Jl(n)}create(n){return new hR(n)}}const fR=(e,n)=>n;class hR{constructor(n){this.length=0,this._linkedRecords=null,this._unlinkedRecords=null,this._previousItHead=null,this._itHead=null,this._itTail=null,this._additionsHead=null,this._additionsTail=null,this._movesHead=null,this._movesTail=null,this._removalsHead=null,this._removalsTail=null,this._identityChangesHead=null,this._identityChangesTail=null,this._trackByFn=n||fR}forEachItem(n){let t;for(t=this._itHead;null!==t;t=t._next)n(t)}forEachOperation(n){let t=this._itHead,i=this._removalsHead,r=0,o=null;for(;t||i;){const s=!i||t&&t.currentIndex{s=this._trackByFn(r,a),null!==t&&Object.is(t.trackById,s)?(i&&(t=this._verifyReinsertion(t,a,s,r)),Object.is(t.item,a)||this._addIdentityChange(t,a)):(t=this._mismatch(t,a,s,r),i=!0),t=t._next,r++}),this.length=r;return this._truncate(t),this.collection=n,this.isDirty}get isDirty(){return null!==this._additionsHead||null!==this._movesHead||null!==this._removalsHead||null!==this._identityChangesHead}_reset(){if(this.isDirty){let n;for(n=this._previousItHead=this._itHead;null!==n;n=n._next)n._nextPrevious=n._next;for(n=this._additionsHead;null!==n;n=n._nextAdded)n.previousIndex=n.currentIndex;for(this._additionsHead=this._additionsTail=null,n=this._movesHead;null!==n;n=n._nextMoved)n.previousIndex=n.currentIndex;this._movesHead=this._movesTail=null,this._removalsHead=this._removalsTail=null,this._identityChangesHead=this._identityChangesTail=null}}_mismatch(n,t,i,r){let o;return null===n?o=this._itTail:(o=n._prev,this._remove(n)),null!==(n=null===this._unlinkedRecords?null:this._unlinkedRecords.get(i,null))?(Object.is(n.item,t)||this._addIdentityChange(n,t),this._reinsertAfter(n,o,r)):null!==(n=null===this._linkedRecords?null:this._linkedRecords.get(i,r))?(Object.is(n.item,t)||this._addIdentityChange(n,t),this._moveAfter(n,o,r)):n=this._addAfter(new pR(t,i),o,r),n}_verifyReinsertion(n,t,i,r){let o=null===this._unlinkedRecords?null:this._unlinkedRecords.get(i,null);return null!==o?n=this._reinsertAfter(o,n._prev,r):n.currentIndex!=r&&(n.currentIndex=r,this._addToMoves(n,r)),n}_truncate(n){for(;null!==n;){const t=n._next;this._addToRemovals(this._unlink(n)),n=t}null!==this._unlinkedRecords&&this._unlinkedRecords.clear(),null!==this._additionsTail&&(this._additionsTail._nextAdded=null),null!==this._movesTail&&(this._movesTail._nextMoved=null),null!==this._itTail&&(this._itTail._next=null),null!==this._removalsTail&&(this._removalsTail._nextRemoved=null),null!==this._identityChangesTail&&(this._identityChangesTail._nextIdentityChange=null)}_reinsertAfter(n,t,i){null!==this._unlinkedRecords&&this._unlinkedRecords.remove(n);const r=n._prevRemoved,o=n._nextRemoved;return null===r?this._removalsHead=o:r._nextRemoved=o,null===o?this._removalsTail=r:o._prevRemoved=r,this._insertAfter(n,t,i),this._addToMoves(n,i),n}_moveAfter(n,t,i){return this._unlink(n),this._insertAfter(n,t,i),this._addToMoves(n,i),n}_addAfter(n,t,i){return this._insertAfter(n,t,i),this._additionsTail=null===this._additionsTail?this._additionsHead=n:this._additionsTail._nextAdded=n,n}_insertAfter(n,t,i){const r=null===t?this._itHead:t._next;return n._next=r,n._prev=t,null===r?this._itTail=n:r._prev=n,null===t?this._itHead=n:t._next=n,null===this._linkedRecords&&(this._linkedRecords=new rC),this._linkedRecords.put(n),n.currentIndex=i,n}_remove(n){return this._addToRemovals(this._unlink(n))}_unlink(n){null!==this._linkedRecords&&this._linkedRecords.remove(n);const t=n._prev,i=n._next;return null===t?this._itHead=i:t._next=i,null===i?this._itTail=t:i._prev=t,n}_addToMoves(n,t){return n.previousIndex===t||(this._movesTail=null===this._movesTail?this._movesHead=n:this._movesTail._nextMoved=n),n}_addToRemovals(n){return null===this._unlinkedRecords&&(this._unlinkedRecords=new rC),this._unlinkedRecords.put(n),n.currentIndex=null,n._nextRemoved=null,null===this._removalsTail?(this._removalsTail=this._removalsHead=n,n._prevRemoved=null):(n._prevRemoved=this._removalsTail,this._removalsTail=this._removalsTail._nextRemoved=n),n}_addIdentityChange(n,t){return n.item=t,this._identityChangesTail=null===this._identityChangesTail?this._identityChangesHead=n:this._identityChangesTail._nextIdentityChange=n,n}}class pR{constructor(n,t){this.item=n,this.trackById=t,this.currentIndex=null,this.previousIndex=null,this._nextPrevious=null,this._prev=null,this._next=null,this._prevDup=null,this._nextDup=null,this._prevRemoved=null,this._nextRemoved=null,this._nextAdded=null,this._nextMoved=null,this._nextIdentityChange=null}}class gR{constructor(){this._head=null,this._tail=null}add(n){null===this._head?(this._head=this._tail=n,n._nextDup=null,n._prevDup=null):(this._tail._nextDup=n,n._prevDup=this._tail,n._nextDup=null,this._tail=n)}get(n,t){let i;for(i=this._head;null!==i;i=i._nextDup)if((null===t||t<=i.currentIndex)&&Object.is(i.trackById,n))return i;return null}remove(n){const t=n._prevDup,i=n._nextDup;return null===t?this._head=i:t._nextDup=i,null===i?this._tail=t:i._prevDup=t,null===this._head}}class rC{constructor(){this.map=new Map}put(n){const t=n.trackById;let i=this.map.get(t);i||(i=new gR,this.map.set(t,i)),i.add(n)}get(n,t){const r=this.map.get(n);return r?r.get(n,t):null}remove(n){const t=n.trackById;return this.map.get(t).remove(n)&&this.map.delete(t),n}get isEmpty(){return 0===this.map.size}clear(){this.map.clear()}}function oC(e,n,t){const i=e.previousIndex;if(null===i)return i;let r=0;return t&&i{if(t&&t.key===r)this._maybeAddToChanges(t,i),this._appendAfter=t,t=t._next;else{const o=this._getOrCreateRecordForKey(r,i);t=this._insertBeforeOrAppend(t,o)}}),t){t._prev&&(t._prev._next=null),this._removalsHead=t;for(let i=t;null!==i;i=i._nextRemoved)i===this._mapHead&&(this._mapHead=null),this._records.delete(i.key),i._nextRemoved=i._next,i.previousValue=i.currentValue,i.currentValue=null,i._prev=null,i._next=null}return this._changesTail&&(this._changesTail._nextChanged=null),this._additionsTail&&(this._additionsTail._nextAdded=null),this.isDirty}_insertBeforeOrAppend(n,t){if(n){const i=n._prev;return t._next=n,t._prev=i,n._prev=t,i&&(i._next=t),n===this._mapHead&&(this._mapHead=t),this._appendAfter=n,n}return this._appendAfter?(this._appendAfter._next=t,t._prev=this._appendAfter):this._mapHead=t,this._appendAfter=t,null}_getOrCreateRecordForKey(n,t){if(this._records.has(n)){const r=this._records.get(n);this._maybeAddToChanges(r,t);const o=r._prev,s=r._next;return o&&(o._next=s),s&&(s._prev=o),r._next=null,r._prev=null,r}const i=new _R(n);return this._records.set(n,i),i.currentValue=t,this._addToAdditions(i),i}_reset(){if(this.isDirty){let n;for(this._previousMapHead=this._mapHead,n=this._previousMapHead;null!==n;n=n._next)n._nextPrevious=n._next;for(n=this._changesHead;null!==n;n=n._nextChanged)n.previousValue=n.currentValue;for(n=this._additionsHead;null!=n;n=n._nextAdded)n.previousValue=n.currentValue;this._changesHead=this._changesTail=null,this._additionsHead=this._additionsTail=null,this._removalsHead=null}}_maybeAddToChanges(n,t){Object.is(t,n.currentValue)||(n.previousValue=n.currentValue,n.currentValue=t,this._addToChanges(n))}_addToAdditions(n){null===this._additionsHead?this._additionsHead=this._additionsTail=n:(this._additionsTail._nextAdded=n,this._additionsTail=n)}_addToChanges(n){null===this._changesHead?this._changesHead=this._changesTail=n:(this._changesTail._nextChanged=n,this._changesTail=n)}_forEach(n,t){n instanceof Map?n.forEach(t):Object.keys(n).forEach(i=>t(n[i],i))}}class _R{constructor(n){this.key=n,this.previousValue=null,this.currentValue=null,this._nextPrevious=null,this._next=null,this._prev=null,this._nextAdded=null,this._nextRemoved=null,this._nextChanged=null}} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */function aC(){return new Pd([new iC])}let Pd=(()=>{class e{constructor(t){this.factories=t}static create(t,i){if(null!=i){const r=i.factories.slice();t=t.concat(r)}return new e(t)}static extend(t){return{provide:e,useFactory:i=>e.create(t,i||aC()),deps:[[e,new Vl,new Ll]]}}find(t){const i=this.factories.find(r=>r.supports(t));if(null!=i)return i;throw new F(901,!1)}}return e.\u0275prov=G({token:e,providedIn:"root",factory:aC}),e})(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -function lC(){return new hc([new sC])}let hc=(()=>{class e{constructor(t){this.factories=t}static create(t,i){if(i){const r=i.factories.slice();t=t.concat(r)}return new e(t)}static extend(t){return{provide:e,useFactory:i=>e.create(t,i||lC()),deps:[[e,new Vl,new Ll]]}}find(t){const i=this.factories.find(r=>r.supports(t));if(i)return i;throw new F(901,!1)}} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -return e.\u0275prov=G({token:e,providedIn:"root",factory:lC}),e})();const bR=G1(null,"core",[]); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -let DR=(()=>{class e{constructor(t){}}return e.\u0275fac=function(t){return new(t||e)(L(fc))},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({}),e})(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -function Dm(e,n){const t=xe(e),i=n.elementInjector||Qu();return new Zl(t).create(i,n.projectableNodes,n.hostElement,n.environmentInjector)} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license Angular v14.2.9 - * (c) 2010-2022 Google LLC. https://angular.io/ - * License: MIT - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -let Fd=null;function lr(){return Fd} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -const Dt=new q("DocumentToken"); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */let Cm=(()=>{class e{historyGo(t){throw new Error("Not implemented")}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:function(){return function MR(){return L(cC)}()},providedIn:"platform"}),e})();const NR=new q("Location Initialized");let cC=(()=>{class e extends Cm{constructor(t){super(),this._doc=t,this._init()}_init(){this.location=window.location,this._history=window.history}getBaseHrefFromDOM(){return lr().getBaseHref(this._doc)}onPopState(t){const i=lr().getGlobalEventTarget(this._doc,"window");return i.addEventListener("popstate",t,!1),()=>i.removeEventListener("popstate",t)}onHashChange(t){const i=lr().getGlobalEventTarget(this._doc,"window");return i.addEventListener("hashchange",t,!1),()=>i.removeEventListener("hashchange",t)}get href(){return this.location.href}get protocol(){return this.location.protocol}get hostname(){return this.location.hostname}get port(){return this.location.port}get pathname(){return this.location.pathname}get search(){return this.location.search}get hash(){return this.location.hash}set pathname(t){this.location.pathname=t}pushState(t,i,r){uC()?this._history.pushState(t,i,r):this.location.hash=r}replaceState(t,i,r){uC()?this._history.replaceState(t,i,r):this.location.hash=r}forward(){this._history.forward()}back(){this._history.back()}historyGo(t=0){this._history.go(t)}getState(){return this._history.state}}return e.\u0275fac=function(t){return new(t||e)(L(Dt))},e.\u0275prov=G({token:e,factory:function(){return function ER(){return new cC(L(Dt))} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */()},providedIn:"platform"}),e})();function uC(){return!!window.history.pushState}function wm(e,n){if(0==e.length)return n;if(0==n.length)return e;let t=0;return e.endsWith("/")&&t++,n.startsWith("/")&&t++,2==t?e+n.substring(1):1==t?e+n:e+"/"+n}function dC(e){const n=e.match(/#|\?|$/),t=n&&n.index||e.length;return e.slice(0,t-("/"===e[t-1]?1:0))+e.slice(t)}function Hr(e){return e&&"?"!==e[0]?"?"+e:e} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */let ts=(()=>{class e{historyGo(t){throw new Error("Not implemented")}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:function(){return St(hC)},providedIn:"root"}),e})();const fC=new q("appBaseHref");let hC=(()=>{class e extends ts{constructor(t,i){super(),this._platformLocation=t,this._removeListenerFns=[],this._baseHref=i??this._platformLocation.getBaseHrefFromDOM()??St(Dt).location?.origin??""}ngOnDestroy(){for(;this._removeListenerFns.length;)this._removeListenerFns.pop()()}onPopState(t){this._removeListenerFns.push(this._platformLocation.onPopState(t),this._platformLocation.onHashChange(t))}getBaseHref(){return this._baseHref}prepareExternalUrl(t){return wm(this._baseHref,t)}path(t=!1){const i=this._platformLocation.pathname+Hr(this._platformLocation.search),r=this._platformLocation.hash;return r&&t?`${i}${r}`:i}pushState(t,i,r,o){const s=this.prepareExternalUrl(r+Hr(o));this._platformLocation.pushState(t,i,s)}replaceState(t,i,r,o){const s=this.prepareExternalUrl(r+Hr(o));this._platformLocation.replaceState(t,i,s)}forward(){this._platformLocation.forward()}back(){this._platformLocation.back()}getState(){return this._platformLocation.getState()}historyGo(t=0){this._platformLocation.historyGo?.(t)}}return e.\u0275fac=function(t){return new(t||e)(L(Cm),L(fC,8))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(),TR=(()=>{class e extends ts{constructor(t,i){super(),this._platformLocation=t,this._baseHref="",this._removeListenerFns=[],null!=i&&(this._baseHref=i)}ngOnDestroy(){for(;this._removeListenerFns.length;)this._removeListenerFns.pop()()}onPopState(t){this._removeListenerFns.push(this._platformLocation.onPopState(t),this._platformLocation.onHashChange(t))}getBaseHref(){return this._baseHref}path(t=!1){let i=this._platformLocation.hash;return null==i&&(i="#"),i.length>0?i.substring(1):i}prepareExternalUrl(t){const i=wm(this._baseHref,t);return i.length>0?"#"+i:i}pushState(t,i,r,o){let s=this.prepareExternalUrl(r+Hr(o));0==s.length&&(s=this._platformLocation.pathname),this._platformLocation.pushState(t,i,s)}replaceState(t,i,r,o){let s=this.prepareExternalUrl(r+Hr(o));0==s.length&&(s=this._platformLocation.pathname),this._platformLocation.replaceState(t,i,s)}forward(){this._platformLocation.forward()}back(){this._platformLocation.back()}getState(){return this._platformLocation.getState()}historyGo(t=0){this._platformLocation.historyGo?.(t)}}return e.\u0275fac=function(t){return new(t||e)(L(Cm),L(fC,8))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(),Sm=(()=>{class e{constructor(t){this._subject=new ue,this._urlChangeListeners=[],this._urlChangeSubscription=null,this._locationStrategy=t;const i=this._locationStrategy.getBaseHref();this._baseHref=dC(pC(i)),this._locationStrategy.onPopState(r=>{this._subject.emit({url:this.path(!0),pop:!0,state:r.state,type:r.type})})}ngOnDestroy(){this._urlChangeSubscription?.unsubscribe(),this._urlChangeListeners=[]}path(t=!1){return this.normalize(this._locationStrategy.path(t))}getState(){return this._locationStrategy.getState()}isCurrentPathEqualTo(t,i=""){return this.path()==this.normalize(t+Hr(i))}normalize(t){return e.stripTrailingSlash(function AR(e,n){return e&&n.startsWith(e)?n.substring(e.length):n}(this._baseHref,pC(t)))}prepareExternalUrl(t){return t&&"/"!==t[0]&&(t="/"+t),this._locationStrategy.prepareExternalUrl(t)}go(t,i="",r=null){this._locationStrategy.pushState(r,"",t,i),this._notifyUrlChangeListeners(this.prepareExternalUrl(t+Hr(i)),r)}replaceState(t,i="",r=null){this._locationStrategy.replaceState(r,"",t,i),this._notifyUrlChangeListeners(this.prepareExternalUrl(t+Hr(i)),r)}forward(){this._locationStrategy.forward()}back(){this._locationStrategy.back()}historyGo(t=0){this._locationStrategy.historyGo?.(t)}onUrlChange(t){return this._urlChangeListeners.push(t),this._urlChangeSubscription||(this._urlChangeSubscription=this.subscribe(i=>{this._notifyUrlChangeListeners(i.url,i.state)})),()=>{const i=this._urlChangeListeners.indexOf(t);this._urlChangeListeners.splice(i,1),0===this._urlChangeListeners.length&&(this._urlChangeSubscription?.unsubscribe(),this._urlChangeSubscription=null)}}_notifyUrlChangeListeners(t="",i){this._urlChangeListeners.forEach(r=>r(t,i))}subscribe(t,i,r){return this._subject.subscribe({next:t,error:i,complete:r})}}return e.normalizeQueryParams=Hr,e.joinWithSlash=wm,e.stripTrailingSlash=dC,e.\u0275fac=function(t){return new(t||e)(L(ts))},e.\u0275prov=G({token:e,factory:function(){return function IR(){return new Sm(L(ts))}()},providedIn:"root"}),e})(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */function pC(e){return e.replace(/\/index.html$/,"")} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -var Nt=(()=>((Nt=Nt||{})[Nt.Format=0]="Format",Nt[Nt.Standalone=1]="Standalone",Nt))(),ve=(()=>((ve=ve||{})[ve.Narrow=0]="Narrow",ve[ve.Abbreviated=1]="Abbreviated",ve[ve.Wide=2]="Wide",ve[ve.Short=3]="Short",ve))(),pt=(()=>((pt=pt||{})[pt.Short=0]="Short",pt[pt.Medium=1]="Medium",pt[pt.Long=2]="Long",pt[pt.Full=3]="Full",pt))(),ee=(()=>((ee=ee||{})[ee.Decimal=0]="Decimal",ee[ee.Group=1]="Group",ee[ee.List=2]="List",ee[ee.PercentSign=3]="PercentSign",ee[ee.PlusSign=4]="PlusSign",ee[ee.MinusSign=5]="MinusSign",ee[ee.Exponential=6]="Exponential",ee[ee.SuperscriptingExponent=7]="SuperscriptingExponent",ee[ee.PerMille=8]="PerMille",ee[ee.Infinity=9]="Infinity",ee[ee.NaN=10]="NaN",ee[ee.TimeSeparator=11]="TimeSeparator",ee[ee.CurrencyDecimal=12]="CurrencyDecimal",ee[ee.CurrencyGroup=13]="CurrencyGroup",ee))();function Ld(e,n){return _i(An(e)[j.DateFormat],n)}function Vd(e,n){return _i(An(e)[j.TimeFormat],n)}function Bd(e,n){return _i(An(e)[j.DateTimeFormat],n)}function mi(e,n){const t=An(e),i=t[j.NumberSymbols][n];if(typeof i>"u"){if(n===ee.CurrencyDecimal)return t[j.NumberSymbols][ee.Decimal];if(n===ee.CurrencyGroup)return t[j.NumberSymbols][ee.Group]}return i}function mC(e){if(!e[j.ExtraData])throw new Error(`Missing extra locale data for the locale "${e[j.LocaleId]}". Use "registerLocaleData" to load new data. See the "I18n guide" on angular.io to know more.`)}function _i(e,n){for(let t=n;t>-1;t--)if(typeof e[t]<"u")return e[t];throw new Error("Locale data API: locale data undefined")}function Nm(e){const[n,t]=e.split(":");return{hours:+n,minutes:+t}} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -const UR=/^(\d{4,})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/,pc={},GR=/((?:[^BEGHLMOSWYZabcdhmswyz']+)|(?:'(?:[^']|'')*')|(?:G{1,5}|y{1,4}|Y{1,4}|M{1,5}|L{1,5}|w{1,2}|W{1}|d{1,2}|E{1,6}|c{1,6}|a{1,5}|b{1,5}|B{1,5}|h{1,2}|H{1,2}|m{1,2}|s{1,2}|S{1,3}|z{1,4}|Z{1,5}|O{1,4}))([\s\S]*)/;var Lt=(()=>((Lt=Lt||{})[Lt.Short=0]="Short",Lt[Lt.ShortGMT=1]="ShortGMT",Lt[Lt.Long=2]="Long",Lt[Lt.Extended=3]="Extended",Lt))(),ie=(()=>((ie=ie||{})[ie.FullYear=0]="FullYear",ie[ie.Month=1]="Month",ie[ie.Date=2]="Date",ie[ie.Hours=3]="Hours",ie[ie.Minutes=4]="Minutes",ie[ie.Seconds=5]="Seconds",ie[ie.FractionalSeconds=6]="FractionalSeconds",ie[ie.Day=7]="Day",ie))(),fe=(()=>((fe=fe||{})[fe.DayPeriods=0]="DayPeriods",fe[fe.Days=1]="Days",fe[fe.Months=2]="Months",fe[fe.Eras=3]="Eras",fe))();function WR(e,n,t,i){let r=function eP(e){if(yC(e))return e;if("number"==typeof e&&!isNaN(e))return new Date(e);if("string"==typeof e){if(e=e.trim(),/^(\d{4}(-\d{1,2}(-\d{1,2})?)?)$/.test(e)){const[r,o=1,s=1]=e.split("-").map(a=>+a);return Hd(r,o-1,s)}const t=parseFloat(e);if(!isNaN(e-t))return new Date(t);let i;if(i=e.match(UR))return function tP(e){const n=new Date(0);let t=0,i=0;const r=e[8]?n.setUTCFullYear:n.setFullYear,o=e[8]?n.setUTCHours:n.setHours;e[9]&&(t=Number(e[9]+e[10]),i=Number(e[9]+e[11])),r.call(n,Number(e[1]),Number(e[2])-1,Number(e[3]));const s=Number(e[4]||0)-t,a=Number(e[5]||0)-i,l=Number(e[6]||0),u=Math.floor(1e3*parseFloat("0."+(e[7]||0)));return o.call(n,s,a,l,u),n}(i)}const n=new Date(e);if(!yC(n))throw new Error(`Unable to convert "${e}" into a date`);return n}(e);n=jr(t,n)||n;let a,s=[];for(;n;){if(a=GR.exec(n),!a){s.push(n);break}{s=s.concat(a.slice(1));const f=s.pop();if(!f)break;n=f}}let l=r.getTimezoneOffset();i&&(l=vC(i,l),r=function XR(e,n,t){const i=t?-1:1,r=e.getTimezoneOffset();return function QR(e,n){return(e=new Date(e.getTime())).setMinutes(e.getMinutes()+n),e}(e,i*(vC(n,r)-r))}(r,i,!0));let u="";return s.forEach(f=>{const p=function JR(e){if(Tm[e])return Tm[e];let n;switch(e){case"G":case"GG":case"GGG":n=Qe(fe.Eras,ve.Abbreviated);break;case"GGGG":n=Qe(fe.Eras,ve.Wide);break;case"GGGGG":n=Qe(fe.Eras,ve.Narrow);break;case"y":n=kt(ie.FullYear,1,0,!1,!0);break;case"yy":n=kt(ie.FullYear,2,0,!0,!0);break;case"yyy":n=kt(ie.FullYear,3,0,!1,!0);break;case"yyyy":n=kt(ie.FullYear,4,0,!1,!0);break;case"Y":n=Gd(1);break;case"YY":n=Gd(2,!0);break;case"YYY":n=Gd(3);break;case"YYYY":n=Gd(4);break;case"M":case"L":n=kt(ie.Month,1,1);break;case"MM":case"LL":n=kt(ie.Month,2,1);break;case"MMM":n=Qe(fe.Months,ve.Abbreviated);break;case"MMMM":n=Qe(fe.Months,ve.Wide);break;case"MMMMM":n=Qe(fe.Months,ve.Narrow);break;case"LLL":n=Qe(fe.Months,ve.Abbreviated,Nt.Standalone);break;case"LLLL":n=Qe(fe.Months,ve.Wide,Nt.Standalone);break;case"LLLLL":n=Qe(fe.Months,ve.Narrow,Nt.Standalone);break;case"w":n=Em(1);break;case"ww":n=Em(2);break;case"W":n=Em(1,!0);break;case"d":n=kt(ie.Date,1);break;case"dd":n=kt(ie.Date,2);break;case"c":case"cc":n=kt(ie.Day,1);break;case"ccc":n=Qe(fe.Days,ve.Abbreviated,Nt.Standalone);break;case"cccc":n=Qe(fe.Days,ve.Wide,Nt.Standalone);break;case"ccccc":n=Qe(fe.Days,ve.Narrow,Nt.Standalone);break;case"cccccc":n=Qe(fe.Days,ve.Short,Nt.Standalone);break;case"E":case"EE":case"EEE":n=Qe(fe.Days,ve.Abbreviated);break;case"EEEE":n=Qe(fe.Days,ve.Wide);break;case"EEEEE":n=Qe(fe.Days,ve.Narrow);break;case"EEEEEE":n=Qe(fe.Days,ve.Short);break;case"a":case"aa":case"aaa":n=Qe(fe.DayPeriods,ve.Abbreviated);break;case"aaaa":n=Qe(fe.DayPeriods,ve.Wide);break;case"aaaaa":n=Qe(fe.DayPeriods,ve.Narrow);break;case"b":case"bb":case"bbb":n=Qe(fe.DayPeriods,ve.Abbreviated,Nt.Standalone,!0);break;case"bbbb":n=Qe(fe.DayPeriods,ve.Wide,Nt.Standalone,!0);break;case"bbbbb":n=Qe(fe.DayPeriods,ve.Narrow,Nt.Standalone,!0);break;case"B":case"BB":case"BBB":n=Qe(fe.DayPeriods,ve.Abbreviated,Nt.Format,!0);break;case"BBBB":n=Qe(fe.DayPeriods,ve.Wide,Nt.Format,!0);break;case"BBBBB":n=Qe(fe.DayPeriods,ve.Narrow,Nt.Format,!0);break;case"h":n=kt(ie.Hours,1,-12);break;case"hh":n=kt(ie.Hours,2,-12);break;case"H":n=kt(ie.Hours,1);break;case"HH":n=kt(ie.Hours,2);break;case"m":n=kt(ie.Minutes,1);break;case"mm":n=kt(ie.Minutes,2);break;case"s":n=kt(ie.Seconds,1);break;case"ss":n=kt(ie.Seconds,2);break;case"S":n=kt(ie.FractionalSeconds,1);break;case"SS":n=kt(ie.FractionalSeconds,2);break;case"SSS":n=kt(ie.FractionalSeconds,3);break;case"Z":case"ZZ":case"ZZZ":n=$d(Lt.Short);break;case"ZZZZZ":n=$d(Lt.Extended);break;case"O":case"OO":case"OOO":case"z":case"zz":case"zzz":n=$d(Lt.ShortGMT);break;case"OOOO":case"ZZZZ":case"zzzz":n=$d(Lt.Long);break;default:return null}return Tm[e]=n,n}(f);u+=p?p(r,t,l):"''"===f?"'":f.replace(/(^'|'$)/g,"").replace(/''/g,"'")}),u}function Hd(e,n,t){const i=new Date(0);return i.setFullYear(e,n,t),i.setHours(0,0,0),i}function jr(e,n){const t=function kR(e){return An(e)[j.LocaleId]}(e);if(pc[t]=pc[t]||{},pc[t][n])return pc[t][n];let i="";switch(n){case"shortDate":i=Ld(e,pt.Short);break;case"mediumDate":i=Ld(e,pt.Medium);break;case"longDate":i=Ld(e,pt.Long);break;case"fullDate":i=Ld(e,pt.Full);break;case"shortTime":i=Vd(e,pt.Short);break;case"mediumTime":i=Vd(e,pt.Medium);break;case"longTime":i=Vd(e,pt.Long);break;case"fullTime":i=Vd(e,pt.Full);break;case"short":const r=jr(e,"shortTime"),o=jr(e,"shortDate");i=jd(Bd(e,pt.Short),[r,o]);break;case"medium":const s=jr(e,"mediumTime"),a=jr(e,"mediumDate");i=jd(Bd(e,pt.Medium),[s,a]);break;case"long":const l=jr(e,"longTime"),u=jr(e,"longDate");i=jd(Bd(e,pt.Long),[l,u]);break;case"full":const f=jr(e,"fullTime"),p=jr(e,"fullDate");i=jd(Bd(e,pt.Full),[f,p])}return i&&(pc[t][n]=i),i}function jd(e,n){return n&&(e=e.replace(/\{([^}]+)}/g,function(t,i){return null!=n&&i in n?n[i]:t})),e}function Ui(e,n,t="-",i,r){let o="";(e<0||r&&e<=0)&&(r?e=1-e:(e=-e,o=t));let s=String(e);for(;s.length0||a>-t)&&(a+=t),e===ie.Hours)0===a&&-12===t&&(a=12);else if(e===ie.FractionalSeconds)return function zR(e,n){return Ui(e,3).substring(0,n)}(a,n);const l=mi(s,ee.MinusSign);return Ui(a,n,l,i,r)}}function Qe(e,n,t=Nt.Format,i=!1){return function(r,o){return function KR(e,n,t,i,r,o){switch(t){case fe.Months:return function RR(e,n,t){const i=An(e),o=_i([i[j.MonthsFormat],i[j.MonthsStandalone]],n);return _i(o,t)}(n,r,i)[e.getMonth()];case fe.Days:return function xR(e,n,t){const i=An(e),o=_i([i[j.DaysFormat],i[j.DaysStandalone]],n);return _i(o,t)}(n,r,i)[e.getDay()];case fe.DayPeriods:const s=e.getHours(),a=e.getMinutes();if(o){const u=function VR(e){const n=An(e);return mC(n),(n[j.ExtraData][2]||[]).map(i=>"string"==typeof i?Nm(i):[Nm(i[0]),Nm(i[1])])}(n),f=function BR(e,n,t){const i=An(e);mC(i);const o=_i([i[j.ExtraData][0],i[j.ExtraData][1]],n)||[];return _i(o,t)||[]}(n,r,i),p=u.findIndex(m=>{if(Array.isArray(m)){const[v,y]=m,D=s>=v.hours&&a>=v.minutes,w=s0?Math.floor(r/60):Math.ceil(r/60);switch(e){case Lt.Short:return(r>=0?"+":"")+Ui(s,2,o)+Ui(Math.abs(r%60),2,o);case Lt.ShortGMT:return"GMT"+(r>=0?"+":"")+Ui(s,1,o);case Lt.Long:return"GMT"+(r>=0?"+":"")+Ui(s,2,o)+":"+Ui(Math.abs(r%60),2,o);case Lt.Extended:return 0===i?"Z":(r>=0?"+":"")+Ui(s,2,o)+":"+Ui(Math.abs(r%60),2,o);default:throw new Error(`Unknown zone width "${e}"`)}}}function _C(e){return Hd(e.getFullYear(),e.getMonth(),e.getDate()+(4-e.getDay()))}function Em(e,n=!1){return function(t,i){let r;if(n){const o=new Date(t.getFullYear(),t.getMonth(),1).getDay()-1,s=t.getDate();r=1+Math.floor((s+o)/7)}else{const o=_C(t),s=function ZR(e){const n=Hd(e,0,1).getDay();return Hd(e,0,1+(n<=4?4:11)-n)}(o.getFullYear()),a=o.getTime()-s.getTime();r=1+Math.round(a/6048e5)}return Ui(r,e,mi(i,ee.MinusSign))}}function Gd(e,n=!1){return function(t,i){return Ui(_C(t).getFullYear(),e,mi(i,ee.MinusSign),n)}}const Tm={};function vC(e,n){e=e.replace(/:/g,"");const t=Date.parse("Jan 01, 1970 00:00:00 "+e)/6e4;return isNaN(t)?n:t}function yC(e){return e instanceof Date&&!isNaN(e.valueOf())} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -function wC(e,n){n=encodeURIComponent(n);for(const t of e.split(";")){const i=t.indexOf("="),[r,o]=-1==i?[t,""]:[t.slice(0,i),t.slice(i+1)];if(r.trim()===n)return decodeURIComponent(o)}return null} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */let SC=(()=>{class e{constructor(t,i,r,o){this._iterableDiffers=t,this._keyValueDiffers=i,this._ngEl=r,this._renderer=o,this._iterableDiffer=null,this._keyValueDiffer=null,this._initialClasses=[],this._rawClass=null}set klass(t){this._removeClasses(this._initialClasses),this._initialClasses="string"==typeof t?t.split(/\s+/):[],this._applyClasses(this._initialClasses),this._applyClasses(this._rawClass)}set ngClass(t){this._removeClasses(this._rawClass),this._applyClasses(this._initialClasses),this._iterableDiffer=null,this._keyValueDiffer=null,this._rawClass="string"==typeof t?t.split(/\s+/):t,this._rawClass&&(Jl(this._rawClass)?this._iterableDiffer=this._iterableDiffers.find(this._rawClass).create():this._keyValueDiffer=this._keyValueDiffers.find(this._rawClass).create())}ngDoCheck(){if(this._iterableDiffer){const t=this._iterableDiffer.diff(this._rawClass);t&&this._applyIterableChanges(t)}else if(this._keyValueDiffer){const t=this._keyValueDiffer.diff(this._rawClass);t&&this._applyKeyValueChanges(t)}}_applyKeyValueChanges(t){t.forEachAddedItem(i=>this._toggleClass(i.key,i.currentValue)),t.forEachChangedItem(i=>this._toggleClass(i.key,i.currentValue)),t.forEachRemovedItem(i=>{i.previousValue&&this._toggleClass(i.key,!1)})}_applyIterableChanges(t){t.forEachAddedItem(i=>{if("string"!=typeof i.item)throw new Error(`NgClass can only toggle CSS classes expressed as strings, got ${Ve(i.item)}`);this._toggleClass(i.item,!0)}),t.forEachRemovedItem(i=>this._toggleClass(i.item,!1))}_applyClasses(t){t&&(Array.isArray(t)||t instanceof Set?t.forEach(i=>this._toggleClass(i,!0)):Object.keys(t).forEach(i=>this._toggleClass(i,!!t[i])))}_removeClasses(t){t&&(Array.isArray(t)||t instanceof Set?t.forEach(i=>this._toggleClass(i,!1)):Object.keys(t).forEach(i=>this._toggleClass(i,!1)))}_toggleClass(t,i){(t=t.trim())&&t.split(/\s+/g).forEach(r=>{i?this._renderer.addClass(this._ngEl.nativeElement,r):this._renderer.removeClass(this._ngEl.nativeElement,r)})}}return e.\u0275fac=function(t){return new(t||e)(C(Pd),C(hc),C(Je),C(pi))},e.\u0275dir=B({type:e,selectors:[["","ngClass",""]],inputs:{klass:["class","klass"],ngClass:"ngClass"},standalone:!0}),e})(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */class pP{constructor(n,t,i,r){this.$implicit=n,this.ngForOf=t,this.index=i,this.count=r}get first(){return 0===this.index}get last(){return this.index===this.count-1}get even(){return this.index%2==0}get odd(){return!this.even}}let Oa=(()=>{class e{constructor(t,i,r){this._viewContainer=t,this._template=i,this._differs=r,this._ngForOf=null,this._ngForOfDirty=!0,this._differ=null}set ngForOf(t){this._ngForOf=t,this._ngForOfDirty=!0}set ngForTrackBy(t){this._trackByFn=t}get ngForTrackBy(){return this._trackByFn}set ngForTemplate(t){t&&(this._template=t)}ngDoCheck(){if(this._ngForOfDirty){this._ngForOfDirty=!1;const t=this._ngForOf;!this._differ&&t&&(this._differ=this._differs.find(t).create(this.ngForTrackBy))}if(this._differ){const t=this._differ.diff(this._ngForOf);t&&this._applyChanges(t)}}_applyChanges(t){const i=this._viewContainer;t.forEachOperation((r,o,s)=>{if(null==r.previousIndex)i.createEmbeddedView(this._template,new pP(r.item,this._ngForOf,-1,-1),null===s?void 0:s);else if(null==s)i.remove(null===o?void 0:o);else if(null!==o){const a=i.get(o);i.move(a,s),EC(a,r)}});for(let r=0,o=i.length;r{EC(i.get(r.currentIndex),r)})}static ngTemplateContextGuard(t,i){return!0}}return e.\u0275fac=function(t){return new(t||e)(C(Hi),C(bt),C(Pd))},e.\u0275dir=B({type:e,selectors:[["","ngFor","","ngForOf",""]],inputs:{ngForOf:"ngForOf",ngForTrackBy:"ngForTrackBy",ngForTemplate:"ngForTemplate"},standalone:!0}),e})();function EC(e,n){e.context.$implicit=n.item} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -let ns=(()=>{class e{constructor(t,i){this._viewContainer=t,this._context=new mP,this._thenTemplateRef=null,this._elseTemplateRef=null,this._thenViewRef=null,this._elseViewRef=null,this._thenTemplateRef=i}set ngIf(t){this._context.$implicit=this._context.ngIf=t,this._updateView()}set ngIfThen(t){TC("ngIfThen",t),this._thenTemplateRef=t,this._thenViewRef=null,this._updateView()}set ngIfElse(t){TC("ngIfElse",t),this._elseTemplateRef=t,this._elseViewRef=null,this._updateView()}_updateView(){this._context.$implicit?this._thenViewRef||(this._viewContainer.clear(),this._elseViewRef=null,this._thenTemplateRef&&(this._thenViewRef=this._viewContainer.createEmbeddedView(this._thenTemplateRef,this._context))):this._elseViewRef||(this._viewContainer.clear(),this._thenViewRef=null,this._elseTemplateRef&&(this._elseViewRef=this._viewContainer.createEmbeddedView(this._elseTemplateRef,this._context)))}static ngTemplateContextGuard(t,i){return!0}}return e.\u0275fac=function(t){return new(t||e)(C(Hi),C(bt))},e.\u0275dir=B({type:e,selectors:[["","ngIf",""]],inputs:{ngIf:"ngIf",ngIfThen:"ngIfThen",ngIfElse:"ngIfElse"},standalone:!0}),e})();class mP{constructor(){this.$implicit=null,this.ngIf=null}}function TC(e,n){if(n&&!n.createEmbeddedView)throw new Error(`${e} must be a TemplateRef, but received '${Ve(n)}'.`)} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -const AP=new q("DATE_PIPE_DEFAULT_TIMEZONE");let AC=(()=>{class e{constructor(t,i){this.locale=t,this.defaultTimezone=i}transform(t,i="mediumDate",r,o){if(null==t||""===t||t!=t)return null;try{return WR(t,i,o||this.locale,r??this.defaultTimezone??void 0)}catch(s){ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -throw function Gi(e,n){return new F(2100,!1)} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */()}}}return e.\u0275fac=function(t){return new(t||e)(C(Fr,16),C(AP,24))},e.\u0275pipe=$t({name:"date",type:e,pure:!0,standalone:!0}),e})(),ei=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({}),e})(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -const OC="browser"; -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -let GP=(()=>{class e{}return e.\u0275prov=G({token:e,providedIn:"root",factory:()=>new WP(L(Dt),window)}),e})();class WP{constructor(n,t){this.document=n,this.window=t,this.offset=()=>[0,0]}setOffset(n){this.offset=Array.isArray(n)?()=>n:n}getScrollPosition(){return this.supportsScrolling()?[this.window.pageXOffset,this.window.pageYOffset]:[0,0]}scrollToPosition(n){this.supportsScrolling()&&this.window.scrollTo(n[0],n[1])}scrollToAnchor(n){if(!this.supportsScrolling())return;const t=function zP(e,n){const t=e.getElementById(n)||e.getElementsByName(n)[0];if(t)return t;if("function"==typeof e.createTreeWalker&&e.body&&(e.body.createShadowRoot||e.body.attachShadow)){const i=e.createTreeWalker(e.body,NodeFilter.SHOW_ELEMENT);let r=i.currentNode;for(;r;){const o=r.shadowRoot;if(o){const s=o.getElementById(n)||o.querySelector(`[name="${n}"]`);if(s)return s}r=i.nextNode()}}return null}(this.document,n);t&&(this.scrollToElement(t),t.focus())}setHistoryScrollRestoration(n){if(this.supportScrollRestoration()){const t=this.window.history;t&&t.scrollRestoration&&(t.scrollRestoration=n)}}scrollToElement(n){const t=n.getBoundingClientRect(),i=t.left+this.window.pageXOffset,r=t.top+this.window.pageYOffset,o=this.offset();this.window.scrollTo(i-o[0],r-o[1])}supportScrollRestoration(){try{if(!this.supportsScrolling())return!1;const n=RC(this.window.history)||RC(Object.getPrototypeOf(this.window.history));return!(!n||!n.writable&&!n.set)}catch{return!1}}supportsScrolling(){try{return!!this.window&&!!this.window.scrollTo&&"pageXOffset"in this.window}catch{return!1}}}function RC(e){return Object.getOwnPropertyDescriptor(e,"scrollRestoration")} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -class PC{} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -class Hm extends -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license Angular v14.2.9 - * (c) 2010-2022 Google LLC. https://angular.io/ - * License: MIT - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -class uF extends class SR{}{constructor(){super(...arguments),this.supportsDOMEvents=!0}}{static makeCurrent(){!function wR(e){Fd||(Fd=e)}(new Hm)}onAndCancel(n,t,i){return n.addEventListener(t,i,!1),()=>{n.removeEventListener(t,i,!1)}}dispatchEvent(n,t){n.dispatchEvent(t)}remove(n){n.parentNode&&n.parentNode.removeChild(n)}createElement(n,t){return(t=t||this.getDefaultDocument()).createElement(n)}createHtmlDocument(){return document.implementation.createHTMLDocument("fakeTitle")}getDefaultDocument(){return document}isElementNode(n){return n.nodeType===Node.ELEMENT_NODE}isShadowRoot(n){return n instanceof DocumentFragment}getGlobalEventTarget(n,t){return"window"===t?window:"document"===t?n:"body"===t?n.body:null}getBaseHref(n){const t=function dF(){return vc=vc||document.querySelector("base"),vc?vc.getAttribute("href"):null}();return null==t?null:function fF(e){Yd=Yd||document.createElement("a"),Yd.setAttribute("href",e);const n=Yd.pathname;return"/"===n.charAt(0)?n:`/${n}`} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */(t)}resetBaseElement(){vc=null}getUserAgent(){return window.navigator.userAgent}getCookie(n){return wC(document.cookie,n)}}let Yd,vc=null;const BC=new q("TRANSITION_ID"),pF=[{provide:Id,useFactory:function hF(e,n,t){return()=>{t.get(Ad).donePromise.then(()=>{const i=lr(),r=n.querySelectorAll(`style[ng-transition="${e}"]`);for(let o=0;o{class e{build(){return new XMLHttpRequest}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */const Kd=new q("EventManagerPlugins");let qd=(()=>{class e{constructor(t,i){this._zone=i,this._eventNameToPlugin=new Map,t.forEach(r=>r.manager=this),this._plugins=t.slice().reverse()}addEventListener(t,i,r){return this._findPluginFor(i).addEventListener(t,i,r)}addGlobalEventListener(t,i,r){return this._findPluginFor(i).addGlobalEventListener(t,i,r)}getZone(){return this._zone}_findPluginFor(t){const i=this._eventNameToPlugin.get(t);if(i)return i;const r=this._plugins;for(let o=0;o{class e{constructor(){this._stylesSet=new Set}addStyles(t){const i=new Set;t.forEach(r=>{this._stylesSet.has(r)||(this._stylesSet.add(r),i.add(r))}),this.onStylesAdded(i)}onStylesAdded(t){}getAllStyles(){return Array.from(this._stylesSet)}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(),yc=(()=>{class e extends jC{constructor(t){super(),this._doc=t,this._hostNodes=new Map,this._hostNodes.set(t.head,[])}_addStylesToHost(t,i,r){t.forEach(o=>{const s=this._doc.createElement("style");s.textContent=o,r.push(i.appendChild(s))})}addHost(t){const i=[];this._addStylesToHost(this._stylesSet,t,i),this._hostNodes.set(t,i)}removeHost(t){const i=this._hostNodes.get(t);i&&i.forEach($C),this._hostNodes.delete(t)}onStylesAdded(t){this._hostNodes.forEach((i,r)=>{this._addStylesToHost(t,r,i)})}ngOnDestroy(){this._hostNodes.forEach(t=>t.forEach($C))}}return e.\u0275fac=function(t){return new(t||e)(L(Dt))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})();function $C(e){lr().remove(e)} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */const jm={svg:"http://www.w3.org/2000/svg",xhtml:"http://www.w3.org/1999/xhtml",xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/",math:"http://www.w3.org/1998/MathML/"},$m=/%COMP%/g;function Zd(e,n,t){for(let i=0;i{if("__ngUnwrap__"===n)return e;!1===e(n)&&(n.preventDefault(),n.returnValue=!1)}}let Um=(()=>{class e{constructor(t,i,r){this.eventManager=t,this.sharedStylesHost=i,this.appId=r,this.rendererByCompId=new Map,this.defaultRenderer=new Gm(t)}createRenderer(t,i){if(!t||!i)return this.defaultRenderer;switch(i.encapsulation){case ai.Emulated:{let r=this.rendererByCompId.get(i.id);return r||(r=new CF(this.eventManager,this.sharedStylesHost,i,this.appId),this.rendererByCompId.set(i.id,r)),r.applyToHost(t),r}case 1:case ai.ShadowDom:return new wF(this.eventManager,this.sharedStylesHost,t,i);default:if(!this.rendererByCompId.has(i.id)){const r=Zd(i.id,i.styles,[]);this.sharedStylesHost.addStyles(r),this.rendererByCompId.set(i.id,this.defaultRenderer)}return this.defaultRenderer}}begin(){}end(){}}return e.\u0275fac=function(t){return new(t||e)(L(qd),L(yc),L(uc))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})();class Gm{constructor(n){this.eventManager=n,this.data=Object.create(null),this.destroyNode=null}destroy(){}createElement(n,t){return t?document.createElementNS(jm[t]||t,n):document.createElement(n)}createComment(n){return document.createComment(n)}createText(n){return document.createTextNode(n)}appendChild(n,t){(YC(n)?n.content:n).appendChild(t)}insertBefore(n,t,i){n&&(YC(n)?n.content:n).insertBefore(t,i)}removeChild(n,t){n&&n.removeChild(t)}selectRootElement(n,t){let i="string"==typeof n?document.querySelector(n):n;if(!i)throw new Error(`The selector "${n}" did not match any elements`);return t||(i.textContent=""),i}parentNode(n){return n.parentNode}nextSibling(n){return n.nextSibling}setAttribute(n,t,i,r){if(r){t=r+":"+t;const o=jm[r];o?n.setAttributeNS(o,t,i):n.setAttribute(t,i)}else n.setAttribute(t,i)}removeAttribute(n,t,i){if(i){const r=jm[i];r?n.removeAttributeNS(r,t):n.removeAttribute(`${i}:${t}`)}else n.removeAttribute(t)}addClass(n,t){n.classList.add(t)}removeClass(n,t){n.classList.remove(t)}setStyle(n,t,i,r){r&(Un.DashCase|Un.Important)?n.style.setProperty(t,i,r&Un.Important?"important":""):n.style[t]=i}removeStyle(n,t,i){i&Un.DashCase?n.style.removeProperty(t):n.style[t]=""}setProperty(n,t,i){n[t]=i}setValue(n,t){n.nodeValue=t}listen(n,t,i){return"string"==typeof n?this.eventManager.addGlobalEventListener(n,t,WC(i)):this.eventManager.addEventListener(n,t,WC(i))}}function YC(e){return"TEMPLATE"===e.tagName&&void 0!==e.content}class CF extends Gm{constructor(n,t,i,r){super(n),this.component=i;const o=Zd(r+"-"+i.id,i.styles,[]);t.addStyles(o),this.contentAttr=function yF(e){return"_ngcontent-%COMP%".replace($m,e)}(r+"-"+i.id),this.hostAttr=function bF(e){return"_nghost-%COMP%".replace($m,e)}(r+"-"+i.id)}applyToHost(n){super.setAttribute(n,this.hostAttr,"")}createElement(n,t){const i=super.createElement(n,t);return super.setAttribute(i,this.contentAttr,""),i}}class wF extends Gm{constructor(n,t,i,r){super(n),this.sharedStylesHost=t,this.hostEl=i,this.shadowRoot=i.attachShadow({mode:"open"}),this.sharedStylesHost.addHost(this.shadowRoot);const o=Zd(r.id,r.styles,[]);for(let s=0;s{class e extends HC{constructor(t){super(t)}supports(t){return!0}addEventListener(t,i,r){return t.addEventListener(i,r,!1),()=>this.removeEventListener(t,i,r)}removeEventListener(t,i,r){return t.removeEventListener(i,r)}}return e.\u0275fac=function(t){return new(t||e)(L(Dt))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */const KC=["alt","control","meta","shift"],MF={"\b":"Backspace","\t":"Tab","\x7f":"Delete","\x1b":"Escape",Del:"Delete",Esc:"Escape",Left:"ArrowLeft",Right:"ArrowRight",Up:"ArrowUp",Down:"ArrowDown",Menu:"ContextMenu",Scroll:"ScrollLock",Win:"OS"},NF={alt:e=>e.altKey,control:e=>e.ctrlKey,meta:e=>e.metaKey,shift:e=>e.shiftKey};let EF=(()=>{class e extends HC{constructor(t){super(t)}supports(t){return null!=e.parseEventName(t)}addEventListener(t,i,r){const o=e.parseEventName(i),s=e.eventCallback(o.fullKey,r,this.manager.getZone());return this.manager.getZone().runOutsideAngular(()=>lr().onAndCancel(t,o.domEventName,s))}static parseEventName(t){const i=t.toLowerCase().split("."),r=i.shift();if(0===i.length||"keydown"!==r&&"keyup"!==r)return null;const o=e._normalizeKey(i.pop());let s="",a=i.indexOf("code");if(a>-1&&(i.splice(a,1),s="code."),KC.forEach(u=>{const f=i.indexOf(u);f>-1&&(i.splice(f,1),s+=u+".")}),s+=o,0!=i.length||0===o.length)return null;const l={};return l.domEventName=r,l.fullKey=s,l}static matchEventFullKeyCode(t,i){let r=MF[t.key]||t.key,o="";return i.indexOf("code.")>-1&&(r=t.code,o="code."),!(null==r||!r)&&(r=r.toLowerCase()," "===r?r="space":"."===r&&(r="dot"),KC.forEach(s=>{s!==r&&(0,NF[s])(t)&&(o+=s+".")}),o+=r,o===i)}static eventCallback(t,i,r){return o=>{e.matchEventFullKeyCode(o,t)&&r.runGuarded(()=>i(o))}}static _normalizeKey(t){return"esc"===t?"escape":t}}return e.\u0275fac=function(t){return new(t||e)(L(Dt))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */const kF=G1(bR,"browser",[{provide:dc,useValue:OC},{provide:R1,useValue:function TF(){Hm.makeCurrent()},multi:!0},{provide:Dt,useFactory:function AF(){return function WE(e){yp=e}(document),document},deps:[]}]),JC=new q(""),QC=[{provide:kd,useClass: -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -class gF{addToWindow(n){We.getAngularTestability=(i,r=!0)=>{const o=n.findTestabilityInTree(i,r);if(null==o)throw new Error("Could not find testability for element.");return o},We.getAllAngularTestabilities=()=>n.getAllTestabilities(),We.getAllAngularRootElements=()=>n.getAllRootElements(),We.frameworkStabilizers||(We.frameworkStabilizers=[]),We.frameworkStabilizers.push(i=>{const r=We.getAllAngularTestabilities();let o=r.length,s=!1;const a=function(l){s=s||l,o--,0==o&&i(s)};r.forEach(function(l){l.whenStable(a)})})}findTestabilityInTree(n,t,i){return null==t?null:n.getTestability(t)??(i?lr().isShadowRoot(t)?this.findTestabilityInTree(n,t.host,!0):this.findTestabilityInTree(n,t.parentElement,!0):null)}},deps:[]},{provide:H1,useClass:fm,deps:[Ye,hm,kd]},{provide:fm,useClass:fm,deps:[Ye,hm,kd]}],XC=[{provide:Ap,useValue:"root"},{provide:da,useFactory:function IF(){return new da},deps:[]},{provide:Kd,useClass:SF,multi:!0,deps:[Dt,Ye,dc]},{provide:Kd,useClass:EF,multi:!0,deps:[Dt]},{provide:Um,useClass:Um,deps:[qd,yc,uc]},{provide:Rp,useExisting:Um},{provide:jC,useExisting:yc},{provide:yc,useClass:yc,deps:[Dt]},{provide:qd,useClass:qd,deps:[Kd,Ye]},{provide:PC,useClass:mF,deps:[]},[]];let OF=(()=>{class e{constructor(t){}static withServerTransition(t){return{ngModule:e,providers:[{provide:uc,useValue:t.appId},{provide:BC,useExisting:uc},pF]}}}return e.\u0275fac=function(t){return new(t||e)(L(JC,12))},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({providers:[...XC,...QC],imports:[ei,DR]}),e})(),ew=(()=>{class e{constructor(t){this._doc=t}getTitle(){return this._doc.title}setTitle(t){this._doc.title=t||""}}return e.\u0275fac=function(t){return new(t||e)(L(Dt))},e.\u0275prov=G({token:e,factory:function(t){let i=null;return i=t?new t: -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -function RF(){return new ew(L(Dt))}(),i},providedIn:"root"}),e})(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -function J(...e){return gt(e,en(e))}typeof window<"u"&&window;class Yt extends Ue{constructor(n){super(),this._value=n}get value(){return this.getValue()}_subscribe(n){const t=super._subscribe(n);return!t.closed&&n.next(this._value),t}getValue(){const{hasError:n,thrownError:t,_value:i}=this;if(n)throw t;return this._throwIfClosed(),i}next(n){super.next(this._value=n)}}const bc=V(e=>function(){e(this),this.name="EmptyError",this.message="no elements in sequence"}),{isArray:$F}=Array,{getPrototypeOf:UF,prototype:GF,keys:WF}=Object;function iw(e){if(1===e.length){const n=e[0];if($F(n))return{args:n,keys:null};if(function zF(e){return e&&"object"==typeof e&&UF(e)===GF}(n)){const t=WF(n);return{args:t.map(i=>n[i]),keys:t}}}return{args:e,keys:null}}const{isArray:YF}=Array;function Ym(e){return ne(n=>function KF(e,n){return YF(n)?e(...n):e(n)}(e,n))}function rw(e,n){return e.reduce((t,i,r)=>(t[i]=n[r],t),{})}function Jd(...e){const n=en(e),t=rt(e),{args:i,keys:r}=iw(e);if(0===i.length)return gt([],n);const o=new je(function qF(e,n,t=Rn){return i=>{ow(n,()=>{const{length:r}=e,o=new Array(r);let s=r,a=r;for(let l=0;l{const u=gt(e[l],n);let f=!1;u.subscribe(Oe(i,p=>{o[l]=p,f||(f=!0,a--),a||i.next(t(o.slice()))},()=>{--s||i.complete()}))},i)},i)}}(i,n,r?s=>rw(r,s):Rn));return t?o.pipe(Ym(t)):o}function ow(e,n,t){e?wi(t,e,n):n()}function Dc(...e){return function ZF(){return Se(1)}()(gt(e,en(e)))}function sw(e){return new je(n=>{ut(e()).subscribe(n)})}function xa(e,n){const t=ye(e)?e:()=>e,i=r=>r.error(t());return new je(n?r=>n.schedule(i,0,r):i)}function Km(){return qe((e,n)=>{let t=null;e._refCount++;const i=Oe(n,void 0,void 0,void 0,()=>{if(!e||e._refCount<=0||0<--e._refCount)return void(t=null);const r=e._connection,o=t;t=null,r&&(!o||r===o)&&r.unsubscribe(),n.unsubscribe()});e.subscribe(i),i.closed||(t=e.connect())})}class aw extends je{constructor(n,t){super(),this.source=n,this.subjectFactory=t,this._subject=null,this._refCount=0,this._connection=null,Y(n)&&(this.lift=n.lift)}_subscribe(n){return this.getSubject().subscribe(n)}getSubject(){const n=this._subject;return(!n||n.isStopped)&&(this._subject=this.subjectFactory()),this._subject}_teardown(){this._refCount=0;const{_connection:n}=this;this._subject=this._connection=null,n?.unsubscribe()}connect(){let n=this._connection;if(!n){n=this._connection=new Ct;const t=this.getSubject();n.add(this.source.subscribe(Oe(t,void 0,()=>{this._teardown(),t.complete()},i=>{this._teardown(),t.error(i)},()=>this._teardown()))),n.closed&&(this._connection=null,n=Ct.EMPTY)}return n}refCount(){return Km()(this)}}function vi(e,n){return qe((t,i)=>{let r=null,o=0,s=!1;const a=()=>s&&!r&&i.complete();t.subscribe(Oe(i,l=>{r?.unsubscribe();let u=0;const f=o++;ut(e(l,f)).subscribe(r=Oe(i,p=>i.next(n?n(l,p,f,u++):p),()=>{r=null,a()}))},()=>{s=!0,a()}))})}function sn(e){return e<=0?()=>Xt:qe((n,t)=>{let i=0;n.subscribe(Oe(t,r=>{++i<=e&&(t.next(r),e<=i&&t.complete())}))})}function vn(e,n){return qe((t,i)=>{let r=0;t.subscribe(Oe(i,o=>e.call(n,o,r++)&&i.next(o)))})}function Xd(e){return qe((n,t)=>{let i=!1;n.subscribe(Oe(t,r=>{i=!0,t.next(r)},()=>{i||t.next(e),t.complete()}))})}function lw(e=JF){return qe((n,t)=>{let i=!1;n.subscribe(Oe(t,r=>{i=!0,t.next(r)},()=>i?t.complete():t.error(e())))})}function JF(){return new bc}function mo(e,n){const t=arguments.length>=2;return i=>i.pipe(e?vn((r,o)=>e(r,o,i)):Rn,sn(1),t?Xd(n):lw(()=>new bc))}function _o(e,n){return ye(n)?dt(e,n,1):dt(e,1)}function Kt(e,n,t){const i=ye(e)||n||t?{next:e,error:n,complete:t}:e;return i?qe((r,o)=>{var s;null===(s=i.subscribe)||void 0===s||s.call(i);let a=!0;r.subscribe(Oe(o,l=>{var u;null===(u=i.next)||void 0===u||u.call(i,l),o.next(l)},()=>{var l;a=!1,null===(l=i.complete)||void 0===l||l.call(i),o.complete()},l=>{var u;a=!1,null===(u=i.error)||void 0===u||u.call(i,l),o.error(l)},()=>{var l,u;a&&(null===(l=i.unsubscribe)||void 0===l||l.call(i)),null===(u=i.finalize)||void 0===u||u.call(i)}))}):Rn}function $r(e){return qe((n,t)=>{let o,i=null,r=!1;i=n.subscribe(Oe(t,void 0,void 0,s=>{o=ut(e(s,$r(e)(n))),i?(i.unsubscribe(),i=null,o.subscribe(t)):r=!0})),r&&(i.unsubscribe(),i=null,o.subscribe(t))})}function QF(e,n,t,i,r){return(o,s)=>{let a=t,l=n,u=0;o.subscribe(Oe(s,f=>{const p=u++;l=a?e(l,f,p):(a=!0,f),i&&s.next(l)},r&&(()=>{a&&s.next(l),s.complete()})))}}function cw(e,n){return qe(QF(e,n,arguments.length>=2,!0))}function qm(e){return e<=0?()=>Xt:qe((n,t)=>{let i=[];n.subscribe(Oe(t,r=>{i.push(r),e{for(const r of i)t.next(r);t.complete()},void 0,()=>{i=null}))})}function uw(e,n){const t=arguments.length>=2;return i=>i.pipe(e?vn((r,o)=>e(r,o,i)):Rn,qm(1),t?Xd(n):lw(()=>new bc))}function Zm(e){return qe((n,t)=>{try{n.subscribe(t)}finally{t.add(e)}})} -/** - * @license Angular v14.2.9 - * (c) 2010-2022 Google LLC. https://angular.io/ - * License: MIT - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */const pe="primary",Cc=Symbol("RouteTitle");class eL{constructor(n){this.params=n||{}}has(n){return Object.prototype.hasOwnProperty.call(this.params,n)}get(n){if(this.has(n)){const t=this.params[n];return Array.isArray(t)?t[0]:t}return null}getAll(n){if(this.has(n)){const t=this.params[n];return Array.isArray(t)?t:[t]}return[]}get keys(){return Object.keys(this.params)}}function Ra(e){return new eL(e)}function tL(e,n,t){const i=t.path.split("/");if(i.length>e.length||"full"===t.pathMatch&&(n.hasChildren()||i.lengthi[o]===r)}return e===n}function hw(e){return Array.prototype.concat.apply([],e)}function pw(e){return e.length>0?e[e.length-1]:null}function an(e,n){for(const t in e)e.hasOwnProperty(t)&&n(e[t],t)}function vo(e){return Rg(e)?e:Xl(e)?gt(Promise.resolve(e)):J(e)} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */const rL={exact:function _w(e,n,t){if(!rs(e.segments,n.segments)||!ef(e.segments,n.segments,t)||e.numberOfChildren!==n.numberOfChildren)return!1;for(const i in n.children)if(!e.children[i]||!_w(e.children[i],n.children[i],t))return!1;return!0},subset:vw},gw={exact:function oL(e,n){return cr(e,n)},subset:function sL(e,n){return Object.keys(n).length<=Object.keys(e).length&&Object.keys(n).every(t=>fw(e[t],n[t]))},ignored:()=>!0};function mw(e,n,t){return rL[t.paths](e.root,n.root,t.matrixParams)&&gw[t.queryParams](e.queryParams,n.queryParams)&&!("exact"===t.fragment&&e.fragment!==n.fragment)}function vw(e,n,t){return yw(e,n,n.segments,t)}function yw(e,n,t,i){if(e.segments.length>t.length){const r=e.segments.slice(0,t.length);return!(!rs(r,t)||n.hasChildren()||!ef(r,t,i))}if(e.segments.length===t.length){if(!rs(e.segments,t)||!ef(e.segments,t,i))return!1;for(const r in n.children)if(!e.children[r]||!vw(e.children[r],n.children[r],i))return!1;return!0}{const r=t.slice(0,e.segments.length),o=t.slice(e.segments.length);return!!(rs(e.segments,r)&&ef(e.segments,r,i)&&e.children[pe])&&yw(e.children[pe],n,o,i)}}function ef(e,n,t){return n.every((i,r)=>gw[t](e[r].parameters,i.parameters))}class is{constructor(n,t,i){this.root=n,this.queryParams=t,this.fragment=i}get queryParamMap(){return this._queryParamMap||(this._queryParamMap=Ra(this.queryParams)),this._queryParamMap}toString(){return cL.serialize(this)}}class me{constructor(n,t){this.segments=n,this.children=t,this.parent=null,an(t,(i,r)=>i.parent=this)}hasChildren(){return this.numberOfChildren>0}get numberOfChildren(){return Object.keys(this.children).length}toString(){return tf(this)}}class wc{constructor(n,t){this.path=n,this.parameters=t}get parameterMap(){return this._parameterMap||(this._parameterMap=Ra(this.parameters)),this._parameterMap}toString(){return ww(this)}}function rs(e,n){return e.length===n.length&&e.every((t,i)=>t.path===n[i].path)}let bw=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:function(){return new Qm},providedIn:"root"}),e})();class Qm{parse(n){const t=new vL(n);return new is(t.parseRootSegment(),t.parseQueryParams(),t.parseFragment())}serialize(n){const t=`/${Sc(n.root,!0)}`,i=function fL(e){const n=Object.keys(e).map(t=>{const i=e[t];return Array.isArray(i)?i.map(r=>`${nf(t)}=${nf(r)}`).join("&"):`${nf(t)}=${nf(i)}`}).filter(t=>!!t);return n.length?`?${n.join("&")}`:""}(n.queryParams);return`${t}${i}${"string"==typeof n.fragment?`#${function uL(e){return encodeURI(e)}(n.fragment)}`:""}`}}const cL=new Qm;function tf(e){return e.segments.map(n=>ww(n)).join("/")}function Sc(e,n){if(!e.hasChildren())return tf(e);if(n){const t=e.children[pe]?Sc(e.children[pe],!1):"",i=[];return an(e.children,(r,o)=>{o!==pe&&i.push(`${o}:${Sc(r,!1)}`)}),i.length>0?`${t}(${i.join("//")})`:t}{const t=function lL(e,n){let t=[];return an(e.children,(i,r)=>{r===pe&&(t=t.concat(n(i,r)))}),an(e.children,(i,r)=>{r!==pe&&(t=t.concat(n(i,r)))}),t}(e,(i,r)=>r===pe?[Sc(e.children[pe],!1)]:[`${r}:${Sc(i,!1)}`]);return 1===Object.keys(e.children).length&&null!=e.children[pe]?`${tf(e)}/${t[0]}`:`${tf(e)}/(${t.join("//")})`}}function Dw(e){return encodeURIComponent(e).replace(/%40/g,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",")}function nf(e){return Dw(e).replace(/%3B/gi,";")}function Xm(e){return Dw(e).replace(/\(/g,"%28").replace(/\)/g,"%29").replace(/%26/gi,"&")}function rf(e){return decodeURIComponent(e)}function Cw(e){return rf(e.replace(/\+/g,"%20"))}function ww(e){return`${Xm(e.path)}${function dL(e){return Object.keys(e).map(n=>`;${Xm(n)}=${Xm(e[n])}`).join("")}(e.parameters)}`}const hL=/^[^\/()?;=#]+/;function sf(e){const n=e.match(hL);return n?n[0]:""}const pL=/^[^=?&#]+/,mL=/^[^&#]+/;class vL{constructor(n){this.url=n,this.remaining=n}parseRootSegment(){return this.consumeOptional("/"),""===this.remaining||this.peekStartsWith("?")||this.peekStartsWith("#")?new me([],{}):new me([],this.parseChildren())}parseQueryParams(){const n={};if(this.consumeOptional("?"))do{this.parseQueryParam(n)}while(this.consumeOptional("&"));return n}parseFragment(){return this.consumeOptional("#")?decodeURIComponent(this.remaining):null}parseChildren(){if(""===this.remaining)return{};this.consumeOptional("/");const n=[];for(this.peekStartsWith("(")||n.push(this.parseSegment());this.peekStartsWith("/")&&!this.peekStartsWith("//")&&!this.peekStartsWith("/(");)this.capture("/"),n.push(this.parseSegment());let t={};this.peekStartsWith("/(")&&(this.capture("/"),t=this.parseParens(!0));let i={};return this.peekStartsWith("(")&&(i=this.parseParens(!1)),(n.length>0||Object.keys(t).length>0)&&(i[pe]=new me(n,t)),i}parseSegment(){const n=sf(this.remaining);if(""===n&&this.peekStartsWith(";"))throw new F(4009,!1);return this.capture(n),new wc(rf(n),this.parseMatrixParams())}parseMatrixParams(){const n={};for(;this.consumeOptional(";");)this.parseParam(n);return n}parseParam(n){const t=sf(this.remaining);if(!t)return;this.capture(t);let i="";if(this.consumeOptional("=")){const r=sf(this.remaining);r&&(i=r,this.capture(i))}n[rf(t)]=rf(i)}parseQueryParam(n){const t=function gL(e){const n=e.match(pL);return n?n[0]:""}(this.remaining);if(!t)return;this.capture(t);let i="";if(this.consumeOptional("=")){const s=function _L(e){const n=e.match(mL);return n?n[0]:""}(this.remaining);s&&(i=s,this.capture(i))}const r=Cw(t),o=Cw(i);if(n.hasOwnProperty(r)){let s=n[r];Array.isArray(s)||(s=[s],n[r]=s),s.push(o)}else n[r]=o}parseParens(n){const t={};for(this.capture("(");!this.consumeOptional(")")&&this.remaining.length>0;){const i=sf(this.remaining),r=this.remaining[i.length];if("/"!==r&&")"!==r&&";"!==r)throw new F(4010,!1);let o;i.indexOf(":")>-1?(o=i.slice(0,i.indexOf(":")),this.capture(o),this.capture(":")):n&&(o=pe);const s=this.parseChildren();t[o]=1===Object.keys(s).length?s[pe]:new me([],s),this.consumeOptional("//")}return t}peekStartsWith(n){return this.remaining.startsWith(n)}consumeOptional(n){return!!this.peekStartsWith(n)&&(this.remaining=this.remaining.substring(n.length),!0)}capture(n){if(!this.consumeOptional(n))throw new F(4011,!1)}}function e_(e){return e.segments.length>0?new me([],{[pe]:e}):e}function af(e){const n={};for(const i of Object.keys(e.children)){const o=af(e.children[i]);(o.segments.length>0||o.hasChildren())&&(n[i]=o)}return function yL(e){if(1===e.numberOfChildren&&e.children[pe]){const n=e.children[pe];return new me(e.segments.concat(n.segments),n.children)}return e}(new me(e.segments,n))}function os(e){return e instanceof is} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */function CL(e,n,t,i,r){if(0===t.length)return Pa(n.root,n.root,n.root,i,r);const o=function Nw(e){if("string"==typeof e[0]&&1===e.length&&"/"===e[0])return new Mw(!0,0,e);let n=0,t=!1;const i=e.reduce((r,o,s)=>{if("object"==typeof o&&null!=o){if(o.outlets){const a={};return an(o.outlets,(l,u)=>{a[u]="string"==typeof l?l.split("/"):l}),[...r,{outlets:a}]}if(o.segmentPath)return[...r,o.segmentPath]}return"string"!=typeof o?[...r,o]:0===s?(o.split("/").forEach((a,l)=>{0==l&&"."===a||(0==l&&""===a?t=!0:".."===a?n++:""!=a&&r.push(a))}),r):[...r,o]},[]);return new Mw(t,n,i)}(t);return o.toRoot()?Pa(n.root,n.root,new me([],{}),i,r):function s(l){const u=function SL(e,n,t,i){if(e.isAbsolute)return new Fa(n.root,!0,0);if(-1===i)return new Fa(t,t===n.root,0);return function Ew(e,n,t){let i=e,r=n,o=t;for(;o>r;){if(o-=r,i=i.parent,!i)throw new F(4005,!1);r=i.segments.length}return new Fa(i,!1,r-o)}(t,i+(Mc(e.commands[0])?0:1),e.numberOfDoubleDots)}(o,n,e.snapshot?._urlSegment,l),f=u.processChildren?Ec(u.segmentGroup,u.index,o.commands):n_(u.segmentGroup,u.index,o.commands);return Pa(n.root,u.segmentGroup,f,i,r)}(e.snapshot?._lastPathIndex)}function Mc(e){return"object"==typeof e&&null!=e&&!e.outlets&&!e.segmentPath}function Nc(e){return"object"==typeof e&&null!=e&&e.outlets}function Pa(e,n,t,i,r){let s,o={};i&&an(i,(l,u)=>{o[u]=Array.isArray(l)?l.map(f=>`${f}`):`${l}`}),s=e===n?t:Sw(e,n,t);const a=e_(af(s));return new is(a,o,r)}function Sw(e,n,t){const i={};return an(e.children,(r,o)=>{i[o]=r===n?t:Sw(r,n,t)}),new me(e.segments,i)}class Mw{constructor(n,t,i){if(this.isAbsolute=n,this.numberOfDoubleDots=t,this.commands=i,n&&i.length>0&&Mc(i[0]))throw new F(4003,!1);const r=i.find(Nc);if(r&&r!==pw(i))throw new F(4004,!1)}toRoot(){return this.isAbsolute&&1===this.commands.length&&"/"==this.commands[0]}}class Fa{constructor(n,t,i){this.segmentGroup=n,this.processChildren=t,this.index=i}}function n_(e,n,t){if(e||(e=new me([],{})),0===e.segments.length&&e.hasChildren())return Ec(e,n,t);const i=function NL(e,n,t){let i=0,r=n;const o={match:!1,pathIndex:0,commandIndex:0};for(;r=t.length)return o;const s=e.segments[r],a=t[i];if(Nc(a))break;const l=`${a}`,u=i0&&void 0===l)break;if(l&&u&&"object"==typeof u&&void 0===u.outlets){if(!Iw(l,u,s))return o;i+=2}else{if(!Iw(l,{},s))return o;i++}r++}return{match:!0,pathIndex:r,commandIndex:i}}(e,n,t),r=t.slice(i.commandIndex);if(i.match&&i.pathIndex{"string"==typeof o&&(o=[o]),null!==o&&(r[s]=n_(e.children[s],n,o))}),an(e.children,(o,s)=>{void 0===i[s]&&(r[s]=o)}),new me(e.segments,r)}}function i_(e,n,t){const i=e.segments.slice(0,n);let r=0;for(;r{"string"==typeof t&&(t=[t]),null!==t&&(n[i]=i_(new me([],{}),0,t))}),n}function Tw(e){const n={};return an(e,(t,i)=>n[i]=`${t}`),n}function Iw(e,n,t){return e==t.path&&cr(n,t.parameters)} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */class Ur{constructor(n,t){this.id=n,this.url=t}}class r_ extends Ur{constructor(n,t,i="imperative",r=null){super(n,t),this.type=0,this.navigationTrigger=i,this.restoredState=r}toString(){return`NavigationStart(id: ${this.id}, url: '${this.url}')`}}class ss extends Ur{constructor(n,t,i){super(n,t),this.urlAfterRedirects=i,this.type=1}toString(){return`NavigationEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}')`}}class lf extends Ur{constructor(n,t,i,r){super(n,t),this.reason=i,this.code=r,this.type=2}toString(){return`NavigationCancel(id: ${this.id}, url: '${this.url}')`}}class Aw extends Ur{constructor(n,t,i,r){super(n,t),this.error=i,this.target=r,this.type=3}toString(){return`NavigationError(id: ${this.id}, url: '${this.url}', error: ${this.error})`}}class TL extends Ur{constructor(n,t,i,r){super(n,t),this.urlAfterRedirects=i,this.state=r,this.type=4}toString(){return`RoutesRecognized(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`}}class IL extends Ur{constructor(n,t,i,r){super(n,t),this.urlAfterRedirects=i,this.state=r,this.type=7}toString(){return`GuardsCheckStart(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`}}class AL extends Ur{constructor(n,t,i,r,o){super(n,t),this.urlAfterRedirects=i,this.state=r,this.shouldActivate=o,this.type=8}toString(){return`GuardsCheckEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state}, shouldActivate: ${this.shouldActivate})`}}class kL extends Ur{constructor(n,t,i,r){super(n,t),this.urlAfterRedirects=i,this.state=r,this.type=5}toString(){return`ResolveStart(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`}}class OL extends Ur{constructor(n,t,i,r){super(n,t),this.urlAfterRedirects=i,this.state=r,this.type=6}toString(){return`ResolveEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`}}class xL{constructor(n){this.route=n,this.type=9}toString(){return`RouteConfigLoadStart(path: ${this.route.path})`}}class RL{constructor(n){this.route=n,this.type=10}toString(){return`RouteConfigLoadEnd(path: ${this.route.path})`}}class PL{constructor(n){this.snapshot=n,this.type=11}toString(){return`ChildActivationStart(path: '${this.snapshot.routeConfig&&this.snapshot.routeConfig.path||""}')`}}class FL{constructor(n){this.snapshot=n,this.type=12}toString(){return`ChildActivationEnd(path: '${this.snapshot.routeConfig&&this.snapshot.routeConfig.path||""}')`}}class LL{constructor(n){this.snapshot=n,this.type=13}toString(){return`ActivationStart(path: '${this.snapshot.routeConfig&&this.snapshot.routeConfig.path||""}')`}}class VL{constructor(n){this.snapshot=n,this.type=14}toString(){return`ActivationEnd(path: '${this.snapshot.routeConfig&&this.snapshot.routeConfig.path||""}')`}}class kw{constructor(n,t,i){this.routerEvent=n,this.position=t,this.anchor=i,this.type=15}toString(){return`Scroll(anchor: '${this.anchor}', position: '${this.position?`${this.position[0]}, ${this.position[1]}`:null}')`}} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -class Ow{constructor(n){this._root=n}get root(){return this._root.value}parent(n){const t=this.pathFromRoot(n);return t.length>1?t[t.length-2]:null}children(n){const t=o_(n,this._root);return t?t.children.map(i=>i.value):[]}firstChild(n){const t=o_(n,this._root);return t&&t.children.length>0?t.children[0].value:null}siblings(n){const t=s_(n,this._root);return t.length<2?[]:t[t.length-2].children.map(r=>r.value).filter(r=>r!==n)}pathFromRoot(n){return s_(n,this._root).map(t=>t.value)}}function o_(e,n){if(e===n.value)return n;for(const t of n.children){const i=o_(e,t);if(i)return i}return null}function s_(e,n){if(e===n.value)return[n];for(const t of n.children){const i=s_(e,t);if(i.length)return i.unshift(n),i}return[]}class Gr{constructor(n,t){this.value=n,this.children=t}toString(){return`TreeNode(${this.value})`}}function La(e){const n={};return e&&e.children.forEach(t=>n[t.value.outlet]=t),n -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */}class xw extends Ow{constructor(n,t){super(n),this.snapshot=t,a_(this,n)}toString(){return this.snapshot.toString()}}function Rw(e,n){const t=function HL(e,n){const s=new cf([],{},{},"",{},pe,n,null,e.root,-1,{});return new Fw("",new Gr(s,[]))}(e,n),i=new Yt([new wc("",{})]),r=new Yt({}),o=new Yt({}),s=new Yt({}),a=new Yt(""),l=new as(i,r,s,a,o,pe,n,t.root);return l.snapshot=t.root,new xw(new Gr(l,[]),t)}class as{constructor(n,t,i,r,o,s,a,l){this.url=n,this.params=t,this.queryParams=i,this.fragment=r,this.data=o,this.outlet=s,this.component=a,this.title=this.data?.pipe(ne(u=>u[Cc]))??J(void 0),this._futureSnapshot=l}get routeConfig(){return this._futureSnapshot.routeConfig}get root(){return this._routerState.root}get parent(){return this._routerState.parent(this)}get firstChild(){return this._routerState.firstChild(this)}get children(){return this._routerState.children(this)}get pathFromRoot(){return this._routerState.pathFromRoot(this)}get paramMap(){return this._paramMap||(this._paramMap=this.params.pipe(ne(n=>Ra(n)))),this._paramMap}get queryParamMap(){return this._queryParamMap||(this._queryParamMap=this.queryParams.pipe(ne(n=>Ra(n)))),this._queryParamMap}toString(){return this.snapshot?this.snapshot.toString():`Future(${this._futureSnapshot})`}}function Pw(e,n="emptyOnly"){const t=e.pathFromRoot;let i=0;if("always"!==n)for(i=t.length-1;i>=1;){const r=t[i],o=t[i-1];if(r.routeConfig&&""===r.routeConfig.path)i--;else{if(o.component)break;i--}}return function jL(e){return e.reduce((n,t)=>({params:{...n.params,...t.params},data:{...n.data,...t.data},resolve:{...t.data,...n.resolve,...t.routeConfig?.data,...t._resolvedData}}),{params:{},data:{},resolve:{}})}(t.slice(i))}class cf{constructor(n,t,i,r,o,s,a,l,u,f,p,m){this.url=n,this.params=t,this.queryParams=i,this.fragment=r,this.data=o,this.outlet=s,this.component=a,this.title=this.data?.[Cc],this.routeConfig=l,this._urlSegment=u,this._lastPathIndex=f,this._correctedLastPathIndex=m??f,this._resolve=p}get root(){return this._routerState.root}get parent(){return this._routerState.parent(this)}get firstChild(){return this._routerState.firstChild(this)}get children(){return this._routerState.children(this)}get pathFromRoot(){return this._routerState.pathFromRoot(this)}get paramMap(){return this._paramMap||(this._paramMap=Ra(this.params)),this._paramMap}get queryParamMap(){return this._queryParamMap||(this._queryParamMap=Ra(this.queryParams)),this._queryParamMap}toString(){return`Route(url:'${this.url.map(i=>i.toString()).join("/")}', path:'${this.routeConfig?this.routeConfig.path:""}')`}}class Fw extends Ow{constructor(n,t){super(t),this.url=n,a_(this,t)}toString(){return Lw(this._root)}}function a_(e,n){n.value._routerState=e,n.children.forEach(t=>a_(e,t))}function Lw(e){const n=e.children.length>0?` { ${e.children.map(Lw).join(", ")} } `:"";return`${e.value}${n}`}function l_(e){if(e.snapshot){const n=e.snapshot,t=e._futureSnapshot;e.snapshot=t,cr(n.queryParams,t.queryParams)||e.queryParams.next(t.queryParams),n.fragment!==t.fragment&&e.fragment.next(t.fragment),cr(n.params,t.params)||e.params.next(t.params),function nL(e,n){if(e.length!==n.length)return!1;for(let t=0;tcr(t.parameters,n[i].parameters))}(e.url,n.url);return t&&!(!e.parent!=!n.parent)&&(!e.parent||c_(e.parent,n.parent))} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */function Tc(e,n,t){if(t&&e.shouldReuseRoute(n.value,t.value.snapshot)){const i=t.value;i._futureSnapshot=n.value;const r=function UL(e,n,t){return n.children.map(i=>{for(const r of t.children)if(e.shouldReuseRoute(i.value,r.value.snapshot))return Tc(e,i,r);return Tc(e,i)})}(e,n,t);return new Gr(i,r)}{if(e.shouldAttach(n.value)){const o=e.retrieve(n.value);if(null!==o){const s=o.route;return s.value._futureSnapshot=n.value,s.children=n.children.map(a=>Tc(e,a)),s}}const i=function GL(e){return new as(new Yt(e.url),new Yt(e.params),new Yt(e.queryParams),new Yt(e.fragment),new Yt(e.data),e.outlet,e.component,e)} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */(n.value),r=n.children.map(o=>Tc(e,o));return new Gr(i,r)}}const u_="ngNavigationCancelingError";function Vw(e,n){const{redirectTo:t,navigationBehaviorOptions:i}=os(n)?{redirectTo:n,navigationBehaviorOptions:void 0}:n,r=Bw(!1,0,n);return r.url=t,r.navigationBehaviorOptions=i,r}function Bw(e,n,t){const i=new Error("NavigationCancelingError: "+(e||""));return i[u_]=!0,i.cancellationCode=n,t&&(i.url=t),i}function Hw(e){return jw(e)&&os(e.url)}function jw(e){return e&&e[u_]} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */class WL{constructor(){this.outlet=null,this.route=null,this.resolver=null,this.injector=null,this.children=new Ic,this.attachRef=null}}let Ic=(()=>{class e{constructor(){this.contexts=new Map}onChildOutletCreated(t,i){const r=this.getOrCreateContext(t);r.outlet=i,this.contexts.set(t,r)}onChildOutletDestroyed(t){const i=this.getContext(t);i&&(i.outlet=null,i.attachRef=null)}onOutletDeactivated(){const t=this.contexts;return this.contexts=new Map,t}onOutletReAttached(t){this.contexts=t}getOrCreateContext(t){let i=this.getContext(t);return i||(i=new WL,this.contexts.set(t,i)),i}getContext(t){return this.contexts.get(t)||null}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */const uf=!1;let d_=(()=>{class e{constructor(t,i,r,o,s){this.parentContexts=t,this.location=i,this.changeDetector=o,this.environmentInjector=s,this.activated=null,this._activatedRoute=null,this.activateEvents=new ue,this.deactivateEvents=new ue,this.attachEvents=new ue,this.detachEvents=new ue,this.name=r||pe,t.onChildOutletCreated(this.name,this)}ngOnDestroy(){this.parentContexts.getContext(this.name)?.outlet===this&&this.parentContexts.onChildOutletDestroyed(this.name)}ngOnInit(){if(!this.activated){const t=this.parentContexts.getContext(this.name);t&&t.route&&(t.attachRef?this.attach(t.attachRef,t.route):this.activateWith(t.route,t.injector))}}get isActivated(){return!!this.activated}get component(){if(!this.activated)throw new F(4012,uf);return this.activated.instance}get activatedRoute(){if(!this.activated)throw new F(4012,uf);return this._activatedRoute}get activatedRouteData(){return this._activatedRoute?this._activatedRoute.snapshot.data:{}}detach(){if(!this.activated)throw new F(4012,uf);this.location.detach();const t=this.activated;return this.activated=null,this._activatedRoute=null,this.detachEvents.emit(t.instance),t}attach(t,i){this.activated=t,this._activatedRoute=i,this.location.insert(t.hostView),this.attachEvents.emit(t.instance)}deactivate(){if(this.activated){const t=this.component;this.activated.destroy(),this.activated=null,this._activatedRoute=null,this.deactivateEvents.emit(t)}}activateWith(t,i){if(this.isActivated)throw new F(4013,uf);this._activatedRoute=t;const r=this.location,s=t._futureSnapshot.component,a=this.parentContexts.getOrCreateContext(this.name).children,l=new zL(t,a,r.injector);if(i&&function YL(e){return!!e.resolveComponentFactory} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */(i)){const u=i.resolveComponentFactory(s);this.activated=r.createComponent(u,r.length,l)}else this.activated=r.createComponent(s,{index:r.length,injector:l,environmentInjector:i??this.environmentInjector});this.changeDetector.markForCheck(),this.activateEvents.emit(this.activated.instance)}}return e.\u0275fac=function(t){return new(t||e)(C(Ic),C(Hi),function zo(e){return function De(e,n){if("class"===n)return e.classes;if("style"===n)return e.styles;const t=e.attrs;if(t){const i=t.length;let r=0;for(;r{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275cmp=et({type:e,selectors:[["ng-component"]],standalone:!0,features:[KD],decls:1,vars:0,template:function(t,i){1&t&&Li(0,"router-outlet")},dependencies:[d_],encapsulation:2}),e})(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */function $w(e,n){return e.providers&&!e._injector&&(e._injector=bd(e.providers,n,`Route: ${e.path}`)),e._injector??n}function p_(e){const n=e.children&&e.children.map(p_),t=n?{...e,children:n}:{...e};return!t.component&&!t.loadComponent&&(n||t.loadChildren)&&t.outlet&&t.outlet!==pe&&(t.component=f_),t}function yi(e){return e.outlet||pe}function Uw(e,n){const t=e.filter(i=>yi(i)===n);return t.push(...e.filter(i=>yi(i)!==n)),t}function Ac(e){if(!e)return null;if(e.routeConfig?._injector)return e.routeConfig._injector;for(let n=e.parent;n;n=n.parent){const t=n.routeConfig;if(t?._loadedInjector)return t._loadedInjector;if(t?._injector)return t._injector}return null} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */class QL{constructor(n,t,i,r){this.routeReuseStrategy=n,this.futureState=t,this.currState=i,this.forwardEvent=r}activate(n){const t=this.futureState._root,i=this.currState?this.currState._root:null;this.deactivateChildRoutes(t,i,n),l_(this.futureState.root),this.activateChildRoutes(t,i,n)}deactivateChildRoutes(n,t,i){const r=La(t);n.children.forEach(o=>{const s=o.value.outlet;this.deactivateRoutes(o,r[s],i),delete r[s]}),an(r,(o,s)=>{this.deactivateRouteAndItsChildren(o,i)})}deactivateRoutes(n,t,i){const r=n.value,o=t?t.value:null;if(r===o)if(r.component){const s=i.getContext(r.outlet);s&&this.deactivateChildRoutes(n,t,s.children)}else this.deactivateChildRoutes(n,t,i);else o&&this.deactivateRouteAndItsChildren(t,i)}deactivateRouteAndItsChildren(n,t){n.value.component&&this.routeReuseStrategy.shouldDetach(n.value.snapshot)?this.detachAndStoreRouteSubtree(n,t):this.deactivateRouteAndOutlet(n,t)}detachAndStoreRouteSubtree(n,t){const i=t.getContext(n.value.outlet),r=i&&n.value.component?i.children:t,o=La(n);for(const s of Object.keys(o))this.deactivateRouteAndItsChildren(o[s],r);if(i&&i.outlet){const s=i.outlet.detach(),a=i.children.onOutletDeactivated();this.routeReuseStrategy.store(n.value.snapshot,{componentRef:s,route:n,contexts:a})}}deactivateRouteAndOutlet(n,t){const i=t.getContext(n.value.outlet),r=i&&n.value.component?i.children:t,o=La(n);for(const s of Object.keys(o))this.deactivateRouteAndItsChildren(o[s],r);i&&i.outlet&&(i.outlet.deactivate(),i.children.onOutletDeactivated(),i.attachRef=null,i.resolver=null,i.route=null)}activateChildRoutes(n,t,i){const r=La(t);n.children.forEach(o=>{this.activateRoutes(o,r[o.value.outlet],i),this.forwardEvent(new VL(o.value.snapshot))}),n.children.length&&this.forwardEvent(new FL(n.value.snapshot))}activateRoutes(n,t,i){const r=n.value,o=t?t.value:null;if(l_(r),r===o)if(r.component){const s=i.getOrCreateContext(r.outlet);this.activateChildRoutes(n,t,s.children)}else this.activateChildRoutes(n,t,i);else if(r.component){const s=i.getOrCreateContext(r.outlet);if(this.routeReuseStrategy.shouldAttach(r.snapshot)){const a=this.routeReuseStrategy.retrieve(r.snapshot);this.routeReuseStrategy.store(r.snapshot,null),s.children.onOutletReAttached(a.contexts),s.attachRef=a.componentRef,s.route=a.route.value,s.outlet&&s.outlet.attach(a.componentRef,a.route.value),l_(a.route.value),this.activateChildRoutes(n,null,s.children)}else{const a=Ac(r.snapshot),l=a?.get(Gl)??null;s.attachRef=null,s.route=r,s.resolver=l,s.injector=a,s.outlet&&s.outlet.activateWith(r,s.injector),this.activateChildRoutes(n,null,s.children)}}else this.activateChildRoutes(n,null,i)}} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */class Gw{constructor(n){this.path=n,this.route=this.path[this.path.length-1]}}class df{constructor(n,t){this.component=n,this.route=t}}function XL(e,n,t){const i=e._root;return kc(i,n?n._root:null,t,[i.value])}function Va(e,n){const t=Symbol(),i=n.get(e,t);return i===t?"function"!=typeof e||function bh(e){return null!==Vs(e)}(e)?n.get(e):e:i}function kc(e,n,t,i,r={canDeactivateChecks:[],canActivateChecks:[]}){const o=La(n);return e.children.forEach(s=>{(function t2(e,n,t,i,r={canDeactivateChecks:[],canActivateChecks:[]}){const o=e.value,s=n?n.value:null,a=t?t.getContext(e.value.outlet):null;if(s&&o.routeConfig===s.routeConfig){const l=function n2(e,n,t){if("function"==typeof t)return t(e,n);switch(t){case"pathParamsChange":return!rs(e.url,n.url);case"pathParamsOrQueryParamsChange":return!rs(e.url,n.url)||!cr(e.queryParams,n.queryParams);case"always":return!0;case"paramsOrQueryParamsChange":return!c_(e,n)||!cr(e.queryParams,n.queryParams);default:return!c_(e,n)}}(s,o,o.routeConfig.runGuardsAndResolvers);l?r.canActivateChecks.push(new Gw(i)):(o.data=s.data,o._resolvedData=s._resolvedData),kc(e,n,o.component?a?a.children:null:t,i,r),l&&a&&a.outlet&&a.outlet.isActivated&&r.canDeactivateChecks.push(new df(a.outlet.component,s))}else s&&Oc(n,a,r),r.canActivateChecks.push(new Gw(i)),kc(e,null,o.component?a?a.children:null:t,i,r)})(s,o[s.value.outlet],t,i.concat([s.value]),r),delete o[s.value.outlet]}),an(o,(s,a)=>Oc(s,t.getContext(a),r)),r}function Oc(e,n,t){const i=La(e),r=e.value;an(i,(o,s)=>{Oc(o,r.component?n?n.children.getContext(s):null:n,t)}),t.canDeactivateChecks.push(new df(r.component&&n&&n.outlet&&n.outlet.isActivated?n.outlet.component:null,r))} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */function xc(e){return"function"==typeof e}function g_(e){return e instanceof bc||"EmptyError"===e?.name} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */const ff=Symbol("INITIAL_VALUE");function Ba(){return vi(e=>Jd(e.map(n=>n.pipe(sn(1),function Qd(...e){const n=en(e);return qe((t,i)=>{(n?Dc(e,t,n):Dc(e,t)).subscribe(i)})}(ff)))).pipe(ne(n=>{for(const t of n)if(!0!==t){if(t===ff)return ff;if(!1===t||t instanceof is)return t}return!0}),vn(n=>n!==ff),sn(1)))} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */function Ww(e){return function Xa(...e){return Cs(e)}(Kt(n=>{if(os(n))throw Vw(0,n)}),ne(n=>!0===n))} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -const m_={matched:!1,consumedSegments:[],remainingSegments:[],parameters:{},positionalParamSegments:{}};function zw(e,n,t,i,r){const o=__(e,n,t);return o.matched?function b2(e,n,t,i){const r=n.canMatch;return r&&0!==r.length?J(r.map(s=>{const a=Va(s,e);return vo(function c2(e){return e&&xc(e.canMatch)}(a)?a.canMatch(n,t):e.runInContext(()=>a(n,t)))})).pipe(Ba(),Ww()):J(!0)}(i=$w(n,i),n,t).pipe(ne(s=>!0===s?o:{...m_})):J(o)}function __(e,n,t){if(""===n.path)return"full"===n.pathMatch&&(e.hasChildren()||t.length>0)?{...m_}:{matched:!0,consumedSegments:[],remainingSegments:t,parameters:{},positionalParamSegments:{}};const r=(n.matcher||tL)(t,e,n);if(!r)return{...m_};const o={};an(r.posParams,(a,l)=>{o[l]=a.path});const s=r.consumed.length>0?{...o,...r.consumed[r.consumed.length-1].parameters}:o;return{matched:!0,consumedSegments:r.consumed,remainingSegments:t.slice(r.consumed.length),parameters:s,positionalParamSegments:r.posParams??{}}}function hf(e,n,t,i,r="corrected"){if(t.length>0&&function w2(e,n,t){return t.some(i=>pf(e,n,i)&&yi(i)!==pe)}(e,t,i)){const s=new me(n,function C2(e,n,t,i){const r={};r[pe]=i,i._sourceSegment=e,i._segmentIndexShift=n.length;for(const o of t)if(""===o.path&&yi(o)!==pe){const s=new me([],{});s._sourceSegment=e,s._segmentIndexShift=n.length,r[yi(o)]=s}return r}(e,n,i,new me(t,e.children)));return s._sourceSegment=e,s._segmentIndexShift=n.length,{segmentGroup:s,slicedSegments:[]}}if(0===t.length&&function S2(e,n,t){return t.some(i=>pf(e,n,i))}(e,t,i)){const s=new me(e.segments,function D2(e,n,t,i,r,o){const s={};for(const a of i)if(pf(e,t,a)&&!r[yi(a)]){const l=new me([],{});l._sourceSegment=e,l._segmentIndexShift="legacy"===o?e.segments.length:n.length,s[yi(a)]=l}return{...r,...s}}(e,n,t,i,e.children,r));return s._sourceSegment=e,s._segmentIndexShift=n.length,{segmentGroup:s,slicedSegments:t}}const o=new me(e.segments,e.children);return o._sourceSegment=e,o._segmentIndexShift=n.length,{segmentGroup:o,slicedSegments:t}}function pf(e,n,t){return(!(e.hasChildren()||n.length>0)||"full"!==t.pathMatch)&&""===t.path}function Yw(e,n,t,i){return!!(yi(e)===i||i!==pe&&pf(n,t,e))&&("**"===e.path||__(n,e,t).matched)}function Kw(e,n,t){return 0===n.length&&!e.children[t]} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */const gf=!1;class mf{constructor(n){this.segmentGroup=n||null}}class qw{constructor(n){this.urlTree=n}}function Rc(e){return xa(new mf(e))}function Zw(e){return xa(new qw(e))}class T2{constructor(n,t,i,r,o){this.injector=n,this.configLoader=t,this.urlSerializer=i,this.urlTree=r,this.config=o,this.allowRedirects=!0}apply(){const n=hf(this.urlTree.root,[],[],this.config).segmentGroup,t=new me(n.segments,n.children);return this.expandSegmentGroup(this.injector,this.config,t,pe).pipe(ne(o=>this.createUrlTree(af(o),this.urlTree.queryParams,this.urlTree.fragment))).pipe($r(o=>{if(o instanceof qw)return this.allowRedirects=!1,this.match(o.urlTree);throw o instanceof mf?this.noMatchError(o):o}))}match(n){return this.expandSegmentGroup(this.injector,this.config,n.root,pe).pipe(ne(r=>this.createUrlTree(af(r),n.queryParams,n.fragment))).pipe($r(r=>{throw r instanceof mf?this.noMatchError(r):r}))}noMatchError(n){return new F(4002,gf)}createUrlTree(n,t,i){const r=e_(n);return new is(r,t,i)}expandSegmentGroup(n,t,i,r){return 0===i.segments.length&&i.hasChildren()?this.expandChildren(n,t,i).pipe(ne(o=>new me([],o))):this.expandSegment(n,i,t,i.segments,r,!0)}expandChildren(n,t,i){const r=[];for(const o of Object.keys(i.children))"primary"===o?r.unshift(o):r.push(o);return gt(r).pipe(_o(o=>{const s=i.children[o],a=Uw(t,o);return this.expandSegmentGroup(n,a,s,o).pipe(ne(l=>({segment:l,outlet:o})))}),cw((o,s)=>(o[s.outlet]=s.segment,o),{}),uw())}expandSegment(n,t,i,r,o,s){return gt(i).pipe(_o(a=>this.expandSegmentAgainstRoute(n,t,i,a,r,o,s).pipe($r(u=>{if(u instanceof mf)return J(null);throw u}))),mo(a=>!!a),$r((a,l)=>{if(g_(a))return Kw(t,r,o)?J(new me([],{})):Rc(t);throw a}))}expandSegmentAgainstRoute(n,t,i,r,o,s,a){return Yw(r,t,o,s)?void 0===r.redirectTo?this.matchSegmentAgainstRoute(n,t,r,o,s):a&&this.allowRedirects?this.expandSegmentAgainstRouteUsingRedirect(n,t,i,r,o,s):Rc(t):Rc(t)}expandSegmentAgainstRouteUsingRedirect(n,t,i,r,o,s){return"**"===r.path?this.expandWildCardWithParamsAgainstRouteUsingRedirect(n,i,r,s):this.expandRegularSegmentAgainstRouteUsingRedirect(n,t,i,r,o,s)}expandWildCardWithParamsAgainstRouteUsingRedirect(n,t,i,r){const o=this.applyRedirectCommands([],i.redirectTo,{});return i.redirectTo.startsWith("/")?Zw(o):this.lineralizeSegments(i,o).pipe(dt(s=>{const a=new me(s,{});return this.expandSegment(n,a,t,s,r,!1)}))}expandRegularSegmentAgainstRouteUsingRedirect(n,t,i,r,o,s){const{matched:a,consumedSegments:l,remainingSegments:u,positionalParamSegments:f}=__(t,r,o);if(!a)return Rc(t);const p=this.applyRedirectCommands(l,r.redirectTo,f);return r.redirectTo.startsWith("/")?Zw(p):this.lineralizeSegments(r,p).pipe(dt(m=>this.expandSegment(n,t,i,m.concat(u),s,!1)))}matchSegmentAgainstRoute(n,t,i,r,o){return"**"===i.path?(n=$w(i,n),i.loadChildren?(i._loadedRoutes?J({routes:i._loadedRoutes,injector:i._loadedInjector}):this.configLoader.loadChildren(n,i)).pipe(ne(a=>(i._loadedRoutes=a.routes,i._loadedInjector=a.injector,new me(r,{})))):J(new me(r,{}))):zw(t,i,r,n).pipe(vi(({matched:s,consumedSegments:a,remainingSegments:l})=>s?this.getChildConfig(n=i._injector??n,i,r).pipe(dt(f=>{const p=f.injector??n,m=f.routes,{segmentGroup:v,slicedSegments:y}=hf(t,a,l,m),D=new me(v.segments,v.children);if(0===y.length&&D.hasChildren())return this.expandChildren(p,m,D).pipe(ne(S=>new me(a,S)));if(0===m.length&&0===y.length)return J(new me(a,{}));const w=yi(i)===o;return this.expandSegment(p,D,m,y,w?pe:o,!0).pipe(ne(A=>new me(a.concat(A.segments),A.children)))})):Rc(t)))}getChildConfig(n,t,i){return t.children?J({routes:t.children,injector:n}):t.loadChildren?void 0!==t._loadedRoutes?J({routes:t._loadedRoutes,injector:t._loadedInjector}):function y2(e,n,t,i){const r=n.canLoad;return void 0===r||0===r.length?J(!0):J(r.map(s=>{const a=Va(s,e);return vo(function o2(e){return e&&xc(e.canLoad)}(a)?a.canLoad(n,t):e.runInContext(()=>a(n,t)))})).pipe(Ba(),Ww())}(n,t,i).pipe(dt(r=>r?this.configLoader.loadChildren(n,t).pipe(Kt(o=>{t._loadedRoutes=o.routes,t._loadedInjector=o.injector})):function N2(e){return xa(Bw(gf,3))}())):J({routes:[],injector:n})}lineralizeSegments(n,t){let i=[],r=t.root;for(;;){if(i=i.concat(r.segments),0===r.numberOfChildren)return J(i);if(r.numberOfChildren>1||!r.children[pe])return xa(new F(4e3,gf));r=r.children[pe]}}applyRedirectCommands(n,t,i){return this.applyRedirectCreateUrlTree(t,this.urlSerializer.parse(t),n,i)}applyRedirectCreateUrlTree(n,t,i,r){const o=this.createSegmentGroup(n,t.root,i,r);return new is(o,this.createQueryParams(t.queryParams,this.urlTree.queryParams),t.fragment)}createQueryParams(n,t){const i={};return an(n,(r,o)=>{if("string"==typeof r&&r.startsWith(":")){const a=r.substring(1);i[o]=t[a]}else i[o]=r}),i}createSegmentGroup(n,t,i,r){const o=this.createSegments(n,t.segments,i,r);let s={};return an(t.children,(a,l)=>{s[l]=this.createSegmentGroup(n,a,i,r)}),new me(o,s)}createSegments(n,t,i,r){return t.map(o=>o.path.startsWith(":")?this.findPosParam(n,o,r):this.findOrReturn(o,i))}findPosParam(n,t,i){const r=i[t.path.substring(1)];if(!r)throw new F(4001,gf);return r}findOrReturn(n,t){let i=0;for(const r of t){if(r.path===n.path)return t.splice(i),r;i++}return n}} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */class A2{}class x2{constructor(n,t,i,r,o,s,a,l){this.injector=n,this.rootComponentType=t,this.config=i,this.urlTree=r,this.url=o,this.paramsInheritanceStrategy=s,this.relativeLinkResolution=a,this.urlSerializer=l}recognize(){const n=hf(this.urlTree.root,[],[],this.config.filter(t=>void 0===t.redirectTo),this.relativeLinkResolution).segmentGroup;return this.processSegmentGroup(this.injector,this.config,n,pe).pipe(ne(t=>{if(null===t)return null;const i=new cf([],Object.freeze({}),Object.freeze({...this.urlTree.queryParams}),this.urlTree.fragment,{},pe,this.rootComponentType,null,this.urlTree.root,-1,{}),r=new Gr(i,t),o=new Fw(this.url,r);return this.inheritParamsAndData(o._root),o}))}inheritParamsAndData(n){const t=n.value,i=Pw(t,this.paramsInheritanceStrategy);t.params=Object.freeze(i.params),t.data=Object.freeze(i.data),n.children.forEach(r=>this.inheritParamsAndData(r))}processSegmentGroup(n,t,i,r){return 0===i.segments.length&&i.hasChildren()?this.processChildren(n,t,i):this.processSegment(n,t,i,i.segments,r)}processChildren(n,t,i){return gt(Object.keys(i.children)).pipe(_o(r=>{const o=i.children[r],s=Uw(t,r);return this.processSegmentGroup(n,s,o,r)}),cw((r,o)=>r&&o?(r.push(...o),r):null),function XF(e,n=!1){return qe((t,i)=>{let r=0;t.subscribe(Oe(i,o=>{const s=e(o,r++);(s||n)&&i.next(o),!s&&i.complete()}))})}(r=>null!==r),Xd(null),uw(),ne(r=>{if(null===r)return null;const o=Jw(r);return function R2(e){e.sort((n,t)=>n.value.outlet===pe?-1:t.value.outlet===pe?1:n.value.outlet.localeCompare(t.value.outlet))}(o),o}))}processSegment(n,t,i,r,o){return gt(t).pipe(_o(s=>this.processSegmentAgainstRoute(s._injector??n,s,i,r,o)),mo(s=>!!s),$r(s=>{if(g_(s))return Kw(i,r,o)?J([]):J(null);throw s}))}processSegmentAgainstRoute(n,t,i,r,o){if(t.redirectTo||!Yw(t,i,r,o))return J(null);let s;if("**"===t.path){const a=r.length>0?pw(r).parameters:{},l=Xw(i)+r.length;s=J({snapshot:new cf(r,a,Object.freeze({...this.urlTree.queryParams}),this.urlTree.fragment,tS(t),yi(t),t.component??t._loadedComponent??null,t,Qw(i),l,nS(t),l),consumedSegments:[],remainingSegments:[]})}else s=zw(i,t,r,n).pipe(ne(({matched:a,consumedSegments:l,remainingSegments:u,parameters:f})=>{if(!a)return null;const p=Xw(i)+l.length;return{snapshot:new cf(l,f,Object.freeze({...this.urlTree.queryParams}),this.urlTree.fragment,tS(t),yi(t),t.component??t._loadedComponent??null,t,Qw(i),p,nS(t),p),consumedSegments:l,remainingSegments:u}}));return s.pipe(vi(a=>{if(null===a)return J(null);const{snapshot:l,consumedSegments:u,remainingSegments:f}=a;n=t._injector??n;const p=t._loadedInjector??n,m=function P2(e){return e.children?e.children:e.loadChildren?e._loadedRoutes:[]}(t),{segmentGroup:v,slicedSegments:y}=hf(i,u,f,m.filter(w=>void 0===w.redirectTo),this.relativeLinkResolution);if(0===y.length&&v.hasChildren())return this.processChildren(p,m,v).pipe(ne(w=>null===w?null:[new Gr(l,w)]));if(0===m.length&&0===y.length)return J([new Gr(l,[])]);const D=yi(t)===o;return this.processSegment(p,m,v,y,D?pe:o).pipe(ne(w=>null===w?null:[new Gr(l,w)]))}))}}function F2(e){const n=e.value.routeConfig;return n&&""===n.path&&void 0===n.redirectTo}function Jw(e){const n=[],t=new Set;for(const i of e){if(!F2(i)){n.push(i);continue}const r=n.find(o=>i.value.routeConfig===o.value.routeConfig);void 0!==r?(r.children.push(...i.children),t.add(r)):n.push(i)}for(const i of t){const r=Jw(i.children);n.push(new Gr(i.value,r))}return n.filter(i=>!t.has(i))}function Qw(e){let n=e;for(;n._sourceSegment;)n=n._sourceSegment;return n}function Xw(e){let n=e,t=n._segmentIndexShift??0;for(;n._sourceSegment;)n=n._sourceSegment,t+=n._segmentIndexShift??0;return t-1}function tS(e){return e.data||{}}function nS(e){return e.resolve||{}} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -function B2(e,n){return dt(t=>{const{targetSnapshot:i,guards:{canActivateChecks:r}}=t;if(!r.length)return J(t);let o=0;return gt(r).pipe(_o(s=>function H2(e,n,t,i){const r=e.routeConfig,o=e._resolve;return void 0!==r?.title&&!iS(r)&&(o[Cc]=r.title),function j2(e,n,t,i){const r=function $2(e){return[...Object.keys(e),...Object.getOwnPropertySymbols(e)]}(e);if(0===r.length)return J({});const o={};return gt(r).pipe(dt(s=>function U2(e,n,t,i){const r=Ac(n)??i,o=Va(e,r);return vo(o.resolve?o.resolve(n,t):r.runInContext(()=>o(n,t)))}(e[s],n,t,i).pipe(mo(),Kt(a=>{o[s]=a}))),qm(1),function dw(e){return ne(()=>e)}(o),$r(s=>g_(s)?Xt:xa(s)))}(o,e,n,i).pipe(ne(s=>(e._resolvedData=s,e.data=Pw(e,t).resolve,r&&iS(r)&&(e.data[Cc]=r.title),null)))}(s.route,i,e,n)),Kt(()=>o++),qm(1),dt(s=>o===r.length?J(t):Xt))})}function iS(e){return"string"==typeof e.title||null===e.title} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */function v_(e){return vi(n=>{const t=e(n);return t?gt(t).pipe(ne(()=>n)):J(n)})} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */let rS=(()=>{class e{buildTitle(t){let i,r=t.root;for(;void 0!==r;)i=this.getResolvedTitleForRoute(r)??i,r=r.children.find(o=>o.outlet===pe);return i}getResolvedTitleForRoute(t){return t.data[Cc]}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:function(){return St(oS)},providedIn:"root"}),e})(),oS=(()=>{class e extends rS{constructor(t){super(),this.title=t}updateTitle(t){const i=this.buildTitle(t);void 0!==i&&this.title.setTitle(i)}}return e.\u0275fac=function(t){return new(t||e)(L(ew))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -class G2{}class z2 extends class W2{shouldDetach(n){return!1}store(n,t){}shouldAttach(n){return!1}retrieve(n){return null}shouldReuseRoute(n,t){return n.routeConfig===t.routeConfig}}{} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */const vf=new q("",{providedIn:"root",factory:()=>({})}),y_=new q("ROUTES"); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */let b_=(()=>{class e{constructor(t,i){this.injector=t,this.compiler=i,this.componentLoaders=new WeakMap,this.childrenLoaders=new WeakMap}loadComponent(t){if(this.componentLoaders.get(t))return this.componentLoaders.get(t);if(t._loadedComponent)return J(t._loadedComponent);this.onLoadStartListener&&this.onLoadStartListener(t);const i=vo(t.loadComponent()).pipe(Kt(o=>{this.onLoadEndListener&&this.onLoadEndListener(t),t._loadedComponent=o}),Zm(()=>{this.componentLoaders.delete(t)})),r=new aw(i,()=>new Ue).pipe(Km());return this.componentLoaders.set(t,r),r}loadChildren(t,i){if(this.childrenLoaders.get(i))return this.childrenLoaders.get(i);if(i._loadedRoutes)return J({routes:i._loadedRoutes,injector:i._loadedInjector});this.onLoadStartListener&&this.onLoadStartListener(i);const o=this.loadModuleFactoryOrRoutes(i.loadChildren).pipe(ne(a=>{this.onLoadEndListener&&this.onLoadEndListener(i);let l,u,f=!1;Array.isArray(a)?u=a:(l=a.create(t).injector,u=hw(l.get(y_,[],X.Self|X.Optional)));return{routes:u.map(p_),injector:l}}),Zm(()=>{this.childrenLoaders.delete(i)})),s=new aw(o,()=>new Ue).pipe(Km());return this.childrenLoaders.set(i,s),s}loadModuleFactoryOrRoutes(t){return vo(t()).pipe(dt(i=>i instanceof zD||Array.isArray(i)?J(i):gt(this.compiler.compileModuleAsync(i))))}}return e.\u0275fac=function(t){return new(t||e)(L(gn),L(lm))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */class K2{}class q2{shouldProcessUrl(n){return!0}extract(n){return n}merge(n,t){return n}} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */function Z2(e){throw e}function J2(e,n,t){return n.parse("/")}const Q2={paths:"exact",fragment:"ignored",matrixParams:"ignored",queryParams:"exact"},X2={paths:"subset",fragment:"ignored",matrixParams:"ignored",queryParams:"subset"};function aS(){const e=St(bw),n=St(Ic),t=St(Sm),i=St(gn),r=St(lm),o=St(y_,{optional:!0})??[],s=St(vf,{optional:!0})??{},a=St(oS),l=St(rS,{optional:!0}),u=St(K2,{optional:!0}),f=St(G2,{optional:!0}),p=new ln(null,e,n,t,i,r,hw(o));return u&&(p.urlHandlingStrategy=u),f&&(p.routeReuseStrategy=f),p.titleStrategy=l??a,function eV(e,n){e.errorHandler&&(n.errorHandler=e.errorHandler),e.malformedUriErrorHandler&&(n.malformedUriErrorHandler=e.malformedUriErrorHandler),e.onSameUrlNavigation&&(n.onSameUrlNavigation=e.onSameUrlNavigation),e.paramsInheritanceStrategy&&(n.paramsInheritanceStrategy=e.paramsInheritanceStrategy),e.relativeLinkResolution&&(n.relativeLinkResolution=e.relativeLinkResolution),e.urlUpdateStrategy&&(n.urlUpdateStrategy=e.urlUpdateStrategy),e.canceledNavigationResolution&&(n.canceledNavigationResolution=e.canceledNavigationResolution)}(s,p),p}let ln=(()=>{class e{constructor(t,i,r,o,s,a,l){this.rootComponentType=t,this.urlSerializer=i,this.rootContexts=r,this.location=o,this.config=l,this.lastSuccessfulNavigation=null,this.currentNavigation=null,this.disposed=!1,this.navigationId=0,this.currentPageId=0,this.isNgZoneEnabled=!1,this.events=new Ue,this.errorHandler=Z2,this.malformedUriErrorHandler=J2,this.navigated=!1,this.lastSuccessfulId=-1,this.afterPreactivation=()=>J(void 0),this.urlHandlingStrategy=new q2,this.routeReuseStrategy=new z2,this.onSameUrlNavigation="ignore",this.paramsInheritanceStrategy="emptyOnly",this.urlUpdateStrategy="deferred",this.relativeLinkResolution="corrected",this.canceledNavigationResolution="replace",this.configLoader=s.get(b_),this.configLoader.onLoadEndListener=m=>this.triggerEvent(new RL(m)),this.configLoader.onLoadStartListener=m=>this.triggerEvent(new xL(m)),this.ngModule=s.get(Xo),this.console=s.get(Hx);const p=s.get(Ye);this.isNgZoneEnabled=p instanceof Ye&&Ye.isInAngularZone(),this.resetConfig(l),this.currentUrlTree=function iL(){return new is(new me([],{}),{},null)}(),this.rawUrlTree=this.currentUrlTree,this.browserUrlTree=this.currentUrlTree,this.routerState=Rw(this.currentUrlTree,this.rootComponentType),this.transitions=new Yt({id:0,targetPageId:0,currentUrlTree:this.currentUrlTree,currentRawUrl:this.currentUrlTree,extractedUrl:this.urlHandlingStrategy.extract(this.currentUrlTree),urlAfterRedirects:this.urlHandlingStrategy.extract(this.currentUrlTree),rawUrl:this.currentUrlTree,extras:{},resolve:null,reject:null,promise:Promise.resolve(!0),source:"imperative",restoredState:null,currentSnapshot:this.routerState.snapshot,targetSnapshot:null,currentRouterState:this.routerState,targetRouterState:null,guards:{canActivateChecks:[],canDeactivateChecks:[]},guardsResult:null}),this.navigations=this.setupNavigations(this.transitions),this.processNavigations()}get browserPageId(){return this.location.getState()?.\u0275routerPageId}setupNavigations(t){const i=this.events;return t.pipe(vn(r=>0!==r.id),ne(r=>({...r,extractedUrl:this.urlHandlingStrategy.extract(r.rawUrl)})),vi(r=>{let o=!1,s=!1;return J(r).pipe(Kt(a=>{this.currentNavigation={id:a.id,initialUrl:a.rawUrl,extractedUrl:a.extractedUrl,trigger:a.source,extras:a.extras,previousNavigation:this.lastSuccessfulNavigation?{...this.lastSuccessfulNavigation,previousNavigation:null}:null}}),vi(a=>{const l=this.browserUrlTree.toString(),u=!this.navigated||a.extractedUrl.toString()!==l||l!==this.currentUrlTree.toString();if(("reload"===this.onSameUrlNavigation||u)&&this.urlHandlingStrategy.shouldProcessUrl(a.rawUrl))return lS(a.source)&&(this.browserUrlTree=a.extractedUrl),J(a).pipe(vi(p=>{const m=this.transitions.getValue();return i.next(new r_(p.id,this.serializeUrl(p.extractedUrl),p.source,p.restoredState)),m!==this.transitions.getValue()?Xt:Promise.resolve(p)}),function I2(e,n,t,i){return vi(r=>function E2(e,n,t,i,r){return new T2(e,n,t,i,r).apply()}(e,n,t,r.extractedUrl,i).pipe(ne(o=>({...r,urlAfterRedirects:o}))))} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */(this.ngModule.injector,this.configLoader,this.urlSerializer,this.config),Kt(p=>{this.currentNavigation={...this.currentNavigation,finalUrl:p.urlAfterRedirects},r.urlAfterRedirects=p.urlAfterRedirects}),function V2(e,n,t,i,r,o){return dt(s=>function O2(e,n,t,i,r,o,s="emptyOnly",a="legacy"){return new x2(e,n,t,i,r,s,a,o).recognize().pipe(vi(l=>null===l?function k2(e){return new je(n=>n.error(e))}(new A2):J(l)))}(e,n,t,s.urlAfterRedirects,i.serialize(s.urlAfterRedirects),i,r,o).pipe(ne(a=>({...s,targetSnapshot:a}))))}(this.ngModule.injector,this.rootComponentType,this.config,this.urlSerializer,this.paramsInheritanceStrategy,this.relativeLinkResolution),Kt(p=>{if(r.targetSnapshot=p.targetSnapshot,"eager"===this.urlUpdateStrategy){if(!p.extras.skipLocationChange){const v=this.urlHandlingStrategy.merge(p.urlAfterRedirects,p.rawUrl);this.setBrowserUrl(v,p)}this.browserUrlTree=p.urlAfterRedirects}const m=new TL(p.id,this.serializeUrl(p.extractedUrl),this.serializeUrl(p.urlAfterRedirects),p.targetSnapshot);i.next(m)}));if(u&&this.rawUrlTree&&this.urlHandlingStrategy.shouldProcessUrl(this.rawUrlTree)){const{id:m,extractedUrl:v,source:y,restoredState:D,extras:w}=a,N=new r_(m,this.serializeUrl(v),y,D);i.next(N);const A=Rw(v,this.rootComponentType).snapshot;return J(r={...a,targetSnapshot:A,urlAfterRedirects:v,extras:{...w,skipLocationChange:!1,replaceUrl:!1}})}return this.rawUrlTree=a.rawUrl,a.resolve(null),Xt}),Kt(a=>{const l=new IL(a.id,this.serializeUrl(a.extractedUrl),this.serializeUrl(a.urlAfterRedirects),a.targetSnapshot);this.triggerEvent(l)}),ne(a=>r={...a,guards:XL(a.targetSnapshot,a.currentSnapshot,this.rootContexts)}),function d2(e,n){return dt(t=>{const{targetSnapshot:i,currentSnapshot:r,guards:{canActivateChecks:o,canDeactivateChecks:s}}=t;return 0===s.length&&0===o.length?J({...t,guardsResult:!0}):function f2(e,n,t,i){return gt(e).pipe(dt(r=>function v2(e,n,t,i,r){const o=n&&n.routeConfig?n.routeConfig.canDeactivate:null;return o&&0!==o.length?J(o.map(a=>{const l=Ac(n)??r,u=Va(a,l);return vo(function l2(e){return e&&xc(e.canDeactivate)}(u)?u.canDeactivate(e,n,t,i):l.runInContext(()=>u(e,n,t,i))).pipe(mo())})).pipe(Ba()):J(!0)}(r.component,r.route,t,n,i)),mo(r=>!0!==r,!0))}(s,i,r,e).pipe(dt(a=>a&&function r2(e){return"boolean"==typeof e}(a)?function h2(e,n,t,i){return gt(n).pipe(_o(r=>Dc(function g2(e,n){return null!==e&&n&&n(new PL(e)),J(!0)}(r.route.parent,i),function p2(e,n){return null!==e&&n&&n(new LL(e)),J(!0)}(r.route,i),function _2(e,n,t){const i=n[n.length-1],o=n.slice(0,n.length-1).reverse().map(s=>function e2(e){const n=e.routeConfig?e.routeConfig.canActivateChild:null;return n&&0!==n.length?{node:e,guards:n}:null}(s)).filter(s=>null!==s).map(s=>sw(()=>J(s.guards.map(l=>{const u=Ac(s.node)??t,f=Va(l,u);return vo(function a2(e){return e&&xc(e.canActivateChild)}(f)?f.canActivateChild(i,e):u.runInContext(()=>f(i,e))).pipe(mo())})).pipe(Ba())));return J(o).pipe(Ba())}(e,r.path,t),function m2(e,n,t){const i=n.routeConfig?n.routeConfig.canActivate:null;if(!i||0===i.length)return J(!0);const r=i.map(o=>sw(()=>{const s=Ac(n)??t,a=Va(o,s);return vo(function s2(e){return e&&xc(e.canActivate)}(a)?a.canActivate(n,e):s.runInContext(()=>a(n,e))).pipe(mo())}));return J(r).pipe(Ba())}(e,r.route,t))),mo(r=>!0!==r,!0))}(i,o,e,n):J(a)),ne(a=>({...t,guardsResult:a})))})}(this.ngModule.injector,a=>this.triggerEvent(a)),Kt(a=>{if(r.guardsResult=a.guardsResult,os(a.guardsResult))throw Vw(0,a.guardsResult);const l=new AL(a.id,this.serializeUrl(a.extractedUrl),this.serializeUrl(a.urlAfterRedirects),a.targetSnapshot,!!a.guardsResult);this.triggerEvent(l)}),vn(a=>!!a.guardsResult||(this.restoreHistory(a),this.cancelNavigationTransition(a,"",3),!1)),v_(a=>{if(a.guards.canActivateChecks.length)return J(a).pipe(Kt(l=>{const u=new kL(l.id,this.serializeUrl(l.extractedUrl),this.serializeUrl(l.urlAfterRedirects),l.targetSnapshot);this.triggerEvent(u)}),vi(l=>{let u=!1;return J(l).pipe(B2(this.paramsInheritanceStrategy,this.ngModule.injector),Kt({next:()=>u=!0,complete:()=>{u||(this.restoreHistory(l),this.cancelNavigationTransition(l,"",2))}}))}),Kt(l=>{const u=new OL(l.id,this.serializeUrl(l.extractedUrl),this.serializeUrl(l.urlAfterRedirects),l.targetSnapshot);this.triggerEvent(u)}))}),v_(a=>{const l=u=>{const f=[];u.routeConfig?.loadComponent&&!u.routeConfig._loadedComponent&&f.push(this.configLoader.loadComponent(u.routeConfig).pipe(Kt(p=>{u.component=p}),ne(()=>{})));for(const p of u.children)f.push(...l(p));return f};return Jd(l(a.targetSnapshot.root)).pipe(Xd(),sn(1))}),v_(()=>this.afterPreactivation()),ne(a=>{const l=function $L(e,n,t){const i=Tc(e,n._root,t?t._root:void 0);return new xw(i,n)}(this.routeReuseStrategy,a.targetSnapshot,a.currentRouterState);return r={...a,targetRouterState:l}}),Kt(a=>{this.currentUrlTree=a.urlAfterRedirects,this.rawUrlTree=this.urlHandlingStrategy.merge(a.urlAfterRedirects,a.rawUrl),this.routerState=a.targetRouterState,"deferred"===this.urlUpdateStrategy&&(a.extras.skipLocationChange||this.setBrowserUrl(this.rawUrlTree,a),this.browserUrlTree=a.urlAfterRedirects)}),((e,n,t)=>ne(i=>(new QL(n,i.targetRouterState,i.currentRouterState,t).activate(e),i)))(this.rootContexts,this.routeReuseStrategy,a=>this.triggerEvent(a)),Kt({next(){o=!0},complete(){o=!0}}),Zm(()=>{o||s||this.cancelNavigationTransition(r,"",1),this.currentNavigation?.id===r.id&&(this.currentNavigation=null)}),$r(a=>{if(s=!0,jw(a)){Hw(a)||(this.navigated=!0,this.restoreHistory(r,!0));const l=new lf(r.id,this.serializeUrl(r.extractedUrl),a.message,a.cancellationCode);if(i.next(l),Hw(a)){const u=this.urlHandlingStrategy.merge(a.url,this.rawUrlTree),f={skipLocationChange:r.extras.skipLocationChange,replaceUrl:"eager"===this.urlUpdateStrategy||lS(r.source)};this.scheduleNavigation(u,"imperative",null,f,{resolve:r.resolve,reject:r.reject,promise:r.promise})}else r.resolve(!1)}else{this.restoreHistory(r,!0);const l=new Aw(r.id,this.serializeUrl(r.extractedUrl),a,r.targetSnapshot??void 0);i.next(l);try{r.resolve(this.errorHandler(a))}catch(u){r.reject(u)}}return Xt}))}))}resetRootComponentType(t){this.rootComponentType=t,this.routerState.root.component=this.rootComponentType}setTransition(t){this.transitions.next({...this.transitions.value,...t})}initialNavigation(){this.setUpLocationChangeListener(),0===this.navigationId&&this.navigateByUrl(this.location.path(!0),{replaceUrl:!0})}setUpLocationChangeListener(){this.locationSubscription||(this.locationSubscription=this.location.subscribe(t=>{const i="popstate"===t.type?"popstate":"hashchange";"popstate"===i&&setTimeout(()=>{const r={replaceUrl:!0},o=t.state?.navigationId?t.state:null;if(o){const a={...o};delete a.navigationId,delete a.\u0275routerPageId,0!==Object.keys(a).length&&(r.state=a)}const s=this.parseUrl(t.url);this.scheduleNavigation(s,i,o,r)},0)}))}get url(){return this.serializeUrl(this.currentUrlTree)}getCurrentNavigation(){return this.currentNavigation}triggerEvent(t){this.events.next(t)}resetConfig(t){this.config=t.map(p_),this.navigated=!1,this.lastSuccessfulId=-1}ngOnDestroy(){this.dispose()}dispose(){this.transitions.complete(),this.locationSubscription&&(this.locationSubscription.unsubscribe(),this.locationSubscription=void 0),this.disposed=!0}createUrlTree(t,i={}){const{relativeTo:r,queryParams:o,fragment:s,queryParamsHandling:a,preserveFragment:l}=i,u=r||this.routerState.root,f=l?this.currentUrlTree.fragment:s;let p=null;switch(a){case"merge":p={...this.currentUrlTree.queryParams,...o};break;case"preserve":p=this.currentUrlTree.queryParams;break;default:p=o||null}return null!==p&&(p=this.removeEmptyProps(p)),CL(u,this.currentUrlTree,t,p,f??null)}navigateByUrl(t,i={skipLocationChange:!1}){const r=os(t)?t:this.parseUrl(t),o=this.urlHandlingStrategy.merge(r,this.rawUrlTree);return this.scheduleNavigation(o,"imperative",null,i)}navigate(t,i={skipLocationChange:!1}){return function tV(e){for(let n=0;n{const o=t[r];return null!=o&&(i[r]=o),i},{})}processNavigations(){this.navigations.subscribe(t=>{this.navigated=!0,this.lastSuccessfulId=t.id,this.currentPageId=t.targetPageId,this.events.next(new ss(t.id,this.serializeUrl(t.extractedUrl),this.serializeUrl(this.currentUrlTree))),this.lastSuccessfulNavigation=this.currentNavigation,this.titleStrategy?.updateTitle(this.routerState.snapshot),t.resolve(!0)},t=>{this.console.warn(`Unhandled Navigation Error: ${t}`)})}scheduleNavigation(t,i,r,o,s){if(this.disposed)return Promise.resolve(!1);let a,l,u;s?(a=s.resolve,l=s.reject,u=s.promise):u=new Promise((m,v)=>{a=m,l=v});const f=++this.navigationId;let p;return"computed"===this.canceledNavigationResolution?(0===this.currentPageId&&(r=this.location.getState()),p=r&&r.\u0275routerPageId?r.\u0275routerPageId:o.replaceUrl||o.skipLocationChange?this.browserPageId??0:(this.browserPageId??0)+1):p=0,this.setTransition({id:f,targetPageId:p,source:i,restoredState:r,currentUrlTree:this.currentUrlTree,currentRawUrl:this.rawUrlTree,rawUrl:t,extras:o,resolve:a,reject:l,promise:u,currentSnapshot:this.routerState.snapshot,currentRouterState:this.routerState}),u.catch(m=>Promise.reject(m))}setBrowserUrl(t,i){const r=this.urlSerializer.serialize(t),o={...i.extras.state,...this.generateNgRouterState(i.id,i.targetPageId)};this.location.isCurrentPathEqualTo(r)||i.extras.replaceUrl?this.location.replaceState(r,"",o):this.location.go(r,"",o)}restoreHistory(t,i=!1){if("computed"===this.canceledNavigationResolution){const r=this.currentPageId-t.targetPageId;"popstate"!==t.source&&"eager"!==this.urlUpdateStrategy&&this.currentUrlTree!==this.currentNavigation?.finalUrl||0===r?this.currentUrlTree===this.currentNavigation?.finalUrl&&0===r&&(this.resetState(t),this.browserUrlTree=t.currentUrlTree,this.resetUrlToCurrentUrlTree()):this.location.historyGo(r)}else"replace"===this.canceledNavigationResolution&&(i&&this.resetState(t),this.resetUrlToCurrentUrlTree())}resetState(t){this.routerState=t.currentRouterState,this.currentUrlTree=t.currentUrlTree,this.rawUrlTree=this.urlHandlingStrategy.merge(this.currentUrlTree,t.rawUrl)}resetUrlToCurrentUrlTree(){this.location.replaceState(this.urlSerializer.serialize(this.rawUrlTree),"",this.generateNgRouterState(this.lastSuccessfulId,this.currentPageId))}cancelNavigationTransition(t,i,r){const o=new lf(t.id,this.serializeUrl(t.extractedUrl),i,r);this.triggerEvent(o),t.resolve(!1)}generateNgRouterState(t,i){return"computed"===this.canceledNavigationResolution?{navigationId:t,\u0275routerPageId:i}:{navigationId:t}}}return e.\u0275fac=function(t){sg()},e.\u0275prov=G({token:e,factory:function(){return aS()},providedIn:"root"}),e})();function lS(e){return"imperative"!==e} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -class cS{}let rV=(()=>{class e{constructor(t,i,r,o,s){this.router=t,this.injector=r,this.preloadingStrategy=o,this.loader=s}setUpPreloading(){this.subscription=this.router.events.pipe(vn(t=>t instanceof ss),_o(()=>this.preload())).subscribe(()=>{})}preload(){return this.processRoutes(this.injector,this.router.config)}ngOnDestroy(){this.subscription&&this.subscription.unsubscribe()}processRoutes(t,i){const r=[];for(const o of i){o.providers&&!o._injector&&(o._injector=bd(o.providers,t,`Route: ${o.path}`));const s=o._injector??t,a=o._loadedInjector??s;o.loadChildren&&!o._loadedRoutes&&void 0===o.canLoad||o.loadComponent&&!o._loadedComponent?r.push(this.preloadConfig(s,o)):(o.children||o._loadedRoutes)&&r.push(this.processRoutes(a,o.children??o._loadedRoutes))}return gt(r).pipe(Se())}preloadConfig(t,i){return this.preloadingStrategy.preload(i,()=>{let r;r=i.loadChildren&&void 0===i.canLoad?this.loader.loadChildren(t,i):J(null);const o=r.pipe(dt(s=>null===s?J(void 0):(i._loadedRoutes=s.routes,i._loadedInjector=s.injector,this.processRoutes(s.injector??t,s.routes))));return i.loadComponent&&!i._loadedComponent?gt([o,this.loader.loadComponent(i)]).pipe(Se()):o})}}return e.\u0275fac=function(t){return new(t||e)(L(ln),L(lm),L(lo),L(cS),L(b_))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */const w_=new q("");let uS=(()=>{class e{constructor(t,i,r={}){this.router=t,this.viewportScroller=i,this.options=r,this.lastId=0,this.lastSource="imperative",this.restoredId=0,this.store={},r.scrollPositionRestoration=r.scrollPositionRestoration||"disabled",r.anchorScrolling=r.anchorScrolling||"disabled"}init(){"disabled"!==this.options.scrollPositionRestoration&&this.viewportScroller.setHistoryScrollRestoration("manual"),this.routerEventsSubscription=this.createScrollEvents(),this.scrollEventsSubscription=this.consumeScrollEvents()}createScrollEvents(){return this.router.events.subscribe(t=>{t instanceof r_?(this.store[this.lastId]=this.viewportScroller.getScrollPosition(),this.lastSource=t.navigationTrigger,this.restoredId=t.restoredState?t.restoredState.navigationId:0):t instanceof ss&&(this.lastId=t.id,this.scheduleScrollEvent(t,this.router.parseUrl(t.urlAfterRedirects).fragment))})}consumeScrollEvents(){return this.router.events.subscribe(t=>{t instanceof kw&&(t.position?"top"===this.options.scrollPositionRestoration?this.viewportScroller.scrollToPosition([0,0]):"enabled"===this.options.scrollPositionRestoration&&this.viewportScroller.scrollToPosition(t.position):t.anchor&&"enabled"===this.options.anchorScrolling?this.viewportScroller.scrollToAnchor(t.anchor):"disabled"!==this.options.scrollPositionRestoration&&this.viewportScroller.scrollToPosition([0,0]))})}scheduleScrollEvent(t,i){this.router.triggerEvent(new kw(t,"popstate"===this.lastSource?this.store[this.restoredId]:null,i))}ngOnDestroy(){this.routerEventsSubscription&&this.routerEventsSubscription.unsubscribe(),this.scrollEventsSubscription&&this.scrollEventsSubscription.unsubscribe()}}return e.\u0275fac=function(t){sg()},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */function Ha(e,n){return{\u0275kind:e,\u0275providers:n}}function S_(e){return[{provide:y_,multi:!0,useValue:e}]}function fS(){const e=St(gn);return n=>{const t=e.get(fc);if(n!==t.components[0])return;const i=e.get(ln),r=e.get(hS);1===e.get(M_)&&i.initialNavigation(),e.get(pS,null,X.Optional)?.setUpPreloading(),e.get(w_,null,X.Optional)?.init(),i.resetRootComponentType(t.componentTypes[0]),r.next(),r.complete()}}const hS=new q("",{factory:()=>new Ue}),M_=new q("",{providedIn:"root",factory:()=>1});const pS=new q("");function lV(e){return Ha(0,[{provide:pS,useExisting:rV},{provide:cS,useExisting:e}])} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -const gS=new q("ROUTER_FORROOT_GUARD"),cV=[Sm,{provide:bw,useClass:Qm},{provide:ln,useFactory:aS},Ic,{provide:as,useFactory:function dS(e){return e.routerState.root},deps:[ln]},b_];function uV(){return new $1("Router",ln)}let Cf=(()=>{class e{constructor(t){}static forRoot(t,i){return{ngModule:e,providers:[cV,[],S_(t),{provide:gS,useFactory:pV,deps:[[ln,new Ll,new Vl]]},{provide:vf,useValue:i||{}},i?.useHash?{provide:ts,useClass:TR}:{provide:ts,useClass:hC},{provide:w_,useFactory:()=>{const e=St(ln),n=St(GP),t=St(vf);return t.scrollOffset&&n.setOffset(t.scrollOffset),new uS(e,n,t)}},i?.preloadingStrategy?lV(i.preloadingStrategy).\u0275providers:[],{provide:$1,multi:!0,useFactory:uV},i?.initialNavigation?gV(i):[],[{provide:mS,useFactory:fS},{provide:P1,multi:!0,useExisting:mS}]]}}static forChild(t){return{ngModule:e,providers:[S_(t)]}}}return e.\u0275fac=function(t){return new(t||e)(L(gS,8))},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[f_]}),e})();function pV(e){return"guarded"}function gV(e){return["disabled"===e.initialNavigation?Ha(3,[{provide:Id,multi:!0,useFactory:()=>{const n=St(ln);return()=>{n.setUpLocationChangeListener()}}},{provide:M_,useValue:2}]).\u0275providers:[],"enabledBlocking"===e.initialNavigation?Ha(2,[{provide:M_,useValue:0},{provide:Id,multi:!0,deps:[gn],useFactory:n=>{const t=n.get(NR,Promise.resolve());let i=!1;return()=>t.then(()=>new Promise(o=>{const s=n.get(ln),a=n.get(hS);(function r(o){n.get(ln).events.pipe(vn(a=>a instanceof ss||a instanceof lf||a instanceof Aw),ne(a=>a instanceof ss||a instanceof lf&&(0===a.code||1===a.code)&&null),vn(a=>null!==a),sn(1)).subscribe(()=>{o()})})(()=>{o(!0),i=!0}),s.afterPreactivation=()=>(o(!0),i||a.closed?J(void 0):a),s.initialNavigation()}))}}]).\u0275providers:[]]}const mS=new q(""); -/** - * @license Angular v14.2.9 - * (c) 2010-2022 Google LLC. https://angular.io/ - * License: MIT - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -let _S=(()=>{class e{constructor(t,i){this._renderer=t,this._elementRef=i,this.onChange=r=>{},this.onTouched=()=>{}}setProperty(t,i){this._renderer.setProperty(this._elementRef.nativeElement,t,i)}registerOnTouched(t){this.onTouched=t}registerOnChange(t){this.onChange=t}setDisabledState(t){this.setProperty("disabled",t)}}return e.\u0275fac=function(t){return new(t||e)(C(pi),C(Je))},e.\u0275dir=B({type:e}),e})(),ls=(()=>{class e extends _S{}return e.\u0275fac=function(){let n;return function(i){return(n||(n=nt(e)))(i||e)}}(),e.\u0275dir=B({type:e,features:[Be]}),e})();const ur=new q("NgValueAccessor"),yV={provide:ur,useExisting:Te(()=>Pc),multi:!0},DV=new q("CompositionEventMode"); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */let Pc=(()=>{class e extends _S{constructor(t,i,r){super(t,i),this._compositionMode=r,this._composing=!1,null==this._compositionMode&&(this._compositionMode=!function bV(){const e=lr()?lr().getUserAgent():"";return/android (\d+)/.test(e.toLowerCase())}())}writeValue(t){this.setProperty("value",t??"")}_handleInput(t){(!this._compositionMode||this._compositionMode&&!this._composing)&&this.onChange(t)}_compositionStart(){this._composing=!0}_compositionEnd(t){this._composing=!1,this._compositionMode&&this.onChange(t)}}return e.\u0275fac=function(t){return new(t||e)(C(pi),C(Je),C(DV,8))},e.\u0275dir=B({type:e,selectors:[["input","formControlName","",3,"type","checkbox"],["textarea","formControlName",""],["input","formControl","",3,"type","checkbox"],["textarea","formControl",""],["input","ngModel","",3,"type","checkbox"],["textarea","ngModel",""],["","ngDefaultControl",""]],hostBindings:function(t,i){1&t&&W("input",function(o){return i._handleInput(o.target.value)})("blur",function(){return i.onTouched()})("compositionstart",function(){return i._compositionStart()})("compositionend",function(o){return i._compositionEnd(o.target.value)})},features:[it([yV]),Be]}),e})(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */const yn=new q("NgValidators"),bo=new q("NgAsyncValidators");function TS(e){return null!=e}function IS(e){return Xl(e)?gt(e):e}function AS(e){let n={};return e.forEach(t=>{n=null!=t?{...n,...t}:n}),0===Object.keys(n).length?null:n}function kS(e,n){return n.map(t=>t(e))}function OS(e){return e.map(n=>function SV(e){return!e.validate}(n)?n:t=>n.validate(t))}function N_(e){return null!=e?function xS(e){if(!e)return null;const n=e.filter(TS);return 0==n.length?null:function(t){return AS(kS(t,n))}}(OS(e)):null}function E_(e){return null!=e?function RS(e){if(!e)return null;const n=e.filter(TS);return 0==n.length?null:function(t){ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -return function _V(...e){const n=rt(e),{args:t,keys:i}=iw(e),r=new je(o=>{const{length:s}=t;if(!s)return void o.complete();const a=new Array(s);let l=s,u=s;for(let f=0;f{p||(p=!0,u--),a[f]=m},()=>l--,void 0,()=>{(!l||!p)&&(u||o.next(i?rw(i,a):a),o.complete())}))}});return n?r.pipe(Ym(n)):r}(kS(t,n).map(IS)).pipe(ne(AS))}}(OS(e)):null}function PS(e,n){return null===e?[n]:Array.isArray(e)?[...e,n]:[e,n]}function T_(e){return e?Array.isArray(e)?e:[e]:[]}function Sf(e,n){return Array.isArray(e)?e.includes(n):e===n}function VS(e,n){const t=T_(n);return T_(e).forEach(r=>{Sf(t,r)||t.push(r)}),t}function BS(e,n){return T_(n).filter(t=>!Sf(e,t))} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */class HS{constructor(){this._rawValidators=[],this._rawAsyncValidators=[],this._onDestroyCallbacks=[]}get value(){return this.control?this.control.value:null}get valid(){return this.control?this.control.valid:null}get invalid(){return this.control?this.control.invalid:null}get pending(){return this.control?this.control.pending:null}get disabled(){return this.control?this.control.disabled:null}get enabled(){return this.control?this.control.enabled:null}get errors(){return this.control?this.control.errors:null}get pristine(){return this.control?this.control.pristine:null}get dirty(){return this.control?this.control.dirty:null}get touched(){return this.control?this.control.touched:null}get status(){return this.control?this.control.status:null}get untouched(){return this.control?this.control.untouched:null}get statusChanges(){return this.control?this.control.statusChanges:null}get valueChanges(){return this.control?this.control.valueChanges:null}get path(){return null}_setValidators(n){this._rawValidators=n||[],this._composedValidatorFn=N_(this._rawValidators)}_setAsyncValidators(n){this._rawAsyncValidators=n||[],this._composedAsyncValidatorFn=E_(this._rawAsyncValidators)}get validator(){return this._composedValidatorFn||null}get asyncValidator(){return this._composedAsyncValidatorFn||null}_registerOnDestroy(n){this._onDestroyCallbacks.push(n)}_invokeOnDestroyCallbacks(){this._onDestroyCallbacks.forEach(n=>n()),this._onDestroyCallbacks=[]}reset(n){this.control&&this.control.reset(n)}hasError(n,t){return!!this.control&&this.control.hasError(n,t)}getError(n,t){return this.control?this.control.getError(n,t):null}} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */class On extends HS{get formDirective(){return null}get path(){return null}} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */class Do extends HS{constructor(){super(...arguments),this._parent=null,this.name=null,this.valueAccessor=null}} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */let I_=(()=>{class e extends class jS{constructor(n){this._cd=n}get isTouched(){return!!this._cd?.control?.touched}get isUntouched(){return!!this._cd?.control?.untouched}get isPristine(){return!!this._cd?.control?.pristine}get isDirty(){return!!this._cd?.control?.dirty}get isValid(){return!!this._cd?.control?.valid}get isInvalid(){return!!this._cd?.control?.invalid}get isPending(){return!!this._cd?.control?.pending}get isSubmitted(){return!!this._cd?.submitted}}{constructor(t){super(t)}}return e.\u0275fac=function(t){return new(t||e)(C(Do,2))},e.\u0275dir=B({type:e,selectors:[["","formControlName",""],["","ngModel",""],["","formControl",""]],hostVars:14,hostBindings:function(t,i){2&t&&ht("ng-untouched",i.isUntouched)("ng-touched",i.isTouched)("ng-pristine",i.isPristine)("ng-dirty",i.isDirty)("ng-valid",i.isValid)("ng-invalid",i.isInvalid)("ng-pending",i.isPending)},features:[Be]}),e})(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -const Fc="VALID",Nf="INVALID",ja="PENDING",Lc="DISABLED";function US(e){return Array.isArray(e)?N_(e):e||null}function GS(e){return Array.isArray(e)?E_(e):e||null}function Ef(e){return null!=e&&!Array.isArray(e)&&"object"==typeof e}function Vc(e,n){(function F_(e,n){const t=function FS(e){return e._rawValidators}(e);null!==n.validator?e.setValidators(PS(t,n.validator)):"function"==typeof t&&e.setValidators([t]);const i=function LS(e){return e._rawAsyncValidators}(e);null!==n.asyncValidator?e.setAsyncValidators(PS(i,n.asyncValidator)):"function"==typeof i&&e.setAsyncValidators([i]);const r=()=>e.updateValueAndValidity();Af(n._rawValidators,r),Af(n._rawAsyncValidators,r)})(e,n),n.valueAccessor.writeValue(e.value),e.disabled&&n.valueAccessor.setDisabledState?.(!0),function RV(e,n){n.valueAccessor.registerOnChange(t=>{e._pendingValue=t,e._pendingChange=!0,e._pendingDirty=!0,"change"===e.updateOn&&KS(e,n)})}(e,n),function FV(e,n){const t=(i,r)=>{n.valueAccessor.writeValue(i),r&&n.viewToModelUpdate(i)};e.registerOnChange(t),n._registerOnDestroy(()=>{e._unregisterOnChange(t)})}(e,n),function PV(e,n){n.valueAccessor.registerOnTouched(()=>{e._pendingTouched=!0,"blur"===e.updateOn&&e._pendingChange&&KS(e,n),"submit"!==e.updateOn&&e.markAsTouched()})}(e,n),function xV(e,n){if(n.valueAccessor.setDisabledState){const t=i=>{n.valueAccessor.setDisabledState(i)};e.registerOnDisabledChange(t),n._registerOnDestroy(()=>{e._unregisterOnDisabledChange(t)})}}(e,n)}function Af(e,n){e.forEach(t=>{t.registerOnValidatorChange&&t.registerOnValidatorChange(n)})}function KS(e,n){e._pendingDirty&&e.markAsDirty(),e.setValue(e._pendingValue,{emitModelToViewChange:!1}),n.viewToModelUpdate(e._pendingValue),e._pendingChange=!1} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -function QS(e,n){const t=e.indexOf(n);t>-1&&e.splice(t,1)} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */function XS(e){return"object"==typeof e&&null!==e&&2===Object.keys(e).length&&"value"in e&&"disabled"in e}const GV={provide:Do,useExisting:Te(()=>Of)},iM=(()=>Promise.resolve())(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */let Of=(()=>{class e extends Do{constructor(t,i,r,o,s){super(),this._changeDetectorRef=s,this.control=new class extends class YS{constructor(n,t){this._pendingDirty=!1,this._hasOwnPendingAsyncValidator=!1,this._pendingTouched=!1,this._onCollectionChange=()=>{},this._parent=null,this.pristine=!0,this.touched=!1,this._onDisabledChange=[],this._rawValidators=n,this._rawAsyncValidators=t,this._composedValidatorFn=US(this._rawValidators),this._composedAsyncValidatorFn=GS(this._rawAsyncValidators)}get validator(){return this._composedValidatorFn}set validator(n){this._rawValidators=this._composedValidatorFn=n}get asyncValidator(){return this._composedAsyncValidatorFn}set asyncValidator(n){this._rawAsyncValidators=this._composedAsyncValidatorFn=n}get parent(){return this._parent}get valid(){return this.status===Fc}get invalid(){return this.status===Nf}get pending(){return this.status==ja}get disabled(){return this.status===Lc}get enabled(){return this.status!==Lc}get dirty(){return!this.pristine}get untouched(){return!this.touched}get updateOn(){return this._updateOn?this._updateOn:this.parent?this.parent.updateOn:"change"}setValidators(n){this._rawValidators=n,this._composedValidatorFn=US(n)}setAsyncValidators(n){this._rawAsyncValidators=n,this._composedAsyncValidatorFn=GS(n)}addValidators(n){this.setValidators(VS(n,this._rawValidators))}addAsyncValidators(n){this.setAsyncValidators(VS(n,this._rawAsyncValidators))}removeValidators(n){this.setValidators(BS(n,this._rawValidators))}removeAsyncValidators(n){this.setAsyncValidators(BS(n,this._rawAsyncValidators))}hasValidator(n){return Sf(this._rawValidators,n)}hasAsyncValidator(n){return Sf(this._rawAsyncValidators,n)}clearValidators(){this.validator=null}clearAsyncValidators(){this.asyncValidator=null}markAsTouched(n={}){this.touched=!0,this._parent&&!n.onlySelf&&this._parent.markAsTouched(n)}markAllAsTouched(){this.markAsTouched({onlySelf:!0}),this._forEachChild(n=>n.markAllAsTouched())}markAsUntouched(n={}){this.touched=!1,this._pendingTouched=!1,this._forEachChild(t=>{t.markAsUntouched({onlySelf:!0})}),this._parent&&!n.onlySelf&&this._parent._updateTouched(n)}markAsDirty(n={}){this.pristine=!1,this._parent&&!n.onlySelf&&this._parent.markAsDirty(n)}markAsPristine(n={}){this.pristine=!0,this._pendingDirty=!1,this._forEachChild(t=>{t.markAsPristine({onlySelf:!0})}),this._parent&&!n.onlySelf&&this._parent._updatePristine(n)}markAsPending(n={}){this.status=ja,!1!==n.emitEvent&&this.statusChanges.emit(this.status),this._parent&&!n.onlySelf&&this._parent.markAsPending(n)}disable(n={}){const t=this._parentMarkedDirty(n.onlySelf);this.status=Lc,this.errors=null,this._forEachChild(i=>{i.disable({...n,onlySelf:!0})}),this._updateValue(),!1!==n.emitEvent&&(this.valueChanges.emit(this.value),this.statusChanges.emit(this.status)),this._updateAncestors({...n,skipPristineCheck:t}),this._onDisabledChange.forEach(i=>i(!0))}enable(n={}){const t=this._parentMarkedDirty(n.onlySelf);this.status=Fc,this._forEachChild(i=>{i.enable({...n,onlySelf:!0})}),this.updateValueAndValidity({onlySelf:!0,emitEvent:n.emitEvent}),this._updateAncestors({...n,skipPristineCheck:t}),this._onDisabledChange.forEach(i=>i(!1))}_updateAncestors(n){this._parent&&!n.onlySelf&&(this._parent.updateValueAndValidity(n),n.skipPristineCheck||this._parent._updatePristine(),this._parent._updateTouched())}setParent(n){this._parent=n}getRawValue(){return this.value}updateValueAndValidity(n={}){this._setInitialStatus(),this._updateValue(),this.enabled&&(this._cancelExistingSubscription(),this.errors=this._runValidator(),this.status=this._calculateStatus(),(this.status===Fc||this.status===ja)&&this._runAsyncValidator(n.emitEvent)),!1!==n.emitEvent&&(this.valueChanges.emit(this.value),this.statusChanges.emit(this.status)),this._parent&&!n.onlySelf&&this._parent.updateValueAndValidity(n)}_updateTreeValidity(n={emitEvent:!0}){this._forEachChild(t=>t._updateTreeValidity(n)),this.updateValueAndValidity({onlySelf:!0,emitEvent:n.emitEvent})}_setInitialStatus(){this.status=this._allControlsDisabled()?Lc:Fc}_runValidator(){return this.validator?this.validator(this):null}_runAsyncValidator(n){if(this.asyncValidator){this.status=ja,this._hasOwnPendingAsyncValidator=!0;const t=IS(this.asyncValidator(this));this._asyncValidationSubscription=t.subscribe(i=>{this._hasOwnPendingAsyncValidator=!1,this.setErrors(i,{emitEvent:n})})}}_cancelExistingSubscription(){this._asyncValidationSubscription&&(this._asyncValidationSubscription.unsubscribe(),this._hasOwnPendingAsyncValidator=!1)}setErrors(n,t={}){this.errors=n,this._updateControlsErrors(!1!==t.emitEvent)}get(n){let t=n;return null==t||(Array.isArray(t)||(t=t.split(".")),0===t.length)?null:t.reduce((i,r)=>i&&i._find(r),this)}getError(n,t){const i=t?this.get(t):this;return i&&i.errors?i.errors[n]:null}hasError(n,t){return!!this.getError(n,t)}get root(){let n=this;for(;n._parent;)n=n._parent;return n}_updateControlsErrors(n){this.status=this._calculateStatus(),n&&this.statusChanges.emit(this.status),this._parent&&this._parent._updateControlsErrors(n)}_initObservables(){this.valueChanges=new ue,this.statusChanges=new ue}_calculateStatus(){return this._allControlsDisabled()?Lc:this.errors?Nf:this._hasOwnPendingAsyncValidator||this._anyControlsHaveStatus(ja)?ja:this._anyControlsHaveStatus(Nf)?Nf:Fc}_anyControlsHaveStatus(n){return this._anyControls(t=>t.status===n)}_anyControlsDirty(){return this._anyControls(n=>n.dirty)}_anyControlsTouched(){return this._anyControls(n=>n.touched)}_updatePristine(n={}){this.pristine=!this._anyControlsDirty(),this._parent&&!n.onlySelf&&this._parent._updatePristine(n)}_updateTouched(n={}){this.touched=this._anyControlsTouched(),this._parent&&!n.onlySelf&&this._parent._updateTouched(n)}_registerOnCollectionChange(n){this._onCollectionChange=n}_setUpdateStrategy(n){Ef(n)&&null!=n.updateOn&&(this._updateOn=n.updateOn)}_parentMarkedDirty(n){return!n&&!(!this._parent||!this._parent.dirty)&&!this._parent._anyControlsDirty()}_find(n){return null}} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */{constructor(n=null,t,i){super(function x_(e){return(Ef(e)?e.validators:e)||null}(t),function R_(e,n){return(Ef(n)?n.asyncValidators:e)||null}(i,t)),this.defaultValue=null,this._onChange=[],this._pendingChange=!1,this._applyFormState(n),this._setUpdateStrategy(t),this._initObservables(),this.updateValueAndValidity({onlySelf:!0,emitEvent:!!this.asyncValidator}),Ef(t)&&(t.nonNullable||t.initialValueIsDefault)&&(this.defaultValue=XS(n)?n.value:n)}setValue(n,t={}){this.value=this._pendingValue=n,this._onChange.length&&!1!==t.emitModelToViewChange&&this._onChange.forEach(i=>i(this.value,!1!==t.emitViewToModelChange)),this.updateValueAndValidity(t)}patchValue(n,t={}){this.setValue(n,t)}reset(n=this.defaultValue,t={}){this._applyFormState(n),this.markAsPristine(t),this.markAsUntouched(t),this.setValue(this.value,t),this._pendingChange=!1}_updateValue(){}_anyControls(n){return!1}_allControlsDisabled(){return this.disabled}registerOnChange(n){this._onChange.push(n)}_unregisterOnChange(n){QS(this._onChange,n)}registerOnDisabledChange(n){this._onDisabledChange.push(n)}_unregisterOnDisabledChange(n){QS(this._onDisabledChange,n)}_forEachChild(n){}_syncPendingControls(){return!("submit"!==this.updateOn||(this._pendingDirty&&this.markAsDirty(),this._pendingTouched&&this.markAsTouched(),!this._pendingChange)||(this.setValue(this._pendingValue,{onlySelf:!0,emitModelToViewChange:!1}),0))}_applyFormState(n){XS(n)?(this.value=this._pendingValue=n.value,n.disabled?this.disable({onlySelf:!0,emitEvent:!1}):this.enable({onlySelf:!0,emitEvent:!1})):this.value=this._pendingValue=n}},this._registered=!1,this.update=new ue,this._parent=t,this._setValidators(i),this._setAsyncValidators(r),this.valueAccessor=function V_(e,n){if(!n)return null;let t,i,r;return Array.isArray(n),n.forEach(o=>{o.constructor===Pc?t=o:function BV(e){return Object.getPrototypeOf(e.constructor)===ls}(o)?i=o:r=o}),r||i||t||null}(0,o)}ngOnChanges(t){if(this._checkForErrors(),!this._registered||"name"in t){if(this._registered&&(this._checkName(),this.formDirective)){const i=t.name.previousValue;this.formDirective.removeControl({name:i,path:this._getPath(i)})}this._setUpControl()}"isDisabled"in t&&this._updateDisabled(t),function L_(e,n){if(!e.hasOwnProperty("model"))return!1;const t=e.model;return!!t.isFirstChange()||!Object.is(n,t.currentValue)}(t,this.viewModel)&&(this._updateValue(this.model),this.viewModel=this.model)}ngOnDestroy(){this.formDirective&&this.formDirective.removeControl(this)}get path(){return this._getPath(this.name)}get formDirective(){return this._parent?this._parent.formDirective:null}viewToModelUpdate(t){this.viewModel=t,this.update.emit(t)}_setUpControl(){this._setUpdateStrategy(),this._isStandalone()?this._setUpStandalone():this.formDirective.addControl(this),this._registered=!0}_setUpdateStrategy(){this.options&&null!=this.options.updateOn&&(this.control._updateOn=this.options.updateOn)}_isStandalone(){return!this._parent||!(!this.options||!this.options.standalone)}_setUpStandalone(){Vc(this.control,this),this.control.updateValueAndValidity({emitEvent:!1})}_checkForErrors(){this._isStandalone()||this._checkParentType(),this._checkName()}_checkParentType(){}_checkName(){this.options&&this.options.name&&(this.name=this.options.name),this._isStandalone()}_updateValue(t){iM.then(()=>{this.control.setValue(t,{emitViewToModelChange:!1}),this._changeDetectorRef?.markForCheck()})}_updateDisabled(t){const i=t.isDisabled.currentValue,r=0!==i&&function Br(e){return"boolean"==typeof e?e:null!=e&&"false"!==e} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */(i);iM.then(()=>{r&&!this.control.disabled?this.control.disable():!r&&this.control.disabled&&this.control.enable(),this._changeDetectorRef?.markForCheck()})}_getPath(t){return this._parent? -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -function Tf(e,n){return[...n.path,e]}(t,this._parent):[t]}}return e.\u0275fac=function(t){return new(t||e)(C(On,9),C(yn,10),C(bo,10),C(ur,10),C(Vr,8))},e.\u0275dir=B({type:e,selectors:[["","ngModel","",3,"formControlName","",3,"formControl",""]],inputs:{name:"name",isDisabled:["disabled","isDisabled"],model:["ngModel","model"],options:["ngModelOptions","options"]},outputs:{update:"ngModelChange"},exportAs:["ngModel"],features:[it([GV]),Be,zt]}),e})(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -const zV={provide:ur,useExisting:Te(()=>H_),multi:!0};let H_=(()=>{class e extends ls{writeValue(t){this.setProperty("value",t??"")}registerOnChange(t){this.onChange=i=>{t(""==i?null:parseFloat(i))}}}return e.\u0275fac=function(){let n;return function(i){return(n||(n=nt(e)))(i||e)}}(),e.\u0275dir=B({type:e,selectors:[["input","type","number","formControlName",""],["input","type","number","formControl",""],["input","type","number","ngModel",""]],hostBindings:function(t,i){1&t&&W("input",function(o){return i.onChange(o.target.value)})("blur",function(){return i.onTouched()})},features:[it([zV]),Be]}),e})(),rM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({}),e})(),gB=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[rM]}),e})(),CM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[gB]}),e})(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -const wM=new q("ngx-mask config"),SM=new q("new ngx-mask config"),MM=new q("initial ngx-mask config"),_B={suffix:"",prefix:"",thousandSeparator:" ",decimalMarker:[".",","],clearIfNotMatch:!1,showTemplate:!1,showMaskTyped:!1,placeHolderCharacter:"_",dropSpecialCharacters:!0,hiddenInput:void 0,shownMaskExpression:"",separatorLimit:"",allowNegativeNumbers:!1,validation:!0,specialCharacters:["-","/","(",")",".",":"," ","+",",","@","[","]",'"',"'"],leadZeroDateTime:!1,triggerOnMaskChange:!1,maskFilled:new ue,patterns:{0:{pattern:new RegExp("\\d")},9:{pattern:new RegExp("\\d"),optional:!0},X:{pattern:new RegExp("\\d"),symbol:"*"},A:{pattern:new RegExp("[a-zA-Z0-9]")},S:{pattern:new RegExp("[a-zA-Z]")},U:{pattern:new RegExp("[A-Z]")},L:{pattern:new RegExp("[a-z]")},d:{pattern:new RegExp("\\d")},m:{pattern:new RegExp("\\d")},M:{pattern:new RegExp("\\d")},H:{pattern:new RegExp("\\d")},h:{pattern:new RegExp("\\d")},s:{pattern:new RegExp("\\d")}}}; -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */let vB=(()=>{class e{constructor(t){this._config=t,this.maskExpression="",this.actualValue="",this.shownMaskExpression="",this._formatWithSeparators=(i,r,o,s)=>{let a=[],l="";if(Array.isArray(o)){const v=new RegExp(o.map(y=>"[\\^$.|?*+()".indexOf(y)>=0?`\\${y}`:y).join("|"));a=i.split(v),l=i.match(v)?.[0]??""}else a=i.split(o),l=o;const u=a.length>1?`${l}${a[1]}`:"";let f=a[0]??"";const p=this.separatorLimit.replace(/\s/g,"");p&&+p&&(f="-"===f[0]?`-${f.slice(1,f.length).slice(0,p.length)}`:f.slice(0,p.length));const m=/(\d+)(\d{3})/;for(;r&&m.test(f);)f=f.replace(m,"$1"+r+"$2");return void 0===s?f+u:0===s?f:f+u.substring(0,s+1)},this.percentage=i=>Number(i)>=0&&Number(i)<=100,this.getPrecision=i=>{const r=i.split(".");return r.length>1?Number(r[r.length-1]):1/0},this.checkAndRemoveSuffix=i=>{for(let r=this.suffix?.length-1;r>=0;r--){const o=this.suffix.substring(r,this.suffix?.length);if(i.includes(o)&&r!==this.suffix?.length-1&&(r-1<0||!i.includes(this.suffix.substring(r-1,this.suffix?.length))))return i.replace(o,"")}return i},this.checkInputPrecision=(i,r,o)=>{if(r<1/0){if(Array.isArray(o)){const u=o.find(f=>f!==this.thousandSeparator);o=u||o[0]}const s=new RegExp(this._charToRegExpExpression(o)+`\\d{${r}}.*$`),l=(i.match(s)??[])[0]?.length??0;l-1>r&&(i=i.substring(0,i.length-(l-1-r))),0===r&&this._compareOrIncludes(i[i.length-1],o,this.thousandSeparator)&&(i=i.substring(0,i.length-1))}return i},this._shift=new Set,this.clearIfNotMatch=this._config.clearIfNotMatch,this.dropSpecialCharacters=this._config.dropSpecialCharacters,this.maskSpecialCharacters=this._config.specialCharacters,this.maskAvailablePatterns=this._config.patterns,this.prefix=this._config.prefix,this.suffix=this._config.suffix,this.thousandSeparator=this._config.thousandSeparator,this.decimalMarker=this._config.decimalMarker,this.hiddenInput=this._config.hiddenInput,this.showMaskTyped=this._config.showMaskTyped,this.placeHolderCharacter=this._config.placeHolderCharacter,this.validation=this._config.validation,this.separatorLimit=this._config.separatorLimit,this.allowNegativeNumbers=this._config.allowNegativeNumbers,this.leadZeroDateTime=this._config.leadZeroDateTime}applyMaskWithPattern(t,i){const[r,o]=i;return this.customPattern=o,this.applyMask(t,r)}applyMask(t,i,r=0,o=!1,s=!1,a=(()=>{})){if(!i||"string"!=typeof t)return"";let l=0,u="",f=!1,p=!1,m=1,v=!1;t.slice(0,this.prefix.length)===this.prefix&&(t=t.slice(this.prefix.length,t.length)),this.suffix&&t?.length>0&&(t=this.checkAndRemoveSuffix(t));const y=t.toString().split("");if("IP"===i){const k=t.split(".");this.ipError=this._validIP(k),i="099.099.099.099"}const D=[];for(let k=0;k11?"00.000.000/0000-00":"000.000.000-00"),i.startsWith("percent")){if(t.match("[a-z]|[A-Z]")||t.match(/[-!$%^&*()_+|~=`{}\[\]:";'<>?,\/.]/)){t=this._stripToDecimal(t);const k=this.getPrecision(i);t=this.checkInputPrecision(t,k,this.decimalMarker)}t.indexOf(".")>0&&!this.percentage(t.substring(0,t.indexOf(".")))&&(t=`${t.substring(0,t.indexOf(".")-1)}${t.substring(t.indexOf("."),t.length)}`),u=this.percentage(t)?t:t.substring(0,t.length-1)}else if(i.startsWith("separator")){(t.match("[w\u0430-\u044f\u0410-\u042f]")||t.match("[\u0401\u0451\u0410-\u044f]")||t.match("[a-z]|[A-Z]")||t.match(/[-@#!$%\\^&*()_\xa3\xac'+|~=`{}\]:";<>.?/]/)||t.match("[^A-Za-z0-9,]"))&&(t=this._stripToDecimal(t)),t=t.length>1&&"0"===t[0]&&t[1]!==this.thousandSeparator&&!this._compareOrIncludes(t[1],this.decimalMarker,this.thousandSeparator)&&!s?t.slice(0,t.length-1):t,s&&(t=this._compareOrIncludes(t[t.length-1],this.decimalMarker,this.thousandSeparator)?t.slice(0,t.length-1):t);const k=this._charToRegExpExpression(this.thousandSeparator);let x='@#!$%^&*()_+|~=`{}\\[\\]:\\s,\\.";<>?\\/'.replace(k,"");if(Array.isArray(this.decimalMarker))for(const Ae of this.decimalMarker)x=x.replace(this._charToRegExpExpression(Ae),"");else x=x.replace(this._charToRegExpExpression(this.decimalMarker),"");const U=new RegExp("["+x+"]");(t.match(U)||1===t.length&&this._compareOrIncludes(t,this.decimalMarker,this.thousandSeparator))&&(t=t.substring(0,t.length-1));const ge=this.getPrecision(i),Ce=(t=this.checkInputPrecision(t,ge,this.decimalMarker)).replace(new RegExp(k,"g"),"");u=this._formatWithSeparators(Ce,this.thousandSeparator,this.decimalMarker,ge);const Ke=u.indexOf(",")-t.indexOf(","),Le=u.length-t.length;if(Le>0&&","!==u[r]){p=!0;let Ae=0;do{this._shift.add(r+Ae),Ae++}while(Ae0&&!(u.indexOf(",")>=r&&r>3)||!(u.indexOf(".")>=r&&r>3)&&Le<=0?(this._shift.clear(),p=!0,m=Le,this._shift.add(r+=Le)):this._shift.clear()}else for(let k=0,x=y[0];k2){l+=1,this._shiftStep(i,l,y.length),k--,this.leadZeroDateTime&&(u+="0");continue}if("h"===i[l]&&"2"===u&&Number(x)>3){l+=1,k--;continue}if("m"===i[l]&&Number(x)>5){l+=1,this._shiftStep(i,l,y.length),k--,this.leadZeroDateTime&&(u+="0");continue}if("s"===i[l]&&Number(x)>5){l+=1,this._shiftStep(i,l,y.length),k--,this.leadZeroDateTime&&(u+="0");continue}const U=31;if("d"===i[l]&&(Number(x)>3&&this.leadZeroDateTime||Number(t.slice(l,l+2))>U||"/"===t[l+1])){l+=1,this._shiftStep(i,l,y.length),k--,this.leadZeroDateTime&&(u+="0");continue}if("M"===i[l]){const Ce=0===l&&(Number(x)>2||Number(t.slice(l,l+2))>12||"/"===t[l+1]),Ke=t.slice(l-3,l-1).includes("/")&&("/"===t[l-2]&&Number(t.slice(l-1,l+1))>12&&"/"!==t[l]||"/"===t[l]||"/"===t[l-3]&&Number(t.slice(l-2,l))>12&&"/"!==t[l-1]||"/"===t[l-1]),Le=Number(t.slice(l-3,l-1))<=U&&!t.slice(l-3,l-1).includes("/")&&"/"===t[l-1]&&(Number(t.slice(l,l+2))>12||"/"===t[l+1]),Ae=Number(t.slice(l-3,l-1))>U&&!t.slice(l-3,l-1).includes("/")&&!t.slice(l-2,l).includes("/")&&Number(t.slice(l-2,l))>12,cn=Number(t.slice(l-3,l-1))<=U&&!t.slice(l-3,l-1).includes("/")&&"/"!==t[l-1]&&Number(t.slice(l-1,l+1))>12;if(Number(x)>1&&this.leadZeroDateTime||Ce||Ke||Le||Ae||cn){l+=1,this._shiftStep(i,l,y.length),k--,this.leadZeroDateTime&&(u+="0");continue}}u+=x,l++}else" "===x&&" "===i[l]?(u+=x,l++):-1!==this.maskSpecialCharacters.indexOf(i[l]??"")?(u+=i[l],l++,this._shiftStep(i,l,y.length),k--):this.maskSpecialCharacters.indexOf(x)>-1&&this.maskAvailablePatterns[i[l]??""]&&this.maskAvailablePatterns[i[l]??""]?.optional?(!!y[l]&&"099.099.099.099"!==i&&"000.000.000-00"!==i&&"00.000.000/0000-00"!==i&&!i.match(/^9+\.0+$/)&&(u+=y[l]),l++,k--):"*"===this.maskExpression[l+1]&&this._findSpecialChar(this.maskExpression[l+2]??"")&&this._findSpecialChar(x)===this.maskExpression[l+2]&&f||"?"===this.maskExpression[l+1]&&this._findSpecialChar(this.maskExpression[l+2]??"")&&this._findSpecialChar(x)===this.maskExpression[l+2]&&f?(l+=3,u+=x):this.showMaskTyped&&this.maskSpecialCharacters.indexOf(x)<0&&x!==this.placeHolderCharacter&&(v=!0);u.length+1===i.length&&-1!==this.maskSpecialCharacters.indexOf(i[i.length-1]??"")&&(u+=i[i.length-1]);let w=r+1;for(;this._shift.has(w);)m++,w++;let N=o&&!i.startsWith("separator")?l:this._shift.has(r)?m:0;v&&N--,a(N,p),m<0&&this._shift.clear();let A=!1;s&&(A=y.every(k=>this.maskSpecialCharacters.includes(k)));let S=`${this.prefix}${A?"":u}${this.suffix}`;return 0===u.length&&(S=`${this.prefix}${u}`),S}_findSpecialChar(t){return this.maskSpecialCharacters.find(i=>i===t)}_checkSymbolMask(t,i){return this.maskAvailablePatterns=this.customPattern?this.customPattern:this.maskAvailablePatterns,(this.maskAvailablePatterns[i]?.pattern&&this.maskAvailablePatterns[i]?.pattern.test(t))??!1}_stripToDecimal(t){return t.split("").filter((i,r)=>{const o="string"==typeof this.decimalMarker?i===this.decimalMarker:this.decimalMarker.includes(i);return i.match("^-?\\d")||i===this.thousandSeparator||o||"-"===i&&0===r&&this.allowNegativeNumbers}).join("")}_charToRegExpExpression(t){return t&&(" "===t?"\\s":"[\\^$.|?*+()".indexOf(t)>=0?`\\${t}`:t)}_shiftStep(t,i,r){const o=/[*?]/g.test(t.slice(0,i))?r:i;this._shift.add(o+this.prefix.length||0)}_compareOrIncludes(t,i,r){return Array.isArray(i)?i.filter(o=>o!==r).includes(t):t===i}_validIP(t){return!(4===t.length&&!t.some((i,r)=>t.length!==r+1?""===i||Number(i)>255:""===i||Number(i.substring(0,3))>255))}}return e.\u0275fac=function(t){return new(t||e)(L(wM))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})();function yB(e,n){return n instanceof Function?{...e,...n()}:{...e,...n}}let bB=(()=>{class e{static forRoot(t){return{ngModule:e,providers:[{provide:SM,useValue:t},{provide:MM,useValue:_B},{provide:wM,useFactory:yB,deps:[MM,SM]},vB]}}static forChild(){return{ngModule:e}}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({}),e})();const NM=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};NM.KeyboardEvent||(NM.KeyboardEvent=function(e,n){});let EM=(()=>{class e{constructor(t,i){this.document=t,this.platformId=i,this.documentIsAccessible=function xC(e){return e===OC}(this.platformId)}static getCookieRegExp(t){const i=t.replace(/([\[\]\{\}\(\)\|\=\;\+\?\,\.\*\^\$])/gi,"\\$1");return new RegExp("(?:^"+i+"|;\\s*"+i+")=(.*?)(?:;|$)","g")}static safeDecodeURIComponent(t){try{return decodeURIComponent(t)}catch{return t}}check(t){return!!this.documentIsAccessible&&(t=encodeURIComponent(t),e.getCookieRegExp(t).test(this.document.cookie))}get(t){if(this.documentIsAccessible&&this.check(t)){t=encodeURIComponent(t);const r=e.getCookieRegExp(t).exec(this.document.cookie);return r[1]?e.safeDecodeURIComponent(r[1]):""}return""}getAll(){if(!this.documentIsAccessible)return{};const t={},i=this.document;return i.cookie&&""!==i.cookie&&i.cookie.split(";").forEach(r=>{const[o,s]=r.split("=");t[e.safeDecodeURIComponent(o.replace(/^ /,""))]=e.safeDecodeURIComponent(s)}),t}set(t,i,r,o,s,a,l){if(!this.documentIsAccessible)return;if("number"==typeof r||r instanceof Date||o||s||a||l)return void this.set(t,i,{expires:r,path:o,domain:s,secure:a,sameSite:l||"Lax"});let u=encodeURIComponent(t)+"="+encodeURIComponent(i)+";";const f=r||{};f.expires&&(u+="number"==typeof f.expires?"expires="+new Date((new Date).getTime()+1e3*f.expires*60*60*24).toUTCString()+";":"expires="+f.expires.toUTCString()+";"),f.path&&(u+="path="+f.path+";"),f.domain&&(u+="domain="+f.domain+";"),!1===f.secure&&"None"===f.sameSite&&(f.secure=!0,console.warn(`[ngx-cookie-service] Cookie ${t} was forced with secure flag because sameSite=None.More details : https://github.com/stevermeister/ngx-cookie-service/issues/86#issuecomment-597720130`)),f.secure&&(u+="secure;"),f.sameSite||(f.sameSite="Lax"),u+="sameSite="+f.sameSite+";",this.document.cookie=u}delete(t,i,r,o,s="Lax"){if(!this.documentIsAccessible)return;const a=new Date("Thu, 01 Jan 1970 00:00:01 GMT");this.set(t,"",{expires:a,path:i,domain:r,secure:o,sameSite:s})}deleteAll(t,i,r,o="Lax"){if(!this.documentIsAccessible)return;const s=this.getAll();for(const a in s)s.hasOwnProperty(a)&&this.delete(a,t,i,r,o)}}return e.\u0275fac=function(t){return new(t||e)(L(Dt),L(dc))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})();const DB=[];let CB=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[Cf.forRoot(DB),Cf]}),e})(),wB=(()=>{class e{constructor(){this.title="dashboard"}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275cmp=et({type:e,selectors:[["app-root"]],decls:1,vars:0,template:function(t,i){1&t&&Li(0,"router-outlet")},dependencies:[d_],encapsulation:2}),e})();const SB=["addListener","removeListener"],MB=["addEventListener","removeEventListener"],NB=["on","off"];function xn(e,n,t,i){if(ye(t)&&(i=t,t=void 0),i)return xn(e,n,t).pipe(Ym(i));const[r,o]=function IB(e){return ye(e.addEventListener)&&ye(e.removeEventListener)}(e)?MB.map(s=>a=>e[s](n,a,t)):function EB(e){return ye(e.addListener)&&ye(e.removeListener)}(e)?SB.map(TM(e,n)):function TB(e){return ye(e.on)&&ye(e.off)}(e)?NB.map(TM(e,n)):[];if(!r&&Ts(e))return dt(s=>xn(s,n,t))(ut(e));if(!r)throw new TypeError("Invalid event target");return new je(s=>{const a=(...l)=>s.next(1o(a)})}function TM(e,n){return t=>i=>e[t](n,i)}class AB extends Ct{constructor(n,t){super()}schedule(n,t=0){return this}}const xf={setInterval(e,n,...t){const{delegate:i}=xf;return i?.setInterval?i.setInterval(e,n,...t):setInterval(e,n,...t)},clearInterval(e){const{delegate:n}=xf;return(n?.clearInterval||clearInterval)(e)},delegate:void 0},IM={now:()=>(IM.delegate||Date).now(),delegate:void 0};class Hc{constructor(n,t=Hc.now){this.schedulerActionCtor=n,this.now=t}schedule(n,t=0,i){return new this.schedulerActionCtor(this,n).schedule(i,t)}}Hc.now=IM.now;const Rf=new class OB extends Hc{constructor(n,t=Hc.now){super(n,t),this.actions=[],this._active=!1}flush(n){const{actions:t}=this;if(this._active)return void t.push(n);let i;this._active=!0;do{if(i=n.execute(n.state,n.delay))break}while(n=t.shift());if(this._active=!1,i){for(;n=t.shift();)n.unsubscribe();throw i}}}(class kB extends AB{constructor(n,t){super(n,t),this.scheduler=n,this.work=t,this.pending=!1}schedule(n,t=0){var i;if(this.closed)return this;this.state=n;const r=this.id,o=this.scheduler;return null!=r&&(this.id=this.recycleAsyncId(o,r,t)),this.pending=!0,this.delay=t,this.id=null!==(i=this.id)&&void 0!==i?i:this.requestAsyncId(o,this.id,t),this}requestAsyncId(n,t,i=0){return xf.setInterval(n.flush.bind(n,this),i)}recycleAsyncId(n,t,i=0){if(null!=i&&this.delay===i&&!1===this.pending)return t;null!=t&&xf.clearInterval(t)}execute(n,t){if(this.closed)return new Error("executing a cancelled action");this.pending=!1;const i=this._execute(n,t);if(i)return i;!1===this.pending&&null!=this.id&&(this.id=this.recycleAsyncId(this.scheduler,this.id,null))}_execute(n,t){let r,i=!1;try{this.work(n)}catch(o){i=!0,r=o||new Error("Scheduled action threw falsy error")}if(i)return this.unsubscribe(),r}unsubscribe(){if(!this.closed){const{id:n,scheduler:t}=this,{actions:i}=t;this.work=this.state=this.scheduler=null,this.pending=!1,dn(i,this),null!=n&&(this.id=this.recycleAsyncId(t,n,null)),this.delay=null,super.unsubscribe()}}}),xB=Rf;function jc(e=0,n,t=xB){let i=-1;return null!=n&&(si(n)?t=n:i=n),new je(r=>{let o=function RB(e){return e instanceof Date&&!isNaN(e)}(e)?+e-t.now():e;o<0&&(o=0);let s=0;return t.schedule(function(){r.closed||(r.next(s++),0<=i?this.schedule(void 0,i):r.complete())},o)})}const{isArray:PB}=Array;function AM(e){return 1===e.length&&PB(e[0])?e[0]:e}function Pf(...e){const n=rt(e),t=AM(e);return t.length?new je(i=>{let r=t.map(()=>[]),o=t.map(()=>!1);i.add(()=>{r=o=null});for(let s=0;!i.closed&&s{if(r[s].push(a),r.every(l=>l.length)){const l=r.map(u=>u.shift());i.next(n?n(...l):l),r.some((u,f)=>!u.length&&o[f])&&i.complete()}},()=>{o[s]=!0,!r[s].length&&i.complete()}));return()=>{r=o=null}}):Xt}function Vt(e){return qe((n,t)=>{ut(e).subscribe(Oe(t,()=>t.complete(),Dn)),!t.closed&&n.subscribe(t)})}function K_(...e){const n=rt(e);return qe((t,i)=>{const r=e.length,o=new Array(r);let s=e.map(()=>!1),a=!1;for(let l=0;l{o[l]=u,!a&&!s[l]&&(s[l]=!0,(a=s.every(Rn))&&(s=null))},Dn));t.subscribe(Oe(i,l=>{if(a){const u=[l,...o];i.next(n?n(...u):u)}}))})}function QH(e,n){if(1&e){const t=It();M(0,"button",1),W("click",function(){return mt(t),_t(z().close())}),T()}}new je(Dn),Math,Math,Math;const ZM=["*"],mj=["dialog"];function sv(e){return"string"==typeof e}function fs(e){return null!=e}function za(e){return(e||document.body).getBoundingClientRect()}const QM={animation:!0,transitionTimerDelayMs:5},u$=()=>{},{transitionTimerDelayMs:d$}=QM,Kc=new Map,bn=(e,n,t,i)=>{let r=i.context||{};const o=Kc.get(n);if(o)switch(i.runningTransition){case"continue":return Xt;case"stop":e.run(()=>o.transition$.complete()),r=Object.assign(o.context,r),Kc.delete(n)}const s=t(n,i.animation,r)||u$;if(!i.animation||"none"===window.getComputedStyle(n).transitionProperty)return e.run(()=>s()),J(void 0).pipe(function l$(e){return n=>new je(t=>n.subscribe({next:s=>e.run(()=>t.next(s)),error:s=>e.run(()=>t.error(s)),complete:()=>e.run(()=>t.complete())}))}(e));const a=new Ue,l=new Ue,u=a.pipe(function LB(...e){return n=>Dc(n,J(...e))}(!0));Kc.set(n,{transition$:a,complete:()=>{l.next(),l.complete()},context:r});const f=function c$(e){const{transitionDelay:n,transitionDuration:t}=window.getComputedStyle(e);return 1e3*(parseFloat(n)+parseFloat(t))}(n);return e.runOutsideAngular(()=>{const p=xn(n,"transitionend").pipe(Vt(u),vn(({target:v})=>v===n));(function kM(...e){return 1===(e=AM(e)).length?ut(e[0]):new je(function FB(e){return n=>{let t=[];for(let i=0;t&&!n.closed&&i{if(t){for(let o=0;o{Kc.delete(n),e.run(()=>{s(),a.next(),a.complete()})})}),a.asObservable()};let qc=(()=>{class e{constructor(){this.animation=QM.animation}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(),rN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[ei]}),e})();const _$=({classList:e})=>{e.remove("show")};let v$=(()=>{class e{constructor(t){this._ngbConfig=t,this.dismissible=!0,this.type="warning"}get animation(){return void 0===this._animation?this._ngbConfig.animation:this._animation}set animation(t){this._animation=t}}return e.\u0275fac=function(t){return new(t||e)(L(qc))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(),y$=(()=>{class e{constructor(t,i,r,o){this._renderer=i,this._element=r,this._zone=o,this.closed=new ue,this.dismissible=t.dismissible,this.type=t.type,this.animation=t.animation}close(){const t=bn(this._zone,this._element.nativeElement,_$,{animation:this.animation,runningTransition:"continue"});return t.subscribe(()=>this.closed.emit()),t}ngOnChanges(t){const i=t.type;i&&!i.firstChange&&(this._renderer.removeClass(this._element.nativeElement,`alert-${i.previousValue}`),this._renderer.addClass(this._element.nativeElement,`alert-${i.currentValue}`))}ngOnInit(){this._renderer.addClass(this._element.nativeElement,`alert-${this.type}`)}}return e.\u0275fac=function(t){return new(t||e)(C(v$),C(pi),C(Je),C(Ye))},e.\u0275cmp=et({type:e,selectors:[["ngb-alert"]],hostAttrs:["role","alert",1,"alert","show"],hostVars:4,hostBindings:function(t,i){2&t&&ht("fade",i.animation)("alert-dismissible",i.dismissible)},inputs:{animation:"animation",dismissible:"dismissible",type:"type"},outputs:{closed:"closed"},exportAs:["ngbAlert"],features:[zt],ngContentSelectors:ZM,decls:2,vars:1,consts:function(){let n;return n=$localize`:@@ngb.alert.close:Close`,[["type","button","class","btn-close","aria-label",n,3,"click",4,"ngIf"],["type","button","aria-label",n,1,"btn-close",3,"click"]]},template:function(t,i){1&t&&(Pg(),Fg(0),Z(1,QH,1,0,"button",0)),2&t&&(P(1),Q("ngIf",i.dismissible))},dependencies:[ns],styles:["ngb-alert{display:block}\n"],encapsulation:2,changeDetection:0}),e})(),oN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[ei]}),e})(),lN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[ei]}),e})(),cN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({}),e})();var Bt=(()=>{return(e=Bt||(Bt={}))[e.Tab=9]="Tab",e[e.Enter=13]="Enter",e[e.Escape=27]="Escape",e[e.Space=32]="Space",e[e.PageUp=33]="PageUp",e[e.PageDown=34]="PageDown",e[e.End=35]="End",e[e.Home=36]="Home",e[e.ArrowLeft=37]="ArrowLeft",e[e.ArrowUp=38]="ArrowUp",e[e.ArrowRight=39]="ArrowRight",e[e.ArrowDown=40]="ArrowDown",Bt;var e})();typeof navigator<"u"&&navigator.userAgent&&(/iPad|iPhone|iPod/.test(navigator.userAgent)||/Macintosh/.test(navigator.userAgent)&&navigator.maxTouchPoints&&navigator.maxTouchPoints>2||/Android/.test(navigator.userAgent));const dN=["a[href]","button:not([disabled])",'input:not([disabled]):not([type="hidden"])',"select:not([disabled])","textarea:not([disabled])","[contenteditable]",'[tabindex]:not([tabindex="-1"])'].join(", ");function fN(e){const n=Array.from(e.querySelectorAll(dN)).filter(t=>-1!==t.tabIndex);return[n[0],n[n.length-1]]}new Date(1882,10,12),new Date(2174,10,25);let bN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[ei,CM]}),e})(),hv=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275dir=B({type:e,selectors:[["",8,"navbar"]]}),e})(),wN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({}),e})();class ms{constructor(n,t,i){this.nodes=n,this.viewRef=t,this.componentRef=i}}let iU=(()=>{class e{constructor(t,i){this._el=t,this._zone=i}ngOnInit(){this._zone.onStable.asObservable().pipe(sn(1)).subscribe(()=>{bn(this._zone,this._el.nativeElement,(t,i)=>{i&&za(t),t.classList.add("show")},{animation:this.animation,runningTransition:"continue"})})}hide(){return bn(this._zone,this._el.nativeElement,({classList:t})=>t.remove("show"),{animation:this.animation,runningTransition:"stop"})}}return e.\u0275fac=function(t){return new(t||e)(C(Je),C(Ye))},e.\u0275cmp=et({type:e,selectors:[["ngb-modal-backdrop"]],hostAttrs:[2,"z-index","1055"],hostVars:6,hostBindings:function(t,i){2&t&&(Jo("modal-backdrop"+(i.backdropClass?" "+i.backdropClass:"")),ht("show",!i.animation)("fade",i.animation))},inputs:{animation:"animation",backdropClass:"backdropClass"},decls:0,vars:0,template:function(t,i){},encapsulation:2}),e})();class pr{close(n){}dismiss(n){}}class rU{constructor(n,t,i,r){this._windowCmptRef=n,this._contentRef=t,this._backdropCmptRef=i,this._beforeDismiss=r,this._closed=new Ue,this._dismissed=new Ue,this._hidden=new Ue,n.instance.dismissEvent.subscribe(o=>{this.dismiss(o)}),this.result=new Promise((o,s)=>{this._resolve=o,this._reject=s}),this.result.then(null,()=>{})}get componentInstance(){if(this._contentRef&&this._contentRef.componentRef)return this._contentRef.componentRef.instance}get closed(){return this._closed.asObservable().pipe(Vt(this._hidden))}get dismissed(){return this._dismissed.asObservable().pipe(Vt(this._hidden))}get hidden(){return this._hidden.asObservable()}get shown(){return this._windowCmptRef.instance.shown.asObservable()}close(n){this._windowCmptRef&&(this._closed.next(n),this._resolve(n),this._removeModalElements())}_dismiss(n){this._dismissed.next(n),this._reject(n),this._removeModalElements()}dismiss(n){if(this._windowCmptRef)if(this._beforeDismiss){const t=this._beforeDismiss();!function JM(e){return e&&e.then}(t)?!1!==t&&this._dismiss(n):t.then(i=>{!1!==i&&this._dismiss(n)},()=>{})}else this._dismiss(n)}_removeModalElements(){const n=this._windowCmptRef.instance.hide(),t=this._backdropCmptRef?this._backdropCmptRef.instance.hide():J(void 0);n.subscribe(()=>{const{nativeElement:i}=this._windowCmptRef.location;i.parentNode.removeChild(i),this._windowCmptRef.destroy(),this._contentRef&&this._contentRef.viewRef&&this._contentRef.viewRef.destroy(),this._windowCmptRef=null,this._contentRef=null}),t.subscribe(()=>{if(this._backdropCmptRef){const{nativeElement:i}=this._backdropCmptRef.location;i.parentNode.removeChild(i),this._backdropCmptRef.destroy(),this._backdropCmptRef=null}}),Pf(n,t).subscribe(()=>{this._hidden.next(),this._hidden.complete()})}}var Xc=(()=>{return(e=Xc||(Xc={}))[e.BACKDROP_CLICK=0]="BACKDROP_CLICK",e[e.ESC=1]="ESC",Xc;var e})();let oU=(()=>{class e{constructor(t,i,r){this._document=t,this._elRef=i,this._zone=r,this._closed$=new Ue,this._elWithFocus=null,this.backdrop=!0,this.keyboard=!0,this.dismissEvent=new ue,this.shown=new Ue,this.hidden=new Ue}get fullscreenClass(){return!0===this.fullscreen?" modal-fullscreen":sv(this.fullscreen)?` modal-fullscreen-${this.fullscreen}-down`:""}dismiss(t){this.dismissEvent.emit(t)}ngOnInit(){this._elWithFocus=this._document.activeElement,this._zone.onStable.asObservable().pipe(sn(1)).subscribe(()=>{this._show()})}ngOnDestroy(){this._disableEventHandling()}hide(){const{nativeElement:t}=this._elRef,i={animation:this.animation,runningTransition:"stop"},s=Pf(bn(this._zone,t,()=>t.classList.remove("show"),i),bn(this._zone,this._dialogEl.nativeElement,()=>{},i));return s.subscribe(()=>{this.hidden.next(),this.hidden.complete()}),this._disableEventHandling(),this._restoreFocus(),s}_show(){const t={animation:this.animation,runningTransition:"continue"};Pf(bn(this._zone,this._elRef.nativeElement,(o,s)=>{s&&za(o),o.classList.add("show")},t),bn(this._zone,this._dialogEl.nativeElement,()=>{},t)).subscribe(()=>{this.shown.next(),this.shown.complete()}),this._enableEventHandling(),this._setFocus()}_enableEventHandling(){const{nativeElement:t}=this._elRef;this._zone.runOutsideAngular(()=>{xn(t,"keydown").pipe(Vt(this._closed$),vn(r=>r.which===Bt.Escape)).subscribe(r=>{this.keyboard?requestAnimationFrame(()=>{r.defaultPrevented||this._zone.run(()=>this.dismiss(Xc.ESC))}):"static"===this.backdrop&&this._bumpBackdrop()});let i=!1;xn(this._dialogEl.nativeElement,"mousedown").pipe(Vt(this._closed$),Kt(()=>i=!1),vi(()=>xn(t,"mouseup").pipe(Vt(this._closed$),sn(1))),vn(({target:r})=>t===r)).subscribe(()=>{i=!0}),xn(t,"click").pipe(Vt(this._closed$)).subscribe(({target:r})=>{t===r&&("static"===this.backdrop?this._bumpBackdrop():!0===this.backdrop&&!i&&this._zone.run(()=>this.dismiss(Xc.BACKDROP_CLICK))),i=!1})})}_disableEventHandling(){this._closed$.next()}_setFocus(){const{nativeElement:t}=this._elRef;if(!t.contains(document.activeElement)){const i=t.querySelector("[ngbAutofocus]"),r=fN(t)[0];(i||r||t).focus()}}_restoreFocus(){const t=this._document.body,i=this._elWithFocus;let r;r=i&&i.focus&&t.contains(i)?i:t,this._zone.runOutsideAngular(()=>{setTimeout(()=>r.focus()),this._elWithFocus=null})}_bumpBackdrop(){"static"===this.backdrop&&bn(this._zone,this._elRef.nativeElement,({classList:t})=>(t.add("modal-static"),()=>t.remove("modal-static")),{animation:this.animation,runningTransition:"continue"})}}return e.\u0275fac=function(t){return new(t||e)(C(Dt),C(Je),C(Ye))},e.\u0275cmp=et({type:e,selectors:[["ngb-modal-window"]],viewQuery:function(t,i){if(1&t&&Nd(mj,7),2&t){let r;at(r=lt())&&(i._dialogEl=r.first)}},hostAttrs:["role","dialog","tabindex","-1"],hostVars:7,hostBindings:function(t,i){2&t&&(ze("aria-modal",!0)("aria-labelledby",i.ariaLabelledBy)("aria-describedby",i.ariaDescribedBy),Jo("modal d-block"+(i.windowClass?" "+i.windowClass:"")),ht("fade",i.animation))},inputs:{animation:"animation",ariaLabelledBy:"ariaLabelledBy",ariaDescribedBy:"ariaDescribedBy",backdrop:"backdrop",centered:"centered",fullscreen:"fullscreen",keyboard:"keyboard",scrollable:"scrollable",size:"size",windowClass:"windowClass",modalDialogClass:"modalDialogClass"},outputs:{dismissEvent:"dismiss"},ngContentSelectors:ZM,decls:4,vars:2,consts:[["role","document"],["dialog",""],[1,"modal-content"]],template:function(t,i){1&t&&(Pg(),M(0,"div",0,1)(2,"div",2),Fg(3),T()()),2&t&&Jo("modal-dialog"+(i.size?" modal-"+i.size:"")+(i.centered?" modal-dialog-centered":"")+i.fullscreenClass+(i.scrollable?" modal-dialog-scrollable":"")+(i.modalDialogClass?" "+i.modalDialogClass:""))},styles:["ngb-modal-window .component-host-scrollable{display:flex;flex-direction:column;overflow:hidden}\n"],encapsulation:2}),e})(),sU=(()=>{class e{constructor(t){this._document=t}hide(){const t=Math.abs(window.innerWidth-this._document.documentElement.clientWidth),i=this._document.body,r=i.style,{overflow:o,paddingRight:s}=r;if(t>0){const a=parseFloat(window.getComputedStyle(i).paddingRight);r.paddingRight=`${a+t}px`}return r.overflow="hidden",()=>{t>0&&(r.paddingRight=s),r.overflow=o}}}return e.\u0275fac=function(t){return new(t||e)(L(Dt))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(),aU=(()=>{class e{constructor(t,i,r,o,s,a){this._applicationRef=t,this._injector=i,this._document=r,this._scrollBar=o,this._rendererFactory=s,this._ngZone=a,this._activeWindowCmptHasChanged=new Ue,this._ariaHiddenValues=new Map,this._scrollBarRestoreFn=null,this._backdropAttributes=["animation","backdropClass"],this._modalRefs=[],this._windowAttributes=["animation","ariaLabelledBy","ariaDescribedBy","backdrop","centered","fullscreen","keyboard","scrollable","size","windowClass","modalDialogClass"],this._windowCmpts=[],this._activeInstances=new ue,this._activeWindowCmptHasChanged.subscribe(()=>{if(this._windowCmpts.length){const l=this._windowCmpts[this._windowCmpts.length-1];((e,n,t,i=!1)=>{this._ngZone.runOutsideAngular(()=>{const r=xn(n,"focusin").pipe(Vt(t),ne(o=>o.target));xn(n,"keydown").pipe(Vt(t),vn(o=>o.which===Bt.Tab),K_(r)).subscribe(([o,s])=>{const[a,l]=fN(n);(s===a||s===n)&&o.shiftKey&&(l.focus(),o.preventDefault()),s===l&&!o.shiftKey&&(a.focus(),o.preventDefault())}),i&&xn(n,"click").pipe(Vt(t),K_(r),ne(o=>o[1])).subscribe(o=>o.focus())})})(0,l.location.nativeElement,this._activeWindowCmptHasChanged),this._revertAriaHidden(),this._setAriaHidden(l.location.nativeElement)}})}_restoreScrollBar(){const t=this._scrollBarRestoreFn;t&&(this._scrollBarRestoreFn=null,t())}_hideScrollBar(){this._scrollBarRestoreFn||(this._scrollBarRestoreFn=this._scrollBar.hide())}open(t,i,r){const o=r.container instanceof HTMLElement?r.container:fs(r.container)?this._document.querySelector(r.container):this._document.body,s=this._rendererFactory.createRenderer(null,null);if(!o)throw new Error(`The specified modal container "${r.container||"body"}" was not found in the DOM.`);this._hideScrollBar();const a=new pr,l=this._getContentRef(r.injector||t,i,a,r);let u=!1!==r.backdrop?this._attachBackdrop(o):void 0,f=this._attachWindowComponent(o,l.nodes),p=new rU(f,l,u,r.beforeDismiss);return this._registerModalRef(p),this._registerWindowCmpt(f),p.hidden.pipe(sn(1)).subscribe(()=>Promise.resolve(!0).then(()=>{this._modalRefs.length||(s.removeClass(this._document.body,"modal-open"),this._restoreScrollBar(),this._revertAriaHidden())})),a.close=m=>{p.close(m)},a.dismiss=m=>{p.dismiss(m)},this._applyWindowOptions(f.instance,r),1===this._modalRefs.length&&s.addClass(this._document.body,"modal-open"),u&&u.instance&&(this._applyBackdropOptions(u.instance,r),u.changeDetectorRef.detectChanges()),f.changeDetectorRef.detectChanges(),p}get activeInstances(){return this._activeInstances}dismissAll(t){this._modalRefs.forEach(i=>i.dismiss(t))}hasOpenModals(){return this._modalRefs.length>0}_attachBackdrop(t){let i=Dm(iU,{environmentInjector:this._applicationRef.injector,elementInjector:this._injector});return this._applicationRef.attachView(i.hostView),t.appendChild(i.location.nativeElement),i}_attachWindowComponent(t,i){let r=Dm(oU,{environmentInjector:this._applicationRef.injector,elementInjector:this._injector,projectableNodes:i});return this._applicationRef.attachView(r.hostView),t.appendChild(r.location.nativeElement),r}_applyWindowOptions(t,i){this._windowAttributes.forEach(r=>{fs(i[r])&&(t[r]=i[r])})}_applyBackdropOptions(t,i){this._backdropAttributes.forEach(r=>{fs(i[r])&&(t[r]=i[r])})}_getContentRef(t,i,r,o){return i?i instanceof bt?this._createFromTemplateRef(i,r):sv(i)?this._createFromString(i):this._createFromComponent(t,i,r,o):new ms([])}_createFromTemplateRef(t,i){const o=t.createEmbeddedView({$implicit:i,close(s){i.close(s)},dismiss(s){i.dismiss(s)}});return this._applicationRef.attachView(o),new ms([o.rootNodes],o)}_createFromString(t){const i=this._document.createTextNode(`${t}`);return new ms([[i]])}_createFromComponent(t,i,r,o){const s=gn.create({providers:[{provide:pr,useValue:r}],parent:t}),a=Dm(i,{environmentInjector:this._applicationRef.injector,elementInjector:s}),l=a.location.nativeElement;return o.scrollable&&l.classList.add("component-host-scrollable"),this._applicationRef.attachView(a.hostView),new ms([[l]],a.hostView,a)}_setAriaHidden(t){const i=t.parentElement;i&&t!==this._document.body&&(Array.from(i.children).forEach(r=>{r!==t&&"SCRIPT"!==r.nodeName&&(this._ariaHiddenValues.set(r,r.getAttribute("aria-hidden")),r.setAttribute("aria-hidden","true"))}),this._setAriaHidden(i))}_revertAriaHidden(){this._ariaHiddenValues.forEach((t,i)=>{t?i.setAttribute("aria-hidden",t):i.removeAttribute("aria-hidden")}),this._ariaHiddenValues.clear()}_registerModalRef(t){const i=()=>{const r=this._modalRefs.indexOf(t);r>-1&&(this._modalRefs.splice(r,1),this._activeInstances.emit(this._modalRefs))};this._modalRefs.push(t),this._activeInstances.emit(this._modalRefs),t.result.then(i,i)}_registerWindowCmpt(t){this._windowCmpts.push(t),this._activeWindowCmptHasChanged.next(),t.onDestroy(()=>{const i=this._windowCmpts.indexOf(t);i>-1&&(this._windowCmpts.splice(i,1),this._activeWindowCmptHasChanged.next())})}}return e.\u0275fac=function(t){return new(t||e)(L(fc),L(gn),L(Dt),L(sU),L(Rp),L(Ye))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(),lU=(()=>{class e{constructor(t){this._ngbConfig=t,this.backdrop=!0,this.fullscreen=!1,this.keyboard=!0}get animation(){return void 0===this._animation?this._ngbConfig.animation:this._animation}set animation(t){this._animation=t}}return e.\u0275fac=function(t){return new(t||e)(L(qc))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(),SN=(()=>{class e{constructor(t,i,r){this._injector=t,this._modalStack=i,this._config=r}open(t,i={}){const r={...this._config,animation:this._config.animation,...i};return this._modalStack.open(this._injector,t,r)}get activeInstances(){return this._modalStack.activeInstances}dismissAll(t){this._modalStack.dismissAll(t)}hasOpenModals(){return this._modalStack.hasOpenModals()}}return e.\u0275fac=function(t){return new(t||e)(L(gn),L(aU),L(lU))},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(),MN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({providers:[SN]}),e})(),IN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[ei]}),e})(),LN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[ei]}),e})(),BN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[ei]}),e})(),HN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[ei]}),e})(),jN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[ei]}),e})(),$N=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[ei]}),e})(),UN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[ei]}),e})(),GN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({}),e})();new q("live announcer delay",{providedIn:"root",factory:function DU(){return 100}});let WN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[ei]}),e})(),zN=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({}),e})();const CU=[rN,oN,lN,cN,bN,wN,MN,IN,zN,LN,BN,HN,jN,$N,UN,GN,WN];let wU=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({imports:[CU,rN,oN,lN,cN,bN,wN,MN,IN,zN,LN,BN,HN,jN,$N,UN,GN,WN]}),e})(),NU=(()=>{class e{constructor(t){this.activeModal=t,this.save=()=>{this.activeModal.close(this.rewindDate)}}}return e.\u0275fac=function(t){return new(t||e)(C(pr))},e.\u0275cmp=et({type:e,selectors:[["app-rewind-modal"]],inputs:{groupId:"groupId",consumerName:"consumerName",topic:"topic"},decls:26,vars:4,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],["for","rewindDate"],[1,"input-group"],["id","rewindDate","placeholder","yyyy-mm-dd hh:MM:ss","type","datetime-local",1,"form-control",3,"ngModel","ngModelChange"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(M(0,"div",0)(1,"h4",1),I(2,"Rewind consumers offset"),T(),M(3,"button",2),W("click",function(){return i.activeModal.dismiss()}),M(4,"span",3),I(5,"\xd7"),T()()(),M(6,"div",4)(7,"div",5)(8,"label",6),I(9,"Select the datetime to rewind all the partition-offsets of the topic "),M(10,"b"),I(11),T(),I(12," from consumers "),M(13,"b"),I(14),T(),I(15," with group id "),M(16,"b"),I(17),T(),I(18,"' "),T(),M(19,"div",7)(20,"input",8),W("ngModelChange",function(o){return i.rewindDate=o}),T()()()(),M(21,"div",9)(22,"button",10),W("click",function(){return i.activeModal.dismiss()}),I(23,"Cancel"),T(),M(24,"button",11),W("click",function(){return i.save()}),I(25,"OK"),T()()),2&t&&(P(11),He("'",i.topic,"'"),P(3),He("'",i.consumerName,"'"),P(3),He("'",i.groupId,""),P(3),Q("ngModel",i.rewindDate))},dependencies:[Pc,I_,Of],encapsulation:2}),e})(),EU=(()=>{class e{constructor(t){this.activeModal=t,this.save=()=>{this.activeModal.close(this.workersCount)}}ngOnInit(){this.oldWorkersCount=this.workersCount}}return e.\u0275fac=function(t){return new(t||e)(C(pr))},e.\u0275cmp=et({type:e,selectors:[["app-workers-count-modal"]],inputs:{workersCount:"workersCount",groupId:"groupId",consumerName:"consumerName"},decls:28,vars:4,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],["for","oldWorkersCount"],[1,"input-group","mb-2"],["id","oldWorkersCount","type","number","readonly","",1,"form-control",3,"ngModel","ngModelChange"],["for","workersCount"],[1,"input-group"],["id","workersCount","type","number",1,"form-control",3,"ngModel","ngModelChange"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(M(0,"div",0)(1,"h4",1),I(2,"Consumer workers running"),T(),M(3,"button",2),W("click",function(){return i.activeModal.dismiss()}),M(4,"span",3),I(5,"\xd7"),T()()(),M(6,"div",4)(7,"div",5)(8,"label"),I(9,"Update the number of workers in consumers "),M(10,"b"),I(11),T(),I(12," from group id "),M(13,"b"),I(14),T()(),M(15,"label",6),I(16,"Current Value"),T(),M(17,"div",7)(18,"input",8),W("ngModelChange",function(o){return i.oldWorkersCount=o}),T()(),M(19,"label",9),I(20,"New Value"),T(),M(21,"div",10)(22,"input",11),W("ngModelChange",function(o){return i.workersCount=o}),T()()()(),M(23,"div",12)(24,"button",13),W("click",function(){return i.activeModal.dismiss()}),I(25,"Cancel"),T(),M(26,"button",14),W("click",function(){return i.save()}),I(27,"OK"),T()()),2&t&&(P(11),He("'",i.consumerName,"'"),P(3),He("'",i.groupId,"'"),P(4),Q("ngModel",i.oldWorkersCount),P(4),Q("ngModel",i.workersCount))},dependencies:[Pc,H_,I_,Of],encapsulation:2}),e})(),TU=(()=>{class e{constructor(t){this.activeModal=t}}return e.\u0275fac=function(t){return new(t||e)(C(pr))},e.\u0275cmp=et({type:e,selectors:[["app-reset-modal"]],inputs:{groupId:"groupId",consumerName:"consumerName",topic:"topic"},decls:26,vars:3,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],[1,"mt-3"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(M(0,"div",0)(1,"h4",1),I(2,"Reset consumers offset"),T(),M(3,"button",2),W("click",function(){return i.activeModal.dismiss()}),M(4,"span",3),I(5,"\xd7"),T()()(),M(6,"div",4)(7,"div",5)(8,"span"),I(9,"Reset the partition-offsets can generate a huge lag at the topic "),M(10,"b"),I(11),T(),I(12," to consumers "),M(13,"b"),I(14),T(),I(15," with group id "),M(16,"b"),I(17),T(),I(18,"'. "),T(),M(19,"h5",6),I(20,"Are you really sure about it?"),T()()(),M(21,"div",7)(22,"button",8),W("click",function(){return i.activeModal.dismiss()}),I(23,"No, cancel"),T(),M(24,"button",9),W("click",function(){return i.activeModal.close()}),I(25,"Yes"),T()()),2&t&&(P(11),He("'",i.topic,"'"),P(3),He("'",i.consumerName,"'"),P(3),He("'",i.groupId,""))},encapsulation:2}),e})(),IU=(()=>{class e{constructor(t){this.activeModal=t}}return e.\u0275fac=function(t){return new(t||e)(C(pr))},e.\u0275cmp=et({type:e,selectors:[["app-pause-modal"]],inputs:{groupId:"groupId",consumerName:"consumerName",topic:"topic"},decls:26,vars:3,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],[1,"mt-3"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(M(0,"div",0)(1,"h4",1),I(2,"Pause consumers"),T(),M(3,"button",2),W("click",function(){return i.activeModal.dismiss()}),M(4,"span",3),I(5,"\xd7"),T()()(),M(6,"div",4)(7,"div",5)(8,"span"),I(9,"Pause all the partitions of the topic "),M(10,"b"),I(11),T(),I(12," from consumers "),M(13,"b"),I(14),T(),I(15," with group id "),M(16,"b"),I(17),T(),I(18,"' will interrupt the kafka data processing and, probably, generate lag. "),T(),M(19,"h5",6),I(20,"Are you really sure about it?"),T()()(),M(21,"div",7)(22,"button",8),W("click",function(){return i.activeModal.dismiss()}),I(23,"No, cancel"),T(),M(24,"button",9),W("click",function(){return i.activeModal.close()}),I(25,"Yes"),T()()),2&t&&(P(11),He("'",i.topic,"'"),P(3),He("'",i.consumerName,"'"),P(3),He("'",i.groupId,""))},encapsulation:2}),e})(),AU=(()=>{class e{constructor(t){this.activeModal=t}}return e.\u0275fac=function(t){return new(t||e)(C(pr))},e.\u0275cmp=et({type:e,selectors:[["app-resume-modal"]],inputs:{groupId:"groupId",consumerName:"consumerName",topic:"topic"},decls:26,vars:3,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],[1,"mt-3"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(M(0,"div",0)(1,"h4",1),I(2,"Resume consumers"),T(),M(3,"button",2),W("click",function(){return i.activeModal.dismiss()}),M(4,"span",3),I(5,"\xd7"),T()()(),M(6,"div",4)(7,"div",5)(8,"span"),I(9,"Resume all the partitions of the topic "),M(10,"b"),I(11),T(),I(12," from consumers "),M(13,"b"),I(14),T(),I(15," with group id "),M(16,"b"),I(17),T(),I(18,"' will restart to process the messages. "),T(),M(19,"h5",6),I(20,"Are you really sure about it?"),T()()(),M(21,"div",7)(22,"button",8),W("click",function(){return i.activeModal.dismiss()}),I(23,"No, cancel"),T(),M(24,"button",9),W("click",function(){return i.activeModal.close()}),I(25,"Yes"),T()()),2&t&&(P(11),He("'",i.topic,"'"),P(3),He("'",i.consumerName,"'"),P(3),He("'",i.groupId,""))},encapsulation:2}),e})(),kU=(()=>{class e{constructor(t){this.activeModal=t}}return e.\u0275fac=function(t){return new(t||e)(C(pr))},e.\u0275cmp=et({type:e,selectors:[["app-restart-modal"]],inputs:{groupId:"groupId",consumerName:"consumerName"},decls:23,vars:2,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],[1,"mt-3"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(M(0,"div",0)(1,"h4",1),I(2,"Restart consumers"),T(),M(3,"button",2),W("click",function(){return i.activeModal.dismiss()}),M(4,"span",3),I(5,"\xd7"),T()()(),M(6,"div",4)(7,"div",5)(8,"span"),I(9,"Restart the consumers "),M(10,"b"),I(11),T(),I(12," from group id "),M(13,"b"),I(14),T(),I(15,"' will can generate a temporary instability in your system. "),T(),M(16,"h5",6),I(17,"Are you really sure about it?"),T()()(),M(18,"div",7)(19,"button",8),W("click",function(){return i.activeModal.dismiss()}),I(20,"No, cancel"),T(),M(21,"button",9),W("click",function(){return i.activeModal.close()}),I(22,"Yes"),T()()),2&t&&(P(11),He("'",i.consumerName,"'"),P(3),He("'",i.groupId,""))},encapsulation:2}),e})(),OU=(()=>{class e{constructor(t){this.activeModal=t}}return e.\u0275fac=function(t){return new(t||e)(C(pr))},e.\u0275cmp=et({type:e,selectors:[["app-start-modal"]],inputs:{groupId:"groupId",consumerName:"consumerName"},decls:22,vars:2,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],[1,"mt-3"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(M(0,"div",0)(1,"h4",1),I(2,"Start consumers"),T(),M(3,"button",2),W("click",function(){return i.activeModal.dismiss()}),M(4,"span",3),I(5,"\xd7"),T()()(),M(6,"div",4)(7,"div",5)(8,"span"),I(9,"Start the consumer "),M(10,"b"),I(11),T(),I(12," from group id "),M(13,"b"),I(14),T()(),M(15,"h5",6),I(16,"Are you really sure about it?"),T()()(),M(17,"div",7)(18,"button",8),W("click",function(){return i.activeModal.dismiss()}),I(19,"No, cancel"),T(),M(20,"button",9),W("click",function(){return i.activeModal.close()}),I(21,"Yes"),T()()),2&t&&(P(11),He("'",i.consumerName,"'"),P(3),He("'",i.groupId,"'"))},encapsulation:2}),e})(),xU=(()=>{class e{constructor(t){this.activeModal=t}}return e.\u0275fac=function(t){return new(t||e)(C(pr))},e.\u0275cmp=et({type:e,selectors:[["app-stop-modal"]],inputs:{groupId:"groupId",consumerName:"consumerName"},decls:22,vars:2,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],[1,"mt-3"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(M(0,"div",0)(1,"h4",1),I(2,"Stop consumer"),T(),M(3,"button",2),W("click",function(){return i.activeModal.dismiss()}),M(4,"span",3),I(5,"\xd7"),T()()(),M(6,"div",4)(7,"div",5)(8,"span"),I(9,"Stop the consumer "),M(10,"b"),I(11),T(),I(12," from group id "),M(13,"b"),I(14),T()(),M(15,"h5",6),I(16,"Are you really sure about it?"),T()()(),M(17,"div",7)(18,"button",8),W("click",function(){return i.activeModal.dismiss()}),I(19,"No, cancel"),T(),M(20,"button",9),W("click",function(){return i.activeModal.close()}),I(21,"Yes"),T()()),2&t&&(P(11),He("'",i.consumerName,"'"),P(3),He("'",i.groupId,"'"))},encapsulation:2}),e})();var YN=iu(439);function KN(e,n,t,i,r,o,s){try{var a=e[o](s),l=a.value}catch(u){return void t(u)}a.done?n(l):Promise.resolve(l).then(i,r)}function Yr(e){return function(){var n=this,t=arguments;return new Promise(function(i,r){var o=e.apply(n,t);function s(l){KN(o,i,r,s,a,"next",l)}function a(l){KN(o,i,r,s,a,"throw",l)}s(void 0)})}}function Kr(e,n){const t="object"==typeof n;return new Promise((i,r)=>{const o=new vr({next:s=>{i(s),o.unsubscribe()},error:r,complete:()=>{t?i(n.defaultValue):r(new bc)}});e.subscribe(o)})}let ZN=(()=>{class e{constructor(){this.rootUrl="/kafkaflow"}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(); -/** - * @license Angular v14.2.9 - * (c) 2010-2022 Google LLC. https://angular.io/ - * License: MIT - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */class JN{}class QN{} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */class qr{constructor(n){this.normalizedNames=new Map,this.lazyUpdate=null,n?this.lazyInit="string"==typeof n?()=>{this.headers=new Map,n.split("\n").forEach(t=>{const i=t.indexOf(":");if(i>0){const r=t.slice(0,i),o=r.toLowerCase(),s=t.slice(i+1).trim();this.maybeSetNormalizedName(r,o),this.headers.has(o)?this.headers.get(o).push(s):this.headers.set(o,[s])}})}:()=>{this.headers=new Map,Object.keys(n).forEach(t=>{let i=n[t];const r=t.toLowerCase();"string"==typeof i&&(i=[i]),i.length>0&&(this.headers.set(r,i),this.maybeSetNormalizedName(t,r))})}:this.headers=new Map}has(n){return this.init(),this.headers.has(n.toLowerCase())}get(n){this.init();const t=this.headers.get(n.toLowerCase());return t&&t.length>0?t[0]:null}keys(){return this.init(),Array.from(this.normalizedNames.values())}getAll(n){return this.init(),this.headers.get(n.toLowerCase())||null}append(n,t){return this.clone({name:n,value:t,op:"a"})}set(n,t){return this.clone({name:n,value:t,op:"s"})}delete(n,t){return this.clone({name:n,value:t,op:"d"})}maybeSetNormalizedName(n,t){this.normalizedNames.has(t)||this.normalizedNames.set(t,n)}init(){this.lazyInit&&(this.lazyInit instanceof qr?this.copyFrom(this.lazyInit):this.lazyInit(),this.lazyInit=null,this.lazyUpdate&&(this.lazyUpdate.forEach(n=>this.applyUpdate(n)),this.lazyUpdate=null))}copyFrom(n){n.init(),Array.from(n.headers.keys()).forEach(t=>{this.headers.set(t,n.headers.get(t)),this.normalizedNames.set(t,n.normalizedNames.get(t))})}clone(n){const t=new qr;return t.lazyInit=this.lazyInit&&this.lazyInit instanceof qr?this.lazyInit:this,t.lazyUpdate=(this.lazyUpdate||[]).concat([n]),t}applyUpdate(n){const t=n.name.toLowerCase();switch(n.op){case"a":case"s":let i=n.value;if("string"==typeof i&&(i=[i]),0===i.length)return;this.maybeSetNormalizedName(n.name,t);const r=("a"===n.op?this.headers.get(t):void 0)||[];r.push(...i),this.headers.set(t,r);break;case"d":const o=n.value;if(o){let s=this.headers.get(t);if(!s)return;s=s.filter(a=>-1===o.indexOf(a)),0===s.length?(this.headers.delete(t),this.normalizedNames.delete(t)):this.headers.set(t,s)}else this.headers.delete(t),this.normalizedNames.delete(t)}}forEach(n){this.init(),Array.from(this.normalizedNames.keys()).forEach(t=>n(this.normalizedNames.get(t),this.headers.get(t)))}} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -class RU{encodeKey(n){return XN(n)}encodeValue(n){return XN(n)}decodeKey(n){return decodeURIComponent(n)}decodeValue(n){return decodeURIComponent(n)}}const FU=/%(\d[a-f0-9])/gi,LU={40:"@","3A":":",24:"$","2C":",","3B":";","3D":"=","3F":"?","2F":"/"};function XN(e){return encodeURIComponent(e).replace(FU,(n,t)=>LU[t]??n)}function Kf(e){return`${e}`}class So{constructor(n={}){if(this.updates=null,this.cloneFrom=null,this.encoder=n.encoder||new RU,n.fromString){if(n.fromObject)throw new Error("Cannot specify both fromString and fromObject.");this.map=function PU(e,n){const t=new Map;return e.length>0&&e.replace(/^\?/,"").split("&").forEach(r=>{const o=r.indexOf("="),[s,a]=-1==o?[n.decodeKey(r),""]:[n.decodeKey(r.slice(0,o)),n.decodeValue(r.slice(o+1))],l=t.get(s)||[];l.push(a),t.set(s,l)}),t}(n.fromString,this.encoder)}else n.fromObject?(this.map=new Map,Object.keys(n.fromObject).forEach(t=>{const i=n.fromObject[t],r=Array.isArray(i)?i.map(Kf):[Kf(i)];this.map.set(t,r)})):this.map=null}has(n){return this.init(),this.map.has(n)}get(n){this.init();const t=this.map.get(n);return t?t[0]:null}getAll(n){return this.init(),this.map.get(n)||null}keys(){return this.init(),Array.from(this.map.keys())}append(n,t){return this.clone({param:n,value:t,op:"a"})}appendAll(n){const t=[];return Object.keys(n).forEach(i=>{const r=n[i];Array.isArray(r)?r.forEach(o=>{t.push({param:i,value:o,op:"a"})}):t.push({param:i,value:r,op:"a"})}),this.clone(t)}set(n,t){return this.clone({param:n,value:t,op:"s"})}delete(n,t){return this.clone({param:n,value:t,op:"d"})}toString(){return this.init(),this.keys().map(n=>{const t=this.encoder.encodeKey(n);return this.map.get(n).map(i=>t+"="+this.encoder.encodeValue(i)).join("&")}).filter(n=>""!==n).join("&")}clone(n){const t=new So({encoder:this.encoder});return t.cloneFrom=this.cloneFrom||this,t.updates=(this.updates||[]).concat(n),t}init(){null===this.map&&(this.map=new Map),null!==this.cloneFrom&&(this.cloneFrom.init(),this.cloneFrom.keys().forEach(n=>this.map.set(n,this.cloneFrom.map.get(n))),this.updates.forEach(n=>{switch(n.op){case"a":case"s":const t=("a"===n.op?this.map.get(n.param):void 0)||[];t.push(Kf(n.value)),this.map.set(n.param,t);break;case"d":if(void 0===n.value){this.map.delete(n.param);break}{let i=this.map.get(n.param)||[];const r=i.indexOf(Kf(n.value));-1!==r&&i.splice(r,1),i.length>0?this.map.set(n.param,i):this.map.delete(n.param)}}}),this.cloneFrom=this.updates=null)}} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */class VU{constructor(){this.map=new Map}set(n,t){return this.map.set(n,t),this}get(n){return this.map.has(n)||this.map.set(n,n.defaultValue()),this.map.get(n)}delete(n){return this.map.delete(n),this}has(n){return this.map.has(n)}keys(){return this.map.keys()}} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */function eE(e){return typeof ArrayBuffer<"u"&&e instanceof ArrayBuffer}function tE(e){return typeof Blob<"u"&&e instanceof Blob}function nE(e){return typeof FormData<"u"&&e instanceof FormData}class eu{constructor(n,t,i,r){let o;if(this.url=t,this.body=null,this.reportProgress=!1,this.withCredentials=!1,this.responseType="json",this.method=n.toUpperCase(),function BU(e){switch(e){case"DELETE":case"GET":case"HEAD":case"OPTIONS":case"JSONP":return!1;default:return!0}}(this.method)||r?(this.body=void 0!==i?i:null,o=r):o=i,o&&(this.reportProgress=!!o.reportProgress,this.withCredentials=!!o.withCredentials,o.responseType&&(this.responseType=o.responseType),o.headers&&(this.headers=o.headers),o.context&&(this.context=o.context),o.params&&(this.params=o.params)),this.headers||(this.headers=new qr),this.context||(this.context=new VU),this.params){const s=this.params.toString();if(0===s.length)this.urlWithParams=t;else{const a=t.indexOf("?");this.urlWithParams=t+(-1===a?"?":ap.set(m,n.setHeaders[m]),l)),n.setParams&&(u=Object.keys(n.setParams).reduce((p,m)=>p.set(m,n.setParams[m]),u)),new eu(t,i,o,{params:u,headers:l,context:f,reportProgress:a,responseType:r,withCredentials:s})}} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */var Ot=(()=>((Ot=Ot||{})[Ot.Sent=0]="Sent",Ot[Ot.UploadProgress=1]="UploadProgress",Ot[Ot.ResponseHeader=2]="ResponseHeader",Ot[Ot.DownloadProgress=3]="DownloadProgress",Ot[Ot.Response=4]="Response",Ot[Ot.User=5]="User",Ot))();class _v{constructor(n,t=200,i="OK"){this.headers=n.headers||new qr,this.status=void 0!==n.status?n.status:t,this.statusText=n.statusText||i,this.url=n.url||null,this.ok=this.status>=200&&this.status<300}}class vv extends _v{constructor(n={}){super(n),this.type=Ot.ResponseHeader}clone(n={}){return new vv({headers:n.headers||this.headers,status:void 0!==n.status?n.status:this.status,statusText:n.statusText||this.statusText,url:n.url||this.url||void 0})}}class qf extends _v{constructor(n={}){super(n),this.type=Ot.Response,this.body=void 0!==n.body?n.body:null}clone(n={}){return new qf({body:void 0!==n.body?n.body:this.body,headers:n.headers||this.headers,status:void 0!==n.status?n.status:this.status,statusText:n.statusText||this.statusText,url:n.url||this.url||void 0})}}class iE extends _v{constructor(n){super(n,0,"Unknown Error"),this.name="HttpErrorResponse",this.ok=!1,this.message=this.status>=200&&this.status<300?`Http failure during parsing for ${n.url||"(unknown url)"}`:`Http failure response for ${n.url||"(unknown url)"}: ${n.status} ${n.statusText}`,this.error=n.error||null}} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */function yv(e,n){return{body:n,headers:e.headers,context:e.context,observe:e.observe,params:e.params,reportProgress:e.reportProgress,responseType:e.responseType,withCredentials:e.withCredentials}}let rE=(()=>{class e{constructor(t){this.handler=t}request(t,i,r={}){let o;if(t instanceof eu)o=t;else{let l,u;l=r.headers instanceof qr?r.headers:new qr(r.headers),r.params&&(u=r.params instanceof So?r.params:new So({fromObject:r.params})),o=new eu(t,i,void 0!==r.body?r.body:null,{headers:l,context:r.context,params:u,reportProgress:r.reportProgress,responseType:r.responseType||"json",withCredentials:r.withCredentials})}const s=J(o).pipe(_o(l=>this.handler.handle(l)));if(t instanceof eu||"events"===r.observe)return s;const a=s.pipe(vn(l=>l instanceof qf));switch(r.observe||"body"){case"body":switch(o.responseType){case"arraybuffer":return a.pipe(ne(l=>{if(null!==l.body&&!(l.body instanceof ArrayBuffer))throw new Error("Response is not an ArrayBuffer.");return l.body}));case"blob":return a.pipe(ne(l=>{if(null!==l.body&&!(l.body instanceof Blob))throw new Error("Response is not a Blob.");return l.body}));case"text":return a.pipe(ne(l=>{if(null!==l.body&&"string"!=typeof l.body)throw new Error("Response is not a string.");return l.body}));default:return a.pipe(ne(l=>l.body))}case"response":return a;default:throw new Error(`Unreachable: unhandled observe type ${r.observe}}`)}}delete(t,i={}){return this.request("DELETE",t,i)}get(t,i={}){return this.request("GET",t,i)}head(t,i={}){return this.request("HEAD",t,i)}jsonp(t,i){return this.request("JSONP",t,{params:(new So).append(i,"JSONP_CALLBACK"),observe:"body",responseType:"json"})}options(t,i={}){return this.request("OPTIONS",t,i)}patch(t,i,r={}){return this.request("PATCH",t,yv(r,i))}post(t,i,r={}){return this.request("POST",t,yv(r,i))}put(t,i,r={}){return this.request("PUT",t,yv(r,i))}}return e.\u0275fac=function(t){return new(t||e)(L(JN))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */class oE{constructor(n,t){this.next=n,this.interceptor=t}handle(n){return this.interceptor.intercept(n,this.next)}}const bv=new q("HTTP_INTERCEPTORS");let jU=(()=>{class e{intercept(t,i){return i.handle(t)}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -const $U=/^\)\]\}',?\n/;let sE=(()=>{class e{constructor(t){this.xhrFactory=t}handle(t){if("JSONP"===t.method)throw new Error("Attempted to construct Jsonp request without HttpClientJsonpModule installed.");return new je(i=>{const r=this.xhrFactory.build();if(r.open(t.method,t.urlWithParams),t.withCredentials&&(r.withCredentials=!0),t.headers.forEach((v,y)=>r.setRequestHeader(v,y.join(","))),t.headers.has("Accept")||r.setRequestHeader("Accept","application/json, text/plain, */*"),!t.headers.has("Content-Type")){const v=t.detectContentTypeHeader();null!==v&&r.setRequestHeader("Content-Type",v)}if(t.responseType){const v=t.responseType.toLowerCase();r.responseType="json"!==v?v:"text"}const o=t.serializeBody();let s=null;const a=()=>{if(null!==s)return s;const v=r.statusText||"OK",y=new qr(r.getAllResponseHeaders()),D=function UU(e){return"responseURL"in e&&e.responseURL?e.responseURL:/^X-Request-URL:/m.test(e.getAllResponseHeaders())?e.getResponseHeader("X-Request-URL"):null}(r)||t.url;return s=new vv({headers:y,status:r.status,statusText:v,url:D}),s},l=()=>{let{headers:v,status:y,statusText:D,url:w}=a(),N=null;204!==y&&(N=typeof r.response>"u"?r.responseText:r.response),0===y&&(y=N?200:0);let A=y>=200&&y<300;if("json"===t.responseType&&"string"==typeof N){const S=N;N=N.replace($U,"");try{N=""!==N?JSON.parse(N):null}catch(k){N=S,A&&(A=!1,N={error:k,text:N})}}A?(i.next(new qf({body:N,headers:v,status:y,statusText:D,url:w||void 0})),i.complete()):i.error(new iE({error:N,headers:v,status:y,statusText:D,url:w||void 0}))},u=v=>{const{url:y}=a(),D=new iE({error:v,status:r.status||0,statusText:r.statusText||"Unknown Error",url:y||void 0});i.error(D)};let f=!1;const p=v=>{f||(i.next(a()),f=!0);let y={type:Ot.DownloadProgress,loaded:v.loaded};v.lengthComputable&&(y.total=v.total),"text"===t.responseType&&!!r.responseText&&(y.partialText=r.responseText),i.next(y)},m=v=>{let y={type:Ot.UploadProgress,loaded:v.loaded};v.lengthComputable&&(y.total=v.total),i.next(y)};return r.addEventListener("load",l),r.addEventListener("error",u),r.addEventListener("timeout",u),r.addEventListener("abort",u),t.reportProgress&&(r.addEventListener("progress",p),null!==o&&r.upload&&r.upload.addEventListener("progress",m)),r.send(o),i.next({type:Ot.Sent}),()=>{r.removeEventListener("error",u),r.removeEventListener("abort",u),r.removeEventListener("load",l),r.removeEventListener("timeout",u),t.reportProgress&&(r.removeEventListener("progress",p),null!==o&&r.upload&&r.upload.removeEventListener("progress",m)),r.readyState!==r.DONE&&r.abort()}})}}return e.\u0275fac=function(t){return new(t||e)(L(PC))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */const Dv=new q("XSRF_COOKIE_NAME"),Cv=new q("XSRF_HEADER_NAME");class aE{}let GU=(()=>{class e{constructor(t,i,r){this.doc=t,this.platform=i,this.cookieName=r,this.lastCookieString="",this.lastToken=null,this.parseCount=0}getToken(){if("server"===this.platform)return null;const t=this.doc.cookie||"";return t!==this.lastCookieString&&(this.parseCount++,this.lastToken=wC(t,this.cookieName),this.lastCookieString=t),this.lastToken}}return e.\u0275fac=function(t){return new(t||e)(L(Dt),L(dc),L(Dv))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(),wv=(()=>{class e{constructor(t,i){this.tokenService=t,this.headerName=i}intercept(t,i){const r=t.url.toLowerCase();if("GET"===t.method||"HEAD"===t.method||r.startsWith("http://")||r.startsWith("https://"))return i.handle(t);const o=this.tokenService.getToken();return null!==o&&!t.headers.has(this.headerName)&&(t=t.clone({headers:t.headers.set(this.headerName,o)})),i.handle(t)}}return e.\u0275fac=function(t){return new(t||e)(L(aE),L(Cv))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(),WU=(()=>{class e{constructor(t,i){this.backend=t,this.injector=i,this.chain=null}handle(t){if(null===this.chain){const i=this.injector.get(bv,[]);this.chain=i.reduceRight((r,o)=>new oE(r,o),this.backend)}return this.chain.handle(t)}}return e.\u0275fac=function(t){return new(t||e)(L(QN),L(gn))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(),zU=(()=>{class e{static disable(){return{ngModule:e,providers:[{provide:wv,useClass:jU}]}}static withOptions(t={}){return{ngModule:e,providers:[t.cookieName?{provide:Dv,useValue:t.cookieName}:[],t.headerName?{provide:Cv,useValue:t.headerName}:[]]}}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({providers:[wv,{provide:bv,useExisting:wv,multi:!0},{provide:aE,useClass:GU},{provide:Dv,useValue:"XSRF-TOKEN"},{provide:Cv,useValue:"X-XSRF-TOKEN"}]}),e})(),YU=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e}),e.\u0275inj=Ne({providers:[rE,{provide:JN,useClass:WU},sE,{provide:QN,useExisting:sE}],imports:[zU.withOptions({cookieName:"XSRF-TOKEN",headerName:"X-XSRF-TOKEN"})]}),e})(),lE=(()=>{class e{constructor(t,i){this.config=t,this.http=i}pauseConsumerTopic(t,i){var r=this;return Yr(function*(){yield Kr(r.http.put(r.config.rootUrl+`/consumers/${t}/topics/${i}/pause`,""))})()}resumeConsumerTopic(t,i){var r=this;return Yr(function*(){yield Kr(r.http.put(r.config.rootUrl+`/consumers/${t}/topics/${i}/resume`,""))})()}resetConsumerTopic(t,i){var r=this;return Yr(function*(){yield Kr(r.http.put(r.config.rootUrl+`/consumers/${t}/topics/${i}/reset`,""))})()}rewindConsumerTopic(t,i,r){var o=this;return Yr(function*(){const s=YN(r).format("YYYY-MM-DD HH:mm:ss");yield Kr(o.http.put(o.config.rootUrl+`/consumers/${t}/topics/${i}/rewind/${s}`,""))})()}stopConsumer(t){var i=this;return Yr(function*(){yield Kr(i.http.put(i.config.rootUrl+`/consumers/${t}/stop`,""))})()}startConsumer(t){var i=this;return Yr(function*(){yield Kr(i.http.put(i.config.rootUrl+`/consumers/${t}/start`,""))})()}restartConsumer(t){var i=this;return Yr(function*(){yield Kr(i.http.put(i.config.rootUrl+`/consumers/${t}/restart`,""))})()}changeWorkers(t,i){var r=this;return Yr(function*(){yield Kr(r.http.put(r.config.rootUrl+`/consumers/${t}/changeWorkers/${i}`,""))})()}getTelemetry(){var t=this;return Yr(function*(){return yield Kr(t.http.get(t.config.rootUrl+"/consumers/telemetry"))})()}}return e.\u0275fac=function(t){return new(t||e)(L(ZN),L(rE))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})(),KU=(()=>{class e{transform(t,i){if(!t)return null;const r=t.reduce((o,s)=>(o[s[i]]?o[s[i]].push(s):o[s[i]]=[s],o),{});return Object.keys(r).map(o=>({key:o,value:r[o]}))}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275pipe=$t({name:"groupBy",type:e,pure:!0}),e})(),qU=(()=>{class e{transform(t,i,r="asc"){return"asc"!==(r=r.toLowerCase())&&"desc"!==r?t:Array.isArray(t)?(t.sort((o,s)=>o[i]s[i]?"asc"===r?1:-1:0),t):null}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275pipe=$t({name:"sort",type:e,pure:!0}),e})(); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */const ZU=["successAlert"];function JU(e,n){if(1&e){const t=It();M(0,"ngb-alert",2,3),W("closed",function(){return mt(t),_t(z().successMessage="")}),M(2,"div",4)(3,"b"),I(4,"Success! "),T(),M(5,"span",4),I(6),T()()()}if(2&e){const t=z();P(6),fo(t.successMessage)}}function QU(e,n){if(1&e){const t=It();M(0,"button",14),W("click",function(){mt(t);const r=z().$implicit,o=z().$implicit;return _t(z().openStartModal(o.groupId,r.name))}),I(1,"Start"),T()}}function XU(e,n){if(1&e){const t=It();M(0,"button",15),W("click",function(){mt(t);const r=z().$implicit,o=z().$implicit;return _t(z().openStopModal(o.groupId,r.name))}),I(1,"Stop"),T()}}function e3(e,n){if(1&e){const t=It();M(0,"button",15),W("click",function(){mt(t);const r=z().$implicit,o=z().$implicit;return _t(z().openRestartModal(o.groupId,r.name))}),I(1,"Restart"),T()}}function t3(e,n){if(1&e){const t=It();M(0,"button",16),W("click",function(){mt(t);const r=z().$implicit,o=z().$implicit;return _t(z().openWorkersCountModal(o.groupId,r.name,r.workersCount))}),I(1,"Change number of workers"),T()}}function n3(e,n){if(1&e){const t=It();M(0,"button",14),W("click",function(){mt(t);const r=z().$implicit,o=z().$implicit,s=z().$implicit;return _t(z().openResumeModal(s.groupId,o.name,r.key))}),I(1,"Resume"),T()}}function r3(e,n){if(1&e){const t=It();M(0,"button",15),W("click",function(){mt(t);const r=z().$implicit,o=z().$implicit,s=z().$implicit;return _t(z().openPauseModal(s.groupId,o.name,r.key))}),I(1,"Pause"),T()}}function o3(e,n){if(1&e){const t=It();M(0,"button",20),W("click",function(){mt(t);const r=z().$implicit,o=z().$implicit,s=z().$implicit;return _t(z().openRewindModal(s.groupId,o.name,r.key))}),I(1,"Rewind Offset"),T()}}function s3(e,n){if(1&e){const t=It();M(0,"button",21),W("click",function(){mt(t);const r=z().$implicit,o=z().$implicit,s=z().$implicit;return _t(z().openResetModal(s.groupId,o.name,r.key))}),I(1,"Reset Offset"),T()}}function a3(e,n){1&e&&Li(0,"div")}function l3(e,n){1&e&&(M(0,"span"),I(1,"Offline"),T())}function c3(e,n){1&e&&(M(0,"span",27),I(1,"Paused"),T())}function u3(e,n){1&e&&(M(0,"span",28),I(1,"Running"),T())}function d3(e,n){if(1&e&&(Z(0,c3,2,0,"ng-template",26),Z(1,u3,2,0,"ng-template",26)),2&e){const t=z().$implicit,i=z(4);Q("ngIf",i.hasPausedPartition(t)),P(1),Q("ngIf",i.hasRunningPartition(t))}}function f3(e,n){if(1&e&&(M(0,"tr")(1,"td",22),I(2),T(),M(3,"td",22),I(4),T(),M(5,"td",22),I(6),T(),M(7,"td",22),Z(8,a3,1,0,"div",23),Z(9,l3,2,0,"ng-template",null,24,ji),Z(11,d3,2,2,"ng-template",null,25,ji),T(),M(13,"td",22)(14,"span",9),I(15),wd(16,"date"),T()()()),2&e){const t=n.$implicit,i=Fi(10),r=Fi(12),o=z(4);P(2),fo(t.instanceName),P(2),fo(o.hasRunningPartition(t)?t.runningPartitions:t.pausedPartitions),P(2),fo(t.lag),P(2),Q("ngIf",t.isLost)("ngIfThen",i)("ngIfElse",r),P(6),Q("ngClass",t.isLost?"text-secondary":"text-success"),P(1),fo(Sd(16,8,t.lastUpdate+"Z","medium"))}}function h3(e,n){if(1&e&&(Li(0,"hr"),M(1,"h5"),I(2),Z(3,n3,2,0,"button",10),Z(4,r3,2,0,"button",11),Z(5,o3,2,0,"button",17),Z(6,s3,2,0,"button",18),T(),M(7,"table",19)(8,"thead")(9,"tr")(10,"th"),I(11,"Consumer instance"),T(),M(12,"th"),I(13,"Partitions"),T(),M(14,"th"),I(15,"Lag"),T(),M(16,"th"),I(17,"Status"),T(),M(18,"th"),I(19,"LastUpdate"),T()()(),M(20,"tbody"),Z(21,f3,17,11,"ng-template",13),wd(22,"sort"),T()()),2&e){const t=n.$implicit,i=z().$implicit,r=z(2);P(2),He(" Topic: ",t.key," "),P(1),Q("ngIf",t.value.some(r.hasPausedPartition)),P(1),Q("ngIf",t.value.some(r.hasRunningPartition)),P(1),Q("ngIf","Running"===i.status),P(1),Q("ngIf","Running"===i.status),P(15),Q("ngForOf",Sd(22,6,t.value,"instanceName"))}}const p3=function(e,n,t){return{"text-success":e,"text-warning":n,"text-danger":t}},g3=function(){return[]};function m3(e,n){if(1&e&&(M(0,"div")(1,"h4"),I(2),T(),M(3,"h4"),I(4,"Status: "),M(5,"span",9),I(6),T(),Z(7,QU,2,0,"button",10),Z(8,XU,2,0,"button",11),Z(9,e3,2,0,"button",11),T(),M(10,"h4"),I(11),T(),M(12,"h4"),I(13),Z(14,t3,2,0,"button",12),T(),Z(15,h3,23,9,"ng-template",13),wd(16,"groupBy"),Li(17,"hr"),T()),2&e){const t=n.$implicit;P(2),He("Consumer: ",t.name,""),P(3),Q("ngClass",Cd(13,p3,"Running"===t.status,"Paused"===t.status,"Not Running"===t.status)),P(1),fo(t.status),P(1),Q("ngIf","Not Running"===t.status),P(1),Q("ngIf","Running"===t.status),P(1),Q("ngIf","Running"===t.status),P(2),He("Lag: ",t.lag,""),P(2),He("Workers: ",t.workersCount," "),P(1),Q("ngIf","Running"===t.status),P(1),Q("ngForOf",Sd(16,10,t.assignments|| -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -function t1(e,n,t){const i=rn()+e,r=O();return r[i]===ae?or(r,i,t?n.call(t):n()):function Ql(e,n){return e[n]}(r,i)}(17,g3),"topicName"))}}function _3(e,n){if(1&e&&(M(0,"div",5)(1,"div",6)(2,"div",7)(3,"h3"),I(4),T(),Z(5,m3,18,18,"div",8),T()()()),2&e){const t=n.$implicit;P(4),He("Group Id: ",t.groupId,""),P(1),Q("ngForOf",t.consumers)}}let v3=(()=>{class e{constructor(t,i){this.modalService=t,this.gateway=i,this.successSubject=new Ue,this.delayMs=5e3,this.successMessage="",this.updateData=()=>{this.gateway.getTelemetry().then(r=>{this.telemetryResponse=this.updateConsumersStatus(r)})},this.hasRunningPartition=r=>r.runningPartitions?.length>0,this.hasPausedPartition=r=>r.pausedPartitions?.length>0,this.isActive=r=>Math.abs(((new Date).getTime()-new Date(r+"Z").getTime())/1e3)<30,this.openWorkersCountModal=(r,o,s)=>{const a=this.modalService.open(EU);a.componentInstance.groupId=r,a.componentInstance.consumerName=o,a.componentInstance.workersCount=s,a.result.then(l=>{this.gateway.changeWorkers(o,l).then(()=>this.successSubject.next("The number of workers was updated successfully"))})},this.openResetModal=(r,o,s)=>{const a=this.modalService.open(TU);a.componentInstance.groupId=r,a.componentInstance.consumerName=o,a.componentInstance.topic=s,a.result.then(()=>{this.gateway.resetConsumerTopic(o,s).then(()=>this.successSubject.next("The partition-offsets of your consumer were reseted successfully"))})},this.openPauseModal=(r,o,s)=>{const a=this.modalService.open(IU);a.componentInstance.groupId=r,a.componentInstance.topic=s,a.componentInstance.consumerName=o,a.result.then(()=>{this.gateway.pauseConsumerTopic(o,s).then(()=>this.successSubject.next("Your consumer was paused successfully"))})},this.openRestartModal=(r,o)=>{const s=this.modalService.open(kU);s.componentInstance.groupId=r,s.componentInstance.consumerName=o,s.result.then(()=>{this.gateway.restartConsumer(o).then(()=>this.successSubject.next("Your consumer was restarted successfully"))})},this.openStartModal=(r,o)=>{const s=this.modalService.open(OU);s.componentInstance.groupId=r,s.componentInstance.consumerName=o,s.result.then(()=>{this.gateway.startConsumer(o).then(()=>this.successSubject.next("Your consumer was started successfully"))})},this.openStopModal=(r,o)=>{const s=this.modalService.open(xU);s.componentInstance.groupId=r,s.componentInstance.consumerName=o,s.result.then(()=>{this.gateway.stopConsumer(o).then(()=>this.successSubject.next("Your consumer was stopped successfully"))})},this.openResumeModal=(r,o,s)=>{const a=this.modalService.open(AU);a.componentInstance.groupId=r,a.componentInstance.consumerName=o,a.componentInstance.topic=s,a.result.then(()=>{this.gateway.resumeConsumerTopic(o,s).then(()=>this.successSubject.next("Your consumer was resumed successfully"))})},this.openRewindModal=(r,o,s)=>{const a=this.modalService.open(NU);a.componentInstance.consumerName=o,a.componentInstance.groupId=r,a.componentInstance.topic=s,a.result.then(l=>{const u=YN(l,"YYYY-MM-DDTHH:mm").toDate();this.gateway.rewindConsumerTopic(o,s,u).then(()=>this.successSubject.next("The partition-offset of your consumer were rewound successfully"))})}}ngOnInit(){this.successSubject.subscribe(t=>this.successMessage=t),this.successSubject.pipe(function MU(e,n=Rf){return qe((t,i)=>{let r=null,o=null,s=null;const a=()=>{if(r){r.unsubscribe(),r=null;const u=o;o=null,i.next(u)}};function l(){const u=s+e,f=n.now();if(f{o=u,s=n.now(),r||(r=n.schedule(l,e),i.add(r))},()=>{a(),i.complete()},void 0,()=>{o=r=null}))})}(5e3)).subscribe(()=>this.successAlert?.close()),this.updateData(),function SU(e=0,n=Rf){return e<0&&(e=0),jc(e,e,n)}(this.delayMs).subscribe(this.updateData)}updateConsumersStatus(t){const i=this;return t.groups?.forEach(r=>{r.consumers?.forEach(o=>{o.status=o.assignments.some(s=>s.runningPartitions?.length>0&&i.isActive(s.lastUpdate))?"Running":o.assignments.some(s=>s.pausedPartitions?.length>0&&i.isActive(s.lastUpdate))?"Paused":"Not Running",o.lag=o.assignments.map(s=>s.lag).reduce((s,a)=>s+a),o.assignments.forEach(s=>s.isLost=!i.isActive(s.lastUpdate))})}),t}}return e.\u0275fac=function(t){return new(t||e)(C(SN),C(lE))},e.\u0275cmp=et({type:e,selectors:[["app-consumer"]],viewQuery:function(t,i){if(1&t&&Nd(ZU,5),2&t){let r;at(r=lt())&&(i.successAlert=r.first)}},decls:2,vars:2,consts:[["type","success",3,"closed",4,"ngIf"],["class","container",4,"ngFor","ngForOf"],["type","success",3,"closed"],["successAlert",""],[1,"text-center"],[1,"container"],[1,"card","my-3"],[1,"card-body"],[4,"ngFor","ngForOf"],[3,"ngClass"],["class","btn btn-sm btn-outline-success ml-2","type","button",3,"click",4,"ngIf"],["class","btn btn-sm btn-outline-warning ml-2","type","button",3,"click",4,"ngIf"],["class","btn btn-sm btn-outline-success ml-3","type","button",3,"click",4,"ngIf"],["ngFor","",3,"ngForOf"],["type","button",1,"btn","btn-sm","btn-outline-success","ml-2",3,"click"],["type","button",1,"btn","btn-sm","btn-outline-warning","ml-2",3,"click"],["type","button",1,"btn","btn-sm","btn-outline-success","ml-3",3,"click"],["class","btn btn-sm btn-outline-info ml-2","type","button",3,"click",4,"ngIf"],["class","btn btn-sm btn-outline-secondary ml-2","type","button",3,"click",4,"ngIf"],[1,"table","table-striped","table-hover","mt-1"],["type","button",1,"btn","btn-sm","btn-outline-info","ml-2",3,"click"],["type","button",1,"btn","btn-sm","btn-outline-secondary","ml-2",3,"click"],[1,"text-left"],[4,"ngIf","ngIfThen","ngIfElse"],["consumer_lost",""],["consumer_on",""],[3,"ngIf"],[1,"font-weight-bold","text-warning"],[1,"font-weight-bold","text-success"]],template:function(t,i){1&t&&(Z(0,JU,7,1,"ngb-alert",0),Z(1,_3,6,2,"div",1)),2&t&&(Q("ngIf",i.successMessage),P(1),Q("ngForOf",null==i.telemetryResponse?null:i.telemetryResponse.groups))},dependencies:[SC,Oa,ns,y$,AC,KU,qU],encapsulation:2}),e})(),y3=(()=>{class e{constructor(){}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275cmp=et({type:e,selectors:[["app-home"]],decls:12,vars:0,consts:[[1,"navbar","navbar-expand-lg","navbar-light","bg-light"],[1,"container-fluid"],["href","#",1,"navbar-brand"],["type","button","data-bs-toggle","collapse","data-bs-target","#navbarSupportedContent","aria-controls","navbarSupportedContent","aria-expanded","false","aria-label","Toggle navigation",1,"navbar-toggler"],[1,"navbar-toggler-icon"],["id","navbarSupportedContent",1,"collapse","navbar-collapse"],[1,"navbar-nav","me-auto","mb-2","mb-lg-0"],[1,"nav-item"],["aria-current","page","href","#",1,"nav-link","active"]],template:function(t,i){1&t&&(M(0,"nav",0)(1,"div",1)(2,"a",2),I(3,"KafkaFlow - Dashboard"),T(),M(4,"button",3),Li(5,"span",4),T(),M(6,"div",5)(7,"ul",6)(8,"li",7)(9,"a",8),I(10,"Consumers"),T()()()()()(),Li(11,"app-consumer"))},dependencies:[hv,v3],encapsulation:2}),e})(),D3=(()=>{class e{constructor(t){this.cookieService=t}intercept(t,i){return t=t.clone({setHeaders:this.cookieService.getAll()}),i.handle(t).pipe(function b3(e=1/0){let n;n=e&&"object"==typeof e?e:{count:e};const{count:t=1/0,delay:i,resetOnSuccess:r=!1}=n;return t<=0?Rn:qe((o,s)=>{let l,a=0;const u=()=>{let f=!1;l=o.subscribe(Oe(s,p=>{r&&(a=0),s.next(p)},void 0,p=>{if(a++{l?(l.unsubscribe(),l=null,u()):f=!0};if(null!=i){const v="number"==typeof i?jc(i):ut(i(p,a)),y=Oe(s,()=>{y.unsubscribe(),m()},()=>{s.complete()});v.subscribe(y)}else m()}else s.error(p)})),f&&(l.unsubscribe(),l=null,u())};u()})}(1),$r(r=>{let o="";return o=r.error instanceof ErrorEvent?`Error: ${r.error.message}`:`Error Code: ${r.status}\nMessage: ${r.message}`,console.error(o),xa(o)}))}}return e.\u0275fac=function(t){return new(t||e)(L(EM))},e.\u0275prov=G({token:e,factory:e.\u0275fac}),e})();const C3={validation:!1},w3=[{path:"",component:y3}];let S3=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=Ee({type:e,bootstrap:[wB]}),e.\u0275inj=Ne({providers:[ZN,EM,lE,{provide:bv,useClass:D3,multi:!0}],imports:[OF,CB,Cf.forRoot(w3),YU,CM,wU,bB.forRoot(C3),Cf]}),e})();(function oR(){Q1=!1} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */)(),kF().bootstrapModule(S3).catch(e=>console.error(e))},439:function(gr,th,iu){(gr=iu.nmd(gr)).exports=function(){"use strict";var ye,No;function V(){return ye.apply(null,arguments)}function dn(c){return c instanceof Array||"[object Array]"===Object.prototype.toString.call(c)}function Ct(c){return null!=c&&"[object Object]"===Object.prototype.toString.call(c)}function we(c,d){return Object.prototype.hasOwnProperty.call(c,d)}function bs(c){if(Object.getOwnPropertyNames)return 0===Object.getOwnPropertyNames(c).length;var d;for(d in c)if(we(c,d))return!1;return!0}function qt(c){return void 0===c}function Zt(c){return"number"==typeof c||"[object Number]"===Object.prototype.toString.call(c)}function Ji(c){return c instanceof Date||"[object Date]"===Object.prototype.toString.call(c)}function Za(c,d){var g,h=[],_=c.length;for(g=0;g<_;++g)h.push(d(c[g],g));return h}function Dn(c,d){for(var h in d)we(d,h)&&(c[h]=d[h]);return we(d,"toString")&&(c.toString=d.toString),we(d,"valueOf")&&(c.valueOf=d.valueOf),c}function ii(c,d,h,g){return Jr(c,d,h,g,!0).utc()}function le(c){return null==c._pf&&(c._pf={empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidEra:null,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1,parsedDateParts:[],era:null,meridiem:null,rfc2822:!1,weekdayMismatch:!1}),c._pf}function Ci(c){if(null==c._isValid){var d=le(c),h=No.call(d.parsedDateParts,function(_){return null!=_}),g=!isNaN(c._d.getTime())&&d.overflow<0&&!d.empty&&!d.invalidEra&&!d.invalidMonth&&!d.invalidWeekday&&!d.weekdayMismatch&&!d.nullInput&&!d.invalidFormat&&!d.userInvalidated&&(!d.meridiem||d.meridiem&&h);if(c._strict&&(g=g&&0===d.charsLeftOver&&0===d.unusedTokens.length&&void 0===d.bigHour),null!=Object.isFrozen&&Object.isFrozen(c))return g;c._isValid=g}return c._isValid}function mr(c){var d=ii(NaN);return null!=c?Dn(le(d),c):le(d).userInvalidated=!0,d}No=Array.prototype.some?Array.prototype.some:function(c){var g,d=Object(this),h=d.length>>>0;for(g=0;g0)for(h=0;h=0?h?"+":"":"-")+Math.pow(10,Math.max(0,d-g.length)).toString().substr(1)+g}var el=/(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|N{1,5}|YYYYYY|YYYYY|YYYY|YY|y{2,4}|yo?|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,ws=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,Ue={},yr={};function Y(c,d,h,g){var _=g;"string"==typeof g&&(_=function(){return this[g]()}),c&&(yr[c]=_),d&&(yr[d[0]]=function(){return oi(_.apply(this,arguments),d[1],d[2])}),h&&(yr[h]=function(){return this.localeData().ordinal(_.apply(this,arguments),c)})}function qe(c){return c.match(/\[[\s\S]/)?c.replace(/^\[|\]$/g,""):c.replace(/\\/g,"")}function Ss(c,d){return c.isValid()?(d=ne(d,c.localeData()),Ue[d]=Ue[d]||function Oe(c){var h,g,d=c.match(el);for(h=0,g=d.length;h=0&&ws.test(c);)c=c.replace(ws,g),ws.lastIndex=0,h-=1;return c}var Ms={};function xt(c,d){var h=c.toLowerCase();Ms[h]=Ms[h+"s"]=Ms[d]=c}function Pn(c){return"string"==typeof c?Ms[c]||Ms[c.toLowerCase()]:void 0}function cu(c){var h,g,d={};for(g in c)we(c,g)&&(h=Pn(g))&&(d[h]=c[g]);return d}var rh={};function Qt(c,d){rh[c]=d}function Ns(c){return c%4==0&&c%100!=0||c%400==0}function zn(c){return c<0?Math.ceil(c)||0:Math.floor(c)}function he(c){var d=+c,h=0;return 0!==d&&isFinite(d)&&(h=zn(d)),h}function To(c,d){return function(h){return null!=h?(oh(this,c,h),V.updateOffset(this,d),this):Es(this,c)}}function Es(c,d){return c.isValid()?c._d["get"+(c._isUTC?"UTC":"")+d]():NaN}function oh(c,d,h){c.isValid()&&!isNaN(h)&&("FullYear"===d&&Ns(c.year())&&1===c.month()&&29===c.date()?(h=he(h),c._d["set"+(c._isUTC?"UTC":"")+d](h,c.month(),Os(h,c.month()))):c._d["set"+(c._isUTC?"UTC":"")+d](h))}var xo,sh=/\d/,Fn=/\d\d/,Ts=/\d{3}/,Is=/\d{4}/,Io=/[+-]?\d{6}/,Ge=/\d\d?/,nl=/\d\d\d\d?/,uu=/\d\d\d\d\d\d?/,Ao=/\d{1,3}/,As=/\d{1,4}/,ko=/[+-]?\d{1,6}/,Dr=/\d+/,ut=/[+-]?\d+/,ah=/Z|[+-]\d\d:?\d\d/gi,ks=/Z|[+-]\d\d(?::?\d\d)?/gi,Oo=/[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i;function $(c,d,h){xo[c]=ri(d)?d:function(g,_){return g&&h?h:d}}function ch(c,d){return we(xo,c)?xo[c](d._strict,d._locale):new RegExp(function wi(c){return Cn(c.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(d,h,g,_,b){return h||g||_||b}))}(c))}function Cn(c){return c.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}xo={};var dt={};function Se(c,d){var h,_,g=d;for("string"==typeof c&&(c=[c]),Zt(d)&&(g=function(b,E){E[d]=he(b)}),_=c.length,h=0;h<_;h++)dt[c[h]]=g}function Xt(c,d){Se(c,function(h,g,_,b){_._w=_._w||{},d(h,_._w,_,b)})}function Fv(c,d,h){null!=d&&we(dt,c)&&dt[c](d,h._a,h,c)}var ft;function Os(c,d){if(isNaN(c)||isNaN(d))return NaN;var h=function dh(c,d){return(c%d+d)%d}(d,12);return c+=(d-h)/12,1===h?Ns(c)?29:28:31-h%7%2}ft=Array.prototype.indexOf?Array.prototype.indexOf:function(c){var d;for(d=0;d68?1900:2e3)};var F=To("FullYear",!0);function oe(c,d,h,g,_,b,E){var K;return c<100&&c>=0?(K=new Date(c+400,d,h,g,_,b,E),isFinite(K.getFullYear())&&K.setFullYear(c)):K=new Date(c,d,h,g,_,b,E),K}function _e(c){var d,h;return c<100&&c>=0?((h=Array.prototype.slice.call(arguments))[0]=c+400,d=new Date(Date.UTC.apply(null,h)),isFinite(d.getUTCFullYear())&&d.setUTCFullYear(c)):d=new Date(Date.UTC.apply(null,arguments)),d}function Ls(c,d,h){var g=7+d-h;return-(7+_e(c,0,g).getUTCDay()-d)%7+g-1}function gh(c,d,h,g,_){var ce,Fe,K=1+7*(d-1)+(7+h-g)%7+Ls(c,g,_);return K<=0?Fe=Ps(ce=c-1)+K:K>Ps(c)?(ce=c+1,Fe=K-Ps(c)):(ce=c,Fe=K),{year:ce,dayOfYear:Fe}}function Ro(c,d,h){var b,E,g=Ls(c.year(),d,h),_=Math.floor((c.dayOfYear()-g-1)/7)+1;return _<1?b=_+Vn(E=c.year()-1,d,h):_>Vn(c.year(),d,h)?(b=_-Vn(c.year(),d,h),E=c.year()+1):(E=c.year(),b=_),{week:b,year:E}}function Vn(c,d,h){var g=Ls(c,d,h),_=Ls(c+1,d,h);return(Ps(c)-g+_)/7}Y("w",["ww",2],"wo","week"),Y("W",["WW",2],"Wo","isoWeek"),xt("week","w"),xt("isoWeek","W"),Qt("week",5),Qt("isoWeek",5),$("w",Ge),$("ww",Ge,Fn),$("W",Ge),$("WW",Ge,Fn),Xt(["w","ww","W","WW"],function(c,d,h,g){d[g.substr(0,1)]=he(c)});function gu(c,d){return c.slice(d,7).concat(c.slice(0,d))}Y("d",0,"do","day"),Y("dd",0,0,function(c){return this.localeData().weekdaysMin(this,c)}),Y("ddd",0,0,function(c){return this.localeData().weekdaysShort(this,c)}),Y("dddd",0,0,function(c){return this.localeData().weekdays(this,c)}),Y("e",0,0,"weekday"),Y("E",0,0,"isoWeekday"),xt("day","d"),xt("weekday","e"),xt("isoWeekday","E"),Qt("day",11),Qt("weekday",11),Qt("isoWeekday",11),$("d",Ge),$("e",Ge),$("E",Ge),$("dd",function(c,d){return d.weekdaysMinRegex(c)}),$("ddd",function(c,d){return d.weekdaysShortRegex(c)}),$("dddd",function(c,d){return d.weekdaysRegex(c)}),Xt(["dd","ddd","dddd"],function(c,d,h,g){var _=h._locale.weekdaysParse(c,g,h._strict);null!=_?d.d=_:le(h).invalidWeekday=c}),Xt(["d","e","E"],function(c,d,h,g){d[g]=he(c)});var _h="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),vh="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),yh="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),$v=Oo,Sn=Oo,ke=Oo;function G(c,d,h){var g,_,b,E=c.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],g=0;g<7;++g)b=ii([2e3,1]).day(g),this._minWeekdaysParse[g]=this.weekdaysMin(b,"").toLocaleLowerCase(),this._shortWeekdaysParse[g]=this.weekdaysShort(b,"").toLocaleLowerCase(),this._weekdaysParse[g]=this.weekdays(b,"").toLocaleLowerCase();return h?"dddd"===d?-1!==(_=ft.call(this._weekdaysParse,E))?_:null:"ddd"===d?-1!==(_=ft.call(this._shortWeekdaysParse,E))?_:null:-1!==(_=ft.call(this._minWeekdaysParse,E))?_:null:"dddd"===d?-1!==(_=ft.call(this._weekdaysParse,E))||-1!==(_=ft.call(this._shortWeekdaysParse,E))||-1!==(_=ft.call(this._minWeekdaysParse,E))?_:null:"ddd"===d?-1!==(_=ft.call(this._shortWeekdaysParse,E))||-1!==(_=ft.call(this._weekdaysParse,E))||-1!==(_=ft.call(this._minWeekdaysParse,E))?_:null:-1!==(_=ft.call(this._minWeekdaysParse,E))||-1!==(_=ft.call(this._weekdaysParse,E))||-1!==(_=ft.call(this._shortWeekdaysParse,E))?_:null}function Bs(){function c(vt,xi){return xi.length-vt.length}var b,E,K,ce,Fe,d=[],h=[],g=[],_=[];for(b=0;b<7;b++)E=ii([2e3,1]).day(b),K=Cn(this.weekdaysMin(E,"")),ce=Cn(this.weekdaysShort(E,"")),Fe=Cn(this.weekdays(E,"")),d.push(K),h.push(ce),g.push(Fe),_.push(K),_.push(ce),_.push(Fe);d.sort(c),h.sort(c),g.sort(c),_.sort(c),this._weekdaysRegex=new RegExp("^("+_.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+g.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+h.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+d.join("|")+")","i")}function Zr(){return this.hours()%12||12}function sl(c,d){Y(c,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),d)})}function _u(c,d){return d._meridiemParse}Y("H",["HH",2],0,"hour"),Y("h",["hh",2],0,Zr),Y("k",["kk",2],0,function ol(){return this.hours()||24}),Y("hmm",0,0,function(){return""+Zr.apply(this)+oi(this.minutes(),2)}),Y("hmmss",0,0,function(){return""+Zr.apply(this)+oi(this.minutes(),2)+oi(this.seconds(),2)}),Y("Hmm",0,0,function(){return""+this.hours()+oi(this.minutes(),2)}),Y("Hmmss",0,0,function(){return""+this.hours()+oi(this.minutes(),2)+oi(this.seconds(),2)}),sl("a",!0),sl("A",!1),xt("hour","h"),Qt("hour",13),$("a",_u),$("A",_u),$("H",Ge),$("h",Ge),$("k",Ge),$("HH",Ge,Fn),$("hh",Ge,Fn),$("kk",Ge,Fn),$("hmm",nl),$("hmmss",uu),$("Hmm",nl),$("Hmmss",uu),Se(["H","HH"],3),Se(["k","kk"],function(c,d,h){var g=he(c);d[3]=24===g?0:g}),Se(["a","A"],function(c,d,h){h._isPm=h._locale.isPM(c),h._meridiem=c}),Se(["h","hh"],function(c,d,h){d[3]=he(c),le(h).bigHour=!0}),Se("hmm",function(c,d,h){var g=c.length-2;d[3]=he(c.substr(0,g)),d[4]=he(c.substr(g)),le(h).bigHour=!0}),Se("hmmss",function(c,d,h){var g=c.length-4,_=c.length-2;d[3]=he(c.substr(0,g)),d[4]=he(c.substr(g,2)),d[5]=he(c.substr(_)),le(h).bigHour=!0}),Se("Hmm",function(c,d,h){var g=c.length-2;d[3]=he(c.substr(0,g)),d[4]=he(c.substr(g))}),Se("Hmmss",function(c,d,h){var g=c.length-4,_=c.length-2;d[3]=he(c.substr(0,g)),d[4]=he(c.substr(g,2)),d[5]=he(c.substr(_))});var wh=To("Hours",!0);var tn,ll={calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},longDateFormat:{LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},invalidDate:"Invalid date",ordinal:"%d",dayOfMonthOrdinalParse:/\d{1,2}/,relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",w:"a week",ww:"%d weeks",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},months:fu,monthsShort:hu,week:{dow:0,doy:6},weekdays:_h,weekdaysMin:yh,weekdaysShort:vh,meridiemParse:/[ap]\.?m?\.?/i},Xe={},Hn={};function Yv(c,d){var h,g=Math.min(c.length,d.length);for(h=0;h0;){if(_=cl(b.slice(0,h).join("-")))return _;if(g&&g.length>=h&&Yv(b,g)>=h-1)break;h--}d++}return tn}(c)}function Po(c){var d,h=c._a;return h&&-2===le(c).overflow&&(d=h[1]<0||h[1]>11?1:h[2]<1||h[2]>Os(h[0],h[1])?2:h[3]<0||h[3]>24||24===h[3]&&(0!==h[4]||0!==h[5]||0!==h[6])?3:h[4]<0||h[4]>59?4:h[5]<0||h[5]>59?5:h[6]<0||h[6]>999?6:-1,le(c)._overflowDayOfYear&&(d<0||d>2)&&(d=2),le(c)._overflowWeeks&&-1===d&&(d=7),le(c)._overflowWeekday&&-1===d&&(d=8),le(c).overflow=d),c}var vu=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Ni=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d|))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Fo=/Z|[+-]\d\d(?::?\d\d)?/,Hs=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/],["YYYYMM",/\d{6}/,!1],["YYYY",/\d{4}/,!1]],et=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],Mh=/^\/?Date\((-?\d+)/i,yu=/^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/,bu={UT:0,GMT:0,EDT:-240,EST:-300,CDT:-300,CST:-360,MDT:-360,MST:-420,PDT:-420,PST:-480};function Ee(c){var d,h,b,E,K,ce,g=c._i,_=vu.exec(g)||Ni.exec(g),Fe=Hs.length,vt=et.length;if(_){for(le(c).iso=!0,d=0,h=Fe;d7)&&(ce=!0)):(b=c._locale._week.dow,E=c._locale._week.doy,Fe=Ro(Re(),b,E),h=Yn(d.gg,c._a[0],Fe.year),g=Yn(d.w,Fe.week),null!=d.d?((_=d.d)<0||_>6)&&(ce=!0):null!=d.e?(_=d.e+b,(d.e<0||d.e>6)&&(ce=!0)):_=b),g<1||g>Vn(h,b,E)?le(c)._overflowWeeks=!0:null!=ce?le(c)._overflowWeekday=!0:(K=gh(h,g,_,b,E),c._a[0]=K.year,c._dayOfYear=K.dayOfYear)}(c),null!=c._dayOfYear&&(E=Yn(c._a[0],_[0]),(c._dayOfYear>Ps(E)||0===c._dayOfYear)&&(le(c)._overflowDayOfYear=!0),h=_e(E,0,c._dayOfYear),c._a[1]=h.getUTCMonth(),c._a[2]=h.getUTCDate()),d=0;d<3&&null==c._a[d];++d)c._a[d]=g[d]=_[d];for(;d<7;d++)c._a[d]=g[d]=c._a[d]??(2===d?1:0);24===c._a[3]&&0===c._a[4]&&0===c._a[5]&&0===c._a[6]&&(c._nextDay=!0,c._a[3]=0),c._d=(c._useUTC?_e:oe).apply(null,g),b=c._useUTC?c._d.getUTCDay():c._d.getDay(),null!=c._tzm&&c._d.setUTCMinutes(c._d.getUTCMinutes()-c._tzm),c._nextDay&&(c._a[3]=24),c._w&&typeof c._w.d<"u"&&c._w.d!==b&&(le(c).weekdayMismatch=!0)}}function se(c){if(c._f!==V.ISO_8601)if(c._f!==V.RFC_2822){c._a=[],le(c).empty=!0;var h,g,_,b,E,Fe,vt,d=""+c._i,K=d.length,ce=0;for(vt=(_=ne(c._f,c._locale).match(el)||[]).length,h=0;h0&&le(c).unusedInput.push(E),d=d.slice(d.indexOf(g)+g.length),ce+=g.length),yr[b]?(g?le(c).empty=!1:le(c).unusedTokens.push(b),Fv(b,g,c)):c._strict&&!g&&le(c).unusedTokens.push(b);le(c).charsLeftOver=K-ce,d.length>0&&le(c).unusedInput.push(d),c._a[3]<=12&&!0===le(c).bigHour&&c._a[3]>0&&(le(c).bigHour=void 0),le(c).parsedDateParts=c._a.slice(0),le(c).meridiem=c._meridiem,c._a[3]=function Ze(c,d,h){var g;return null==h?d:null!=c.meridiemHour?c.meridiemHour(d,h):(null!=c.isPM&&((g=c.isPM(h))&&d<12&&(d+=12),!g&&12===d&&(d=0)),d)}(c._locale,c._a[3],c._meridiem),null!==(Fe=le(c).era)&&(c._a[0]=c._locale.erasConvertYear(Fe,c._a[0])),fn(c),Po(c)}else Ut(c);else Ee(c)}function er(c){var d=c._i,h=c._f;return c._locale=c._locale||jn(c._l),null===d||void 0===h&&""===d?mr({nullInput:!0}):("string"==typeof d&&(c._i=d=c._locale.preparse(d)),Wn(d)?new _r(Po(d)):(Ji(d)?c._d=d:dn(h)?function Nn(c){var d,h,g,_,b,E,K=!1,ce=c._f.length;if(0===ce)return le(c).invalidFormat=!0,void(c._d=new Date(NaN));for(_=0;_this?this:c:mr()});function Sr(c,d){var h,g;if(1===d.length&&dn(d[0])&&(d=d[0]),!d.length)return Re();for(h=d[0],g=1;g=0?new Date(c+400,d,h)-Bo:new Date(c,d,h).valueOf()}function zs(c,d,h){return c<100&&c>=0?Date.UTC(c+400,d,h)-Bo:Date.UTC(c,d,h)}function Ks(c,d){return d.erasAbbrRegex(c)}function jo(){var _,b,c=[],d=[],h=[],g=[],E=this.eras();for(_=0,b=E.length;_(b=Vn(c,g,_))&&(d=b),Ai.call(this,c,d,h,g,_))}function Ai(c,d,h,g,_){var b=gh(c,d,h,g,_),E=_e(b.year,0,b.dayOfYear);return this.year(E.getUTCFullYear()),this.month(E.getUTCMonth()),this.date(E.getUTCDate()),this}Y("N",0,0,"eraAbbr"),Y("NN",0,0,"eraAbbr"),Y("NNN",0,0,"eraAbbr"),Y("NNNN",0,0,"eraName"),Y("NNNNN",0,0,"eraNarrow"),Y("y",["y",1],"yo","eraYear"),Y("y",["yy",2],0,"eraYear"),Y("y",["yyy",3],0,"eraYear"),Y("y",["yyyy",4],0,"eraYear"),$("N",Ks),$("NN",Ks),$("NNN",Ks),$("NNNN",function Ho(c,d){return d.erasNameRegex(c)}),$("NNNNN",function ci(c,d){return d.erasNarrowRegex(c)}),Se(["N","NN","NNN","NNNN","NNNNN"],function(c,d,h,g){var _=h._locale.erasParse(c,g,h._strict);_?le(h).era=_:le(h).invalidEra=c}),$("y",Dr),$("yy",Dr),$("yyy",Dr),$("yyyy",Dr),$("yo",function bl(c,d){return d._eraYearOrdinalRegex||Dr}),Se(["y","yy","yyy","yyyy"],0),Se(["yo"],function(c,d,h,g){var _;h._locale._eraYearOrdinalRegex&&(_=c.match(h._locale._eraYearOrdinalRegex)),d[0]=h._locale.eraYearOrdinalParse?h._locale.eraYearOrdinalParse(c,_):parseInt(c,10)}),Y(0,["gg",2],0,function(){return this.weekYear()%100}),Y(0,["GG",2],0,function(){return this.isoWeekYear()%100}),Dl("gggg","weekYear"),Dl("ggggg","weekYear"),Dl("GGGG","isoWeekYear"),Dl("GGGGG","isoWeekYear"),xt("weekYear","gg"),xt("isoWeekYear","GG"),Qt("weekYear",1),Qt("isoWeekYear",1),$("G",ut),$("g",ut),$("GG",Ge,Fn),$("gg",Ge,Fn),$("GGGG",As,Is),$("gggg",As,Is),$("GGGGG",ko,Io),$("ggggg",ko,Io),Xt(["gggg","ggggg","GGGG","GGGGG"],function(c,d,h,g){d[g.substr(0,2)]=he(c)}),Xt(["gg","GG"],function(c,d,h,g){d[g]=V.parseTwoDigitYear(c)}),Y("Q",0,"Qo","quarter"),xt("quarter","Q"),Qt("quarter",7),$("Q",sh),Se("Q",function(c,d){d[1]=3*(he(c)-1)}),Y("D",["DD",2],"Do","date"),xt("date","D"),Qt("date",9),$("D",Ge),$("DD",Ge,Fn),$("Do",function(c,d){return c?d._dayOfMonthOrdinalParse||d._ordinalParse:d._dayOfMonthOrdinalParseLenient}),Se(["D","DD"],2),Se("Do",function(c,d){d[2]=he(c.match(Ge)[0])});var Cl=To("Date",!0);Y("DDD",["DDDD",3],"DDDo","dayOfYear"),xt("dayOfYear","DDD"),Qt("dayOfYear",4),$("DDD",Ao),$("DDDD",Ts),Se(["DDD","DDDD"],function(c,d,h){h._dayOfYear=he(c)}),Y("m",["mm",2],0,"minute"),xt("minute","m"),Qt("minute",14),$("m",Ge),$("mm",Ge,Fn),Se(["m","mm"],4);var Jh=To("Minutes",!1);Y("s",["ss",2],0,"second"),xt("second","s"),Qt("second",15),$("s",Ge),$("ss",Ge,Fn),Se(["s","ss"],5);var ui,Sl,wl=To("Seconds",!1);for(Y("S",0,0,function(){return~~(this.millisecond()/100)}),Y(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),Y(0,["SSS",3],0,"millisecond"),Y(0,["SSSS",4],0,function(){return 10*this.millisecond()}),Y(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),Y(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),Y(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),Y(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),Y(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),xt("millisecond","ms"),Qt("millisecond",16),$("S",Ao,sh),$("SS",Ao,Fn),$("SSS",Ao,Ts),ui="SSSS";ui.length<=9;ui+="S")$(ui,Dr);function Ml(c,d){d[6]=he(1e3*("0."+c))}for(ui="S";ui.length<=9;ui+="S")Se(ui,Ml);Sl=To("Milliseconds",!1),Y("z",0,0,"zoneAbbr"),Y("zz",0,0,"zoneName");var R=_r.prototype;function Nl(c){return c}R.add=Jv,R.calendar=function gl(c,d){1===arguments.length&&(arguments[0]?Xv(arguments[0])?(c=arguments[0],d=void 0):ny(arguments[0])&&(d=arguments[0],c=void 0):(c=void 0,d=void 0));var h=c||Re(),g=eo(h,this).startOf("day"),_=V.calendarFormat(this,g)||"sameElse",b=d&&(ri(d[_])?d[_].call(this,h):d[_]);return this.format(b||this.localeData().calendar(_,this,Re(h)))},R.clone=function iy(){return new _r(this)},R.diff=function Fh(c,d,h){var g,_,b;if(!this.isValid())return NaN;if(!(g=eo(c,this)).isValid())return NaN;switch(_=6e4*(g.utcOffset()-this.utcOffset()),d=Pn(d)){case"year":b=Gs(this,g)/12;break;case"month":b=Gs(this,g);break;case"quarter":b=Gs(this,g)/3;break;case"second":b=(this-g)/1e3;break;case"minute":b=(this-g)/6e4;break;case"hour":b=(this-g)/36e5;break;case"day":b=(this-g-_)/864e5;break;case"week":b=(this-g-_)/6048e5;break;default:b=this-g}return h?b:zn(b)},R.endOf=function En(c){var d,h;if(void 0===(c=Pn(c))||"millisecond"===c||!this.isValid())return this;switch(h=this._isUTC?zs:Tu,c){case"year":d=h(this.year()+1,0,1)-1;break;case"quarter":d=h(this.year(),this.month()-this.month()%3+3,1)-1;break;case"month":d=h(this.year(),this.month()+1,1)-1;break;case"week":d=h(this.year(),this.month(),this.date()-this.weekday()+7)-1;break;case"isoWeek":d=h(this.year(),this.month(),this.date()-(this.isoWeekday()-1)+7)-1;break;case"day":case"date":d=h(this.year(),this.month(),this.date()+1)-1;break;case"hour":d=this._d.valueOf(),d+=vl-Rt(d+(this._isUTC?0:this.utcOffset()*no),vl)-1;break;case"minute":d=this._d.valueOf(),d+=no-Rt(d,no)-1;break;case"second":d=this._d.valueOf(),d+=1e3-Rt(d,1e3)-1}return this._d.setTime(d),V.updateOffset(this,!0),this},R.format=function ml(c){c||(c=this.isUtc()?V.defaultFormatUtc:V.defaultFormat);var d=Ss(this,c);return this.localeData().postformat(d)},R.from=function Vh(c,d){return this.isValid()&&(Wn(c)&&c.isValid()||Re(c).isValid())?li({to:this,from:c}).locale(this.locale()).humanize(!d):this.localeData().invalidDate()},R.fromNow=function $n(c){return this.from(Re(),c)},R.to=function _l(c,d){return this.isValid()&&(Wn(c)&&c.isValid()||Re(c).isValid())?li({from:this,to:c}).locale(this.locale()).humanize(!d):this.localeData().invalidDate()},R.toNow=function Bh(c){return this.to(Re(),c)},R.get=function Rv(c){return ri(this[c=Pn(c)])?this[c]():this},R.invalidAt=function sy(){return le(this).overflow},R.isAfter=function ry(c,d){var h=Wn(c)?c:Re(c);return!(!this.isValid()||!h.isValid())&&("millisecond"===(d=Pn(d)||"millisecond")?this.valueOf()>h.valueOf():h.valueOf()9999?Ss(h,d?"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYYYY-MM-DD[T]HH:mm:ss.SSSZ"):ri(Date.prototype.toISOString)?d?this.toDate().toISOString():new Date(this.valueOf()+60*this.utcOffset()*1e3).toISOString().replace("Z",Ss(h,"Z")):Ss(h,d?"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYY-MM-DD[T]HH:mm:ss.SSSZ")},R.inspect=function Lh(){if(!this.isValid())return"moment.invalid(/* "+this._i+" */)";var h,g,c="moment",d="";return this.isLocal()||(c=0===this.utcOffset()?"moment.utc":"moment.parseZone",d="Z"),h="["+c+'("]',g=0<=this.year()&&this.year()<=9999?"YYYY":"YYYYYY",this.format(h+g+"-MM-DD[T]HH:mm:ss.SSS"+d+'[")]')},typeof Symbol<"u"&&null!=Symbol.for&&(R[Symbol.for("nodejs.util.inspect.custom")]=function(){return"Moment<"+this.format()+">"}),R.toJSON=function yl(){return this.isValid()?this.toISOString():null},R.toString=function Mu(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},R.unix=function Ys(){return Math.floor(this.valueOf()/1e3)},R.valueOf=function jh(){return this._d.valueOf()-6e4*(this._offset||0)},R.creationData=function Uh(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}},R.eraName=function zh(){var c,d,h,g=this.localeData().eras();for(c=0,d=g.length;cthis.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()},R.isLocal=function Ih(){return!!this.isValid()&&!this._isUTC},R.isUtcOffset=function Kv(){return!!this.isValid()&&this._isUTC},R.isUtc=Cu,R.isUTC=Cu,R.zoneAbbr=function Qh(){return this._isUTC?"UTC":""},R.zoneName=function Ru(){return this._isUTC?"Coordinated Universal Time":""},R.dates=Jt("dates accessor is deprecated. Use date instead.",Cl),R.months=Jt("months accessor is deprecated. Use month instead",xs),R.years=Jt("years accessor is deprecated. Use year instead",F),R.zone=Jt("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",function Th(c,d){return null!=c?("string"!=typeof c&&(c=-c),this.utcOffset(c,d),this):-this.utcOffset()}),R.isDSTShifted=Jt("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",function Zn(){if(!qt(this._isDSTShifted))return this._isDSTShifted;var d,c={};return Ja(c,this),(c=er(c))._a?(d=c._isUTC?ii(c._a):Re(c._a),this._isDSTShifted=this.isValid()&&function Eh(c,d,h){var E,g=Math.min(c.length,d.length),_=Math.abs(c.length-d.length),b=0;for(E=0;E0):this._isDSTShifted=!1,this._isDSTShifted});var Me=Xa.prototype;function ro(c,d,h,g){var _=jn(),b=ii().set(g,d);return _[h](b,c)}function Lu(c,d,h){if(Zt(c)&&(d=c,c=void 0),c=c||"",null!=d)return ro(c,d,h,"month");var g,_=[];for(g=0;g<12;g++)_[g]=ro(c,g,h,"month");return _}function El(c,d,h,g){"boolean"==typeof c?(Zt(d)&&(h=d,d=void 0),d=d||""):(h=d=c,c=!1,Zt(d)&&(h=d,d=void 0),d=d||"");var E,_=jn(),b=c?_._week.dow:0,K=[];if(null!=h)return ro(d,(h+b)%7,g,"day");for(E=0;E<7;E++)K[E]=ro(d,(E+b)%7,g,"day");return K}Me.calendar=function su(c,d,h){var g=this._calendar[c]||this._calendar.sameElse;return ri(g)?g.call(d,h):g},Me.longDateFormat=function Tv(c){var d=this._longDateFormat[c],h=this._longDateFormat[c.toUpperCase()];return d||!h?d:(this._longDateFormat[c]=h.match(el).map(function(g){return"MMMM"===g||"MM"===g||"DD"===g||"dddd"===g?g.slice(1):g}).join(""),this._longDateFormat[c])},Me.invalidDate=function Iv(){return this._invalidDate},Me.ordinal=function Ov(c){return this._ordinal.replace("%d",c)},Me.preparse=Nl,Me.postformat=Nl,Me.relativeTime=function xv(c,d,h,g){var _=this._relativeTime[h];return ri(_)?_(c,d,h,g):_.replace(/%d/i,c)},Me.pastFuture=function lu(c,d){var h=this._relativeTime[c>0?"future":"past"];return ri(h)?h(d):h.replace(/%s/i,d)},Me.set=function Qa(c){var d,h;for(h in c)we(c,h)&&(ri(d=c[h])?this[h]=d:this["_"+h]=d);this._config=c,this._dayOfMonthOrdinalParseLenient=new RegExp((this._dayOfMonthOrdinalParse.source||this._ordinalParse.source)+"|"+/\d{1,2}/.source)},Me.eras=function Gh(c,d){var h,g,_,b=this._eras||jn("en")._eras;for(h=0,g=b.length;h=0)return b[g]},Me.erasConvertYear=function ku(c,d){var h=c.since<=c.until?1:-1;return void 0===d?V(c.since).year():V(c.since).year()+(d-c.offset)*h},Me.erasAbbrRegex=function _t(c){return we(this,"_erasAbbrRegex")||jo.call(this),c?this._erasAbbrRegex:this._erasRegex},Me.erasNameRegex=function mt(c){return we(this,"_erasNameRegex")||jo.call(this),c?this._erasNameRegex:this._erasRegex},Me.erasNarrowRegex=function wt(c){return we(this,"_erasNarrowRegex")||jo.call(this),c?this._erasNarrowRegex:this._erasRegex},Me.months=function hh(c,d){return c?dn(this._months)?this._months[c.month()]:this._months[(this._months.isFormat||pu).test(d)?"format":"standalone"][c.month()]:dn(this._months)?this._months:this._months.standalone},Me.monthsShort=function il(c,d){return c?dn(this._monthsShort)?this._monthsShort[c.month()]:this._monthsShort[pu.test(d)?"format":"standalone"][c.month()]:dn(this._monthsShort)?this._monthsShort:this._monthsShort.standalone},Me.monthsParse=function rl(c,d,h){var g,_,b;if(this._monthsParseExact)return $e.call(this,c,d,h);for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),g=0;g<12;g++){if(_=ii([2e3,g]),h&&!this._longMonthsParse[g]&&(this._longMonthsParse[g]=new RegExp("^"+this.months(_,"").replace(".","")+"$","i"),this._shortMonthsParse[g]=new RegExp("^"+this.monthsShort(_,"").replace(".","")+"$","i")),!h&&!this._monthsParse[g]&&(b="^"+this.months(_,"")+"|^"+this.monthsShort(_,""),this._monthsParse[g]=new RegExp(b.replace(".",""),"i")),h&&"MMMM"===d&&this._longMonthsParse[g].test(c))return g;if(h&&"MMM"===d&&this._shortMonthsParse[g].test(c))return g;if(!h&&this._monthsParse[g].test(c))return g}},Me.monthsRegex=function te(c){return this._monthsParseExact?(we(this,"_monthsRegex")||Rs.call(this),c?this._monthsStrictRegex:this._monthsRegex):(we(this,"_monthsRegex")||(this._monthsRegex=fh),this._monthsStrictRegex&&c?this._monthsStrictRegex:this._monthsRegex)},Me.monthsShortRegex=function Te(c){return this._monthsParseExact?(we(this,"_monthsRegex")||Rs.call(this),c?this._monthsShortStrictRegex:this._monthsShortRegex):(we(this,"_monthsShortRegex")||(this._monthsShortRegex=gt),this._monthsShortStrictRegex&&c?this._monthsShortStrictRegex:this._monthsShortRegex)},Me.week=function wn(c){return Ro(c,this._week.dow,this._week.doy).week},Me.firstDayOfYear=function Vv(){return this._week.doy},Me.firstDayOfWeek=function mh(){return this._week.dow},Me.weekdays=function Uv(c,d){var h=dn(this._weekdays)?this._weekdays:this._weekdays[c&&!0!==c&&this._weekdays.isFormat.test(d)?"format":"standalone"];return!0===c?gu(h,this._week.dow):c?h[c.day()]:h},Me.weekdaysMin=function Wv(c){return!0===c?gu(this._weekdaysMin,this._week.dow):c?this._weekdaysMin[c.day()]:this._weekdaysMin},Me.weekdaysShort=function Gv(c){return!0===c?gu(this._weekdaysShort,this._week.dow):c?this._weekdaysShort[c.day()]:this._weekdaysShort},Me.weekdaysParse=function zv(c,d,h){var g,_,b;if(this._weekdaysParseExact)return G.call(this,c,d,h);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),g=0;g<7;g++){if(_=ii([2e3,1]).day(g),h&&!this._fullWeekdaysParse[g]&&(this._fullWeekdaysParse[g]=new RegExp("^"+this.weekdays(_,"").replace(".","\\.?")+"$","i"),this._shortWeekdaysParse[g]=new RegExp("^"+this.weekdaysShort(_,"").replace(".","\\.?")+"$","i"),this._minWeekdaysParse[g]=new RegExp("^"+this.weekdaysMin(_,"").replace(".","\\.?")+"$","i")),this._weekdaysParse[g]||(b="^"+this.weekdays(_,"")+"|^"+this.weekdaysShort(_,"")+"|^"+this.weekdaysMin(_,""),this._weekdaysParse[g]=new RegExp(b.replace(".",""),"i")),h&&"dddd"===d&&this._fullWeekdaysParse[g].test(c))return g;if(h&&"ddd"===d&&this._shortWeekdaysParse[g].test(c))return g;if(h&&"dd"===d&&this._minWeekdaysParse[g].test(c))return g;if(!h&&this._weekdaysParse[g].test(c))return g}},Me.weekdaysRegex=function mu(c){return this._weekdaysParseExact?(we(this,"_weekdaysRegex")||Bs.call(this),c?this._weekdaysStrictRegex:this._weekdaysRegex):(we(this,"_weekdaysRegex")||(this._weekdaysRegex=$v),this._weekdaysStrictRegex&&c?this._weekdaysStrictRegex:this._weekdaysRegex)},Me.weekdaysShortRegex=function Dh(c){return this._weekdaysParseExact?(we(this,"_weekdaysRegex")||Bs.call(this),c?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(we(this,"_weekdaysShortRegex")||(this._weekdaysShortRegex=Sn),this._weekdaysShortStrictRegex&&c?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)},Me.weekdaysMinRegex=function Ch(c){return this._weekdaysParseExact?(we(this,"_weekdaysRegex")||Bs.call(this),c?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(we(this,"_weekdaysMinRegex")||(this._weekdaysMinRegex=ke),this._weekdaysMinStrictRegex&&c?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)},Me.isPM=function X(c){return"p"===(c+"").toLowerCase().charAt(0)},Me.meridiem=function Bn(c,d,h){return c>11?h?"pm":"PM":h?"am":"AM"},Cr("en",{eras:[{since:"0001-01-01",until:1/0,offset:1,name:"Anno Domini",narrow:"AD",abbr:"AD"},{since:"0000-12-31",until:-1/0,offset:1,name:"Before Christ",narrow:"BC",abbr:"BC"}],dayOfMonthOrdinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(c){var d=c%10;return c+(1===he(c%100/10)?"th":1===d?"st":2===d?"nd":3===d?"rd":"th")}}),V.lang=Jt("moment.lang is deprecated. Use moment.locale instead.",Cr),V.langData=Jt("moment.langData is deprecated. Use moment.localeData instead.",jn);var ki=Math.abs;function Vu(c,d,h,g){var _=li(d,h);return c._milliseconds+=g*_._milliseconds,c._days+=g*_._days,c._months+=g*_._months,c._bubble()}function $o(c){return c<0?Math.floor(c):Math.ceil(c)}function Js(c){return 4800*c/146097}function Qs(c){return 146097*c/4800}function Tn(c){return function(){return this.as(c)}}var rp=Tn("ms"),op=Tn("s"),Uo=Tn("m"),Tl=Tn("h"),sp=Tn("d"),ap=Tn("w"),ly=Tn("M"),cy=Tn("Q"),Xs=Tn("y");function di(c){return function(){return this.isValid()?this._data[c]:NaN}}var ju=di("milliseconds"),$u=di("seconds"),oo=di("minutes"),lp=di("hours"),so=di("days"),Il=di("months"),ea=di("years");var fi=Math.round,Ir={ss:44,s:45,m:45,h:22,d:26,w:null,M:11};function cp(c,d,h,g,_){return _.relativeTime(d||1,!!h,c,g)}var Wo=Math.abs;function Oi(c){return(c>0)-(c<0)||+c}function Ar(){if(!this.isValid())return this.localeData().invalidDate();var g,_,b,E,ce,Fe,vt,xi,c=Wo(this._milliseconds)/1e3,d=Wo(this._days),h=Wo(this._months),K=this.asSeconds();return K?(g=zn(c/60),_=zn(g/60),c%=60,g%=60,b=zn(h/12),h%=12,E=c?c.toFixed(3).replace(/\.?0+$/,""):"",ce=K<0?"-":"",Fe=Oi(this._months)!==Oi(K)?"-":"",vt=Oi(this._days)!==Oi(K)?"-":"",xi=Oi(this._milliseconds)!==Oi(K)?"-":"",ce+"P"+(b?Fe+b+"Y":"")+(h?Fe+h+"M":"")+(d?vt+d+"D":"")+(_||g||c?"T":"")+(_?xi+_+"H":"")+(g?xi+g+"M":"")+(c?xi+E+"S":"")):"P0D"}var De=Lo.prototype; -//! moment.js -return De.isValid=function Kn(){return this._isValid},De.abs=function tp(){var c=this._data;return this._milliseconds=ki(this._milliseconds),this._days=ki(this._days),this._months=ki(this._months),c.milliseconds=ki(c.milliseconds),c.seconds=ki(c.seconds),c.minutes=ki(c.minutes),c.hours=ki(c.hours),c.months=ki(c.months),c.years=ki(c.years),this},De.add=function np(c,d){return Vu(this,c,d,1)},De.subtract=function qs(c,d){return Vu(this,c,d,-1)},De.as=function ip(c){if(!this.isValid())return NaN;var d,h,g=this._milliseconds;if("month"===(c=Pn(c))||"quarter"===c||"year"===c)switch(d=this._days+g/864e5,h=this._months+Js(d),c){case"month":return h;case"quarter":return h/3;case"year":return h/12}else switch(d=this._days+Math.round(Qs(this._months)),c){case"week":return d/7+g/6048e5;case"day":return d+g/864e5;case"hour":return 24*d+g/36e5;case"minute":return 1440*d+g/6e4;case"second":return 86400*d+g/1e3;case"millisecond":return Math.floor(864e5*d)+g;default:throw new Error("Unknown unit "+c)}},De.asMilliseconds=rp,De.asSeconds=op,De.asMinutes=Uo,De.asHours=Tl,De.asDays=sp,De.asWeeks=ap,De.asMonths=ly,De.asQuarters=cy,De.asYears=Xs,De.valueOf=function ir(){return this.isValid()?this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*he(this._months/12):NaN},De._bubble=function Zs(){var _,b,E,K,ce,c=this._milliseconds,d=this._days,h=this._months,g=this._data;return c>=0&&d>=0&&h>=0||c<=0&&d<=0&&h<=0||(c+=864e5*$o(Qs(h)+d),d=0,h=0),g.milliseconds=c%1e3,_=zn(c/1e3),g.seconds=_%60,b=zn(_/60),g.minutes=b%60,E=zn(b/60),g.hours=E%24,d+=zn(E/24),h+=ce=zn(Js(d)),d-=$o(Qs(ce)),K=zn(h/12),h%=12,g.days=d,g.months=h,g.years=K,this},De.clone=function Bu(){return li(this)},De.get=function Hu(c){return c=Pn(c),this.isValid()?this[c+"s"]():NaN},De.milliseconds=ju,De.seconds=$u,De.minutes=oo,De.hours=lp,De.days=so,De.weeks=function uy(){return zn(this.days()/7)},De.months=Il,De.years=ea,De.humanize=function Al(c,d){if(!this.isValid())return this.localeData().invalidDate();var _,b,h=!1,g=Ir;return"object"==typeof c&&(d=c,c=!1),"boolean"==typeof c&&(h=c),"object"==typeof d&&(g=Object.assign({},Ir,d),null!=d.s&&null==d.ss&&(g.ss=d.s-1)),b=function hi(c,d,h,g){var _=li(c).abs(),b=fi(_.as("s")),E=fi(_.as("m")),K=fi(_.as("h")),ce=fi(_.as("d")),Fe=fi(_.as("M")),vt=fi(_.as("w")),xi=fi(_.as("y")),nt=b<=h.ss&&["s",b]||b0,nt[4]=g,cp.apply(null,nt)}(this,!h,g,_=this.localeData()),h&&(b=_.pastFuture(+this,b)),_.postformat(b)},De.toISOString=Ar,De.toString=Ar,De.toJSON=Ar,De.locale=Ws,De.localeData=Hh,De.toIsoString=Jt("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",Ar),De.lang=Eu,Y("X",0,0,"unix"),Y("x",0,0,"valueOf"),$("x",ut),$("X",/[+-]?\d+(\.\d{1,3})?/),Se("X",function(c,d,h){h._d=new Date(1e3*parseFloat(c))}),Se("x",function(c,d,h){h._d=new Date(he(c))}),V.version="2.29.4",function qa(c){ye=c}(Re),V.fn=R,V.min=function dl(){return Sr("isBefore",[].slice.call(arguments,0))},V.max=function Mr(){return Sr("isAfter",[].slice.call(arguments,0))},V.now=function(){return Date.now?Date.now():+new Date},V.utc=ii,V.unix=function Pu(c){return Re(1e3*c)},V.months=function on(c,d){return Lu(c,d,"months")},V.isDate=Ji,V.locale=Cr,V.invalid=mr,V.duration=li,V.isMoment=Wn,V.weekdays=function st(c,d,h){return El(c,d,h,"weekdays")},V.parseZone=function Fu(){return Re.apply(null,arguments).parseZone()},V.localeData=jn,V.isDuration=Pe,V.monthsShort=function nr(c,d){return Lu(c,d,"monthsShort")},V.weekdaysMin=function ep(c,d,h){return El(c,d,h,"weekdaysMin")},V.defineLocale=Xi,V.updateLocale=function Ie(c,d){if(null!=d){var h,g,_=ll;null!=Xe[c]&&null!=Xe[c].parentLocale?Xe[c].set(Rn(Xe[c]._config,d)):(null!=(g=cl(c))&&(_=g._config),d=Rn(_,d),null==g&&(d.abbr=c),(h=new Xa(d)).parentLocale=Xe[c],Xe[c]=h),Cr(c)}else null!=Xe[c]&&(null!=Xe[c].parentLocale?(Xe[c]=Xe[c].parentLocale,c===Cr()&&Cr(c)):null!=Xe[c]&&delete Xe[c]);return Xe[c]},V.locales=function ul(){return Cs(Xe)},V.weekdaysShort=function Xh(c,d,h){return El(c,d,h,"weekdaysShort")},V.normalizeUnits=Pn,V.relativeTimeRounding=function up(c){return void 0===c?fi:"function"==typeof c&&(fi=c,!0)},V.relativeTimeThreshold=function Go(c,d){return void 0!==Ir[c]&&(void 0===d?Ir[c]:(Ir[c]=d,"s"===c&&(Ir.ss=d-1),!0))},V.calendarFormat=function wu(c,d){var h=c.diff(d,"days",!0);return h<-6?"sameElse":h<-1?"lastWeek":h<0?"lastDay":h<1?"sameDay":h<2?"nextDay":h<7?"nextWeek":"sameElse"},V.prototype=R,V.HTML5_FMT={DATETIME_LOCAL:"YYYY-MM-DDTHH:mm",DATETIME_LOCAL_SECONDS:"YYYY-MM-DDTHH:mm:ss",DATETIME_LOCAL_MS:"YYYY-MM-DDTHH:mm:ss.SSS",DATE:"YYYY-MM-DD",TIME:"HH:mm",TIME_SECONDS:"HH:mm:ss",TIME_MS:"HH:mm:ss.SSS",WEEK:"GGGG-[W]WW",MONTH:"YYYY-MM"},V}()}},gr=>{gr(gr.s=381)}]); \ No newline at end of file +(self.webpackChunkdashboard=self.webpackChunkdashboard||[]).push([[179],{631:(hr,lh,Xc)=>{"use strict";function be(e){return"function"==typeof e}function V(e){const t=e(i=>{Error.call(i),i.stack=(new Error).stack});return t.prototype=Object.create(Error.prototype),t.prototype.constructor=t,t}const Ja=V(e=>function(t){e(this),this.message=t?`${t.length} errors occurred during unsubscription:\n${t.map((i,r)=>`${r+1}) ${i.toString()}`).join("\n ")}`:"",this.name="UnsubscriptionError",this.errors=t});function dn(e,n){if(e){const t=e.indexOf(n);0<=t&&e.splice(t,1)}}class _t{constructor(n){this.initialTeardown=n,this.closed=!1,this._parentage=null,this._finalizers=null}unsubscribe(){let n;if(!this.closed){this.closed=!0;const{_parentage:t}=this;if(t)if(this._parentage=null,Array.isArray(t))for(const o of t)o.remove(this);else t.remove(this);const{initialTeardown:i}=this;if(be(i))try{i()}catch(o){n=o instanceof Ja?o.errors:[o]}const{_finalizers:r}=this;if(r){this._finalizers=null;for(const o of r)try{qt(o)}catch(s){n=n??[],s instanceof Ja?n=[...n,...s.errors]:n.push(s)}}if(n)throw new Ja(n)}}add(n){var t;if(n&&n!==this)if(this.closed)qt(n);else{if(n instanceof _t){if(n.closed||n._hasParent(this))return;n._addParent(this)}(this._finalizers=null!==(t=this._finalizers)&&void 0!==t?t:[]).push(n)}}_hasParent(n){const{_parentage:t}=this;return t===n||Array.isArray(t)&&t.includes(n)}_addParent(n){const{_parentage:t}=this;this._parentage=Array.isArray(t)?(t.push(n),t):t?[t,n]:n}_removeParent(n){const{_parentage:t}=this;t===n?this._parentage=null:Array.isArray(t)&&dn(t,n)}remove(n){const{_finalizers:t}=this;t&&dn(t,n),n instanceof _t&&n._removeParent(this)}}_t.EMPTY=(()=>{const e=new _t;return e.closed=!0,e})();const we=_t.EMPTY;function ws(e){return e instanceof _t||e&&"closed"in e&&be(e.remove)&&be(e.add)&&be(e.unsubscribe)}function qt(e){be(e)?e():e.unsubscribe()}const Jt={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1},zi={setTimeout(e,n,...t){const{delegate:i}=zi;return i?.setTimeout?i.setTimeout(e,n,...t):setTimeout(e,n,...t)},clearTimeout(e){const{delegate:n}=zi;return(n?.clearTimeout||clearTimeout)(e)},delegate:void 0};function Za(e){zi.setTimeout(()=>{const{onUnhandledError:n}=Jt;if(!n)throw e;n(e)})}function Cn(){}const ni=Mo("C",void 0,void 0);function Mo(e,n,t){return{kind:e,value:n,error:t}}let _i=null;function pr(e){if(Jt.useDeprecatedSynchronousErrorHandling){const n=!_i;if(n&&(_i={errorThrown:!1,error:null}),e(),n){const{errorThrown:t,error:i}=_i;if(_i=null,t)throw i}}else e()}class To extends _t{constructor(n){super(),this.isStopped=!1,n?(this.destination=n,ws(n)&&n.add(this)):this.destination=ii}static create(n,t,i){return new mr(n,t,i)}next(n){this.isStopped?Ss(function le(e){return Mo("N",e,void 0)}(n),this):this._next(n)}error(n){this.isStopped?Ss(function ch(e){return Mo("E",void 0,e)}(n),this):(this.isStopped=!0,this._error(n))}complete(){this.isStopped?Ss(ni,this):(this.isStopped=!0,this._complete())}unsubscribe(){this.closed||(this.isStopped=!0,super.unsubscribe(),this.destination=null)}_next(n){this.destination.next(n)}_error(n){try{this.destination.error(n)}finally{this.unsubscribe()}}_complete(){try{this.destination.complete()}finally{this.unsubscribe()}}}const Qa=Function.prototype.bind;function gr(e,n){return Qa.call(e,n)}class Wn{constructor(n){this.partialObserver=n}next(n){const{partialObserver:t}=this;if(t.next)try{t.next(n)}catch(i){Zt(i)}}error(n){const{partialObserver:t}=this;if(t.error)try{t.error(n)}catch(i){Zt(i)}else Zt(n)}complete(){const{partialObserver:n}=this;if(n.complete)try{n.complete()}catch(t){Zt(t)}}}class mr extends To{constructor(n,t,i){let r;if(super(),be(n)||!n)r={next:n??void 0,error:t??void 0,complete:i??void 0};else{let o;this&&Jt.useDeprecatedNextContext?(o=Object.create(n),o.unsubscribe=()=>this.unsubscribe(),r={next:n.next&&gr(n.next,o),error:n.error&&gr(n.error,o),complete:n.complete&&gr(n.complete,o)}):r=n}this.destination=new Wn(r)}}function Zt(e){Jt.useDeprecatedSynchronousErrorHandling?function eu(e){Jt.useDeprecatedSynchronousErrorHandling&&_i&&(_i.errorThrown=!0,_i.error=e)}(e):Za(e)}function Ss(e,n){const{onStoppedNotification:t}=Jt;t&&zi.setTimeout(()=>t(e,n))}const ii={closed:!0,next:Cn,error:function tu(e){throw e},complete:Cn},Xa="function"==typeof Symbol&&Symbol.observable||"@@observable";function Pn(e){return e}function Es(e){return 0===e.length?Pn:1===e.length?e[0]:function(t){return e.reduce((i,r)=>r(i),t)}}let Ve=(()=>{class e{constructor(t){t&&(this._subscribe=t)}lift(t){const i=new e;return i.source=this,i.operator=t,i}subscribe(t,i,r){const o=function tl(e){return e&&e instanceof To||function ri(e){return e&&be(e.next)&&be(e.error)&&be(e.complete)}(e)&&ws(e)}(t)?t:new mr(t,i,r);return pr(()=>{const{operator:s,source:a}=this;o.add(s?s.call(o,a):a?this._subscribe(o):this._trySubscribe(o))}),o}_trySubscribe(t){try{return this._subscribe(t)}catch(i){t.error(i)}}forEach(t,i){return new(i=nu(i))((r,o)=>{const s=new mr({next:a=>{try{t(a)}catch(l){o(l),s.unsubscribe()}},error:o,complete:r});this.subscribe(s)})}_subscribe(t){var i;return null===(i=this.source)||void 0===i?void 0:i.subscribe(t)}[Xa](){return this}pipe(...t){return Es(t)(this)}toPromise(t){return new(t=nu(t))((i,r)=>{let o;this.subscribe(s=>o=s,s=>r(s),()=>i(o))})}}return e.create=n=>new e(n),e})();function nu(e){var n;return null!==(n=e??Jt.Promise)&&void 0!==n?n:Promise}const Ms=V(e=>function(){e(this),this.name="ObjectUnsubscribedError",this.message="object unsubscribed"});let je=(()=>{class e extends Ve{constructor(){super(),this.closed=!1,this.currentObservers=null,this.observers=[],this.isStopped=!1,this.hasError=!1,this.thrownError=null}lift(t){const i=new _r(this,this);return i.operator=t,i}_throwIfClosed(){if(this.closed)throw new Ms}next(t){pr(()=>{if(this._throwIfClosed(),!this.isStopped){this.currentObservers||(this.currentObservers=Array.from(this.observers));for(const i of this.currentObservers)i.next(t)}})}error(t){pr(()=>{if(this._throwIfClosed(),!this.isStopped){this.hasError=this.isStopped=!0,this.thrownError=t;const{observers:i}=this;for(;i.length;)i.shift().error(t)}})}complete(){pr(()=>{if(this._throwIfClosed(),!this.isStopped){this.isStopped=!0;const{observers:t}=this;for(;t.length;)t.shift().complete()}})}unsubscribe(){this.isStopped=this.closed=!0,this.observers=this.currentObservers=null}get observed(){var t;return(null===(t=this.observers)||void 0===t?void 0:t.length)>0}_trySubscribe(t){return this._throwIfClosed(),super._trySubscribe(t)}_subscribe(t){return this._throwIfClosed(),this._checkFinalizedStatuses(t),this._innerSubscribe(t)}_innerSubscribe(t){const{hasError:i,isStopped:r,observers:o}=this;return i||r?we:(this.currentObservers=null,o.push(t),new _t(()=>{this.currentObservers=null,dn(o,t)}))}_checkFinalizedStatuses(t){const{hasError:i,thrownError:r,isStopped:o}=this;i?t.error(r):o&&t.complete()}asObservable(){const t=new Ve;return t.source=this,t}}return e.create=(n,t)=>new _r(n,t),e})();class _r extends je{constructor(n,t){super(),this.destination=n,this.source=t}next(n){var t,i;null===(i=null===(t=this.destination)||void 0===t?void 0:t.next)||void 0===i||i.call(t,n)}error(n){var t,i;null===(i=null===(t=this.destination)||void 0===t?void 0:t.error)||void 0===i||i.call(t,n)}complete(){var n,t;null===(t=null===(n=this.destination)||void 0===n?void 0:n.complete)||void 0===t||t.call(n)}_subscribe(n){var t,i;return null!==(i=null===(t=this.source)||void 0===t?void 0:t.subscribe(n))&&void 0!==i?i:we}}function q(e){return be(e?.lift)}function qe(e){return n=>{if(q(n))return n.lift(function(t){try{return e(t,this)}catch(i){this.error(i)}});throw new TypeError("Unable to lift unknown Observable type")}}function Oe(e,n,t,i,r){return new Ts(e,n,t,i,r)}class Ts extends To{constructor(n,t,i,r,o,s){super(n),this.onFinalize=o,this.shouldUnsubscribe=s,this._next=t?function(a){try{t(a)}catch(l){n.error(l)}}:super._next,this._error=r?function(a){try{r(a)}catch(l){n.error(l)}finally{this.unsubscribe()}}:super._error,this._complete=i?function(){try{i()}catch(a){n.error(a)}finally{this.unsubscribe()}}:super._complete}unsubscribe(){var n;if(!this.shouldUnsubscribe||this.shouldUnsubscribe()){const{closed:t}=this;super.unsubscribe(),!t&&(null===(n=this.onFinalize)||void 0===n||n.call(this))}}}function ie(e,n){return qe((t,i)=>{let r=0;t.subscribe(Oe(i,o=>{i.next(e.call(n,o,r++))}))})}function wn(e){return this instanceof wn?(this.v=e,this):new wn(e)}function Io(e,n,t){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var r,i=t.apply(e,n||[]),o=[];return r={},s("next"),s("throw"),s("return"),r[Symbol.asyncIterator]=function(){return this},r;function s(m){i[m]&&(r[m]=function(v){return new Promise(function(y,D){o.push([m,v,y,D])>1||a(m,v)})})}function a(m,v){try{!function l(m){m.value instanceof wn?Promise.resolve(m.value.v).then(u,f):p(o[0][2],m)}(i[m](v))}catch(y){p(o[0][3],y)}}function u(m){a("next",m)}function f(m){a("throw",m)}function p(m,v){m(v),o.shift(),o.length&&a(o[0][0],o[0][1])}}function su(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t,n=e[Symbol.asyncIterator];return n?n.call(e):(e=function St(e){var n="function"==typeof Symbol&&Symbol.iterator,t=n&&e[n],i=0;if(t)return t.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&i>=e.length&&(e=void 0),{value:e&&e[i++],done:!e}}};throw new TypeError(n?"Object is not iterable.":"Symbol.iterator is not defined.")}(e),t={},i("next"),i("throw"),i("return"),t[Symbol.asyncIterator]=function(){return this},t);function i(o){t[o]=e[o]&&function(s){return new Promise(function(a,l){!function r(o,s,a,l){Promise.resolve(l).then(function(u){o({value:u,done:a})},s)}(a,l,(s=e[o](s)).done,s.value)})}}}"function"==typeof SuppressedError&&SuppressedError;const Yr=e=>e&&"number"==typeof e.length&&"function"!=typeof e;function vr(e){return be(e?.then)}function Oo(e){return be(e[Xa])}function fu(e){return Symbol.asyncIterator&&be(e?.[Symbol.asyncIterator])}function ko(e){return new TypeError(`You provided ${null!==e&&"object"==typeof e?"an invalid object":`'${e}'`} where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.`)}const qr=function gh(){return"function"==typeof Symbol&&Symbol.iterator?Symbol.iterator:"@@iterator"}();function Ro(e){return be(e?.[qr])}function $(e){return Io(this,arguments,function*(){const t=e.getReader();try{for(;;){const{value:i,done:r}=yield wn(t.read());if(r)return yield wn(void 0);yield yield wn(i)}}finally{t.releaseLock()}})}function hu(e){return be(e?.getReader)}function Et(e){if(e instanceof Ve)return e;if(null!=e){if(Oo(e))return function En(e){return new Ve(n=>{const t=e[Xa]();if(be(t.subscribe))return t.subscribe(n);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}(e);if(Yr(e))return function ol(e){return new Ve(n=>{for(let t=0;t{e.then(t=>{n.closed||(n.next(t),n.complete())},t=>n.error(t)).then(null,Za)})}(e);if(fu(e))return pu(e);if(Ro(e))return function xo(e){return new Ve(n=>{for(const t of e)if(n.next(t),n.closed)return;n.complete()})}(e);if(hu(e))return function $t(e){return pu($(e))}(e)}throw ko(e)}function pu(e){return new Ve(n=>{(function vi(e,n){var t,i,r,o;return function xt(e,n,t,i){return new(t||(t=Promise))(function(o,s){function a(f){try{u(i.next(f))}catch(p){s(p)}}function l(f){try{u(i.throw(f))}catch(p){s(p)}}function u(f){f.done?o(f.value):function r(o){return o instanceof t?o:new t(function(s){s(o)})}(f.value).then(a,l)}u((i=i.apply(e,n||[])).next())})}(this,void 0,void 0,function*(){try{for(t=su(e);!(i=yield t.next()).done;)if(n.next(i.value),n.closed)return}catch(s){r={error:s}}finally{try{i&&!i.done&&(o=t.return)&&(yield o.call(t))}finally{if(r)throw r.error}}n.complete()})})(e,n).catch(t=>n.error(t))})}function Mt(e,n,t,i=0,r=!1){const o=n.schedule(function(){t(),r?e.add(this.schedule(null,i)):this.unsubscribe()},i);if(e.add(o),!r)return o}function ke(e,n,t=1/0){return be(n)?ke((i,r)=>ie((o,s)=>n(i,o,r,s))(Et(e(i,r))),t):("number"==typeof n&&(t=n),qe((i,r)=>function vt(e,n,t,i,r,o,s,a){const l=[];let u=0,f=0,p=!1;const m=()=>{p&&!l.length&&!u&&n.complete()},v=D=>u{o&&n.next(D),u++;let w=!1;Et(t(D,f++)).subscribe(Oe(n,S=>{r?.(S),o?v(S):n.next(S)},()=>{w=!0},void 0,()=>{if(w)try{for(u--;l.length&&uy(S)):y(S)}m()}catch(S){n.error(S)}}))};return e.subscribe(Oe(n,v,()=>{p=!0,m()})),()=>{a?.()}}(i,r,e,t)))}function fn(e=1/0){return ke(Pn,e)}const Ft=new Ve(e=>e.complete());function gu(e){return e&&be(e.schedule)}function tt(e){return e[e.length-1]}function yr(e){return be(tt(e))?e.pop():void 0}function Fo(e){return gu(tt(e))?e.pop():void 0}function sl(e,n=0){return qe((t,i)=>{t.subscribe(Oe(i,r=>Mt(i,e,()=>i.next(r),n),()=>Mt(i,e,()=>i.complete(),n),r=>Mt(i,e,()=>i.error(r),n)))})}function _u(e,n=0){return qe((t,i)=>{i.add(e.schedule(()=>t.subscribe(i),n))})}function vu(e,n){if(!e)throw new Error("Iterable cannot be null");return new Ve(t=>{Mt(t,n,()=>{const i=e[Symbol.asyncIterator]();Mt(t,n,()=>{i.next().then(r=>{r.done?t.complete():t.next(r.value)})},0,!0)})})}function dt(e,n){return n?function bu(e,n){if(null!=e){if(Oo(e))return function _h(e,n){return Et(e).pipe(_u(n),sl(n))}(e,n);if(Yr(e))return function yh(e,n){return new Ve(t=>{let i=0;return n.schedule(function(){i===e.length?t.complete():(t.next(e[i++]),t.closed||this.schedule())})})}(e,n);if(vr(e))return function vh(e,n){return Et(e).pipe(_u(n),sl(n))}(e,n);if(fu(e))return vu(e,n);if(Ro(e))return function bh(e,n){return new Ve(t=>{let i;return Mt(t,n,()=>{i=e[qr](),Mt(t,n,()=>{let r,o;try{({value:r,done:o}=i.next())}catch(s){return void t.error(s)}o?t.complete():t.next(r)},0,!0)}),()=>be(i?.return)&&i.return()})}(e,n);if(hu(e))return function yu(e,n){return vu($(e),n)}(e,n)}throw ko(e)}(e,n):Et(e)}function Os(e,n,...t){if(!0===n)return void e();if(!1===n)return;const i=new mr({next:()=>{i.unsubscribe(),e()}});return n(...t).subscribe(i)}function Ne(e){for(let n in e)if(e[n]===Ne)return n;throw Error("Could not find renamed property on target object.")}function ks(e,n){for(const t in n)n.hasOwnProperty(t)&&!e.hasOwnProperty(t)&&(e[t]=n[t])}function He(e){if("string"==typeof e)return e;if(Array.isArray(e))return"["+e.map(He).join(", ")+"]";if(null==e)return""+e;if(e.overriddenName)return`${e.overriddenName}`;if(e.name)return`${e.name}`;const n=e.toString();if(null==n)return""+n;const t=n.indexOf("\n");return-1===t?n:n.substring(0,t)}function al(e,n){return null==e||""===e?null===n?"":n:null==n||""===n?e:e+" "+n}const Po=Ne({__forward_ref__:Ne});function De(e){return e.__forward_ref__=De,e.toString=function(){return He(this())},e}function te(e){return br(e)?e():e}function br(e){return"function"==typeof e&&e.hasOwnProperty(Po)&&e.__forward_ref__===De}class F extends Error{constructor(n,t){super(function Rs(e,n){return`NG0${Math.abs(e)}${n?": "+n.trim():""}`}(n,t)),this.code=n}}function se(e){return"string"==typeof e?e:null==e?"":String(e)}function xs(e,n){throw new F(-201,!1)}function Mn(e,n){null==e&&function Ie(e,n,t,i){throw new Error(`ASSERTION ERROR: ${e}`+(null==i?"":` [Expected=> ${t} ${i} ${n} <=Actual]`))}(n,e,null,"!=")}function U(e){return{token:e.token,providedIn:e.providedIn||null,factory:e.factory,value:void 0}}function Me(e){return{providers:e.providers||[],imports:e.imports||[]}}function Lo(e){return Su(e,Vo)||Su(e,Jr)}function Su(e,n){return e.hasOwnProperty(n)?e[n]:null}function Eu(e){return e&&(e.hasOwnProperty($e)||e.hasOwnProperty(Ho))?e[$e]:null}const Vo=Ne({\u0275prov:Ne}),$e=Ne({\u0275inj:Ne}),Jr=Ne({ngInjectableDef:Ne}),Ho=Ne({ngInjectorDef:Ne});var ee=(()=>((ee=ee||{})[ee.Default=0]="Default",ee[ee.Host=1]="Host",ee[ee.Self=2]="Self",ee[ee.SkipSelf=4]="SkipSelf",ee[ee.Optional=8]="Optional",ee))();let Fs;function Hn(e){const n=Fs;return Fs=e,n}function Bo(e,n,t){const i=Lo(e);return i&&"root"==i.providedIn?void 0===i.value?i.value=i.factory():i.value:t&ee.Optional?null:void 0!==n?n:void xs(He(e))}function oi(e){return{toString:e}.toString()}var Kn=(()=>((Kn=Kn||{})[Kn.OnPush=0]="OnPush",Kn[Kn.Default=1]="Default",Kn))(),Bn=(()=>{return(e=Bn||(Bn={}))[e.Emulated=0]="Emulated",e[e.None=2]="None",e[e.ShadowDom=3]="ShadowDom",Bn;var e})();const Ue=(()=>typeof globalThis<"u"&&globalThis||typeof global<"u"&&global||typeof window<"u"&&window||typeof self<"u"&&typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope&&self)(),bi={},Se=[],Ps=Ne({\u0275cmp:Ne}),ll=Ne({\u0275dir:Ne}),cl=Ne({\u0275pipe:Ne}),ul=Ne({\u0275mod:Ne}),Di=Ne({\u0275fac:Ne}),jo=Ne({__NG_ELEMENT_ID__:Ne});let Ih=0;function lt(e){return oi(()=>{const t=!0===e.standalone,i={},r={type:e.type,providersResolver:null,decls:e.decls,vars:e.vars,factory:null,template:e.template||null,consts:e.consts||null,ngContentSelectors:e.ngContentSelectors,hostBindings:e.hostBindings||null,hostVars:e.hostVars||0,hostAttrs:e.hostAttrs||null,contentQueries:e.contentQueries||null,declaredInputs:i,inputs:null,outputs:null,exportAs:e.exportAs||null,onPush:e.changeDetection===Kn.OnPush,directiveDefs:null,pipeDefs:null,standalone:t,dependencies:t&&e.dependencies||null,getStandaloneInjector:null,selectors:e.selectors||Se,viewQuery:e.viewQuery||null,features:e.features||null,data:e.data||{},encapsulation:e.encapsulation||Bn.Emulated,id:"c"+Ih++,styles:e.styles||Se,_:null,setInput:null,schemas:e.schemas||null,tView:null},o=e.dependencies,s=e.features;return r.inputs=Ls(e.inputs,i),r.outputs=Ls(e.outputs),s&&s.forEach(a=>a(r)),r.directiveDefs=o?()=>("function"==typeof o?o():o).map(dl).filter(Mu):null,r.pipeDefs=o?()=>("function"==typeof o?o():o).map(en).filter(Mu):null,r})}function dl(e){return Re(e)||Xt(e)}function Mu(e){return null!==e}function ge(e){return oi(()=>({type:e.type,bootstrap:e.bootstrap||Se,declarations:e.declarations||Se,imports:e.imports||Se,exports:e.exports||Se,transitiveCompileScopes:null,schemas:e.schemas||null,id:e.id||null}))}function Ls(e,n){if(null==e)return bi;const t={};for(const i in e)if(e.hasOwnProperty(i)){let r=e[i],o=r;Array.isArray(r)&&(o=r[1],r=r[0]),t[r]=i,n&&(n[r]=o)}return t}const B=lt;function Tt(e){return{type:e.type,name:e.name,factory:null,pure:!1!==e.pure,standalone:!0===e.standalone,onDestroy:e.type.prototype.ngOnDestroy||null}}function Re(e){return e[Ps]||null}function Xt(e){return e[ll]||null}function en(e){return e[cl]||null}function hn(e,n){const t=e[ul]||null;if(!t&&!0===n)throw new Error(`Type ${He(e)} does not have '\u0275mod' property.`);return t}function tn(e){return Array.isArray(e)&&"object"==typeof e[1]}function zn(e){return Array.isArray(e)&&!0===e[1]}function hl(e){return 0!=(8&e.flags)}function pn(e){return 2==(2&e.flags)}function si(e){return 1==(1&e.flags)}function $n(e){return null!==e.template}function Ph(e){return 0!=(256&e[2])}function Sr(e,n){return e.hasOwnProperty(Di)?e[Di]:null}class Bh{constructor(n,t,i){this.previousValue=n,this.currentValue=t,this.firstChange=i}isFirstChange(){return this.firstChange}}function Wt(){return Au}function Au(e){return e.type.prototype.ngOnChanges&&(e.setInput=$h),jh}function jh(){const e=_l(this),n=e?.current;if(n){const t=e.previous;if(t===bi)e.previous=n;else for(let i in n)t[i]=n[i];e.current=null,this.ngOnChanges(n)}}function $h(e,n,t,i){const r=_l(e)||function Iu(e,n){return e[ml]=n}(e,{previous:bi,current:null}),o=r.current||(r.current={}),s=r.previous,a=this.declaredInputs[t],l=s[a];o[a]=new Bh(l&&l.currentValue,n,s===bi),e[i]=n}Wt.ngInherit=!0;const ml="__ngSimpleChanges__";function _l(e){return e[ml]||null}function ft(e){for(;Array.isArray(e);)e=e[0];return e}function Gs(e,n){return ft(n[e])}function An(e,n){return ft(n[e.index])}function vl(e,n){return e.data[n]}function ro(e,n){return e[n]}function In(e,n){const t=n[e];return tn(t)?t:t[0]}function Ws(e){return 64==(64&e[2])}function Qi(e,n){return null==n?null:e[n]}function ku(e){e[18]=0}function yl(e,n){e[5]+=n;let t=e,i=e[3];for(;null!==i&&(1===n&&1===t[5]||-1===n&&0===t[5]);)i[5]+=n,t=i,i=i[3]}const oe={lFrame:Hu(null),bindingsEnabled:!0};function Ks(){return oe.bindingsEnabled}function k(){return oe.lFrame.lView}function me(){return oe.lFrame.tView}function nt(e){return oe.lFrame.contextLView=e,e[8]}function ht(e){return oe.lFrame.contextLView=null,e}function yt(){let e=xu();for(;null!==e&&64===e.type;)e=e.parent;return e}function xu(){return oe.lFrame.currentTNode}function ai(e,n){const t=oe.lFrame;t.currentTNode=e,t.isParent=n}function bl(){return oe.lFrame.isParent}function zs(){oe.lFrame.isParent=!1}function rn(){const e=oe.lFrame;let n=e.bindingRootIndex;return-1===n&&(n=e.bindingRootIndex=e.tView.bindingStartIndex),n}function Er(){return oe.lFrame.bindingIndex++}function Ti(e){const n=oe.lFrame,t=n.bindingIndex;return n.bindingIndex=n.bindingIndex+e,t}function x(e,n){const t=oe.lFrame;t.bindingIndex=t.bindingRootIndex=e,Dl(n)}function Dl(e){oe.lFrame.currentDirectiveIndex=e}function Ee(){return oe.lFrame.currentQueryIndex}function oo(e){oe.lFrame.currentQueryIndex=e}function Lu(e){const n=e[1];return 2===n.type?n.declTNode:1===n.type?e[6]:null}function qs(e,n,t){if(t&ee.SkipSelf){let r=n,o=e;for(;!(r=r.parent,null!==r||t&ee.Host||(r=Lu(o),null===r||(o=o[15],10&r.type))););if(null===r)return!1;n=r,e=o}const i=oe.lFrame=Vu();return i.currentTNode=n,i.lView=e,!0}function Cl(e){const n=Vu(),t=e[1];oe.lFrame=n,n.currentTNode=t.firstChild,n.lView=e,n.tView=t,n.contextLView=e,n.bindingIndex=t.bindingStartIndex,n.inI18n=!1}function Vu(){const e=oe.lFrame,n=null===e?null:e.child;return null===n?Hu(e):n}function Hu(e){const n={currentTNode:null,isParent:!0,lView:null,tView:null,selectedIndex:-1,contextLView:null,elementDepthCount:0,currentNamespace:null,currentDirectiveIndex:-1,bindingRootIndex:-1,bindingIndex:-1,currentQueryIndex:0,parent:e,child:null,inI18n:!1};return null!==e&&(e.child=n),n}function Bu(){const e=oe.lFrame;return oe.lFrame=e.parent,e.currentTNode=null,e.lView=null,e}const ju=Bu;function Yn(){const e=Bu();e.isParent=!0,e.tView=null,e.selectedIndex=-1,e.contextLView=null,e.elementDepthCount=0,e.currentDirectiveIndex=-1,e.currentNamespace=null,e.bindingRootIndex=-1,e.bindingIndex=-1,e.currentQueryIndex=0}function on(){return oe.lFrame.selectedIndex}function Xi(e){oe.lFrame.selectedIndex=e}function Ze(){const e=oe.lFrame;return vl(e.tView,e.selectedIndex)}function Js(e,n){for(let t=n.directiveStart,i=n.directiveEnd;t=i)break}else n[l]<0&&(e[18]+=65536),(a>11>16&&(3&e[2])===n){e[2]+=2048;try{o.call(a)}finally{}}}else try{o.call(a)}finally{}}class Wo{constructor(n,t,i){this.factory=n,this.resolving=!1,this.canSeeViewProviders=t,this.injectImpl=i}}function Xs(e,n,t){let i=0;for(;in){s=o-1;break}}}for(;o>16}(e),i=n;for(;t>0;)i=i[15],t--;return i}let El=!0;function ta(e){const n=El;return El=e,n}let Ce=0;const c={};function h(e,n){const t=_(e,n);if(-1!==t)return t;const i=n[1];i.firstCreatePass&&(e.injectorIndex=n.length,g(i.data,e),g(n,null),g(i.blueprint,null));const r=b(e,n),o=e.injectorIndex;if(Mr(r)){const s=so(r),a=ao(r,n),l=a[1].data;for(let u=0;u<8;u++)n[o+u]=a[s+u]|l[s+u]}return n[o+8]=r,o}function g(e,n){e.push(0,0,0,0,0,0,0,0,n)}function _(e,n){return-1===e.injectorIndex||e.parent&&e.parent.injectorIndex===e.injectorIndex||null===n[e.injectorIndex+8]?-1:e.injectorIndex}function b(e,n){if(e.parent&&-1!==e.parent.injectorIndex)return e.parent.injectorIndex;let t=0,i=null,r=n;for(;null!==r;){if(i=yy(r),null===i)return-1;if(t++,r=r[15],-1!==i.injectorIndex)return i.injectorIndex|t<<16}return-1}function T(e,n,t){!function d(e,n,t){let i;"string"==typeof t?i=t.charCodeAt(0)||0:t.hasOwnProperty(jo)&&(i=t[jo]),null==i&&(i=t[jo]=Ce++);const r=255&i;n.data[e+(r>>5)]|=1<=0?255&n:TT:n}(t);if("function"==typeof o){if(!qs(n,e,i))return i&ee.Host?ue(r,0,i):xe(n,t,i,r);try{const s=o(i);if(null!=s||i&ee.Optional)return s;xs()}finally{ju()}}else if("number"==typeof o){let s=null,a=_(e,n),l=-1,u=i&ee.Host?n[16][6]:null;for((-1===a||i&ee.SkipSelf)&&(l=-1===a?b(e,n):n[a+8],-1!==l&&vy(i,!1)?(s=n[1],a=so(l),n=ao(l,n)):a=-1);-1!==a;){const f=n[1];if(_y(o,a,f.data)){const p=tr(a,n,t,s,i,u);if(p!==c)return p}l=n[a+8],-1!==l&&vy(i,n[1].data[a+8]===u)&&_y(o,a,n)?(s=f,a=so(l),n=ao(l,n)):a=-1}}return r}function tr(e,n,t,i,r,o){const s=n[1],a=s.data[e+8],f=Yu(a,s,t,null==i?pn(a)&&El:i!=s&&0!=(3&a.type),r&ee.Host&&o===a);return null!==f?Ml(n,s,f,a):c}function Yu(e,n,t,i,r){const o=e.providerIndexes,s=n.data,a=1048575&o,l=e.directiveStart,f=o>>20,m=r?a+f:e.directiveEnd;for(let v=i?a:a+f;v=l&&y.type===t)return v}if(r){const v=s[l];if(v&&$n(v)&&v.type===t)return l}return null}function Ml(e,n,t,i){let r=e[t];const o=n.data;if(function ap(e){return e instanceof Wo}(r)){const s=r;s.resolving&&function wh(e,n){const t=n?`. Dependency path: ${n.join(" > ")} > ${e}`:"";throw new F(-200,`Circular dependency in DI detected for ${e}${t}`)}(function Ae(e){return"function"==typeof e?e.name||e.toString():"object"==typeof e&&null!=e&&"function"==typeof e.type?e.type.name||e.type.toString():se(e)}(o[t]));const a=ta(s.canSeeViewProviders);s.resolving=!0;const l=s.injectImpl?Hn(s.injectImpl):null;qs(e,i,ee.Default);try{r=e[t]=s.factory(void 0,o,e,i),n.firstCreatePass&&t>=i.directiveStart&&function Ni(e,n,t){const{ngOnChanges:i,ngOnInit:r,ngDoCheck:o}=n.type.prototype;if(i){const s=Au(n);(t.preOrderHooks||(t.preOrderHooks=[])).push(e,s),(t.preOrderCheckHooks||(t.preOrderCheckHooks=[])).push(e,s)}r&&(t.preOrderHooks||(t.preOrderHooks=[])).push(0-e,r),o&&((t.preOrderHooks||(t.preOrderHooks=[])).push(e,o),(t.preOrderCheckHooks||(t.preOrderCheckHooks=[])).push(e,o))}(t,o[t],n)}finally{null!==l&&Hn(l),ta(a),s.resolving=!1,ju()}}return r}function _y(e,n,t){return!!(t[n+(e>>5)]&1<{const n=e.prototype.constructor,t=n[Di]||fp(n),i=Object.prototype;let r=Object.getPrototypeOf(e.prototype).constructor;for(;r&&r!==i;){const o=r[Di]||fp(r);if(o&&o!==t)return o;r=Object.getPrototypeOf(r)}return o=>new o})}function fp(e){return br(e)?()=>{const n=fp(te(e));return n&&n()}:Sr(e)}function yy(e){const n=e[1],t=n.type;return 2===t?n.declTNode:1===t?e[6]:null}const ra="__parameters__";function sa(e,n,t){return oi(()=>{const i=function hp(e){return function(...t){if(e){const i=e(...t);for(const r in i)this[r]=i[r]}}}(n);function r(...o){if(this instanceof r)return i.apply(this,o),this;const s=new r(...o);return a.annotation=s,a;function a(l,u,f){const p=l.hasOwnProperty(ra)?l[ra]:Object.defineProperty(l,ra,{value:[]})[ra];for(;p.length<=f;)p.push(null);return(p[f]=p[f]||[]).push(s),l}}return t&&(r.prototype=Object.create(t.prototype)),r.prototype.ngMetadataName=e,r.annotationCls=r,r})}class Y{constructor(n,t){this._desc=n,this.ngMetadataName="InjectionToken",this.\u0275prov=void 0,"number"==typeof t?this.__NG_ELEMENT_ID__=t:void 0!==t&&(this.\u0275prov=U({token:this,providedIn:t.providedIn||"root",factory:t.factory}))}get multi(){return this}toString(){return`InjectionToken ${this._desc}`}}function qn(e,n){void 0===n&&(n=e);for(let t=0;tArray.isArray(t)?Nr(t,n):n(t))}function Dy(e,n,t){n>=e.length?e.push(t):e.splice(n,0,t)}function qu(e,n){return n>=e.length-1?e.pop():e.splice(n,1)[0]}function Al(e,n){const t=[];for(let i=0;i=0?e[1|i]=t:(i=~i,function kT(e,n,t,i){let r=e.length;if(r==n)e.push(t,i);else if(1===r)e.push(i,e[0]),e[0]=t;else{for(r--,e.push(e[r-1],e[r]);r>n;)e[r]=e[r-2],r--;e[n]=t,e[n+1]=i}}(e,i,n,t)),i}function gp(e,n){const t=aa(e,n);if(t>=0)return e[1|t]}function aa(e,n){return function Sy(e,n,t){let i=0,r=e.length>>t;for(;r!==i;){const o=i+(r-i>>1),s=e[o<n?r=o:i=o+1}return~(r<((Un=Un||{})[Un.Important=1]="Important",Un[Un.DashCase=2]="DashCase",Un))();const wp=new Map;let aN=0;const Ep="__ngContext__";function mn(e,n){tn(n)?(e[Ep]=n[20],function cN(e){wp.set(e[20],e)}(n)):e[Ep]=n}function Tp(e,n){return undefined(e,n)}function Vl(e){const n=e[3];return zn(n)?n[3]:n}function Np(e){return Ky(e[13])}function Ap(e){return Ky(e[4])}function Ky(e){for(;null!==e&&!zn(e);)e=e[4];return e}function ua(e,n,t,i,r){if(null!=i){let o,s=!1;zn(i)?o=i:tn(i)&&(s=!0,i=i[0]);const a=ft(i);0===e&&null!==t?null==r?Qy(n,t,a):qo(n,t,a,r||null,!0):1===e&&null!==t?qo(n,t,a,r||null,!0):2===e?function Pp(e,n,t){const i=ed(e,n);i&&function ON(e,n,t,i){e.removeChild(n,t,i)}(e,i,n,t)}(n,a,s):3===e&&n.destroyNode(a),null!=o&&function xN(e,n,t,i,r){const o=t[7];o!==ft(t)&&ua(n,e,i,o,r);for(let a=10;a0&&(e[t-1][4]=i[4]);const o=qu(e,10+n);!function wN(e,n){Hl(e,n,n[11],2,null,null),n[0]=null,n[6]=null}(i[1],i);const s=o[19];null!==s&&s.detachView(o[1]),i[3]=null,i[4]=null,i[2]&=-65}return i}function qy(e,n){if(!(128&n[2])){const t=n[11];t.destroyNode&&Hl(e,n,t,3,null,null),function MN(e){let n=e[13];if(!n)return Rp(e[1],e);for(;n;){let t=null;if(tn(n))t=n[13];else{const i=n[10];i&&(t=i)}if(!t){for(;n&&!n[4]&&n!==e;)tn(n)&&Rp(n[1],n),n=n[3];null===n&&(n=e),tn(n)&&Rp(n[1],n),t=n&&n[4]}n=t}}(n)}}function Rp(e,n){if(!(128&n[2])){n[2]&=-65,n[2]|=128,function IN(e,n){let t;if(null!=e&&null!=(t=e.destroyHooks))for(let i=0;i=0?i[r=u]():i[r=-u].unsubscribe(),o+=2}else{const s=i[r=t[o+1]];t[o].call(s)}if(null!==i){for(let o=r+1;o{const s=o;Yp(s,t,[],i)&&(r||(r=[]),r.push(s))}),void 0!==r&&S0(r,t),t}function S0(e,n){for(let t=0;t{n.push(o)})}}function Yp(e,n,t,i){if(!(e=te(e)))return!1;let r=null,o=Eu(e);const s=!o&&Re(e);if(o||s){if(s&&!s.standalone)return!1;r=e}else{const l=e.ngModule;if(o=Eu(l),!o)return!1;r=l}const a=i.has(r);if(s){if(a)return!1;if(i.add(r),s.dependencies){const l="function"==typeof s.dependencies?s.dependencies():s.dependencies;for(const u of l)Yp(u,n,t,i)}}else{if(!o)return!1;{if(null!=o.imports&&!a){let u;i.add(r);try{Nr(o.imports,f=>{Yp(f,n,t,i)&&(u||(u=[]),u.push(f))})}finally{}void 0!==u&&S0(u,n)}if(!a){const u=Sr(r)||(()=>new r);n.push({provide:r,useFactory:u,deps:Se},{provide:D0,useValue:r,multi:!0},{provide:zp,useValue:()=>L(r),multi:!0})}const l=o.providers;null==l||a||Nr(l,f=>{n.push(f)})}}return r!==e&&void 0!==e.providers}const uA=Ne({provide:String,useValue:Ne});function qp(e){return null!==e&&"object"==typeof e&&uA in e}function Zo(e){return"function"==typeof e}const Jp=new Y("Set Injector scope."),sd={},fA={};let Zp;function ad(){return void 0===Zp&&(Zp=new C0),Zp}class co{}class T0 extends co{constructor(n,t,i,r){super(),this.parent=t,this.source=i,this.scopes=r,this.records=new Map,this._ngOnDestroyHooks=new Set,this._onDestroyHooks=[],this._destroyed=!1,Xp(n,s=>this.processProvider(s)),this.records.set(b0,da(void 0,this)),r.has("environment")&&this.records.set(co,da(void 0,this));const o=this.records.get(Jp);null!=o&&"string"==typeof o.value&&this.scopes.add(o.value),this.injectorDefTypes=new Set(this.get(D0.multi,Se,ee.Self))}get destroyed(){return this._destroyed}destroy(){this.assertNotDestroyed(),this._destroyed=!0;try{for(const n of this._ngOnDestroyHooks)n.ngOnDestroy();for(const n of this._onDestroyHooks)n()}finally{this.records.clear(),this._ngOnDestroyHooks.clear(),this.injectorDefTypes.clear(),this._onDestroyHooks.length=0}}onDestroy(n){this._onDestroyHooks.push(n)}runInContext(n){this.assertNotDestroyed();const t=la(this),i=Hn(void 0);try{return n()}finally{la(t),Hn(i)}}get(n,t=Il,i=ee.Default){this.assertNotDestroyed();const r=la(this),o=Hn(void 0);try{if(!(i&ee.SkipSelf)){let a=this.records.get(n);if(void 0===a){const l=function _A(e){return"function"==typeof e||"object"==typeof e&&e instanceof Y}(n)&&Lo(n);a=l&&this.injectableDefInScope(l)?da(Qp(n),sd):null,this.records.set(n,a)}if(null!=a)return this.hydrate(n,a)}return(i&ee.Self?ad():this.parent).get(n,t=i&ee.Optional&&t===Il?null:t)}catch(s){if("NullInjectorError"===s.name){if((s[Zu]=s[Zu]||[]).unshift(He(n)),r)throw s;return function GT(e,n,t,i){const r=e[Zu];throw n[Ey]&&r.unshift(n[Ey]),e.message=function WT(e,n,t,i=null){e=e&&"\n"===e.charAt(0)&&"\u0275"==e.charAt(1)?e.slice(2):e;let r=He(n);if(Array.isArray(n))r=n.map(He).join(" -> ");else if("object"==typeof n){let o=[];for(let s in n)if(n.hasOwnProperty(s)){let a=n[s];o.push(s+":"+("string"==typeof a?JSON.stringify(a):He(a)))}r=`{${o.join(", ")}}`}return`${t}${i?"("+i+")":""}[${r}]: ${e.replace(BT,"\n ")}`}("\n"+e.message,r,t,i),e.ngTokenPath=r,e[Zu]=null,e}(s,n,"R3InjectorError",this.source)}throw s}finally{Hn(o),la(r)}}resolveInjectorInitializers(){const n=la(this),t=Hn(void 0);try{const i=this.get(zp.multi,Se,ee.Self);for(const r of i)r()}finally{la(n),Hn(t)}}toString(){const n=[],t=this.records;for(const i of t.keys())n.push(He(i));return`R3Injector[${n.join(", ")}]`}assertNotDestroyed(){if(this._destroyed)throw new F(205,!1)}processProvider(n){let t=Zo(n=te(n))?n:te(n&&n.provide);const i=function pA(e){return qp(e)?da(void 0,e.useValue):da(N0(e),sd)}(n);if(Zo(n)||!0!==n.multi)this.records.get(t);else{let r=this.records.get(t);r||(r=da(void 0,sd,!0),r.factory=()=>vp(r.multi),this.records.set(t,r)),t=n,r.multi.push(n)}this.records.set(t,i)}hydrate(n,t){return t.value===sd&&(t.value=fA,t.value=t.factory()),"object"==typeof t.value&&t.value&&function mA(e){return null!==e&&"object"==typeof e&&"function"==typeof e.ngOnDestroy}(t.value)&&this._ngOnDestroyHooks.add(t.value),t.value}injectableDefInScope(n){if(!n.providedIn)return!1;const t=te(n.providedIn);return"string"==typeof t?"any"===t||this.scopes.has(t):this.injectorDefTypes.has(t)}}function Qp(e){const n=Lo(e),t=null!==n?n.factory:Sr(e);if(null!==t)return t;if(e instanceof Y)throw new F(204,!1);if(e instanceof Function)return function hA(e){const n=e.length;if(n>0)throw Al(n,"?"),new F(204,!1);const t=function Th(e){const n=e&&(e[Vo]||e[Jr]);if(n){const t=function Nh(e){if(e.hasOwnProperty("name"))return e.name;const n=(""+e).match(/^function\s*([^\s(]+)/);return null===n?"":n[1]}(e);return console.warn(`DEPRECATED: DI is instantiating a token "${t}" that inherits its @Injectable decorator but does not provide one itself.\nThis will become an error in a future version of Angular. Please add @Injectable() to the "${t}" class.`),n}return null}(e);return null!==t?()=>t.factory(e):()=>new e}(e);throw new F(204,!1)}function N0(e,n,t){let i;if(Zo(e)){const r=te(e);return Sr(r)||Qp(r)}if(qp(e))i=()=>te(e.useValue);else if(function M0(e){return!(!e||!e.useFactory)}(e))i=()=>e.useFactory(...vp(e.deps||[]));else if(function E0(e){return!(!e||!e.useExisting)}(e))i=()=>L(te(e.useExisting));else{const r=te(e&&(e.useClass||e.provide));if(!function gA(e){return!!e.deps}(e))return Sr(r)||Qp(r);i=()=>new r(...vp(e.deps))}return i}function da(e,n,t=!1){return{factory:e,value:n,multi:t?[]:void 0}}function vA(e){return!!e.\u0275providers}function Xp(e,n){for(const t of e)Array.isArray(t)?Xp(t,n):vA(t)?Xp(t.\u0275providers,n):n(t)}class A0{}class DA{resolveComponentFactory(n){throw function bA(e){const n=Error(`No component factory found for ${He(e)}. Did you add it to @NgModule.entryComponents?`);return n.ngComponent=e,n}(n)}}let Ul=(()=>{class e{}return e.NULL=new DA,e})();function CA(){return fa(yt(),k())}function fa(e,n){return new Qe(An(e,n))}let Qe=(()=>{class e{constructor(t){this.nativeElement=t}}return e.__NG_ELEMENT_ID__=CA,e})();function wA(e){return e instanceof Qe?e.nativeElement:e}class eg{}let ui=(()=>{class e{}return e.__NG_ELEMENT_ID__=()=>function SA(){const e=k(),t=In(yt().index,e);return(tn(t)?t:e)[11]}(),e})(),EA=(()=>{class e{}return e.\u0275prov=U({token:e,providedIn:"root",factory:()=>null}),e})();class Gl{constructor(n){this.full=n,this.major=n.split(".")[0],this.minor=n.split(".")[1],this.patch=n.split(".").slice(2).join(".")}}const MA=new Gl("14.3.0"),tg={};function ig(e){return e.ngOriginalError}class ha{constructor(){this._console=console}handleError(n){const t=this._findOriginalError(n);this._console.error("ERROR",n),t&&this._console.error("ORIGINAL ERROR",t)}_findOriginalError(n){let t=n&&ig(n);for(;t&&ig(t);)t=ig(t);return t||null}}function Ir(e){return e instanceof Function?e():e}function k0(e,n,t){let i=e.length;for(;;){const r=e.indexOf(n,t);if(-1===r)return r;if(0===r||e.charCodeAt(r-1)<=32){const o=n.length;if(r+o===i||e.charCodeAt(r+o)<=32)return r}t=r+1}}const R0="ng-template";function LA(e,n,t){let i=0;for(;io?"":r[p+1].toLowerCase();const v=8&i?m:null;if(v&&-1!==k0(v,u,0)||2&i&&u!==m){if(Ii(i))return!1;s=!0}}}}else{if(!s&&!Ii(i)&&!Ii(l))return!1;if(s&&Ii(l))continue;s=!1,i=l|1&i}}return Ii(i)||s}function Ii(e){return 0==(1&e)}function BA(e,n,t,i){if(null===n)return-1;let r=0;if(i||!t){let o=!1;for(;r-1)for(t++;t0?'="'+a+'"':"")+"]"}else 8&i?r+="."+s:4&i&&(r+=" "+s);else""!==r&&!Ii(s)&&(n+=P0(o,r),r=""),i=s,o=o||!Ii(i);t++}return""!==r&&(n+=P0(o,r)),n}const ae={};function P(e){L0(me(),k(),on()+e,!1)}function L0(e,n,t,i){if(!i)if(3==(3&n[2])){const o=e.preOrderCheckHooks;null!==o&&Zs(n,o,t)}else{const o=e.preOrderHooks;null!==o&&Qs(n,o,0,t)}Xi(t)}function j0(e,n=null,t=null,i){const r=$0(e,n,t,i);return r.resolveInjectorInitializers(),r}function $0(e,n=null,t=null,i,r=new Set){const o=[t||Se,cA(e)];return i=i||("object"==typeof e?void 0:He(e)),new T0(o,n||ad(),i||null,r)}let _n=(()=>{class e{static create(t,i){if(Array.isArray(t))return j0({name:""},i,t,"");{const r=t.name??"";return j0({name:r},t.parent,t.providers,r)}}}return e.THROW_IF_NOT_FOUND=Il,e.NULL=new C0,e.\u0275prov=U({token:e,providedIn:"any",factory:()=>L(b0)}),e.__NG_ELEMENT_ID__=-1,e})();function C(e,n=ee.Default){const t=k();return null===t?L(e,n):Kt(yt(),t,te(e),n)}function lg(){throw new Error("invalid")}function cd(e,n){return e<<17|n<<2}function Oi(e){return e>>17&32767}function cg(e){return 2|e}function Or(e){return(131068&e)>>2}function ug(e,n){return-131069&e|n<<2}function dg(e){return 1|e}function ob(e,n){const t=e.contentQueries;if(null!==t)for(let i=0;i22&&L0(e,n,22,!1),t(i,r)}finally{Xi(o)}}function Dg(e,n,t){!Ks()||(function kI(e,n,t,i){const r=t.directiveStart,o=t.directiveEnd;e.firstCreatePass||h(t,n),mn(i,n);const s=t.initialInputs;for(let a=r;a0;){const t=e[--n];if("number"==typeof t&&t<0)return t}return 0})(a)!=l&&a.push(l),a.push(i,r,s)}}function pb(e,n){null!==e.hostBindings&&e.hostBindings(1,n)}function gb(e,n){n.flags|=2,(e.components||(e.components=[])).push(n.index)}function PI(e,n,t){if(t){if(n.exportAs)for(let i=0;i0&&Mg(t)}}function Mg(e){for(let i=Np(e);null!==i;i=Ap(i))for(let r=10;r0&&Mg(o)}const t=e[1].components;if(null!==t)for(let i=0;i0&&Mg(r)}}function UI(e,n){const t=In(n,e),i=t[1];(function GI(e,n){for(let t=n.length;t-1&&(kp(n,i),qu(t,i))}this._attachedToViewContainer=!1}qy(this._lView[1],this._lView)}onDestroy(n){cb(this._lView[1],this._lView,null,n)}markForCheck(){Tg(this._cdRefInjectingView||this._lView)}detach(){this._lView[2]&=-65}reattach(){this._lView[2]|=64}detectChanges(){gd(this._lView[1],this._lView,this.context)}checkNoChanges(){}attachToViewContainerRef(){if(this._appRef)throw new F(902,!1);this._attachedToViewContainer=!0}detachFromAppRef(){this._appRef=null,function EN(e,n){Hl(e,n,n[11],2,null,null)}(this._lView[1],this._lView)}attachToAppRef(n){if(this._attachedToViewContainer)throw new F(902,!1);this._appRef=n}}class WI extends Wl{constructor(n){super(n),this._view=n}detectChanges(){const n=this._view;gd(n[1],n,n[8],!1)}checkNoChanges(){}get context(){return null}}class Ig extends Ul{constructor(n){super(),this.ngModule=n}resolveComponentFactory(n){const t=Re(n);return new Kl(t,this.ngModule)}}function wb(e){const n=[];for(let t in e)e.hasOwnProperty(t)&&n.push({propName:e[t],templateName:t});return n}class zI{constructor(n,t){this.injector=n,this.parentInjector=t}get(n,t,i){const r=this.injector.get(n,tg,i);return r!==tg||t===tg?r:this.parentInjector.get(n,t,i)}}class Kl extends A0{constructor(n,t){super(),this.componentDef=n,this.ngModule=t,this.componentType=n.type,this.selector=function KA(e){return e.map(WA).join(",")}(n.selectors),this.ngContentSelectors=n.ngContentSelectors?n.ngContentSelectors:[],this.isBoundToModule=!!t}get inputs(){return wb(this.componentDef.inputs)}get outputs(){return wb(this.componentDef.outputs)}create(n,t,i,r){let o=(r=r||this.ngModule)instanceof co?r:r?.injector;o&&null!==this.componentDef.getStandaloneInjector&&(o=this.componentDef.getStandaloneInjector(o)||o);const s=o?new zI(n,o):n,a=s.get(eg,null);if(null===a)throw new F(407,!1);const l=s.get(EA,null),u=a.createRenderer(null,this.componentDef),f=this.componentDef.selectors[0][0]||"div",p=i?function MI(e,n,t){return e.selectRootElement(n,t===Bn.ShadowDom)}(u,i,this.componentDef.encapsulation):Op(u,f,function KI(e){const n=e.toLowerCase();return"svg"===n?"svg":"math"===n?"math":null}(f)),m=this.componentDef.onPush?288:272,v=wg(0,null,null,1,0,null,null,null,null,null),y=fd(null,v,null,m,null,null,a,u,l,s,null);let D,w;Cl(y);try{const S=function JI(e,n,t,i,r,o){const s=t[1];t[22]=e;const l=ma(s,22,2,"#host",null),u=l.mergedAttrs=n.hostAttrs;null!==u&&(md(l,u,!0),null!==e&&(Xs(r,e,u),null!==l.classes&&Vp(r,e,l.classes),null!==l.styles&&a0(r,e,l.styles)));const f=i.createRenderer(e,n),p=fd(t,lb(n),null,n.onPush?32:16,t[22],l,i,f,o||null,null,null);return s.firstCreatePass&&(T(h(l,t),s,n.type),gb(s,l),mb(l,t.length,1)),pd(t,p),t[22]=p}(p,this.componentDef,y,a,u);if(p)if(i)Xs(u,p,["ng-version",MA.full]);else{const{attrs:O,classes:E}=function zA(e){const n=[],t=[];let i=1,r=2;for(;i0&&Vp(u,p,E.join(" "))}if(w=vl(v,22),void 0!==t){const O=w.projection=[];for(let E=0;E=0;i--){const r=e[i];r.hostVars=n+=r.hostVars,r.hostAttrs=ea(r.hostAttrs,t=ea(t,r.hostAttrs))}}(i)}function Og(e){return e===bi?{}:e===Se?[]:e}function eO(e,n){const t=e.viewQuery;e.viewQuery=t?(i,r)=>{n(i,r),t(i,r)}:n}function tO(e,n){const t=e.contentQueries;e.contentQueries=t?(i,r,o)=>{n(i,r,o),t(i,r,o)}:n}function nO(e,n){const t=e.hostBindings;e.hostBindings=t?(i,r)=>{n(i,r),t(i,r)}:n}let vd=null;function Qo(){if(!vd){const e=Ue.Symbol;if(e&&e.iterator)vd=e.iterator;else{const n=Object.getOwnPropertyNames(Map.prototype);for(let t=0;ta(ft(R[i.index])):i.index;let A=null;if(!a&&l&&(A=function pO(e,n,t,i){const r=e.cleanup;if(null!=r)for(let o=0;ol?a[l]:null}"string"==typeof s&&(o+=2)}return null}(e,n,r,i.index)),null!==A)(A.__ngLastListenerFn__||A).__ngNextListenerFn__=o,A.__ngLastListenerFn__=o,v=!1;else{o=Hb(i,n,p,o,!1);const R=t.listen(S,r,o);m.push(o,R),f&&f.push(r,E,O,O+1)}}else o=Hb(i,n,p,o,!1);const y=i.outputs;let D;if(v&&null!==y&&(D=y[r])){const w=D.length;if(w)for(let S=0;S0;)n=n[15],e--;return n}(e,oe.lFrame.contextLView))[8]}(e)}function gO(e,n){let t=null;const i=function jA(e){const n=e.attrs;if(null!=n){const t=n.indexOf(5);if(0==(1&t))return n[t+1]}return null}(e);for(let r=0;r=0}const Lt={textEnd:0,key:0,keyEnd:0,value:0,valueEnd:0};function qb(e){return e.substring(Lt.key,Lt.keyEnd)}function Jb(e,n){const t=Lt.textEnd;return t===n?-1:(n=Lt.keyEnd=function CO(e,n,t){for(;n32;)n++;return n}(e,Lt.key=n,t),Ta(e,n,t))}function Ta(e,n,t){for(;n=0;t=Jb(n,t))Jn(e,qb(n),!0)}function tD(e,n){return n>=e.expandoStartIndex}function nD(e,n,t,i){const r=e.data;if(null===r[t+1]){const o=r[on()],s=tD(e,t);sD(o,i)&&null===n&&!s&&(n=!1),n=function MO(e,n,t,i){const r=function Ys(e){const n=oe.lFrame.currentDirectiveIndex;return-1===n?null:e[n]}(e);let o=i?n.residualClasses:n.residualStyles;if(null===r)0===(i?n.classBindings:n.styleBindings)&&(t=Jl(t=jg(null,e,n,t,i),n.attrs,i),o=null);else{const s=n.directiveStylingLast;if(-1===s||e[s]!==r)if(t=jg(r,e,n,t,i),null===o){let l=function TO(e,n,t){const i=t?n.classBindings:n.styleBindings;if(0!==Or(i))return e[Oi(i)]}(e,n,i);void 0!==l&&Array.isArray(l)&&(l=jg(null,e,n,l[1],i),l=Jl(l,n.attrs,i),function NO(e,n,t,i){e[Oi(t?n.classBindings:n.styleBindings)]=i}(e,n,i,l))}else o=function AO(e,n,t){let i;const r=n.directiveEnd;for(let o=1+n.directiveStylingLast;o0)&&(u=!0)}else f=t;if(r)if(0!==l){const m=Oi(e[a+1]);e[i+1]=cd(m,a),0!==m&&(e[m+1]=ug(e[m+1],i)),e[a+1]=function fI(e,n){return 131071&e|n<<17}(e[a+1],i)}else e[i+1]=cd(a,0),0!==a&&(e[a+1]=ug(e[a+1],i)),a=i;else e[i+1]=cd(l,0),0===a?a=i:e[l+1]=ug(e[l+1],i),l=i;u&&(e[i+1]=cg(e[i+1])),Yb(e,f,i,!0),Yb(e,f,i,!1),function _O(e,n,t,i,r){const o=r?e.residualClasses:e.residualStyles;null!=o&&"string"==typeof n&&aa(o,n)>=0&&(t[i+1]=dg(t[i+1]))}(n,f,e,i,o),s=cd(a,l),o?n.classBindings=s:n.styleBindings=s}(r,o,n,t,s,i)}}function jg(e,n,t,i,r){let o=null;const s=t.directiveEnd;let a=t.directiveStylingLast;for(-1===a?a=t.directiveStart:a++;a0;){const l=e[r],u=Array.isArray(l),f=u?l[1]:l,p=null===f;let m=t[r+1];m===ae&&(m=p?Se:void 0);let v=p?gp(m,i):f===i?m:void 0;if(u&&!Dd(v)&&(v=gp(l,i)),Dd(v)&&(a=v,s))return a;const y=e[r+1];r=s?Oi(y):Or(y)}if(null!==n){let l=o?n.residualClasses:n.residualStyles;null!=l&&(a=gp(l,i))}return a}function Dd(e){return void 0!==e}function sD(e,n){return 0!=(e.flags&(n?16:32))}function I(e,n=""){const t=k(),i=me(),r=e+22,o=i.firstCreatePass?ma(i,r,1,n,null):i.data[r],s=t[r]=function Ip(e,n){return e.createText(n)}(t[11],n);td(i,t,s,o),ai(o,!1)}function Rr(e){return Be("",e,""),Rr}function Be(e,n,t){const i=k(),r=function ya(e,n,t,i){return vn(e,Er(),t)?n+se(t)+i:ae}(i,e,n,t);return r!==ae&&function kr(e,n,t){const i=Gs(n,e);!function zy(e,n,t){e.setValue(n,t)}(e[11],i,t)}(i,on(),r),Be}const ts=void 0;var QO=["en",[["a","p"],["AM","PM"],ts],[["AM","PM"],ts,ts],[["S","M","T","W","T","F","S"],["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],["Su","Mo","Tu","We","Th","Fr","Sa"]],ts,[["J","F","M","A","M","J","J","A","S","O","N","D"],["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],["January","February","March","April","May","June","July","August","September","October","November","December"]],ts,[["B","A"],["BC","AD"],["Before Christ","Anno Domini"]],0,[6,0],["M/d/yy","MMM d, y","MMMM d, y","EEEE, MMMM d, y"],["h:mm a","h:mm:ss a","h:mm:ss a z","h:mm:ss a zzzz"],["{1}, {0}",ts,"{1} 'at' {0}",ts],[".",",",";","%","+","-","E","\xd7","\u2030","\u221e","NaN",":"],["#,##0.###","#,##0%","\xa4#,##0.00","#E0"],"USD","$","US Dollar",{},"ltr",function ZO(e){const t=Math.floor(Math.abs(e)),i=e.toString().replace(/^[^.]*\.?/,"").length;return 1===t&&0===i?1:5}];let Aa={};function kn(e){const n=function XO(e){return e.toLowerCase().replace(/_/g,"-")}(e);let t=MD(n);if(t)return t;const i=n.split("-")[0];if(t=MD(i),t)return t;if("en"===i)return QO;throw new F(701,!1)}function MD(e){return e in Aa||(Aa[e]=Ue.ng&&Ue.ng.common&&Ue.ng.common.locales&&Ue.ng.common.locales[e]),Aa[e]}var j=(()=>((j=j||{})[j.LocaleId=0]="LocaleId",j[j.DayPeriodsFormat=1]="DayPeriodsFormat",j[j.DayPeriodsStandalone=2]="DayPeriodsStandalone",j[j.DaysFormat=3]="DaysFormat",j[j.DaysStandalone=4]="DaysStandalone",j[j.MonthsFormat=5]="MonthsFormat",j[j.MonthsStandalone=6]="MonthsStandalone",j[j.Eras=7]="Eras",j[j.FirstDayOfWeek=8]="FirstDayOfWeek",j[j.WeekendRange=9]="WeekendRange",j[j.DateFormat=10]="DateFormat",j[j.TimeFormat=11]="TimeFormat",j[j.DateTimeFormat=12]="DateTimeFormat",j[j.NumberSymbols=13]="NumberSymbols",j[j.NumberFormats=14]="NumberFormats",j[j.CurrencyCode=15]="CurrencyCode",j[j.CurrencySymbol=16]="CurrencySymbol",j[j.CurrencyName=17]="CurrencyName",j[j.Currencies=18]="Currencies",j[j.Directionality=19]="Directionality",j[j.PluralCase=20]="PluralCase",j[j.ExtraData=21]="ExtraData",j))();const Ia="en-US";let TD=Ia;function Wg(e,n,t,i,r){if(e=te(e),Array.isArray(e))for(let o=0;o>20;if(Zo(e)||!e.multi){const v=new Wo(l,r,C),y=zg(a,n,r?f:f+m,p);-1===y?(T(h(u,s),o,a),Kg(o,e,n.length),n.push(a),u.directiveStart++,u.directiveEnd++,r&&(u.providerIndexes+=1048576),t.push(v),s.push(v)):(t[y]=v,s[y]=v)}else{const v=zg(a,n,f+m,p),y=zg(a,n,f,f+m),D=v>=0&&t[v],w=y>=0&&t[y];if(r&&!w||!r&&!D){T(h(u,s),o,a);const S=function Yk(e,n,t,i,r){const o=new Wo(e,t,C);return o.multi=[],o.index=n,o.componentProviders=0,QD(o,r,i&&!t),o}(r?zk:Kk,t.length,r,i,l);!r&&w&&(t[y].providerFactory=S),Kg(o,e,n.length,0),n.push(a),u.directiveStart++,u.directiveEnd++,r&&(u.providerIndexes+=1048576),t.push(S),s.push(S)}else Kg(o,e,v>-1?v:y,QD(t[r?y:v],l,!r&&i));!r&&i&&w&&t[y].componentProviders++}}}function Kg(e,n,t,i){const r=Zo(n),o=function dA(e){return!!e.useClass}(n);if(r||o){const l=(o?te(n.useClass):n).prototype.ngOnDestroy;if(l){const u=e.destroyHooks||(e.destroyHooks=[]);if(!r&&n.multi){const f=u.indexOf(t);-1===f?u.push(t,[i,l]):u[f+1].push(i,l)}else u.push(t,l)}}}function QD(e,n,t){return t&&e.componentProviders++,e.multi.push(n)-1}function zg(e,n,t,i){for(let r=t;r{t.providersResolver=(i,r)=>function Wk(e,n,t){const i=me();if(i.firstCreatePass){const r=$n(e);Wg(t,i.data,i.blueprint,r,!0),Wg(n,i.data,i.blueprint,r,!1)}}(i,r?r(e):e,n)}}class ns{}class XD{}class e1 extends ns{constructor(n,t){super(),this._parent=t,this._bootstrapComponents=[],this.destroyCbs=[],this.componentFactoryResolver=new Ig(this);const i=hn(n);this._bootstrapComponents=Ir(i.bootstrap),this._r3Injector=$0(n,t,[{provide:ns,useValue:this},{provide:Ul,useValue:this.componentFactoryResolver}],He(n),new Set(["environment"])),this._r3Injector.resolveInjectorInitializers(),this.instance=this._r3Injector.get(n)}get injector(){return this._r3Injector}destroy(){const n=this._r3Injector;!n.destroyed&&n.destroy(),this.destroyCbs.forEach(t=>t()),this.destroyCbs=null}onDestroy(n){this.destroyCbs.push(n)}}class qg extends XD{constructor(n){super(),this.moduleType=n}create(n){return new e1(this.moduleType,n)}}class Jk extends ns{constructor(n,t,i){super(),this.componentFactoryResolver=new Ig(this),this.instance=null;const r=new T0([...n,{provide:ns,useValue:this},{provide:Ul,useValue:this.componentFactoryResolver}],t||ad(),i,new Set(["environment"]));this.injector=r,r.resolveInjectorInitializers()}destroy(){this.injector.destroy()}onDestroy(n){this.injector.onDestroy(n)}}function Md(e,n,t=null){return new Jk(e,n,t).injector}let Zk=(()=>{class e{constructor(t){this._injector=t,this.cachedInjectors=new Map}getOrCreateStandaloneInjector(t){if(!t.standalone)return null;if(!this.cachedInjectors.has(t.id)){const i=w0(0,t.type),r=i.length>0?Md([i],this._injector,`Standalone[${t.type.name}]`):null;this.cachedInjectors.set(t.id,r)}return this.cachedInjectors.get(t.id)}ngOnDestroy(){try{for(const t of this.cachedInjectors.values())null!==t&&t.destroy()}finally{this.cachedInjectors.clear()}}}return e.\u0275prov=U({token:e,providedIn:"environment",factory:()=>new e(L(co))}),e})();function t1(e){e.getStandaloneInjector=n=>n.get(Zk).getOrCreateStandaloneInjector(e)}function Nd(e,n,t,i,r,o){return function d1(e,n,t,i,r,o,s,a){const l=n+t;return function yd(e,n,t,i,r){const o=Xo(e,n,t,i);return vn(e,n+2,r)||o}(e,l,r,o,s)?ir(e,l+3,a?i.call(a,r,o,s):i(r,o,s)):ic(e,l+3)}(k(),rn(),e,n,t,i,r,o)}function ic(e,n){const t=e[n];return t===ae?void 0:t}function Ad(e,n){const t=me();let i;const r=e+22;t.firstCreatePass?(i=function fR(e,n){if(n)for(let t=n.length-1;t>=0;t--){const i=n[t];if(e===i.name)return i}}(n,t.pipeRegistry),t.data[r]=i,i.onDestroy&&(t.destroyHooks||(t.destroyHooks=[])).push(r,i.onDestroy)):i=t.data[r];const o=i.factory||(i.factory=Sr(i.type)),s=Hn(C);try{const a=ta(!1),l=o();return ta(a),function dO(e,n,t,i){t>=e.data.length&&(e.data[t]=null,e.blueprint[t]=null),n[t]=i}(t,k(),r,l),l}finally{Hn(s)}}function Id(e,n,t,i){const r=e+22,o=k(),s=ro(o,r);return function rc(e,n){return e[1].data[n].pure}(o,r)?function u1(e,n,t,i,r,o,s){const a=n+t;return Xo(e,a,r,o)?ir(e,a+2,s?i.call(s,r,o):i(r,o)):ic(e,a+2)}(o,rn(),n,s.transform,t,i,s):s.transform(t,i)}function Zg(e){return n=>{setTimeout(e,void 0,n)}}const de=class _R extends je{constructor(n=!1){super(),this.__isAsync=n}emit(n){super.next(n)}subscribe(n,t,i){let r=n,o=t||(()=>null),s=i;if(n&&"object"==typeof n){const l=n;r=l.next?.bind(l),o=l.error?.bind(l),s=l.complete?.bind(l)}this.__isAsync&&(o=Zg(o),r&&(r=Zg(r)),s&&(s=Zg(s)));const a=super.subscribe({next:r,error:o,complete:s});return n instanceof _t&&n.add(a),a}};function vR(){return this._results[Qo()]()}class Qg{constructor(n=!1){this._emitDistinctChangesOnly=n,this.dirty=!0,this._results=[],this._changesDetected=!1,this._changes=null,this.length=0,this.first=void 0,this.last=void 0;const t=Qo(),i=Qg.prototype;i[t]||(i[t]=vR)}get changes(){return this._changes||(this._changes=new de)}get(n){return this._results[n]}map(n){return this._results.map(n)}filter(n){return this._results.filter(n)}find(n){return this._results.find(n)}reduce(n,t){return this._results.reduce(n,t)}forEach(n){this._results.forEach(n)}some(n){return this._results.some(n)}toArray(){return this._results.slice()}toString(){return this._results.toString()}reset(n,t){const i=this;i.dirty=!1;const r=qn(n);(this._changesDetected=!function IT(e,n,t){if(e.length!==n.length)return!1;for(let i=0;i{class e{}return e.__NG_ELEMENT_ID__=DR,e})();const yR=gt,bR=class extends yR{constructor(n,t,i){super(),this._declarationLView=n,this._declarationTContainer=t,this.elementRef=i}createEmbeddedView(n,t){const i=this._declarationTContainer.tViews,r=fd(this._declarationLView,i,n,16,null,i.declTNode,null,null,null,null,t||null);r[17]=this._declarationLView[this._declarationTContainer.index];const s=this._declarationLView[19];return null!==s&&(r[19]=s.createEmbeddedView(i)),bg(i,r,n),new Wl(r)}};function DR(){return Od(yt(),k())}function Od(e,n){return 4&e.type?new bR(n,e,fa(e,n)):null}let Pi=(()=>{class e{}return e.__NG_ELEMENT_ID__=CR,e})();function CR(){return m1(yt(),k())}const wR=Pi,p1=class extends wR{constructor(n,t,i){super(),this._lContainer=n,this._hostTNode=t,this._hostLView=i}get element(){return fa(this._hostTNode,this._hostLView)}get injector(){return new na(this._hostTNode,this._hostLView)}get parentInjector(){const n=b(this._hostTNode,this._hostLView);if(Mr(n)){const t=ao(n,this._hostLView),i=so(n);return new na(t[1].data[i+8],t)}return new na(null,this._hostLView)}clear(){for(;this.length>0;)this.remove(this.length-1)}get(n){const t=g1(this._lContainer);return null!==t&&t[n]||null}get length(){return this._lContainer.length-10}createEmbeddedView(n,t,i){let r,o;"number"==typeof i?r=i:null!=i&&(r=i.index,o=i.injector);const s=n.createEmbeddedView(t||{},o);return this.insert(s,r),s}createComponent(n,t,i,r,o){const s=n&&!function Nl(e){return"function"==typeof e}(n);let a;if(s)a=t;else{const p=t||{};a=p.index,i=p.injector,r=p.projectableNodes,o=p.environmentInjector||p.ngModuleRef}const l=s?n:new Kl(Re(n)),u=i||this.parentInjector;if(!o&&null==l.ngModule){const m=(s?u:this.parentInjector).get(co,null);m&&(o=m)}const f=l.create(u,r,void 0,o);return this.insert(f.hostView,a),f}insert(n,t){const i=n._lView,r=i[1];if(function Kh(e){return zn(e[3])}(i)){const f=this.indexOf(n);if(-1!==f)this.detach(f);else{const p=i[3],m=new p1(p,p[6],p[3]);m.detach(m.indexOf(n))}}const o=this._adjustIndex(t),s=this._lContainer;!function TN(e,n,t,i){const r=10+i,o=t.length;i>0&&(t[r-1][4]=n),i0)i.push(s[a/2]);else{const u=o[a+1],f=n[-l];for(let p=10;p{class e{constructor(t){this.appInits=t,this.resolve=xd,this.reject=xd,this.initialized=!1,this.done=!1,this.donePromise=new Promise((i,r)=>{this.resolve=i,this.reject=r})}runInitializers(){if(this.initialized)return;const t=[],i=()=>{this.done=!0,this.resolve()};if(this.appInits)for(let r=0;r{o.subscribe({complete:a,error:l})});t.push(s)}}Promise.all(t).then(()=>{i()}).catch(r=>{this.reject(r)}),0===t.length&&i(),this.initialized=!0}}return e.\u0275fac=function(t){return new(t||e)(L(Fd,8))},e.\u0275prov=U({token:e,factory:e.\u0275fac,providedIn:"root"}),e})();const sc=new Y("AppId",{providedIn:"root",factory:function B1(){return`${cm()}${cm()}${cm()}`}});function cm(){return String.fromCharCode(97+Math.floor(25*Math.random()))}const j1=new Y("Platform Initializer"),ac=new Y("Platform ID",{providedIn:"platform",factory:()=>"unknown"}),$1=new Y("appBootstrapListener");let ZR=(()=>{class e{log(t){console.log(t)}warn(t){console.warn(t)}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=U({token:e,factory:e.\u0275fac,providedIn:"platform"}),e})();const xr=new Y("LocaleId",{providedIn:"root",factory:()=>bt(xr,ee.Optional|ee.SkipSelf)||function QR(){return typeof $localize<"u"&&$localize.locale||Ia}()});class ex{constructor(n,t){this.ngModuleFactory=n,this.componentFactories=t}}let um=(()=>{class e{compileModuleSync(t){return new qg(t)}compileModuleAsync(t){return Promise.resolve(this.compileModuleSync(t))}compileModuleAndAllComponentsSync(t){const i=this.compileModuleSync(t),o=Ir(hn(t).declarations).reduce((s,a)=>{const l=Re(a);return l&&s.push(new Kl(l)),s},[]);return new ex(i,o)}compileModuleAndAllComponentsAsync(t){return Promise.resolve(this.compileModuleAndAllComponentsSync(t))}clearCache(){}clearCacheFor(t){}getModuleId(t){}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=U({token:e,factory:e.\u0275fac,providedIn:"root"}),e})();const ix=(()=>Promise.resolve(0))();function dm(e){typeof Zone>"u"?ix.then(()=>{e&&e.apply(null,null)}):Zone.current.scheduleMicroTask("scheduleMicrotask",e)}class Ye{constructor({enableLongStackTrace:n=!1,shouldCoalesceEventChangeDetection:t=!1,shouldCoalesceRunChangeDetection:i=!1}){if(this.hasPendingMacrotasks=!1,this.hasPendingMicrotasks=!1,this.isStable=!0,this.onUnstable=new de(!1),this.onMicrotaskEmpty=new de(!1),this.onStable=new de(!1),this.onError=new de(!1),typeof Zone>"u")throw new F(908,!1);Zone.assertZonePatched();const r=this;if(r._nesting=0,r._outer=r._inner=Zone.current,Zone.AsyncStackTaggingZoneSpec){const o=Zone.AsyncStackTaggingZoneSpec;r._inner=r._inner.fork(new o("Angular"))}Zone.TaskTrackingZoneSpec&&(r._inner=r._inner.fork(new Zone.TaskTrackingZoneSpec)),n&&Zone.longStackTraceZoneSpec&&(r._inner=r._inner.fork(Zone.longStackTraceZoneSpec)),r.shouldCoalesceEventChangeDetection=!i&&t,r.shouldCoalesceRunChangeDetection=i,r.lastRequestAnimationFrameId=-1,r.nativeRequestAnimationFrame=function rx(){let e=Ue.requestAnimationFrame,n=Ue.cancelAnimationFrame;if(typeof Zone<"u"&&e&&n){const t=e[Zone.__symbol__("OriginalDelegate")];t&&(e=t);const i=n[Zone.__symbol__("OriginalDelegate")];i&&(n=i)}return{nativeRequestAnimationFrame:e,nativeCancelAnimationFrame:n}}().nativeRequestAnimationFrame,function ax(e){const n=()=>{!function sx(e){e.isCheckStableRunning||-1!==e.lastRequestAnimationFrameId||(e.lastRequestAnimationFrameId=e.nativeRequestAnimationFrame.call(Ue,()=>{e.fakeTopEventTask||(e.fakeTopEventTask=Zone.root.scheduleEventTask("fakeTopEventTask",()=>{e.lastRequestAnimationFrameId=-1,hm(e),e.isCheckStableRunning=!0,fm(e),e.isCheckStableRunning=!1},void 0,()=>{},()=>{})),e.fakeTopEventTask.invoke()}),hm(e))}(e)};e._inner=e._inner.fork({name:"angular",properties:{isAngularZone:!0},onInvokeTask:(t,i,r,o,s,a)=>{try{return W1(e),t.invokeTask(r,o,s,a)}finally{(e.shouldCoalesceEventChangeDetection&&"eventTask"===o.type||e.shouldCoalesceRunChangeDetection)&&n(),K1(e)}},onInvoke:(t,i,r,o,s,a,l)=>{try{return W1(e),t.invoke(r,o,s,a,l)}finally{e.shouldCoalesceRunChangeDetection&&n(),K1(e)}},onHasTask:(t,i,r,o)=>{t.hasTask(r,o),i===r&&("microTask"==o.change?(e._hasPendingMicrotasks=o.microTask,hm(e),fm(e)):"macroTask"==o.change&&(e.hasPendingMacrotasks=o.macroTask))},onHandleError:(t,i,r,o)=>(t.handleError(r,o),e.runOutsideAngular(()=>e.onError.emit(o)),!1)})}(r)}static isInAngularZone(){return typeof Zone<"u"&&!0===Zone.current.get("isAngularZone")}static assertInAngularZone(){if(!Ye.isInAngularZone())throw new F(909,!1)}static assertNotInAngularZone(){if(Ye.isInAngularZone())throw new F(909,!1)}run(n,t,i){return this._inner.run(n,t,i)}runTask(n,t,i,r){const o=this._inner,s=o.scheduleEventTask("NgZoneEvent: "+r,n,ox,xd,xd);try{return o.runTask(s,t,i)}finally{o.cancelTask(s)}}runGuarded(n,t,i){return this._inner.runGuarded(n,t,i)}runOutsideAngular(n){return this._outer.run(n)}}const ox={};function fm(e){if(0==e._nesting&&!e.hasPendingMicrotasks&&!e.isStable)try{e._nesting++,e.onMicrotaskEmpty.emit(null)}finally{if(e._nesting--,!e.hasPendingMicrotasks)try{e.runOutsideAngular(()=>e.onStable.emit(null))}finally{e.isStable=!0}}}function hm(e){e.hasPendingMicrotasks=!!(e._hasPendingMicrotasks||(e.shouldCoalesceEventChangeDetection||e.shouldCoalesceRunChangeDetection)&&-1!==e.lastRequestAnimationFrameId)}function W1(e){e._nesting++,e.isStable&&(e.isStable=!1,e.onUnstable.emit(null))}function K1(e){e._nesting--,fm(e)}class lx{constructor(){this.hasPendingMicrotasks=!1,this.hasPendingMacrotasks=!1,this.isStable=!0,this.onUnstable=new de,this.onMicrotaskEmpty=new de,this.onStable=new de,this.onError=new de}run(n,t,i){return n.apply(t,i)}runGuarded(n,t,i){return n.apply(t,i)}runOutsideAngular(n){return n()}runTask(n,t,i,r){return n.apply(t,i)}}const z1=new Y(""),Ld=new Y("");let mm,pm=(()=>{class e{constructor(t,i,r){this._ngZone=t,this.registry=i,this._pendingCount=0,this._isZoneStable=!0,this._didWork=!1,this._callbacks=[],this.taskTrackingZone=null,mm||(function cx(e){mm=e}(r),r.addToWindow(i)),this._watchAngularEvents(),t.run(()=>{this.taskTrackingZone=typeof Zone>"u"?null:Zone.current.get("TaskTrackingZone")})}_watchAngularEvents(){this._ngZone.onUnstable.subscribe({next:()=>{this._didWork=!0,this._isZoneStable=!1}}),this._ngZone.runOutsideAngular(()=>{this._ngZone.onStable.subscribe({next:()=>{Ye.assertNotInAngularZone(),dm(()=>{this._isZoneStable=!0,this._runCallbacksIfReady()})}})})}increasePendingRequestCount(){return this._pendingCount+=1,this._didWork=!0,this._pendingCount}decreasePendingRequestCount(){if(this._pendingCount-=1,this._pendingCount<0)throw new Error("pending async requests below zero");return this._runCallbacksIfReady(),this._pendingCount}isStable(){return this._isZoneStable&&0===this._pendingCount&&!this._ngZone.hasPendingMacrotasks}_runCallbacksIfReady(){if(this.isStable())dm(()=>{for(;0!==this._callbacks.length;){let t=this._callbacks.pop();clearTimeout(t.timeoutId),t.doneCb(this._didWork)}this._didWork=!1});else{let t=this.getPendingTasks();this._callbacks=this._callbacks.filter(i=>!i.updateCb||!i.updateCb(t)||(clearTimeout(i.timeoutId),!1)),this._didWork=!0}}getPendingTasks(){return this.taskTrackingZone?this.taskTrackingZone.macroTasks.map(t=>({source:t.source,creationLocation:t.creationLocation,data:t.data})):[]}addCallback(t,i,r){let o=-1;i&&i>0&&(o=setTimeout(()=>{this._callbacks=this._callbacks.filter(s=>s.timeoutId!==o),t(this._didWork,this.getPendingTasks())},i)),this._callbacks.push({doneCb:t,timeoutId:o,updateCb:r})}whenStable(t,i,r){if(r&&!this.taskTrackingZone)throw new Error('Task tracking zone is required when passing an update callback to whenStable(). Is "zone.js/plugins/task-tracking" loaded?');this.addCallback(t,i,r),this._runCallbacksIfReady()}getPendingRequestCount(){return this._pendingCount}registerApplication(t){this.registry.registerApplication(t,this)}unregisterApplication(t){this.registry.unregisterApplication(t)}findProviders(t,i,r){return[]}}return e.\u0275fac=function(t){return new(t||e)(L(Ye),L(gm),L(Ld))},e.\u0275prov=U({token:e,factory:e.\u0275fac}),e})(),gm=(()=>{class e{constructor(){this._applications=new Map}registerApplication(t,i){this._applications.set(t,i)}unregisterApplication(t){this._applications.delete(t)}unregisterAllApplications(){this._applications.clear()}getTestability(t){return this._applications.get(t)||null}getAllTestabilities(){return Array.from(this._applications.values())}getAllRootElements(){return Array.from(this._applications.keys())}findTestabilityInTree(t,i=!0){return mm?.findTestabilityInTree(this,t,i)??null}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=U({token:e,factory:e.\u0275fac,providedIn:"platform"}),e})(),po=null;const Y1=new Y("AllowMultipleToken"),_m=new Y("PlatformDestroyListeners");class q1{constructor(n,t){this.name=n,this.token=t}}function Z1(e,n,t=[]){const i=`Platform: ${n}`,r=new Y(i);return(o=[])=>{let s=vm();if(!s||s.injector.get(Y1,!1)){const a=[...t,...o,{provide:r,useValue:!0}];e?e(a):function fx(e){if(po&&!po.get(Y1,!1))throw new F(400,!1);po=e;const n=e.get(X1);(function J1(e){const n=e.get(j1,null);n&&n.forEach(t=>t())})(e)}(function Q1(e=[],n){return _n.create({name:n,providers:[{provide:Jp,useValue:"platform"},{provide:_m,useValue:new Set([()=>po=null])},...e]})}(a,i))}return function px(e){const n=vm();if(!n)throw new F(401,!1);return n}()}}function vm(){return po?.get(X1)??null}let X1=(()=>{class e{constructor(t){this._injector=t,this._modules=[],this._destroyListeners=[],this._destroyed=!1}bootstrapModuleFactory(t,i){const r=function tC(e,n){let t;return t="noop"===e?new lx:("zone.js"===e?void 0:e)||new Ye(n),t}(i?.ngZone,function eC(e){return{enableLongStackTrace:!1,shouldCoalesceEventChangeDetection:!(!e||!e.ngZoneEventCoalescing)||!1,shouldCoalesceRunChangeDetection:!(!e||!e.ngZoneRunCoalescing)||!1}}(i)),o=[{provide:Ye,useValue:r}];return r.run(()=>{const s=_n.create({providers:o,parent:this.injector,name:t.moduleType.name}),a=t.create(s),l=a.injector.get(ha,null);if(!l)throw new F(402,!1);return r.runOutsideAngular(()=>{const u=r.onError.subscribe({next:f=>{l.handleError(f)}});a.onDestroy(()=>{Vd(this._modules,a),u.unsubscribe()})}),function nC(e,n,t){try{const i=t();return ql(i)?i.catch(r=>{throw n.runOutsideAngular(()=>e.handleError(r)),r}):i}catch(i){throw n.runOutsideAngular(()=>e.handleError(i)),i}}(l,r,()=>{const u=a.injector.get(Pd);return u.runInitializers(),u.donePromise.then(()=>(function ND(e){Mn(e,"Expected localeId to be defined"),"string"==typeof e&&(TD=e.toLowerCase().replace(/_/g,"-"))}(a.injector.get(xr,Ia)||Ia),this._moduleDoBootstrap(a),a))})})}bootstrapModule(t,i=[]){const r=iC({},i);return function ux(e,n,t){const i=new qg(t);return Promise.resolve(i)}(0,0,t).then(o=>this.bootstrapModuleFactory(o,r))}_moduleDoBootstrap(t){const i=t.injector.get(lc);if(t._bootstrapComponents.length>0)t._bootstrapComponents.forEach(r=>i.bootstrap(r));else{if(!t.instance.ngDoBootstrap)throw new F(403,!1);t.instance.ngDoBootstrap(i)}this._modules.push(t)}onDestroy(t){this._destroyListeners.push(t)}get injector(){return this._injector}destroy(){if(this._destroyed)throw new F(404,!1);this._modules.slice().forEach(i=>i.destroy()),this._destroyListeners.forEach(i=>i());const t=this._injector.get(_m,null);t&&(t.forEach(i=>i()),t.clear()),this._destroyed=!0}get destroyed(){return this._destroyed}}return e.\u0275fac=function(t){return new(t||e)(L(_n))},e.\u0275prov=U({token:e,factory:e.\u0275fac,providedIn:"platform"}),e})();function iC(e,n){return Array.isArray(n)?n.reduce(iC,e):{...e,...n}}let lc=(()=>{class e{constructor(t,i,r){this._zone=t,this._injector=i,this._exceptionHandler=r,this._bootstrapListeners=[],this._views=[],this._runningTick=!1,this._stable=!0,this._destroyed=!1,this._destroyListeners=[],this.componentTypes=[],this.components=[],this._onMicrotaskEmptySubscription=this._zone.onMicrotaskEmpty.subscribe({next:()=>{this._zone.run(()=>{this.tick()})}});const o=new Ve(a=>{this._stable=this._zone.isStable&&!this._zone.hasPendingMacrotasks&&!this._zone.hasPendingMicrotasks,this._zone.runOutsideAngular(()=>{a.next(this._stable),a.complete()})}),s=new Ve(a=>{let l;this._zone.runOutsideAngular(()=>{l=this._zone.onStable.subscribe(()=>{Ye.assertNotInAngularZone(),dm(()=>{!this._stable&&!this._zone.hasPendingMacrotasks&&!this._zone.hasPendingMicrotasks&&(this._stable=!0,a.next(!0))})})});const u=this._zone.onUnstable.subscribe(()=>{Ye.assertInAngularZone(),this._stable&&(this._stable=!1,this._zone.runOutsideAngular(()=>{a.next(!1)}))});return()=>{l.unsubscribe(),u.unsubscribe()}});this.isStable=function Dh(...e){const n=Fo(e),t=function mu(e,n){return"number"==typeof tt(e)?e.pop():n}(e,1/0),i=e;return i.length?1===i.length?Et(i[0]):fn(t)(dt(i,n)):Ft}(o,s.pipe(function Ch(e={}){const{connector:n=(()=>new je),resetOnError:t=!0,resetOnComplete:i=!0,resetOnRefCountZero:r=!0}=e;return o=>{let s,a,l,u=0,f=!1,p=!1;const m=()=>{a?.unsubscribe(),a=void 0},v=()=>{m(),s=l=void 0,f=p=!1},y=()=>{const D=s;v(),D?.unsubscribe()};return qe((D,w)=>{u++,!p&&!f&&m();const S=l=l??n();w.add(()=>{u--,0===u&&!p&&!f&&(a=Os(y,r))}),S.subscribe(w),!s&&u>0&&(s=new mr({next:O=>S.next(O),error:O=>{p=!0,m(),a=Os(v,t,O),S.error(O)},complete:()=>{f=!0,m(),a=Os(v,i),S.complete()}}),Et(D).subscribe(s))})(o)}}()))}get destroyed(){return this._destroyed}get injector(){return this._injector}bootstrap(t,i){const r=t instanceof A0;if(!this._injector.get(Pd).done)throw!r&&function Zr(e){const n=Re(e)||Xt(e)||en(e);return null!==n&&n.standalone}(t),new F(405,false);let s;s=r?t:this._injector.get(Ul).resolveComponentFactory(t),this.componentTypes.push(s.componentType);const a=function dx(e){return e.isBoundToModule}(s)?void 0:this._injector.get(ns),u=s.create(_n.NULL,[],i||s.selector,a),f=u.location.nativeElement,p=u.injector.get(z1,null);return p?.registerApplication(f),u.onDestroy(()=>{this.detachView(u.hostView),Vd(this.components,u),p?.unregisterApplication(f)}),this._loadComponent(u),u}tick(){if(this._runningTick)throw new F(101,!1);try{this._runningTick=!0;for(let t of this._views)t.detectChanges()}catch(t){this._zone.runOutsideAngular(()=>this._exceptionHandler.handleError(t))}finally{this._runningTick=!1}}attachView(t){const i=t;this._views.push(i),i.attachToAppRef(this)}detachView(t){const i=t;Vd(this._views,i),i.detachFromAppRef()}_loadComponent(t){this.attachView(t.hostView),this.tick(),this.components.push(t),this._injector.get($1,[]).concat(this._bootstrapListeners).forEach(r=>r(t))}ngOnDestroy(){if(!this._destroyed)try{this._destroyListeners.forEach(t=>t()),this._views.slice().forEach(t=>t.destroy()),this._onMicrotaskEmptySubscription.unsubscribe()}finally{this._destroyed=!0,this._views=[],this._bootstrapListeners=[],this._destroyListeners=[]}}onDestroy(t){return this._destroyListeners.push(t),()=>Vd(this._destroyListeners,t)}destroy(){if(this._destroyed)throw new F(406,!1);const t=this._injector;t.destroy&&!t.destroyed&&t.destroy()}get viewCount(){return this._views.length}warnIfDestroyed(){}}return e.\u0275fac=function(t){return new(t||e)(L(Ye),L(co),L(ha))},e.\u0275prov=U({token:e,factory:e.\u0275fac,providedIn:"root"}),e})();function Vd(e,n){const t=e.indexOf(n);t>-1&&e.splice(t,1)}let Pr=(()=>{class e{}return e.__NG_ELEMENT_ID__=_x,e})();function _x(e){return function vx(e,n,t){if(pn(e)&&!t){const i=In(e.index,n);return new Wl(i,i)}return 47&e.type?new Wl(n[16],n):null}(yt(),k(),16==(16&e))}class uC{constructor(){}supports(n){return zl(n)}create(n){return new Sx(n)}}const wx=(e,n)=>n;class Sx{constructor(n){this.length=0,this._linkedRecords=null,this._unlinkedRecords=null,this._previousItHead=null,this._itHead=null,this._itTail=null,this._additionsHead=null,this._additionsTail=null,this._movesHead=null,this._movesTail=null,this._removalsHead=null,this._removalsTail=null,this._identityChangesHead=null,this._identityChangesTail=null,this._trackByFn=n||wx}forEachItem(n){let t;for(t=this._itHead;null!==t;t=t._next)n(t)}forEachOperation(n){let t=this._itHead,i=this._removalsHead,r=0,o=null;for(;t||i;){const s=!i||t&&t.currentIndex{s=this._trackByFn(r,a),null!==t&&Object.is(t.trackById,s)?(i&&(t=this._verifyReinsertion(t,a,s,r)),Object.is(t.item,a)||this._addIdentityChange(t,a)):(t=this._mismatch(t,a,s,r),i=!0),t=t._next,r++}),this.length=r;return this._truncate(t),this.collection=n,this.isDirty}get isDirty(){return null!==this._additionsHead||null!==this._movesHead||null!==this._removalsHead||null!==this._identityChangesHead}_reset(){if(this.isDirty){let n;for(n=this._previousItHead=this._itHead;null!==n;n=n._next)n._nextPrevious=n._next;for(n=this._additionsHead;null!==n;n=n._nextAdded)n.previousIndex=n.currentIndex;for(this._additionsHead=this._additionsTail=null,n=this._movesHead;null!==n;n=n._nextMoved)n.previousIndex=n.currentIndex;this._movesHead=this._movesTail=null,this._removalsHead=this._removalsTail=null,this._identityChangesHead=this._identityChangesTail=null}}_mismatch(n,t,i,r){let o;return null===n?o=this._itTail:(o=n._prev,this._remove(n)),null!==(n=null===this._unlinkedRecords?null:this._unlinkedRecords.get(i,null))?(Object.is(n.item,t)||this._addIdentityChange(n,t),this._reinsertAfter(n,o,r)):null!==(n=null===this._linkedRecords?null:this._linkedRecords.get(i,r))?(Object.is(n.item,t)||this._addIdentityChange(n,t),this._moveAfter(n,o,r)):n=this._addAfter(new Ex(t,i),o,r),n}_verifyReinsertion(n,t,i,r){let o=null===this._unlinkedRecords?null:this._unlinkedRecords.get(i,null);return null!==o?n=this._reinsertAfter(o,n._prev,r):n.currentIndex!=r&&(n.currentIndex=r,this._addToMoves(n,r)),n}_truncate(n){for(;null!==n;){const t=n._next;this._addToRemovals(this._unlink(n)),n=t}null!==this._unlinkedRecords&&this._unlinkedRecords.clear(),null!==this._additionsTail&&(this._additionsTail._nextAdded=null),null!==this._movesTail&&(this._movesTail._nextMoved=null),null!==this._itTail&&(this._itTail._next=null),null!==this._removalsTail&&(this._removalsTail._nextRemoved=null),null!==this._identityChangesTail&&(this._identityChangesTail._nextIdentityChange=null)}_reinsertAfter(n,t,i){null!==this._unlinkedRecords&&this._unlinkedRecords.remove(n);const r=n._prevRemoved,o=n._nextRemoved;return null===r?this._removalsHead=o:r._nextRemoved=o,null===o?this._removalsTail=r:o._prevRemoved=r,this._insertAfter(n,t,i),this._addToMoves(n,i),n}_moveAfter(n,t,i){return this._unlink(n),this._insertAfter(n,t,i),this._addToMoves(n,i),n}_addAfter(n,t,i){return this._insertAfter(n,t,i),this._additionsTail=null===this._additionsTail?this._additionsHead=n:this._additionsTail._nextAdded=n,n}_insertAfter(n,t,i){const r=null===t?this._itHead:t._next;return n._next=r,n._prev=t,null===r?this._itTail=n:r._prev=n,null===t?this._itHead=n:t._next=n,null===this._linkedRecords&&(this._linkedRecords=new dC),this._linkedRecords.put(n),n.currentIndex=i,n}_remove(n){return this._addToRemovals(this._unlink(n))}_unlink(n){null!==this._linkedRecords&&this._linkedRecords.remove(n);const t=n._prev,i=n._next;return null===t?this._itHead=i:t._next=i,null===i?this._itTail=t:i._prev=t,n}_addToMoves(n,t){return n.previousIndex===t||(this._movesTail=null===this._movesTail?this._movesHead=n:this._movesTail._nextMoved=n),n}_addToRemovals(n){return null===this._unlinkedRecords&&(this._unlinkedRecords=new dC),this._unlinkedRecords.put(n),n.currentIndex=null,n._nextRemoved=null,null===this._removalsTail?(this._removalsTail=this._removalsHead=n,n._prevRemoved=null):(n._prevRemoved=this._removalsTail,this._removalsTail=this._removalsTail._nextRemoved=n),n}_addIdentityChange(n,t){return n.item=t,this._identityChangesTail=null===this._identityChangesTail?this._identityChangesHead=n:this._identityChangesTail._nextIdentityChange=n,n}}class Ex{constructor(n,t){this.item=n,this.trackById=t,this.currentIndex=null,this.previousIndex=null,this._nextPrevious=null,this._prev=null,this._next=null,this._prevDup=null,this._nextDup=null,this._prevRemoved=null,this._nextRemoved=null,this._nextAdded=null,this._nextMoved=null,this._nextIdentityChange=null}}class Mx{constructor(){this._head=null,this._tail=null}add(n){null===this._head?(this._head=this._tail=n,n._nextDup=null,n._prevDup=null):(this._tail._nextDup=n,n._prevDup=this._tail,n._nextDup=null,this._tail=n)}get(n,t){let i;for(i=this._head;null!==i;i=i._nextDup)if((null===t||t<=i.currentIndex)&&Object.is(i.trackById,n))return i;return null}remove(n){const t=n._prevDup,i=n._nextDup;return null===t?this._head=i:t._nextDup=i,null===i?this._tail=t:i._prevDup=t,null===this._head}}class dC{constructor(){this.map=new Map}put(n){const t=n.trackById;let i=this.map.get(t);i||(i=new Mx,this.map.set(t,i)),i.add(n)}get(n,t){const r=this.map.get(n);return r?r.get(n,t):null}remove(n){const t=n.trackById;return this.map.get(t).remove(n)&&this.map.delete(t),n}get isEmpty(){return 0===this.map.size}clear(){this.map.clear()}}function fC(e,n,t){const i=e.previousIndex;if(null===i)return i;let r=0;return t&&i{if(t&&t.key===r)this._maybeAddToChanges(t,i),this._appendAfter=t,t=t._next;else{const o=this._getOrCreateRecordForKey(r,i);t=this._insertBeforeOrAppend(t,o)}}),t){t._prev&&(t._prev._next=null),this._removalsHead=t;for(let i=t;null!==i;i=i._nextRemoved)i===this._mapHead&&(this._mapHead=null),this._records.delete(i.key),i._nextRemoved=i._next,i.previousValue=i.currentValue,i.currentValue=null,i._prev=null,i._next=null}return this._changesTail&&(this._changesTail._nextChanged=null),this._additionsTail&&(this._additionsTail._nextAdded=null),this.isDirty}_insertBeforeOrAppend(n,t){if(n){const i=n._prev;return t._next=n,t._prev=i,n._prev=t,i&&(i._next=t),n===this._mapHead&&(this._mapHead=t),this._appendAfter=n,n}return this._appendAfter?(this._appendAfter._next=t,t._prev=this._appendAfter):this._mapHead=t,this._appendAfter=t,null}_getOrCreateRecordForKey(n,t){if(this._records.has(n)){const r=this._records.get(n);this._maybeAddToChanges(r,t);const o=r._prev,s=r._next;return o&&(o._next=s),s&&(s._prev=o),r._next=null,r._prev=null,r}const i=new Nx(n);return this._records.set(n,i),i.currentValue=t,this._addToAdditions(i),i}_reset(){if(this.isDirty){let n;for(this._previousMapHead=this._mapHead,n=this._previousMapHead;null!==n;n=n._next)n._nextPrevious=n._next;for(n=this._changesHead;null!==n;n=n._nextChanged)n.previousValue=n.currentValue;for(n=this._additionsHead;null!=n;n=n._nextAdded)n.previousValue=n.currentValue;this._changesHead=this._changesTail=null,this._additionsHead=this._additionsTail=null,this._removalsHead=null}}_maybeAddToChanges(n,t){Object.is(t,n.currentValue)||(n.previousValue=n.currentValue,n.currentValue=t,this._addToChanges(n))}_addToAdditions(n){null===this._additionsHead?this._additionsHead=this._additionsTail=n:(this._additionsTail._nextAdded=n,this._additionsTail=n)}_addToChanges(n){null===this._changesHead?this._changesHead=this._changesTail=n:(this._changesTail._nextChanged=n,this._changesTail=n)}_forEach(n,t){n instanceof Map?n.forEach(t):Object.keys(n).forEach(i=>t(n[i],i))}}class Nx{constructor(n){this.key=n,this.previousValue=null,this.currentValue=null,this._nextPrevious=null,this._next=null,this._prev=null,this._nextAdded=null,this._nextRemoved=null,this._nextChanged=null}}function pC(){return new jd([new uC])}let jd=(()=>{class e{constructor(t){this.factories=t}static create(t,i){if(null!=i){const r=i.factories.slice();t=t.concat(r)}return new e(t)}static extend(t){return{provide:e,useFactory:i=>e.create(t,i||pC()),deps:[[e,new xl,new Rl]]}}find(t){const i=this.factories.find(r=>r.supports(t));if(null!=i)return i;throw new F(901,!1)}}return e.\u0275prov=U({token:e,providedIn:"root",factory:pC}),e})();function gC(){return new cc([new hC])}let cc=(()=>{class e{constructor(t){this.factories=t}static create(t,i){if(i){const r=i.factories.slice();t=t.concat(r)}return new e(t)}static extend(t){return{provide:e,useFactory:i=>e.create(t,i||gC()),deps:[[e,new xl,new Rl]]}}find(t){const i=this.factories.find(r=>r.supports(t));if(i)return i;throw new F(901,!1)}}return e.\u0275prov=U({token:e,providedIn:"root",factory:gC}),e})();const Ox=Z1(null,"core",[]);let kx=(()=>{class e{constructor(t){}}return e.\u0275fac=function(t){return new(t||e)(L(lc))},e.\u0275mod=ge({type:e}),e.\u0275inj=Me({}),e})();function wm(e,n){const t=Re(e),i=n.elementInjector||ad();return new Kl(t).create(i,n.projectableNodes,n.hostElement,n.environmentInjector)}let $d=null;function sr(){return $d}const mt=new Y("DocumentToken");let Sm=(()=>{class e{historyGo(t){throw new Error("Not implemented")}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=U({token:e,factory:function(){return function Px(){return L(mC)}()},providedIn:"platform"}),e})();const Lx=new Y("Location Initialized");let mC=(()=>{class e extends Sm{constructor(t){super(),this._doc=t,this._init()}_init(){this.location=window.location,this._history=window.history}getBaseHrefFromDOM(){return sr().getBaseHref(this._doc)}onPopState(t){const i=sr().getGlobalEventTarget(this._doc,"window");return i.addEventListener("popstate",t,!1),()=>i.removeEventListener("popstate",t)}onHashChange(t){const i=sr().getGlobalEventTarget(this._doc,"window");return i.addEventListener("hashchange",t,!1),()=>i.removeEventListener("hashchange",t)}get href(){return this.location.href}get protocol(){return this.location.protocol}get hostname(){return this.location.hostname}get port(){return this.location.port}get pathname(){return this.location.pathname}get search(){return this.location.search}get hash(){return this.location.hash}set pathname(t){this.location.pathname=t}pushState(t,i,r){_C()?this._history.pushState(t,i,r):this.location.hash=r}replaceState(t,i,r){_C()?this._history.replaceState(t,i,r):this.location.hash=r}forward(){this._history.forward()}back(){this._history.back()}historyGo(t=0){this._history.go(t)}getState(){return this._history.state}}return e.\u0275fac=function(t){return new(t||e)(L(mt))},e.\u0275prov=U({token:e,factory:function(){return function Vx(){return new mC(L(mt))}()},providedIn:"platform"}),e})();function _C(){return!!window.history.pushState}function Em(e,n){if(0==e.length)return n;if(0==n.length)return e;let t=0;return e.endsWith("/")&&t++,n.startsWith("/")&&t++,2==t?e+n.substring(1):1==t?e+n:e+"/"+n}function vC(e){const n=e.match(/#|\?|$/),t=n&&n.index||e.length;return e.slice(0,t-("/"===e[t-1]?1:0))+e.slice(t)}function Vr(e){return e&&"?"!==e[0]?"?"+e:e}let rs=(()=>{class e{historyGo(t){throw new Error("Not implemented")}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=U({token:e,factory:function(){return bt(bC)},providedIn:"root"}),e})();const yC=new Y("appBaseHref");let bC=(()=>{class e extends rs{constructor(t,i){super(),this._platformLocation=t,this._removeListenerFns=[],this._baseHref=i??this._platformLocation.getBaseHrefFromDOM()??bt(mt).location?.origin??""}ngOnDestroy(){for(;this._removeListenerFns.length;)this._removeListenerFns.pop()()}onPopState(t){this._removeListenerFns.push(this._platformLocation.onPopState(t),this._platformLocation.onHashChange(t))}getBaseHref(){return this._baseHref}prepareExternalUrl(t){return Em(this._baseHref,t)}path(t=!1){const i=this._platformLocation.pathname+Vr(this._platformLocation.search),r=this._platformLocation.hash;return r&&t?`${i}${r}`:i}pushState(t,i,r,o){const s=this.prepareExternalUrl(r+Vr(o));this._platformLocation.pushState(t,i,s)}replaceState(t,i,r,o){const s=this.prepareExternalUrl(r+Vr(o));this._platformLocation.replaceState(t,i,s)}forward(){this._platformLocation.forward()}back(){this._platformLocation.back()}getState(){return this._platformLocation.getState()}historyGo(t=0){this._platformLocation.historyGo?.(t)}}return e.\u0275fac=function(t){return new(t||e)(L(Sm),L(yC,8))},e.\u0275prov=U({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(),Hx=(()=>{class e extends rs{constructor(t,i){super(),this._platformLocation=t,this._baseHref="",this._removeListenerFns=[],null!=i&&(this._baseHref=i)}ngOnDestroy(){for(;this._removeListenerFns.length;)this._removeListenerFns.pop()()}onPopState(t){this._removeListenerFns.push(this._platformLocation.onPopState(t),this._platformLocation.onHashChange(t))}getBaseHref(){return this._baseHref}path(t=!1){let i=this._platformLocation.hash;return null==i&&(i="#"),i.length>0?i.substring(1):i}prepareExternalUrl(t){const i=Em(this._baseHref,t);return i.length>0?"#"+i:i}pushState(t,i,r,o){let s=this.prepareExternalUrl(r+Vr(o));0==s.length&&(s=this._platformLocation.pathname),this._platformLocation.pushState(t,i,s)}replaceState(t,i,r,o){let s=this.prepareExternalUrl(r+Vr(o));0==s.length&&(s=this._platformLocation.pathname),this._platformLocation.replaceState(t,i,s)}forward(){this._platformLocation.forward()}back(){this._platformLocation.back()}getState(){return this._platformLocation.getState()}historyGo(t=0){this._platformLocation.historyGo?.(t)}}return e.\u0275fac=function(t){return new(t||e)(L(Sm),L(yC,8))},e.\u0275prov=U({token:e,factory:e.\u0275fac}),e})(),Mm=(()=>{class e{constructor(t){this._subject=new de,this._urlChangeListeners=[],this._urlChangeSubscription=null,this._locationStrategy=t;const i=this._locationStrategy.getBaseHref();this._baseHref=vC(DC(i)),this._locationStrategy.onPopState(r=>{this._subject.emit({url:this.path(!0),pop:!0,state:r.state,type:r.type})})}ngOnDestroy(){this._urlChangeSubscription?.unsubscribe(),this._urlChangeListeners=[]}path(t=!1){return this.normalize(this._locationStrategy.path(t))}getState(){return this._locationStrategy.getState()}isCurrentPathEqualTo(t,i=""){return this.path()==this.normalize(t+Vr(i))}normalize(t){return e.stripTrailingSlash(function jx(e,n){return e&&n.startsWith(e)?n.substring(e.length):n}(this._baseHref,DC(t)))}prepareExternalUrl(t){return t&&"/"!==t[0]&&(t="/"+t),this._locationStrategy.prepareExternalUrl(t)}go(t,i="",r=null){this._locationStrategy.pushState(r,"",t,i),this._notifyUrlChangeListeners(this.prepareExternalUrl(t+Vr(i)),r)}replaceState(t,i="",r=null){this._locationStrategy.replaceState(r,"",t,i),this._notifyUrlChangeListeners(this.prepareExternalUrl(t+Vr(i)),r)}forward(){this._locationStrategy.forward()}back(){this._locationStrategy.back()}historyGo(t=0){this._locationStrategy.historyGo?.(t)}onUrlChange(t){return this._urlChangeListeners.push(t),this._urlChangeSubscription||(this._urlChangeSubscription=this.subscribe(i=>{this._notifyUrlChangeListeners(i.url,i.state)})),()=>{const i=this._urlChangeListeners.indexOf(t);this._urlChangeListeners.splice(i,1),0===this._urlChangeListeners.length&&(this._urlChangeSubscription?.unsubscribe(),this._urlChangeSubscription=null)}}_notifyUrlChangeListeners(t="",i){this._urlChangeListeners.forEach(r=>r(t,i))}subscribe(t,i,r){return this._subject.subscribe({next:t,error:i,complete:r})}}return e.normalizeQueryParams=Vr,e.joinWithSlash=Em,e.stripTrailingSlash=vC,e.\u0275fac=function(t){return new(t||e)(L(rs))},e.\u0275prov=U({token:e,factory:function(){return function Bx(){return new Mm(L(rs))}()},providedIn:"root"}),e})();function DC(e){return e.replace(/\/index.html$/,"")}var Ct=(()=>((Ct=Ct||{})[Ct.Format=0]="Format",Ct[Ct.Standalone=1]="Standalone",Ct))(),ye=(()=>((ye=ye||{})[ye.Narrow=0]="Narrow",ye[ye.Abbreviated=1]="Abbreviated",ye[ye.Wide=2]="Wide",ye[ye.Short=3]="Short",ye))(),ut=(()=>((ut=ut||{})[ut.Short=0]="Short",ut[ut.Medium=1]="Medium",ut[ut.Long=2]="Long",ut[ut.Full=3]="Full",ut))(),ne=(()=>((ne=ne||{})[ne.Decimal=0]="Decimal",ne[ne.Group=1]="Group",ne[ne.List=2]="List",ne[ne.PercentSign=3]="PercentSign",ne[ne.PlusSign=4]="PlusSign",ne[ne.MinusSign=5]="MinusSign",ne[ne.Exponential=6]="Exponential",ne[ne.SuperscriptingExponent=7]="SuperscriptingExponent",ne[ne.PerMille=8]="PerMille",ne[ne.Infinity=9]="Infinity",ne[ne.NaN=10]="NaN",ne[ne.TimeSeparator=11]="TimeSeparator",ne[ne.CurrencyDecimal=12]="CurrencyDecimal",ne[ne.CurrencyGroup=13]="CurrencyGroup",ne))();function Ud(e,n){return hi(kn(e)[j.DateFormat],n)}function Gd(e,n){return hi(kn(e)[j.TimeFormat],n)}function Wd(e,n){return hi(kn(e)[j.DateTimeFormat],n)}function fi(e,n){const t=kn(e),i=t[j.NumberSymbols][n];if(typeof i>"u"){if(n===ne.CurrencyDecimal)return t[j.NumberSymbols][ne.Decimal];if(n===ne.CurrencyGroup)return t[j.NumberSymbols][ne.Group]}return i}function wC(e){if(!e[j.ExtraData])throw new Error(`Missing extra locale data for the locale "${e[j.LocaleId]}". Use "registerLocaleData" to load new data. See the "I18n guide" on angular.io to know more.`)}function hi(e,n){for(let t=n;t>-1;t--)if(typeof e[t]<"u")return e[t];throw new Error("Locale data API: locale data undefined")}function Nm(e){const[n,t]=e.split(":");return{hours:+n,minutes:+t}}const eF=/^(\d{4,})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/,uc={},tF=/((?:[^BEGHLMOSWYZabcdhmswyz']+)|(?:'(?:[^']|'')*')|(?:G{1,5}|y{1,4}|Y{1,4}|M{1,5}|L{1,5}|w{1,2}|W{1}|d{1,2}|E{1,6}|c{1,6}|a{1,5}|b{1,5}|B{1,5}|h{1,2}|H{1,2}|m{1,2}|s{1,2}|S{1,3}|z{1,4}|Z{1,5}|O{1,4}))([\s\S]*)/;var Vt=(()=>((Vt=Vt||{})[Vt.Short=0]="Short",Vt[Vt.ShortGMT=1]="ShortGMT",Vt[Vt.Long=2]="Long",Vt[Vt.Extended=3]="Extended",Vt))(),re=(()=>((re=re||{})[re.FullYear=0]="FullYear",re[re.Month=1]="Month",re[re.Date=2]="Date",re[re.Hours=3]="Hours",re[re.Minutes=4]="Minutes",re[re.Seconds=5]="Seconds",re[re.FractionalSeconds=6]="FractionalSeconds",re[re.Day=7]="Day",re))(),fe=(()=>((fe=fe||{})[fe.DayPeriods=0]="DayPeriods",fe[fe.Days=1]="Days",fe[fe.Months=2]="Months",fe[fe.Eras=3]="Eras",fe))();function nF(e,n,t,i){let r=function dF(e){if(MC(e))return e;if("number"==typeof e&&!isNaN(e))return new Date(e);if("string"==typeof e){if(e=e.trim(),/^(\d{4}(-\d{1,2}(-\d{1,2})?)?)$/.test(e)){const[r,o=1,s=1]=e.split("-").map(a=>+a);return Kd(r,o-1,s)}const t=parseFloat(e);if(!isNaN(e-t))return new Date(t);let i;if(i=e.match(eF))return function fF(e){const n=new Date(0);let t=0,i=0;const r=e[8]?n.setUTCFullYear:n.setFullYear,o=e[8]?n.setUTCHours:n.setHours;e[9]&&(t=Number(e[9]+e[10]),i=Number(e[9]+e[11])),r.call(n,Number(e[1]),Number(e[2])-1,Number(e[3]));const s=Number(e[4]||0)-t,a=Number(e[5]||0)-i,l=Number(e[6]||0),u=Math.floor(1e3*parseFloat("0."+(e[7]||0)));return o.call(n,s,a,l,u),n}(i)}const n=new Date(e);if(!MC(n))throw new Error(`Unable to convert "${e}" into a date`);return n}(e);n=Hr(t,n)||n;let a,s=[];for(;n;){if(a=tF.exec(n),!a){s.push(n);break}{s=s.concat(a.slice(1));const f=s.pop();if(!f)break;n=f}}let l=r.getTimezoneOffset();i&&(l=EC(i,l),r=function uF(e,n,t){const i=t?-1:1,r=e.getTimezoneOffset();return function cF(e,n){return(e=new Date(e.getTime())).setMinutes(e.getMinutes()+n),e}(e,i*(EC(n,r)-r))}(r,i,!0));let u="";return s.forEach(f=>{const p=function lF(e){if(Im[e])return Im[e];let n;switch(e){case"G":case"GG":case"GGG":n=Xe(fe.Eras,ye.Abbreviated);break;case"GGGG":n=Xe(fe.Eras,ye.Wide);break;case"GGGGG":n=Xe(fe.Eras,ye.Narrow);break;case"y":n=kt(re.FullYear,1,0,!1,!0);break;case"yy":n=kt(re.FullYear,2,0,!0,!0);break;case"yyy":n=kt(re.FullYear,3,0,!1,!0);break;case"yyyy":n=kt(re.FullYear,4,0,!1,!0);break;case"Y":n=Jd(1);break;case"YY":n=Jd(2,!0);break;case"YYY":n=Jd(3);break;case"YYYY":n=Jd(4);break;case"M":case"L":n=kt(re.Month,1,1);break;case"MM":case"LL":n=kt(re.Month,2,1);break;case"MMM":n=Xe(fe.Months,ye.Abbreviated);break;case"MMMM":n=Xe(fe.Months,ye.Wide);break;case"MMMMM":n=Xe(fe.Months,ye.Narrow);break;case"LLL":n=Xe(fe.Months,ye.Abbreviated,Ct.Standalone);break;case"LLLL":n=Xe(fe.Months,ye.Wide,Ct.Standalone);break;case"LLLLL":n=Xe(fe.Months,ye.Narrow,Ct.Standalone);break;case"w":n=Am(1);break;case"ww":n=Am(2);break;case"W":n=Am(1,!0);break;case"d":n=kt(re.Date,1);break;case"dd":n=kt(re.Date,2);break;case"c":case"cc":n=kt(re.Day,1);break;case"ccc":n=Xe(fe.Days,ye.Abbreviated,Ct.Standalone);break;case"cccc":n=Xe(fe.Days,ye.Wide,Ct.Standalone);break;case"ccccc":n=Xe(fe.Days,ye.Narrow,Ct.Standalone);break;case"cccccc":n=Xe(fe.Days,ye.Short,Ct.Standalone);break;case"E":case"EE":case"EEE":n=Xe(fe.Days,ye.Abbreviated);break;case"EEEE":n=Xe(fe.Days,ye.Wide);break;case"EEEEE":n=Xe(fe.Days,ye.Narrow);break;case"EEEEEE":n=Xe(fe.Days,ye.Short);break;case"a":case"aa":case"aaa":n=Xe(fe.DayPeriods,ye.Abbreviated);break;case"aaaa":n=Xe(fe.DayPeriods,ye.Wide);break;case"aaaaa":n=Xe(fe.DayPeriods,ye.Narrow);break;case"b":case"bb":case"bbb":n=Xe(fe.DayPeriods,ye.Abbreviated,Ct.Standalone,!0);break;case"bbbb":n=Xe(fe.DayPeriods,ye.Wide,Ct.Standalone,!0);break;case"bbbbb":n=Xe(fe.DayPeriods,ye.Narrow,Ct.Standalone,!0);break;case"B":case"BB":case"BBB":n=Xe(fe.DayPeriods,ye.Abbreviated,Ct.Format,!0);break;case"BBBB":n=Xe(fe.DayPeriods,ye.Wide,Ct.Format,!0);break;case"BBBBB":n=Xe(fe.DayPeriods,ye.Narrow,Ct.Format,!0);break;case"h":n=kt(re.Hours,1,-12);break;case"hh":n=kt(re.Hours,2,-12);break;case"H":n=kt(re.Hours,1);break;case"HH":n=kt(re.Hours,2);break;case"m":n=kt(re.Minutes,1);break;case"mm":n=kt(re.Minutes,2);break;case"s":n=kt(re.Seconds,1);break;case"ss":n=kt(re.Seconds,2);break;case"S":n=kt(re.FractionalSeconds,1);break;case"SS":n=kt(re.FractionalSeconds,2);break;case"SSS":n=kt(re.FractionalSeconds,3);break;case"Z":case"ZZ":case"ZZZ":n=Yd(Vt.Short);break;case"ZZZZZ":n=Yd(Vt.Extended);break;case"O":case"OO":case"OOO":case"z":case"zz":case"zzz":n=Yd(Vt.ShortGMT);break;case"OOOO":case"ZZZZ":case"zzzz":n=Yd(Vt.Long);break;default:return null}return Im[e]=n,n}(f);u+=p?p(r,t,l):"''"===f?"'":f.replace(/(^'|'$)/g,"").replace(/''/g,"'")}),u}function Kd(e,n,t){const i=new Date(0);return i.setFullYear(e,n,t),i.setHours(0,0,0),i}function Hr(e,n){const t=function $x(e){return kn(e)[j.LocaleId]}(e);if(uc[t]=uc[t]||{},uc[t][n])return uc[t][n];let i="";switch(n){case"shortDate":i=Ud(e,ut.Short);break;case"mediumDate":i=Ud(e,ut.Medium);break;case"longDate":i=Ud(e,ut.Long);break;case"fullDate":i=Ud(e,ut.Full);break;case"shortTime":i=Gd(e,ut.Short);break;case"mediumTime":i=Gd(e,ut.Medium);break;case"longTime":i=Gd(e,ut.Long);break;case"fullTime":i=Gd(e,ut.Full);break;case"short":const r=Hr(e,"shortTime"),o=Hr(e,"shortDate");i=zd(Wd(e,ut.Short),[r,o]);break;case"medium":const s=Hr(e,"mediumTime"),a=Hr(e,"mediumDate");i=zd(Wd(e,ut.Medium),[s,a]);break;case"long":const l=Hr(e,"longTime"),u=Hr(e,"longDate");i=zd(Wd(e,ut.Long),[l,u]);break;case"full":const f=Hr(e,"fullTime"),p=Hr(e,"fullDate");i=zd(Wd(e,ut.Full),[f,p])}return i&&(uc[t][n]=i),i}function zd(e,n){return n&&(e=e.replace(/\{([^}]+)}/g,function(t,i){return null!=n&&i in n?n[i]:t})),e}function Hi(e,n,t="-",i,r){let o="";(e<0||r&&e<=0)&&(r?e=1-e:(e=-e,o=t));let s=String(e);for(;s.length0||a>-t)&&(a+=t),e===re.Hours)0===a&&-12===t&&(a=12);else if(e===re.FractionalSeconds)return function iF(e,n){return Hi(e,3).substring(0,n)}(a,n);const l=fi(s,ne.MinusSign);return Hi(a,n,l,i,r)}}function Xe(e,n,t=Ct.Format,i=!1){return function(r,o){return function oF(e,n,t,i,r,o){switch(t){case fe.Months:return function Wx(e,n,t){const i=kn(e),o=hi([i[j.MonthsFormat],i[j.MonthsStandalone]],n);return hi(o,t)}(n,r,i)[e.getMonth()];case fe.Days:return function Gx(e,n,t){const i=kn(e),o=hi([i[j.DaysFormat],i[j.DaysStandalone]],n);return hi(o,t)}(n,r,i)[e.getDay()];case fe.DayPeriods:const s=e.getHours(),a=e.getMinutes();if(o){const u=function qx(e){const n=kn(e);return wC(n),(n[j.ExtraData][2]||[]).map(i=>"string"==typeof i?Nm(i):[Nm(i[0]),Nm(i[1])])}(n),f=function Jx(e,n,t){const i=kn(e);wC(i);const o=hi([i[j.ExtraData][0],i[j.ExtraData][1]],n)||[];return hi(o,t)||[]}(n,r,i),p=u.findIndex(m=>{if(Array.isArray(m)){const[v,y]=m,D=s>=v.hours&&a>=v.minutes,w=s0?Math.floor(r/60):Math.ceil(r/60);switch(e){case Vt.Short:return(r>=0?"+":"")+Hi(s,2,o)+Hi(Math.abs(r%60),2,o);case Vt.ShortGMT:return"GMT"+(r>=0?"+":"")+Hi(s,1,o);case Vt.Long:return"GMT"+(r>=0?"+":"")+Hi(s,2,o)+":"+Hi(Math.abs(r%60),2,o);case Vt.Extended:return 0===i?"Z":(r>=0?"+":"")+Hi(s,2,o)+":"+Hi(Math.abs(r%60),2,o);default:throw new Error(`Unknown zone width "${e}"`)}}}function SC(e){return Kd(e.getFullYear(),e.getMonth(),e.getDate()+(4-e.getDay()))}function Am(e,n=!1){return function(t,i){let r;if(n){const o=new Date(t.getFullYear(),t.getMonth(),1).getDay()-1,s=t.getDate();r=1+Math.floor((s+o)/7)}else{const o=SC(t),s=function aF(e){const n=Kd(e,0,1).getDay();return Kd(e,0,1+(n<=4?4:11)-n)}(o.getFullYear()),a=o.getTime()-s.getTime();r=1+Math.round(a/6048e5)}return Hi(r,e,fi(i,ne.MinusSign))}}function Jd(e,n=!1){return function(t,i){return Hi(SC(t).getFullYear(),e,fi(i,ne.MinusSign),n)}}const Im={};function EC(e,n){e=e.replace(/:/g,"");const t=Date.parse("Jan 01, 1970 00:00:00 "+e)/6e4;return isNaN(t)?n:t}function MC(e){return e instanceof Date&&!isNaN(e.valueOf())}function IC(e,n){n=encodeURIComponent(n);for(const t of e.split(";")){const i=t.indexOf("="),[r,o]=-1==i?[t,""]:[t.slice(0,i),t.slice(i+1)];if(r.trim()===n)return decodeURIComponent(o)}return null}let OC=(()=>{class e{constructor(t,i,r,o){this._iterableDiffers=t,this._keyValueDiffers=i,this._ngEl=r,this._renderer=o,this._iterableDiffer=null,this._keyValueDiffer=null,this._initialClasses=[],this._rawClass=null}set klass(t){this._removeClasses(this._initialClasses),this._initialClasses="string"==typeof t?t.split(/\s+/):[],this._applyClasses(this._initialClasses),this._applyClasses(this._rawClass)}set ngClass(t){this._removeClasses(this._rawClass),this._applyClasses(this._initialClasses),this._iterableDiffer=null,this._keyValueDiffer=null,this._rawClass="string"==typeof t?t.split(/\s+/):t,this._rawClass&&(zl(this._rawClass)?this._iterableDiffer=this._iterableDiffers.find(this._rawClass).create():this._keyValueDiffer=this._keyValueDiffers.find(this._rawClass).create())}ngDoCheck(){if(this._iterableDiffer){const t=this._iterableDiffer.diff(this._rawClass);t&&this._applyIterableChanges(t)}else if(this._keyValueDiffer){const t=this._keyValueDiffer.diff(this._rawClass);t&&this._applyKeyValueChanges(t)}}_applyKeyValueChanges(t){t.forEachAddedItem(i=>this._toggleClass(i.key,i.currentValue)),t.forEachChangedItem(i=>this._toggleClass(i.key,i.currentValue)),t.forEachRemovedItem(i=>{i.previousValue&&this._toggleClass(i.key,!1)})}_applyIterableChanges(t){t.forEachAddedItem(i=>{if("string"!=typeof i.item)throw new Error(`NgClass can only toggle CSS classes expressed as strings, got ${He(i.item)}`);this._toggleClass(i.item,!0)}),t.forEachRemovedItem(i=>this._toggleClass(i.item,!1))}_applyClasses(t){t&&(Array.isArray(t)||t instanceof Set?t.forEach(i=>this._toggleClass(i,!0)):Object.keys(t).forEach(i=>this._toggleClass(i,!!t[i])))}_removeClasses(t){t&&(Array.isArray(t)||t instanceof Set?t.forEach(i=>this._toggleClass(i,!1)):Object.keys(t).forEach(i=>this._toggleClass(i,!1)))}_toggleClass(t,i){(t=t.trim())&&t.split(/\s+/g).forEach(r=>{i?this._renderer.addClass(this._ngEl.nativeElement,r):this._renderer.removeClass(this._ngEl.nativeElement,r)})}}return e.\u0275fac=function(t){return new(t||e)(C(jd),C(cc),C(Qe),C(ui))},e.\u0275dir=B({type:e,selectors:[["","ngClass",""]],inputs:{klass:["class","klass"],ngClass:"ngClass"},standalone:!0}),e})();class EF{constructor(n,t,i,r){this.$implicit=n,this.ngForOf=t,this.index=i,this.count=r}get first(){return 0===this.index}get last(){return this.index===this.count-1}get even(){return this.index%2==0}get odd(){return!this.even}}let Ra=(()=>{class e{constructor(t,i,r){this._viewContainer=t,this._template=i,this._differs=r,this._ngForOf=null,this._ngForOfDirty=!0,this._differ=null}set ngForOf(t){this._ngForOf=t,this._ngForOfDirty=!0}set ngForTrackBy(t){this._trackByFn=t}get ngForTrackBy(){return this._trackByFn}set ngForTemplate(t){t&&(this._template=t)}ngDoCheck(){if(this._ngForOfDirty){this._ngForOfDirty=!1;const t=this._ngForOf;!this._differ&&t&&(this._differ=this._differs.find(t).create(this.ngForTrackBy))}if(this._differ){const t=this._differ.diff(this._ngForOf);t&&this._applyChanges(t)}}_applyChanges(t){const i=this._viewContainer;t.forEachOperation((r,o,s)=>{if(null==r.previousIndex)i.createEmbeddedView(this._template,new EF(r.item,this._ngForOf,-1,-1),null===s?void 0:s);else if(null==s)i.remove(null===o?void 0:o);else if(null!==o){const a=i.get(o);i.move(a,s),xC(a,r)}});for(let r=0,o=i.length;r{xC(i.get(r.currentIndex),r)})}static ngTemplateContextGuard(t,i){return!0}}return e.\u0275fac=function(t){return new(t||e)(C(Pi),C(gt),C(jd))},e.\u0275dir=B({type:e,selectors:[["","ngFor","","ngForOf",""]],inputs:{ngForOf:"ngForOf",ngForTrackBy:"ngForTrackBy",ngForTemplate:"ngForTemplate"},standalone:!0}),e})();function xC(e,n){e.context.$implicit=n.item}let os=(()=>{class e{constructor(t,i){this._viewContainer=t,this._context=new TF,this._thenTemplateRef=null,this._elseTemplateRef=null,this._thenViewRef=null,this._elseViewRef=null,this._thenTemplateRef=i}set ngIf(t){this._context.$implicit=this._context.ngIf=t,this._updateView()}set ngIfThen(t){FC("ngIfThen",t),this._thenTemplateRef=t,this._thenViewRef=null,this._updateView()}set ngIfElse(t){FC("ngIfElse",t),this._elseTemplateRef=t,this._elseViewRef=null,this._updateView()}_updateView(){this._context.$implicit?this._thenViewRef||(this._viewContainer.clear(),this._elseViewRef=null,this._thenTemplateRef&&(this._thenViewRef=this._viewContainer.createEmbeddedView(this._thenTemplateRef,this._context))):this._elseViewRef||(this._viewContainer.clear(),this._thenViewRef=null,this._elseTemplateRef&&(this._elseViewRef=this._viewContainer.createEmbeddedView(this._elseTemplateRef,this._context)))}static ngTemplateContextGuard(t,i){return!0}}return e.\u0275fac=function(t){return new(t||e)(C(Pi),C(gt))},e.\u0275dir=B({type:e,selectors:[["","ngIf",""]],inputs:{ngIf:"ngIf",ngIfThen:"ngIfThen",ngIfElse:"ngIfElse"},standalone:!0}),e})();class TF{constructor(){this.$implicit=null,this.ngIf=null}}function FC(e,n){if(n&&!n.createEmbeddedView)throw new Error(`${e} must be a TemplateRef, but received '${He(n)}'.`)}const jF=new Y("DATE_PIPE_DEFAULT_TIMEZONE");let LC=(()=>{class e{constructor(t,i){this.locale=t,this.defaultTimezone=i}transform(t,i="mediumDate",r,o){if(null==t||""===t||t!=t)return null;try{return nF(t,i,o||this.locale,r??this.defaultTimezone??void 0)}catch(s){throw function Bi(e,n){return new F(2100,!1)}()}}}return e.\u0275fac=function(t){return new(t||e)(C(xr,16),C(jF,24))},e.\u0275pipe=Tt({name:"date",type:e,pure:!0,standalone:!0}),e})(),Qn=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=ge({type:e}),e.\u0275inj=Me({}),e})();const HC="browser";let tP=(()=>{class e{}return e.\u0275prov=U({token:e,providedIn:"root",factory:()=>new nP(L(mt),window)}),e})();class nP{constructor(n,t){this.document=n,this.window=t,this.offset=()=>[0,0]}setOffset(n){this.offset=Array.isArray(n)?()=>n:n}getScrollPosition(){return this.supportsScrolling()?[this.window.pageXOffset,this.window.pageYOffset]:[0,0]}scrollToPosition(n){this.supportsScrolling()&&this.window.scrollTo(n[0],n[1])}scrollToAnchor(n){if(!this.supportsScrolling())return;const t=function iP(e,n){const t=e.getElementById(n)||e.getElementsByName(n)[0];if(t)return t;if("function"==typeof e.createTreeWalker&&e.body&&(e.body.createShadowRoot||e.body.attachShadow)){const i=e.createTreeWalker(e.body,NodeFilter.SHOW_ELEMENT);let r=i.currentNode;for(;r;){const o=r.shadowRoot;if(o){const s=o.getElementById(n)||o.querySelector(`[name="${n}"]`);if(s)return s}r=i.nextNode()}}return null}(this.document,n);t&&(this.scrollToElement(t),t.focus())}setHistoryScrollRestoration(n){if(this.supportScrollRestoration()){const t=this.window.history;t&&t.scrollRestoration&&(t.scrollRestoration=n)}}scrollToElement(n){const t=n.getBoundingClientRect(),i=t.left+this.window.pageXOffset,r=t.top+this.window.pageYOffset,o=this.offset();this.window.scrollTo(i-o[0],r-o[1])}supportScrollRestoration(){try{if(!this.supportsScrolling())return!1;const n=jC(this.window.history)||jC(Object.getPrototypeOf(this.window.history));return!(!n||!n.writable&&!n.set)}catch{return!1}}supportsScrolling(){try{return!!this.window&&!!this.window.scrollTo&&"pageXOffset"in this.window}catch{return!1}}}function jC(e){return Object.getOwnPropertyDescriptor(e,"scrollRestoration")}class $C{}class $m extends class IP extends class Fx{}{constructor(){super(...arguments),this.supportsDOMEvents=!0}}{static makeCurrent(){!function xx(e){$d||($d=e)}(new $m)}onAndCancel(n,t,i){return n.addEventListener(t,i,!1),()=>{n.removeEventListener(t,i,!1)}}dispatchEvent(n,t){n.dispatchEvent(t)}remove(n){n.parentNode&&n.parentNode.removeChild(n)}createElement(n,t){return(t=t||this.getDefaultDocument()).createElement(n)}createHtmlDocument(){return document.implementation.createHTMLDocument("fakeTitle")}getDefaultDocument(){return document}isElementNode(n){return n.nodeType===Node.ELEMENT_NODE}isShadowRoot(n){return n instanceof DocumentFragment}getGlobalEventTarget(n,t){return"window"===t?window:"document"===t?n:"body"===t?n.body:null}getBaseHref(n){const t=function OP(){return pc=pc||document.querySelector("base"),pc?pc.getAttribute("href"):null}();return null==t?null:function kP(e){ef=ef||document.createElement("a"),ef.setAttribute("href",e);const n=ef.pathname;return"/"===n.charAt(0)?n:`/${n}`}(t)}resetBaseElement(){pc=null}getUserAgent(){return window.navigator.userAgent}getCookie(n){return IC(document.cookie,n)}}let ef,pc=null;const zC=new Y("TRANSITION_ID"),xP=[{provide:Fd,useFactory:function RP(e,n,t){return()=>{t.get(Pd).donePromise.then(()=>{const i=sr(),r=n.querySelectorAll(`style[ng-transition="${e}"]`);for(let o=0;o{class e{build(){return new XMLHttpRequest}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=U({token:e,factory:e.\u0275fac}),e})();const tf=new Y("EventManagerPlugins");let nf=(()=>{class e{constructor(t,i){this._zone=i,this._eventNameToPlugin=new Map,t.forEach(r=>r.manager=this),this._plugins=t.slice().reverse()}addEventListener(t,i,r){return this._findPluginFor(i).addEventListener(t,i,r)}addGlobalEventListener(t,i,r){return this._findPluginFor(i).addGlobalEventListener(t,i,r)}getZone(){return this._zone}_findPluginFor(t){const i=this._eventNameToPlugin.get(t);if(i)return i;const r=this._plugins;for(let o=0;o{class e{constructor(){this._stylesSet=new Set}addStyles(t){const i=new Set;t.forEach(r=>{this._stylesSet.has(r)||(this._stylesSet.add(r),i.add(r))}),this.onStylesAdded(i)}onStylesAdded(t){}getAllStyles(){return Array.from(this._stylesSet)}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=U({token:e,factory:e.\u0275fac}),e})(),gc=(()=>{class e extends qC{constructor(t){super(),this._doc=t,this._hostNodes=new Map,this._hostNodes.set(t.head,[])}_addStylesToHost(t,i,r){t.forEach(o=>{const s=this._doc.createElement("style");s.textContent=o,r.push(i.appendChild(s))})}addHost(t){const i=[];this._addStylesToHost(this._stylesSet,t,i),this._hostNodes.set(t,i)}removeHost(t){const i=this._hostNodes.get(t);i&&i.forEach(JC),this._hostNodes.delete(t)}onStylesAdded(t){this._hostNodes.forEach((i,r)=>{this._addStylesToHost(t,r,i)})}ngOnDestroy(){this._hostNodes.forEach(t=>t.forEach(JC))}}return e.\u0275fac=function(t){return new(t||e)(L(mt))},e.\u0275prov=U({token:e,factory:e.\u0275fac}),e})();function JC(e){sr().remove(e)}const Um={svg:"http://www.w3.org/2000/svg",xhtml:"http://www.w3.org/1999/xhtml",xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/",math:"http://www.w3.org/1998/MathML/"},Gm=/%COMP%/g;function rf(e,n,t){for(let i=0;i{if("__ngUnwrap__"===n)return e;!1===e(n)&&(n.preventDefault(),n.returnValue=!1)}}let Wm=(()=>{class e{constructor(t,i,r){this.eventManager=t,this.sharedStylesHost=i,this.appId=r,this.rendererByCompId=new Map,this.defaultRenderer=new Km(t)}createRenderer(t,i){if(!t||!i)return this.defaultRenderer;switch(i.encapsulation){case Bn.Emulated:{let r=this.rendererByCompId.get(i.id);return r||(r=new $P(this.eventManager,this.sharedStylesHost,i,this.appId),this.rendererByCompId.set(i.id,r)),r.applyToHost(t),r}case 1:case Bn.ShadowDom:return new UP(this.eventManager,this.sharedStylesHost,t,i);default:if(!this.rendererByCompId.has(i.id)){const r=rf(i.id,i.styles,[]);this.sharedStylesHost.addStyles(r),this.rendererByCompId.set(i.id,this.defaultRenderer)}return this.defaultRenderer}}begin(){}end(){}}return e.\u0275fac=function(t){return new(t||e)(L(nf),L(gc),L(sc))},e.\u0275prov=U({token:e,factory:e.\u0275fac}),e})();class Km{constructor(n){this.eventManager=n,this.data=Object.create(null),this.destroyNode=null}destroy(){}createElement(n,t){return t?document.createElementNS(Um[t]||t,n):document.createElement(n)}createComment(n){return document.createComment(n)}createText(n){return document.createTextNode(n)}appendChild(n,t){(tw(n)?n.content:n).appendChild(t)}insertBefore(n,t,i){n&&(tw(n)?n.content:n).insertBefore(t,i)}removeChild(n,t){n&&n.removeChild(t)}selectRootElement(n,t){let i="string"==typeof n?document.querySelector(n):n;if(!i)throw new Error(`The selector "${n}" did not match any elements`);return t||(i.textContent=""),i}parentNode(n){return n.parentNode}nextSibling(n){return n.nextSibling}setAttribute(n,t,i,r){if(r){t=r+":"+t;const o=Um[r];o?n.setAttributeNS(o,t,i):n.setAttribute(t,i)}else n.setAttribute(t,i)}removeAttribute(n,t,i){if(i){const r=Um[i];r?n.removeAttributeNS(r,t):n.removeAttribute(`${i}:${t}`)}else n.removeAttribute(t)}addClass(n,t){n.classList.add(t)}removeClass(n,t){n.classList.remove(t)}setStyle(n,t,i,r){r&(Un.DashCase|Un.Important)?n.style.setProperty(t,i,r&Un.Important?"important":""):n.style[t]=i}removeStyle(n,t,i){i&Un.DashCase?n.style.removeProperty(t):n.style[t]=""}setProperty(n,t,i){n[t]=i}setValue(n,t){n.nodeValue=t}listen(n,t,i){return"string"==typeof n?this.eventManager.addGlobalEventListener(n,t,XC(i)):this.eventManager.addEventListener(n,t,XC(i))}}function tw(e){return"TEMPLATE"===e.tagName&&void 0!==e.content}class $P extends Km{constructor(n,t,i,r){super(n),this.component=i;const o=rf(r+"-"+i.id,i.styles,[]);t.addStyles(o),this.contentAttr=function HP(e){return"_ngcontent-%COMP%".replace(Gm,e)}(r+"-"+i.id),this.hostAttr=function BP(e){return"_nghost-%COMP%".replace(Gm,e)}(r+"-"+i.id)}applyToHost(n){super.setAttribute(n,this.hostAttr,"")}createElement(n,t){const i=super.createElement(n,t);return super.setAttribute(i,this.contentAttr,""),i}}class UP extends Km{constructor(n,t,i,r){super(n),this.sharedStylesHost=t,this.hostEl=i,this.shadowRoot=i.attachShadow({mode:"open"}),this.sharedStylesHost.addHost(this.shadowRoot);const o=rf(r.id,r.styles,[]);for(let s=0;s{class e extends YC{constructor(t){super(t)}supports(t){return!0}addEventListener(t,i,r){return t.addEventListener(i,r,!1),()=>this.removeEventListener(t,i,r)}removeEventListener(t,i,r){return t.removeEventListener(i,r)}}return e.\u0275fac=function(t){return new(t||e)(L(mt))},e.\u0275prov=U({token:e,factory:e.\u0275fac}),e})();const nw=["alt","control","meta","shift"],WP={"\b":"Backspace","\t":"Tab","\x7f":"Delete","\x1b":"Escape",Del:"Delete",Esc:"Escape",Left:"ArrowLeft",Right:"ArrowRight",Up:"ArrowUp",Down:"ArrowDown",Menu:"ContextMenu",Scroll:"ScrollLock",Win:"OS"},KP={alt:e=>e.altKey,control:e=>e.ctrlKey,meta:e=>e.metaKey,shift:e=>e.shiftKey};let zP=(()=>{class e extends YC{constructor(t){super(t)}supports(t){return null!=e.parseEventName(t)}addEventListener(t,i,r){const o=e.parseEventName(i),s=e.eventCallback(o.fullKey,r,this.manager.getZone());return this.manager.getZone().runOutsideAngular(()=>sr().onAndCancel(t,o.domEventName,s))}static parseEventName(t){const i=t.toLowerCase().split("."),r=i.shift();if(0===i.length||"keydown"!==r&&"keyup"!==r)return null;const o=e._normalizeKey(i.pop());let s="",a=i.indexOf("code");if(a>-1&&(i.splice(a,1),s="code."),nw.forEach(u=>{const f=i.indexOf(u);f>-1&&(i.splice(f,1),s+=u+".")}),s+=o,0!=i.length||0===o.length)return null;const l={};return l.domEventName=r,l.fullKey=s,l}static matchEventFullKeyCode(t,i){let r=WP[t.key]||t.key,o="";return i.indexOf("code.")>-1&&(r=t.code,o="code."),!(null==r||!r)&&(r=r.toLowerCase()," "===r?r="space":"."===r&&(r="dot"),nw.forEach(s=>{s!==r&&(0,KP[s])(t)&&(o+=s+".")}),o+=r,o===i)}static eventCallback(t,i,r){return o=>{e.matchEventFullKeyCode(o,t)&&r.runGuarded(()=>i(o))}}static _normalizeKey(t){return"esc"===t?"escape":t}}return e.\u0275fac=function(t){return new(t||e)(L(mt))},e.\u0275prov=U({token:e,factory:e.\u0275fac}),e})();const ZP=Z1(Ox,"browser",[{provide:ac,useValue:HC},{provide:j1,useValue:function YP(){$m.makeCurrent()},multi:!0},{provide:mt,useFactory:function JP(){return function HN(e){Bp=e}(document),document},deps:[]}]),ow=new Y(""),sw=[{provide:Ld,useClass:class FP{addToWindow(n){Ue.getAngularTestability=(i,r=!0)=>{const o=n.findTestabilityInTree(i,r);if(null==o)throw new Error("Could not find testability for element.");return o},Ue.getAllAngularTestabilities=()=>n.getAllTestabilities(),Ue.getAllAngularRootElements=()=>n.getAllRootElements(),Ue.frameworkStabilizers||(Ue.frameworkStabilizers=[]),Ue.frameworkStabilizers.push(i=>{const r=Ue.getAllAngularTestabilities();let o=r.length,s=!1;const a=function(l){s=s||l,o--,0==o&&i(s)};r.forEach(function(l){l.whenStable(a)})})}findTestabilityInTree(n,t,i){return null==t?null:n.getTestability(t)??(i?sr().isShadowRoot(t)?this.findTestabilityInTree(n,t.host,!0):this.findTestabilityInTree(n,t.parentElement,!0):null)}},deps:[]},{provide:z1,useClass:pm,deps:[Ye,gm,Ld]},{provide:pm,useClass:pm,deps:[Ye,gm,Ld]}],aw=[{provide:Jp,useValue:"root"},{provide:ha,useFactory:function qP(){return new ha},deps:[]},{provide:tf,useClass:GP,multi:!0,deps:[mt,Ye,ac]},{provide:tf,useClass:zP,multi:!0,deps:[mt]},{provide:Wm,useClass:Wm,deps:[nf,gc,sc]},{provide:eg,useExisting:Wm},{provide:qC,useExisting:gc},{provide:gc,useClass:gc,deps:[mt]},{provide:nf,useClass:nf,deps:[tf,Ye]},{provide:$C,useClass:PP,deps:[]},[]];let QP=(()=>{class e{constructor(t){}static withServerTransition(t){return{ngModule:e,providers:[{provide:sc,useValue:t.appId},{provide:zC,useExisting:sc},xP]}}}return e.\u0275fac=function(t){return new(t||e)(L(ow,12))},e.\u0275mod=ge({type:e}),e.\u0275inj=Me({providers:[...aw,...sw],imports:[Qn,kx]}),e})(),lw=(()=>{class e{constructor(t){this._doc=t}getTitle(){return this._doc.title}setTitle(t){this._doc.title=t||""}}return e.\u0275fac=function(t){return new(t||e)(L(mt))},e.\u0275prov=U({token:e,factory:function(t){let i=null;return i=t?new t:function eL(){return new lw(L(mt))}(),i},providedIn:"root"}),e})();function Q(...e){return dt(e,Fo(e))}typeof window<"u"&&window;class zt extends je{constructor(n){super(),this._value=n}get value(){return this.getValue()}_subscribe(n){const t=super._subscribe(n);return!t.closed&&n.next(this._value),t}getValue(){const{hasError:n,thrownError:t,_value:i}=this;if(n)throw t;return this._throwIfClosed(),i}next(n){super.next(this._value=n)}}const mc=V(e=>function(){e(this),this.name="EmptyError",this.message="no elements in sequence"}),{isArray:lL}=Array,{getPrototypeOf:cL,prototype:uL,keys:dL}=Object;function dw(e){if(1===e.length){const n=e[0];if(lL(n))return{args:n,keys:null};if(function fL(e){return e&&"object"==typeof e&&cL(e)===uL}(n)){const t=dL(n);return{args:t.map(i=>n[i]),keys:t}}}return{args:e,keys:null}}const{isArray:hL}=Array;function qm(e){return ie(n=>function pL(e,n){return hL(n)?e(...n):e(n)}(e,n))}function fw(e,n){return e.reduce((t,i,r)=>(t[i]=n[r],t),{})}function sf(...e){const n=Fo(e),t=yr(e),{args:i,keys:r}=dw(e);if(0===i.length)return dt([],n);const o=new Ve(function gL(e,n,t=Pn){return i=>{hw(n,()=>{const{length:r}=e,o=new Array(r);let s=r,a=r;for(let l=0;l{const u=dt(e[l],n);let f=!1;u.subscribe(Oe(i,p=>{o[l]=p,f||(f=!0,a--),a||i.next(t(o.slice()))},()=>{--s||i.complete()}))},i)},i)}}(i,n,r?s=>fw(r,s):Pn));return t?o.pipe(qm(t)):o}function hw(e,n,t){e?Mt(t,e,n):n()}function _c(...e){return function mL(){return fn(1)}()(dt(e,Fo(e)))}function pw(e){return new Ve(n=>{Et(e()).subscribe(n)})}function xa(e,n){const t=be(e)?e:()=>e,i=r=>r.error(t());return new Ve(n?r=>n.schedule(i,0,r):i)}function Jm(){return qe((e,n)=>{let t=null;e._refCount++;const i=Oe(n,void 0,void 0,void 0,()=>{if(!e||e._refCount<=0||0<--e._refCount)return void(t=null);const r=e._connection,o=t;t=null,r&&(!o||r===o)&&r.unsubscribe(),n.unsubscribe()});e.subscribe(i),i.closed||(t=e.connect())})}class gw extends Ve{constructor(n,t){super(),this.source=n,this.subjectFactory=t,this._subject=null,this._refCount=0,this._connection=null,q(n)&&(this.lift=n.lift)}_subscribe(n){return this.getSubject().subscribe(n)}getSubject(){const n=this._subject;return(!n||n.isStopped)&&(this._subject=this.subjectFactory()),this._subject}_teardown(){this._refCount=0;const{_connection:n}=this;this._subject=this._connection=null,n?.unsubscribe()}connect(){let n=this._connection;if(!n){n=this._connection=new _t;const t=this.getSubject();n.add(this.source.subscribe(Oe(t,void 0,()=>{this._teardown(),t.complete()},i=>{this._teardown(),t.error(i)},()=>this._teardown()))),n.closed&&(this._connection=null,n=_t.EMPTY)}return n}refCount(){return Jm()(this)}}function pi(e,n){return qe((t,i)=>{let r=null,o=0,s=!1;const a=()=>s&&!r&&i.complete();t.subscribe(Oe(i,l=>{r?.unsubscribe();let u=0;const f=o++;Et(e(l,f)).subscribe(r=Oe(i,p=>i.next(n?n(l,p,f,u++):p),()=>{r=null,a()}))},()=>{s=!0,a()}))})}function sn(e){return e<=0?()=>Ft:qe((n,t)=>{let i=0;n.subscribe(Oe(t,r=>{++i<=e&&(t.next(r),e<=i&&t.complete())}))})}function yn(e,n){return qe((t,i)=>{let r=0;t.subscribe(Oe(i,o=>e.call(n,o,r++)&&i.next(o)))})}function lf(e){return qe((n,t)=>{let i=!1;n.subscribe(Oe(t,r=>{i=!0,t.next(r)},()=>{i||t.next(e),t.complete()}))})}function mw(e=_L){return qe((n,t)=>{let i=!1;n.subscribe(Oe(t,r=>{i=!0,t.next(r)},()=>i?t.complete():t.error(e())))})}function _L(){return new mc}function mo(e,n){const t=arguments.length>=2;return i=>i.pipe(e?yn((r,o)=>e(r,o,i)):Pn,sn(1),t?lf(n):mw(()=>new mc))}function _o(e,n){return be(n)?ke(e,n,1):ke(e,1)}function Yt(e,n,t){const i=be(e)||n||t?{next:e,error:n,complete:t}:e;return i?qe((r,o)=>{var s;null===(s=i.subscribe)||void 0===s||s.call(i);let a=!0;r.subscribe(Oe(o,l=>{var u;null===(u=i.next)||void 0===u||u.call(i,l),o.next(l)},()=>{var l;a=!1,null===(l=i.complete)||void 0===l||l.call(i),o.complete()},l=>{var u;a=!1,null===(u=i.error)||void 0===u||u.call(i,l),o.error(l)},()=>{var l,u;a&&(null===(l=i.unsubscribe)||void 0===l||l.call(i)),null===(u=i.finalize)||void 0===u||u.call(i)}))}):Pn}function Br(e){return qe((n,t)=>{let o,i=null,r=!1;i=n.subscribe(Oe(t,void 0,void 0,s=>{o=Et(e(s,Br(e)(n))),i?(i.unsubscribe(),i=null,o.subscribe(t)):r=!0})),r&&(i.unsubscribe(),i=null,o.subscribe(t))})}function vL(e,n,t,i,r){return(o,s)=>{let a=t,l=n,u=0;o.subscribe(Oe(s,f=>{const p=u++;l=a?e(l,f,p):(a=!0,f),i&&s.next(l)},r&&(()=>{a&&s.next(l),s.complete()})))}}function _w(e,n){return qe(vL(e,n,arguments.length>=2,!0))}function Zm(e){return e<=0?()=>Ft:qe((n,t)=>{let i=[];n.subscribe(Oe(t,r=>{i.push(r),e{for(const r of i)t.next(r);t.complete()},void 0,()=>{i=null}))})}function vw(e,n){const t=arguments.length>=2;return i=>i.pipe(e?yn((r,o)=>e(r,o,i)):Pn,Zm(1),t?lf(n):mw(()=>new mc))}function Qm(e){return qe((n,t)=>{try{n.subscribe(t)}finally{t.add(e)}})}const pe="primary",vc=Symbol("RouteTitle");class bL{constructor(n){this.params=n||{}}has(n){return Object.prototype.hasOwnProperty.call(this.params,n)}get(n){if(this.has(n)){const t=this.params[n];return Array.isArray(t)?t[0]:t}return null}getAll(n){if(this.has(n)){const t=this.params[n];return Array.isArray(t)?t:[t]}return[]}get keys(){return Object.keys(this.params)}}function Fa(e){return new bL(e)}function DL(e,n,t){const i=t.path.split("/");if(i.length>e.length||"full"===t.pathMatch&&(n.hasChildren()||i.lengthi[o]===r)}return e===n}function Dw(e){return Array.prototype.concat.apply([],e)}function Cw(e){return e.length>0?e[e.length-1]:null}function an(e,n){for(const t in e)e.hasOwnProperty(t)&&n(e[t],t)}function vo(e){return Pg(e)?e:ql(e)?dt(Promise.resolve(e)):Q(e)}const SL={exact:function Ew(e,n,t){if(!as(e.segments,n.segments)||!cf(e.segments,n.segments,t)||e.numberOfChildren!==n.numberOfChildren)return!1;for(const i in n.children)if(!e.children[i]||!Ew(e.children[i],n.children[i],t))return!1;return!0},subset:Mw},ww={exact:function EL(e,n){return ar(e,n)},subset:function ML(e,n){return Object.keys(n).length<=Object.keys(e).length&&Object.keys(n).every(t=>bw(e[t],n[t]))},ignored:()=>!0};function Sw(e,n,t){return SL[t.paths](e.root,n.root,t.matrixParams)&&ww[t.queryParams](e.queryParams,n.queryParams)&&!("exact"===t.fragment&&e.fragment!==n.fragment)}function Mw(e,n,t){return Tw(e,n,n.segments,t)}function Tw(e,n,t,i){if(e.segments.length>t.length){const r=e.segments.slice(0,t.length);return!(!as(r,t)||n.hasChildren()||!cf(r,t,i))}if(e.segments.length===t.length){if(!as(e.segments,t)||!cf(e.segments,t,i))return!1;for(const r in n.children)if(!e.children[r]||!Mw(e.children[r],n.children[r],i))return!1;return!0}{const r=t.slice(0,e.segments.length),o=t.slice(e.segments.length);return!!(as(e.segments,r)&&cf(e.segments,r,i)&&e.children[pe])&&Tw(e.children[pe],n,o,i)}}function cf(e,n,t){return n.every((i,r)=>ww[t](e[r].parameters,i.parameters))}class ss{constructor(n,t,i){this.root=n,this.queryParams=t,this.fragment=i}get queryParamMap(){return this._queryParamMap||(this._queryParamMap=Fa(this.queryParams)),this._queryParamMap}toString(){return AL.serialize(this)}}class _e{constructor(n,t){this.segments=n,this.children=t,this.parent=null,an(t,(i,r)=>i.parent=this)}hasChildren(){return this.numberOfChildren>0}get numberOfChildren(){return Object.keys(this.children).length}toString(){return uf(this)}}class yc{constructor(n,t){this.path=n,this.parameters=t}get parameterMap(){return this._parameterMap||(this._parameterMap=Fa(this.parameters)),this._parameterMap}toString(){return Ow(this)}}function as(e,n){return e.length===n.length&&e.every((t,i)=>t.path===n[i].path)}let Nw=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=U({token:e,factory:function(){return new e_},providedIn:"root"}),e})();class e_{parse(n){const t=new VL(n);return new ss(t.parseRootSegment(),t.parseQueryParams(),t.parseFragment())}serialize(n){const t=`/${bc(n.root,!0)}`,i=function kL(e){const n=Object.keys(e).map(t=>{const i=e[t];return Array.isArray(i)?i.map(r=>`${df(t)}=${df(r)}`).join("&"):`${df(t)}=${df(i)}`}).filter(t=>!!t);return n.length?`?${n.join("&")}`:""}(n.queryParams);return`${t}${i}${"string"==typeof n.fragment?`#${function IL(e){return encodeURI(e)}(n.fragment)}`:""}`}}const AL=new e_;function uf(e){return e.segments.map(n=>Ow(n)).join("/")}function bc(e,n){if(!e.hasChildren())return uf(e);if(n){const t=e.children[pe]?bc(e.children[pe],!1):"",i=[];return an(e.children,(r,o)=>{o!==pe&&i.push(`${o}:${bc(r,!1)}`)}),i.length>0?`${t}(${i.join("//")})`:t}{const t=function NL(e,n){let t=[];return an(e.children,(i,r)=>{r===pe&&(t=t.concat(n(i,r)))}),an(e.children,(i,r)=>{r!==pe&&(t=t.concat(n(i,r)))}),t}(e,(i,r)=>r===pe?[bc(e.children[pe],!1)]:[`${r}:${bc(i,!1)}`]);return 1===Object.keys(e.children).length&&null!=e.children[pe]?`${uf(e)}/${t[0]}`:`${uf(e)}/(${t.join("//")})`}}function Aw(e){return encodeURIComponent(e).replace(/%40/g,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",")}function df(e){return Aw(e).replace(/%3B/gi,";")}function t_(e){return Aw(e).replace(/\(/g,"%28").replace(/\)/g,"%29").replace(/%26/gi,"&")}function ff(e){return decodeURIComponent(e)}function Iw(e){return ff(e.replace(/\+/g,"%20"))}function Ow(e){return`${t_(e.path)}${function OL(e){return Object.keys(e).map(n=>`;${t_(n)}=${t_(e[n])}`).join("")}(e.parameters)}`}const RL=/^[^\/()?;=#]+/;function hf(e){const n=e.match(RL);return n?n[0]:""}const xL=/^[^=?&#]+/,PL=/^[^&#]+/;class VL{constructor(n){this.url=n,this.remaining=n}parseRootSegment(){return this.consumeOptional("/"),""===this.remaining||this.peekStartsWith("?")||this.peekStartsWith("#")?new _e([],{}):new _e([],this.parseChildren())}parseQueryParams(){const n={};if(this.consumeOptional("?"))do{this.parseQueryParam(n)}while(this.consumeOptional("&"));return n}parseFragment(){return this.consumeOptional("#")?decodeURIComponent(this.remaining):null}parseChildren(){if(""===this.remaining)return{};this.consumeOptional("/");const n=[];for(this.peekStartsWith("(")||n.push(this.parseSegment());this.peekStartsWith("/")&&!this.peekStartsWith("//")&&!this.peekStartsWith("/(");)this.capture("/"),n.push(this.parseSegment());let t={};this.peekStartsWith("/(")&&(this.capture("/"),t=this.parseParens(!0));let i={};return this.peekStartsWith("(")&&(i=this.parseParens(!1)),(n.length>0||Object.keys(t).length>0)&&(i[pe]=new _e(n,t)),i}parseSegment(){const n=hf(this.remaining);if(""===n&&this.peekStartsWith(";"))throw new F(4009,!1);return this.capture(n),new yc(ff(n),this.parseMatrixParams())}parseMatrixParams(){const n={};for(;this.consumeOptional(";");)this.parseParam(n);return n}parseParam(n){const t=hf(this.remaining);if(!t)return;this.capture(t);let i="";if(this.consumeOptional("=")){const r=hf(this.remaining);r&&(i=r,this.capture(i))}n[ff(t)]=ff(i)}parseQueryParam(n){const t=function FL(e){const n=e.match(xL);return n?n[0]:""}(this.remaining);if(!t)return;this.capture(t);let i="";if(this.consumeOptional("=")){const s=function LL(e){const n=e.match(PL);return n?n[0]:""}(this.remaining);s&&(i=s,this.capture(i))}const r=Iw(t),o=Iw(i);if(n.hasOwnProperty(r)){let s=n[r];Array.isArray(s)||(s=[s],n[r]=s),s.push(o)}else n[r]=o}parseParens(n){const t={};for(this.capture("(");!this.consumeOptional(")")&&this.remaining.length>0;){const i=hf(this.remaining),r=this.remaining[i.length];if("/"!==r&&")"!==r&&";"!==r)throw new F(4010,!1);let o;i.indexOf(":")>-1?(o=i.slice(0,i.indexOf(":")),this.capture(o),this.capture(":")):n&&(o=pe);const s=this.parseChildren();t[o]=1===Object.keys(s).length?s[pe]:new _e([],s),this.consumeOptional("//")}return t}peekStartsWith(n){return this.remaining.startsWith(n)}consumeOptional(n){return!!this.peekStartsWith(n)&&(this.remaining=this.remaining.substring(n.length),!0)}capture(n){if(!this.consumeOptional(n))throw new F(4011,!1)}}function n_(e){return e.segments.length>0?new _e([],{[pe]:e}):e}function pf(e){const n={};for(const i of Object.keys(e.children)){const o=pf(e.children[i]);(o.segments.length>0||o.hasChildren())&&(n[i]=o)}return function HL(e){if(1===e.numberOfChildren&&e.children[pe]){const n=e.children[pe];return new _e(e.segments.concat(n.segments),n.children)}return e}(new _e(e.segments,n))}function ls(e){return e instanceof ss}function $L(e,n,t,i,r){if(0===t.length)return Pa(n.root,n.root,n.root,i,r);const o=function xw(e){if("string"==typeof e[0]&&1===e.length&&"/"===e[0])return new Rw(!0,0,e);let n=0,t=!1;const i=e.reduce((r,o,s)=>{if("object"==typeof o&&null!=o){if(o.outlets){const a={};return an(o.outlets,(l,u)=>{a[u]="string"==typeof l?l.split("/"):l}),[...r,{outlets:a}]}if(o.segmentPath)return[...r,o.segmentPath]}return"string"!=typeof o?[...r,o]:0===s?(o.split("/").forEach((a,l)=>{0==l&&"."===a||(0==l&&""===a?t=!0:".."===a?n++:""!=a&&r.push(a))}),r):[...r,o]},[]);return new Rw(t,n,i)}(t);return o.toRoot()?Pa(n.root,n.root,new _e([],{}),i,r):function s(l){const u=function GL(e,n,t,i){if(e.isAbsolute)return new La(n.root,!0,0);if(-1===i)return new La(t,t===n.root,0);return function Fw(e,n,t){let i=e,r=n,o=t;for(;o>r;){if(o-=r,i=i.parent,!i)throw new F(4005,!1);r=i.segments.length}return new La(i,!1,r-o)}(t,i+(Dc(e.commands[0])?0:1),e.numberOfDoubleDots)}(o,n,e.snapshot?._urlSegment,l),f=u.processChildren?wc(u.segmentGroup,u.index,o.commands):r_(u.segmentGroup,u.index,o.commands);return Pa(n.root,u.segmentGroup,f,i,r)}(e.snapshot?._lastPathIndex)}function Dc(e){return"object"==typeof e&&null!=e&&!e.outlets&&!e.segmentPath}function Cc(e){return"object"==typeof e&&null!=e&&e.outlets}function Pa(e,n,t,i,r){let s,o={};i&&an(i,(l,u)=>{o[u]=Array.isArray(l)?l.map(f=>`${f}`):`${l}`}),s=e===n?t:kw(e,n,t);const a=n_(pf(s));return new ss(a,o,r)}function kw(e,n,t){const i={};return an(e.children,(r,o)=>{i[o]=r===n?t:kw(r,n,t)}),new _e(e.segments,i)}class Rw{constructor(n,t,i){if(this.isAbsolute=n,this.numberOfDoubleDots=t,this.commands=i,n&&i.length>0&&Dc(i[0]))throw new F(4003,!1);const r=i.find(Cc);if(r&&r!==Cw(i))throw new F(4004,!1)}toRoot(){return this.isAbsolute&&1===this.commands.length&&"/"==this.commands[0]}}class La{constructor(n,t,i){this.segmentGroup=n,this.processChildren=t,this.index=i}}function r_(e,n,t){if(e||(e=new _e([],{})),0===e.segments.length&&e.hasChildren())return wc(e,n,t);const i=function KL(e,n,t){let i=0,r=n;const o={match:!1,pathIndex:0,commandIndex:0};for(;r=t.length)return o;const s=e.segments[r],a=t[i];if(Cc(a))break;const l=`${a}`,u=i0&&void 0===l)break;if(l&&u&&"object"==typeof u&&void 0===u.outlets){if(!Lw(l,u,s))return o;i+=2}else{if(!Lw(l,{},s))return o;i++}r++}return{match:!0,pathIndex:r,commandIndex:i}}(e,n,t),r=t.slice(i.commandIndex);if(i.match&&i.pathIndex{"string"==typeof o&&(o=[o]),null!==o&&(r[s]=r_(e.children[s],n,o))}),an(e.children,(o,s)=>{void 0===i[s]&&(r[s]=o)}),new _e(e.segments,r)}}function o_(e,n,t){const i=e.segments.slice(0,n);let r=0;for(;r{"string"==typeof t&&(t=[t]),null!==t&&(n[i]=o_(new _e([],{}),0,t))}),n}function Pw(e){const n={};return an(e,(t,i)=>n[i]=`${t}`),n}function Lw(e,n,t){return e==t.path&&ar(n,t.parameters)}class jr{constructor(n,t){this.id=n,this.url=t}}class s_ extends jr{constructor(n,t,i="imperative",r=null){super(n,t),this.type=0,this.navigationTrigger=i,this.restoredState=r}toString(){return`NavigationStart(id: ${this.id}, url: '${this.url}')`}}class cs extends jr{constructor(n,t,i){super(n,t),this.urlAfterRedirects=i,this.type=1}toString(){return`NavigationEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}')`}}class gf extends jr{constructor(n,t,i,r){super(n,t),this.reason=i,this.code=r,this.type=2}toString(){return`NavigationCancel(id: ${this.id}, url: '${this.url}')`}}class Vw extends jr{constructor(n,t,i,r){super(n,t),this.error=i,this.target=r,this.type=3}toString(){return`NavigationError(id: ${this.id}, url: '${this.url}', error: ${this.error})`}}class YL extends jr{constructor(n,t,i,r){super(n,t),this.urlAfterRedirects=i,this.state=r,this.type=4}toString(){return`RoutesRecognized(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`}}class qL extends jr{constructor(n,t,i,r){super(n,t),this.urlAfterRedirects=i,this.state=r,this.type=7}toString(){return`GuardsCheckStart(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`}}class JL extends jr{constructor(n,t,i,r,o){super(n,t),this.urlAfterRedirects=i,this.state=r,this.shouldActivate=o,this.type=8}toString(){return`GuardsCheckEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state}, shouldActivate: ${this.shouldActivate})`}}class ZL extends jr{constructor(n,t,i,r){super(n,t),this.urlAfterRedirects=i,this.state=r,this.type=5}toString(){return`ResolveStart(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`}}class QL extends jr{constructor(n,t,i,r){super(n,t),this.urlAfterRedirects=i,this.state=r,this.type=6}toString(){return`ResolveEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`}}class XL{constructor(n){this.route=n,this.type=9}toString(){return`RouteConfigLoadStart(path: ${this.route.path})`}}class e2{constructor(n){this.route=n,this.type=10}toString(){return`RouteConfigLoadEnd(path: ${this.route.path})`}}class t2{constructor(n){this.snapshot=n,this.type=11}toString(){return`ChildActivationStart(path: '${this.snapshot.routeConfig&&this.snapshot.routeConfig.path||""}')`}}class n2{constructor(n){this.snapshot=n,this.type=12}toString(){return`ChildActivationEnd(path: '${this.snapshot.routeConfig&&this.snapshot.routeConfig.path||""}')`}}class r2{constructor(n){this.snapshot=n,this.type=13}toString(){return`ActivationStart(path: '${this.snapshot.routeConfig&&this.snapshot.routeConfig.path||""}')`}}class o2{constructor(n){this.snapshot=n,this.type=14}toString(){return`ActivationEnd(path: '${this.snapshot.routeConfig&&this.snapshot.routeConfig.path||""}')`}}class Hw{constructor(n,t,i){this.routerEvent=n,this.position=t,this.anchor=i,this.type=15}toString(){return`Scroll(anchor: '${this.anchor}', position: '${this.position?`${this.position[0]}, ${this.position[1]}`:null}')`}}class Bw{constructor(n){this._root=n}get root(){return this._root.value}parent(n){const t=this.pathFromRoot(n);return t.length>1?t[t.length-2]:null}children(n){const t=a_(n,this._root);return t?t.children.map(i=>i.value):[]}firstChild(n){const t=a_(n,this._root);return t&&t.children.length>0?t.children[0].value:null}siblings(n){const t=l_(n,this._root);return t.length<2?[]:t[t.length-2].children.map(r=>r.value).filter(r=>r!==n)}pathFromRoot(n){return l_(n,this._root).map(t=>t.value)}}function a_(e,n){if(e===n.value)return n;for(const t of n.children){const i=a_(e,t);if(i)return i}return null}function l_(e,n){if(e===n.value)return[n];for(const t of n.children){const i=l_(e,t);if(i.length)return i.unshift(n),i}return[]}class $r{constructor(n,t){this.value=n,this.children=t}toString(){return`TreeNode(${this.value})`}}function Va(e){const n={};return e&&e.children.forEach(t=>n[t.value.outlet]=t),n}class jw extends Bw{constructor(n,t){super(n),this.snapshot=t,c_(this,n)}toString(){return this.snapshot.toString()}}function $w(e,n){const t=function a2(e,n){const s=new mf([],{},{},"",{},pe,n,null,e.root,-1,{});return new Gw("",new $r(s,[]))}(e,n),i=new zt([new yc("",{})]),r=new zt({}),o=new zt({}),s=new zt({}),a=new zt(""),l=new us(i,r,s,a,o,pe,n,t.root);return l.snapshot=t.root,new jw(new $r(l,[]),t)}class us{constructor(n,t,i,r,o,s,a,l){this.url=n,this.params=t,this.queryParams=i,this.fragment=r,this.data=o,this.outlet=s,this.component=a,this.title=this.data?.pipe(ie(u=>u[vc]))??Q(void 0),this._futureSnapshot=l}get routeConfig(){return this._futureSnapshot.routeConfig}get root(){return this._routerState.root}get parent(){return this._routerState.parent(this)}get firstChild(){return this._routerState.firstChild(this)}get children(){return this._routerState.children(this)}get pathFromRoot(){return this._routerState.pathFromRoot(this)}get paramMap(){return this._paramMap||(this._paramMap=this.params.pipe(ie(n=>Fa(n)))),this._paramMap}get queryParamMap(){return this._queryParamMap||(this._queryParamMap=this.queryParams.pipe(ie(n=>Fa(n)))),this._queryParamMap}toString(){return this.snapshot?this.snapshot.toString():`Future(${this._futureSnapshot})`}}function Uw(e,n="emptyOnly"){const t=e.pathFromRoot;let i=0;if("always"!==n)for(i=t.length-1;i>=1;){const r=t[i],o=t[i-1];if(r.routeConfig&&""===r.routeConfig.path)i--;else{if(o.component)break;i--}}return function l2(e){return e.reduce((n,t)=>({params:{...n.params,...t.params},data:{...n.data,...t.data},resolve:{...t.data,...n.resolve,...t.routeConfig?.data,...t._resolvedData}}),{params:{},data:{},resolve:{}})}(t.slice(i))}class mf{constructor(n,t,i,r,o,s,a,l,u,f,p,m){this.url=n,this.params=t,this.queryParams=i,this.fragment=r,this.data=o,this.outlet=s,this.component=a,this.title=this.data?.[vc],this.routeConfig=l,this._urlSegment=u,this._lastPathIndex=f,this._correctedLastPathIndex=m??f,this._resolve=p}get root(){return this._routerState.root}get parent(){return this._routerState.parent(this)}get firstChild(){return this._routerState.firstChild(this)}get children(){return this._routerState.children(this)}get pathFromRoot(){return this._routerState.pathFromRoot(this)}get paramMap(){return this._paramMap||(this._paramMap=Fa(this.params)),this._paramMap}get queryParamMap(){return this._queryParamMap||(this._queryParamMap=Fa(this.queryParams)),this._queryParamMap}toString(){return`Route(url:'${this.url.map(i=>i.toString()).join("/")}', path:'${this.routeConfig?this.routeConfig.path:""}')`}}class Gw extends Bw{constructor(n,t){super(t),this.url=n,c_(this,t)}toString(){return Ww(this._root)}}function c_(e,n){n.value._routerState=e,n.children.forEach(t=>c_(e,t))}function Ww(e){const n=e.children.length>0?` { ${e.children.map(Ww).join(", ")} } `:"";return`${e.value}${n}`}function u_(e){if(e.snapshot){const n=e.snapshot,t=e._futureSnapshot;e.snapshot=t,ar(n.queryParams,t.queryParams)||e.queryParams.next(t.queryParams),n.fragment!==t.fragment&&e.fragment.next(t.fragment),ar(n.params,t.params)||e.params.next(t.params),function CL(e,n){if(e.length!==n.length)return!1;for(let t=0;tar(t.parameters,n[i].parameters))}(e.url,n.url);return t&&!(!e.parent!=!n.parent)&&(!e.parent||d_(e.parent,n.parent))}function Sc(e,n,t){if(t&&e.shouldReuseRoute(n.value,t.value.snapshot)){const i=t.value;i._futureSnapshot=n.value;const r=function u2(e,n,t){return n.children.map(i=>{for(const r of t.children)if(e.shouldReuseRoute(i.value,r.value.snapshot))return Sc(e,i,r);return Sc(e,i)})}(e,n,t);return new $r(i,r)}{if(e.shouldAttach(n.value)){const o=e.retrieve(n.value);if(null!==o){const s=o.route;return s.value._futureSnapshot=n.value,s.children=n.children.map(a=>Sc(e,a)),s}}const i=function d2(e){return new us(new zt(e.url),new zt(e.params),new zt(e.queryParams),new zt(e.fragment),new zt(e.data),e.outlet,e.component,e)}(n.value),r=n.children.map(o=>Sc(e,o));return new $r(i,r)}}const f_="ngNavigationCancelingError";function Kw(e,n){const{redirectTo:t,navigationBehaviorOptions:i}=ls(n)?{redirectTo:n,navigationBehaviorOptions:void 0}:n,r=zw(!1,0,n);return r.url=t,r.navigationBehaviorOptions=i,r}function zw(e,n,t){const i=new Error("NavigationCancelingError: "+(e||""));return i[f_]=!0,i.cancellationCode=n,t&&(i.url=t),i}function Yw(e){return qw(e)&&ls(e.url)}function qw(e){return e&&e[f_]}class f2{constructor(){this.outlet=null,this.route=null,this.resolver=null,this.injector=null,this.children=new Ec,this.attachRef=null}}let Ec=(()=>{class e{constructor(){this.contexts=new Map}onChildOutletCreated(t,i){const r=this.getOrCreateContext(t);r.outlet=i,this.contexts.set(t,r)}onChildOutletDestroyed(t){const i=this.getContext(t);i&&(i.outlet=null,i.attachRef=null)}onOutletDeactivated(){const t=this.contexts;return this.contexts=new Map,t}onOutletReAttached(t){this.contexts=t}getOrCreateContext(t){let i=this.getContext(t);return i||(i=new f2,this.contexts.set(t,i)),i}getContext(t){return this.contexts.get(t)||null}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=U({token:e,factory:e.\u0275fac,providedIn:"root"}),e})();const _f=!1;let h_=(()=>{class e{constructor(t,i,r,o,s){this.parentContexts=t,this.location=i,this.changeDetector=o,this.environmentInjector=s,this.activated=null,this._activatedRoute=null,this.activateEvents=new de,this.deactivateEvents=new de,this.attachEvents=new de,this.detachEvents=new de,this.name=r||pe,t.onChildOutletCreated(this.name,this)}ngOnDestroy(){this.parentContexts.getContext(this.name)?.outlet===this&&this.parentContexts.onChildOutletDestroyed(this.name)}ngOnInit(){if(!this.activated){const t=this.parentContexts.getContext(this.name);t&&t.route&&(t.attachRef?this.attach(t.attachRef,t.route):this.activateWith(t.route,t.injector))}}get isActivated(){return!!this.activated}get component(){if(!this.activated)throw new F(4012,_f);return this.activated.instance}get activatedRoute(){if(!this.activated)throw new F(4012,_f);return this._activatedRoute}get activatedRouteData(){return this._activatedRoute?this._activatedRoute.snapshot.data:{}}detach(){if(!this.activated)throw new F(4012,_f);this.location.detach();const t=this.activated;return this.activated=null,this._activatedRoute=null,this.detachEvents.emit(t.instance),t}attach(t,i){this.activated=t,this._activatedRoute=i,this.location.insert(t.hostView),this.attachEvents.emit(t.instance)}deactivate(){if(this.activated){const t=this.component;this.activated.destroy(),this.activated=null,this._activatedRoute=null,this.deactivateEvents.emit(t)}}activateWith(t,i){if(this.isActivated)throw new F(4013,_f);this._activatedRoute=t;const r=this.location,s=t._futureSnapshot.component,a=this.parentContexts.getOrCreateContext(this.name).children,l=new h2(t,a,r.injector);if(i&&function p2(e){return!!e.resolveComponentFactory}(i)){const u=i.resolveComponentFactory(s);this.activated=r.createComponent(u,r.length,l)}else this.activated=r.createComponent(s,{index:r.length,injector:l,environmentInjector:i??this.environmentInjector});this.changeDetector.markForCheck(),this.activateEvents.emit(this.activated.instance)}}return e.\u0275fac=function(t){return new(t||e)(C(Ec),C(Pi),function Yo(e){return function J(e,n){if("class"===n)return e.classes;if("style"===n)return e.styles;const t=e.attrs;if(t){const i=t.length;let r=0;for(;r{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275cmp=lt({type:e,selectors:[["ng-component"]],standalone:!0,features:[t1],decls:1,vars:0,template:function(t,i){1&t&&Ri(0,"router-outlet")},dependencies:[h_],encapsulation:2}),e})();function Jw(e,n){return e.providers&&!e._injector&&(e._injector=Md(e.providers,n,`Route: ${e.path}`)),e._injector??n}function m_(e){const n=e.children&&e.children.map(m_),t=n?{...e,children:n}:{...e};return!t.component&&!t.loadComponent&&(n||t.loadChildren)&&t.outlet&&t.outlet!==pe&&(t.component=p_),t}function gi(e){return e.outlet||pe}function Zw(e,n){const t=e.filter(i=>gi(i)===n);return t.push(...e.filter(i=>gi(i)!==n)),t}function Mc(e){if(!e)return null;if(e.routeConfig?._injector)return e.routeConfig._injector;for(let n=e.parent;n;n=n.parent){const t=n.routeConfig;if(t?._loadedInjector)return t._loadedInjector;if(t?._injector)return t._injector}return null}class y2{constructor(n,t,i,r){this.routeReuseStrategy=n,this.futureState=t,this.currState=i,this.forwardEvent=r}activate(n){const t=this.futureState._root,i=this.currState?this.currState._root:null;this.deactivateChildRoutes(t,i,n),u_(this.futureState.root),this.activateChildRoutes(t,i,n)}deactivateChildRoutes(n,t,i){const r=Va(t);n.children.forEach(o=>{const s=o.value.outlet;this.deactivateRoutes(o,r[s],i),delete r[s]}),an(r,(o,s)=>{this.deactivateRouteAndItsChildren(o,i)})}deactivateRoutes(n,t,i){const r=n.value,o=t?t.value:null;if(r===o)if(r.component){const s=i.getContext(r.outlet);s&&this.deactivateChildRoutes(n,t,s.children)}else this.deactivateChildRoutes(n,t,i);else o&&this.deactivateRouteAndItsChildren(t,i)}deactivateRouteAndItsChildren(n,t){n.value.component&&this.routeReuseStrategy.shouldDetach(n.value.snapshot)?this.detachAndStoreRouteSubtree(n,t):this.deactivateRouteAndOutlet(n,t)}detachAndStoreRouteSubtree(n,t){const i=t.getContext(n.value.outlet),r=i&&n.value.component?i.children:t,o=Va(n);for(const s of Object.keys(o))this.deactivateRouteAndItsChildren(o[s],r);if(i&&i.outlet){const s=i.outlet.detach(),a=i.children.onOutletDeactivated();this.routeReuseStrategy.store(n.value.snapshot,{componentRef:s,route:n,contexts:a})}}deactivateRouteAndOutlet(n,t){const i=t.getContext(n.value.outlet),r=i&&n.value.component?i.children:t,o=Va(n);for(const s of Object.keys(o))this.deactivateRouteAndItsChildren(o[s],r);i&&i.outlet&&(i.outlet.deactivate(),i.children.onOutletDeactivated(),i.attachRef=null,i.resolver=null,i.route=null)}activateChildRoutes(n,t,i){const r=Va(t);n.children.forEach(o=>{this.activateRoutes(o,r[o.value.outlet],i),this.forwardEvent(new o2(o.value.snapshot))}),n.children.length&&this.forwardEvent(new n2(n.value.snapshot))}activateRoutes(n,t,i){const r=n.value,o=t?t.value:null;if(u_(r),r===o)if(r.component){const s=i.getOrCreateContext(r.outlet);this.activateChildRoutes(n,t,s.children)}else this.activateChildRoutes(n,t,i);else if(r.component){const s=i.getOrCreateContext(r.outlet);if(this.routeReuseStrategy.shouldAttach(r.snapshot)){const a=this.routeReuseStrategy.retrieve(r.snapshot);this.routeReuseStrategy.store(r.snapshot,null),s.children.onOutletReAttached(a.contexts),s.attachRef=a.componentRef,s.route=a.route.value,s.outlet&&s.outlet.attach(a.componentRef,a.route.value),u_(a.route.value),this.activateChildRoutes(n,null,s.children)}else{const a=Mc(r.snapshot),l=a?.get(Ul)??null;s.attachRef=null,s.route=r,s.resolver=l,s.injector=a,s.outlet&&s.outlet.activateWith(r,s.injector),this.activateChildRoutes(n,null,s.children)}}else this.activateChildRoutes(n,null,i)}}class Qw{constructor(n){this.path=n,this.route=this.path[this.path.length-1]}}class vf{constructor(n,t){this.component=n,this.route=t}}function b2(e,n,t){const i=e._root;return Tc(i,n?n._root:null,t,[i.value])}function Ha(e,n){const t=Symbol(),i=n.get(e,t);return i===t?"function"!=typeof e||function wu(e){return null!==Lo(e)}(e)?n.get(e):e:i}function Tc(e,n,t,i,r={canDeactivateChecks:[],canActivateChecks:[]}){const o=Va(n);return e.children.forEach(s=>{(function C2(e,n,t,i,r={canDeactivateChecks:[],canActivateChecks:[]}){const o=e.value,s=n?n.value:null,a=t?t.getContext(e.value.outlet):null;if(s&&o.routeConfig===s.routeConfig){const l=function w2(e,n,t){if("function"==typeof t)return t(e,n);switch(t){case"pathParamsChange":return!as(e.url,n.url);case"pathParamsOrQueryParamsChange":return!as(e.url,n.url)||!ar(e.queryParams,n.queryParams);case"always":return!0;case"paramsOrQueryParamsChange":return!d_(e,n)||!ar(e.queryParams,n.queryParams);default:return!d_(e,n)}}(s,o,o.routeConfig.runGuardsAndResolvers);l?r.canActivateChecks.push(new Qw(i)):(o.data=s.data,o._resolvedData=s._resolvedData),Tc(e,n,o.component?a?a.children:null:t,i,r),l&&a&&a.outlet&&a.outlet.isActivated&&r.canDeactivateChecks.push(new vf(a.outlet.component,s))}else s&&Nc(n,a,r),r.canActivateChecks.push(new Qw(i)),Tc(e,null,o.component?a?a.children:null:t,i,r)})(s,o[s.value.outlet],t,i.concat([s.value]),r),delete o[s.value.outlet]}),an(o,(s,a)=>Nc(s,t.getContext(a),r)),r}function Nc(e,n,t){const i=Va(e),r=e.value;an(i,(o,s)=>{Nc(o,r.component?n?n.children.getContext(s):null:n,t)}),t.canDeactivateChecks.push(new vf(r.component&&n&&n.outlet&&n.outlet.isActivated?n.outlet.component:null,r))}function Ac(e){return"function"==typeof e}function __(e){return e instanceof mc||"EmptyError"===e?.name}const yf=Symbol("INITIAL_VALUE");function Ba(){return pi(e=>sf(e.map(n=>n.pipe(sn(1),function af(...e){const n=Fo(e);return qe((t,i)=>{(n?_c(e,t,n):_c(e,t)).subscribe(i)})}(yf)))).pipe(ie(n=>{for(const t of n)if(!0!==t){if(t===yf)return yf;if(!1===t||t instanceof ss)return t}return!0}),yn(n=>n!==yf),sn(1)))}function Xw(e){return function el(...e){return Es(e)}(Yt(n=>{if(ls(n))throw Kw(0,n)}),ie(n=>!0===n))}const v_={matched:!1,consumedSegments:[],remainingSegments:[],parameters:{},positionalParamSegments:{}};function eS(e,n,t,i,r){const o=y_(e,n,t);return o.matched?function B2(e,n,t,i){const r=n.canMatch;return r&&0!==r.length?Q(r.map(s=>{const a=Ha(s,e);return vo(function A2(e){return e&&Ac(e.canMatch)}(a)?a.canMatch(n,t):e.runInContext(()=>a(n,t)))})).pipe(Ba(),Xw()):Q(!0)}(i=Jw(n,i),n,t).pipe(ie(s=>!0===s?o:{...v_})):Q(o)}function y_(e,n,t){if(""===n.path)return"full"===n.pathMatch&&(e.hasChildren()||t.length>0)?{...v_}:{matched:!0,consumedSegments:[],remainingSegments:t,parameters:{},positionalParamSegments:{}};const r=(n.matcher||DL)(t,e,n);if(!r)return{...v_};const o={};an(r.posParams,(a,l)=>{o[l]=a.path});const s=r.consumed.length>0?{...o,...r.consumed[r.consumed.length-1].parameters}:o;return{matched:!0,consumedSegments:r.consumed,remainingSegments:t.slice(r.consumed.length),parameters:s,positionalParamSegments:r.posParams??{}}}function bf(e,n,t,i,r="corrected"){if(t.length>0&&function U2(e,n,t){return t.some(i=>Df(e,n,i)&&gi(i)!==pe)}(e,t,i)){const s=new _e(n,function $2(e,n,t,i){const r={};r[pe]=i,i._sourceSegment=e,i._segmentIndexShift=n.length;for(const o of t)if(""===o.path&&gi(o)!==pe){const s=new _e([],{});s._sourceSegment=e,s._segmentIndexShift=n.length,r[gi(o)]=s}return r}(e,n,i,new _e(t,e.children)));return s._sourceSegment=e,s._segmentIndexShift=n.length,{segmentGroup:s,slicedSegments:[]}}if(0===t.length&&function G2(e,n,t){return t.some(i=>Df(e,n,i))}(e,t,i)){const s=new _e(e.segments,function j2(e,n,t,i,r,o){const s={};for(const a of i)if(Df(e,t,a)&&!r[gi(a)]){const l=new _e([],{});l._sourceSegment=e,l._segmentIndexShift="legacy"===o?e.segments.length:n.length,s[gi(a)]=l}return{...r,...s}}(e,n,t,i,e.children,r));return s._sourceSegment=e,s._segmentIndexShift=n.length,{segmentGroup:s,slicedSegments:t}}const o=new _e(e.segments,e.children);return o._sourceSegment=e,o._segmentIndexShift=n.length,{segmentGroup:o,slicedSegments:t}}function Df(e,n,t){return(!(e.hasChildren()||n.length>0)||"full"!==t.pathMatch)&&""===t.path}function tS(e,n,t,i){return!!(gi(e)===i||i!==pe&&Df(n,t,e))&&("**"===e.path||y_(n,e,t).matched)}function nS(e,n,t){return 0===n.length&&!e.children[t]}const Cf=!1;class wf{constructor(n){this.segmentGroup=n||null}}class iS{constructor(n){this.urlTree=n}}function Ic(e){return xa(new wf(e))}function rS(e){return xa(new iS(e))}class Y2{constructor(n,t,i,r,o){this.injector=n,this.configLoader=t,this.urlSerializer=i,this.urlTree=r,this.config=o,this.allowRedirects=!0}apply(){const n=bf(this.urlTree.root,[],[],this.config).segmentGroup,t=new _e(n.segments,n.children);return this.expandSegmentGroup(this.injector,this.config,t,pe).pipe(ie(o=>this.createUrlTree(pf(o),this.urlTree.queryParams,this.urlTree.fragment))).pipe(Br(o=>{if(o instanceof iS)return this.allowRedirects=!1,this.match(o.urlTree);throw o instanceof wf?this.noMatchError(o):o}))}match(n){return this.expandSegmentGroup(this.injector,this.config,n.root,pe).pipe(ie(r=>this.createUrlTree(pf(r),n.queryParams,n.fragment))).pipe(Br(r=>{throw r instanceof wf?this.noMatchError(r):r}))}noMatchError(n){return new F(4002,Cf)}createUrlTree(n,t,i){const r=n_(n);return new ss(r,t,i)}expandSegmentGroup(n,t,i,r){return 0===i.segments.length&&i.hasChildren()?this.expandChildren(n,t,i).pipe(ie(o=>new _e([],o))):this.expandSegment(n,i,t,i.segments,r,!0)}expandChildren(n,t,i){const r=[];for(const o of Object.keys(i.children))"primary"===o?r.unshift(o):r.push(o);return dt(r).pipe(_o(o=>{const s=i.children[o],a=Zw(t,o);return this.expandSegmentGroup(n,a,s,o).pipe(ie(l=>({segment:l,outlet:o})))}),_w((o,s)=>(o[s.outlet]=s.segment,o),{}),vw())}expandSegment(n,t,i,r,o,s){return dt(i).pipe(_o(a=>this.expandSegmentAgainstRoute(n,t,i,a,r,o,s).pipe(Br(u=>{if(u instanceof wf)return Q(null);throw u}))),mo(a=>!!a),Br((a,l)=>{if(__(a))return nS(t,r,o)?Q(new _e([],{})):Ic(t);throw a}))}expandSegmentAgainstRoute(n,t,i,r,o,s,a){return tS(r,t,o,s)?void 0===r.redirectTo?this.matchSegmentAgainstRoute(n,t,r,o,s):a&&this.allowRedirects?this.expandSegmentAgainstRouteUsingRedirect(n,t,i,r,o,s):Ic(t):Ic(t)}expandSegmentAgainstRouteUsingRedirect(n,t,i,r,o,s){return"**"===r.path?this.expandWildCardWithParamsAgainstRouteUsingRedirect(n,i,r,s):this.expandRegularSegmentAgainstRouteUsingRedirect(n,t,i,r,o,s)}expandWildCardWithParamsAgainstRouteUsingRedirect(n,t,i,r){const o=this.applyRedirectCommands([],i.redirectTo,{});return i.redirectTo.startsWith("/")?rS(o):this.lineralizeSegments(i,o).pipe(ke(s=>{const a=new _e(s,{});return this.expandSegment(n,a,t,s,r,!1)}))}expandRegularSegmentAgainstRouteUsingRedirect(n,t,i,r,o,s){const{matched:a,consumedSegments:l,remainingSegments:u,positionalParamSegments:f}=y_(t,r,o);if(!a)return Ic(t);const p=this.applyRedirectCommands(l,r.redirectTo,f);return r.redirectTo.startsWith("/")?rS(p):this.lineralizeSegments(r,p).pipe(ke(m=>this.expandSegment(n,t,i,m.concat(u),s,!1)))}matchSegmentAgainstRoute(n,t,i,r,o){return"**"===i.path?(n=Jw(i,n),i.loadChildren?(i._loadedRoutes?Q({routes:i._loadedRoutes,injector:i._loadedInjector}):this.configLoader.loadChildren(n,i)).pipe(ie(a=>(i._loadedRoutes=a.routes,i._loadedInjector=a.injector,new _e(r,{})))):Q(new _e(r,{}))):eS(t,i,r,n).pipe(pi(({matched:s,consumedSegments:a,remainingSegments:l})=>s?this.getChildConfig(n=i._injector??n,i,r).pipe(ke(f=>{const p=f.injector??n,m=f.routes,{segmentGroup:v,slicedSegments:y}=bf(t,a,l,m),D=new _e(v.segments,v.children);if(0===y.length&&D.hasChildren())return this.expandChildren(p,m,D).pipe(ie(E=>new _e(a,E)));if(0===m.length&&0===y.length)return Q(new _e(a,{}));const w=gi(i)===o;return this.expandSegment(p,D,m,y,w?pe:o,!0).pipe(ie(O=>new _e(a.concat(O.segments),O.children)))})):Ic(t)))}getChildConfig(n,t,i){return t.children?Q({routes:t.children,injector:n}):t.loadChildren?void 0!==t._loadedRoutes?Q({routes:t._loadedRoutes,injector:t._loadedInjector}):function H2(e,n,t,i){const r=n.canLoad;return void 0===r||0===r.length?Q(!0):Q(r.map(s=>{const a=Ha(s,e);return vo(function E2(e){return e&&Ac(e.canLoad)}(a)?a.canLoad(n,t):e.runInContext(()=>a(n,t)))})).pipe(Ba(),Xw())}(n,t,i).pipe(ke(r=>r?this.configLoader.loadChildren(n,t).pipe(Yt(o=>{t._loadedRoutes=o.routes,t._loadedInjector=o.injector})):function K2(e){return xa(zw(Cf,3))}())):Q({routes:[],injector:n})}lineralizeSegments(n,t){let i=[],r=t.root;for(;;){if(i=i.concat(r.segments),0===r.numberOfChildren)return Q(i);if(r.numberOfChildren>1||!r.children[pe])return xa(new F(4e3,Cf));r=r.children[pe]}}applyRedirectCommands(n,t,i){return this.applyRedirectCreateUrlTree(t,this.urlSerializer.parse(t),n,i)}applyRedirectCreateUrlTree(n,t,i,r){const o=this.createSegmentGroup(n,t.root,i,r);return new ss(o,this.createQueryParams(t.queryParams,this.urlTree.queryParams),t.fragment)}createQueryParams(n,t){const i={};return an(n,(r,o)=>{if("string"==typeof r&&r.startsWith(":")){const a=r.substring(1);i[o]=t[a]}else i[o]=r}),i}createSegmentGroup(n,t,i,r){const o=this.createSegments(n,t.segments,i,r);let s={};return an(t.children,(a,l)=>{s[l]=this.createSegmentGroup(n,a,i,r)}),new _e(o,s)}createSegments(n,t,i,r){return t.map(o=>o.path.startsWith(":")?this.findPosParam(n,o,r):this.findOrReturn(o,i))}findPosParam(n,t,i){const r=i[t.path.substring(1)];if(!r)throw new F(4001,Cf);return r}findOrReturn(n,t){let i=0;for(const r of t){if(r.path===n.path)return t.splice(i),r;i++}return n}}class J2{}class X2{constructor(n,t,i,r,o,s,a,l){this.injector=n,this.rootComponentType=t,this.config=i,this.urlTree=r,this.url=o,this.paramsInheritanceStrategy=s,this.relativeLinkResolution=a,this.urlSerializer=l}recognize(){const n=bf(this.urlTree.root,[],[],this.config.filter(t=>void 0===t.redirectTo),this.relativeLinkResolution).segmentGroup;return this.processSegmentGroup(this.injector,this.config,n,pe).pipe(ie(t=>{if(null===t)return null;const i=new mf([],Object.freeze({}),Object.freeze({...this.urlTree.queryParams}),this.urlTree.fragment,{},pe,this.rootComponentType,null,this.urlTree.root,-1,{}),r=new $r(i,t),o=new Gw(this.url,r);return this.inheritParamsAndData(o._root),o}))}inheritParamsAndData(n){const t=n.value,i=Uw(t,this.paramsInheritanceStrategy);t.params=Object.freeze(i.params),t.data=Object.freeze(i.data),n.children.forEach(r=>this.inheritParamsAndData(r))}processSegmentGroup(n,t,i,r){return 0===i.segments.length&&i.hasChildren()?this.processChildren(n,t,i):this.processSegment(n,t,i,i.segments,r)}processChildren(n,t,i){return dt(Object.keys(i.children)).pipe(_o(r=>{const o=i.children[r],s=Zw(t,r);return this.processSegmentGroup(n,s,o,r)}),_w((r,o)=>r&&o?(r.push(...o),r):null),function yL(e,n=!1){return qe((t,i)=>{let r=0;t.subscribe(Oe(i,o=>{const s=e(o,r++);(s||n)&&i.next(o),!s&&i.complete()}))})}(r=>null!==r),lf(null),vw(),ie(r=>{if(null===r)return null;const o=oS(r);return function eV(e){e.sort((n,t)=>n.value.outlet===pe?-1:t.value.outlet===pe?1:n.value.outlet.localeCompare(t.value.outlet))}(o),o}))}processSegment(n,t,i,r,o){return dt(t).pipe(_o(s=>this.processSegmentAgainstRoute(s._injector??n,s,i,r,o)),mo(s=>!!s),Br(s=>{if(__(s))return nS(i,r,o)?Q([]):Q(null);throw s}))}processSegmentAgainstRoute(n,t,i,r,o){if(t.redirectTo||!tS(t,i,r,o))return Q(null);let s;if("**"===t.path){const a=r.length>0?Cw(r).parameters:{},l=aS(i)+r.length;s=Q({snapshot:new mf(r,a,Object.freeze({...this.urlTree.queryParams}),this.urlTree.fragment,cS(t),gi(t),t.component??t._loadedComponent??null,t,sS(i),l,uS(t),l),consumedSegments:[],remainingSegments:[]})}else s=eS(i,t,r,n).pipe(ie(({matched:a,consumedSegments:l,remainingSegments:u,parameters:f})=>{if(!a)return null;const p=aS(i)+l.length;return{snapshot:new mf(l,f,Object.freeze({...this.urlTree.queryParams}),this.urlTree.fragment,cS(t),gi(t),t.component??t._loadedComponent??null,t,sS(i),p,uS(t),p),consumedSegments:l,remainingSegments:u}}));return s.pipe(pi(a=>{if(null===a)return Q(null);const{snapshot:l,consumedSegments:u,remainingSegments:f}=a;n=t._injector??n;const p=t._loadedInjector??n,m=function tV(e){return e.children?e.children:e.loadChildren?e._loadedRoutes:[]}(t),{segmentGroup:v,slicedSegments:y}=bf(i,u,f,m.filter(w=>void 0===w.redirectTo),this.relativeLinkResolution);if(0===y.length&&v.hasChildren())return this.processChildren(p,m,v).pipe(ie(w=>null===w?null:[new $r(l,w)]));if(0===m.length&&0===y.length)return Q([new $r(l,[])]);const D=gi(t)===o;return this.processSegment(p,m,v,y,D?pe:o).pipe(ie(w=>null===w?null:[new $r(l,w)]))}))}}function nV(e){const n=e.value.routeConfig;return n&&""===n.path&&void 0===n.redirectTo}function oS(e){const n=[],t=new Set;for(const i of e){if(!nV(i)){n.push(i);continue}const r=n.find(o=>i.value.routeConfig===o.value.routeConfig);void 0!==r?(r.children.push(...i.children),t.add(r)):n.push(i)}for(const i of t){const r=oS(i.children);n.push(new $r(i.value,r))}return n.filter(i=>!t.has(i))}function sS(e){let n=e;for(;n._sourceSegment;)n=n._sourceSegment;return n}function aS(e){let n=e,t=n._segmentIndexShift??0;for(;n._sourceSegment;)n=n._sourceSegment,t+=n._segmentIndexShift??0;return t-1}function cS(e){return e.data||{}}function uS(e){return e.resolve||{}}function oV(e,n){return ke(t=>{const{targetSnapshot:i,guards:{canActivateChecks:r}}=t;if(!r.length)return Q(t);let o=0;return dt(r).pipe(_o(s=>function sV(e,n,t,i){const r=e.routeConfig,o=e._resolve;return void 0!==r?.title&&!dS(r)&&(o[vc]=r.title),function aV(e,n,t,i){const r=function lV(e){return[...Object.keys(e),...Object.getOwnPropertySymbols(e)]}(e);if(0===r.length)return Q({});const o={};return dt(r).pipe(ke(s=>function cV(e,n,t,i){const r=Mc(n)??i,o=Ha(e,r);return vo(o.resolve?o.resolve(n,t):r.runInContext(()=>o(n,t)))}(e[s],n,t,i).pipe(mo(),Yt(a=>{o[s]=a}))),Zm(1),function yw(e){return ie(()=>e)}(o),Br(s=>__(s)?Ft:xa(s)))}(o,e,n,i).pipe(ie(s=>(e._resolvedData=s,e.data=Uw(e,t).resolve,r&&dS(r)&&(e.data[vc]=r.title),null)))}(s.route,i,e,n)),Yt(()=>o++),Zm(1),ke(s=>o===r.length?Q(t):Ft))})}function dS(e){return"string"==typeof e.title||null===e.title}function b_(e){return pi(n=>{const t=e(n);return t?dt(t).pipe(ie(()=>n)):Q(n)})}let fS=(()=>{class e{buildTitle(t){let i,r=t.root;for(;void 0!==r;)i=this.getResolvedTitleForRoute(r)??i,r=r.children.find(o=>o.outlet===pe);return i}getResolvedTitleForRoute(t){return t.data[vc]}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=U({token:e,factory:function(){return bt(hS)},providedIn:"root"}),e})(),hS=(()=>{class e extends fS{constructor(t){super(),this.title=t}updateTitle(t){const i=this.buildTitle(t);void 0!==i&&this.title.setTitle(i)}}return e.\u0275fac=function(t){return new(t||e)(L(lw))},e.\u0275prov=U({token:e,factory:e.\u0275fac,providedIn:"root"}),e})();class uV{}class fV extends class dV{shouldDetach(n){return!1}store(n,t){}shouldAttach(n){return!1}retrieve(n){return null}shouldReuseRoute(n,t){return n.routeConfig===t.routeConfig}}{}const Ef=new Y("",{providedIn:"root",factory:()=>({})}),D_=new Y("ROUTES");let C_=(()=>{class e{constructor(t,i){this.injector=t,this.compiler=i,this.componentLoaders=new WeakMap,this.childrenLoaders=new WeakMap}loadComponent(t){if(this.componentLoaders.get(t))return this.componentLoaders.get(t);if(t._loadedComponent)return Q(t._loadedComponent);this.onLoadStartListener&&this.onLoadStartListener(t);const i=vo(t.loadComponent()).pipe(Yt(o=>{this.onLoadEndListener&&this.onLoadEndListener(t),t._loadedComponent=o}),Qm(()=>{this.componentLoaders.delete(t)})),r=new gw(i,()=>new je).pipe(Jm());return this.componentLoaders.set(t,r),r}loadChildren(t,i){if(this.childrenLoaders.get(i))return this.childrenLoaders.get(i);if(i._loadedRoutes)return Q({routes:i._loadedRoutes,injector:i._loadedInjector});this.onLoadStartListener&&this.onLoadStartListener(i);const o=this.loadModuleFactoryOrRoutes(i.loadChildren).pipe(ie(a=>{this.onLoadEndListener&&this.onLoadEndListener(i);let l,u,f=!1;Array.isArray(a)?u=a:(l=a.create(t).injector,u=Dw(l.get(D_,[],ee.Self|ee.Optional)));return{routes:u.map(m_),injector:l}}),Qm(()=>{this.childrenLoaders.delete(i)})),s=new gw(o,()=>new je).pipe(Jm());return this.childrenLoaders.set(i,s),s}loadModuleFactoryOrRoutes(t){return vo(t()).pipe(ke(i=>i instanceof XD||Array.isArray(i)?Q(i):dt(this.compiler.compileModuleAsync(i))))}}return e.\u0275fac=function(t){return new(t||e)(L(_n),L(um))},e.\u0275prov=U({token:e,factory:e.\u0275fac,providedIn:"root"}),e})();class pV{}class gV{shouldProcessUrl(n){return!0}extract(n){return n}merge(n,t){return n}}function mV(e){throw e}function _V(e,n,t){return n.parse("/")}const vV={paths:"exact",fragment:"ignored",matrixParams:"ignored",queryParams:"exact"},yV={paths:"subset",fragment:"ignored",matrixParams:"ignored",queryParams:"subset"};function gS(){const e=bt(Nw),n=bt(Ec),t=bt(Mm),i=bt(_n),r=bt(um),o=bt(D_,{optional:!0})??[],s=bt(Ef,{optional:!0})??{},a=bt(hS),l=bt(fS,{optional:!0}),u=bt(pV,{optional:!0}),f=bt(uV,{optional:!0}),p=new ln(null,e,n,t,i,r,Dw(o));return u&&(p.urlHandlingStrategy=u),f&&(p.routeReuseStrategy=f),p.titleStrategy=l??a,function bV(e,n){e.errorHandler&&(n.errorHandler=e.errorHandler),e.malformedUriErrorHandler&&(n.malformedUriErrorHandler=e.malformedUriErrorHandler),e.onSameUrlNavigation&&(n.onSameUrlNavigation=e.onSameUrlNavigation),e.paramsInheritanceStrategy&&(n.paramsInheritanceStrategy=e.paramsInheritanceStrategy),e.relativeLinkResolution&&(n.relativeLinkResolution=e.relativeLinkResolution),e.urlUpdateStrategy&&(n.urlUpdateStrategy=e.urlUpdateStrategy),e.canceledNavigationResolution&&(n.canceledNavigationResolution=e.canceledNavigationResolution)}(s,p),p}let ln=(()=>{class e{constructor(t,i,r,o,s,a,l){this.rootComponentType=t,this.urlSerializer=i,this.rootContexts=r,this.location=o,this.config=l,this.lastSuccessfulNavigation=null,this.currentNavigation=null,this.disposed=!1,this.navigationId=0,this.currentPageId=0,this.isNgZoneEnabled=!1,this.events=new je,this.errorHandler=mV,this.malformedUriErrorHandler=_V,this.navigated=!1,this.lastSuccessfulId=-1,this.afterPreactivation=()=>Q(void 0),this.urlHandlingStrategy=new gV,this.routeReuseStrategy=new fV,this.onSameUrlNavigation="ignore",this.paramsInheritanceStrategy="emptyOnly",this.urlUpdateStrategy="deferred",this.relativeLinkResolution="corrected",this.canceledNavigationResolution="replace",this.configLoader=s.get(C_),this.configLoader.onLoadEndListener=m=>this.triggerEvent(new e2(m)),this.configLoader.onLoadStartListener=m=>this.triggerEvent(new XL(m)),this.ngModule=s.get(ns),this.console=s.get(ZR);const p=s.get(Ye);this.isNgZoneEnabled=p instanceof Ye&&Ye.isInAngularZone(),this.resetConfig(l),this.currentUrlTree=function wL(){return new ss(new _e([],{}),{},null)}(),this.rawUrlTree=this.currentUrlTree,this.browserUrlTree=this.currentUrlTree,this.routerState=$w(this.currentUrlTree,this.rootComponentType),this.transitions=new zt({id:0,targetPageId:0,currentUrlTree:this.currentUrlTree,currentRawUrl:this.currentUrlTree,extractedUrl:this.urlHandlingStrategy.extract(this.currentUrlTree),urlAfterRedirects:this.urlHandlingStrategy.extract(this.currentUrlTree),rawUrl:this.currentUrlTree,extras:{},resolve:null,reject:null,promise:Promise.resolve(!0),source:"imperative",restoredState:null,currentSnapshot:this.routerState.snapshot,targetSnapshot:null,currentRouterState:this.routerState,targetRouterState:null,guards:{canActivateChecks:[],canDeactivateChecks:[]},guardsResult:null}),this.navigations=this.setupNavigations(this.transitions),this.processNavigations()}get browserPageId(){return this.location.getState()?.\u0275routerPageId}setupNavigations(t){const i=this.events;return t.pipe(yn(r=>0!==r.id),ie(r=>({...r,extractedUrl:this.urlHandlingStrategy.extract(r.rawUrl)})),pi(r=>{let o=!1,s=!1;return Q(r).pipe(Yt(a=>{this.currentNavigation={id:a.id,initialUrl:a.rawUrl,extractedUrl:a.extractedUrl,trigger:a.source,extras:a.extras,previousNavigation:this.lastSuccessfulNavigation?{...this.lastSuccessfulNavigation,previousNavigation:null}:null}}),pi(a=>{const l=this.browserUrlTree.toString(),u=!this.navigated||a.extractedUrl.toString()!==l||l!==this.currentUrlTree.toString();if(("reload"===this.onSameUrlNavigation||u)&&this.urlHandlingStrategy.shouldProcessUrl(a.rawUrl))return mS(a.source)&&(this.browserUrlTree=a.extractedUrl),Q(a).pipe(pi(p=>{const m=this.transitions.getValue();return i.next(new s_(p.id,this.serializeUrl(p.extractedUrl),p.source,p.restoredState)),m!==this.transitions.getValue()?Ft:Promise.resolve(p)}),function q2(e,n,t,i){return pi(r=>function z2(e,n,t,i,r){return new Y2(e,n,t,i,r).apply()}(e,n,t,r.extractedUrl,i).pipe(ie(o=>({...r,urlAfterRedirects:o}))))}(this.ngModule.injector,this.configLoader,this.urlSerializer,this.config),Yt(p=>{this.currentNavigation={...this.currentNavigation,finalUrl:p.urlAfterRedirects},r.urlAfterRedirects=p.urlAfterRedirects}),function rV(e,n,t,i,r,o){return ke(s=>function Q2(e,n,t,i,r,o,s="emptyOnly",a="legacy"){return new X2(e,n,t,i,r,s,a,o).recognize().pipe(pi(l=>null===l?function Z2(e){return new Ve(n=>n.error(e))}(new J2):Q(l)))}(e,n,t,s.urlAfterRedirects,i.serialize(s.urlAfterRedirects),i,r,o).pipe(ie(a=>({...s,targetSnapshot:a}))))}(this.ngModule.injector,this.rootComponentType,this.config,this.urlSerializer,this.paramsInheritanceStrategy,this.relativeLinkResolution),Yt(p=>{if(r.targetSnapshot=p.targetSnapshot,"eager"===this.urlUpdateStrategy){if(!p.extras.skipLocationChange){const v=this.urlHandlingStrategy.merge(p.urlAfterRedirects,p.rawUrl);this.setBrowserUrl(v,p)}this.browserUrlTree=p.urlAfterRedirects}const m=new YL(p.id,this.serializeUrl(p.extractedUrl),this.serializeUrl(p.urlAfterRedirects),p.targetSnapshot);i.next(m)}));if(u&&this.rawUrlTree&&this.urlHandlingStrategy.shouldProcessUrl(this.rawUrlTree)){const{id:m,extractedUrl:v,source:y,restoredState:D,extras:w}=a,S=new s_(m,this.serializeUrl(v),y,D);i.next(S);const O=$w(v,this.rootComponentType).snapshot;return Q(r={...a,targetSnapshot:O,urlAfterRedirects:v,extras:{...w,skipLocationChange:!1,replaceUrl:!1}})}return this.rawUrlTree=a.rawUrl,a.resolve(null),Ft}),Yt(a=>{const l=new qL(a.id,this.serializeUrl(a.extractedUrl),this.serializeUrl(a.urlAfterRedirects),a.targetSnapshot);this.triggerEvent(l)}),ie(a=>r={...a,guards:b2(a.targetSnapshot,a.currentSnapshot,this.rootContexts)}),function O2(e,n){return ke(t=>{const{targetSnapshot:i,currentSnapshot:r,guards:{canActivateChecks:o,canDeactivateChecks:s}}=t;return 0===s.length&&0===o.length?Q({...t,guardsResult:!0}):function k2(e,n,t,i){return dt(e).pipe(ke(r=>function V2(e,n,t,i,r){const o=n&&n.routeConfig?n.routeConfig.canDeactivate:null;return o&&0!==o.length?Q(o.map(a=>{const l=Mc(n)??r,u=Ha(a,l);return vo(function N2(e){return e&&Ac(e.canDeactivate)}(u)?u.canDeactivate(e,n,t,i):l.runInContext(()=>u(e,n,t,i))).pipe(mo())})).pipe(Ba()):Q(!0)}(r.component,r.route,t,n,i)),mo(r=>!0!==r,!0))}(s,i,r,e).pipe(ke(a=>a&&function S2(e){return"boolean"==typeof e}(a)?function R2(e,n,t,i){return dt(n).pipe(_o(r=>_c(function F2(e,n){return null!==e&&n&&n(new t2(e)),Q(!0)}(r.route.parent,i),function x2(e,n){return null!==e&&n&&n(new r2(e)),Q(!0)}(r.route,i),function L2(e,n,t){const i=n[n.length-1],o=n.slice(0,n.length-1).reverse().map(s=>function D2(e){const n=e.routeConfig?e.routeConfig.canActivateChild:null;return n&&0!==n.length?{node:e,guards:n}:null}(s)).filter(s=>null!==s).map(s=>pw(()=>Q(s.guards.map(l=>{const u=Mc(s.node)??t,f=Ha(l,u);return vo(function T2(e){return e&&Ac(e.canActivateChild)}(f)?f.canActivateChild(i,e):u.runInContext(()=>f(i,e))).pipe(mo())})).pipe(Ba())));return Q(o).pipe(Ba())}(e,r.path,t),function P2(e,n,t){const i=n.routeConfig?n.routeConfig.canActivate:null;if(!i||0===i.length)return Q(!0);const r=i.map(o=>pw(()=>{const s=Mc(n)??t,a=Ha(o,s);return vo(function M2(e){return e&&Ac(e.canActivate)}(a)?a.canActivate(n,e):s.runInContext(()=>a(n,e))).pipe(mo())}));return Q(r).pipe(Ba())}(e,r.route,t))),mo(r=>!0!==r,!0))}(i,o,e,n):Q(a)),ie(a=>({...t,guardsResult:a})))})}(this.ngModule.injector,a=>this.triggerEvent(a)),Yt(a=>{if(r.guardsResult=a.guardsResult,ls(a.guardsResult))throw Kw(0,a.guardsResult);const l=new JL(a.id,this.serializeUrl(a.extractedUrl),this.serializeUrl(a.urlAfterRedirects),a.targetSnapshot,!!a.guardsResult);this.triggerEvent(l)}),yn(a=>!!a.guardsResult||(this.restoreHistory(a),this.cancelNavigationTransition(a,"",3),!1)),b_(a=>{if(a.guards.canActivateChecks.length)return Q(a).pipe(Yt(l=>{const u=new ZL(l.id,this.serializeUrl(l.extractedUrl),this.serializeUrl(l.urlAfterRedirects),l.targetSnapshot);this.triggerEvent(u)}),pi(l=>{let u=!1;return Q(l).pipe(oV(this.paramsInheritanceStrategy,this.ngModule.injector),Yt({next:()=>u=!0,complete:()=>{u||(this.restoreHistory(l),this.cancelNavigationTransition(l,"",2))}}))}),Yt(l=>{const u=new QL(l.id,this.serializeUrl(l.extractedUrl),this.serializeUrl(l.urlAfterRedirects),l.targetSnapshot);this.triggerEvent(u)}))}),b_(a=>{const l=u=>{const f=[];u.routeConfig?.loadComponent&&!u.routeConfig._loadedComponent&&f.push(this.configLoader.loadComponent(u.routeConfig).pipe(Yt(p=>{u.component=p}),ie(()=>{})));for(const p of u.children)f.push(...l(p));return f};return sf(l(a.targetSnapshot.root)).pipe(lf(),sn(1))}),b_(()=>this.afterPreactivation()),ie(a=>{const l=function c2(e,n,t){const i=Sc(e,n._root,t?t._root:void 0);return new jw(i,n)}(this.routeReuseStrategy,a.targetSnapshot,a.currentRouterState);return r={...a,targetRouterState:l}}),Yt(a=>{this.currentUrlTree=a.urlAfterRedirects,this.rawUrlTree=this.urlHandlingStrategy.merge(a.urlAfterRedirects,a.rawUrl),this.routerState=a.targetRouterState,"deferred"===this.urlUpdateStrategy&&(a.extras.skipLocationChange||this.setBrowserUrl(this.rawUrlTree,a),this.browserUrlTree=a.urlAfterRedirects)}),((e,n,t)=>ie(i=>(new y2(n,i.targetRouterState,i.currentRouterState,t).activate(e),i)))(this.rootContexts,this.routeReuseStrategy,a=>this.triggerEvent(a)),Yt({next(){o=!0},complete(){o=!0}}),Qm(()=>{o||s||this.cancelNavigationTransition(r,"",1),this.currentNavigation?.id===r.id&&(this.currentNavigation=null)}),Br(a=>{if(s=!0,qw(a)){Yw(a)||(this.navigated=!0,this.restoreHistory(r,!0));const l=new gf(r.id,this.serializeUrl(r.extractedUrl),a.message,a.cancellationCode);if(i.next(l),Yw(a)){const u=this.urlHandlingStrategy.merge(a.url,this.rawUrlTree),f={skipLocationChange:r.extras.skipLocationChange,replaceUrl:"eager"===this.urlUpdateStrategy||mS(r.source)};this.scheduleNavigation(u,"imperative",null,f,{resolve:r.resolve,reject:r.reject,promise:r.promise})}else r.resolve(!1)}else{this.restoreHistory(r,!0);const l=new Vw(r.id,this.serializeUrl(r.extractedUrl),a,r.targetSnapshot??void 0);i.next(l);try{r.resolve(this.errorHandler(a))}catch(u){r.reject(u)}}return Ft}))}))}resetRootComponentType(t){this.rootComponentType=t,this.routerState.root.component=this.rootComponentType}setTransition(t){this.transitions.next({...this.transitions.value,...t})}initialNavigation(){this.setUpLocationChangeListener(),0===this.navigationId&&this.navigateByUrl(this.location.path(!0),{replaceUrl:!0})}setUpLocationChangeListener(){this.locationSubscription||(this.locationSubscription=this.location.subscribe(t=>{const i="popstate"===t.type?"popstate":"hashchange";"popstate"===i&&setTimeout(()=>{const r={replaceUrl:!0},o=t.state?.navigationId?t.state:null;if(o){const a={...o};delete a.navigationId,delete a.\u0275routerPageId,0!==Object.keys(a).length&&(r.state=a)}const s=this.parseUrl(t.url);this.scheduleNavigation(s,i,o,r)},0)}))}get url(){return this.serializeUrl(this.currentUrlTree)}getCurrentNavigation(){return this.currentNavigation}triggerEvent(t){this.events.next(t)}resetConfig(t){this.config=t.map(m_),this.navigated=!1,this.lastSuccessfulId=-1}ngOnDestroy(){this.dispose()}dispose(){this.transitions.complete(),this.locationSubscription&&(this.locationSubscription.unsubscribe(),this.locationSubscription=void 0),this.disposed=!0}createUrlTree(t,i={}){const{relativeTo:r,queryParams:o,fragment:s,queryParamsHandling:a,preserveFragment:l}=i,u=r||this.routerState.root,f=l?this.currentUrlTree.fragment:s;let p=null;switch(a){case"merge":p={...this.currentUrlTree.queryParams,...o};break;case"preserve":p=this.currentUrlTree.queryParams;break;default:p=o||null}return null!==p&&(p=this.removeEmptyProps(p)),$L(u,this.currentUrlTree,t,p,f??null)}navigateByUrl(t,i={skipLocationChange:!1}){const r=ls(t)?t:this.parseUrl(t),o=this.urlHandlingStrategy.merge(r,this.rawUrlTree);return this.scheduleNavigation(o,"imperative",null,i)}navigate(t,i={skipLocationChange:!1}){return function DV(e){for(let n=0;n{const o=t[r];return null!=o&&(i[r]=o),i},{})}processNavigations(){this.navigations.subscribe(t=>{this.navigated=!0,this.lastSuccessfulId=t.id,this.currentPageId=t.targetPageId,this.events.next(new cs(t.id,this.serializeUrl(t.extractedUrl),this.serializeUrl(this.currentUrlTree))),this.lastSuccessfulNavigation=this.currentNavigation,this.titleStrategy?.updateTitle(this.routerState.snapshot),t.resolve(!0)},t=>{this.console.warn(`Unhandled Navigation Error: ${t}`)})}scheduleNavigation(t,i,r,o,s){if(this.disposed)return Promise.resolve(!1);let a,l,u;s?(a=s.resolve,l=s.reject,u=s.promise):u=new Promise((m,v)=>{a=m,l=v});const f=++this.navigationId;let p;return"computed"===this.canceledNavigationResolution?(0===this.currentPageId&&(r=this.location.getState()),p=r&&r.\u0275routerPageId?r.\u0275routerPageId:o.replaceUrl||o.skipLocationChange?this.browserPageId??0:(this.browserPageId??0)+1):p=0,this.setTransition({id:f,targetPageId:p,source:i,restoredState:r,currentUrlTree:this.currentUrlTree,currentRawUrl:this.rawUrlTree,rawUrl:t,extras:o,resolve:a,reject:l,promise:u,currentSnapshot:this.routerState.snapshot,currentRouterState:this.routerState}),u.catch(m=>Promise.reject(m))}setBrowserUrl(t,i){const r=this.urlSerializer.serialize(t),o={...i.extras.state,...this.generateNgRouterState(i.id,i.targetPageId)};this.location.isCurrentPathEqualTo(r)||i.extras.replaceUrl?this.location.replaceState(r,"",o):this.location.go(r,"",o)}restoreHistory(t,i=!1){if("computed"===this.canceledNavigationResolution){const r=this.currentPageId-t.targetPageId;"popstate"!==t.source&&"eager"!==this.urlUpdateStrategy&&this.currentUrlTree!==this.currentNavigation?.finalUrl||0===r?this.currentUrlTree===this.currentNavigation?.finalUrl&&0===r&&(this.resetState(t),this.browserUrlTree=t.currentUrlTree,this.resetUrlToCurrentUrlTree()):this.location.historyGo(r)}else"replace"===this.canceledNavigationResolution&&(i&&this.resetState(t),this.resetUrlToCurrentUrlTree())}resetState(t){this.routerState=t.currentRouterState,this.currentUrlTree=t.currentUrlTree,this.rawUrlTree=this.urlHandlingStrategy.merge(this.currentUrlTree,t.rawUrl)}resetUrlToCurrentUrlTree(){this.location.replaceState(this.urlSerializer.serialize(this.rawUrlTree),"",this.generateNgRouterState(this.lastSuccessfulId,this.currentPageId))}cancelNavigationTransition(t,i,r){const o=new gf(t.id,this.serializeUrl(t.extractedUrl),i,r);this.triggerEvent(o),t.resolve(!1)}generateNgRouterState(t,i){return"computed"===this.canceledNavigationResolution?{navigationId:t,\u0275routerPageId:i}:{navigationId:t}}}return e.\u0275fac=function(t){lg()},e.\u0275prov=U({token:e,factory:function(){return gS()},providedIn:"root"}),e})();function mS(e){return"imperative"!==e}class _S{}let SV=(()=>{class e{constructor(t,i,r,o,s){this.router=t,this.injector=r,this.preloadingStrategy=o,this.loader=s}setUpPreloading(){this.subscription=this.router.events.pipe(yn(t=>t instanceof cs),_o(()=>this.preload())).subscribe(()=>{})}preload(){return this.processRoutes(this.injector,this.router.config)}ngOnDestroy(){this.subscription&&this.subscription.unsubscribe()}processRoutes(t,i){const r=[];for(const o of i){o.providers&&!o._injector&&(o._injector=Md(o.providers,t,`Route: ${o.path}`));const s=o._injector??t,a=o._loadedInjector??s;o.loadChildren&&!o._loadedRoutes&&void 0===o.canLoad||o.loadComponent&&!o._loadedComponent?r.push(this.preloadConfig(s,o)):(o.children||o._loadedRoutes)&&r.push(this.processRoutes(a,o.children??o._loadedRoutes))}return dt(r).pipe(fn())}preloadConfig(t,i){return this.preloadingStrategy.preload(i,()=>{let r;r=i.loadChildren&&void 0===i.canLoad?this.loader.loadChildren(t,i):Q(null);const o=r.pipe(ke(s=>null===s?Q(void 0):(i._loadedRoutes=s.routes,i._loadedInjector=s.injector,this.processRoutes(s.injector??t,s.routes))));return i.loadComponent&&!i._loadedComponent?dt([o,this.loader.loadComponent(i)]).pipe(fn()):o})}}return e.\u0275fac=function(t){return new(t||e)(L(ln),L(um),L(co),L(_S),L(C_))},e.\u0275prov=U({token:e,factory:e.\u0275fac,providedIn:"root"}),e})();const E_=new Y("");let vS=(()=>{class e{constructor(t,i,r={}){this.router=t,this.viewportScroller=i,this.options=r,this.lastId=0,this.lastSource="imperative",this.restoredId=0,this.store={},r.scrollPositionRestoration=r.scrollPositionRestoration||"disabled",r.anchorScrolling=r.anchorScrolling||"disabled"}init(){"disabled"!==this.options.scrollPositionRestoration&&this.viewportScroller.setHistoryScrollRestoration("manual"),this.routerEventsSubscription=this.createScrollEvents(),this.scrollEventsSubscription=this.consumeScrollEvents()}createScrollEvents(){return this.router.events.subscribe(t=>{t instanceof s_?(this.store[this.lastId]=this.viewportScroller.getScrollPosition(),this.lastSource=t.navigationTrigger,this.restoredId=t.restoredState?t.restoredState.navigationId:0):t instanceof cs&&(this.lastId=t.id,this.scheduleScrollEvent(t,this.router.parseUrl(t.urlAfterRedirects).fragment))})}consumeScrollEvents(){return this.router.events.subscribe(t=>{t instanceof Hw&&(t.position?"top"===this.options.scrollPositionRestoration?this.viewportScroller.scrollToPosition([0,0]):"enabled"===this.options.scrollPositionRestoration&&this.viewportScroller.scrollToPosition(t.position):t.anchor&&"enabled"===this.options.anchorScrolling?this.viewportScroller.scrollToAnchor(t.anchor):"disabled"!==this.options.scrollPositionRestoration&&this.viewportScroller.scrollToPosition([0,0]))})}scheduleScrollEvent(t,i){this.router.triggerEvent(new Hw(t,"popstate"===this.lastSource?this.store[this.restoredId]:null,i))}ngOnDestroy(){this.routerEventsSubscription&&this.routerEventsSubscription.unsubscribe(),this.scrollEventsSubscription&&this.scrollEventsSubscription.unsubscribe()}}return e.\u0275fac=function(t){lg()},e.\u0275prov=U({token:e,factory:e.\u0275fac}),e})();function ja(e,n){return{\u0275kind:e,\u0275providers:n}}function M_(e){return[{provide:D_,multi:!0,useValue:e}]}function bS(){const e=bt(_n);return n=>{const t=e.get(lc);if(n!==t.components[0])return;const i=e.get(ln),r=e.get(DS);1===e.get(T_)&&i.initialNavigation(),e.get(CS,null,ee.Optional)?.setUpPreloading(),e.get(E_,null,ee.Optional)?.init(),i.resetRootComponentType(t.componentTypes[0]),r.closed||(r.next(),r.unsubscribe())}}const DS=new Y("",{factory:()=>new je}),T_=new Y("",{providedIn:"root",factory:()=>1});const CS=new Y("");function NV(e){return ja(0,[{provide:CS,useExisting:SV},{provide:_S,useExisting:e}])}const wS=new Y("ROUTER_FORROOT_GUARD"),AV=[Mm,{provide:Nw,useClass:e_},{provide:ln,useFactory:gS},Ec,{provide:us,useFactory:function yS(e){return e.routerState.root},deps:[ln]},C_];function IV(){return new q1("Router",ln)}let Af=(()=>{class e{constructor(t){}static forRoot(t,i){return{ngModule:e,providers:[AV,[],M_(t),{provide:wS,useFactory:xV,deps:[[ln,new Rl,new xl]]},{provide:Ef,useValue:i||{}},i?.useHash?{provide:rs,useClass:Hx}:{provide:rs,useClass:bC},{provide:E_,useFactory:()=>{const e=bt(ln),n=bt(tP),t=bt(Ef);return t.scrollOffset&&n.setOffset(t.scrollOffset),new vS(e,n,t)}},i?.preloadingStrategy?NV(i.preloadingStrategy).\u0275providers:[],{provide:q1,multi:!0,useFactory:IV},i?.initialNavigation?FV(i):[],[{provide:SS,useFactory:bS},{provide:$1,multi:!0,useExisting:SS}]]}}static forChild(t){return{ngModule:e,providers:[M_(t)]}}}return e.\u0275fac=function(t){return new(t||e)(L(wS,8))},e.\u0275mod=ge({type:e}),e.\u0275inj=Me({imports:[p_]}),e})();function xV(e){return"guarded"}function FV(e){return["disabled"===e.initialNavigation?ja(3,[{provide:Fd,multi:!0,useFactory:()=>{const n=bt(ln);return()=>{n.setUpLocationChangeListener()}}},{provide:T_,useValue:2}]).\u0275providers:[],"enabledBlocking"===e.initialNavigation?ja(2,[{provide:T_,useValue:0},{provide:Fd,multi:!0,deps:[_n],useFactory:n=>{const t=n.get(Lx,Promise.resolve());let i=!1;return()=>t.then(()=>new Promise(o=>{const s=n.get(ln),a=n.get(DS);(function r(o){n.get(ln).events.pipe(yn(a=>a instanceof cs||a instanceof gf||a instanceof Vw),ie(a=>a instanceof cs||a instanceof gf&&(0===a.code||1===a.code)&&null),yn(a=>null!==a),sn(1)).subscribe(()=>{o()})})(()=>{o(!0),i=!0}),s.afterPreactivation=()=>(o(!0),i||a.closed?Q(void 0):a),s.initialNavigation()}))}}]).\u0275providers:[]]}const SS=new Y("");let ES=(()=>{class e{constructor(t,i){this._renderer=t,this._elementRef=i,this.onChange=r=>{},this.onTouched=()=>{}}setProperty(t,i){this._renderer.setProperty(this._elementRef.nativeElement,t,i)}registerOnTouched(t){this.onTouched=t}registerOnChange(t){this.onChange=t}setDisabledState(t){this.setProperty("disabled",t)}}return e.\u0275fac=function(t){return new(t||e)(C(ui),C(Qe))},e.\u0275dir=B({type:e}),e})(),ds=(()=>{class e extends ES{}return e.\u0275fac=function(){let n;return function(i){return(n||(n=gn(e)))(i||e)}}(),e.\u0275dir=B({type:e,features:[Le]}),e})();const lr=new Y("NgValueAccessor"),HV={provide:lr,useExisting:De(()=>Oc),multi:!0},jV=new Y("CompositionEventMode");let Oc=(()=>{class e extends ES{constructor(t,i,r){super(t,i),this._compositionMode=r,this._composing=!1,null==this._compositionMode&&(this._compositionMode=!function BV(){const e=sr()?sr().getUserAgent():"";return/android (\d+)/.test(e.toLowerCase())}())}writeValue(t){this.setProperty("value",t??"")}_handleInput(t){(!this._compositionMode||this._compositionMode&&!this._composing)&&this.onChange(t)}_compositionStart(){this._composing=!0}_compositionEnd(t){this._composing=!1,this._compositionMode&&this.onChange(t)}}return e.\u0275fac=function(t){return new(t||e)(C(ui),C(Qe),C(jV,8))},e.\u0275dir=B({type:e,selectors:[["input","formControlName","",3,"type","checkbox"],["textarea","formControlName",""],["input","formControl","",3,"type","checkbox"],["textarea","formControl",""],["input","ngModel","",3,"type","checkbox"],["textarea","ngModel",""],["","ngDefaultControl",""]],hostBindings:function(t,i){1&t&&K("input",function(o){return i._handleInput(o.target.value)})("blur",function(){return i.onTouched()})("compositionstart",function(){return i._compositionStart()})("compositionend",function(o){return i._compositionEnd(o.target.value)})},features:[it([HV]),Le]}),e})();const bn=new Y("NgValidators"),bo=new Y("NgAsyncValidators");function PS(e){return null!=e}function LS(e){return ql(e)?dt(e):e}function VS(e){let n={};return e.forEach(t=>{n=null!=t?{...n,...t}:n}),0===Object.keys(n).length?null:n}function HS(e,n){return n.map(t=>t(e))}function BS(e){return e.map(n=>function GV(e){return!e.validate}(n)?n:t=>n.validate(t))}function N_(e){return null!=e?function jS(e){if(!e)return null;const n=e.filter(PS);return 0==n.length?null:function(t){return VS(HS(t,n))}}(BS(e)):null}function A_(e){return null!=e?function $S(e){if(!e)return null;const n=e.filter(PS);return 0==n.length?null:function(t){return function LV(...e){const n=yr(e),{args:t,keys:i}=dw(e),r=new Ve(o=>{const{length:s}=t;if(!s)return void o.complete();const a=new Array(s);let l=s,u=s;for(let f=0;f{p||(p=!0,u--),a[f]=m},()=>l--,void 0,()=>{(!l||!p)&&(u||o.next(i?fw(i,a):a),o.complete())}))}});return n?r.pipe(qm(n)):r}(HS(t,n).map(LS)).pipe(ie(VS))}}(BS(e)):null}function US(e,n){return null===e?[n]:Array.isArray(e)?[...e,n]:[e,n]}function I_(e){return e?Array.isArray(e)?e:[e]:[]}function Of(e,n){return Array.isArray(e)?e.includes(n):e===n}function KS(e,n){const t=I_(n);return I_(e).forEach(r=>{Of(t,r)||t.push(r)}),t}function zS(e,n){return I_(n).filter(t=>!Of(e,t))}class YS{constructor(){this._rawValidators=[],this._rawAsyncValidators=[],this._onDestroyCallbacks=[]}get value(){return this.control?this.control.value:null}get valid(){return this.control?this.control.valid:null}get invalid(){return this.control?this.control.invalid:null}get pending(){return this.control?this.control.pending:null}get disabled(){return this.control?this.control.disabled:null}get enabled(){return this.control?this.control.enabled:null}get errors(){return this.control?this.control.errors:null}get pristine(){return this.control?this.control.pristine:null}get dirty(){return this.control?this.control.dirty:null}get touched(){return this.control?this.control.touched:null}get status(){return this.control?this.control.status:null}get untouched(){return this.control?this.control.untouched:null}get statusChanges(){return this.control?this.control.statusChanges:null}get valueChanges(){return this.control?this.control.valueChanges:null}get path(){return null}_setValidators(n){this._rawValidators=n||[],this._composedValidatorFn=N_(this._rawValidators)}_setAsyncValidators(n){this._rawAsyncValidators=n||[],this._composedAsyncValidatorFn=A_(this._rawAsyncValidators)}get validator(){return this._composedValidatorFn||null}get asyncValidator(){return this._composedAsyncValidatorFn||null}_registerOnDestroy(n){this._onDestroyCallbacks.push(n)}_invokeOnDestroyCallbacks(){this._onDestroyCallbacks.forEach(n=>n()),this._onDestroyCallbacks=[]}reset(n){this.control&&this.control.reset(n)}hasError(n,t){return!!this.control&&this.control.hasError(n,t)}getError(n,t){return this.control?this.control.getError(n,t):null}}class xn extends YS{get formDirective(){return null}get path(){return null}}class Do extends YS{constructor(){super(...arguments),this._parent=null,this.name=null,this.valueAccessor=null}}let O_=(()=>{class e extends class qS{constructor(n){this._cd=n}get isTouched(){return!!this._cd?.control?.touched}get isUntouched(){return!!this._cd?.control?.untouched}get isPristine(){return!!this._cd?.control?.pristine}get isDirty(){return!!this._cd?.control?.dirty}get isValid(){return!!this._cd?.control?.valid}get isInvalid(){return!!this._cd?.control?.invalid}get isPending(){return!!this._cd?.control?.pending}get isSubmitted(){return!!this._cd?.submitted}}{constructor(t){super(t)}}return e.\u0275fac=function(t){return new(t||e)(C(Do,2))},e.\u0275dir=B({type:e,selectors:[["","formControlName",""],["","ngModel",""],["","formControl",""]],hostVars:14,hostBindings:function(t,i){2&t&&ct("ng-untouched",i.isUntouched)("ng-touched",i.isTouched)("ng-pristine",i.isPristine)("ng-dirty",i.isDirty)("ng-valid",i.isValid)("ng-invalid",i.isInvalid)("ng-pending",i.isPending)},features:[Le]}),e})();const kc="VALID",Rf="INVALID",$a="PENDING",Rc="DISABLED";function ZS(e){return Array.isArray(e)?N_(e):e||null}function QS(e){return Array.isArray(e)?A_(e):e||null}function xf(e){return null!=e&&!Array.isArray(e)&&"object"==typeof e}function xc(e,n){(function V_(e,n){const t=function GS(e){return e._rawValidators}(e);null!==n.validator?e.setValidators(US(t,n.validator)):"function"==typeof t&&e.setValidators([t]);const i=function WS(e){return e._rawAsyncValidators}(e);null!==n.asyncValidator?e.setAsyncValidators(US(i,n.asyncValidator)):"function"==typeof i&&e.setAsyncValidators([i]);const r=()=>e.updateValueAndValidity();Lf(n._rawValidators,r),Lf(n._rawAsyncValidators,r)})(e,n),n.valueAccessor.writeValue(e.value),e.disabled&&n.valueAccessor.setDisabledState?.(!0),function eH(e,n){n.valueAccessor.registerOnChange(t=>{e._pendingValue=t,e._pendingChange=!0,e._pendingDirty=!0,"change"===e.updateOn&&nE(e,n)})}(e,n),function nH(e,n){const t=(i,r)=>{n.valueAccessor.writeValue(i),r&&n.viewToModelUpdate(i)};e.registerOnChange(t),n._registerOnDestroy(()=>{e._unregisterOnChange(t)})}(e,n),function tH(e,n){n.valueAccessor.registerOnTouched(()=>{e._pendingTouched=!0,"blur"===e.updateOn&&e._pendingChange&&nE(e,n),"submit"!==e.updateOn&&e.markAsTouched()})}(e,n),function XV(e,n){if(n.valueAccessor.setDisabledState){const t=i=>{n.valueAccessor.setDisabledState(i)};e.registerOnDisabledChange(t),n._registerOnDestroy(()=>{e._unregisterOnDisabledChange(t)})}}(e,n)}function Lf(e,n){e.forEach(t=>{t.registerOnValidatorChange&&t.registerOnValidatorChange(n)})}function nE(e,n){e._pendingDirty&&e.markAsDirty(),e.setValue(e._pendingValue,{emitModelToViewChange:!1}),n.viewToModelUpdate(e._pendingValue),e._pendingChange=!1}function sE(e,n){const t=e.indexOf(n);t>-1&&e.splice(t,1)}function aE(e){return"object"==typeof e&&null!==e&&2===Object.keys(e).length&&"value"in e&&"disabled"in e}const uH={provide:Do,useExisting:De(()=>Hf)},dE=(()=>Promise.resolve())();let Hf=(()=>{class e extends Do{constructor(t,i,r,o,s){super(),this._changeDetectorRef=s,this.control=new class extends class tE{constructor(n,t){this._pendingDirty=!1,this._hasOwnPendingAsyncValidator=!1,this._pendingTouched=!1,this._onCollectionChange=()=>{},this._parent=null,this.pristine=!0,this.touched=!1,this._onDisabledChange=[],this._rawValidators=n,this._rawAsyncValidators=t,this._composedValidatorFn=ZS(this._rawValidators),this._composedAsyncValidatorFn=QS(this._rawAsyncValidators)}get validator(){return this._composedValidatorFn}set validator(n){this._rawValidators=this._composedValidatorFn=n}get asyncValidator(){return this._composedAsyncValidatorFn}set asyncValidator(n){this._rawAsyncValidators=this._composedAsyncValidatorFn=n}get parent(){return this._parent}get valid(){return this.status===kc}get invalid(){return this.status===Rf}get pending(){return this.status==$a}get disabled(){return this.status===Rc}get enabled(){return this.status!==Rc}get dirty(){return!this.pristine}get untouched(){return!this.touched}get updateOn(){return this._updateOn?this._updateOn:this.parent?this.parent.updateOn:"change"}setValidators(n){this._rawValidators=n,this._composedValidatorFn=ZS(n)}setAsyncValidators(n){this._rawAsyncValidators=n,this._composedAsyncValidatorFn=QS(n)}addValidators(n){this.setValidators(KS(n,this._rawValidators))}addAsyncValidators(n){this.setAsyncValidators(KS(n,this._rawAsyncValidators))}removeValidators(n){this.setValidators(zS(n,this._rawValidators))}removeAsyncValidators(n){this.setAsyncValidators(zS(n,this._rawAsyncValidators))}hasValidator(n){return Of(this._rawValidators,n)}hasAsyncValidator(n){return Of(this._rawAsyncValidators,n)}clearValidators(){this.validator=null}clearAsyncValidators(){this.asyncValidator=null}markAsTouched(n={}){this.touched=!0,this._parent&&!n.onlySelf&&this._parent.markAsTouched(n)}markAllAsTouched(){this.markAsTouched({onlySelf:!0}),this._forEachChild(n=>n.markAllAsTouched())}markAsUntouched(n={}){this.touched=!1,this._pendingTouched=!1,this._forEachChild(t=>{t.markAsUntouched({onlySelf:!0})}),this._parent&&!n.onlySelf&&this._parent._updateTouched(n)}markAsDirty(n={}){this.pristine=!1,this._parent&&!n.onlySelf&&this._parent.markAsDirty(n)}markAsPristine(n={}){this.pristine=!0,this._pendingDirty=!1,this._forEachChild(t=>{t.markAsPristine({onlySelf:!0})}),this._parent&&!n.onlySelf&&this._parent._updatePristine(n)}markAsPending(n={}){this.status=$a,!1!==n.emitEvent&&this.statusChanges.emit(this.status),this._parent&&!n.onlySelf&&this._parent.markAsPending(n)}disable(n={}){const t=this._parentMarkedDirty(n.onlySelf);this.status=Rc,this.errors=null,this._forEachChild(i=>{i.disable({...n,onlySelf:!0})}),this._updateValue(),!1!==n.emitEvent&&(this.valueChanges.emit(this.value),this.statusChanges.emit(this.status)),this._updateAncestors({...n,skipPristineCheck:t}),this._onDisabledChange.forEach(i=>i(!0))}enable(n={}){const t=this._parentMarkedDirty(n.onlySelf);this.status=kc,this._forEachChild(i=>{i.enable({...n,onlySelf:!0})}),this.updateValueAndValidity({onlySelf:!0,emitEvent:n.emitEvent}),this._updateAncestors({...n,skipPristineCheck:t}),this._onDisabledChange.forEach(i=>i(!1))}_updateAncestors(n){this._parent&&!n.onlySelf&&(this._parent.updateValueAndValidity(n),n.skipPristineCheck||this._parent._updatePristine(),this._parent._updateTouched())}setParent(n){this._parent=n}getRawValue(){return this.value}updateValueAndValidity(n={}){this._setInitialStatus(),this._updateValue(),this.enabled&&(this._cancelExistingSubscription(),this.errors=this._runValidator(),this.status=this._calculateStatus(),(this.status===kc||this.status===$a)&&this._runAsyncValidator(n.emitEvent)),!1!==n.emitEvent&&(this.valueChanges.emit(this.value),this.statusChanges.emit(this.status)),this._parent&&!n.onlySelf&&this._parent.updateValueAndValidity(n)}_updateTreeValidity(n={emitEvent:!0}){this._forEachChild(t=>t._updateTreeValidity(n)),this.updateValueAndValidity({onlySelf:!0,emitEvent:n.emitEvent})}_setInitialStatus(){this.status=this._allControlsDisabled()?Rc:kc}_runValidator(){return this.validator?this.validator(this):null}_runAsyncValidator(n){if(this.asyncValidator){this.status=$a,this._hasOwnPendingAsyncValidator=!0;const t=LS(this.asyncValidator(this));this._asyncValidationSubscription=t.subscribe(i=>{this._hasOwnPendingAsyncValidator=!1,this.setErrors(i,{emitEvent:n})})}}_cancelExistingSubscription(){this._asyncValidationSubscription&&(this._asyncValidationSubscription.unsubscribe(),this._hasOwnPendingAsyncValidator=!1)}setErrors(n,t={}){this.errors=n,this._updateControlsErrors(!1!==t.emitEvent)}get(n){let t=n;return null==t||(Array.isArray(t)||(t=t.split(".")),0===t.length)?null:t.reduce((i,r)=>i&&i._find(r),this)}getError(n,t){const i=t?this.get(t):this;return i&&i.errors?i.errors[n]:null}hasError(n,t){return!!this.getError(n,t)}get root(){let n=this;for(;n._parent;)n=n._parent;return n}_updateControlsErrors(n){this.status=this._calculateStatus(),n&&this.statusChanges.emit(this.status),this._parent&&this._parent._updateControlsErrors(n)}_initObservables(){this.valueChanges=new de,this.statusChanges=new de}_calculateStatus(){return this._allControlsDisabled()?Rc:this.errors?Rf:this._hasOwnPendingAsyncValidator||this._anyControlsHaveStatus($a)?$a:this._anyControlsHaveStatus(Rf)?Rf:kc}_anyControlsHaveStatus(n){return this._anyControls(t=>t.status===n)}_anyControlsDirty(){return this._anyControls(n=>n.dirty)}_anyControlsTouched(){return this._anyControls(n=>n.touched)}_updatePristine(n={}){this.pristine=!this._anyControlsDirty(),this._parent&&!n.onlySelf&&this._parent._updatePristine(n)}_updateTouched(n={}){this.touched=this._anyControlsTouched(),this._parent&&!n.onlySelf&&this._parent._updateTouched(n)}_registerOnCollectionChange(n){this._onCollectionChange=n}_setUpdateStrategy(n){xf(n)&&null!=n.updateOn&&(this._updateOn=n.updateOn)}_parentMarkedDirty(n){return!n&&!(!this._parent||!this._parent.dirty)&&!this._parent._anyControlsDirty()}_find(n){return null}}{constructor(n=null,t,i){super(function F_(e){return(xf(e)?e.validators:e)||null}(t),function P_(e,n){return(xf(n)?n.asyncValidators:e)||null}(i,t)),this.defaultValue=null,this._onChange=[],this._pendingChange=!1,this._applyFormState(n),this._setUpdateStrategy(t),this._initObservables(),this.updateValueAndValidity({onlySelf:!0,emitEvent:!!this.asyncValidator}),xf(t)&&(t.nonNullable||t.initialValueIsDefault)&&(this.defaultValue=aE(n)?n.value:n)}setValue(n,t={}){this.value=this._pendingValue=n,this._onChange.length&&!1!==t.emitModelToViewChange&&this._onChange.forEach(i=>i(this.value,!1!==t.emitViewToModelChange)),this.updateValueAndValidity(t)}patchValue(n,t={}){this.setValue(n,t)}reset(n=this.defaultValue,t={}){this._applyFormState(n),this.markAsPristine(t),this.markAsUntouched(t),this.setValue(this.value,t),this._pendingChange=!1}_updateValue(){}_anyControls(n){return!1}_allControlsDisabled(){return this.disabled}registerOnChange(n){this._onChange.push(n)}_unregisterOnChange(n){sE(this._onChange,n)}registerOnDisabledChange(n){this._onDisabledChange.push(n)}_unregisterOnDisabledChange(n){sE(this._onDisabledChange,n)}_forEachChild(n){}_syncPendingControls(){return!("submit"!==this.updateOn||(this._pendingDirty&&this.markAsDirty(),this._pendingTouched&&this.markAsTouched(),!this._pendingChange)||(this.setValue(this._pendingValue,{onlySelf:!0,emitModelToViewChange:!1}),0))}_applyFormState(n){aE(n)?(this.value=this._pendingValue=n.value,n.disabled?this.disable({onlySelf:!0,emitEvent:!1}):this.enable({onlySelf:!0,emitEvent:!1})):this.value=this._pendingValue=n}},this._registered=!1,this.update=new de,this._parent=t,this._setValidators(i),this._setAsyncValidators(r),this.valueAccessor=function B_(e,n){if(!n)return null;let t,i,r;return Array.isArray(n),n.forEach(o=>{o.constructor===Oc?t=o:function oH(e){return Object.getPrototypeOf(e.constructor)===ds}(o)?i=o:r=o}),r||i||t||null}(0,o)}ngOnChanges(t){if(this._checkForErrors(),!this._registered||"name"in t){if(this._registered&&(this._checkName(),this.formDirective)){const i=t.name.previousValue;this.formDirective.removeControl({name:i,path:this._getPath(i)})}this._setUpControl()}"isDisabled"in t&&this._updateDisabled(t),function H_(e,n){if(!e.hasOwnProperty("model"))return!1;const t=e.model;return!!t.isFirstChange()||!Object.is(n,t.currentValue)}(t,this.viewModel)&&(this._updateValue(this.model),this.viewModel=this.model)}ngOnDestroy(){this.formDirective&&this.formDirective.removeControl(this)}get path(){return this._getPath(this.name)}get formDirective(){return this._parent?this._parent.formDirective:null}viewToModelUpdate(t){this.viewModel=t,this.update.emit(t)}_setUpControl(){this._setUpdateStrategy(),this._isStandalone()?this._setUpStandalone():this.formDirective.addControl(this),this._registered=!0}_setUpdateStrategy(){this.options&&null!=this.options.updateOn&&(this.control._updateOn=this.options.updateOn)}_isStandalone(){return!this._parent||!(!this.options||!this.options.standalone)}_setUpStandalone(){xc(this.control,this),this.control.updateValueAndValidity({emitEvent:!1})}_checkForErrors(){this._isStandalone()||this._checkParentType(),this._checkName()}_checkParentType(){}_checkName(){this.options&&this.options.name&&(this.name=this.options.name),this._isStandalone()}_updateValue(t){dE.then(()=>{this.control.setValue(t,{emitViewToModelChange:!1}),this._changeDetectorRef?.markForCheck()})}_updateDisabled(t){const i=t.isDisabled.currentValue,r=0!==i&&function Lr(e){return"boolean"==typeof e?e:null!=e&&"false"!==e}(i);dE.then(()=>{r&&!this.control.disabled?this.control.disable():!r&&this.control.disabled&&this.control.enable(),this._changeDetectorRef?.markForCheck()})}_getPath(t){return this._parent?function Ff(e,n){return[...n.path,e]}(t,this._parent):[t]}}return e.\u0275fac=function(t){return new(t||e)(C(xn,9),C(bn,10),C(bo,10),C(lr,10),C(Pr,8))},e.\u0275dir=B({type:e,selectors:[["","ngModel","",3,"formControlName","",3,"formControl",""]],inputs:{name:"name",isDisabled:["disabled","isDisabled"],model:["ngModel","model"],options:["ngModelOptions","options"]},outputs:{update:"ngModelChange"},exportAs:["ngModel"],features:[it([uH]),Le,Wt]}),e})();const fH={provide:lr,useExisting:De(()=>$_),multi:!0};let $_=(()=>{class e extends ds{writeValue(t){this.setProperty("value",t??"")}registerOnChange(t){this.onChange=i=>{t(""==i?null:parseFloat(i))}}}return e.\u0275fac=function(){let n;return function(i){return(n||(n=gn(e)))(i||e)}}(),e.\u0275dir=B({type:e,selectors:[["input","type","number","formControlName",""],["input","type","number","formControl",""],["input","type","number","ngModel",""]],hostBindings:function(t,i){1&t&&K("input",function(o){return i.onChange(o.target.value)})("blur",function(){return i.onTouched()})},features:[it([fH]),Le]}),e})(),fE=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=ge({type:e}),e.\u0275inj=Me({}),e})(),FH=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=ge({type:e}),e.\u0275inj=Me({imports:[fE]}),e})(),IE=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=ge({type:e}),e.\u0275inj=Me({imports:[FH]}),e})();const OE=new Y("ngx-mask config"),kE=new Y("new ngx-mask config"),RE=new Y("initial ngx-mask config"),LH={suffix:"",prefix:"",thousandSeparator:" ",decimalMarker:[".",","],clearIfNotMatch:!1,showTemplate:!1,showMaskTyped:!1,placeHolderCharacter:"_",dropSpecialCharacters:!0,hiddenInput:void 0,shownMaskExpression:"",separatorLimit:"",allowNegativeNumbers:!1,validation:!0,specialCharacters:["-","/","(",")",".",":"," ","+",",","@","[","]",'"',"'"],leadZeroDateTime:!1,triggerOnMaskChange:!1,maskFilled:new de,patterns:{0:{pattern:new RegExp("\\d")},9:{pattern:new RegExp("\\d"),optional:!0},X:{pattern:new RegExp("\\d"),symbol:"*"},A:{pattern:new RegExp("[a-zA-Z0-9]")},S:{pattern:new RegExp("[a-zA-Z]")},U:{pattern:new RegExp("[A-Z]")},L:{pattern:new RegExp("[a-z]")},d:{pattern:new RegExp("\\d")},m:{pattern:new RegExp("\\d")},M:{pattern:new RegExp("\\d")},H:{pattern:new RegExp("\\d")},h:{pattern:new RegExp("\\d")},s:{pattern:new RegExp("\\d")}}};let VH=(()=>{class e{constructor(t){this._config=t,this.maskExpression="",this.actualValue="",this.shownMaskExpression="",this._formatWithSeparators=(i,r,o,s)=>{let a=[],l="";if(Array.isArray(o)){const v=new RegExp(o.map(y=>"[\\^$.|?*+()".indexOf(y)>=0?`\\${y}`:y).join("|"));a=i.split(v),l=i.match(v)?.[0]??""}else a=i.split(o),l=o;const u=a.length>1?`${l}${a[1]}`:"";let f=a[0]??"";const p=this.separatorLimit.replace(/\s/g,"");p&&+p&&(f="-"===f[0]?`-${f.slice(1,f.length).slice(0,p.length)}`:f.slice(0,p.length));const m=/(\d+)(\d{3})/;for(;r&&m.test(f);)f=f.replace(m,"$1"+r+"$2");return void 0===s?f+u:0===s?f:f+u.substring(0,s+1)},this.percentage=i=>Number(i)>=0&&Number(i)<=100,this.getPrecision=i=>{const r=i.split(".");return r.length>1?Number(r[r.length-1]):1/0},this.checkAndRemoveSuffix=i=>{for(let r=this.suffix?.length-1;r>=0;r--){const o=this.suffix.substring(r,this.suffix?.length);if(i.includes(o)&&r!==this.suffix?.length-1&&(r-1<0||!i.includes(this.suffix.substring(r-1,this.suffix?.length))))return i.replace(o,"")}return i},this.checkInputPrecision=(i,r,o)=>{if(r<1/0){if(Array.isArray(o)){const u=o.find(f=>f!==this.thousandSeparator);o=u||o[0]}const s=new RegExp(this._charToRegExpExpression(o)+`\\d{${r}}.*$`),l=(i.match(s)??[])[0]?.length??0;l-1>r&&(i=i.substring(0,i.length-(l-1-r))),0===r&&this._compareOrIncludes(i[i.length-1],o,this.thousandSeparator)&&(i=i.substring(0,i.length-1))}return i},this._shift=new Set,this.clearIfNotMatch=this._config.clearIfNotMatch,this.dropSpecialCharacters=this._config.dropSpecialCharacters,this.maskSpecialCharacters=this._config.specialCharacters,this.maskAvailablePatterns=this._config.patterns,this.prefix=this._config.prefix,this.suffix=this._config.suffix,this.thousandSeparator=this._config.thousandSeparator,this.decimalMarker=this._config.decimalMarker,this.hiddenInput=this._config.hiddenInput,this.showMaskTyped=this._config.showMaskTyped,this.placeHolderCharacter=this._config.placeHolderCharacter,this.validation=this._config.validation,this.separatorLimit=this._config.separatorLimit,this.allowNegativeNumbers=this._config.allowNegativeNumbers,this.leadZeroDateTime=this._config.leadZeroDateTime}applyMaskWithPattern(t,i){const[r,o]=i;return this.customPattern=o,this.applyMask(t,r)}applyMask(t,i,r=0,o=!1,s=!1,a=(()=>{})){if(!i||"string"!=typeof t)return"";let l=0,u="",f=!1,p=!1,m=1,v=!1;t.slice(0,this.prefix.length)===this.prefix&&(t=t.slice(this.prefix.length,t.length)),this.suffix&&t?.length>0&&(t=this.checkAndRemoveSuffix(t));const y=t.toString().split("");if("IP"===i){const A=t.split(".");this.ipError=this._validIP(A),i="099.099.099.099"}const D=[];for(let A=0;A11?"00.000.000/0000-00":"000.000.000-00"),i.startsWith("percent")){if(t.match("[a-z]|[A-Z]")||t.match(/[-!$%^&*()_+|~=`{}\[\]:";'<>?,\/.]/)){t=this._stripToDecimal(t);const A=this.getPrecision(i);t=this.checkInputPrecision(t,A,this.decimalMarker)}t.indexOf(".")>0&&!this.percentage(t.substring(0,t.indexOf(".")))&&(t=`${t.substring(0,t.indexOf(".")-1)}${t.substring(t.indexOf("."),t.length)}`),u=this.percentage(t)?t:t.substring(0,t.length-1)}else if(i.startsWith("separator")){(t.match("[w\u0430-\u044f\u0410-\u042f]")||t.match("[\u0401\u0451\u0410-\u044f]")||t.match("[a-z]|[A-Z]")||t.match(/[-@#!$%\\^&*()_\xa3\xac'+|~=`{}\]:";<>.?/]/)||t.match("[^A-Za-z0-9,]"))&&(t=this._stripToDecimal(t)),t=t.length>1&&"0"===t[0]&&t[1]!==this.thousandSeparator&&!this._compareOrIncludes(t[1],this.decimalMarker,this.thousandSeparator)&&!s?t.slice(0,t.length-1):t,s&&(t=this._compareOrIncludes(t[t.length-1],this.decimalMarker,this.thousandSeparator)?t.slice(0,t.length-1):t);const A=this._charToRegExpExpression(this.thousandSeparator);let R='@#!$%^&*()_+|~=`{}\\[\\]:\\s,\\.";<>?\\/'.replace(A,"");if(Array.isArray(this.decimalMarker))for(const We of this.decimalMarker)R=R.replace(this._charToRegExpExpression(We),"");else R=R.replace(this._charToRegExpExpression(this.decimalMarker),"");const W=new RegExp("["+R+"]");(t.match(W)||1===t.length&&this._compareOrIncludes(t,this.decimalMarker,this.thousandSeparator))&&(t=t.substring(0,t.length-1));const ve=this.getPrecision(i),Te=(t=this.checkInputPrecision(t,ve,this.decimalMarker)).replace(new RegExp(A,"g"),"");u=this._formatWithSeparators(Te,this.thousandSeparator,this.decimalMarker,ve);const et=u.indexOf(",")-t.indexOf(","),Fe=u.length-t.length;if(Fe>0&&","!==u[r]){p=!0;let We=0;do{this._shift.add(r+We),We++}while(We0&&!(u.indexOf(",")>=r&&r>3)||!(u.indexOf(".")>=r&&r>3)&&Fe<=0?(this._shift.clear(),p=!0,m=Fe,this._shift.add(r+=Fe)):this._shift.clear()}else for(let A=0,R=y[0];A2){l+=1,this._shiftStep(i,l,y.length),A--,this.leadZeroDateTime&&(u+="0");continue}if("h"===i[l]&&"2"===u&&Number(R)>3){l+=1,A--;continue}if("m"===i[l]&&Number(R)>5){l+=1,this._shiftStep(i,l,y.length),A--,this.leadZeroDateTime&&(u+="0");continue}if("s"===i[l]&&Number(R)>5){l+=1,this._shiftStep(i,l,y.length),A--,this.leadZeroDateTime&&(u+="0");continue}const W=31;if("d"===i[l]&&(Number(R)>3&&this.leadZeroDateTime||Number(t.slice(l,l+2))>W||"/"===t[l+1])){l+=1,this._shiftStep(i,l,y.length),A--,this.leadZeroDateTime&&(u+="0");continue}if("M"===i[l]){const Te=0===l&&(Number(R)>2||Number(t.slice(l,l+2))>12||"/"===t[l+1]),et=t.slice(l-3,l-1).includes("/")&&("/"===t[l-2]&&Number(t.slice(l-1,l+1))>12&&"/"!==t[l]||"/"===t[l]||"/"===t[l-3]&&Number(t.slice(l-2,l))>12&&"/"!==t[l-1]||"/"===t[l-1]),Fe=Number(t.slice(l-3,l-1))<=W&&!t.slice(l-3,l-1).includes("/")&&"/"===t[l-1]&&(Number(t.slice(l,l+2))>12||"/"===t[l+1]),We=Number(t.slice(l-3,l-1))>W&&!t.slice(l-3,l-1).includes("/")&&!t.slice(l-2,l).includes("/")&&Number(t.slice(l-2,l))>12,cn=Number(t.slice(l-3,l-1))<=W&&!t.slice(l-3,l-1).includes("/")&&"/"!==t[l-1]&&Number(t.slice(l-1,l+1))>12;if(Number(R)>1&&this.leadZeroDateTime||Te||et||Fe||We||cn){l+=1,this._shiftStep(i,l,y.length),A--,this.leadZeroDateTime&&(u+="0");continue}}u+=R,l++}else" "===R&&" "===i[l]?(u+=R,l++):-1!==this.maskSpecialCharacters.indexOf(i[l]??"")?(u+=i[l],l++,this._shiftStep(i,l,y.length),A--):this.maskSpecialCharacters.indexOf(R)>-1&&this.maskAvailablePatterns[i[l]??""]&&this.maskAvailablePatterns[i[l]??""]?.optional?(!!y[l]&&"099.099.099.099"!==i&&"000.000.000-00"!==i&&"00.000.000/0000-00"!==i&&!i.match(/^9+\.0+$/)&&(u+=y[l]),l++,A--):"*"===this.maskExpression[l+1]&&this._findSpecialChar(this.maskExpression[l+2]??"")&&this._findSpecialChar(R)===this.maskExpression[l+2]&&f||"?"===this.maskExpression[l+1]&&this._findSpecialChar(this.maskExpression[l+2]??"")&&this._findSpecialChar(R)===this.maskExpression[l+2]&&f?(l+=3,u+=R):this.showMaskTyped&&this.maskSpecialCharacters.indexOf(R)<0&&R!==this.placeHolderCharacter&&(v=!0);u.length+1===i.length&&-1!==this.maskSpecialCharacters.indexOf(i[i.length-1]??"")&&(u+=i[i.length-1]);let w=r+1;for(;this._shift.has(w);)m++,w++;let S=o&&!i.startsWith("separator")?l:this._shift.has(r)?m:0;v&&S--,a(S,p),m<0&&this._shift.clear();let O=!1;s&&(O=y.every(A=>this.maskSpecialCharacters.includes(A)));let E=`${this.prefix}${O?"":u}${this.suffix}`;return 0===u.length&&(E=`${this.prefix}${u}`),E}_findSpecialChar(t){return this.maskSpecialCharacters.find(i=>i===t)}_checkSymbolMask(t,i){return this.maskAvailablePatterns=this.customPattern?this.customPattern:this.maskAvailablePatterns,(this.maskAvailablePatterns[i]?.pattern&&this.maskAvailablePatterns[i]?.pattern.test(t))??!1}_stripToDecimal(t){return t.split("").filter((i,r)=>{const o="string"==typeof this.decimalMarker?i===this.decimalMarker:this.decimalMarker.includes(i);return i.match("^-?\\d")||i===this.thousandSeparator||o||"-"===i&&0===r&&this.allowNegativeNumbers}).join("")}_charToRegExpExpression(t){return t&&(" "===t?"\\s":"[\\^$.|?*+()".indexOf(t)>=0?`\\${t}`:t)}_shiftStep(t,i,r){const o=/[*?]/g.test(t.slice(0,i))?r:i;this._shift.add(o+this.prefix.length||0)}_compareOrIncludes(t,i,r){return Array.isArray(i)?i.filter(o=>o!==r).includes(t):t===i}_validIP(t){return!(4===t.length&&!t.some((i,r)=>t.length!==r+1?""===i||Number(i)>255:""===i||Number(i.substring(0,3))>255))}}return e.\u0275fac=function(t){return new(t||e)(L(OE))},e.\u0275prov=U({token:e,factory:e.\u0275fac}),e})();function HH(e,n){return n instanceof Function?{...e,...n()}:{...e,...n}}let BH=(()=>{class e{static forRoot(t){return{ngModule:e,providers:[{provide:kE,useValue:t},{provide:RE,useValue:LH},{provide:OE,useFactory:HH,deps:[RE,kE]},VH]}}static forChild(){return{ngModule:e}}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=ge({type:e}),e.\u0275inj=Me({}),e})();const xE=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};xE.KeyboardEvent||(xE.KeyboardEvent=function(e,n){});let FE=(()=>{class e{constructor(t,i){this.document=t,this.platformId=i,this.documentIsAccessible=function BC(e){return e===HC}(this.platformId)}static getCookieRegExp(t){const i=t.replace(/([\[\]\{\}\(\)\|\=\;\+\?\,\.\*\^\$])/gi,"\\$1");return new RegExp("(?:^"+i+"|;\\s*"+i+")=(.*?)(?:;|$)","g")}static safeDecodeURIComponent(t){try{return decodeURIComponent(t)}catch{return t}}check(t){return!!this.documentIsAccessible&&(t=encodeURIComponent(t),e.getCookieRegExp(t).test(this.document.cookie))}get(t){if(this.documentIsAccessible&&this.check(t)){t=encodeURIComponent(t);const r=e.getCookieRegExp(t).exec(this.document.cookie);return r[1]?e.safeDecodeURIComponent(r[1]):""}return""}getAll(){if(!this.documentIsAccessible)return{};const t={},i=this.document;return i.cookie&&""!==i.cookie&&i.cookie.split(";").forEach(r=>{const[o,s]=r.split("=");t[e.safeDecodeURIComponent(o.replace(/^ /,""))]=e.safeDecodeURIComponent(s)}),t}set(t,i,r,o,s,a,l){if(!this.documentIsAccessible)return;if("number"==typeof r||r instanceof Date||o||s||a||l)return void this.set(t,i,{expires:r,path:o,domain:s,secure:a,sameSite:l||"Lax"});let u=encodeURIComponent(t)+"="+encodeURIComponent(i)+";";const f=r||{};f.expires&&(u+="number"==typeof f.expires?"expires="+new Date((new Date).getTime()+1e3*f.expires*60*60*24).toUTCString()+";":"expires="+f.expires.toUTCString()+";"),f.path&&(u+="path="+f.path+";"),f.domain&&(u+="domain="+f.domain+";"),!1===f.secure&&"None"===f.sameSite&&(f.secure=!0,console.warn(`[ngx-cookie-service] Cookie ${t} was forced with secure flag because sameSite=None.More details : https://github.com/stevermeister/ngx-cookie-service/issues/86#issuecomment-597720130`)),f.secure&&(u+="secure;"),f.sameSite||(f.sameSite="Lax"),u+="sameSite="+f.sameSite+";",this.document.cookie=u}delete(t,i,r,o,s="Lax"){if(!this.documentIsAccessible)return;const a=new Date("Thu, 01 Jan 1970 00:00:01 GMT");this.set(t,"",{expires:a,path:i,domain:r,secure:o,sameSite:s})}deleteAll(t,i,r,o="Lax"){if(!this.documentIsAccessible)return;const s=this.getAll();for(const a in s)s.hasOwnProperty(a)&&this.delete(a,t,i,r,o)}}return e.\u0275fac=function(t){return new(t||e)(L(mt),L(ac))},e.\u0275prov=U({token:e,factory:e.\u0275fac,providedIn:"root"}),e})();const jH=[];let $H=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=ge({type:e}),e.\u0275inj=Me({imports:[Af.forRoot(jH),Af]}),e})(),UH=(()=>{class e{constructor(){this.title="dashboard"}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275cmp=lt({type:e,selectors:[["app-root"]],decls:1,vars:0,template:function(t,i){1&t&&Ri(0,"router-outlet")},dependencies:[h_],encapsulation:2}),e})();const GH=["addListener","removeListener"],WH=["addEventListener","removeEventListener"],KH=["on","off"];function Fn(e,n,t,i){if(be(t)&&(i=t,t=void 0),i)return Fn(e,n,t).pipe(qm(i));const[r,o]=function qH(e){return be(e.addEventListener)&&be(e.removeEventListener)}(e)?WH.map(s=>a=>e[s](n,a,t)):function zH(e){return be(e.addListener)&&be(e.removeListener)}(e)?GH.map(PE(e,n)):function YH(e){return be(e.on)&&be(e.off)}(e)?KH.map(PE(e,n)):[];if(!r&&Yr(e))return ke(s=>Fn(s,n,t))(Et(e));if(!r)throw new TypeError("Invalid event target");return new Ve(s=>{const a=(...l)=>s.next(1o(a)})}function PE(e,n){return t=>i=>e[t](n,i)}class JH extends _t{constructor(n,t){super()}schedule(n,t=0){return this}}const Bf={setInterval(e,n,...t){const{delegate:i}=Bf;return i?.setInterval?i.setInterval(e,n,...t):setInterval(e,n,...t)},clearInterval(e){const{delegate:n}=Bf;return(n?.clearInterval||clearInterval)(e)},delegate:void 0},LE={now:()=>(LE.delegate||Date).now(),delegate:void 0};class Pc{constructor(n,t=Pc.now){this.schedulerActionCtor=n,this.now=t}schedule(n,t=0,i){return new this.schedulerActionCtor(this,n).schedule(i,t)}}Pc.now=LE.now;const jf=new class QH extends Pc{constructor(n,t=Pc.now){super(n,t),this.actions=[],this._active=!1}flush(n){const{actions:t}=this;if(this._active)return void t.push(n);let i;this._active=!0;do{if(i=n.execute(n.state,n.delay))break}while(n=t.shift());if(this._active=!1,i){for(;n=t.shift();)n.unsubscribe();throw i}}}(class ZH extends JH{constructor(n,t){super(n,t),this.scheduler=n,this.work=t,this.pending=!1}schedule(n,t=0){var i;if(this.closed)return this;this.state=n;const r=this.id,o=this.scheduler;return null!=r&&(this.id=this.recycleAsyncId(o,r,t)),this.pending=!0,this.delay=t,this.id=null!==(i=this.id)&&void 0!==i?i:this.requestAsyncId(o,this.id,t),this}requestAsyncId(n,t,i=0){return Bf.setInterval(n.flush.bind(n,this),i)}recycleAsyncId(n,t,i=0){if(null!=i&&this.delay===i&&!1===this.pending)return t;null!=t&&Bf.clearInterval(t)}execute(n,t){if(this.closed)return new Error("executing a cancelled action");this.pending=!1;const i=this._execute(n,t);if(i)return i;!1===this.pending&&null!=this.id&&(this.id=this.recycleAsyncId(this.scheduler,this.id,null))}_execute(n,t){let r,i=!1;try{this.work(n)}catch(o){i=!0,r=o||new Error("Scheduled action threw falsy error")}if(i)return this.unsubscribe(),r}unsubscribe(){if(!this.closed){const{id:n,scheduler:t}=this,{actions:i}=t;this.work=this.state=this.scheduler=null,this.pending=!1,dn(i,this),null!=n&&(this.id=this.recycleAsyncId(t,n,null)),this.delay=null,super.unsubscribe()}}}),XH=jf;function Lc(e=0,n,t=XH){let i=-1;return null!=n&&(gu(n)?t=n:i=n),new Ve(r=>{let o=function eB(e){return e instanceof Date&&!isNaN(e)}(e)?+e-t.now():e;o<0&&(o=0);let s=0;return t.schedule(function(){r.closed||(r.next(s++),0<=i?this.schedule(void 0,i):r.complete())},o)})}const{isArray:tB}=Array;function VE(e){return 1===e.length&&tB(e[0])?e[0]:e}function $f(...e){const n=yr(e),t=VE(e);return t.length?new Ve(i=>{let r=t.map(()=>[]),o=t.map(()=>!1);i.add(()=>{r=o=null});for(let s=0;!i.closed&&s{if(r[s].push(a),r.every(l=>l.length)){const l=r.map(u=>u.shift());i.next(n?n(...l):l),r.some((u,f)=>!u.length&&o[f])&&i.complete()}},()=>{o[s]=!0,!r[s].length&&i.complete()}));return()=>{r=o=null}}):Ft}function Ht(e){return qe((n,t)=>{Et(e).subscribe(Oe(t,()=>t.complete(),Cn)),!t.closed&&n.subscribe(t)})}function J_(...e){const n=yr(e);return qe((t,i)=>{const r=e.length,o=new Array(r);let s=e.map(()=>!1),a=!1;for(let l=0;l{o[l]=u,!a&&!s[l]&&(s[l]=!0,(a=s.every(Pn))&&(s=null))},Cn));t.subscribe(Oe(i,l=>{if(a){const u=[l,...o];i.next(n?n(...u):u)}}))})}function vj(e,n){if(1&e){const t=It();M(0,"button",1),K("click",function(){return nt(t),ht(z().close())}),N()}}new Ve(Cn),Math,Math,Math;const rM=["*"],Pj=["dialog"];function lv(e){return"string"==typeof e}function gs(e){return null!=e}function za(e){return(e||document.body).getBoundingClientRect()}const sM={animation:!0,transitionTimerDelayMs:5},I$=()=>{},{transitionTimerDelayMs:O$}=sM,Gc=new Map,Dn=(e,n,t,i)=>{let r=i.context||{};const o=Gc.get(n);if(o)switch(i.runningTransition){case"continue":return Ft;case"stop":e.run(()=>o.transition$.complete()),r=Object.assign(o.context,r),Gc.delete(n)}const s=t(n,i.animation,r)||I$;if(!i.animation||"none"===window.getComputedStyle(n).transitionProperty)return e.run(()=>s()),Q(void 0).pipe(function N$(e){return n=>new Ve(t=>n.subscribe({next:s=>e.run(()=>t.next(s)),error:s=>e.run(()=>t.error(s)),complete:()=>e.run(()=>t.complete())}))}(e));const a=new je,l=new je,u=a.pipe(function iB(...e){return n=>_c(n,Q(...e))}(!0));Gc.set(n,{transition$:a,complete:()=>{l.next(),l.complete()},context:r});const f=function A$(e){const{transitionDelay:n,transitionDuration:t}=window.getComputedStyle(e);return 1e3*(parseFloat(n)+parseFloat(t))}(n);return e.runOutsideAngular(()=>{const p=Fn(n,"transitionend").pipe(Ht(u),yn(({target:v})=>v===n));(function HE(...e){return 1===(e=VE(e)).length?Et(e[0]):new Ve(function nB(e){return n=>{let t=[];for(let i=0;t&&!n.closed&&i{if(t){for(let o=0;o{Gc.delete(n),e.run(()=>{s(),a.next(),a.complete()})})}),a.asObservable()};let Wc=(()=>{class e{constructor(){this.animation=sM.animation}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=U({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(),fM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=ge({type:e}),e.\u0275inj=Me({imports:[Qn]}),e})();const L$=({classList:e})=>{e.remove("show")};let V$=(()=>{class e{constructor(t){this._ngbConfig=t,this.dismissible=!0,this.type="warning"}get animation(){return void 0===this._animation?this._ngbConfig.animation:this._animation}set animation(t){this._animation=t}}return e.\u0275fac=function(t){return new(t||e)(L(Wc))},e.\u0275prov=U({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(),H$=(()=>{class e{constructor(t,i,r,o){this._renderer=i,this._element=r,this._zone=o,this.closed=new de,this.dismissible=t.dismissible,this.type=t.type,this.animation=t.animation}close(){const t=Dn(this._zone,this._element.nativeElement,L$,{animation:this.animation,runningTransition:"continue"});return t.subscribe(()=>this.closed.emit()),t}ngOnChanges(t){const i=t.type;i&&!i.firstChange&&(this._renderer.removeClass(this._element.nativeElement,`alert-${i.previousValue}`),this._renderer.addClass(this._element.nativeElement,`alert-${i.currentValue}`))}ngOnInit(){this._renderer.addClass(this._element.nativeElement,`alert-${this.type}`)}}return e.\u0275fac=function(t){return new(t||e)(C(V$),C(ui),C(Qe),C(Ye))},e.\u0275cmp=lt({type:e,selectors:[["ngb-alert"]],hostAttrs:["role","alert",1,"alert","show"],hostVars:4,hostBindings:function(t,i){2&t&&ct("fade",i.animation)("alert-dismissible",i.dismissible)},inputs:{animation:"animation",dismissible:"dismissible",type:"type"},outputs:{closed:"closed"},exportAs:["ngbAlert"],features:[Wt],ngContentSelectors:rM,decls:2,vars:1,consts:function(){let n;return n=$localize`:@@ngb.alert.close:Close`,[["type","button","class","btn-close","aria-label",n,3,"click",4,"ngIf"],["type","button","aria-label",n,1,"btn-close",3,"click"]]},template:function(t,i){1&t&&(Lg(),Vg(0),Z(1,vj,1,0,"button",0)),2&t&&(P(1),X("ngIf",i.dismissible))},dependencies:[os],styles:["ngb-alert{display:block}\n"],encapsulation:2,changeDetection:0}),e})(),hM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=ge({type:e}),e.\u0275inj=Me({imports:[Qn]}),e})(),mM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=ge({type:e}),e.\u0275inj=Me({imports:[Qn]}),e})(),_M=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=ge({type:e}),e.\u0275inj=Me({}),e})();var Bt=(()=>{return(e=Bt||(Bt={}))[e.Tab=9]="Tab",e[e.Enter=13]="Enter",e[e.Escape=27]="Escape",e[e.Space=32]="Space",e[e.PageUp=33]="PageUp",e[e.PageDown=34]="PageDown",e[e.End=35]="End",e[e.Home=36]="Home",e[e.ArrowLeft=37]="ArrowLeft",e[e.ArrowUp=38]="ArrowUp",e[e.ArrowRight=39]="ArrowRight",e[e.ArrowDown=40]="ArrowDown",Bt;var e})();typeof navigator<"u"&&navigator.userAgent&&(/iPad|iPhone|iPod/.test(navigator.userAgent)||/Macintosh/.test(navigator.userAgent)&&navigator.maxTouchPoints&&navigator.maxTouchPoints>2||/Android/.test(navigator.userAgent));const yM=["a[href]","button:not([disabled])",'input:not([disabled]):not([type="hidden"])',"select:not([disabled])","textarea:not([disabled])","[contenteditable]",'[tabindex]:not([tabindex="-1"])'].join(", ");function bM(e){const n=Array.from(e.querySelectorAll(yM)).filter(t=>-1!==t.tabIndex);return[n[0],n[n.length-1]]}new Date(1882,10,12),new Date(2174,10,25);let NM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=ge({type:e}),e.\u0275inj=Me({imports:[Qn,IE]}),e})(),gv=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275dir=B({type:e,selectors:[["",8,"navbar"]]}),e})(),OM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=ge({type:e}),e.\u0275inj=Me({}),e})();class ys{constructor(n,t,i){this.nodes=n,this.viewRef=t,this.componentRef=i}}let S3=(()=>{class e{constructor(t,i){this._el=t,this._zone=i}ngOnInit(){this._zone.onStable.asObservable().pipe(sn(1)).subscribe(()=>{Dn(this._zone,this._el.nativeElement,(t,i)=>{i&&za(t),t.classList.add("show")},{animation:this.animation,runningTransition:"continue"})})}hide(){return Dn(this._zone,this._el.nativeElement,({classList:t})=>t.remove("show"),{animation:this.animation,runningTransition:"stop"})}}return e.\u0275fac=function(t){return new(t||e)(C(Qe),C(Ye))},e.\u0275cmp=lt({type:e,selectors:[["ngb-modal-backdrop"]],hostAttrs:[2,"z-index","1055"],hostVars:6,hostBindings:function(t,i){2&t&&(es("modal-backdrop"+(i.backdropClass?" "+i.backdropClass:"")),ct("show",!i.animation)("fade",i.animation))},inputs:{animation:"animation",backdropClass:"backdropClass"},decls:0,vars:0,template:function(t,i){},encapsulation:2}),e})();class fr{close(n){}dismiss(n){}}class E3{constructor(n,t,i,r){this._windowCmptRef=n,this._contentRef=t,this._backdropCmptRef=i,this._beforeDismiss=r,this._closed=new je,this._dismissed=new je,this._hidden=new je,n.instance.dismissEvent.subscribe(o=>{this.dismiss(o)}),this.result=new Promise((o,s)=>{this._resolve=o,this._reject=s}),this.result.then(null,()=>{})}get componentInstance(){if(this._contentRef&&this._contentRef.componentRef)return this._contentRef.componentRef.instance}get closed(){return this._closed.asObservable().pipe(Ht(this._hidden))}get dismissed(){return this._dismissed.asObservable().pipe(Ht(this._hidden))}get hidden(){return this._hidden.asObservable()}get shown(){return this._windowCmptRef.instance.shown.asObservable()}close(n){this._windowCmptRef&&(this._closed.next(n),this._resolve(n),this._removeModalElements())}_dismiss(n){this._dismissed.next(n),this._reject(n),this._removeModalElements()}dismiss(n){if(this._windowCmptRef)if(this._beforeDismiss){const t=this._beforeDismiss();!function oM(e){return e&&e.then}(t)?!1!==t&&this._dismiss(n):t.then(i=>{!1!==i&&this._dismiss(n)},()=>{})}else this._dismiss(n)}_removeModalElements(){const n=this._windowCmptRef.instance.hide(),t=this._backdropCmptRef?this._backdropCmptRef.instance.hide():Q(void 0);n.subscribe(()=>{const{nativeElement:i}=this._windowCmptRef.location;i.parentNode.removeChild(i),this._windowCmptRef.destroy(),this._contentRef&&this._contentRef.viewRef&&this._contentRef.viewRef.destroy(),this._windowCmptRef=null,this._contentRef=null}),t.subscribe(()=>{if(this._backdropCmptRef){const{nativeElement:i}=this._backdropCmptRef.location;i.parentNode.removeChild(i),this._backdropCmptRef.destroy(),this._backdropCmptRef=null}}),$f(n,t).subscribe(()=>{this._hidden.next(),this._hidden.complete()})}}var qc=(()=>{return(e=qc||(qc={}))[e.BACKDROP_CLICK=0]="BACKDROP_CLICK",e[e.ESC=1]="ESC",qc;var e})();let M3=(()=>{class e{constructor(t,i,r){this._document=t,this._elRef=i,this._zone=r,this._closed$=new je,this._elWithFocus=null,this.backdrop=!0,this.keyboard=!0,this.dismissEvent=new de,this.shown=new je,this.hidden=new je}get fullscreenClass(){return!0===this.fullscreen?" modal-fullscreen":lv(this.fullscreen)?` modal-fullscreen-${this.fullscreen}-down`:""}dismiss(t){this.dismissEvent.emit(t)}ngOnInit(){this._elWithFocus=this._document.activeElement,this._zone.onStable.asObservable().pipe(sn(1)).subscribe(()=>{this._show()})}ngOnDestroy(){this._disableEventHandling()}hide(){const{nativeElement:t}=this._elRef,i={animation:this.animation,runningTransition:"stop"},s=$f(Dn(this._zone,t,()=>t.classList.remove("show"),i),Dn(this._zone,this._dialogEl.nativeElement,()=>{},i));return s.subscribe(()=>{this.hidden.next(),this.hidden.complete()}),this._disableEventHandling(),this._restoreFocus(),s}_show(){const t={animation:this.animation,runningTransition:"continue"};$f(Dn(this._zone,this._elRef.nativeElement,(o,s)=>{s&&za(o),o.classList.add("show")},t),Dn(this._zone,this._dialogEl.nativeElement,()=>{},t)).subscribe(()=>{this.shown.next(),this.shown.complete()}),this._enableEventHandling(),this._setFocus()}_enableEventHandling(){const{nativeElement:t}=this._elRef;this._zone.runOutsideAngular(()=>{Fn(t,"keydown").pipe(Ht(this._closed$),yn(r=>r.which===Bt.Escape)).subscribe(r=>{this.keyboard?requestAnimationFrame(()=>{r.defaultPrevented||this._zone.run(()=>this.dismiss(qc.ESC))}):"static"===this.backdrop&&this._bumpBackdrop()});let i=!1;Fn(this._dialogEl.nativeElement,"mousedown").pipe(Ht(this._closed$),Yt(()=>i=!1),pi(()=>Fn(t,"mouseup").pipe(Ht(this._closed$),sn(1))),yn(({target:r})=>t===r)).subscribe(()=>{i=!0}),Fn(t,"click").pipe(Ht(this._closed$)).subscribe(({target:r})=>{t===r&&("static"===this.backdrop?this._bumpBackdrop():!0===this.backdrop&&!i&&this._zone.run(()=>this.dismiss(qc.BACKDROP_CLICK))),i=!1})})}_disableEventHandling(){this._closed$.next()}_setFocus(){const{nativeElement:t}=this._elRef;if(!t.contains(document.activeElement)){const i=t.querySelector("[ngbAutofocus]"),r=bM(t)[0];(i||r||t).focus()}}_restoreFocus(){const t=this._document.body,i=this._elWithFocus;let r;r=i&&i.focus&&t.contains(i)?i:t,this._zone.runOutsideAngular(()=>{setTimeout(()=>r.focus()),this._elWithFocus=null})}_bumpBackdrop(){"static"===this.backdrop&&Dn(this._zone,this._elRef.nativeElement,({classList:t})=>(t.add("modal-static"),()=>t.remove("modal-static")),{animation:this.animation,runningTransition:"continue"})}}return e.\u0275fac=function(t){return new(t||e)(C(mt),C(Qe),C(Ye))},e.\u0275cmp=lt({type:e,selectors:[["ngb-modal-window"]],viewQuery:function(t,i){if(1&t&&kd(Pj,7),2&t){let r;ot(r=st())&&(i._dialogEl=r.first)}},hostAttrs:["role","dialog","tabindex","-1"],hostVars:7,hostBindings:function(t,i){2&t&&(ze("aria-modal",!0)("aria-labelledby",i.ariaLabelledBy)("aria-describedby",i.ariaDescribedBy),es("modal d-block"+(i.windowClass?" "+i.windowClass:"")),ct("fade",i.animation))},inputs:{animation:"animation",ariaLabelledBy:"ariaLabelledBy",ariaDescribedBy:"ariaDescribedBy",backdrop:"backdrop",centered:"centered",fullscreen:"fullscreen",keyboard:"keyboard",scrollable:"scrollable",size:"size",windowClass:"windowClass",modalDialogClass:"modalDialogClass"},outputs:{dismissEvent:"dismiss"},ngContentSelectors:rM,decls:4,vars:2,consts:[["role","document"],["dialog",""],[1,"modal-content"]],template:function(t,i){1&t&&(Lg(),M(0,"div",0,1)(2,"div",2),Vg(3),N()()),2&t&&es("modal-dialog"+(i.size?" modal-"+i.size:"")+(i.centered?" modal-dialog-centered":"")+i.fullscreenClass+(i.scrollable?" modal-dialog-scrollable":"")+(i.modalDialogClass?" "+i.modalDialogClass:""))},styles:["ngb-modal-window .component-host-scrollable{display:flex;flex-direction:column;overflow:hidden}\n"],encapsulation:2}),e})(),T3=(()=>{class e{constructor(t){this._document=t}hide(){const t=Math.abs(window.innerWidth-this._document.documentElement.clientWidth),i=this._document.body,r=i.style,{overflow:o,paddingRight:s}=r;if(t>0){const a=parseFloat(window.getComputedStyle(i).paddingRight);r.paddingRight=`${a+t}px`}return r.overflow="hidden",()=>{t>0&&(r.paddingRight=s),r.overflow=o}}}return e.\u0275fac=function(t){return new(t||e)(L(mt))},e.\u0275prov=U({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(),N3=(()=>{class e{constructor(t,i,r,o,s,a){this._applicationRef=t,this._injector=i,this._document=r,this._scrollBar=o,this._rendererFactory=s,this._ngZone=a,this._activeWindowCmptHasChanged=new je,this._ariaHiddenValues=new Map,this._scrollBarRestoreFn=null,this._backdropAttributes=["animation","backdropClass"],this._modalRefs=[],this._windowAttributes=["animation","ariaLabelledBy","ariaDescribedBy","backdrop","centered","fullscreen","keyboard","scrollable","size","windowClass","modalDialogClass"],this._windowCmpts=[],this._activeInstances=new de,this._activeWindowCmptHasChanged.subscribe(()=>{if(this._windowCmpts.length){const l=this._windowCmpts[this._windowCmpts.length-1];((e,n,t,i=!1)=>{this._ngZone.runOutsideAngular(()=>{const r=Fn(n,"focusin").pipe(Ht(t),ie(o=>o.target));Fn(n,"keydown").pipe(Ht(t),yn(o=>o.which===Bt.Tab),J_(r)).subscribe(([o,s])=>{const[a,l]=bM(n);(s===a||s===n)&&o.shiftKey&&(l.focus(),o.preventDefault()),s===l&&!o.shiftKey&&(a.focus(),o.preventDefault())}),i&&Fn(n,"click").pipe(Ht(t),J_(r),ie(o=>o[1])).subscribe(o=>o.focus())})})(0,l.location.nativeElement,this._activeWindowCmptHasChanged),this._revertAriaHidden(),this._setAriaHidden(l.location.nativeElement)}})}_restoreScrollBar(){const t=this._scrollBarRestoreFn;t&&(this._scrollBarRestoreFn=null,t())}_hideScrollBar(){this._scrollBarRestoreFn||(this._scrollBarRestoreFn=this._scrollBar.hide())}open(t,i,r){const o=r.container instanceof HTMLElement?r.container:gs(r.container)?this._document.querySelector(r.container):this._document.body,s=this._rendererFactory.createRenderer(null,null);if(!o)throw new Error(`The specified modal container "${r.container||"body"}" was not found in the DOM.`);this._hideScrollBar();const a=new fr,l=this._getContentRef(r.injector||t,i,a,r);let u=!1!==r.backdrop?this._attachBackdrop(o):void 0,f=this._attachWindowComponent(o,l.nodes),p=new E3(f,l,u,r.beforeDismiss);return this._registerModalRef(p),this._registerWindowCmpt(f),p.hidden.pipe(sn(1)).subscribe(()=>Promise.resolve(!0).then(()=>{this._modalRefs.length||(s.removeClass(this._document.body,"modal-open"),this._restoreScrollBar(),this._revertAriaHidden())})),a.close=m=>{p.close(m)},a.dismiss=m=>{p.dismiss(m)},this._applyWindowOptions(f.instance,r),1===this._modalRefs.length&&s.addClass(this._document.body,"modal-open"),u&&u.instance&&(this._applyBackdropOptions(u.instance,r),u.changeDetectorRef.detectChanges()),f.changeDetectorRef.detectChanges(),p}get activeInstances(){return this._activeInstances}dismissAll(t){this._modalRefs.forEach(i=>i.dismiss(t))}hasOpenModals(){return this._modalRefs.length>0}_attachBackdrop(t){let i=wm(S3,{environmentInjector:this._applicationRef.injector,elementInjector:this._injector});return this._applicationRef.attachView(i.hostView),t.appendChild(i.location.nativeElement),i}_attachWindowComponent(t,i){let r=wm(M3,{environmentInjector:this._applicationRef.injector,elementInjector:this._injector,projectableNodes:i});return this._applicationRef.attachView(r.hostView),t.appendChild(r.location.nativeElement),r}_applyWindowOptions(t,i){this._windowAttributes.forEach(r=>{gs(i[r])&&(t[r]=i[r])})}_applyBackdropOptions(t,i){this._backdropAttributes.forEach(r=>{gs(i[r])&&(t[r]=i[r])})}_getContentRef(t,i,r,o){return i?i instanceof gt?this._createFromTemplateRef(i,r):lv(i)?this._createFromString(i):this._createFromComponent(t,i,r,o):new ys([])}_createFromTemplateRef(t,i){const o=t.createEmbeddedView({$implicit:i,close(s){i.close(s)},dismiss(s){i.dismiss(s)}});return this._applicationRef.attachView(o),new ys([o.rootNodes],o)}_createFromString(t){const i=this._document.createTextNode(`${t}`);return new ys([[i]])}_createFromComponent(t,i,r,o){const s=_n.create({providers:[{provide:fr,useValue:r}],parent:t}),a=wm(i,{environmentInjector:this._applicationRef.injector,elementInjector:s}),l=a.location.nativeElement;return o.scrollable&&l.classList.add("component-host-scrollable"),this._applicationRef.attachView(a.hostView),new ys([[l]],a.hostView,a)}_setAriaHidden(t){const i=t.parentElement;i&&t!==this._document.body&&(Array.from(i.children).forEach(r=>{r!==t&&"SCRIPT"!==r.nodeName&&(this._ariaHiddenValues.set(r,r.getAttribute("aria-hidden")),r.setAttribute("aria-hidden","true"))}),this._setAriaHidden(i))}_revertAriaHidden(){this._ariaHiddenValues.forEach((t,i)=>{t?i.setAttribute("aria-hidden",t):i.removeAttribute("aria-hidden")}),this._ariaHiddenValues.clear()}_registerModalRef(t){const i=()=>{const r=this._modalRefs.indexOf(t);r>-1&&(this._modalRefs.splice(r,1),this._activeInstances.emit(this._modalRefs))};this._modalRefs.push(t),this._activeInstances.emit(this._modalRefs),t.result.then(i,i)}_registerWindowCmpt(t){this._windowCmpts.push(t),this._activeWindowCmptHasChanged.next(),t.onDestroy(()=>{const i=this._windowCmpts.indexOf(t);i>-1&&(this._windowCmpts.splice(i,1),this._activeWindowCmptHasChanged.next())})}}return e.\u0275fac=function(t){return new(t||e)(L(lc),L(_n),L(mt),L(T3),L(eg),L(Ye))},e.\u0275prov=U({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(),A3=(()=>{class e{constructor(t){this._ngbConfig=t,this.backdrop=!0,this.fullscreen=!1,this.keyboard=!0}get animation(){return void 0===this._animation?this._ngbConfig.animation:this._animation}set animation(t){this._animation=t}}return e.\u0275fac=function(t){return new(t||e)(L(Wc))},e.\u0275prov=U({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(),kM=(()=>{class e{constructor(t,i,r){this._injector=t,this._modalStack=i,this._config=r}open(t,i={}){const r={...this._config,animation:this._config.animation,...i};return this._modalStack.open(this._injector,t,r)}get activeInstances(){return this._modalStack.activeInstances}dismissAll(t){this._modalStack.dismissAll(t)}hasOpenModals(){return this._modalStack.hasOpenModals()}}return e.\u0275fac=function(t){return new(t||e)(L(_n),L(N3),L(A3))},e.\u0275prov=U({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(),RM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=ge({type:e}),e.\u0275inj=Me({providers:[kM]}),e})(),LM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=ge({type:e}),e.\u0275inj=Me({imports:[Qn]}),e})(),WM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=ge({type:e}),e.\u0275inj=Me({imports:[Qn]}),e})(),zM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=ge({type:e}),e.\u0275inj=Me({imports:[Qn]}),e})(),YM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=ge({type:e}),e.\u0275inj=Me({imports:[Qn]}),e})(),qM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=ge({type:e}),e.\u0275inj=Me({imports:[Qn]}),e})(),JM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=ge({type:e}),e.\u0275inj=Me({imports:[Qn]}),e})(),ZM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=ge({type:e}),e.\u0275inj=Me({imports:[Qn]}),e})(),QM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=ge({type:e}),e.\u0275inj=Me({}),e})();new Y("live announcer delay",{providedIn:"root",factory:function $3(){return 100}});let XM=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=ge({type:e}),e.\u0275inj=Me({imports:[Qn]}),e})(),eT=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=ge({type:e}),e.\u0275inj=Me({}),e})();const U3=[fM,hM,mM,_M,NM,OM,RM,LM,eT,WM,zM,YM,qM,JM,ZM,QM,XM];let G3=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=ge({type:e}),e.\u0275inj=Me({imports:[U3,fM,hM,mM,_M,NM,OM,RM,LM,eT,WM,zM,YM,qM,JM,ZM,QM,XM]}),e})(),z3=(()=>{class e{constructor(t){this.activeModal=t,this.save=()=>{this.activeModal.close(this.rewindDate)}}}return e.\u0275fac=function(t){return new(t||e)(C(fr))},e.\u0275cmp=lt({type:e,selectors:[["app-rewind-modal"]],inputs:{groupId:"groupId",consumerName:"consumerName",topic:"topic"},decls:26,vars:4,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],["for","rewindDate"],[1,"input-group"],["id","rewindDate","placeholder","yyyy-mm-dd hh:MM:ss","type","datetime-local",1,"form-control",3,"ngModel","ngModelChange"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(M(0,"div",0)(1,"h4",1),I(2,"Rewind consumers offset"),N(),M(3,"button",2),K("click",function(){return i.activeModal.dismiss()}),M(4,"span",3),I(5,"\xd7"),N()()(),M(6,"div",4)(7,"div",5)(8,"label",6),I(9,"Select the datetime to rewind all the partition-offsets of the topic "),M(10,"b"),I(11),N(),I(12," from consumers "),M(13,"b"),I(14),N(),I(15," with group id "),M(16,"b"),I(17),N(),I(18,"' "),N(),M(19,"div",7)(20,"input",8),K("ngModelChange",function(o){return i.rewindDate=o}),N()()()(),M(21,"div",9)(22,"button",10),K("click",function(){return i.activeModal.dismiss()}),I(23,"Cancel"),N(),M(24,"button",11),K("click",function(){return i.save()}),I(25,"OK"),N()()),2&t&&(P(11),Be("'",i.topic,"'"),P(3),Be("'",i.consumerName,"'"),P(3),Be("'",i.groupId,""),P(3),X("ngModel",i.rewindDate))},dependencies:[Oc,O_,Hf],encapsulation:2}),e})(),Y3=(()=>{class e{constructor(t){this.activeModal=t,this.save=()=>{this.activeModal.close(this.workersCount)}}}return e.\u0275fac=function(t){return new(t||e)(C(fr))},e.\u0275cmp=lt({type:e,selectors:[["app-workers-count-modal"]],inputs:{workersCount:"workersCount",groupId:"groupId",consumerName:"consumerName"},decls:24,vars:3,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],["for","workersCount"],[1,"input-group"],["id","workersCount","type","number",1,"form-control",3,"ngModel","ngModelChange"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(M(0,"div",0)(1,"h4",1),I(2,"Consumer workers running"),N(),M(3,"button",2),K("click",function(){return i.activeModal.dismiss()}),M(4,"span",3),I(5,"\xd7"),N()()(),M(6,"div",4)(7,"div",5)(8,"label"),I(9,"Update the number of workers in consumers "),M(10,"b"),I(11),N(),I(12," from group id "),M(13,"b"),I(14),N()(),M(15,"label",6),I(16,"New Value"),N(),M(17,"div",7)(18,"input",8),K("ngModelChange",function(o){return i.workersCount=o}),N()()()(),M(19,"div",9)(20,"button",10),K("click",function(){return i.activeModal.dismiss()}),I(21,"Cancel"),N(),M(22,"button",11),K("click",function(){return i.save()}),I(23,"OK"),N()()),2&t&&(P(11),Be("'",i.consumerName,"'"),P(3),Be("'",i.groupId,"'"),P(4),X("ngModel",i.workersCount))},dependencies:[Oc,$_,O_,Hf],encapsulation:2}),e})(),q3=(()=>{class e{constructor(t){this.activeModal=t}}return e.\u0275fac=function(t){return new(t||e)(C(fr))},e.\u0275cmp=lt({type:e,selectors:[["app-reset-modal"]],inputs:{groupId:"groupId",consumerName:"consumerName",topic:"topic"},decls:26,vars:3,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],[1,"mt-3"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(M(0,"div",0)(1,"h4",1),I(2,"Reset consumers offset"),N(),M(3,"button",2),K("click",function(){return i.activeModal.dismiss()}),M(4,"span",3),I(5,"\xd7"),N()()(),M(6,"div",4)(7,"div",5)(8,"span"),I(9,"Reset the partition-offsets can generate a huge lag at the topic "),M(10,"b"),I(11),N(),I(12," to consumers "),M(13,"b"),I(14),N(),I(15," with group id "),M(16,"b"),I(17),N(),I(18,"'. "),N(),M(19,"h5",6),I(20,"Are you really sure about it?"),N()()(),M(21,"div",7)(22,"button",8),K("click",function(){return i.activeModal.dismiss()}),I(23,"No, cancel"),N(),M(24,"button",9),K("click",function(){return i.activeModal.close()}),I(25,"Yes"),N()()),2&t&&(P(11),Be("'",i.topic,"'"),P(3),Be("'",i.consumerName,"'"),P(3),Be("'",i.groupId,""))},encapsulation:2}),e})(),J3=(()=>{class e{constructor(t){this.activeModal=t}}return e.\u0275fac=function(t){return new(t||e)(C(fr))},e.\u0275cmp=lt({type:e,selectors:[["app-pause-modal"]],inputs:{groupId:"groupId",consumerName:"consumerName",topic:"topic"},decls:26,vars:3,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],[1,"mt-3"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(M(0,"div",0)(1,"h4",1),I(2,"Pause consumers"),N(),M(3,"button",2),K("click",function(){return i.activeModal.dismiss()}),M(4,"span",3),I(5,"\xd7"),N()()(),M(6,"div",4)(7,"div",5)(8,"span"),I(9,"Pause all the partitions of the topic "),M(10,"b"),I(11),N(),I(12," from consumers "),M(13,"b"),I(14),N(),I(15," with group id "),M(16,"b"),I(17),N(),I(18,"' will interrupt the kafka data processing and, probably, generate lag. "),N(),M(19,"h5",6),I(20,"Are you really sure about it?"),N()()(),M(21,"div",7)(22,"button",8),K("click",function(){return i.activeModal.dismiss()}),I(23,"No, cancel"),N(),M(24,"button",9),K("click",function(){return i.activeModal.close()}),I(25,"Yes"),N()()),2&t&&(P(11),Be("'",i.topic,"'"),P(3),Be("'",i.consumerName,"'"),P(3),Be("'",i.groupId,""))},encapsulation:2}),e})(),Z3=(()=>{class e{constructor(t){this.activeModal=t}}return e.\u0275fac=function(t){return new(t||e)(C(fr))},e.\u0275cmp=lt({type:e,selectors:[["app-resume-modal"]],inputs:{groupId:"groupId",consumerName:"consumerName",topic:"topic"},decls:26,vars:3,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],[1,"mt-3"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(M(0,"div",0)(1,"h4",1),I(2,"Resume consumers"),N(),M(3,"button",2),K("click",function(){return i.activeModal.dismiss()}),M(4,"span",3),I(5,"\xd7"),N()()(),M(6,"div",4)(7,"div",5)(8,"span"),I(9,"Resume all the partitions of the topic "),M(10,"b"),I(11),N(),I(12," from consumers "),M(13,"b"),I(14),N(),I(15," with group id "),M(16,"b"),I(17),N(),I(18,"' will restart to process the messages. "),N(),M(19,"h5",6),I(20,"Are you really sure about it?"),N()()(),M(21,"div",7)(22,"button",8),K("click",function(){return i.activeModal.dismiss()}),I(23,"No, cancel"),N(),M(24,"button",9),K("click",function(){return i.activeModal.close()}),I(25,"Yes"),N()()),2&t&&(P(11),Be("'",i.topic,"'"),P(3),Be("'",i.consumerName,"'"),P(3),Be("'",i.groupId,""))},encapsulation:2}),e})(),Q3=(()=>{class e{constructor(t){this.activeModal=t}}return e.\u0275fac=function(t){return new(t||e)(C(fr))},e.\u0275cmp=lt({type:e,selectors:[["app-restart-modal"]],inputs:{groupId:"groupId",consumerName:"consumerName"},decls:23,vars:2,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],[1,"mt-3"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(M(0,"div",0)(1,"h4",1),I(2,"Restart consumers"),N(),M(3,"button",2),K("click",function(){return i.activeModal.dismiss()}),M(4,"span",3),I(5,"\xd7"),N()()(),M(6,"div",4)(7,"div",5)(8,"span"),I(9,"Restart the consumers "),M(10,"b"),I(11),N(),I(12," from group id "),M(13,"b"),I(14),N(),I(15,"' will can generate a temporary instability in your system. "),N(),M(16,"h5",6),I(17,"Are you really sure about it?"),N()()(),M(18,"div",7)(19,"button",8),K("click",function(){return i.activeModal.dismiss()}),I(20,"No, cancel"),N(),M(21,"button",9),K("click",function(){return i.activeModal.close()}),I(22,"Yes"),N()()),2&t&&(P(11),Be("'",i.consumerName,"'"),P(3),Be("'",i.groupId,""))},encapsulation:2}),e})(),X3=(()=>{class e{constructor(t){this.activeModal=t}}return e.\u0275fac=function(t){return new(t||e)(C(fr))},e.\u0275cmp=lt({type:e,selectors:[["app-start-modal"]],inputs:{groupId:"groupId",consumerName:"consumerName"},decls:22,vars:2,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],[1,"mt-3"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(M(0,"div",0)(1,"h4",1),I(2,"Start consumers"),N(),M(3,"button",2),K("click",function(){return i.activeModal.dismiss()}),M(4,"span",3),I(5,"\xd7"),N()()(),M(6,"div",4)(7,"div",5)(8,"span"),I(9,"Start the consumer "),M(10,"b"),I(11),N(),I(12," from group id "),M(13,"b"),I(14),N()(),M(15,"h5",6),I(16,"Are you really sure about it?"),N()()(),M(17,"div",7)(18,"button",8),K("click",function(){return i.activeModal.dismiss()}),I(19,"No, cancel"),N(),M(20,"button",9),K("click",function(){return i.activeModal.close()}),I(21,"Yes"),N()()),2&t&&(P(11),Be("'",i.consumerName,"'"),P(3),Be("'",i.groupId,"'"))},encapsulation:2}),e})(),eU=(()=>{class e{constructor(t){this.activeModal=t}}return e.\u0275fac=function(t){return new(t||e)(C(fr))},e.\u0275cmp=lt({type:e,selectors:[["app-stop-modal"]],inputs:{groupId:"groupId",consumerName:"consumerName"},decls:22,vars:2,consts:[[1,"modal-header"],["id","modal-basic-title",1,"modal-title"],["type","button","aria-label","Close",1,"close",3,"click"],["aria-hidden","true"],[1,"modal-body"],[1,"form-group"],[1,"mt-3"],[1,"modal-footer"],["type","button",1,"btn","btn-outline-dark",3,"click"],["type","button",1,"btn","btn-success",3,"click"]],template:function(t,i){1&t&&(M(0,"div",0)(1,"h4",1),I(2,"Stop consumer"),N(),M(3,"button",2),K("click",function(){return i.activeModal.dismiss()}),M(4,"span",3),I(5,"\xd7"),N()()(),M(6,"div",4)(7,"div",5)(8,"span"),I(9,"Stop the consumer "),M(10,"b"),I(11),N(),I(12," from group id "),M(13,"b"),I(14),N()(),M(15,"h5",6),I(16,"Are you really sure about it?"),N()()(),M(17,"div",7)(18,"button",8),K("click",function(){return i.activeModal.dismiss()}),I(19,"No, cancel"),N(),M(20,"button",9),K("click",function(){return i.activeModal.close()}),I(21,"Yes"),N()()),2&t&&(P(11),Be("'",i.consumerName,"'"),P(3),Be("'",i.groupId,"'"))},encapsulation:2}),e})();var tT=Xc(439);function nT(e,n,t,i,r,o,s){try{var a=e[o](s),l=a.value}catch(u){return void t(u)}a.done?n(l):Promise.resolve(l).then(i,r)}function Wr(e){return function(){var n=this,t=arguments;return new Promise(function(i,r){var o=e.apply(n,t);function s(l){nT(o,i,r,s,a,"next",l)}function a(l){nT(o,i,r,s,a,"throw",l)}s(void 0)})}}function Kr(e,n){const t="object"==typeof n;return new Promise((i,r)=>{const o=new mr({next:s=>{i(s),o.unsubscribe()},error:r,complete:()=>{t?i(n.defaultValue):r(new mc)}});e.subscribe(o)})}let rT=(()=>{class e{constructor(){this.rootUrl="http://localhost:5000/kafkaflow"}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=U({token:e,factory:e.\u0275fac,providedIn:"root"}),e})();class oT{}class sT{}class zr{constructor(n){this.normalizedNames=new Map,this.lazyUpdate=null,n?this.lazyInit="string"==typeof n?()=>{this.headers=new Map,n.split("\n").forEach(t=>{const i=t.indexOf(":");if(i>0){const r=t.slice(0,i),o=r.toLowerCase(),s=t.slice(i+1).trim();this.maybeSetNormalizedName(r,o),this.headers.has(o)?this.headers.get(o).push(s):this.headers.set(o,[s])}})}:()=>{this.headers=new Map,Object.keys(n).forEach(t=>{let i=n[t];const r=t.toLowerCase();"string"==typeof i&&(i=[i]),i.length>0&&(this.headers.set(r,i),this.maybeSetNormalizedName(t,r))})}:this.headers=new Map}has(n){return this.init(),this.headers.has(n.toLowerCase())}get(n){this.init();const t=this.headers.get(n.toLowerCase());return t&&t.length>0?t[0]:null}keys(){return this.init(),Array.from(this.normalizedNames.values())}getAll(n){return this.init(),this.headers.get(n.toLowerCase())||null}append(n,t){return this.clone({name:n,value:t,op:"a"})}set(n,t){return this.clone({name:n,value:t,op:"s"})}delete(n,t){return this.clone({name:n,value:t,op:"d"})}maybeSetNormalizedName(n,t){this.normalizedNames.has(t)||this.normalizedNames.set(t,n)}init(){this.lazyInit&&(this.lazyInit instanceof zr?this.copyFrom(this.lazyInit):this.lazyInit(),this.lazyInit=null,this.lazyUpdate&&(this.lazyUpdate.forEach(n=>this.applyUpdate(n)),this.lazyUpdate=null))}copyFrom(n){n.init(),Array.from(n.headers.keys()).forEach(t=>{this.headers.set(t,n.headers.get(t)),this.normalizedNames.set(t,n.normalizedNames.get(t))})}clone(n){const t=new zr;return t.lazyInit=this.lazyInit&&this.lazyInit instanceof zr?this.lazyInit:this,t.lazyUpdate=(this.lazyUpdate||[]).concat([n]),t}applyUpdate(n){const t=n.name.toLowerCase();switch(n.op){case"a":case"s":let i=n.value;if("string"==typeof i&&(i=[i]),0===i.length)return;this.maybeSetNormalizedName(n.name,t);const r=("a"===n.op?this.headers.get(t):void 0)||[];r.push(...i),this.headers.set(t,r);break;case"d":const o=n.value;if(o){let s=this.headers.get(t);if(!s)return;s=s.filter(a=>-1===o.indexOf(a)),0===s.length?(this.headers.delete(t),this.normalizedNames.delete(t)):this.headers.set(t,s)}else this.headers.delete(t),this.normalizedNames.delete(t)}}forEach(n){this.init(),Array.from(this.normalizedNames.keys()).forEach(t=>n(this.normalizedNames.get(t),this.headers.get(t)))}}class tU{encodeKey(n){return aT(n)}encodeValue(n){return aT(n)}decodeKey(n){return decodeURIComponent(n)}decodeValue(n){return decodeURIComponent(n)}}const iU=/%(\d[a-f0-9])/gi,rU={40:"@","3A":":",24:"$","2C":",","3B":";","3D":"=","3F":"?","2F":"/"};function aT(e){return encodeURIComponent(e).replace(iU,(n,t)=>rU[t]??n)}function th(e){return`${e}`}class So{constructor(n={}){if(this.updates=null,this.cloneFrom=null,this.encoder=n.encoder||new tU,n.fromString){if(n.fromObject)throw new Error("Cannot specify both fromString and fromObject.");this.map=function nU(e,n){const t=new Map;return e.length>0&&e.replace(/^\?/,"").split("&").forEach(r=>{const o=r.indexOf("="),[s,a]=-1==o?[n.decodeKey(r),""]:[n.decodeKey(r.slice(0,o)),n.decodeValue(r.slice(o+1))],l=t.get(s)||[];l.push(a),t.set(s,l)}),t}(n.fromString,this.encoder)}else n.fromObject?(this.map=new Map,Object.keys(n.fromObject).forEach(t=>{const i=n.fromObject[t],r=Array.isArray(i)?i.map(th):[th(i)];this.map.set(t,r)})):this.map=null}has(n){return this.init(),this.map.has(n)}get(n){this.init();const t=this.map.get(n);return t?t[0]:null}getAll(n){return this.init(),this.map.get(n)||null}keys(){return this.init(),Array.from(this.map.keys())}append(n,t){return this.clone({param:n,value:t,op:"a"})}appendAll(n){const t=[];return Object.keys(n).forEach(i=>{const r=n[i];Array.isArray(r)?r.forEach(o=>{t.push({param:i,value:o,op:"a"})}):t.push({param:i,value:r,op:"a"})}),this.clone(t)}set(n,t){return this.clone({param:n,value:t,op:"s"})}delete(n,t){return this.clone({param:n,value:t,op:"d"})}toString(){return this.init(),this.keys().map(n=>{const t=this.encoder.encodeKey(n);return this.map.get(n).map(i=>t+"="+this.encoder.encodeValue(i)).join("&")}).filter(n=>""!==n).join("&")}clone(n){const t=new So({encoder:this.encoder});return t.cloneFrom=this.cloneFrom||this,t.updates=(this.updates||[]).concat(n),t}init(){null===this.map&&(this.map=new Map),null!==this.cloneFrom&&(this.cloneFrom.init(),this.cloneFrom.keys().forEach(n=>this.map.set(n,this.cloneFrom.map.get(n))),this.updates.forEach(n=>{switch(n.op){case"a":case"s":const t=("a"===n.op?this.map.get(n.param):void 0)||[];t.push(th(n.value)),this.map.set(n.param,t);break;case"d":if(void 0===n.value){this.map.delete(n.param);break}{let i=this.map.get(n.param)||[];const r=i.indexOf(th(n.value));-1!==r&&i.splice(r,1),i.length>0?this.map.set(n.param,i):this.map.delete(n.param)}}}),this.cloneFrom=this.updates=null)}}class oU{constructor(){this.map=new Map}set(n,t){return this.map.set(n,t),this}get(n){return this.map.has(n)||this.map.set(n,n.defaultValue()),this.map.get(n)}delete(n){return this.map.delete(n),this}has(n){return this.map.has(n)}keys(){return this.map.keys()}}function lT(e){return typeof ArrayBuffer<"u"&&e instanceof ArrayBuffer}function cT(e){return typeof Blob<"u"&&e instanceof Blob}function uT(e){return typeof FormData<"u"&&e instanceof FormData}class Jc{constructor(n,t,i,r){let o;if(this.url=t,this.body=null,this.reportProgress=!1,this.withCredentials=!1,this.responseType="json",this.method=n.toUpperCase(),function sU(e){switch(e){case"DELETE":case"GET":case"HEAD":case"OPTIONS":case"JSONP":return!1;default:return!0}}(this.method)||r?(this.body=void 0!==i?i:null,o=r):o=i,o&&(this.reportProgress=!!o.reportProgress,this.withCredentials=!!o.withCredentials,o.responseType&&(this.responseType=o.responseType),o.headers&&(this.headers=o.headers),o.context&&(this.context=o.context),o.params&&(this.params=o.params)),this.headers||(this.headers=new zr),this.context||(this.context=new oU),this.params){const s=this.params.toString();if(0===s.length)this.urlWithParams=t;else{const a=t.indexOf("?");this.urlWithParams=t+(-1===a?"?":ap.set(m,n.setHeaders[m]),l)),n.setParams&&(u=Object.keys(n.setParams).reduce((p,m)=>p.set(m,n.setParams[m]),u)),new Jc(t,i,o,{params:u,headers:l,context:f,reportProgress:a,responseType:r,withCredentials:s})}}var Rt=(()=>((Rt=Rt||{})[Rt.Sent=0]="Sent",Rt[Rt.UploadProgress=1]="UploadProgress",Rt[Rt.ResponseHeader=2]="ResponseHeader",Rt[Rt.DownloadProgress=3]="DownloadProgress",Rt[Rt.Response=4]="Response",Rt[Rt.User=5]="User",Rt))();class yv{constructor(n,t=200,i="OK"){this.headers=n.headers||new zr,this.status=void 0!==n.status?n.status:t,this.statusText=n.statusText||i,this.url=n.url||null,this.ok=this.status>=200&&this.status<300}}class bv extends yv{constructor(n={}){super(n),this.type=Rt.ResponseHeader}clone(n={}){return new bv({headers:n.headers||this.headers,status:void 0!==n.status?n.status:this.status,statusText:n.statusText||this.statusText,url:n.url||this.url||void 0})}}class nh extends yv{constructor(n={}){super(n),this.type=Rt.Response,this.body=void 0!==n.body?n.body:null}clone(n={}){return new nh({body:void 0!==n.body?n.body:this.body,headers:n.headers||this.headers,status:void 0!==n.status?n.status:this.status,statusText:n.statusText||this.statusText,url:n.url||this.url||void 0})}}class dT extends yv{constructor(n){super(n,0,"Unknown Error"),this.name="HttpErrorResponse",this.ok=!1,this.message=this.status>=200&&this.status<300?`Http failure during parsing for ${n.url||"(unknown url)"}`:`Http failure response for ${n.url||"(unknown url)"}: ${n.status} ${n.statusText}`,this.error=n.error||null}}function Dv(e,n){return{body:n,headers:e.headers,context:e.context,observe:e.observe,params:e.params,reportProgress:e.reportProgress,responseType:e.responseType,withCredentials:e.withCredentials}}let fT=(()=>{class e{constructor(t){this.handler=t}request(t,i,r={}){let o;if(t instanceof Jc)o=t;else{let l,u;l=r.headers instanceof zr?r.headers:new zr(r.headers),r.params&&(u=r.params instanceof So?r.params:new So({fromObject:r.params})),o=new Jc(t,i,void 0!==r.body?r.body:null,{headers:l,context:r.context,params:u,reportProgress:r.reportProgress,responseType:r.responseType||"json",withCredentials:r.withCredentials})}const s=Q(o).pipe(_o(l=>this.handler.handle(l)));if(t instanceof Jc||"events"===r.observe)return s;const a=s.pipe(yn(l=>l instanceof nh));switch(r.observe||"body"){case"body":switch(o.responseType){case"arraybuffer":return a.pipe(ie(l=>{if(null!==l.body&&!(l.body instanceof ArrayBuffer))throw new Error("Response is not an ArrayBuffer.");return l.body}));case"blob":return a.pipe(ie(l=>{if(null!==l.body&&!(l.body instanceof Blob))throw new Error("Response is not a Blob.");return l.body}));case"text":return a.pipe(ie(l=>{if(null!==l.body&&"string"!=typeof l.body)throw new Error("Response is not a string.");return l.body}));default:return a.pipe(ie(l=>l.body))}case"response":return a;default:throw new Error(`Unreachable: unhandled observe type ${r.observe}}`)}}delete(t,i={}){return this.request("DELETE",t,i)}get(t,i={}){return this.request("GET",t,i)}head(t,i={}){return this.request("HEAD",t,i)}jsonp(t,i){return this.request("JSONP",t,{params:(new So).append(i,"JSONP_CALLBACK"),observe:"body",responseType:"json"})}options(t,i={}){return this.request("OPTIONS",t,i)}patch(t,i,r={}){return this.request("PATCH",t,Dv(r,i))}post(t,i,r={}){return this.request("POST",t,Dv(r,i))}put(t,i,r={}){return this.request("PUT",t,Dv(r,i))}}return e.\u0275fac=function(t){return new(t||e)(L(oT))},e.\u0275prov=U({token:e,factory:e.\u0275fac}),e})();class hT{constructor(n,t){this.next=n,this.interceptor=t}handle(n){return this.interceptor.intercept(n,this.next)}}const Cv=new Y("HTTP_INTERCEPTORS");let lU=(()=>{class e{intercept(t,i){return i.handle(t)}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=U({token:e,factory:e.\u0275fac}),e})();const cU=/^\)\]\}',?\n/;let pT=(()=>{class e{constructor(t){this.xhrFactory=t}handle(t){if("JSONP"===t.method)throw new Error("Attempted to construct Jsonp request without HttpClientJsonpModule installed.");return new Ve(i=>{const r=this.xhrFactory.build();if(r.open(t.method,t.urlWithParams),t.withCredentials&&(r.withCredentials=!0),t.headers.forEach((v,y)=>r.setRequestHeader(v,y.join(","))),t.headers.has("Accept")||r.setRequestHeader("Accept","application/json, text/plain, */*"),!t.headers.has("Content-Type")){const v=t.detectContentTypeHeader();null!==v&&r.setRequestHeader("Content-Type",v)}if(t.responseType){const v=t.responseType.toLowerCase();r.responseType="json"!==v?v:"text"}const o=t.serializeBody();let s=null;const a=()=>{if(null!==s)return s;const v=r.statusText||"OK",y=new zr(r.getAllResponseHeaders()),D=function uU(e){return"responseURL"in e&&e.responseURL?e.responseURL:/^X-Request-URL:/m.test(e.getAllResponseHeaders())?e.getResponseHeader("X-Request-URL"):null}(r)||t.url;return s=new bv({headers:y,status:r.status,statusText:v,url:D}),s},l=()=>{let{headers:v,status:y,statusText:D,url:w}=a(),S=null;204!==y&&(S=typeof r.response>"u"?r.responseText:r.response),0===y&&(y=S?200:0);let O=y>=200&&y<300;if("json"===t.responseType&&"string"==typeof S){const E=S;S=S.replace(cU,"");try{S=""!==S?JSON.parse(S):null}catch(A){S=E,O&&(O=!1,S={error:A,text:S})}}O?(i.next(new nh({body:S,headers:v,status:y,statusText:D,url:w||void 0})),i.complete()):i.error(new dT({error:S,headers:v,status:y,statusText:D,url:w||void 0}))},u=v=>{const{url:y}=a(),D=new dT({error:v,status:r.status||0,statusText:r.statusText||"Unknown Error",url:y||void 0});i.error(D)};let f=!1;const p=v=>{f||(i.next(a()),f=!0);let y={type:Rt.DownloadProgress,loaded:v.loaded};v.lengthComputable&&(y.total=v.total),"text"===t.responseType&&!!r.responseText&&(y.partialText=r.responseText),i.next(y)},m=v=>{let y={type:Rt.UploadProgress,loaded:v.loaded};v.lengthComputable&&(y.total=v.total),i.next(y)};return r.addEventListener("load",l),r.addEventListener("error",u),r.addEventListener("timeout",u),r.addEventListener("abort",u),t.reportProgress&&(r.addEventListener("progress",p),null!==o&&r.upload&&r.upload.addEventListener("progress",m)),r.send(o),i.next({type:Rt.Sent}),()=>{r.removeEventListener("error",u),r.removeEventListener("abort",u),r.removeEventListener("load",l),r.removeEventListener("timeout",u),t.reportProgress&&(r.removeEventListener("progress",p),null!==o&&r.upload&&r.upload.removeEventListener("progress",m)),r.readyState!==r.DONE&&r.abort()}})}}return e.\u0275fac=function(t){return new(t||e)(L($C))},e.\u0275prov=U({token:e,factory:e.\u0275fac}),e})();const wv=new Y("XSRF_COOKIE_NAME"),Sv=new Y("XSRF_HEADER_NAME");class gT{}let dU=(()=>{class e{constructor(t,i,r){this.doc=t,this.platform=i,this.cookieName=r,this.lastCookieString="",this.lastToken=null,this.parseCount=0}getToken(){if("server"===this.platform)return null;const t=this.doc.cookie||"";return t!==this.lastCookieString&&(this.parseCount++,this.lastToken=IC(t,this.cookieName),this.lastCookieString=t),this.lastToken}}return e.\u0275fac=function(t){return new(t||e)(L(mt),L(ac),L(wv))},e.\u0275prov=U({token:e,factory:e.\u0275fac}),e})(),Ev=(()=>{class e{constructor(t,i){this.tokenService=t,this.headerName=i}intercept(t,i){const r=t.url.toLowerCase();if("GET"===t.method||"HEAD"===t.method||r.startsWith("http://")||r.startsWith("https://"))return i.handle(t);const o=this.tokenService.getToken();return null!==o&&!t.headers.has(this.headerName)&&(t=t.clone({headers:t.headers.set(this.headerName,o)})),i.handle(t)}}return e.\u0275fac=function(t){return new(t||e)(L(gT),L(Sv))},e.\u0275prov=U({token:e,factory:e.\u0275fac}),e})(),fU=(()=>{class e{constructor(t,i){this.backend=t,this.injector=i,this.chain=null}handle(t){if(null===this.chain){const i=this.injector.get(Cv,[]);this.chain=i.reduceRight((r,o)=>new hT(r,o),this.backend)}return this.chain.handle(t)}}return e.\u0275fac=function(t){return new(t||e)(L(sT),L(_n))},e.\u0275prov=U({token:e,factory:e.\u0275fac}),e})(),hU=(()=>{class e{static disable(){return{ngModule:e,providers:[{provide:Ev,useClass:lU}]}}static withOptions(t={}){return{ngModule:e,providers:[t.cookieName?{provide:wv,useValue:t.cookieName}:[],t.headerName?{provide:Sv,useValue:t.headerName}:[]]}}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=ge({type:e}),e.\u0275inj=Me({providers:[Ev,{provide:Cv,useExisting:Ev,multi:!0},{provide:gT,useClass:dU},{provide:wv,useValue:"XSRF-TOKEN"},{provide:Sv,useValue:"X-XSRF-TOKEN"}]}),e})(),pU=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=ge({type:e}),e.\u0275inj=Me({providers:[fT,{provide:oT,useClass:fU},pT,{provide:sT,useExisting:pT}],imports:[hU.withOptions({cookieName:"XSRF-TOKEN",headerName:"X-XSRF-TOKEN"})]}),e})(),mT=(()=>{class e{constructor(t,i){this.config=t,this.http=i}pauseConsumerTopic(t,i){var r=this;return Wr(function*(){yield Kr(r.http.put(r.config.rootUrl+`/consumers/${t}/topics/${i}/pause`,""))})()}resumeConsumerTopic(t,i){var r=this;return Wr(function*(){yield Kr(r.http.put(r.config.rootUrl+`/consumers/${t}/topics/${i}/resume`,""))})()}resetConsumerTopic(t,i){var r=this;return Wr(function*(){yield Kr(r.http.put(r.config.rootUrl+`/consumers/${t}/topics/${i}/reset`,""))})()}rewindConsumerTopic(t,i,r){var o=this;return Wr(function*(){const s=tT(r).format("YYYY-MM-DD HH:mm:ss");yield Kr(o.http.put(o.config.rootUrl+`/consumers/${t}/topics/${i}/rewind/${s}`,""))})()}stopConsumer(t){var i=this;return Wr(function*(){yield Kr(i.http.put(i.config.rootUrl+`/consumers/${t}/stop`,""))})()}startConsumer(t){var i=this;return Wr(function*(){yield Kr(i.http.put(i.config.rootUrl+`/consumers/${t}/start`,""))})()}restartConsumer(t){var i=this;return Wr(function*(){yield Kr(i.http.put(i.config.rootUrl+`/consumers/${t}/restart`,""))})()}changeWorkers(t,i){var r=this;return Wr(function*(){yield Kr(r.http.put(r.config.rootUrl+`/consumers/${t}/changeWorkers/${i}`,""))})()}getTelemetry(){var t=this;return Wr(function*(){return yield Kr(t.http.get(t.config.rootUrl+"/consumers/telemetry"))})()}}return e.\u0275fac=function(t){return new(t||e)(L(rT),L(fT))},e.\u0275prov=U({token:e,factory:e.\u0275fac}),e})(),gU=(()=>{class e{transform(t,i){if(!t)return null;const r=t.reduce((o,s)=>(o[s[i]]?o[s[i]].push(s):o[s[i]]=[s],o),{});return Object.keys(r).map(o=>({key:o,value:r[o]}))}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275pipe=Tt({name:"groupBy",type:e,pure:!0}),e})(),mU=(()=>{class e{transform(t,i,r="asc"){return"asc"!==(r=r.toLowerCase())&&"desc"!==r?t:Array.isArray(t)?(t.sort((o,s)=>o[i]s[i]?"asc"===r?1:-1:0),t):null}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275pipe=Tt({name:"sort",type:e,pure:!0}),e})();const _U=["successAlert"];function vU(e,n){if(1&e){const t=It();M(0,"ngb-alert",2,3),K("closed",function(){return nt(t),ht(z().successMessage="")}),M(2,"div",4)(3,"b"),I(4,"Success! "),N(),M(5,"span",4),I(6),N()()()}if(2&e){const t=z();P(6),Rr(t.successMessage)}}function yU(e,n){if(1&e){const t=It();M(0,"button",14),K("click",function(){nt(t);const r=z().$implicit,o=z().$implicit;return ht(z().openStartModal(o.groupId,r.name))}),I(1,"Start"),N()}}function bU(e,n){if(1&e){const t=It();M(0,"button",15),K("click",function(){nt(t);const r=z().$implicit,o=z().$implicit;return ht(z().openStopModal(o.groupId,r.name))}),I(1,"Stop"),N()}}function DU(e,n){if(1&e){const t=It();M(0,"button",15),K("click",function(){nt(t);const r=z().$implicit,o=z().$implicit;return ht(z().openRestartModal(o.groupId,r.name))}),I(1,"Restart"),N()}}function CU(e,n){if(1&e){const t=It();M(0,"button",16),K("click",function(){nt(t);const r=z().$implicit,o=z().$implicit;return ht(z().openWorkersCountModal(o.groupId,r.name))}),I(1,"Force number of workers"),N()}}function wU(e,n){if(1&e){const t=It();M(0,"button",14),K("click",function(){nt(t);const r=z().$implicit,o=z().$implicit,s=z().$implicit;return ht(z().openResumeModal(s.groupId,o.name,r.key))}),I(1,"Resume"),N()}}function SU(e,n){if(1&e){const t=It();M(0,"button",15),K("click",function(){nt(t);const r=z().$implicit,o=z().$implicit,s=z().$implicit;return ht(z().openPauseModal(s.groupId,o.name,r.key))}),I(1,"Pause"),N()}}function EU(e,n){if(1&e){const t=It();M(0,"button",20),K("click",function(){nt(t);const r=z().$implicit,o=z().$implicit,s=z().$implicit;return ht(z().openRewindModal(s.groupId,o.name,r.key))}),I(1,"Rewind Offset"),N()}}function MU(e,n){if(1&e){const t=It();M(0,"button",21),K("click",function(){nt(t);const r=z().$implicit,o=z().$implicit,s=z().$implicit;return ht(z().openResetModal(s.groupId,o.name,r.key))}),I(1,"Reset Offset"),N()}}function TU(e,n){1&e&&Ri(0,"div")}function NU(e,n){1&e&&(M(0,"span"),I(1,"Offline"),N())}function AU(e,n){1&e&&(M(0,"span",27),I(1,"Paused"),N())}function IU(e,n){1&e&&(M(0,"span",28),I(1,"Running"),N())}function OU(e,n){if(1&e&&(Z(0,AU,2,0,"ng-template",26),Z(1,IU,2,0,"ng-template",26)),2&e){const t=z().$implicit,i=z(4);X("ngIf",i.hasPausedPartition(t)),P(1),X("ngIf",i.hasRunningPartition(t))}}function kU(e,n){if(1&e&&(M(0,"tr")(1,"td",22),I(2),N(),M(3,"td",22),I(4),N(),M(5,"td",22),I(6),N(),M(7,"td",22),I(8),N(),M(9,"td",22),Z(10,TU,1,0,"div",23),Z(11,NU,2,0,"ng-template",null,24,Li),Z(13,OU,2,2,"ng-template",null,25,Li),N(),M(15,"td",22)(16,"span",9),I(17),Ad(18,"date"),N()()()),2&e){const t=n.$implicit,i=ki(12),r=ki(14),o=z(4);P(2),Rr(t.instanceName),P(2),Rr(t.workers),P(2),Rr(o.hasRunningPartition(t)?t.runningPartitions:t.pausedPartitions),P(2),Rr(t.lag),P(2),X("ngIf",t.isLost)("ngIfThen",i)("ngIfElse",r),P(6),X("ngClass",t.isLost?"text-secondary":"text-success"),P(1),Rr(Id(18,9,t.lastUpdate+"Z","medium"))}}function RU(e,n){if(1&e&&(Ri(0,"hr"),M(1,"h5"),I(2),Z(3,wU,2,0,"button",10),Z(4,SU,2,0,"button",11),Z(5,EU,2,0,"button",17),Z(6,MU,2,0,"button",18),N(),M(7,"table",19)(8,"thead")(9,"tr")(10,"th"),I(11,"Consumer instance"),N(),M(12,"th"),I(13,"Workers"),N(),M(14,"th"),I(15,"Partitions"),N(),M(16,"th"),I(17,"Lag"),N(),M(18,"th"),I(19,"Status"),N(),M(20,"th"),I(21,"LastUpdate"),N()()(),M(22,"tbody"),Z(23,kU,19,12,"ng-template",13),Ad(24,"sort"),N()()),2&e){const t=n.$implicit,i=z().$implicit,r=z(2);P(2),Be(" Topic: ",t.key," "),P(1),X("ngIf",t.value.some(r.hasPausedPartition)),P(1),X("ngIf",t.value.some(r.hasRunningPartition)),P(1),X("ngIf","Running"===i.status),P(1),X("ngIf","Running"===i.status),P(17),X("ngForOf",Id(24,6,t.value,"instanceName"))}}const xU=function(e,n,t){return{"text-success":e,"text-warning":n,"text-danger":t}},FU=function(){return[]};function PU(e,n){if(1&e&&(M(0,"div")(1,"h4"),I(2),N(),M(3,"h4"),I(4,"Status: "),M(5,"span",9),I(6),N(),Z(7,yU,2,0,"button",10),Z(8,bU,2,0,"button",11),Z(9,DU,2,0,"button",11),Z(10,CU,2,0,"button",12),N(),M(11,"h4"),I(12),N(),Z(13,RU,25,9,"ng-template",13),Ad(14,"groupBy"),Ri(15,"hr"),N()),2&e){const t=n.$implicit;P(2),Be("Consumer: ",t.name,""),P(3),X("ngClass",Nd(12,xU,"Running"===t.status,"Paused"===t.status,"Not Running"===t.status)),P(1),Rr(t.status),P(1),X("ngIf","Not Running"===t.status),P(1),X("ngIf","Running"===t.status),P(1),X("ngIf","Running"===t.status),P(1),X("ngIf","Running"===t.status),P(2),Be("Lag: ",t.lag,""),P(1),X("ngForOf",Id(14,9,t.assignments||function l1(e,n,t){const i=rn()+e,r=k();return r[i]===ae?ir(r,i,t?n.call(t):n()):function Yl(e,n){return e[n]}(r,i)}(16,FU),"topicName"))}}function LU(e,n){if(1&e&&(M(0,"div",5)(1,"div",6)(2,"div",7)(3,"h3"),I(4),N(),Z(5,PU,16,17,"div",8),N()()()),2&e){const t=n.$implicit;P(4),Be("Group Id: ",t.groupId,""),P(1),X("ngForOf",t.consumers)}}let VU=(()=>{class e{constructor(t,i){this.modalService=t,this.gateway=i,this.successSubject=new je,this.delayMs=5e3,this.successMessage="",this.updateData=()=>{this.gateway.getTelemetry().then(r=>{this.telemetryResponse=this.updateConsumersStatus(r)})},this.hasRunningPartition=r=>r.runningPartitions?.length>0,this.hasPausedPartition=r=>r.pausedPartitions?.length>0,this.isActive=r=>Math.abs(((new Date).getTime()-new Date(r+"Z").getTime())/1e3)<30,this.openWorkersCountModal=(r,o)=>{const s=this.modalService.open(Y3);s.componentInstance.groupId=r,s.componentInstance.consumerName=o,s.result.then(a=>{this.gateway.changeWorkers(o,a).then(()=>this.successSubject.next("The number of workers was updated successfully"))})},this.openResetModal=(r,o,s)=>{const a=this.modalService.open(q3);a.componentInstance.groupId=r,a.componentInstance.consumerName=o,a.componentInstance.topic=s,a.result.then(()=>{this.gateway.resetConsumerTopic(o,s).then(()=>this.successSubject.next("The partition-offsets of your consumer were reseted successfully"))})},this.openPauseModal=(r,o,s)=>{const a=this.modalService.open(J3);a.componentInstance.groupId=r,a.componentInstance.topic=s,a.componentInstance.consumerName=o,a.result.then(()=>{this.gateway.pauseConsumerTopic(o,s).then(()=>this.successSubject.next("Your consumer was paused successfully"))})},this.openRestartModal=(r,o)=>{const s=this.modalService.open(Q3);s.componentInstance.groupId=r,s.componentInstance.consumerName=o,s.result.then(()=>{this.gateway.restartConsumer(o).then(()=>this.successSubject.next("Your consumer was restarted successfully"))})},this.openStartModal=(r,o)=>{const s=this.modalService.open(X3);s.componentInstance.groupId=r,s.componentInstance.consumerName=o,s.result.then(()=>{this.gateway.startConsumer(o).then(()=>this.successSubject.next("Your consumer was started successfully"))})},this.openStopModal=(r,o)=>{const s=this.modalService.open(eU);s.componentInstance.groupId=r,s.componentInstance.consumerName=o,s.result.then(()=>{this.gateway.stopConsumer(o).then(()=>this.successSubject.next("Your consumer was stopped successfully"))})},this.openResumeModal=(r,o,s)=>{const a=this.modalService.open(Z3);a.componentInstance.groupId=r,a.componentInstance.consumerName=o,a.componentInstance.topic=s,a.result.then(()=>{this.gateway.resumeConsumerTopic(o,s).then(()=>this.successSubject.next("Your consumer was resumed successfully"))})},this.openRewindModal=(r,o,s)=>{const a=this.modalService.open(z3);a.componentInstance.consumerName=o,a.componentInstance.groupId=r,a.componentInstance.topic=s,a.result.then(l=>{const u=tT(l,"YYYY-MM-DDTHH:mm").toDate();this.gateway.rewindConsumerTopic(o,s,u).then(()=>this.successSubject.next("The partition-offset of your consumer were rewound successfully"))})}}ngOnInit(){this.successSubject.subscribe(t=>this.successMessage=t),this.successSubject.pipe(function K3(e,n=jf){return qe((t,i)=>{let r=null,o=null,s=null;const a=()=>{if(r){r.unsubscribe(),r=null;const u=o;o=null,i.next(u)}};function l(){const u=s+e,f=n.now();if(f{o=u,s=n.now(),r||(r=n.schedule(l,e),i.add(r))},()=>{a(),i.complete()},void 0,()=>{o=r=null}))})}(5e3)).subscribe(()=>this.successAlert?.close()),this.updateData(),function W3(e=0,n=jf){return e<0&&(e=0),Lc(e,e,n)}(this.delayMs).subscribe(this.updateData)}updateConsumersStatus(t){const i=this;return t.groups?.forEach(r=>{r.consumers?.forEach(o=>{o.status=o.assignments.some(s=>s.runningPartitions?.length>0&&i.isActive(s.lastUpdate))?"Running":o.assignments.some(s=>s.pausedPartitions?.length>0&&i.isActive(s.lastUpdate))?"Paused":"Not Running",o.lag=o.assignments.map(s=>s.lag).reduce((s,a)=>s+a),o.assignments.forEach(s=>s.isLost=!i.isActive(s.lastUpdate))})}),t}}return e.\u0275fac=function(t){return new(t||e)(C(kM),C(mT))},e.\u0275cmp=lt({type:e,selectors:[["app-consumer"]],viewQuery:function(t,i){if(1&t&&kd(_U,5),2&t){let r;ot(r=st())&&(i.successAlert=r.first)}},decls:2,vars:2,consts:[["type","success",3,"closed",4,"ngIf"],["class","container",4,"ngFor","ngForOf"],["type","success",3,"closed"],["successAlert",""],[1,"text-center"],[1,"container"],[1,"card","my-3"],[1,"card-body"],[4,"ngFor","ngForOf"],[3,"ngClass"],["class","btn btn-sm btn-outline-success ml-2","type","button",3,"click",4,"ngIf"],["class","btn btn-sm btn-outline-warning ml-2","type","button",3,"click",4,"ngIf"],["class","btn btn-sm btn-outline-success ml-3","type","button",3,"click",4,"ngIf"],["ngFor","",3,"ngForOf"],["type","button",1,"btn","btn-sm","btn-outline-success","ml-2",3,"click"],["type","button",1,"btn","btn-sm","btn-outline-warning","ml-2",3,"click"],["type","button",1,"btn","btn-sm","btn-outline-success","ml-3",3,"click"],["class","btn btn-sm btn-outline-info ml-2","type","button",3,"click",4,"ngIf"],["class","btn btn-sm btn-outline-secondary ml-2","type","button",3,"click",4,"ngIf"],[1,"table","table-striped","table-hover","mt-1"],["type","button",1,"btn","btn-sm","btn-outline-info","ml-2",3,"click"],["type","button",1,"btn","btn-sm","btn-outline-secondary","ml-2",3,"click"],[1,"text-left"],[4,"ngIf","ngIfThen","ngIfElse"],["consumer_lost",""],["consumer_on",""],[3,"ngIf"],[1,"font-weight-bold","text-warning"],[1,"font-weight-bold","text-success"]],template:function(t,i){1&t&&(Z(0,vU,7,1,"ngb-alert",0),Z(1,LU,6,2,"div",1)),2&t&&(X("ngIf",i.successMessage),P(1),X("ngForOf",null==i.telemetryResponse?null:i.telemetryResponse.groups))},dependencies:[OC,Ra,os,H$,LC,gU,mU],encapsulation:2}),e})(),HU=(()=>{class e{constructor(){}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275cmp=lt({type:e,selectors:[["app-home"]],decls:12,vars:0,consts:[[1,"navbar","navbar-expand-lg","navbar-light","bg-light"],[1,"container-fluid"],["href","#",1,"navbar-brand"],["type","button","data-bs-toggle","collapse","data-bs-target","#navbarSupportedContent","aria-controls","navbarSupportedContent","aria-expanded","false","aria-label","Toggle navigation",1,"navbar-toggler"],[1,"navbar-toggler-icon"],["id","navbarSupportedContent",1,"collapse","navbar-collapse"],[1,"navbar-nav","me-auto","mb-2","mb-lg-0"],[1,"nav-item"],["aria-current","page","href","#",1,"nav-link","active"]],template:function(t,i){1&t&&(M(0,"nav",0)(1,"div",1)(2,"a",2),I(3,"KafkaFlow - Dashboard"),N(),M(4,"button",3),Ri(5,"span",4),N(),M(6,"div",5)(7,"ul",6)(8,"li",7)(9,"a",8),I(10,"Consumers"),N()()()()()(),Ri(11,"app-consumer"))},dependencies:[gv,VU],encapsulation:2}),e})(),jU=(()=>{class e{constructor(t){this.cookieService=t}intercept(t,i){return t=t.clone({setHeaders:this.cookieService.getAll()}),i.handle(t).pipe(function BU(e=1/0){let n;n=e&&"object"==typeof e?e:{count:e};const{count:t=1/0,delay:i,resetOnSuccess:r=!1}=n;return t<=0?Pn:qe((o,s)=>{let l,a=0;const u=()=>{let f=!1;l=o.subscribe(Oe(s,p=>{r&&(a=0),s.next(p)},void 0,p=>{if(a++{l?(l.unsubscribe(),l=null,u()):f=!0};if(null!=i){const v="number"==typeof i?Lc(i):Et(i(p,a)),y=Oe(s,()=>{y.unsubscribe(),m()},()=>{s.complete()});v.subscribe(y)}else m()}else s.error(p)})),f&&(l.unsubscribe(),l=null,u())};u()})}(1),Br(r=>{let o="";return o=r.error instanceof ErrorEvent?`Error: ${r.error.message}`:`Error Code: ${r.status}\nMessage: ${r.message}`,console.error(o),xa(o)}))}}return e.\u0275fac=function(t){return new(t||e)(L(FE))},e.\u0275prov=U({token:e,factory:e.\u0275fac}),e})();const $U={validation:!1},UU=[{path:"",component:HU}];let GU=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275mod=ge({type:e,bootstrap:[UH]}),e.\u0275inj=Me({providers:[rT,FE,mT,{provide:Cv,useClass:jU,multi:!0}],imports:[QP,$H,Af.forRoot(UU),pU,IE,G3,BH.forRoot($U),Af]}),e})();ZP().bootstrapModule(GU).catch(e=>console.error(e))},439:function(hr,lh,Xc){(hr=Xc.nmd(hr)).exports=function(){"use strict";var be,Mo;function V(){return be.apply(null,arguments)}function dn(c){return c instanceof Array||"[object Array]"===Object.prototype.toString.call(c)}function _t(c){return null!=c&&"[object Object]"===Object.prototype.toString.call(c)}function we(c,d){return Object.prototype.hasOwnProperty.call(c,d)}function ws(c){if(Object.getOwnPropertyNames)return 0===Object.getOwnPropertyNames(c).length;var d;for(d in c)if(we(c,d))return!1;return!0}function qt(c){return void 0===c}function Jt(c){return"number"==typeof c||"[object Number]"===Object.prototype.toString.call(c)}function zi(c){return c instanceof Date||"[object Date]"===Object.prototype.toString.call(c)}function Za(c,d){var g,h=[],_=c.length;for(g=0;g<_;++g)h.push(d(c[g],g));return h}function Cn(c,d){for(var h in d)we(d,h)&&(c[h]=d[h]);return we(d,"toString")&&(c.toString=d.toString),we(d,"valueOf")&&(c.valueOf=d.valueOf),c}function ni(c,d,h,g){return H(c,d,h,g,!0).utc()}function le(c){return null==c._pf&&(c._pf={empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidEra:null,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1,parsedDateParts:[],era:null,meridiem:null,rfc2822:!1,weekdayMismatch:!1}),c._pf}function _i(c){if(null==c._isValid){var d=le(c),h=Mo.call(d.parsedDateParts,function(_){return null!=_}),g=!isNaN(c._d.getTime())&&d.overflow<0&&!d.empty&&!d.invalidEra&&!d.invalidMonth&&!d.invalidWeekday&&!d.weekdayMismatch&&!d.nullInput&&!d.invalidFormat&&!d.userInvalidated&&(!d.meridiem||d.meridiem&&h);if(c._strict&&(g=g&&0===d.charsLeftOver&&0===d.unusedTokens.length&&void 0===d.bigHour),null!=Object.isFrozen&&Object.isFrozen(c))return g;c._isValid=g}return c._isValid}function pr(c){var d=ni(NaN);return null!=c?Cn(le(d),c):le(d).userInvalidated=!0,d}Mo=Array.prototype.some?Array.prototype.some:function(c){var g,d=Object(this),h=d.length>>>0;for(g=0;g0)for(h=0;h=0?h?"+":"":"-")+Math.pow(10,Math.max(0,d-g.length)).toString().substr(1)+g}var tl=/(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|N{1,5}|YYYYYY|YYYYY|YYYY|YY|y{2,4}|yo?|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,Ms=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,je={},_r={};function q(c,d,h,g){var _=g;"string"==typeof g&&(_=function(){return this[g]()}),c&&(_r[c]=_),d&&(_r[d[0]]=function(){return ri(_.apply(this,arguments),d[1],d[2])}),h&&(_r[h]=function(){return this.localeData().ordinal(_.apply(this,arguments),c)})}function qe(c){return c.match(/\[[\s\S]/)?c.replace(/^\[|\]$/g,""):c.replace(/\\/g,"")}function Ts(c,d){return c.isValid()?(d=ie(d,c.localeData()),je[d]=je[d]||function Oe(c){var h,g,d=c.match(tl);for(h=0,g=d.length;h=0&&Ms.test(c);)c=c.replace(Ms,g),Ms.lastIndex=0,h-=1;return c}var No={};function xt(c,d){var h=c.toLowerCase();No[h]=No[h+"s"]=No[d]=c}function Ln(c){return"string"==typeof c?No[c]||No[c.toLowerCase()]:void 0}function Ao(c){var h,g,d={};for(g in c)we(c,g)&&(h=Ln(g))&&(d[h]=c[g]);return d}var iu={};function St(c,d){iu[c]=d}function Ns(c){return c%4==0&&c%100!=0||c%400==0}function Vn(c){return c<0?Math.ceil(c)||0:Math.floor(c)}function he(c){var d=+c,h=0;return 0!==d&&isFinite(d)&&(h=Vn(d)),h}function wn(c,d){return function(h){return null!=h?(ou(this,c,h),V.updateOffset(this,d),this):Io(this,c)}}function Io(c,d){return c.isValid()?c._d["get"+(c._isUTC?"UTC":"")+d]():NaN}function ou(c,d,h){c.isValid()&&!isNaN(h)&&("FullYear"===d&&Ns(c.year())&&1===c.month()&&29===c.date()?(h=he(h),c._d["set"+(c._isUTC?"UTC":"")+d](h,c.month(),yr(h,c.month()))):c._d["set"+(c._isUTC?"UTC":"")+d](h))}var Ro,au=/\d/,Sn=/\d\d/,lu=/\d{3}/,rl=/\d{4}/,As=/[+-]?\d{6}/,Ke=/\d\d?/,cu=/\d\d\d\d?/,uu=/\d\d\d\d\d\d?/,Is=/\d{1,3}/,du=/\d{1,4}/,Yr=/[+-]?\d{1,6}/,vr=/\d+/,Oo=/[+-]?\d+/,fu=/Z|[+-]\d\d:?\d\d/gi,ko=/Z|[+-]\d\d(?::?\d\d)?/gi,qr=/[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i;function $(c,d,h){Ro[c]=ii(d)?d:function(g,_){return g&&h?h:d}}function hu(c,d){return we(Ro,c)?Ro[c](d._strict,d._locale):new RegExp(function Et(c){return En(c.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(d,h,g,_,b){return h||g||_||b}))}(c))}function En(c){return c.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}Ro={};var ol={};function Pe(c,d){var h,_,g=d;for("string"==typeof c&&(c=[c]),Jt(d)&&(g=function(b,T){T[d]=he(b)}),_=c.length,h=0;h<_;h++)ol[c[h]]=g}function xo(c,d){Pe(c,function(h,g,_,b){_._w=_._w||{},d(h,_._w,_,b)})}function pu(c,d,h){null!=d&&we(ol,c)&&ol[c](d,h._a,h,c)}var tt;function yr(c,d){if(isNaN(c)||isNaN(d))return NaN;var h=function gu(c,d){return(c%d+d)%d}(d,12);return c+=(d-h)/12,1===h?Ns(c)?29:28:31-h%7%2}tt=Array.prototype.indexOf?Array.prototype.indexOf:function(c){var d;for(d=0;d68?1900:2e3)};var ks=wn("FullYear",!0);function al(c,d,h,g,_,b,T){var J;return c<100&&c>=0?(J=new Date(c+400,d,h,g,_,b,T),isFinite(J.getFullYear())&&J.setFullYear(c)):J=new Date(c,d,h,g,_,b,T),J}function Po(c){var d,h;return c<100&&c>=0?((h=Array.prototype.slice.call(arguments))[0]=c+400,d=new Date(Date.UTC.apply(null,h)),isFinite(d.getUTCFullYear())&&d.setUTCFullYear(c)):d=new Date(Date.UTC.apply(null,arguments)),d}function De(c,d,h){var g=7+d-h;return-(7+Po(c,0,g).getUTCDay()-d)%7+g-1}function te(c,d,h,g,_){var ue,xe,J=1+7*(d-1)+(7+h-g)%7+De(c,g,_);return J<=0?xe=Ne(ue=c-1)+J:J>Ne(c)?(ue=c+1,xe=J-Ne(c)):(ue=c,xe=J),{year:ue,dayOfYear:xe}}function br(c,d,h){var b,T,g=De(c.year(),d,h),_=Math.floor((c.dayOfYear()-g-1)/7)+1;return _<1?b=_+Yi(T=c.year()-1,d,h):_>Yi(c.year(),d,h)?(b=_-Yi(c.year(),d,h),T=c.year()+1):(T=c.year(),b=_),{week:b,year:T}}function Yi(c,d,h){var g=De(c,d,h),_=De(c+1,d,h);return(Ne(c)-g+_)/7}q("w",["ww",2],"wo","week"),q("W",["WW",2],"Wo","isoWeek"),xt("week","w"),xt("isoWeek","W"),St("week",5),St("isoWeek",5),$("w",Ke),$("ww",Ke,Sn),$("W",Ke),$("WW",Ke,Sn),xo(["w","ww","W","WW"],function(c,d,h,g){d[g.substr(0,1)]=he(c)});function Qt(c,d){return c.slice(d,7).concat(c.slice(0,d))}q("d",0,"do","day"),q("dd",0,0,function(c){return this.localeData().weekdaysMin(this,c)}),q("ddd",0,0,function(c){return this.localeData().weekdaysShort(this,c)}),q("dddd",0,0,function(c){return this.localeData().weekdays(this,c)}),q("e",0,0,"weekday"),q("E",0,0,"isoWeekday"),xt("day","d"),xt("weekday","e"),xt("isoWeekday","E"),St("day",11),St("weekday",11),St("isoWeekday",11),$("d",Ke),$("e",Ke),$("E",Ke),$("dd",function(c,d){return d.weekdaysMinRegex(c)}),$("ddd",function(c,d){return d.weekdaysShortRegex(c)}),$("dddd",function(c,d){return d.weekdaysRegex(c)}),xo(["dd","ddd","dddd"],function(c,d,h,g){var _=h._locale.weekdaysParse(c,g,h._strict);null!=_?d.d=_:le(h).invalidWeekday=c}),xo(["d","e","E"],function(c,d,h,g){d[g]=he(c)});var Pv="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),Du="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),Lv="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),yi=qr,Vv=qr,Hv=qr;function $v(c,d,h){var g,_,b,T=c.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],g=0;g<7;++g)b=ni([2e3,1]).day(g),this._minWeekdaysParse[g]=this.weekdaysMin(b,"").toLocaleLowerCase(),this._shortWeekdaysParse[g]=this.weekdaysShort(b,"").toLocaleLowerCase(),this._weekdaysParse[g]=this.weekdays(b,"").toLocaleLowerCase();return h?"dddd"===d?-1!==(_=tt.call(this._weekdaysParse,T))?_:null:"ddd"===d?-1!==(_=tt.call(this._shortWeekdaysParse,T))?_:null:-1!==(_=tt.call(this._minWeekdaysParse,T))?_:null:"dddd"===d?-1!==(_=tt.call(this._weekdaysParse,T))||-1!==(_=tt.call(this._shortWeekdaysParse,T))||-1!==(_=tt.call(this._minWeekdaysParse,T))?_:null:"ddd"===d?-1!==(_=tt.call(this._shortWeekdaysParse,T))||-1!==(_=tt.call(this._weekdaysParse,T))||-1!==(_=tt.call(this._minWeekdaysParse,T))?_:null:-1!==(_=tt.call(this._minWeekdaysParse,T))||-1!==(_=tt.call(this._weekdaysParse,T))||-1!==(_=tt.call(this._shortWeekdaysParse,T))?_:null}function U(){function c(Kt,ci){return ci.length-Kt.length}var b,T,J,ue,xe,d=[],h=[],g=[],_=[];for(b=0;b<7;b++)T=ni([2e3,1]).day(b),J=En(this.weekdaysMin(T,"")),ue=En(this.weekdaysShort(T,"")),xe=En(this.weekdays(T,"")),d.push(J),h.push(ue),g.push(xe),_.push(J),_.push(ue),_.push(xe);d.sort(c),h.sort(c),g.sort(c),_.sort(c),this._weekdaysRegex=new RegExp("^("+_.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+g.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+h.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+d.join("|")+")","i")}function Cu(){return this.hours()%12||12}function Lo(c,d){q(c,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),d)})}function wu(c,d){return d._meridiemParse}q("H",["HH",2],0,"hour"),q("h",["hh",2],0,Cu),q("k",["kk",2],0,function Me(){return this.hours()||24}),q("hmm",0,0,function(){return""+Cu.apply(this)+ri(this.minutes(),2)}),q("hmmss",0,0,function(){return""+Cu.apply(this)+ri(this.minutes(),2)+ri(this.seconds(),2)}),q("Hmm",0,0,function(){return""+this.hours()+ri(this.minutes(),2)}),q("Hmmss",0,0,function(){return""+this.hours()+ri(this.minutes(),2)+ri(this.seconds(),2)}),Lo("a",!0),Lo("A",!1),xt("hour","h"),St("hour",13),$("a",wu),$("A",wu),$("H",Ke),$("h",Ke),$("k",Ke),$("HH",Ke,Sn),$("hh",Ke,Sn),$("kk",Ke,Sn),$("hmm",cu),$("hmmss",uu),$("Hmm",cu),$("Hmmss",uu),Pe(["H","HH"],3),Pe(["k","kk"],function(c,d,h){var g=he(c);d[3]=24===g?0:g}),Pe(["a","A"],function(c,d,h){h._isPm=h._locale.isPM(c),h._meridiem=c}),Pe(["h","hh"],function(c,d,h){d[3]=he(c),le(h).bigHour=!0}),Pe("hmm",function(c,d,h){var g=c.length-2;d[3]=he(c.substr(0,g)),d[4]=he(c.substr(g)),le(h).bigHour=!0}),Pe("hmmss",function(c,d,h){var g=c.length-4,_=c.length-2;d[3]=he(c.substr(0,g)),d[4]=he(c.substr(g,2)),d[5]=he(c.substr(_)),le(h).bigHour=!0}),Pe("Hmm",function(c,d,h){var g=c.length-2;d[3]=he(c.substr(0,g)),d[4]=he(c.substr(g))}),Pe("Hmmss",function(c,d,h){var g=c.length-4,_=c.length-2;d[3]=he(c.substr(0,g)),d[4]=he(c.substr(g,2)),d[5]=he(c.substr(_))});var Nh=wn("Hours",!0);var Ho,Vo={calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},longDateFormat:{LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},invalidDate:"Invalid date",ordinal:"%d",dayOfMonthOrdinalParse:/\d{1,2}/,relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",w:"a week",ww:"%d weeks",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},months:Fo,monthsShort:mu,week:{dow:0,doy:6},weekdays:Pv,weekdaysMin:Lv,weekdaysShort:Du,meridiemParse:/[ap]\.?m?\.?/i},$e={},Jr={};function ee(c,d){var h,g=Math.min(c.length,d.length);for(h=0;h0;){if(_=Bo(b.slice(0,h).join("-")))return _;if(g&&g.length>=h&&ee(b,g)>=h-1)break;h--}d++}return Ho}(c)}function Bn(c){var d,h=c._a;return h&&-2===le(c).overflow&&(d=h[1]<0||h[1]>11?1:h[2]<1||h[2]>yr(h[0],h[1])?2:h[3]<0||h[3]>24||24===h[3]&&(0!==h[4]||0!==h[5]||0!==h[6])?3:h[4]<0||h[4]>59?4:h[5]<0||h[5]>59?5:h[6]<0||h[6]>999?6:-1,le(c)._overflowDayOfYear&&(d<0||d>2)&&(d=2),le(c)._overflowWeeks&&-1===d&&(d=7),le(c)._overflowWeekday&&-1===d&&(d=8),le(c).overflow=d),c}var Ue=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Yv=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d|))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,qv=/Z|[+-]\d\d(?::?\d\d)?/,bi=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/],["YYYYMM",/\d{6}/,!1],["YYYY",/\d{4}/,!1]],Se=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],Ps=/^\/?Date\((-?\d+)/i,ll=/^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/,cl={UT:0,GMT:0,EDT:-240,EST:-300,CDT:-300,CST:-360,MDT:-360,MST:-420,PDT:-420,PST:-480};function ul(c){var d,h,b,T,J,ue,g=c._i,_=Ue.exec(g)||Yv.exec(g),xe=bi.length,Kt=Se.length;if(_){for(le(c).iso=!0,d=0,h=xe;d7)&&(ue=!0)):(b=c._locale._week.dow,T=c._locale._week.doy,xe=br(G(),b,T),h=ge(d.gg,c._a[0],xe.year),g=ge(d.w,xe.week),null!=d.d?((_=d.d)<0||_>6)&&(ue=!0):null!=d.e?(_=d.e+b,(d.e<0||d.e>6)&&(ue=!0)):_=b),g<1||g>Yi(h,b,T)?le(c)._overflowWeeks=!0:null!=ue?le(c)._overflowWeekday=!0:(J=te(h,g,_,b,T),c._a[0]=J.year,c._dayOfYear=J.dayOfYear)}(c),null!=c._dayOfYear&&(T=ge(c._a[0],_[0]),(c._dayOfYear>Ne(T)||0===c._dayOfYear)&&(le(c)._overflowDayOfYear=!0),h=Po(T,0,c._dayOfYear),c._a[1]=h.getUTCMonth(),c._a[2]=h.getUTCDate()),d=0;d<3&&null==c._a[d];++d)c._a[d]=g[d]=_[d];for(;d<7;d++)c._a[d]=g[d]=c._a[d]??(2===d?1:0);24===c._a[3]&&0===c._a[4]&&0===c._a[5]&&0===c._a[6]&&(c._nextDay=!0,c._a[3]=0),c._d=(c._useUTC?Po:al).apply(null,g),b=c._useUTC?c._d.getUTCDay():c._d.getDay(),null!=c._tzm&&c._d.setUTCMinutes(c._d.getUTCMinutes()-c._tzm),c._nextDay&&(c._a[3]=24),c._w&&typeof c._w.d<"u"&&c._w.d!==b&&(le(c).weekdayMismatch=!0)}}function Tt(c){if(c._f!==V.ISO_8601)if(c._f!==V.RFC_2822){c._a=[],le(c).empty=!0;var h,g,_,b,T,xe,Kt,d=""+c._i,J=d.length,ue=0;for(Kt=(_=ie(c._f,c._locale).match(tl)||[]).length,h=0;h0&&le(c).unusedInput.push(T),d=d.slice(d.indexOf(g)+g.length),ue+=g.length),_r[b]?(g?le(c).empty=!1:le(c).unusedTokens.push(b),pu(b,g,c)):c._strict&&!g&&le(c).unusedTokens.push(b);le(c).charsLeftOver=J-ue,d.length>0&&le(c).unusedInput.push(d),c._a[3]<=12&&!0===le(c).bigHour&&c._a[3]>0&&(le(c).bigHour=void 0),le(c).parsedDateParts=c._a.slice(0),le(c).meridiem=c._meridiem,c._a[3]=function Re(c,d,h){var g;return null==h?d:null!=c.meridiemHour?c.meridiemHour(d,h):(null!=c.isPM&&((g=c.isPM(h))&&d<12&&(d+=12),!g&&12===d&&(d=0)),d)}(c._locale,c._a[3],c._meridiem),null!==(xe=le(c).era)&&(c._a[0]=c._locale.erasConvertYear(xe,c._a[0])),Ls(c),Bn(c)}else dl(c);else ul(c)}function hn(c){var d=c._i,h=c._f;return c._locale=c._locale||qi(c._l),null===d||void 0===h&&""===d?pr({nullInput:!0}):("string"==typeof d&&(c._i=d=c._locale.preparse(d)),Wn(d)?new gr(Bn(d)):(zi(d)?c._d=d:dn(h)?function Xt(c){var d,h,g,_,b,T,J=!1,ue=c._f.length;if(0===ue)return le(c).invalidFormat=!0,void(c._d=new Date(NaN));for(_=0;_this?this:c:pr()});function Ji(c,d){var h,g;if(1===d.length&&dn(d[0])&&(d=d[0]),!d.length)return G();for(h=d[0],g=1;g=0?new Date(c+400,d,h)-$s:new Date(c,d,h).valueOf()}function Ou(c,d,h){return c<100&&c>=0?Date.UTC(c+400,d,h)-$s:Date.UTC(c,d,h)}function Ks(c,d){return d.erasAbbrRegex(c)}function me(){var _,b,c=[],d=[],h=[],g=[],T=this.eras();for(_=0,b=T.length;_(b=Yi(c,g,_))&&(d=b),py.call(this,c,d,h,g,_))}function py(c,d,h,g,_){var b=te(c,d,h,g,_),T=Po(b.year,0,b.dayOfYear);return this.year(T.getUTCFullYear()),this.month(T.getUTCMonth()),this.date(T.getUTCDate()),this}q("N",0,0,"eraAbbr"),q("NN",0,0,"eraAbbr"),q("NNN",0,0,"eraAbbr"),q("NNNN",0,0,"eraName"),q("NNNNN",0,0,"eraNarrow"),q("y",["y",1],"yo","eraYear"),q("y",["yy",2],0,"eraYear"),q("y",["yyy",3],0,"eraYear"),q("y",["yyyy",4],0,"eraYear"),$("N",Ks),$("NN",Ks),$("NNN",Ks),$("NNNN",function Jh(c,d){return d.erasNameRegex(c)}),$("NNNNN",function Zh(c,d){return d.erasNarrowRegex(c)}),Pe(["N","NN","NNN","NNNN","NNNNN"],function(c,d,h,g){var _=h._locale.erasParse(c,g,h._strict);_?le(h).era=_:le(h).invalidEra=c}),$("y",vr),$("yy",vr),$("yyy",vr),$("yyyy",vr),$("yo",function k(c,d){return d._eraYearOrdinalRegex||vr}),Pe(["y","yy","yyy","yyyy"],0),Pe(["yo"],function(c,d,h,g){var _;h._locale._eraYearOrdinalRegex&&(_=c.match(h._locale._eraYearOrdinalRegex)),d[0]=h._locale.eraYearOrdinalParse?h._locale.eraYearOrdinalParse(c,_):parseInt(c,10)}),q(0,["gg",2],0,function(){return this.weekYear()%100}),q(0,["GG",2],0,function(){return this.isoWeekYear()%100}),nt("gggg","weekYear"),nt("ggggg","weekYear"),nt("GGGG","isoWeekYear"),nt("GGGGG","isoWeekYear"),xt("weekYear","gg"),xt("isoWeekYear","GG"),St("weekYear",1),St("isoWeekYear",1),$("G",Oo),$("g",Oo),$("GG",Ke,Sn),$("gg",Ke,Sn),$("GGGG",du,rl),$("gggg",du,rl),$("GGGGG",Yr,As),$("ggggg",Yr,As),xo(["gggg","ggggg","GGGG","GGGGG"],function(c,d,h,g){d[g.substr(0,2)]=he(c)}),xo(["gg","GG"],function(c,d,h,g){d[g]=V.parseTwoDigitYear(c)}),q("Q",0,"Qo","quarter"),xt("quarter","Q"),St("quarter",7),$("Q",au),Pe("Q",function(c,d){d[1]=3*(he(c)-1)}),q("D",["DD",2],"Do","date"),xt("date","D"),St("date",9),$("D",Ke),$("DD",Ke,Sn),$("Do",function(c,d){return c?d._dayOfMonthOrdinalParse||d._ordinalParse:d._dayOfMonthOrdinalParseLenient}),Pe(["D","DD"],2),Pe("Do",function(c,d){d[2]=he(c.match(Ke)[0])});var Xh=wn("Date",!0);q("DDD",["DDDD",3],"DDDo","dayOfYear"),xt("dayOfYear","DDD"),St("dayOfYear",4),$("DDD",Is),$("DDDD",lu),Pe(["DDD","DDDD"],function(c,d,h){h._dayOfYear=he(c)}),q("m",["mm",2],0,"minute"),xt("minute","m"),St("minute",14),$("m",Ke),$("mm",Ke,Sn),Pe(["m","mm"],4);var rn=wn("Minutes",!1);q("s",["ss",2],0,"second"),xt("second","s"),St("second",15),$("s",Ke),$("ss",Ke,Sn),Pe(["s","ss"],5);var Mi,Er,Ei=wn("Seconds",!1);for(q("S",0,0,function(){return~~(this.millisecond()/100)}),q(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),q(0,["SSS",3],0,"millisecond"),q(0,["SSSS",4],0,function(){return 10*this.millisecond()}),q(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),q(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),q(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),q(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),q(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),xt("millisecond","ms"),St("millisecond",16),$("S",Is,au),$("SS",Is,Sn),$("SSS",Is,lu),Mi="SSSS";Mi.length<=9;Mi+="S")$(Mi,vr);function Ti(c,d){d[6]=he(1e3*("0."+c))}for(Mi="S";Mi.length<=9;Mi+="S")Pe(Mi,Ti);Er=wn("Milliseconds",!1),q("z",0,0,"zoneAbbr"),q("zz",0,0,"zoneName");var x=gr.prototype;function Ys(c){return c}x.add=Vh,x.calendar=function ny(c,d){1===arguments.length&&(arguments[0]?Zv(arguments[0])?(c=arguments[0],d=void 0):ey(arguments[0])&&(d=arguments[0],c=void 0):(c=void 0,d=void 0));var h=c||G(),g=Zi(h,this).startOf("day"),_=V.calendarFormat(this,g)||"sameElse",b=d&&(ii(d[_])?d[_].call(this,h):d[_]);return this.format(b||this.localeData().calendar(_,this,G(h)))},x.clone=function iy(){return new gr(this)},x.diff=function pl(c,d,h){var g,_,b;if(!this.isValid())return NaN;if(!(g=Zi(c,this)).isValid())return NaN;switch(_=6e4*(g.utcOffset()-this.utcOffset()),d=Ln(d)){case"year":b=gl(this,g)/12;break;case"month":b=gl(this,g);break;case"quarter":b=gl(this,g)/3;break;case"second":b=(this-g)/1e3;break;case"minute":b=(this-g)/6e4;break;case"hour":b=(this-g)/36e5;break;case"day":b=(this-g-_)/864e5;break;case"week":b=(this-g-_)/6048e5;break;default:b=this-g}return h?b:Vn(b)},x.endOf=function ft(c){var d,h;if(void 0===(c=Ln(c))||"millisecond"===c||!this.isValid())return this;switch(h=this._isUTC?Ou:Us,c){case"year":d=h(this.year()+1,0,1)-1;break;case"quarter":d=h(this.year(),this.month()-this.month()%3+3,1)-1;break;case"month":d=h(this.year(),this.month()+1,1)-1;break;case"week":d=h(this.year(),this.month(),this.date()-this.weekday()+7)-1;break;case"isoWeek":d=h(this.year(),this.month(),this.date()-(this.isoWeekday()-1)+7)-1;break;case"day":case"date":d=h(this.year(),this.month(),this.date()+1)-1;break;case"hour":d=this._d.valueOf(),d+=nn-io(d+(this._isUTC?0:this.utcOffset()*no),nn)-1;break;case"minute":d=this._d.valueOf(),d+=no-io(d,no)-1;break;case"second":d=this._d.valueOf(),d+=1e3-io(d,1e3)-1}return this._d.setTime(d),V.updateOffset(this,!0),this},x.format=function Bh(c){c||(c=this.isUtc()?V.defaultFormatUtc:V.defaultFormat);var d=Ts(this,c);return this.localeData().postformat(d)},x.from=function Wt(c,d){return this.isValid()&&(Wn(c)&&c.isValid()||G(c).isValid())?pn({to:this,from:c}).locale(this.locale()).humanize(!d):this.localeData().invalidDate()},x.fromNow=function Au(c){return this.from(G(),c)},x.to=function jh(c,d){return this.isValid()&&(Wn(c)&&c.isValid()||G(c).isValid())?pn({from:this,to:c}).locale(this.locale()).humanize(!d):this.localeData().invalidDate()},x.toNow=function $h(c){return this.to(G(),c)},x.get=function su(c){return ii(this[c=Ln(c)])?this[c]():this},x.invalidAt=function Wh(){return le(this).overflow},x.isAfter=function ry(c,d){var h=Wn(c)?c:G(c);return!(!this.isValid()||!h.isValid())&&("millisecond"===(d=Ln(d)||"millisecond")?this.valueOf()>h.valueOf():h.valueOf()9999?Ts(h,d?"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYYYY-MM-DD[T]HH:mm:ss.SSSZ"):ii(Date.prototype.toISOString)?d?this.toDate().toISOString():new Date(this.valueOf()+60*this.utcOffset()*1e3).toISOString().replace("Z",Ts(h,"Z")):Ts(h,d?"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYY-MM-DD[T]HH:mm:ss.SSSZ")},x.inspect=function Sr(){if(!this.isValid())return"moment.invalid(/* "+this._i+" */)";var h,g,c="moment",d="";return this.isLocal()||(c=0===this.utcOffset()?"moment.utc":"moment.parseZone",d="Z"),h="["+c+'("]',g=0<=this.year()&&this.year()<=9999?"YYYY":"YYYYYY",this.format(h+g+"-MM-DD[T]HH:mm:ss.SSS"+d+'[")]')},typeof Symbol<"u"&&null!=Symbol.for&&(x[Symbol.for("nodejs.util.inspect.custom")]=function(){return"Moment<"+this.format()+">"}),x.toJSON=function vl(){return this.isValid()?this.toISOString():null},x.toString=function cy(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},x.unix=function fy(){return Math.floor(this.valueOf()/1e3)},x.valueOf=function Uh(){return this._d.valueOf()-6e4*(this._offset||0)},x.creationData=function Ws(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}},x.eraName=function yl(){var c,d,h,g=this.localeData().eras();for(c=0,d=g.length;cthis.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()},x.isLocal=function Gt(){return!!this.isValid()&&!this._isUTC},x.isUtcOffset=function Fh(){return!!this.isValid()&&this._isUTC},x.isUtc=tn,x.isUTC=tn,x.zoneAbbr=function ep(){return this._isUTC?"UTC":""},x.zoneName=function Pu(){return this._isUTC?"Coordinated Universal Time":""},x.dates=Zt("dates accessor is deprecated. Use date instead.",Xh),x.months=Zt("months accessor is deprecated. Use month instead",bu),x.years=Zt("years accessor is deprecated. Use year instead",ks),x.zone=Zt("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",function Rh(c,d){return null!=c?("string"!=typeof c&&(c=-c),this.utcOffset(c,d),this):-this.utcOffset()}),x.isDSTShifted=Zt("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",function wr(){if(!qt(this._isDSTShifted))return this._isDSTShifted;var d,c={};return Qa(c,this),(c=hn(c))._a?(d=c._isUTC?ni(c._a):G(c._a),this._isDSTShifted=this.isValid()&&function Ut(c,d,h){var T,g=Math.min(c.length,d.length),_=Math.abs(c.length-d.length),b=0;for(T=0;T0):this._isDSTShifted=!1,this._isDSTShifted});var Ee=el.prototype;function oo(c,d,h,g){var _=qi(),b=ni().set(g,d);return _[h](b,c)}function Lu(c,d,h){if(Jt(c)&&(d=c,c=void 0),c=c||"",null!=d)return oo(c,d,h,"month");var g,_=[];for(g=0;g<12;g++)_[g]=oo(c,g,h,"month");return _}function qs(c,d,h,g){"boolean"==typeof c?(Jt(d)&&(h=d,d=void 0),d=d||""):(h=d=c,c=!1,Jt(d)&&(h=d,d=void 0),d=d||"");var T,_=qi(),b=c?_._week.dow:0,J=[];if(null!=h)return oo(d,(h+b)%7,g,"day");for(T=0;T<7;T++)J[T]=oo(d,(T+b)%7,g,"day");return J}Ee.calendar=function nu(c,d,h){var g=this._calendar[c]||this._calendar.sameElse;return ii(g)?g.call(d,h):g},Ee.longDateFormat=function uh(c){var d=this._longDateFormat[c],h=this._longDateFormat[c.toUpperCase()];return d||!h?d:(this._longDateFormat[c]=h.match(tl).map(function(g){return"MMMM"===g||"MM"===g||"DD"===g||"dddd"===g?g.slice(1):g}).join(""),this._longDateFormat[c])},Ee.invalidDate=function dh(){return this._invalidDate},Ee.ordinal=function Iv(c){return this._ordinal.replace("%d",c)},Ee.preparse=Ys,Ee.postformat=Ys,Ee.relativeTime=function kv(c,d,h,g){var _=this._relativeTime[h];return ii(_)?_(c,d,h,g):_.replace(/%d/i,c)},Ee.pastFuture=function Rv(c,d){var h=this._relativeTime[c>0?"future":"past"];return ii(h)?h(d):h.replace(/%s/i,d)},Ee.set=function Xa(c){var d,h;for(h in c)we(c,h)&&(ii(d=c[h])?this[h]=d:this["_"+h]=d);this._config=c,this._dayOfMonthOrdinalParseLenient=new RegExp((this._dayOfMonthOrdinalParse.source||this._ordinalParse.source)+"|"+/\d{1,2}/.source)},Ee.eras=function Kh(c,d){var h,g,_,b=this._eras||qi("en")._eras;for(h=0,g=b.length;h=0)return b[g]},Ee.erasConvertYear=function ku(c,d){var h=c.since<=c.until?1:-1;return void 0===d?V(c.since).year():V(c.since).year()+(d-c.offset)*h},Ee.erasAbbrRegex=function Yh(c){return we(this,"_erasAbbrRegex")||me.call(this),c?this._erasAbbrRegex:this._erasRegex},Ee.erasNameRegex=function zh(c){return we(this,"_erasNameRegex")||me.call(this),c?this._erasNameRegex:this._erasRegex},Ee.erasNarrowRegex=function qh(c){return we(this,"_erasNarrowRegex")||me.call(this),c?this._erasNarrowRegex:this._erasRegex},Ee.months=function vh(c,d){return c?dn(this._months)?this._months[c.month()]:this._months[(this._months.isFormat||sl).test(d)?"format":"standalone"][c.month()]:dn(this._months)?this._months:this._months.standalone},Ee.monthsShort=function yh(c,d){return c?dn(this._monthsShort)?this._monthsShort[c.month()]:this._monthsShort[sl.test(d)?"format":"standalone"][c.month()]:dn(this._monthsShort)?this._monthsShort:this._monthsShort.standalone},Ee.monthsParse=function vu(c,d,h){var g,_,b;if(this._monthsParseExact)return bh.call(this,c,d,h);for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),g=0;g<12;g++){if(_=ni([2e3,g]),h&&!this._longMonthsParse[g]&&(this._longMonthsParse[g]=new RegExp("^"+this.months(_,"").replace(".","")+"$","i"),this._shortMonthsParse[g]=new RegExp("^"+this.monthsShort(_,"").replace(".","")+"$","i")),!h&&!this._monthsParse[g]&&(b="^"+this.months(_,"")+"|^"+this.monthsShort(_,""),this._monthsParse[g]=new RegExp(b.replace(".",""),"i")),h&&"MMMM"===d&&this._longMonthsParse[g].test(c))return g;if(h&&"MMM"===d&&this._shortMonthsParse[g].test(c))return g;if(!h&&this._monthsParse[g].test(c))return g}},Ee.monthsRegex=function Ch(c){return this._monthsParseExact?(we(this,"_monthsRegex")||Os.call(this),c?this._monthsStrictRegex:this._monthsRegex):(we(this,"_monthsRegex")||(this._monthsRegex=_h),this._monthsStrictRegex&&c?this._monthsStrictRegex:this._monthsRegex)},Ee.monthsShortRegex=function Dh(c){return this._monthsParseExact?(we(this,"_monthsRegex")||Os.call(this),c?this._monthsShortStrictRegex:this._monthsShortRegex):(we(this,"_monthsShortRegex")||(this._monthsShortRegex=_u),this._monthsShortStrictRegex&&c?this._monthsShortStrictRegex:this._monthsShortRegex)},Ee.week=function F(c){return br(c,this._week.dow,this._week.doy).week},Ee.firstDayOfYear=function Ae(){return this._week.doy},Ee.firstDayOfWeek=function se(){return this._week.dow},Ee.weekdays=function Bv(c,d){var h=dn(this._weekdays)?this._weekdays:this._weekdays[c&&!0!==c&&this._weekdays.isFormat.test(d)?"format":"standalone"];return!0===c?Qt(h,this._week.dow):c?h[c.day()]:h},Ee.weekdaysMin=function Eh(c){return!0===c?Qt(this._weekdaysMin,this._week.dow):c?this._weekdaysMin[c.day()]:this._weekdaysMin},Ee.weekdaysShort=function jv(c){return!0===c?Qt(this._weekdaysShort,this._week.dow):c?this._weekdaysShort[c.day()]:this._weekdaysShort},Ee.weekdaysParse=function Mh(c,d,h){var g,_,b;if(this._weekdaysParseExact)return $v.call(this,c,d,h);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),g=0;g<7;g++){if(_=ni([2e3,1]).day(g),h&&!this._fullWeekdaysParse[g]&&(this._fullWeekdaysParse[g]=new RegExp("^"+this.weekdays(_,"").replace(".","\\.?")+"$","i"),this._shortWeekdaysParse[g]=new RegExp("^"+this.weekdaysShort(_,"").replace(".","\\.?")+"$","i"),this._minWeekdaysParse[g]=new RegExp("^"+this.weekdaysMin(_,"").replace(".","\\.?")+"$","i")),this._weekdaysParse[g]||(b="^"+this.weekdays(_,"")+"|^"+this.weekdaysShort(_,"")+"|^"+this.weekdaysMin(_,""),this._weekdaysParse[g]=new RegExp(b.replace(".",""),"i")),h&&"dddd"===d&&this._fullWeekdaysParse[g].test(c))return g;if(h&&"ddd"===d&&this._shortWeekdaysParse[g].test(c))return g;if(h&&"dd"===d&&this._minWeekdaysParse[g].test(c))return g;if(!h&&this._weekdaysParse[g].test(c))return g}},Ee.weekdaysRegex=function Gv(c){return this._weekdaysParseExact?(we(this,"_weekdaysRegex")||U.call(this),c?this._weekdaysStrictRegex:this._weekdaysRegex):(we(this,"_weekdaysRegex")||(this._weekdaysRegex=yi),this._weekdaysStrictRegex&&c?this._weekdaysStrictRegex:this._weekdaysRegex)},Ee.weekdaysShortRegex=function Wv(c){return this._weekdaysParseExact?(we(this,"_weekdaysRegex")||U.call(this),c?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(we(this,"_weekdaysShortRegex")||(this._weekdaysShortRegex=Vv),this._weekdaysShortStrictRegex&&c?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)},Ee.weekdaysMinRegex=function Kv(c){return this._weekdaysParseExact?(we(this,"_weekdaysRegex")||U.call(this),c?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(we(this,"_weekdaysMinRegex")||(this._weekdaysMinRegex=Hv),this._weekdaysMinStrictRegex&&c?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)},Ee.isPM=function Su(c){return"p"===(c+"").toLowerCase().charAt(0)},Ee.meridiem=function Eu(c,d,h){return c>11?h?"pm":"PM":h?"am":"AM"},Dr("en",{eras:[{since:"0001-01-01",until:1/0,offset:1,name:"Anno Domini",narrow:"AD",abbr:"AD"},{since:"0000-12-31",until:-1/0,offset:1,name:"Before Christ",narrow:"BC",abbr:"BC"}],dayOfMonthOrdinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(c){var d=c%10;return c+(1===he(c%100/10)?"th":1===d?"st":2===d?"nd":3===d?"rd":"th")}}),V.lang=Zt("moment.lang is deprecated. Use moment.locale instead.",Dr),V.langData=Zt("moment.langData is deprecated. Use moment.localeData instead.",qi);var Yn=Math.abs;function $u(c,d,h,g){var _=pn(d,h);return c._milliseconds+=g*_._milliseconds,c._days+=g*_._days,c._months+=g*_._months,c._bubble()}function Ze(c){return c<0?Math.floor(c):Math.ceil(c)}function Uu(c){return 4800*c/146097}function wl(c){return 146097*c/4800}function Ni(c){return function(){return this.as(c)}}var Js=Ni("ms"),Zs=Ni("s"),Qs=Ni("m"),Sl=Ni("h"),Gu=Ni("d"),sp=Ni("w"),er=Ni("M"),Wo=Ni("Q"),ap=Ni("y");function Ai(c){return function(){return this.isValid()?this._data[c]:NaN}}var cp=Ai("milliseconds"),up=Ai("seconds"),gy=Ai("minutes"),my=Ai("hours"),Xs=Ai("days"),Wu=Ai("months"),Ku=Ai("years");var li=Math.round,Mr={ss:44,s:45,m:45,h:22,d:26,w:null,M:11};function so(c,d,h,g,_){return _.relativeTime(d||1,!!h,c,g)}var zu=Math.abs;function Tr(c){return(c>0)-(c<0)||+c}function zo(){if(!this.isValid())return this.localeData().invalidDate();var g,_,b,T,ue,xe,Kt,ci,c=zu(this._milliseconds)/1e3,d=zu(this._days),h=zu(this._months),J=this.asSeconds();return J?(g=Vn(c/60),_=Vn(g/60),c%=60,g%=60,b=Vn(h/12),h%=12,T=c?c.toFixed(3).replace(/\.?0+$/,""):"",ue=J<0?"-":"",xe=Tr(this._months)!==Tr(J)?"-":"",Kt=Tr(this._days)!==Tr(J)?"-":"",ci=Tr(this._milliseconds)!==Tr(J)?"-":"",ue+"P"+(b?xe+b+"Y":"")+(h?xe+h+"M":"")+(d?Kt+d+"D":"")+(_||g||c?"T":"")+(_?ci+_+"H":"")+(g?ci+g+"M":"")+(c?ci+T+"S":"")):"P0D"}var Ce=wi.prototype;return Ce.isValid=function ce(){return this._isValid},Ce.abs=function np(){var c=this._data;return this._milliseconds=Yn(this._milliseconds),this._days=Yn(this._days),this._months=Yn(this._months),c.milliseconds=Yn(c.milliseconds),c.seconds=Yn(c.seconds),c.minutes=Yn(c.minutes),c.hours=Yn(c.hours),c.months=Yn(c.months),c.years=Yn(c.years),this},Ce.add=function on(c,d){return $u(this,c,d,1)},Ce.subtract=function Xi(c,d){return $u(this,c,d,-1)},Ce.as=function rp(c){if(!this.isValid())return NaN;var d,h,g=this._milliseconds;if("month"===(c=Ln(c))||"quarter"===c||"year"===c)switch(d=this._days+g/864e5,h=this._months+Uu(d),c){case"month":return h;case"quarter":return h/3;case"year":return h/12}else switch(d=this._days+Math.round(wl(this._months)),c){case"week":return d/7+g/6048e5;case"day":return d+g/864e5;case"hour":return 24*d+g/36e5;case"minute":return 1440*d+g/6e4;case"second":return 86400*d+g/1e3;case"millisecond":return Math.floor(864e5*d)+g;default:throw new Error("Unknown unit "+c)}},Ce.asMilliseconds=Js,Ce.asSeconds=Zs,Ce.asMinutes=Qs,Ce.asHours=Sl,Ce.asDays=Gu,Ce.asWeeks=sp,Ce.asMonths=er,Ce.asQuarters=Wo,Ce.asYears=ap,Ce.valueOf=function op(){return this.isValid()?this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*he(this._months/12):NaN},Ce._bubble=function ip(){var _,b,T,J,ue,c=this._milliseconds,d=this._days,h=this._months,g=this._data;return c>=0&&d>=0&&h>=0||c<=0&&d<=0&&h<=0||(c+=864e5*Ze(wl(h)+d),d=0,h=0),g.milliseconds=c%1e3,_=Vn(c/1e3),g.seconds=_%60,b=Vn(_/60),g.minutes=b%60,T=Vn(b/60),g.hours=T%24,d+=Vn(T/24),h+=ue=Vn(Uu(d)),d-=Ze(wl(ue)),J=Vn(h/12),h%=12,g.days=d,g.months=h,g.years=J,this},Ce.clone=function lp(){return pn(this)},Ce.get=function Ko(c){return c=Ln(c),this.isValid()?this[c+"s"]():NaN},Ce.milliseconds=cp,Ce.seconds=up,Ce.minutes=gy,Ce.hours=my,Ce.days=Xs,Ce.weeks=function ea(){return Vn(this.days()/7)},Ce.months=Wu,Ce.years=Ku,Ce.humanize=function ta(c,d){if(!this.isValid())return this.localeData().invalidDate();var _,b,h=!1,g=Mr;return"object"==typeof c&&(d=c,c=!1),"boolean"==typeof c&&(h=c),"object"==typeof d&&(g=Object.assign({},Mr,d),null!=d.s&&null==d.ss&&(g.ss=d.s-1)),b=function dp(c,d,h,g){var _=pn(c).abs(),b=li(_.as("s")),T=li(_.as("m")),J=li(_.as("h")),ue=li(_.as("d")),xe=li(_.as("M")),Kt=li(_.as("w")),ci=li(_.as("y")),tr=b<=h.ss&&["s",b]||b0,tr[4]=g,so.apply(null,tr)}(this,!h,g,_=this.localeData()),h&&(b=_.pastFuture(+this,b)),_.postformat(b)},Ce.toISOString=zo,Ce.toString=zo,Ce.toJSON=zo,Ce.locale=ml,Ce.localeData=Iu,Ce.toIsoString=Zt("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",zo),Ce.lang=_l,q("X",0,0,"unix"),q("x",0,0,"valueOf"),$("x",Oo),$("X",/[+-]?\d+(\.\d{1,3})?/),Pe("X",function(c,d,h){h._d=new Date(1e3*parseFloat(c))}),Pe("x",function(c,d,h){h._d=new Date(he(c))}),V.version="2.29.4",function Ja(c){be=c}(G),V.fn=x,V.min=function Nt(){return Ji("isBefore",[].slice.call(arguments,0))},V.max=function Cr(){return Ji("isAfter",[].slice.call(arguments,0))},V.now=function(){return Date.now?Date.now():+new Date},V.utc=ni,V.unix=function tp(c){return G(1e3*c)},V.months=function Cl(c,d){return Lu(c,d,"months")},V.isDate=zi,V.locale=Dr,V.invalid=pr,V.duration=pn,V.isMoment=Wn,V.weekdays=function Hu(c,d,h){return qs(c,d,h,"weekdays")},V.parseZone=function Dl(){return G.apply(null,arguments).parseZone()},V.localeData=qi,V.isDuration=Qr,V.monthsShort=function Vu(c,d){return Lu(c,d,"monthsShort")},V.weekdaysMin=function ju(c,d,h){return qs(c,d,h,"weekdaysMin")},V.defineLocale=oi,V.updateLocale=function Kn(c,d){if(null!=d){var h,g,_=Vo;null!=$e[c]&&null!=$e[c].parentLocale?$e[c].set(Pn($e[c]._config,d)):(null!=(g=Bo(c))&&(_=g._config),d=Pn(_,d),null==g&&(d.abbr=c),(h=new el(d)).parentLocale=$e[c],$e[c]=h),Dr(c)}else null!=$e[c]&&(null!=$e[c].parentLocale?($e[c]=$e[c].parentLocale,c===Dr()&&Dr(c)):null!=$e[c]&&delete $e[c]);return $e[c]},V.locales=function zv(){return Es($e)},V.weekdaysShort=function Bu(c,d,h){return qs(c,d,h,"weekdaysShort")},V.normalizeUnits=Ln,V.relativeTimeRounding=function ao(c){return void 0===c?li:"function"==typeof c&&(li=c,!0)},V.relativeTimeThreshold=function El(c,d){return void 0!==Mr[c]&&(void 0===d?Mr[c]:(Mr[c]=d,"s"===c&&(Mr.ss=d-1),!0))},V.calendarFormat=function ty(c,d){var h=c.diff(d,"days",!0);return h<-6?"sameElse":h<-1?"lastWeek":h<0?"lastDay":h<1?"sameDay":h<2?"nextDay":h<7?"nextWeek":"sameElse"},V.prototype=x,V.HTML5_FMT={DATETIME_LOCAL:"YYYY-MM-DDTHH:mm",DATETIME_LOCAL_SECONDS:"YYYY-MM-DDTHH:mm:ss",DATETIME_LOCAL_MS:"YYYY-MM-DDTHH:mm:ss.SSS",DATE:"YYYY-MM-DD",TIME:"HH:mm",TIME_SECONDS:"HH:mm:ss",TIME_MS:"HH:mm:ss.SSS",WEEK:"GGGG-[W]WW",MONTH:"YYYY-MM"},V}()}},hr=>{hr(hr.s=631)}]); \ No newline at end of file diff --git a/src/KafkaFlow.Admin.Dashboard/ClientApp/dist/polyfills.js b/src/KafkaFlow.Admin.Dashboard/ClientApp/dist/polyfills.js index 1536f9c60..6263d3963 100644 --- a/src/KafkaFlow.Admin.Dashboard/ClientApp/dist/polyfills.js +++ b/src/KafkaFlow.Admin.Dashboard/ClientApp/dist/polyfills.js @@ -1,197 +1 @@ -"use strict";(self.webpackChunkdashboard=self.webpackChunkdashboard||[]).push([[429],{565:(rr,Ar,ds)=>{Error; -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -const jo=function(r,...e){if(jo.translate){const n=jo.translate(r,e);r=n[0],e=n[1]}let t=Kl(r[0],r.raw[0]);for(let n=1;ntypeof globalThis<"u"&&globalThis||typeof global<"u"&&global||typeof window<"u"&&window||typeof self<"u"&&typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope&&self)().$localize=jo,ds(609)},609:function(rr,Ar,ds){var Fe,at,bt=this&&this.__spreadArray||function(St,Ot,yn){if(yn||2===arguments.length)for(var Dt,It=0,ue=Ot.length;It",this._properties=v&&v.properties||{},this._zoneDelegate=new q(this,this._parent&&this._parent._zoneDelegate,v)}return k.assertZonePatched=function(){if(p.Promise!==re.ZoneAwarePromise)throw new Error("Zone.js has detected that ZoneAwarePromise `(window|global).Promise` has been overwritten.\nMost likely cause is that a Promise polyfill has been loaded after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. If you must load one, do so before loading zone.js.)")},Object.defineProperty(k,"root",{get:function(){for(var y=k.current;y.parent;)y=y.parent;return y},enumerable:!1,configurable:!0}),Object.defineProperty(k,"current",{get:function(){return Me.zone},enumerable:!1,configurable:!0}),Object.defineProperty(k,"currentTask",{get:function(){return Ze},enumerable:!1,configurable:!0}),k.__load_patch=function(y,v,S){if(void 0===S&&(S=!1),re.hasOwnProperty(y)){if(!S&&b)throw Error("Already loaded patch: "+y)}else if(!p["__Zone_disable_"+y]){var K="Zone:"+y;m(K),re[y]=v(p,k,Ie),d(K,K)}},Object.defineProperty(k.prototype,"parent",{get:function(){return this._parent},enumerable:!1,configurable:!0}),Object.defineProperty(k.prototype,"name",{get:function(){return this._name},enumerable:!1,configurable:!0}),k.prototype.get=function(y){var v=this.getZoneWith(y);if(v)return v._properties[y]},k.prototype.getZoneWith=function(y){for(var v=this;v;){if(v._properties.hasOwnProperty(y))return v;v=v._parent}return null},k.prototype.fork=function(y){if(!y)throw new Error("ZoneSpec required!");return this._zoneDelegate.fork(this,y)},k.prototype.wrap=function(y,v){if("function"!=typeof y)throw new Error("Expecting function got: "+y);var S=this._zoneDelegate.intercept(this,y,v),K=this;return function(){return K.runGuarded(S,this,arguments,v)}},k.prototype.run=function(y,v,S,K){Me={parent:Me,zone:this};try{return this._zoneDelegate.invoke(this,y,v,S,K)}finally{Me=Me.parent}},k.prototype.runGuarded=function(y,v,S,K){void 0===v&&(v=null),Me={parent:Me,zone:this};try{try{return this._zoneDelegate.invoke(this,y,v,S,K)}catch(be){if(this._zoneDelegate.handleError(this,be))throw be}}finally{Me=Me.parent}},k.prototype.runTask=function(y,v,S){if(y.zone!=this)throw new Error("A task can only be run in the zone of creation! (Creation: "+(y.zone||H).name+"; Execution: "+this.name+")");if(y.state!==Ae||y.type!==de&&y.type!==ne){var K=y.state!=Ce;K&&y._transitionTo(Ce,Te),y.runCount++;var be=Ze;Ze=y,Me={parent:Me,zone:this};try{y.type==ne&&y.data&&!y.data.isPeriodic&&(y.cancelFn=void 0);try{return this._zoneDelegate.invokeTask(this,y,v,S)}catch(ut){if(this._zoneDelegate.handleError(this,ut))throw ut}}finally{y.state!==Ae&&y.state!==Ne&&(y.type==de||y.data&&y.data.isPeriodic?K&&y._transitionTo(Te,Ce):(y.runCount=0,this._updateTaskCount(y,-1),K&&y._transitionTo(Ae,Ce,Ae))),Me=Me.parent,Ze=be}}},k.prototype.scheduleTask=function(y){if(y.zone&&y.zone!==this)for(var v=this;v;){if(v===y.zone)throw Error("can not reschedule task to ".concat(this.name," which is descendants of the original zone ").concat(y.zone.name));v=v.parent}y._transitionTo(_e,Ae);var S=[];y._zoneDelegates=S,y._zone=this;try{y=this._zoneDelegate.scheduleTask(this,y)}catch(K){throw y._transitionTo(Ne,_e,Ae),this._zoneDelegate.handleError(this,K),K}return y._zoneDelegates===S&&this._updateTaskCount(y,1),y.state==_e&&y._transitionTo(Te,_e),y},k.prototype.scheduleMicroTask=function(y,v,S,K){return this.scheduleTask(new C(he,y,v,S,K,void 0))},k.prototype.scheduleMacroTask=function(y,v,S,K,be){return this.scheduleTask(new C(ne,y,v,S,K,be))},k.prototype.scheduleEventTask=function(y,v,S,K,be){return this.scheduleTask(new C(de,y,v,S,K,be))},k.prototype.cancelTask=function(y){if(y.zone!=this)throw new Error("A task can only be cancelled in the zone of creation! (Creation: "+(y.zone||H).name+"; Execution: "+this.name+")");y._transitionTo(X,Te,Ce);try{this._zoneDelegate.cancelTask(this,y)}catch(v){throw y._transitionTo(Ne,X),this._zoneDelegate.handleError(this,v),v}return this._updateTaskCount(y,-1),y._transitionTo(Ae,X),y.runCount=0,y},k.prototype._updateTaskCount=function(y,v){var S=y._zoneDelegates;-1==v&&(y._zoneDelegates=null);for(var K=0;K0,macroTask:S.macroTask>0,eventTask:S.eventTask>0,change:y})},k}(),C=function(){function k(y,v,S,K,be,ut){if(this._zone=null,this.runCount=0,this._zoneDelegates=null,this._state="notScheduled",this.type=y,this.source=v,this.data=K,this.scheduleFn=be,this.cancelFn=ut,!S)throw new Error("callback is not defined");this.callback=S;var I=this;this.invoke=y===de&&K&&K.useG?k.invokeTask:function(){return k.invokeTask.call(p,I,this,arguments)}}return k.invokeTask=function(y,v,S){y||(y=this),Pe++;try{return y.runCount++,y.zone.runTask(y,v,S)}finally{1==Pe&&me(),Pe--}},Object.defineProperty(k.prototype,"zone",{get:function(){return this._zone},enumerable:!1,configurable:!0}),Object.defineProperty(k.prototype,"state",{get:function(){return this._state},enumerable:!1,configurable:!0}),k.prototype.cancelScheduleRequest=function(){this._transitionTo(Ae,_e)},k.prototype._transitionTo=function(y,v,S){if(this._state!==v&&this._state!==S)throw new Error("".concat(this.type," '").concat(this.source,"': can not transition to '").concat(y,"', expecting state '").concat(v,"'").concat(S?" or '"+S+"'":"",", was '").concat(this._state,"'."));this._state=y,y==Ae&&(this._zoneDelegates=null)},k.prototype.toString=function(){return this.data&&typeof this.data.handleId<"u"?this.data.handleId.toString():Object.prototype.toString.call(this)},k.prototype.toJSON=function(){return{type:this.type,state:this.state,source:this.source,zone:this.zone.name,runCount:this.runCount}},k}(),W=x("setTimeout"),U=x("Promise"),te=x("then"),Q=[],fe=!1;function pe(k){if(Re||p[U]&&(Re=p[U].resolve(0)),Re){var y=Re[te];y||(y=Re.then),y.call(Re,k)}else p[W](k,0)}function Le(k){0===Pe&&0===Q.length&&pe(me),k&&Q.push(k)}function me(){if(!fe){for(fe=!0;Q.length;){var k=Q;Q=[];for(var y=0;y=0;m--)"function"==typeof p[m]&&(p[m]=br(p[m],f+"_"+m));return p}function fs(p){return!p||!1!==p.writable&&!("function"==typeof p.get&&typeof p.set>"u")}var ms=typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope,ir=!("nw"in Ve)&&typeof Ve.process<"u"&&"[object process]"==={}.toString.call(Ve.process),Sn=!ir&&!ms&&!(!st||!Zt.HTMLElement),hi=typeof Ve.process<"u"&&"[object process]"==={}.toString.call(Ve.process)&&!ms&&!(!st||!Zt.HTMLElement),or={},gs=function(p){if(p=p||Ve.event){var f=or[p.type];f||(f=or[p.type]=ee("ON_PROPERTY"+p.type));var T,m=this||p.target||Ve,d=m[f];return Sn&&m===Zt&&"error"===p.type?!0===(T=d&&d.call(this,p.message,p.filename,p.lineno,p.colno,p.error))&&p.preventDefault():null!=(T=d&&d.apply(this,arguments))&&!T&&p.preventDefault(),T}};function vs(p,f,m){var d=St(p,f);if(!d&&m&&St(m,f)&&(d={enumerable:!0,configurable:!0}),d&&d.configurable){var x=ee("on"+f+"patched");if(!p.hasOwnProperty(x)||!p[x]){delete d.writable,delete d.value;var b=d.get,P=d.set,O=f.slice(2),q=or[O];q||(q=or[O]=ee("ON_PROPERTY"+O)),d.set=function(C){var W=this;!W&&p===Ve&&(W=Ve),W&&("function"==typeof W[q]&&W.removeEventListener(O,gs),P&&P.call(W,null),W[q]=C,"function"==typeof C&&W.addEventListener(O,gs,!1))},d.get=function(){var C=this;if(!C&&p===Ve&&(C=Ve),!C)return null;var W=C[q];if(W)return W;if(b){var U=b.call(this);if(U)return d.set.call(this,U),"function"==typeof C.removeAttribute&&C.removeAttribute(f),U}return null},Ot(p,f,d),p[x]=!0}}}function Es(p,f,m){if(f)for(var d=0;d=0&&"function"==typeof P[O.cbIdx]?Ir(O.name,P[O.cbIdx],O,T):x.apply(b,P)}})}function wt(p,f){p[ee("OriginalDelegate")]=f}var Dr=!1,Nr=!1;function di(){if(Dr)return Nr;Dr=!0;try{var p=Zt.navigator.userAgent;(-1!==p.indexOf("MSIE ")||-1!==p.indexOf("Trident/")||-1!==p.indexOf("Edge/"))&&(Nr=!0)}catch{}return Nr} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */Zone.__load_patch("ZoneAwarePromise",function(p,f,m){var d=Object.getOwnPropertyDescriptor,T=Object.defineProperty;var b=m.symbol,P=[],O=!0===p[b("DISABLE_WRAPPING_UNCAUGHT_PROMISE_REJECTION")],q=b("Promise"),C=b("then");m.onUnhandledError=function(I){if(m.showUncaughtError()){var B=I&&I.rejection;B?console.error("Unhandled Promise rejection:",B instanceof Error?B.message:B,"; Zone:",I.zone.name,"; Task:",I.task&&I.task.source,"; Value:",B,B instanceof Error?B.stack:void 0):console.error(I)}},m.microtaskDrainDone=function(){for(var I=function(){var B=P.shift();try{B.zone.runGuarded(function(){throw B.throwOriginal?B.rejection:B})}catch(L){!function te(I){m.onUnhandledError(I);try{var B=f[U];"function"==typeof B&&B.call(this,I)}catch{}}(L)}};P.length;)I()};var U=b("unhandledPromiseRejectionHandler");function Q(I){return I&&I.then}function fe(I){return I}function Re(I){return v.reject(I)}var pe=b("state"),Le=b("value"),me=b("finally"),H=b("parentPromiseValue"),Ae=b("parentPromiseState"),Te=null,X=!1;function he(I,B){return function(L){try{Ie(I,B,L)}catch(A){Ie(I,!1,A)}}}var ne=function(){var I=!1;return function(L){return function(){I||(I=!0,L.apply(null,arguments))}}},re=b("currentTaskTrace");function Ie(I,B,L){var A=ne();if(I===L)throw new TypeError("Promise resolved with itself");if(I[pe]===Te){var R=null;try{("object"==typeof L||"function"==typeof L)&&(R=L&&L.then)}catch(le){return A(function(){Ie(I,!1,le)})(),I}if(B!==X&&L instanceof v&&L.hasOwnProperty(pe)&&L.hasOwnProperty(Le)&&L[pe]!==Te)Ze(L),Ie(I,L[pe],L[Le]);else if(B!==X&&"function"==typeof R)try{R.call(L,A(he(I,B)),A(he(I,!1)))}catch(le){A(function(){Ie(I,!1,le)})()}else{I[pe]=B;var se=I[Le];if(I[Le]=L,I[me]===me&&true===B&&(I[pe]=I[Ae],I[Le]=I[H]),B===X&&L instanceof Error){var Y=f.currentTask&&f.currentTask.data&&f.currentTask.data.__creationTrace__;Y&&T(L,re,{configurable:!0,enumerable:!1,writable:!0,value:Y})}for(var ie=0;ie2}).map(function(f){return f.substring(2)})}function xs(p,f){if((!ir||hi)&&!Zone[p.symbol("patchEvents")]){var m=f.__Zone_ignore_on_properties,d=[];if(Sn){var T=window;d=d.concat(["Document","SVGElement","Element","HTMLElement","HTMLBodyElement","HTMLMediaElement","HTMLFrameSetElement","HTMLFrameElement","HTMLIFrameElement","HTMLMarqueeElement","Worker"]);var x=function wn(){try{var p=Zt.navigator.userAgent;if(-1!==p.indexOf("MSIE ")||-1!==p.indexOf("Trident/"))return!0}catch{}return!1}()?[{target:T,ignoreProperties:["error"]}]:[];Ts(T,ur(T),m&&m.concat(x),yn(T))}d=d.concat(["XMLHttpRequest","XMLHttpRequestEventTarget","IDBIndex","IDBRequest","IDBOpenDBRequest","IDBDatabase","IDBTransaction","IDBCursor","WebSocket"]);for(var b=0;b"u"?delete m.configurable:m.configurable=d;try{return qn(p,f,m)}catch(P){var T=!1;if(("createdCallback"===f||"attachedCallback"===f||"detachedCallback"===f||"attributeChangedCallback"===f)&&(T=!0),!T)throw P;var x=null;try{x=JSON.stringify(m)}catch{x=m.toString()}console.log("Attempting to configure '".concat(f,"' with descriptor '").concat(x,"' on object '").concat(p,"' and got error, giving up: ").concat(P))}}} -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -function vi(p,f){var m=p.getGlobalObjects();if((!m.isNode||m.isMix)&&!function Ei(p,f){var m=p.getGlobalObjects();if((m.isBrowser||m.isMix)&&!p.ObjectGetOwnPropertyDescriptor(HTMLElement.prototype,"onclick")&&typeof Element<"u"){var x=p.ObjectGetOwnPropertyDescriptor(Element.prototype,"onclick");if(x&&!x.configurable)return!1;if(x){p.ObjectDefineProperty(Element.prototype,"onclick",{enumerable:!0,configurable:!0,get:function(){return!0}});var P=!!document.createElement("div").onclick;return p.ObjectDefineProperty(Element.prototype,"onclick",x),P}}var O=f.XMLHttpRequest;if(!O)return!1;var q="onreadystatechange",C=O.prototype,W=p.ObjectGetOwnPropertyDescriptor(C,q);if(W)return p.ObjectDefineProperty(C,q,{enumerable:!0,configurable:!0,get:function(){return!0}}),P=!!(U=new O).onreadystatechange,p.ObjectDefineProperty(C,q,W||{}),P;var te=p.symbol("fake");p.ObjectDefineProperty(C,q,{enumerable:!0,configurable:!0,get:function(){return this[te]},set:function(pe){this[te]=pe}});var U,Q=function(){};return(U=new O).onreadystatechange=Q,P=U[te]===Q,U.onreadystatechange=null,P}(p,f)){var x=typeof WebSocket<"u";(function Si(p){for(var f=p.symbol("unbound"),m=function(T){var x=bs[T],b="on"+x;self.addEventListener(x,function(P){var q,C,O=P.target;for(C=O?O.constructor.name+"."+b:"unknown."+b;O;)O[b]&&!O[b][f]&&((q=p.wrapWithCurrentZone(O[b],C))[f]=O[b],O[b]=q),O=O.parentElement},!0)},d=0;d1?new x(O,q):new x(O),te=p.ObjectGetOwnPropertyDescriptor(C,"onmessage");return te&&!1===te.configurable?(W=p.ObjectCreate(C),U=C,[d,T,"send","close"].forEach(function(Q){W[Q]=function(){var fe=p.ArraySlice.call(arguments);if(Q===d||Q===T){var Re=fe.length>0?fe[0]:void 0;if(Re){var pe=Zone.__symbol__("ON_PROPERTY"+Re);C[pe]=W[pe]}}return C[Q].apply(C,fe)}})):W=C,p.patchOnProperties(W,["close","error","message","open"],U),W};var b=f.WebSocket;for(var P in x)b[P]=x[P]}(p,f),Zone[p.symbol("patchEvents")]=!0}}Zone.__load_patch("util",function(p,f,m){var d=ur(p);m.patchOnProperties=Es,m.patchMethod=mt,m.bindArguments=Ee,m.patchMacroTask=Wo;var T=f.__symbol__("BLACK_LISTED_EVENTS"),x=f.__symbol__("UNPATCHED_EVENTS");p[x]&&(p[T]=p[x]),p[T]&&(f[T]=f[x]=p[T]),m.patchEventPrototype=fi,m.patchEventTarget=_s,m.isIEOrEdge=di,m.ObjectDefineProperty=Ot,m.ObjectGetOwnPropertyDescriptor=St,m.ObjectCreate=It,m.ArraySlice=ue,m.patchClass=$n,m.wrapWithCurrentZone=br,m.filterProperties=ws,m.attachOriginToPatched=wt,m._redefineProperty=Object.defineProperty,m.patchCallbacks=mi,m.getGlobalObjects=function(){return{globalSources:Pr,zoneSymbolEventNames:gt,eventNames:d,isBrowser:Sn,isMix:hi,isNode:ir,TRUE_STR:Qe,FALSE_STR:dt,ZONE_SYMBOL_PREFIX:On,ADD_EVENT_LISTENER_STR:Dt,REMOVE_EVENT_LISTENER_STR:_n}}});var p,f,bs=bt(bt(bt(bt(bt(bt(bt(bt([],["abort","animationcancel","animationend","animationiteration","auxclick","beforeinput","blur","cancel","canplay","canplaythrough","change","compositionstart","compositionupdate","compositionend","cuechange","click","close","contextmenu","curechange","dblclick","drag","dragend","dragenter","dragexit","dragleave","dragover","drop","durationchange","emptied","ended","error","focus","focusin","focusout","gotpointercapture","input","invalid","keydown","keypress","keyup","load","loadstart","loadeddata","loadedmetadata","lostpointercapture","mousedown","mouseenter","mouseleave","mousemove","mouseout","mouseover","mouseup","mousewheel","orientationchange","pause","play","playing","pointercancel","pointerdown","pointerenter","pointerleave","pointerlockchange","mozpointerlockchange","webkitpointerlockerchange","pointerlockerror","mozpointerlockerror","webkitpointerlockerror","pointermove","pointout","pointerover","pointerup","progress","ratechange","reset","resize","scroll","seeked","seeking","select","selectionchange","selectstart","show","sort","stalled","submit","suspend","timeupdate","volumechange","touchcancel","touchmove","touchstart","touchend","transitioncancel","transitionend","waiting","wheel"],!0),["webglcontextrestored","webglcontextlost","webglcontextcreationerror"],!0),["autocomplete","autocompleteerror"],!0),["toggle"],!0),["afterscriptexecute","beforescriptexecute","DOMContentLoaded","freeze","fullscreenchange","mozfullscreenchange","webkitfullscreenchange","msfullscreenchange","fullscreenerror","mozfullscreenerror","webkitfullscreenerror","msfullscreenerror","readystatechange","visibilitychange","resume"],!0),["absolutedeviceorientation","afterinput","afterprint","appinstalled","beforeinstallprompt","beforeprint","beforeunload","devicelight","devicemotion","deviceorientation","deviceorientationabsolute","deviceproximity","hashchange","languagechange","message","mozbeforepaint","offline","online","paint","pageshow","pagehide","popstate","rejectionhandled","storage","unhandledrejection","unload","userproximity","vrdisplayconnected","vrdisplaydisconnected","vrdisplaypresentchange"],!0),["beforecopy","beforecut","beforepaste","copy","cut","paste","dragstart","loadend","animationstart","search","transitionrun","transitionstart","webkitanimationend","webkitanimationiteration","webkitanimationstart","webkittransitionend"],!0),["activate","afterupdate","ariarequest","beforeactivate","beforedeactivate","beforeeditfocus","beforeupdate","cellchange","controlselect","dataavailable","datasetchanged","datasetcomplete","errorupdate","filterchange","layoutcomplete","losecapture","move","moveend","movestart","propertychange","resizeend","resizestart","rowenter","rowexit","rowsdelete","rowsinserted","command","compassneedscalibration","deactivate","help","mscontentzoom","msmanipulationstatechanged","msgesturechange","msgesturedoubletap","msgestureend","msgesturehold","msgesturestart","msgesturetap","msgotpointercapture","msinertiastart","mslostpointercapture","mspointercancel","mspointerdown","mspointerenter","mspointerhover","mspointerleave","mspointermove","mspointerout","mspointerover","mspointerup","pointerout","mssitemodejumplistitemremoved","msthumbnailclick","stop","storagecommit"],!0); -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -p=typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{},f=p.__Zone_symbol_prefix||"__zone_symbol__",p[function m(d){return f+d}("legacyPatch")]=function(){var d=p.Zone;d.__load_patch("defineProperty",function(T,x,b){b._redefineProperty=We,function gi(){Vn=Zone.__symbol__,qn=Object[Vn("defineProperty")]=Object.defineProperty,Je=Object[Vn("getOwnPropertyDescriptor")]=Object.getOwnPropertyDescriptor,et=Object.create,Kt=Vn("unconfigurables"),Object.defineProperty=function(p,f,m){if(lr(p,f))throw new TypeError("Cannot assign to read only property '"+f+"' of "+p);var d=m.configurable;return"prototype"!==f&&(m=Lr(p,f,m)),Cs(p,f,m,d)},Object.defineProperties=function(p,f){Object.keys(f).forEach(function(b){Object.defineProperty(p,b,f[b])});for(var m=0,d=Object.getOwnPropertySymbols(f);m0){var ge=ne.invoke;ne.invoke=function(){for(var k=re[f.__symbol__("loadfalse")],y=0;y{rr(rr.s=565)}]); \ No newline at end of file +"use strict";(self.webpackChunkdashboard=self.webpackChunkdashboard||[]).push([[429],{565:(rr,Ar,ds)=>{Error;const jo=function(r,...e){if(jo.translate){const n=jo.translate(r,e);r=n[0],e=n[1]}let t=Xl(r[0],r.raw[0]);for(let n=1;ntypeof globalThis<"u"&&globalThis||typeof global<"u"&&global||typeof window<"u"&&window||typeof self<"u"&&typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope&&self)().$localize=jo,ds(609)},609:function(rr,Ar,ds){var Fe,at,bt=this&&this.__spreadArray||function(wt,Ot,_n){if(_n||2===arguments.length)for(var Dt,It=0,ue=Ot.length;It",this._properties=v&&v.properties||{},this._zoneDelegate=new q(this,this._parent&&this._parent._zoneDelegate,v)}return k.assertZonePatched=function(){if(p.Promise!==re.ZoneAwarePromise)throw new Error("Zone.js has detected that ZoneAwarePromise `(window|global).Promise` has been overwritten.\nMost likely cause is that a Promise polyfill has been loaded after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. If you must load one, do so before loading zone.js.)")},Object.defineProperty(k,"root",{get:function(){for(var y=k.current;y.parent;)y=y.parent;return y},enumerable:!1,configurable:!0}),Object.defineProperty(k,"current",{get:function(){return Me.zone},enumerable:!1,configurable:!0}),Object.defineProperty(k,"currentTask",{get:function(){return Ze},enumerable:!1,configurable:!0}),k.__load_patch=function(y,v,S){if(void 0===S&&(S=!1),re.hasOwnProperty(y)){if(!S&&b)throw Error("Already loaded patch: "+y)}else if(!p["__Zone_disable_"+y]){var K="Zone:"+y;m(K),re[y]=v(p,k,Ie),d(K,K)}},Object.defineProperty(k.prototype,"parent",{get:function(){return this._parent},enumerable:!1,configurable:!0}),Object.defineProperty(k.prototype,"name",{get:function(){return this._name},enumerable:!1,configurable:!0}),k.prototype.get=function(y){var v=this.getZoneWith(y);if(v)return v._properties[y]},k.prototype.getZoneWith=function(y){for(var v=this;v;){if(v._properties.hasOwnProperty(y))return v;v=v._parent}return null},k.prototype.fork=function(y){if(!y)throw new Error("ZoneSpec required!");return this._zoneDelegate.fork(this,y)},k.prototype.wrap=function(y,v){if("function"!=typeof y)throw new Error("Expecting function got: "+y);var S=this._zoneDelegate.intercept(this,y,v),K=this;return function(){return K.runGuarded(S,this,arguments,v)}},k.prototype.run=function(y,v,S,K){Me={parent:Me,zone:this};try{return this._zoneDelegate.invoke(this,y,v,S,K)}finally{Me=Me.parent}},k.prototype.runGuarded=function(y,v,S,K){void 0===v&&(v=null),Me={parent:Me,zone:this};try{try{return this._zoneDelegate.invoke(this,y,v,S,K)}catch(be){if(this._zoneDelegate.handleError(this,be))throw be}}finally{Me=Me.parent}},k.prototype.runTask=function(y,v,S){if(y.zone!=this)throw new Error("A task can only be run in the zone of creation! (Creation: "+(y.zone||H).name+"; Execution: "+this.name+")");if(y.state!==Ae||y.type!==de&&y.type!==ne){var K=y.state!=Ce;K&&y._transitionTo(Ce,Te),y.runCount++;var be=Ze;Ze=y,Me={parent:Me,zone:this};try{y.type==ne&&y.data&&!y.data.isPeriodic&&(y.cancelFn=void 0);try{return this._zoneDelegate.invokeTask(this,y,v,S)}catch(ut){if(this._zoneDelegate.handleError(this,ut))throw ut}}finally{y.state!==Ae&&y.state!==Ne&&(y.type==de||y.data&&y.data.isPeriodic?K&&y._transitionTo(Te,Ce):(y.runCount=0,this._updateTaskCount(y,-1),K&&y._transitionTo(Ae,Ce,Ae))),Me=Me.parent,Ze=be}}},k.prototype.scheduleTask=function(y){if(y.zone&&y.zone!==this)for(var v=this;v;){if(v===y.zone)throw Error("can not reschedule task to ".concat(this.name," which is descendants of the original zone ").concat(y.zone.name));v=v.parent}y._transitionTo(_e,Ae);var S=[];y._zoneDelegates=S,y._zone=this;try{y=this._zoneDelegate.scheduleTask(this,y)}catch(K){throw y._transitionTo(Ne,_e,Ae),this._zoneDelegate.handleError(this,K),K}return y._zoneDelegates===S&&this._updateTaskCount(y,1),y.state==_e&&y._transitionTo(Te,_e),y},k.prototype.scheduleMicroTask=function(y,v,S,K){return this.scheduleTask(new C(he,y,v,S,K,void 0))},k.prototype.scheduleMacroTask=function(y,v,S,K,be){return this.scheduleTask(new C(ne,y,v,S,K,be))},k.prototype.scheduleEventTask=function(y,v,S,K,be){return this.scheduleTask(new C(de,y,v,S,K,be))},k.prototype.cancelTask=function(y){if(y.zone!=this)throw new Error("A task can only be cancelled in the zone of creation! (Creation: "+(y.zone||H).name+"; Execution: "+this.name+")");y._transitionTo(X,Te,Ce);try{this._zoneDelegate.cancelTask(this,y)}catch(v){throw y._transitionTo(Ne,X),this._zoneDelegate.handleError(this,v),v}return this._updateTaskCount(y,-1),y._transitionTo(Ae,X),y.runCount=0,y},k.prototype._updateTaskCount=function(y,v){var S=y._zoneDelegates;-1==v&&(y._zoneDelegates=null);for(var K=0;K0,macroTask:S.macroTask>0,eventTask:S.eventTask>0,change:y})},k}(),C=function(){function k(y,v,S,K,be,ut){if(this._zone=null,this.runCount=0,this._zoneDelegates=null,this._state="notScheduled",this.type=y,this.source=v,this.data=K,this.scheduleFn=be,this.cancelFn=ut,!S)throw new Error("callback is not defined");this.callback=S;var I=this;this.invoke=y===de&&K&&K.useG?k.invokeTask:function(){return k.invokeTask.call(p,I,this,arguments)}}return k.invokeTask=function(y,v,S){y||(y=this),Pe++;try{return y.runCount++,y.zone.runTask(y,v,S)}finally{1==Pe&&me(),Pe--}},Object.defineProperty(k.prototype,"zone",{get:function(){return this._zone},enumerable:!1,configurable:!0}),Object.defineProperty(k.prototype,"state",{get:function(){return this._state},enumerable:!1,configurable:!0}),k.prototype.cancelScheduleRequest=function(){this._transitionTo(Ae,_e)},k.prototype._transitionTo=function(y,v,S){if(this._state!==v&&this._state!==S)throw new Error("".concat(this.type," '").concat(this.source,"': can not transition to '").concat(y,"', expecting state '").concat(v,"'").concat(S?" or '"+S+"'":"",", was '").concat(this._state,"'."));this._state=y,y==Ae&&(this._zoneDelegates=null)},k.prototype.toString=function(){return this.data&&typeof this.data.handleId<"u"?this.data.handleId.toString():Object.prototype.toString.call(this)},k.prototype.toJSON=function(){return{type:this.type,state:this.state,source:this.source,zone:this.zone.name,runCount:this.runCount}},k}(),W=x("setTimeout"),U=x("Promise"),te=x("then"),Q=[],fe=!1;function pe(k){if(Re||p[U]&&(Re=p[U].resolve(0)),Re){var y=Re[te];y||(y=Re.then),y.call(Re,k)}else p[W](k,0)}function Le(k){0===Pe&&0===Q.length&&pe(me),k&&Q.push(k)}function me(){if(!fe){for(fe=!0;Q.length;){var k=Q;Q=[];for(var y=0;y=0;m--)"function"==typeof p[m]&&(p[m]=br(p[m],f+"_"+m));return p}function fs(p){return!p||!1!==p.writable&&!("function"==typeof p.get&&typeof p.set>"u")}var ms=typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope,ir=!("nw"in Ve)&&typeof Ve.process<"u"&&"[object process]"==={}.toString.call(Ve.process),wn=!ir&&!ms&&!(!st||!Kt.HTMLElement),hi=typeof Ve.process<"u"&&"[object process]"==={}.toString.call(Ve.process)&&!ms&&!(!st||!Kt.HTMLElement),or={},gs=function(p){if(p=p||Ve.event){var f=or[p.type];f||(f=or[p.type]=ee("ON_PROPERTY"+p.type));var T,m=this||p.target||Ve,d=m[f];return wn&&m===Kt&&"error"===p.type?!0===(T=d&&d.call(this,p.message,p.filename,p.lineno,p.colno,p.error))&&p.preventDefault():null!=(T=d&&d.apply(this,arguments))&&!T&&p.preventDefault(),T}};function vs(p,f,m){var d=wt(p,f);if(!d&&m&&wt(m,f)&&(d={enumerable:!0,configurable:!0}),d&&d.configurable){var x=ee("on"+f+"patched");if(!p.hasOwnProperty(x)||!p[x]){delete d.writable,delete d.value;var b=d.get,P=d.set,O=f.slice(2),q=or[O];q||(q=or[O]=ee("ON_PROPERTY"+O)),d.set=function(C){var W=this;!W&&p===Ve&&(W=Ve),W&&("function"==typeof W[q]&&W.removeEventListener(O,gs),P&&P.call(W,null),W[q]=C,"function"==typeof C&&W.addEventListener(O,gs,!1))},d.get=function(){var C=this;if(!C&&p===Ve&&(C=Ve),!C)return null;var W=C[q];if(W)return W;if(b){var U=b.call(this);if(U)return d.set.call(this,U),"function"==typeof C.removeAttribute&&C.removeAttribute(f),U}return null},Ot(p,f,d),p[x]=!0}}}function Es(p,f,m){if(f)for(var d=0;d=0&&"function"==typeof P[O.cbIdx]?Ir(O.name,P[O.cbIdx],O,T):x.apply(b,P)}})}function Tt(p,f){p[ee("OriginalDelegate")]=f}var Dr=!1,Nr=!1;function di(){if(Dr)return Nr;Dr=!0;try{var p=Kt.navigator.userAgent;(-1!==p.indexOf("MSIE ")||-1!==p.indexOf("Trident/")||-1!==p.indexOf("Edge/"))&&(Nr=!0)}catch{}return Nr}Zone.__load_patch("ZoneAwarePromise",function(p,f,m){var d=Object.getOwnPropertyDescriptor,T=Object.defineProperty;var b=m.symbol,P=[],O=!0===p[b("DISABLE_WRAPPING_UNCAUGHT_PROMISE_REJECTION")],q=b("Promise"),C=b("then");m.onUnhandledError=function(I){if(m.showUncaughtError()){var B=I&&I.rejection;B?console.error("Unhandled Promise rejection:",B instanceof Error?B.message:B,"; Zone:",I.zone.name,"; Task:",I.task&&I.task.source,"; Value:",B,B instanceof Error?B.stack:void 0):console.error(I)}},m.microtaskDrainDone=function(){for(var I=function(){var B=P.shift();try{B.zone.runGuarded(function(){throw B.throwOriginal?B.rejection:B})}catch(L){!function te(I){m.onUnhandledError(I);try{var B=f[U];"function"==typeof B&&B.call(this,I)}catch{}}(L)}};P.length;)I()};var U=b("unhandledPromiseRejectionHandler");function Q(I){return I&&I.then}function fe(I){return I}function Re(I){return v.reject(I)}var pe=b("state"),Le=b("value"),me=b("finally"),H=b("parentPromiseValue"),Ae=b("parentPromiseState"),Te=null,X=!1;function he(I,B){return function(L){try{Ie(I,B,L)}catch(A){Ie(I,!1,A)}}}var ne=function(){var I=!1;return function(L){return function(){I||(I=!0,L.apply(null,arguments))}}},re=b("currentTaskTrace");function Ie(I,B,L){var A=ne();if(I===L)throw new TypeError("Promise resolved with itself");if(I[pe]===Te){var R=null;try{("object"==typeof L||"function"==typeof L)&&(R=L&&L.then)}catch(le){return A(function(){Ie(I,!1,le)})(),I}if(B!==X&&L instanceof v&&L.hasOwnProperty(pe)&&L.hasOwnProperty(Le)&&L[pe]!==Te)Ze(L),Ie(I,L[pe],L[Le]);else if(B!==X&&"function"==typeof R)try{R.call(L,A(he(I,B)),A(he(I,!1)))}catch(le){A(function(){Ie(I,!1,le)})()}else{I[pe]=B;var se=I[Le];if(I[Le]=L,I[me]===me&&true===B&&(I[pe]=I[Ae],I[Le]=I[H]),B===X&&L instanceof Error){var Y=f.currentTask&&f.currentTask.data&&f.currentTask.data.__creationTrace__;Y&&T(L,re,{configurable:!0,enumerable:!1,writable:!0,value:Y})}for(var ie=0;ie2}).map(function(f){return f.substring(2)})}function xs(p,f){if((!ir||hi)&&!Zone[p.symbol("patchEvents")]){var m=f.__Zone_ignore_on_properties,d=[];if(wn){var T=window;d=d.concat(["Document","SVGElement","Element","HTMLElement","HTMLBodyElement","HTMLMediaElement","HTMLFrameSetElement","HTMLFrameElement","HTMLIFrameElement","HTMLMarqueeElement","Worker"]);var x=function Tn(){try{var p=Kt.navigator.userAgent;if(-1!==p.indexOf("MSIE ")||-1!==p.indexOf("Trident/"))return!0}catch{}return!1}()?[{target:T,ignoreProperties:["error"]}]:[];Ts(T,ur(T),m&&m.concat(x),_n(T))}d=d.concat(["XMLHttpRequest","XMLHttpRequestEventTarget","IDBIndex","IDBRequest","IDBOpenDBRequest","IDBDatabase","IDBTransaction","IDBCursor","WebSocket"]);for(var b=0;b"u"?delete m.configurable:m.configurable=d;try{return qn(p,f,m)}catch(P){var T=!1;if(("createdCallback"===f||"attachedCallback"===f||"detachedCallback"===f||"attributeChangedCallback"===f)&&(T=!0),!T)throw P;var x=null;try{x=JSON.stringify(m)}catch{x=m.toString()}console.log("Attempting to configure '".concat(f,"' with descriptor '").concat(x,"' on object '").concat(p,"' and got error, giving up: ").concat(P))}}}function vi(p,f){var m=p.getGlobalObjects();if((!m.isNode||m.isMix)&&!function Ei(p,f){var m=p.getGlobalObjects();if((m.isBrowser||m.isMix)&&!p.ObjectGetOwnPropertyDescriptor(HTMLElement.prototype,"onclick")&&typeof Element<"u"){var x=p.ObjectGetOwnPropertyDescriptor(Element.prototype,"onclick");if(x&&!x.configurable)return!1;if(x){p.ObjectDefineProperty(Element.prototype,"onclick",{enumerable:!0,configurable:!0,get:function(){return!0}});var P=!!document.createElement("div").onclick;return p.ObjectDefineProperty(Element.prototype,"onclick",x),P}}var O=f.XMLHttpRequest;if(!O)return!1;var q="onreadystatechange",C=O.prototype,W=p.ObjectGetOwnPropertyDescriptor(C,q);if(W)return p.ObjectDefineProperty(C,q,{enumerable:!0,configurable:!0,get:function(){return!0}}),P=!!(U=new O).onreadystatechange,p.ObjectDefineProperty(C,q,W||{}),P;var te=p.symbol("fake");p.ObjectDefineProperty(C,q,{enumerable:!0,configurable:!0,get:function(){return this[te]},set:function(pe){this[te]=pe}});var U,Q=function(){};return(U=new O).onreadystatechange=Q,P=U[te]===Q,U.onreadystatechange=null,P}(p,f)){var x=typeof WebSocket<"u";(function Si(p){for(var f=p.symbol("unbound"),m=function(T){var x=bs[T],b="on"+x;self.addEventListener(x,function(P){var q,C,O=P.target;for(C=O?O.constructor.name+"."+b:"unknown."+b;O;)O[b]&&!O[b][f]&&((q=p.wrapWithCurrentZone(O[b],C))[f]=O[b],O[b]=q),O=O.parentElement},!0)},d=0;d1?new x(O,q):new x(O),te=p.ObjectGetOwnPropertyDescriptor(C,"onmessage");return te&&!1===te.configurable?(W=p.ObjectCreate(C),U=C,[d,T,"send","close"].forEach(function(Q){W[Q]=function(){var fe=p.ArraySlice.call(arguments);if(Q===d||Q===T){var Re=fe.length>0?fe[0]:void 0;if(Re){var pe=Zone.__symbol__("ON_PROPERTY"+Re);C[pe]=W[pe]}}return C[Q].apply(C,fe)}})):W=C,p.patchOnProperties(W,["close","error","message","open"],U),W};var b=f.WebSocket;for(var P in x)b[P]=x[P]}(p,f),Zone[p.symbol("patchEvents")]=!0}}Zone.__load_patch("util",function(p,f,m){var d=ur(p);m.patchOnProperties=Es,m.patchMethod=mt,m.bindArguments=Ee,m.patchMacroTask=Wo;var T=f.__symbol__("BLACK_LISTED_EVENTS"),x=f.__symbol__("UNPATCHED_EVENTS");p[x]&&(p[T]=p[x]),p[T]&&(f[T]=f[x]=p[T]),m.patchEventPrototype=fi,m.patchEventTarget=_s,m.isIEOrEdge=di,m.ObjectDefineProperty=Ot,m.ObjectGetOwnPropertyDescriptor=wt,m.ObjectCreate=It,m.ArraySlice=ue,m.patchClass=$n,m.wrapWithCurrentZone=br,m.filterProperties=ws,m.attachOriginToPatched=Tt,m._redefineProperty=Object.defineProperty,m.patchCallbacks=mi,m.getGlobalObjects=function(){return{globalSources:Pr,zoneSymbolEventNames:gt,eventNames:d,isBrowser:wn,isMix:hi,isNode:ir,TRUE_STR:Qe,FALSE_STR:dt,ZONE_SYMBOL_PREFIX:On,ADD_EVENT_LISTENER_STR:Dt,REMOVE_EVENT_LISTENER_STR:Sn}}});var p,f,bs=bt(bt(bt(bt(bt(bt(bt(bt([],["abort","animationcancel","animationend","animationiteration","auxclick","beforeinput","blur","cancel","canplay","canplaythrough","change","compositionstart","compositionupdate","compositionend","cuechange","click","close","contextmenu","curechange","dblclick","drag","dragend","dragenter","dragexit","dragleave","dragover","drop","durationchange","emptied","ended","error","focus","focusin","focusout","gotpointercapture","input","invalid","keydown","keypress","keyup","load","loadstart","loadeddata","loadedmetadata","lostpointercapture","mousedown","mouseenter","mouseleave","mousemove","mouseout","mouseover","mouseup","mousewheel","orientationchange","pause","play","playing","pointercancel","pointerdown","pointerenter","pointerleave","pointerlockchange","mozpointerlockchange","webkitpointerlockerchange","pointerlockerror","mozpointerlockerror","webkitpointerlockerror","pointermove","pointout","pointerover","pointerup","progress","ratechange","reset","resize","scroll","seeked","seeking","select","selectionchange","selectstart","show","sort","stalled","submit","suspend","timeupdate","volumechange","touchcancel","touchmove","touchstart","touchend","transitioncancel","transitionend","waiting","wheel"],!0),["webglcontextrestored","webglcontextlost","webglcontextcreationerror"],!0),["autocomplete","autocompleteerror"],!0),["toggle"],!0),["afterscriptexecute","beforescriptexecute","DOMContentLoaded","freeze","fullscreenchange","mozfullscreenchange","webkitfullscreenchange","msfullscreenchange","fullscreenerror","mozfullscreenerror","webkitfullscreenerror","msfullscreenerror","readystatechange","visibilitychange","resume"],!0),["absolutedeviceorientation","afterinput","afterprint","appinstalled","beforeinstallprompt","beforeprint","beforeunload","devicelight","devicemotion","deviceorientation","deviceorientationabsolute","deviceproximity","hashchange","languagechange","message","mozbeforepaint","offline","online","paint","pageshow","pagehide","popstate","rejectionhandled","storage","unhandledrejection","unload","userproximity","vrdisplayconnected","vrdisplaydisconnected","vrdisplaypresentchange"],!0),["beforecopy","beforecut","beforepaste","copy","cut","paste","dragstart","loadend","animationstart","search","transitionrun","transitionstart","webkitanimationend","webkitanimationiteration","webkitanimationstart","webkittransitionend"],!0),["activate","afterupdate","ariarequest","beforeactivate","beforedeactivate","beforeeditfocus","beforeupdate","cellchange","controlselect","dataavailable","datasetchanged","datasetcomplete","errorupdate","filterchange","layoutcomplete","losecapture","move","moveend","movestart","propertychange","resizeend","resizestart","rowenter","rowexit","rowsdelete","rowsinserted","command","compassneedscalibration","deactivate","help","mscontentzoom","msmanipulationstatechanged","msgesturechange","msgesturedoubletap","msgestureend","msgesturehold","msgesturestart","msgesturetap","msgotpointercapture","msinertiastart","mslostpointercapture","mspointercancel","mspointerdown","mspointerenter","mspointerhover","mspointerleave","mspointermove","mspointerout","mspointerover","mspointerup","pointerout","mssitemodejumplistitemremoved","msthumbnailclick","stop","storagecommit"],!0);p=typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{},f=p.__Zone_symbol_prefix||"__zone_symbol__",p[function m(d){return f+d}("legacyPatch")]=function(){var d=p.Zone;d.__load_patch("defineProperty",function(T,x,b){b._redefineProperty=We,function gi(){Vn=Zone.__symbol__,qn=Object[Vn("defineProperty")]=Object.defineProperty,Je=Object[Vn("getOwnPropertyDescriptor")]=Object.getOwnPropertyDescriptor,et=Object.create,Xt=Vn("unconfigurables"),Object.defineProperty=function(p,f,m){if(lr(p,f))throw new TypeError("Cannot assign to read only property '"+f+"' of "+p);var d=m.configurable;return"prototype"!==f&&(m=Lr(p,f,m)),Cs(p,f,m,d)},Object.defineProperties=function(p,f){Object.keys(f).forEach(function(b){Object.defineProperty(p,b,f[b])});for(var m=0,d=Object.getOwnPropertySymbols(f);m0){var ge=ne.invoke;ne.invoke=function(){for(var k=re[f.__symbol__("loadfalse")],y=0;y{rr(rr.s=565)}]); \ No newline at end of file diff --git a/src/KafkaFlow.Admin.Dashboard/ClientApp/dist/styles.css b/src/KafkaFlow.Admin.Dashboard/ClientApp/dist/styles.css index 3a24755a9..e0cfa2898 100644 --- a/src/KafkaFlow.Admin.Dashboard/ClientApp/dist/styles.css +++ b/src/KafkaFlow.Admin.Dashboard/ClientApp/dist/styles.css @@ -1,6 +1,5 @@ @charset "UTF-8";/*! - * Bootstrap v5.2.2 (https://getbootstrap.com/) - * Copyright 2011-2022 The Bootstrap Authors - * Copyright 2011-2022 Twitter, Inc. + * Bootstrap v5.3.0 (https://getbootstrap.com/) + * Copyright 2011-2023 The Bootstrap Authors * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */:root{--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-white-rgb: 255, 255, 255;--bs-black-rgb: 0, 0, 0;--bs-body-color-rgb: 33, 37, 41;--bs-body-bg-rgb: 255, 255, 255;--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, .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-bg: #fff;--bs-border-width: 1px;--bs-border-style: solid;--bs-border-color: #dee2e6;--bs-border-color-translucent: rgba(0, 0, 0, .175);--bs-border-radius: .375rem;--bs-border-radius-sm: .25rem;--bs-border-radius-lg: .5rem;--bs-border-radius-xl: 1rem;--bs-border-radius-2xl: 2rem;--bs-border-radius-pill: 50rem;--bs-link-color: #0d6efd;--bs-link-hover-color: #0a58ca;--bs-code-color: #d63384;--bs-highlight-bg: #fff3cd}*,*: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:1px solid;opacity:.25}h6,.h6,h5,.h5,h4,.h4,h3,.h3,h2,.h2,h1,.h1{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}h1,.h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width: 1200px){h1,.h1{font-size:2.5rem}}h2,.h2{font-size:calc(1.325rem + .9vw)}@media (min-width: 1200px){h2,.h2{font-size:2rem}}h3,.h3{font-size:calc(1.3rem + .6vw)}@media (min-width: 1200px){h3,.h3{font-size:1.75rem}}h4,.h4{font-size:calc(1.275rem + .3vw)}@media (min-width: 1200px){h4,.h4{font-size:1.5rem}}h5,.h5{font-size:1.25rem}h6,.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:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small,.small{font-size:.875em}mark,.mark{padding:.1875em;background-color:var(--bs-highlight-bg)}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:var(--bs-link-color);text-decoration:underline}a:hover{color:var(--bs-link-hover-color)}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:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:var(--bs-code-color);word-wrap:break-word}a>code{color:inherit}kbd{padding:.1875rem .375rem;font-size:.875em;color:var(--bs-body-bg);background-color:var(--bs-body-color);border-radius:.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:.5rem;padding-bottom:.5rem;color:#6c757d;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:.5rem;font-size:calc(1.275rem + .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]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::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}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media (min-width: 1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media (min-width: 1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media (min-width: 1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media (min-width: 1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media (min-width: 1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media (min-width: 1200px){.display-6{font-size:2.5rem}}.list-unstyled,.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:.875em;color:#6c757d}.blockquote-footer:before{content:"\2014\a0"}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid var(--bs-border-color);border-radius:.375rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:.875em;color:#6c757d}.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-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-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}}.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>*{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.3333333333%}.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.6666666667%}.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: .25rem}.g-1,.gy-1{--bs-gutter-y: .25rem}.g-2,.gx-2{--bs-gutter-x: .5rem}.g-2,.gy-2{--bs-gutter-y: .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.3333333333%}.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.6666666667%}.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: .25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y: .25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x: .5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y: .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.3333333333%}.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.6666666667%}.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: .25rem}.g-md-1,.gy-md-1{--bs-gutter-y: .25rem}.g-md-2,.gx-md-2{--bs-gutter-x: .5rem}.g-md-2,.gy-md-2{--bs-gutter-y: .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.3333333333%}.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.6666666667%}.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: .25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y: .25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x: .5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y: .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.3333333333%}.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.6666666667%}.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: .25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y: .25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x: .5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y: .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.3333333333%}.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.6666666667%}.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: .25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y: .25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x: .5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y: .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}}.table{--bs-table-color: var(--bs-body-color);--bs-table-bg: transparent;--bs-table-border-color: var(--bs-border-color);--bs-table-accent-bg: transparent;--bs-table-striped-color: var(--bs-body-color);--bs-table-striped-bg: rgba(0, 0, 0, .05);--bs-table-active-color: var(--bs-body-color);--bs-table-active-bg: rgba(0, 0, 0, .1);--bs-table-hover-color: var(--bs-body-color);--bs-table-hover-bg: rgba(0, 0, 0, .075);width:100%;margin-bottom:1rem;color:var(--bs-table-color);vertical-align:top;border-color:var(--bs-table-border-color)}.table>:not(caption)>*>*{padding:.5rem;background-color:var(--bs-table-bg);border-bottom-width:1px;box-shadow:inset 0 0 0 9999px var(--bs-table-accent-bg)}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table-group-divider{border-top:2px solid currentcolor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem}.table-bordered>:not(caption)>*{border-width:1px 0}.table-bordered>:not(caption)>*>*{border-width:0 1px}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-accent-bg: var(--bs-table-striped-bg);color:var(--bs-table-striped-color)}.table-striped-columns>:not(caption)>tr>:nth-child(even){--bs-table-accent-bg: var(--bs-table-striped-bg);color:var(--bs-table-striped-color)}.table-active{--bs-table-accent-bg: var(--bs-table-active-bg);color:var(--bs-table-active-color)}.table-hover>tbody>tr:hover>*{--bs-table-accent-bg: var(--bs-table-hover-bg);color:var(--bs-table-hover-color)}.table-primary{--bs-table-color: #000;--bs-table-bg: #cfe2ff;--bs-table-border-color: #bacbe6;--bs-table-striped-bg: #c5d7f2;--bs-table-striped-color: #000;--bs-table-active-bg: #bacbe6;--bs-table-active-color: #000;--bs-table-hover-bg: #bfd1ec;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-secondary{--bs-table-color: #000;--bs-table-bg: #e2e3e5;--bs-table-border-color: #cbccce;--bs-table-striped-bg: #d7d8da;--bs-table-striped-color: #000;--bs-table-active-bg: #cbccce;--bs-table-active-color: #000;--bs-table-hover-bg: #d1d2d4;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-success{--bs-table-color: #000;--bs-table-bg: #d1e7dd;--bs-table-border-color: #bcd0c7;--bs-table-striped-bg: #c7dbd2;--bs-table-striped-color: #000;--bs-table-active-bg: #bcd0c7;--bs-table-active-color: #000;--bs-table-hover-bg: #c1d6cc;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-info{--bs-table-color: #000;--bs-table-bg: #cff4fc;--bs-table-border-color: #badce3;--bs-table-striped-bg: #c5e8ef;--bs-table-striped-color: #000;--bs-table-active-bg: #badce3;--bs-table-active-color: #000;--bs-table-hover-bg: #bfe2e9;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-warning{--bs-table-color: #000;--bs-table-bg: #fff3cd;--bs-table-border-color: #e6dbb9;--bs-table-striped-bg: #f2e7c3;--bs-table-striped-color: #000;--bs-table-active-bg: #e6dbb9;--bs-table-active-color: #000;--bs-table-hover-bg: #ece1be;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-danger{--bs-table-color: #000;--bs-table-bg: #f8d7da;--bs-table-border-color: #dfc2c4;--bs-table-striped-bg: #eccccf;--bs-table-striped-color: #000;--bs-table-active-bg: #dfc2c4;--bs-table-active-color: #000;--bs-table-hover-bg: #e5c7ca;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-light{--bs-table-color: #000;--bs-table-bg: #f8f9fa;--bs-table-border-color: #dfe0e1;--bs-table-striped-bg: #ecedee;--bs-table-striped-color: #000;--bs-table-active-bg: #dfe0e1;--bs-table-active-color: #000;--bs-table-hover-bg: #e5e6e7;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-dark{--bs-table-color: #fff;--bs-table-bg: #212529;--bs-table-border-color: #373b3e;--bs-table-striped-bg: #2c3034;--bs-table-striped-color: #fff;--bs-table-active-bg: #373b3e;--bs-table-active-color: #fff;--bs-table-hover-bg: #323539;--bs-table-hover-color: #fff;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media (max-width: 575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width: 767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width: 991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width: 1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width: 1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem}.form-text{margin-top:.25rem;font-size:.875em;color:#6c757d}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;-webkit-appearance:none;appearance:none;border-radius:.375rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:#212529;background-color:#fff;border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem #0d6efd40}.form-control::-webkit-date-and-time-value{height:1.5em}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled{background-color:#e9ecef;opacity:1}.form-control::file-selector-button{padding:.375rem .75rem;margin:-.375rem -.75rem;margin-inline-end:.75rem;color:#212529;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:#dde0e3}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:#212529;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext:focus{outline:0}.form-control-plaintext.form-control-sm,.form-control-plaintext.form-control-lg{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + .5rem + 2px);padding:.25rem .5rem;font-size:.875rem;border-radius:.25rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-.25rem -.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + 2px);padding:.5rem 1rem;font-size:1.25rem;border-radius:.5rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-.5rem -1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + .75rem + 2px)}textarea.form-control-sm{min-height:calc(1.5em + .5rem + 2px)}textarea.form-control-lg{min-height:calc(1.5em + 1rem + 2px)}.form-control-color{width:3rem;height:calc(1.5em + .75rem + 2px);padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{border:0!important;border-radius:.375rem}.form-control-color::-webkit-color-swatch{border-radius:.375rem}.form-control-color.form-control-sm{height:calc(1.5em + .5rem + 2px)}.form-control-color.form-control-lg{height:calc(1.5em + 1rem + 2px)}.form-select{display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;-moz-padding-start:calc(.75rem - 3px);font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:1px solid #ced4da;border-radius:.375rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;appearance:none}@media (prefers-reduced-motion: reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem #0d6efd40}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:#e9ecef}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 #212529}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem;border-radius:.25rem}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem;border-radius:.5rem}.form-check{display:block;min-height:1.5rem;padding-left:1.5em;margin-bottom:.125rem}.form-check .form-check-input{float:left;margin-left:-1.5em}.form-check-reverse{padding-right:1.5em;padding-left:0;text-align:right}.form-check-reverse .form-check-input{float:right;margin-right:-1.5em;margin-left:0}.form-check-input{width:1em;height:1em;margin-top:.25em;vertical-align:top;background-color:#fff;background-repeat:no-repeat;background-position:center;background-size:contain;border:1px solid rgba(0,0,0,.25);-webkit-appearance:none;appearance:none;-webkit-print-color-adjust:exact;print-color-adjust:exact}.form-check-input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem #0d6efd40}.form-check-input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input[disabled]~.form-check-label,.form-check-input:disabled~.form-check-label{cursor:default;opacity:.5}.form-switch{padding-left:2.5em}.form-switch .form-check-input{width:2em;margin-left:-2.5em;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");background-position:left center;border-radius:2em;transition:background-position .15s ease-in-out}@media (prefers-reduced-motion: reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-switch.form-check-reverse{padding-right:2.5em;padding-left:0}.form-switch.form-check-reverse .form-check-input{margin-right:-2.5em;margin-left:0}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.btn-check[disabled]+.btn,.btn-check:disabled+.btn{pointer-events:none;filter:none;opacity:.65}.form-range{width:100%;height:1.5rem;padding:0;background-color:transparent;-webkit-appearance:none;appearance:none}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem #0d6efd40}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem #0d6efd40}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#0d6efd;border:0;border-radius:1rem;-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;appearance:none}@media (prefers-reduced-motion: reduce){.form-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#0d6efd;border:0;border-radius:1rem;-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none}@media (prefers-reduced-motion: reduce){.form-range::-moz-range-thumb{-moz-transition:none;transition:none}}.form-range::-moz-range-thumb:active{background-color:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:#adb5bd}.form-range:disabled::-moz-range-thumb{background-color:#adb5bd}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-control-plaintext,.form-floating>.form-select{height:calc(3.5rem + 2px);line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;width:100%;height:100%;padding:1rem .75rem;overflow:hidden;text-align:start;text-overflow:ellipsis;white-space:nowrap;pointer-events:none;border:1px solid transparent;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media (prefers-reduced-motion: reduce){.form-floating>label{transition:none}}.form-floating>.form-control,.form-floating>.form-control-plaintext{padding:1rem .75rem}.form-floating>.form-control::placeholder,.form-floating>.form-control-plaintext::placeholder{color:transparent}.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown),.form-floating>.form-control-plaintext:focus,.form-floating>.form-control-plaintext:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:-webkit-autofill,.form-floating>.form-control-plaintext:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-control-plaintext~label,.form-floating>.form-select~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translate(.15rem)}.form-floating>.form-control:-webkit-autofill~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translate(.15rem)}.form-floating>.form-control-plaintext~label{border-width:1px 0}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-select,.input-group>.form-floating{position:relative;flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-select:focus,.input-group>.form-floating:focus-within{z-index:5}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:5}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.375rem}.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text,.input-group-lg>.btn{padding:.5rem 1rem;font-size:1.25rem;border-radius:.5rem}.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text,.input-group-sm>.btn{padding:.25rem .5rem;font-size:.875rem;border-radius:.25rem}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-control,.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-select{border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-control,.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-select{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:-1px;border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.form-floating:not(:first-child)>.form-control,.input-group>.form-floating:not(:first-child)>.form-select{border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:#198754}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:#198754e6;border-radius:.375rem}.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip,.is-valid~.valid-feedback,.is-valid~.valid-tooltip{display:block}.was-validated .form-control:valid,.form-control.is-valid{border-color:#198754;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.was-validated .form-control:valid:focus,.form-control.is-valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem #19875440}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.was-validated .form-select:valid,.form-select.is-valid{border-color:#198754}.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"],.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"]{padding-right:4.125rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.was-validated .form-select:valid:focus,.form-select.is-valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem #19875440}.was-validated .form-control-color:valid,.form-control-color.is-valid{width:calc(3.75rem + 1.5em)}.was-validated .form-check-input:valid,.form-check-input.is-valid{border-color:#198754}.was-validated .form-check-input:valid:checked,.form-check-input.is-valid:checked{background-color:#198754}.was-validated .form-check-input:valid:focus,.form-check-input.is-valid:focus{box-shadow:0 0 0 .25rem #19875440}.was-validated .form-check-input:valid~.form-check-label,.form-check-input.is-valid~.form-check-label{color:#198754}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.was-validated .input-group>.form-control:not(:focus):valid,.input-group>.form-control:not(:focus).is-valid,.was-validated .input-group>.form-select:not(:focus):valid,.input-group>.form-select:not(:focus).is-valid,.was-validated .input-group>.form-floating:not(:focus-within):valid,.input-group>.form-floating:not(:focus-within).is-valid{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:#dc3545e6;border-radius:.375rem}.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip,.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip{display:block}.was-validated .form-control:invalid,.form-control.is-invalid{border-color:#dc3545;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.was-validated .form-control:invalid:focus,.form-control.is-invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem #dc354540}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.was-validated .form-select:invalid,.form-select.is-invalid{border-color:#dc3545}.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"],.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"]{padding-right:4.125rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.was-validated .form-select:invalid:focus,.form-select.is-invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem #dc354540}.was-validated .form-control-color:invalid,.form-control-color.is-invalid{width:calc(3.75rem + 1.5em)}.was-validated .form-check-input:invalid,.form-check-input.is-invalid{border-color:#dc3545}.was-validated .form-check-input:invalid:checked,.form-check-input.is-invalid:checked{background-color:#dc3545}.was-validated .form-check-input:invalid:focus,.form-check-input.is-invalid:focus{box-shadow:0 0 0 .25rem #dc354540}.was-validated .form-check-input:invalid~.form-check-label,.form-check-input.is-invalid~.form-check-label{color:#dc3545}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.was-validated .input-group>.form-control:not(:focus):invalid,.input-group>.form-control:not(:focus).is-invalid,.was-validated .input-group>.form-select:not(:focus):invalid,.input-group>.form-select:not(:focus).is-invalid,.was-validated .input-group>.form-floating:not(:focus-within):invalid,.input-group>.form-floating:not(:focus-within).is-invalid{z-index:4}.btn{--bs-btn-padding-x: .75rem;--bs-btn-padding-y: .375rem;--bs-btn-font-family: ;--bs-btn-font-size: 1rem;--bs-btn-font-weight: 400;--bs-btn-line-height: 1.5;--bs-btn-color: #212529;--bs-btn-bg: transparent;--bs-btn-border-width: 1px;--bs-btn-border-color: transparent;--bs-btn-border-radius: .375rem;--bs-btn-hover-border-color: transparent;--bs-btn-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);--bs-btn-disabled-opacity: .65;--bs-btn-focus-box-shadow: 0 0 0 .25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-family:var(--bs-btn-font-family);font-size:var(--bs-btn-font-size);font-weight:var(--bs-btn-font-weight);line-height:var(--bs-btn-line-height);color:var(--bs-btn-color);text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;user-select:none;border:var(--bs-btn-border-width) solid var(--bs-btn-border-color);border-radius:var(--bs-btn-border-radius);background-color:var(--bs-btn-bg);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.btn{transition:none}}.btn:hover{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color)}.btn-check+.btn:hover{color:var(--bs-btn-color);background-color:var(--bs-btn-bg);border-color:var(--bs-btn-border-color)}.btn:focus-visible{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:focus-visible+.btn{border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked+.btn,:not(.btn-check)+.btn:active,.btn:first-child:active,.btn.active,.btn.show{color:var(--bs-btn-active-color);background-color:var(--bs-btn-active-bg);border-color:var(--bs-btn-active-border-color)}.btn-check:checked+.btn:focus-visible,:not(.btn-check)+.btn:active:focus-visible,.btn:first-child:active:focus-visible,.btn.active:focus-visible,.btn.show:focus-visible{box-shadow:var(--bs-btn-focus-box-shadow)}.btn:disabled,.btn.disabled,fieldset:disabled .btn{color:var(--bs-btn-disabled-color);pointer-events:none;background-color:var(--bs-btn-disabled-bg);border-color:var(--bs-btn-disabled-border-color);opacity:var(--bs-btn-disabled-opacity)}.btn-primary{--bs-btn-color: #fff;--bs-btn-bg: #0d6efd;--bs-btn-border-color: #0d6efd;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #0b5ed7;--bs-btn-hover-border-color: #0a58ca;--bs-btn-focus-shadow-rgb: 49, 132, 253;--bs-btn-active-color: #fff;--bs-btn-active-bg: #0a58ca;--bs-btn-active-border-color: #0a53be;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #0d6efd;--bs-btn-disabled-border-color: #0d6efd}.btn-secondary{--bs-btn-color: #fff;--bs-btn-bg: #6c757d;--bs-btn-border-color: #6c757d;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #5c636a;--bs-btn-hover-border-color: #565e64;--bs-btn-focus-shadow-rgb: 130, 138, 145;--bs-btn-active-color: #fff;--bs-btn-active-bg: #565e64;--bs-btn-active-border-color: #51585e;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #6c757d;--bs-btn-disabled-border-color: #6c757d}.btn-success{--bs-btn-color: #fff;--bs-btn-bg: #198754;--bs-btn-border-color: #198754;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #157347;--bs-btn-hover-border-color: #146c43;--bs-btn-focus-shadow-rgb: 60, 153, 110;--bs-btn-active-color: #fff;--bs-btn-active-bg: #146c43;--bs-btn-active-border-color: #13653f;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #198754;--bs-btn-disabled-border-color: #198754}.btn-info{--bs-btn-color: #000;--bs-btn-bg: #0dcaf0;--bs-btn-border-color: #0dcaf0;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #31d2f2;--bs-btn-hover-border-color: #25cff2;--bs-btn-focus-shadow-rgb: 11, 172, 204;--bs-btn-active-color: #000;--bs-btn-active-bg: #3dd5f3;--bs-btn-active-border-color: #25cff2;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #0dcaf0;--bs-btn-disabled-border-color: #0dcaf0}.btn-warning{--bs-btn-color: #000;--bs-btn-bg: #ffc107;--bs-btn-border-color: #ffc107;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #ffca2c;--bs-btn-hover-border-color: #ffc720;--bs-btn-focus-shadow-rgb: 217, 164, 6;--bs-btn-active-color: #000;--bs-btn-active-bg: #ffcd39;--bs-btn-active-border-color: #ffc720;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #ffc107;--bs-btn-disabled-border-color: #ffc107}.btn-danger{--bs-btn-color: #fff;--bs-btn-bg: #dc3545;--bs-btn-border-color: #dc3545;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #bb2d3b;--bs-btn-hover-border-color: #b02a37;--bs-btn-focus-shadow-rgb: 225, 83, 97;--bs-btn-active-color: #fff;--bs-btn-active-bg: #b02a37;--bs-btn-active-border-color: #a52834;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #dc3545;--bs-btn-disabled-border-color: #dc3545}.btn-light{--bs-btn-color: #000;--bs-btn-bg: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #d3d4d5;--bs-btn-hover-border-color: #c6c7c8;--bs-btn-focus-shadow-rgb: 211, 212, 213;--bs-btn-active-color: #000;--bs-btn-active-bg: #c6c7c8;--bs-btn-active-border-color: #babbbc;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #f8f9fa;--bs-btn-disabled-border-color: #f8f9fa}.btn-dark{--bs-btn-color: #fff;--bs-btn-bg: #212529;--bs-btn-border-color: #212529;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #424649;--bs-btn-hover-border-color: #373b3e;--bs-btn-focus-shadow-rgb: 66, 70, 73;--bs-btn-active-color: #fff;--bs-btn-active-bg: #4d5154;--bs-btn-active-border-color: #373b3e;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #212529;--bs-btn-disabled-border-color: #212529}.btn-outline-primary{--bs-btn-color: #0d6efd;--bs-btn-border-color: #0d6efd;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #0d6efd;--bs-btn-hover-border-color: #0d6efd;--bs-btn-focus-shadow-rgb: 13, 110, 253;--bs-btn-active-color: #fff;--bs-btn-active-bg: #0d6efd;--bs-btn-active-border-color: #0d6efd;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #0d6efd;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #0d6efd;--bs-gradient: none}.btn-outline-secondary{--bs-btn-color: #6c757d;--bs-btn-border-color: #6c757d;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #6c757d;--bs-btn-hover-border-color: #6c757d;--bs-btn-focus-shadow-rgb: 108, 117, 125;--bs-btn-active-color: #fff;--bs-btn-active-bg: #6c757d;--bs-btn-active-border-color: #6c757d;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #6c757d;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #6c757d;--bs-gradient: none}.btn-outline-success{--bs-btn-color: #198754;--bs-btn-border-color: #198754;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #198754;--bs-btn-hover-border-color: #198754;--bs-btn-focus-shadow-rgb: 25, 135, 84;--bs-btn-active-color: #fff;--bs-btn-active-bg: #198754;--bs-btn-active-border-color: #198754;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #198754;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #198754;--bs-gradient: none}.btn-outline-info{--bs-btn-color: #0dcaf0;--bs-btn-border-color: #0dcaf0;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #0dcaf0;--bs-btn-hover-border-color: #0dcaf0;--bs-btn-focus-shadow-rgb: 13, 202, 240;--bs-btn-active-color: #000;--bs-btn-active-bg: #0dcaf0;--bs-btn-active-border-color: #0dcaf0;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #0dcaf0;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #0dcaf0;--bs-gradient: none}.btn-outline-warning{--bs-btn-color: #ffc107;--bs-btn-border-color: #ffc107;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #ffc107;--bs-btn-hover-border-color: #ffc107;--bs-btn-focus-shadow-rgb: 255, 193, 7;--bs-btn-active-color: #000;--bs-btn-active-bg: #ffc107;--bs-btn-active-border-color: #ffc107;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #ffc107;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #ffc107;--bs-gradient: none}.btn-outline-danger{--bs-btn-color: #dc3545;--bs-btn-border-color: #dc3545;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #dc3545;--bs-btn-hover-border-color: #dc3545;--bs-btn-focus-shadow-rgb: 220, 53, 69;--bs-btn-active-color: #fff;--bs-btn-active-bg: #dc3545;--bs-btn-active-border-color: #dc3545;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #dc3545;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #dc3545;--bs-gradient: none}.btn-outline-light{--bs-btn-color: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #f8f9fa;--bs-btn-hover-border-color: #f8f9fa;--bs-btn-focus-shadow-rgb: 248, 249, 250;--bs-btn-active-color: #000;--bs-btn-active-bg: #f8f9fa;--bs-btn-active-border-color: #f8f9fa;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #f8f9fa;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #f8f9fa;--bs-gradient: none}.btn-outline-dark{--bs-btn-color: #212529;--bs-btn-border-color: #212529;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #212529;--bs-btn-hover-border-color: #212529;--bs-btn-focus-shadow-rgb: 33, 37, 41;--bs-btn-active-color: #fff;--bs-btn-active-bg: #212529;--bs-btn-active-border-color: #212529;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #212529;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #212529;--bs-gradient: none}.btn-link{--bs-btn-font-weight: 400;--bs-btn-color: var(--bs-link-color);--bs-btn-bg: transparent;--bs-btn-border-color: transparent;--bs-btn-hover-color: var(--bs-link-hover-color);--bs-btn-hover-border-color: transparent;--bs-btn-active-color: var(--bs-link-hover-color);--bs-btn-active-border-color: transparent;--bs-btn-disabled-color: #6c757d;--bs-btn-disabled-border-color: transparent;--bs-btn-box-shadow: none;--bs-btn-focus-shadow-rgb: 49, 132, 253;text-decoration:underline}.btn-link:focus-visible{color:var(--bs-btn-color)}.btn-link:hover{color:var(--bs-btn-hover-color)}.btn-lg,.btn-group-lg>.btn{--bs-btn-padding-y: .5rem;--bs-btn-padding-x: 1rem;--bs-btn-font-size: 1.25rem;--bs-btn-border-radius: .5rem}.btn-sm,.btn-group-sm>.btn{--bs-btn-padding-y: .25rem;--bs-btn-padding-x: .5rem;--bs-btn-font-size: .875rem;--bs-btn-border-radius: .25rem}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion: reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion: reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media (prefers-reduced-motion: reduce){.collapsing.collapse-horizontal{transition:none}}.dropup,.dropend,.dropdown,.dropstart,.dropup-center,.dropdown-center{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle:after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty:after{margin-left:0}.dropdown-menu{--bs-dropdown-zindex: 1000;--bs-dropdown-min-width: 10rem;--bs-dropdown-padding-x: 0;--bs-dropdown-padding-y: .5rem;--bs-dropdown-spacer: .125rem;--bs-dropdown-font-size: 1rem;--bs-dropdown-color: #212529;--bs-dropdown-bg: #fff;--bs-dropdown-border-color: var(--bs-border-color-translucent);--bs-dropdown-border-radius: .375rem;--bs-dropdown-border-width: 1px;--bs-dropdown-inner-border-radius:calc(.375rem - 1px);--bs-dropdown-divider-bg: var(--bs-border-color-translucent);--bs-dropdown-divider-margin-y: .5rem;--bs-dropdown-box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .15);--bs-dropdown-link-color: #212529;--bs-dropdown-link-hover-color: #1e2125;--bs-dropdown-link-hover-bg: #e9ecef;--bs-dropdown-link-active-color: #fff;--bs-dropdown-link-active-bg: #0d6efd;--bs-dropdown-link-disabled-color: #adb5bd;--bs-dropdown-item-padding-x: 1rem;--bs-dropdown-item-padding-y: .25rem;--bs-dropdown-header-color: #6c757d;--bs-dropdown-header-padding-x: 1rem;--bs-dropdown-header-padding-y: .5rem;position:absolute;z-index:var(--bs-dropdown-zindex);display:none;min-width:var(--bs-dropdown-min-width);padding:var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x);margin:0;font-size:var(--bs-dropdown-font-size);color:var(--bs-dropdown-color);text-align:left;list-style:none;background-color:var(--bs-dropdown-bg);background-clip:padding-box;border:var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color);border-radius:var(--bs-dropdown-border-radius)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:var(--bs-dropdown-spacer)}.dropdown-menu-start{--bs-position: start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position: end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media (min-width: 576px){.dropdown-menu-sm-start{--bs-position: start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position: end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media (min-width: 768px){.dropdown-menu-md-start{--bs-position: start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position: end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media (min-width: 992px){.dropdown-menu-lg-start{--bs-position: start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position: end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media (min-width: 1200px){.dropdown-menu-xl-start{--bs-position: start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position: end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media (min-width: 1400px){.dropdown-menu-xxl-start{--bs-position: start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position: end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:var(--bs-dropdown-spacer)}.dropup .dropdown-toggle:after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty:after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:var(--bs-dropdown-spacer)}.dropend .dropdown-toggle:after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty:after{margin-left:0}.dropend .dropdown-toggle:after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:var(--bs-dropdown-spacer)}.dropstart .dropdown-toggle:after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle:after{display:none}.dropstart .dropdown-toggle:before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty:after{margin-left:0}.dropstart .dropdown-toggle:before{vertical-align:0}.dropdown-divider{height:0;margin:var(--bs-dropdown-divider-margin-y) 0;overflow:hidden;border-top:1px solid var(--bs-dropdown-divider-bg);opacity:1}.dropdown-item{display:block;width:100%;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);clear:both;font-weight:400;color:var(--bs-dropdown-link-color);text-align:inherit;text-decoration:none;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:hover,.dropdown-item:focus{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}.dropdown-item.active,.dropdown-item:active{color:var(--bs-dropdown-link-active-color);text-decoration:none;background-color:var(--bs-dropdown-link-active-bg)}.dropdown-item.disabled,.dropdown-item:disabled{color:var(--bs-dropdown-link-disabled-color);pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x);margin-bottom:0;font-size:.875rem;color:var(--bs-dropdown-header-color);white-space:nowrap}.dropdown-item-text{display:block;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);color:var(--bs-dropdown-link-color)}.dropdown-menu-dark{--bs-dropdown-color: #dee2e6;--bs-dropdown-bg: #343a40;--bs-dropdown-border-color: var(--bs-border-color-translucent);--bs-dropdown-box-shadow: ;--bs-dropdown-link-color: #dee2e6;--bs-dropdown-link-hover-color: #fff;--bs-dropdown-divider-bg: var(--bs-border-color-translucent);--bs-dropdown-link-hover-bg: rgba(255, 255, 255, .15);--bs-dropdown-link-active-color: #fff;--bs-dropdown-link-active-bg: #0d6efd;--bs-dropdown-link-disabled-color: #adb5bd;--bs-dropdown-header-color: #adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;flex:1 1 auto}.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn:hover,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn.active{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group{border-radius:.375rem}.btn-group>:not(.btn-check:first-child)+.btn,.btn-group>.btn-group:not(:first-child){margin-left:-1px}.btn-group>.btn:not(:last-child):not(.dropdown-toggle),.btn-group>.btn.dropdown-toggle-split:first-child,.btn-group>.btn-group:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn,.btn-group>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split:after,.dropup .dropdown-toggle-split:after,.dropend .dropdown-toggle-split:after{margin-left:0}.dropstart .dropdown-toggle-split:before{margin-right:0}.btn-sm+.dropdown-toggle-split,.btn-group-sm>.btn+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-lg+.dropdown-toggle-split,.btn-group-lg>.btn+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn:not(:first-child),.btn-group-vertical>.btn-group:not(:first-child){margin-top:-1px}.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle),.btn-group-vertical>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn~.btn,.btn-group-vertical>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{--bs-nav-link-padding-x: 1rem;--bs-nav-link-padding-y: .5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color: var(--bs-link-color);--bs-nav-link-hover-color: var(--bs-link-hover-color);--bs-nav-link-disabled-color: #6c757d;display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);font-size:var(--bs-nav-link-font-size);font-weight:var(--bs-nav-link-font-weight);color:var(--bs-nav-link-color);text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media (prefers-reduced-motion: reduce){.nav-link{transition:none}}.nav-link:hover,.nav-link:focus{color:var(--bs-nav-link-hover-color)}.nav-link.disabled{color:var(--bs-nav-link-disabled-color);pointer-events:none;cursor:default}.nav-tabs{--bs-nav-tabs-border-width: 1px;--bs-nav-tabs-border-color: #dee2e6;--bs-nav-tabs-border-radius: .375rem;--bs-nav-tabs-link-hover-border-color: #e9ecef #e9ecef #dee2e6;--bs-nav-tabs-link-active-color: #495057;--bs-nav-tabs-link-active-bg: #fff;--bs-nav-tabs-link-active-border-color: #dee2e6 #dee2e6 #fff;border-bottom:var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color)}.nav-tabs .nav-link{margin-bottom:calc(-1 * var(--bs-nav-tabs-border-width));background:none;border:var(--bs-nav-tabs-border-width) solid transparent;border-top-left-radius:var(--bs-nav-tabs-border-radius);border-top-right-radius:var(--bs-nav-tabs-border-radius)}.nav-tabs .nav-link:hover,.nav-tabs .nav-link:focus{isolation:isolate;border-color:var(--bs-nav-tabs-link-hover-border-color)}.nav-tabs .nav-link.disabled,.nav-tabs .nav-link:disabled{color:var(--bs-nav-link-disabled-color);background-color:transparent;border-color:transparent}.nav-tabs .nav-link.active,.nav-tabs .nav-item.show .nav-link{color:var(--bs-nav-tabs-link-active-color);background-color:var(--bs-nav-tabs-link-active-bg);border-color:var(--bs-nav-tabs-link-active-border-color)}.nav-tabs .dropdown-menu{margin-top:calc(-1 * var(--bs-nav-tabs-border-width));border-top-left-radius:0;border-top-right-radius:0}.nav-pills{--bs-nav-pills-border-radius: .375rem;--bs-nav-pills-link-active-color: #fff;--bs-nav-pills-link-active-bg: #0d6efd}.nav-pills .nav-link{background:none;border:0;border-radius:var(--bs-nav-pills-border-radius)}.nav-pills .nav-link:disabled{color:var(--bs-nav-link-disabled-color);background-color:transparent;border-color:transparent}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:var(--bs-nav-pills-link-active-color);background-color:var(--bs-nav-pills-link-active-bg)}.nav-fill>.nav-link,.nav-fill .nav-item{flex:1 1 auto;text-align:center}.nav-justified>.nav-link,.nav-justified .nav-item{flex-basis:0;flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{--bs-navbar-padding-x: 0;--bs-navbar-padding-y: .5rem;--bs-navbar-color: rgba(0, 0, 0, .55);--bs-navbar-hover-color: rgba(0, 0, 0, .7);--bs-navbar-disabled-color: rgba(0, 0, 0, .3);--bs-navbar-active-color: rgba(0, 0, 0, .9);--bs-navbar-brand-padding-y: .3125rem;--bs-navbar-brand-margin-end: 1rem;--bs-navbar-brand-font-size: 1.25rem;--bs-navbar-brand-color: rgba(0, 0, 0, .9);--bs-navbar-brand-hover-color: rgba(0, 0, 0, .9);--bs-navbar-nav-link-padding-x: .5rem;--bs-navbar-toggler-padding-y: .25rem;--bs-navbar-toggler-padding-x: .75rem;--bs-navbar-toggler-font-size: 1.25rem;--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%280, 0, 0, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");--bs-navbar-toggler-border-color: rgba(0, 0, 0, .1);--bs-navbar-toggler-border-radius: .375rem;--bs-navbar-toggler-focus-width: .25rem;--bs-navbar-toggler-transition: box-shadow .15s ease-in-out;position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:var(--bs-navbar-padding-y) var(--bs-navbar-padding-x)}.navbar>.container,.navbar>.container-fluid,.navbar>.container-sm,.navbar>.container-md,.navbar>.container-lg,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:var(--bs-navbar-brand-padding-y);padding-bottom:var(--bs-navbar-brand-padding-y);margin-right:var(--bs-navbar-brand-margin-end);font-size:var(--bs-navbar-brand-font-size);color:var(--bs-navbar-brand-color);text-decoration:none;white-space:nowrap}.navbar-brand:hover,.navbar-brand:focus{color:var(--bs-navbar-brand-hover-color)}.navbar-nav{--bs-nav-link-padding-x: 0;--bs-nav-link-padding-y: .5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color: var(--bs-navbar-color);--bs-nav-link-hover-color: var(--bs-navbar-hover-color);--bs-nav-link-disabled-color: var(--bs-navbar-disabled-color);display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .show>.nav-link,.navbar-nav .nav-link.active{color:var(--bs-navbar-active-color)}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-navbar-color)}.navbar-text a,.navbar-text a:hover,.navbar-text a:focus{color:var(--bs-navbar-active-color)}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x);font-size:var(--bs-navbar-toggler-font-size);line-height:1;color:var(--bs-navbar-color);background-color:transparent;border:var(--bs-border-width) solid var(--bs-navbar-toggler-border-color);border-radius:var(--bs-navbar-toggler-border-radius);transition:var(--bs-navbar-toggler-transition)}@media (prefers-reduced-motion: reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 var(--bs-navbar-toggler-focus-width)}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-image:var(--bs-navbar-toggler-icon-bg);background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height, 75vh);overflow-y:auto}@media (min-width: 576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-sm .offcanvas .offcanvas-header{display:none}.navbar-expand-sm .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width: 768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-md .offcanvas .offcanvas-header{display:none}.navbar-expand-md .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width: 992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-lg .offcanvas .offcanvas-header{display:none}.navbar-expand-lg .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width: 1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xl .offcanvas .offcanvas-header{display:none}.navbar-expand-xl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width: 1400px){.navbar-expand-xxl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xxl .offcanvas .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand .offcanvas .offcanvas-header{display:none}.navbar-expand .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}.navbar-dark{--bs-navbar-color: rgba(255, 255, 255, .55);--bs-navbar-hover-color: rgba(255, 255, 255, .75);--bs-navbar-disabled-color: rgba(255, 255, 255, .25);--bs-navbar-active-color: #fff;--bs-navbar-brand-color: #fff;--bs-navbar-brand-hover-color: #fff;--bs-navbar-toggler-border-color: rgba(255, 255, 255, .1);--bs-navbar-toggler-icon-bg: 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")}.card{--bs-card-spacer-y: 1rem;--bs-card-spacer-x: 1rem;--bs-card-title-spacer-y: .5rem;--bs-card-border-width: 1px;--bs-card-border-color: var(--bs-border-color-translucent);--bs-card-border-radius: .375rem;--bs-card-box-shadow: ;--bs-card-inner-border-radius:calc(.375rem - 1px);--bs-card-cap-padding-y: .5rem;--bs-card-cap-padding-x: 1rem;--bs-card-cap-bg: rgba(0, 0, 0, .03);--bs-card-cap-color: ;--bs-card-height: ;--bs-card-color: ;--bs-card-bg: #fff;--bs-card-img-overlay-padding: 1rem;--bs-card-group-margin: .75rem;position:relative;display:flex;flex-direction:column;min-width:0;height:var(--bs-card-height);word-wrap:break-word;background-color:var(--bs-card-bg);background-clip:border-box;border:var(--bs-card-border-width) solid var(--bs-card-border-color);border-radius:var(--bs-card-border-radius)}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:var(--bs-card-spacer-y) var(--bs-card-spacer-x);color:var(--bs-card-color)}.card-title{margin-bottom:var(--bs-card-title-spacer-y)}.card-subtitle{margin-top:calc(-.5 * var(--bs-card-title-spacer-y));margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:var(--bs-card-spacer-x)}.card-header{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);margin-bottom:0;color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-bottom:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-header:first-child{border-radius:var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius) 0 0}.card-footer{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-top:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-footer:last-child{border-radius:0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius)}.card-header-tabs{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-bottom:calc(-1 * var(--bs-card-cap-padding-y));margin-left:calc(-.5 * var(--bs-card-cap-padding-x));border-bottom:0}.card-header-tabs .nav-link.active{background-color:var(--bs-card-bg);border-bottom-color:var(--bs-card-bg)}.card-header-pills{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-left:calc(-.5 * var(--bs-card-cap-padding-x))}.card-img-overlay{position:absolute;inset:0;padding:var(--bs-card-img-overlay-padding);border-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-top,.card-img-bottom{width:100%}.card-img,.card-img-top{border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom{border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card-group>.card{margin-bottom:var(--bs-card-group-margin)}@media (min-width: 576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-img-top,.card-group>.card:not(:last-child) .card-header{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-img-bottom,.card-group>.card:not(:last-child) .card-footer{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-img-top,.card-group>.card:not(:first-child) .card-header{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-img-bottom,.card-group>.card:not(:first-child) .card-footer{border-bottom-left-radius:0}}.accordion{--bs-accordion-color: #212529;--bs-accordion-bg: #fff;--bs-accordion-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out, border-radius .15s ease;--bs-accordion-border-color: var(--bs-border-color);--bs-accordion-border-width: 1px;--bs-accordion-border-radius: .375rem;--bs-accordion-inner-border-radius:calc(.375rem - 1px);--bs-accordion-btn-padding-x: 1.25rem;--bs-accordion-btn-padding-y: 1rem;--bs-accordion-btn-color: #212529;--bs-accordion-btn-bg: var(--bs-accordion-bg);--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-icon-width: 1.25rem;--bs-accordion-btn-icon-transform: rotate(-180deg);--bs-accordion-btn-icon-transition: transform .2s ease-in-out;--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%230c63e4'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-focus-border-color: #86b7fe;--bs-accordion-btn-focus-box-shadow: 0 0 0 .25rem rgba(13, 110, 253, .25);--bs-accordion-body-padding-x: 1.25rem;--bs-accordion-body-padding-y: 1rem;--bs-accordion-active-color: #0c63e4;--bs-accordion-active-bg: #e7f1ff}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x);font-size:1rem;color:var(--bs-accordion-btn-color);text-align:left;background-color:var(--bs-accordion-btn-bg);border:0;border-radius:0;overflow-anchor:none;transition:var(--bs-accordion-transition)}@media (prefers-reduced-motion: reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:var(--bs-accordion-active-color);background-color:var(--bs-accordion-active-bg);box-shadow:inset 0 calc(-1 * var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color)}.accordion-button:not(.collapsed):after{background-image:var(--bs-accordion-btn-active-icon);transform:var(--bs-accordion-btn-icon-transform)}.accordion-button:after{flex-shrink:0;width:var(--bs-accordion-btn-icon-width);height:var(--bs-accordion-btn-icon-width);margin-left:auto;content:"";background-image:var(--bs-accordion-btn-icon);background-repeat:no-repeat;background-size:var(--bs-accordion-btn-icon-width);transition:var(--bs-accordion-btn-icon-transition)}@media (prefers-reduced-motion: reduce){.accordion-button:after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;border-color:var(--bs-accordion-btn-focus-border-color);outline:0;box-shadow:var(--bs-accordion-btn-focus-box-shadow)}.accordion-header{margin-bottom:0}.accordion-item{color:var(--bs-accordion-color);background-color:var(--bs-accordion-bg);border:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.accordion-item:first-of-type{border-top-left-radius:var(--bs-accordion-border-radius);border-top-right-radius:var(--bs-accordion-border-radius)}.accordion-item:first-of-type .accordion-button{border-top-left-radius:var(--bs-accordion-inner-border-radius);border-top-right-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-item:last-of-type .accordion-button.collapsed{border-bottom-right-radius:var(--bs-accordion-inner-border-radius);border-bottom-left-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:last-of-type .accordion-collapse{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-body{padding:var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x)}.accordion-flush .accordion-collapse{border-width:0}.accordion-flush .accordion-item{border-right:0;border-left:0;border-radius:0}.accordion-flush .accordion-item:first-child{border-top:0}.accordion-flush .accordion-item:last-child{border-bottom:0}.accordion-flush .accordion-item .accordion-button,.accordion-flush .accordion-item .accordion-button.collapsed{border-radius:0}.breadcrumb{--bs-breadcrumb-padding-x: 0;--bs-breadcrumb-padding-y: 0;--bs-breadcrumb-margin-bottom: 1rem;--bs-breadcrumb-bg: ;--bs-breadcrumb-border-radius: ;--bs-breadcrumb-divider-color: #6c757d;--bs-breadcrumb-item-padding-x: .5rem;--bs-breadcrumb-item-active-color: #6c757d;display:flex;flex-wrap:wrap;padding:var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x);margin-bottom:var(--bs-breadcrumb-margin-bottom);font-size:var(--bs-breadcrumb-font-size);list-style:none;background-color:var(--bs-breadcrumb-bg);border-radius:var(--bs-breadcrumb-border-radius)}.breadcrumb-item+.breadcrumb-item{padding-left:var(--bs-breadcrumb-item-padding-x)}.breadcrumb-item+.breadcrumb-item:before{float:left;padding-right:var(--bs-breadcrumb-item-padding-x);color:var(--bs-breadcrumb-divider-color);content:var(--bs-breadcrumb-divider, "/")}.breadcrumb-item.active{color:var(--bs-breadcrumb-item-active-color)}.pagination{--bs-pagination-padding-x: .75rem;--bs-pagination-padding-y: .375rem;--bs-pagination-font-size: 1rem;--bs-pagination-color: var(--bs-link-color);--bs-pagination-bg: #fff;--bs-pagination-border-width: 1px;--bs-pagination-border-color: #dee2e6;--bs-pagination-border-radius: .375rem;--bs-pagination-hover-color: var(--bs-link-hover-color);--bs-pagination-hover-bg: #e9ecef;--bs-pagination-hover-border-color: #dee2e6;--bs-pagination-focus-color: var(--bs-link-hover-color);--bs-pagination-focus-bg: #e9ecef;--bs-pagination-focus-box-shadow: 0 0 0 .25rem rgba(13, 110, 253, .25);--bs-pagination-active-color: #fff;--bs-pagination-active-bg: #0d6efd;--bs-pagination-active-border-color: #0d6efd;--bs-pagination-disabled-color: #6c757d;--bs-pagination-disabled-bg: #fff;--bs-pagination-disabled-border-color: #dee2e6;display:flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;padding:var(--bs-pagination-padding-y) var(--bs-pagination-padding-x);font-size:var(--bs-pagination-font-size);color:var(--bs-pagination-color);text-decoration:none;background-color:var(--bs-pagination-bg);border:var(--bs-pagination-border-width) solid var(--bs-pagination-border-color);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:var(--bs-pagination-hover-color);background-color:var(--bs-pagination-hover-bg);border-color:var(--bs-pagination-hover-border-color)}.page-link:focus{z-index:3;color:var(--bs-pagination-focus-color);background-color:var(--bs-pagination-focus-bg);outline:0;box-shadow:var(--bs-pagination-focus-box-shadow)}.page-link.active,.active>.page-link{z-index:3;color:var(--bs-pagination-active-color);background-color:var(--bs-pagination-active-bg);border-color:var(--bs-pagination-active-border-color)}.page-link.disabled,.disabled>.page-link{color:var(--bs-pagination-disabled-color);pointer-events:none;background-color:var(--bs-pagination-disabled-bg);border-color:var(--bs-pagination-disabled-border-color)}.page-item:not(:first-child) .page-link{margin-left:-1px}.page-item:first-child .page-link{border-top-left-radius:var(--bs-pagination-border-radius);border-bottom-left-radius:var(--bs-pagination-border-radius)}.page-item:last-child .page-link{border-top-right-radius:var(--bs-pagination-border-radius);border-bottom-right-radius:var(--bs-pagination-border-radius)}.pagination-lg{--bs-pagination-padding-x: 1.5rem;--bs-pagination-padding-y: .75rem;--bs-pagination-font-size: 1.25rem;--bs-pagination-border-radius: .5rem}.pagination-sm{--bs-pagination-padding-x: .5rem;--bs-pagination-padding-y: .25rem;--bs-pagination-font-size: .875rem;--bs-pagination-border-radius: .25rem}.badge{--bs-badge-padding-x: .65em;--bs-badge-padding-y: .35em;--bs-badge-font-size: .75em;--bs-badge-font-weight: 700;--bs-badge-color: #fff;--bs-badge-border-radius: .375rem;display:inline-block;padding:var(--bs-badge-padding-y) var(--bs-badge-padding-x);font-size:var(--bs-badge-font-size);font-weight:var(--bs-badge-font-weight);line-height:1;color:var(--bs-badge-color);text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:var(--bs-badge-border-radius)}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{--bs-alert-bg: transparent;--bs-alert-padding-x: 1rem;--bs-alert-padding-y: 1rem;--bs-alert-margin-bottom: 1rem;--bs-alert-color: inherit;--bs-alert-border-color: transparent;--bs-alert-border: 1px solid var(--bs-alert-border-color);--bs-alert-border-radius: .375rem;position:relative;padding:var(--bs-alert-padding-y) var(--bs-alert-padding-x);margin-bottom:var(--bs-alert-margin-bottom);color:var(--bs-alert-color);background-color:var(--bs-alert-bg);border:var(--bs-alert-border);border-radius:var(--bs-alert-border-radius)}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-primary{--bs-alert-color: #084298;--bs-alert-bg: #cfe2ff;--bs-alert-border-color: #b6d4fe}.alert-primary .alert-link{color:#06357a}.alert-secondary{--bs-alert-color: #41464b;--bs-alert-bg: #e2e3e5;--bs-alert-border-color: #d3d6d8}.alert-secondary .alert-link{color:#34383c}.alert-success{--bs-alert-color: #0f5132;--bs-alert-bg: #d1e7dd;--bs-alert-border-color: #badbcc}.alert-success .alert-link{color:#0c4128}.alert-info{--bs-alert-color: #055160;--bs-alert-bg: #cff4fc;--bs-alert-border-color: #b6effb}.alert-info .alert-link{color:#04414d}.alert-warning{--bs-alert-color: #664d03;--bs-alert-bg: #fff3cd;--bs-alert-border-color: #ffecb5}.alert-warning .alert-link{color:#523e02}.alert-danger{--bs-alert-color: #842029;--bs-alert-bg: #f8d7da;--bs-alert-border-color: #f5c2c7}.alert-danger .alert-link{color:#6a1a21}.alert-light{--bs-alert-color: #636464;--bs-alert-bg: #fefefe;--bs-alert-border-color: #fdfdfe}.alert-light .alert-link{color:#4f5050}.alert-dark{--bs-alert-color: #141619;--bs-alert-bg: #d3d3d4;--bs-alert-border-color: #bcbebf}.alert-dark .alert-link{color:#101214}@keyframes progress-bar-stripes{0%{background-position-x:1rem}}.progress{--bs-progress-height: 1rem;--bs-progress-font-size: .75rem;--bs-progress-bg: #e9ecef;--bs-progress-border-radius: .375rem;--bs-progress-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .075);--bs-progress-bar-color: #fff;--bs-progress-bar-bg: #0d6efd;--bs-progress-bar-transition: width .6s ease;display:flex;height:var(--bs-progress-height);overflow:hidden;font-size:var(--bs-progress-font-size);background-color:var(--bs-progress-bg);border-radius:var(--bs-progress-border-radius)}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:var(--bs-progress-bar-color);text-align:center;white-space:nowrap;background-color:var(--bs-progress-bar-bg);transition:var(--bs-progress-bar-transition)}@media (prefers-reduced-motion: reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:var(--bs-progress-height) var(--bs-progress-height)}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media (prefers-reduced-motion: reduce){.progress-bar-animated{animation:none}}.list-group{--bs-list-group-color: #212529;--bs-list-group-bg: #fff;--bs-list-group-border-color: rgba(0, 0, 0, .125);--bs-list-group-border-width: 1px;--bs-list-group-border-radius: .375rem;--bs-list-group-item-padding-x: 1rem;--bs-list-group-item-padding-y: .5rem;--bs-list-group-action-color: #495057;--bs-list-group-action-hover-color: #495057;--bs-list-group-action-hover-bg: #f8f9fa;--bs-list-group-action-active-color: #212529;--bs-list-group-action-active-bg: #e9ecef;--bs-list-group-disabled-color: #6c757d;--bs-list-group-disabled-bg: #fff;--bs-list-group-active-color: #fff;--bs-list-group-active-bg: #0d6efd;--bs-list-group-active-border-color: #0d6efd;display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:var(--bs-list-group-border-radius)}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>.list-group-item:before{content:counters(section,".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:var(--bs-list-group-action-color);text-align:inherit}.list-group-item-action:hover,.list-group-item-action:focus{z-index:1;color:var(--bs-list-group-action-hover-color);text-decoration:none;background-color:var(--bs-list-group-action-hover-bg)}.list-group-item-action:active{color:var(--bs-list-group-action-active-color);background-color:var(--bs-list-group-action-active-bg)}.list-group-item{position:relative;display:block;padding:var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x);color:var(--bs-list-group-color);text-decoration:none;background-color:var(--bs-list-group-bg);border:var(--bs-list-group-border-width) solid var(--bs-list-group-border-color)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:var(--bs-list-group-disabled-color);pointer-events:none;background-color:var(--bs-list-group-disabled-bg)}.list-group-item.active{z-index:2;color:var(--bs-list-group-active-color);background-color:var(--bs-list-group-active-bg);border-color:var(--bs-list-group-active-border-color)}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:calc(-1 * var(--bs-list-group-border-width));border-top-width:var(--bs-list-group-border-width)}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}@media (min-width: 576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width: 768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width: 992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width: 1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width: 1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 var(--bs-list-group-border-width)}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{color:#084298;background-color:#cfe2ff}.list-group-item-primary.list-group-item-action:hover,.list-group-item-primary.list-group-item-action:focus{color:#084298;background-color:#bacbe6}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#084298;border-color:#084298}.list-group-item-secondary{color:#41464b;background-color:#e2e3e5}.list-group-item-secondary.list-group-item-action:hover,.list-group-item-secondary.list-group-item-action:focus{color:#41464b;background-color:#cbccce}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#41464b;border-color:#41464b}.list-group-item-success{color:#0f5132;background-color:#d1e7dd}.list-group-item-success.list-group-item-action:hover,.list-group-item-success.list-group-item-action:focus{color:#0f5132;background-color:#bcd0c7}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#0f5132;border-color:#0f5132}.list-group-item-info{color:#055160;background-color:#cff4fc}.list-group-item-info.list-group-item-action:hover,.list-group-item-info.list-group-item-action:focus{color:#055160;background-color:#badce3}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#055160;border-color:#055160}.list-group-item-warning{color:#664d03;background-color:#fff3cd}.list-group-item-warning.list-group-item-action:hover,.list-group-item-warning.list-group-item-action:focus{color:#664d03;background-color:#e6dbb9}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#664d03;border-color:#664d03}.list-group-item-danger{color:#842029;background-color:#f8d7da}.list-group-item-danger.list-group-item-action:hover,.list-group-item-danger.list-group-item-action:focus{color:#842029;background-color:#dfc2c4}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#842029;border-color:#842029}.list-group-item-light{color:#636464;background-color:#fefefe}.list-group-item-light.list-group-item-action:hover,.list-group-item-light.list-group-item-action:focus{color:#636464;background-color:#e5e5e5}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#636464;border-color:#636464}.list-group-item-dark{color:#141619;background-color:#d3d3d4}.list-group-item-dark.list-group-item-action:hover,.list-group-item-dark.list-group-item-action:focus{color:#141619;background-color:#bebebf}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#141619;border-color:#141619}.btn-close{box-sizing:content-box;width:1em;height:1em;padding:.25em;color:#000;background:transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat;border:0;border-radius:.375rem;opacity:.5}.btn-close:hover{color:#000;text-decoration:none;opacity:.75}.btn-close:focus{outline:0;box-shadow:0 0 0 .25rem #0d6efd40;opacity:1}.btn-close:disabled,.btn-close.disabled{pointer-events:none;-webkit-user-select:none;user-select:none;opacity:.25}.btn-close-white{filter:invert(1) grayscale(100%) brightness(200%)}.toast{--bs-toast-zindex: 1090;--bs-toast-padding-x: .75rem;--bs-toast-padding-y: .5rem;--bs-toast-spacing: 1.5rem;--bs-toast-max-width: 350px;--bs-toast-font-size: .875rem;--bs-toast-color: ;--bs-toast-bg: rgba(255, 255, 255, .85);--bs-toast-border-width: 1px;--bs-toast-border-color: var(--bs-border-color-translucent);--bs-toast-border-radius: .375rem;--bs-toast-box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .15);--bs-toast-header-color: #6c757d;--bs-toast-header-bg: rgba(255, 255, 255, .85);--bs-toast-header-border-color: rgba(0, 0, 0, .05);width:var(--bs-toast-max-width);max-width:100%;font-size:var(--bs-toast-font-size);color:var(--bs-toast-color);pointer-events:auto;background-color:var(--bs-toast-bg);background-clip:padding-box;border:var(--bs-toast-border-width) solid var(--bs-toast-border-color);box-shadow:var(--bs-toast-box-shadow);border-radius:var(--bs-toast-border-radius)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{--bs-toast-zindex: 1090;position:absolute;z-index:var(--bs-toast-zindex);width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:var(--bs-toast-spacing)}.toast-header{display:flex;align-items:center;padding:var(--bs-toast-padding-y) var(--bs-toast-padding-x);color:var(--bs-toast-header-color);background-color:var(--bs-toast-header-bg);background-clip:padding-box;border-bottom:var(--bs-toast-border-width) solid var(--bs-toast-header-border-color);border-top-left-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));border-top-right-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width))}.toast-header .btn-close{margin-right:calc(-.5 * var(--bs-toast-padding-x));margin-left:var(--bs-toast-padding-x)}.toast-body{padding:var(--bs-toast-padding-x);word-wrap:break-word}.modal{--bs-modal-zindex: 1055;--bs-modal-width: 500px;--bs-modal-padding: 1rem;--bs-modal-margin: .5rem;--bs-modal-color: ;--bs-modal-bg: #fff;--bs-modal-border-color: var(--bs-border-color-translucent);--bs-modal-border-width: 1px;--bs-modal-border-radius: .5rem;--bs-modal-box-shadow: 0 .125rem .25rem rgba(0, 0, 0, .075);--bs-modal-inner-border-radius:calc(.5rem - 1px);--bs-modal-header-padding-x: 1rem;--bs-modal-header-padding-y: 1rem;--bs-modal-header-padding: 1rem 1rem;--bs-modal-header-border-color: var(--bs-border-color);--bs-modal-header-border-width: 1px;--bs-modal-title-line-height: 1.5;--bs-modal-footer-gap: .5rem;--bs-modal-footer-bg: ;--bs-modal-footer-border-color: var(--bs-border-color);--bs-modal-footer-border-width: 1px;position:fixed;top:0;left:0;z-index:var(--bs-modal-zindex);display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:var(--bs-modal-margin);pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translateY(-50px)}@media (prefers-reduced-motion: reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - var(--bs-modal-margin) * 2)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - var(--bs-modal-margin) * 2)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;color:var(--bs-modal-color);pointer-events:auto;background-color:var(--bs-modal-bg);background-clip:padding-box;border:var(--bs-modal-border-width) solid var(--bs-modal-border-color);border-radius:var(--bs-modal-border-radius);outline:0}.modal-backdrop{--bs-backdrop-zindex: 1050;--bs-backdrop-bg: #000;--bs-backdrop-opacity: .5;position:fixed;top:0;left:0;z-index:var(--bs-backdrop-zindex);width:100vw;height:100vh;background-color:var(--bs-backdrop-bg)}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:var(--bs-backdrop-opacity)}.modal-header{display:flex;flex-shrink:0;align-items:center;justify-content:space-between;padding:var(--bs-modal-header-padding);border-bottom:var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color);border-top-left-radius:var(--bs-modal-inner-border-radius);border-top-right-radius:var(--bs-modal-inner-border-radius)}.modal-header .btn-close{padding:calc(var(--bs-modal-header-padding-y) * .5) calc(var(--bs-modal-header-padding-x) * .5);margin:calc(-.5 * var(--bs-modal-header-padding-y)) calc(-.5 * var(--bs-modal-header-padding-x)) calc(-.5 * var(--bs-modal-header-padding-y)) auto}.modal-title{margin-bottom:0;line-height:var(--bs-modal-title-line-height)}.modal-body{position:relative;flex:1 1 auto;padding:var(--bs-modal-padding)}.modal-footer{display:flex;flex-shrink:0;flex-wrap:wrap;align-items:center;justify-content:flex-end;padding:calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap) * .5);background-color:var(--bs-modal-footer-bg);border-top:var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color);border-bottom-right-radius:var(--bs-modal-inner-border-radius);border-bottom-left-radius:var(--bs-modal-inner-border-radius)}.modal-footer>*{margin:calc(var(--bs-modal-footer-gap) * .5)}@media (min-width: 576px){.modal{--bs-modal-margin: 1.75rem;--bs-modal-box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .15)}.modal-dialog{max-width:var(--bs-modal-width);margin-right:auto;margin-left:auto}.modal-sm{--bs-modal-width: 300px}}@media (min-width: 992px){.modal-lg,.modal-xl{--bs-modal-width: 800px}}@media (min-width: 1200px){.modal-xl{--bs-modal-width: 1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-header,.modal-fullscreen .modal-footer{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}@media (max-width: 575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-header,.modal-fullscreen-sm-down .modal-footer{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@media (max-width: 767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-header,.modal-fullscreen-md-down .modal-footer{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@media (max-width: 991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-header,.modal-fullscreen-lg-down .modal-footer{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@media (max-width: 1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-header,.modal-fullscreen-xl-down .modal-footer{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@media (max-width: 1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xxl-down .modal-header,.modal-fullscreen-xxl-down .modal-footer{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{--bs-tooltip-zindex: 1080;--bs-tooltip-max-width: 200px;--bs-tooltip-padding-x: .5rem;--bs-tooltip-padding-y: .25rem;--bs-tooltip-margin: ;--bs-tooltip-font-size: .875rem;--bs-tooltip-color: #fff;--bs-tooltip-bg: #000;--bs-tooltip-border-radius: .375rem;--bs-tooltip-opacity: .9;--bs-tooltip-arrow-width: .8rem;--bs-tooltip-arrow-height: .4rem;z-index:var(--bs-tooltip-zindex);display:block;padding:var(--bs-tooltip-arrow-height);margin:var(--bs-tooltip-margin);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-tooltip-font-size);word-wrap:break-word;opacity:0}.tooltip.show{opacity:var(--bs-tooltip-opacity)}.tooltip .tooltip-arrow{display:block;width:var(--bs-tooltip-arrow-width);height:var(--bs-tooltip-arrow-height)}.tooltip .tooltip-arrow:before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-top .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow{bottom:0}.bs-tooltip-top .tooltip-arrow:before,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow:before{top:-1px;border-width:var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-top-color:var(--bs-tooltip-bg)}.bs-tooltip-end .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow{left:0;width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-end .tooltip-arrow:before,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow:before{right:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-right-color:var(--bs-tooltip-bg)}.bs-tooltip-bottom .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow{top:0}.bs-tooltip-bottom .tooltip-arrow:before,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow:before{bottom:-1px;border-width:0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-bottom-color:var(--bs-tooltip-bg)}.bs-tooltip-start .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow{right:0;width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-start .tooltip-arrow:before,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow:before{left:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) 0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-left-color:var(--bs-tooltip-bg)}.tooltip-inner{max-width:var(--bs-tooltip-max-width);padding:var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x);color:var(--bs-tooltip-color);text-align:center;background-color:var(--bs-tooltip-bg);border-radius:var(--bs-tooltip-border-radius)}.popover{--bs-popover-zindex: 1070;--bs-popover-max-width: 276px;--bs-popover-font-size: .875rem;--bs-popover-bg: #fff;--bs-popover-border-width: 1px;--bs-popover-border-color: var(--bs-border-color-translucent);--bs-popover-border-radius: .5rem;--bs-popover-inner-border-radius:calc(.5rem - 1px);--bs-popover-box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .15);--bs-popover-header-padding-x: 1rem;--bs-popover-header-padding-y: .5rem;--bs-popover-header-font-size: 1rem;--bs-popover-header-color: ;--bs-popover-header-bg: #f0f0f0;--bs-popover-body-padding-x: 1rem;--bs-popover-body-padding-y: 1rem;--bs-popover-body-color: #212529;--bs-popover-arrow-width: 1rem;--bs-popover-arrow-height: .5rem;--bs-popover-arrow-border: var(--bs-popover-border-color);z-index:var(--bs-popover-zindex);display:block;max-width:var(--bs-popover-max-width);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-popover-font-size);word-wrap:break-word;background-color:var(--bs-popover-bg);background-clip:padding-box;border:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-radius:var(--bs-popover-border-radius)}.popover .popover-arrow{display:block;width:var(--bs-popover-arrow-width);height:var(--bs-popover-arrow-height)}.popover .popover-arrow:before,.popover .popover-arrow:after{position:absolute;display:block;content:"";border-color:transparent;border-style:solid;border-width:0}.bs-popover-top>.popover-arrow,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow{bottom:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-top>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow:before,.bs-popover-top>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow:after{border-width:var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-top>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow:before{bottom:0;border-top-color:var(--bs-popover-arrow-border)}.bs-popover-top>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow:after{bottom:var(--bs-popover-border-width);border-top-color:var(--bs-popover-bg)}.bs-popover-end>.popover-arrow,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow{left:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-end>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow:before,.bs-popover-end>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow:after{border-width:calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-end>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow:before{left:0;border-right-color:var(--bs-popover-arrow-border)}.bs-popover-end>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow:after{left:var(--bs-popover-border-width);border-right-color:var(--bs-popover-bg)}.bs-popover-bottom>.popover-arrow,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow{top:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-bottom>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow:before,.bs-popover-bottom>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow:after{border-width:0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-bottom>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow:before{top:0;border-bottom-color:var(--bs-popover-arrow-border)}.bs-popover-bottom>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow:after{top:var(--bs-popover-border-width);border-bottom-color:var(--bs-popover-bg)}.bs-popover-bottom .popover-header:before,.bs-popover-auto[data-popper-placement^=bottom] .popover-header:before{position:absolute;top:0;left:50%;display:block;width:var(--bs-popover-arrow-width);margin-left:calc(-.5 * var(--bs-popover-arrow-width));content:"";border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-header-bg)}.bs-popover-start>.popover-arrow,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow{right:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-start>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow:before,.bs-popover-start>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow:after{border-width:calc(var(--bs-popover-arrow-width) * .5) 0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-start>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow:before{right:0;border-left-color:var(--bs-popover-arrow-border)}.bs-popover-start>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow:after{right:var(--bs-popover-border-width);border-left-color:var(--bs-popover-bg)}.popover-header{padding:var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x);margin-bottom:0;font-size:var(--bs-popover-header-font-size);color:var(--bs-popover-header-color);background-color:var(--bs-popover-header-bg);border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-top-left-radius:var(--bs-popover-inner-border-radius);border-top-right-radius:var(--bs-popover-inner-border-radius)}.popover-header:empty{display:none}.popover-body{padding:var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x);color:var(--bs-popover-body-color)}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner:after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:transform .6s ease-in-out}@media (prefers-reduced-motion: reduce){.carousel-item{transition:none}}.carousel-item.active,.carousel-item-next,.carousel-item-prev{display:block}.carousel-item-next:not(.carousel-item-start),.active.carousel-item-end{transform:translate(100%)}.carousel-item-prev:not(.carousel-item-end),.active.carousel-item-start{transform:translate(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item.active,.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end{z-index:1;opacity:1}.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion: reduce){.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{transition:none}}.carousel-control-prev,.carousel-control-next{position:absolute;top:0;bottom:0;z-index:1;display:flex;align-items:center;justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:none;border:0;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion: reduce){.carousel-control-prev,.carousel-control-next{transition:none}}.carousel-control-prev:hover,.carousel-control-prev:focus,.carousel-control-next:hover,.carousel-control-next:focus{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-prev-icon,.carousel-control-next-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%;list-style:none}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion: reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-prev-icon,.carousel-dark .carousel-control-next-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}.spinner-grow,.spinner-border{display:inline-block;width:var(--bs-spinner-width);height:var(--bs-spinner-height);vertical-align:var(--bs-spinner-vertical-align);border-radius:50%;animation:var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name)}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{--bs-spinner-width: 2rem;--bs-spinner-height: 2rem;--bs-spinner-vertical-align: -.125em;--bs-spinner-border-width: .25em;--bs-spinner-animation-speed: .75s;--bs-spinner-animation-name: spinner-border;border:var(--bs-spinner-border-width) solid currentcolor;border-right-color:transparent}.spinner-border-sm{--bs-spinner-width: 1rem;--bs-spinner-height: 1rem;--bs-spinner-border-width: .2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{--bs-spinner-width: 2rem;--bs-spinner-height: 2rem;--bs-spinner-vertical-align: -.125em;--bs-spinner-animation-speed: .75s;--bs-spinner-animation-name: spinner-grow;background-color:currentcolor;opacity:0}.spinner-grow-sm{--bs-spinner-width: 1rem;--bs-spinner-height: 1rem}@media (prefers-reduced-motion: reduce){.spinner-border,.spinner-grow{--bs-spinner-animation-speed: 1.5s}}.offcanvas,.offcanvas-xxl,.offcanvas-xl,.offcanvas-lg,.offcanvas-md,.offcanvas-sm{--bs-offcanvas-zindex: 1045;--bs-offcanvas-width: 400px;--bs-offcanvas-height: 30vh;--bs-offcanvas-padding-x: 1rem;--bs-offcanvas-padding-y: 1rem;--bs-offcanvas-color: ;--bs-offcanvas-bg: #fff;--bs-offcanvas-border-width: 1px;--bs-offcanvas-border-color: var(--bs-border-color-translucent);--bs-offcanvas-box-shadow: 0 .125rem .25rem rgba(0, 0, 0, .075)}@media (max-width: 575.98px){.offcanvas-sm{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:transform .3s ease-in-out}}@media (max-width: 575.98px) and (prefers-reduced-motion: reduce){.offcanvas-sm{transition:none}}@media (max-width: 575.98px){.offcanvas-sm.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(-100%)}}@media (max-width: 575.98px){.offcanvas-sm.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(100%)}}@media (max-width: 575.98px){.offcanvas-sm.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}}@media (max-width: 575.98px){.offcanvas-sm.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}}@media (max-width: 575.98px){.offcanvas-sm.showing,.offcanvas-sm.show:not(.hiding){transform:none}}@media (max-width: 575.98px){.offcanvas-sm.showing,.offcanvas-sm.hiding,.offcanvas-sm.show{visibility:visible}}@media (min-width: 576px){.offcanvas-sm{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-sm .offcanvas-header{display:none}.offcanvas-sm .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width: 767.98px){.offcanvas-md{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:transform .3s ease-in-out}}@media (max-width: 767.98px) and (prefers-reduced-motion: reduce){.offcanvas-md{transition:none}}@media (max-width: 767.98px){.offcanvas-md.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(-100%)}}@media (max-width: 767.98px){.offcanvas-md.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(100%)}}@media (max-width: 767.98px){.offcanvas-md.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}}@media (max-width: 767.98px){.offcanvas-md.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}}@media (max-width: 767.98px){.offcanvas-md.showing,.offcanvas-md.show:not(.hiding){transform:none}}@media (max-width: 767.98px){.offcanvas-md.showing,.offcanvas-md.hiding,.offcanvas-md.show{visibility:visible}}@media (min-width: 768px){.offcanvas-md{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-md .offcanvas-header{display:none}.offcanvas-md .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width: 991.98px){.offcanvas-lg{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:transform .3s ease-in-out}}@media (max-width: 991.98px) and (prefers-reduced-motion: reduce){.offcanvas-lg{transition:none}}@media (max-width: 991.98px){.offcanvas-lg.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(-100%)}}@media (max-width: 991.98px){.offcanvas-lg.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(100%)}}@media (max-width: 991.98px){.offcanvas-lg.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}}@media (max-width: 991.98px){.offcanvas-lg.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}}@media (max-width: 991.98px){.offcanvas-lg.showing,.offcanvas-lg.show:not(.hiding){transform:none}}@media (max-width: 991.98px){.offcanvas-lg.showing,.offcanvas-lg.hiding,.offcanvas-lg.show{visibility:visible}}@media (min-width: 992px){.offcanvas-lg{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-lg .offcanvas-header{display:none}.offcanvas-lg .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width: 1199.98px){.offcanvas-xl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:transform .3s ease-in-out}}@media (max-width: 1199.98px) and (prefers-reduced-motion: reduce){.offcanvas-xl{transition:none}}@media (max-width: 1199.98px){.offcanvas-xl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(-100%)}}@media (max-width: 1199.98px){.offcanvas-xl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(100%)}}@media (max-width: 1199.98px){.offcanvas-xl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}}@media (max-width: 1199.98px){.offcanvas-xl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}}@media (max-width: 1199.98px){.offcanvas-xl.showing,.offcanvas-xl.show:not(.hiding){transform:none}}@media (max-width: 1199.98px){.offcanvas-xl.showing,.offcanvas-xl.hiding,.offcanvas-xl.show{visibility:visible}}@media (min-width: 1200px){.offcanvas-xl{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-xl .offcanvas-header{display:none}.offcanvas-xl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width: 1399.98px){.offcanvas-xxl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:transform .3s ease-in-out}}@media (max-width: 1399.98px) and (prefers-reduced-motion: reduce){.offcanvas-xxl{transition:none}}@media (max-width: 1399.98px){.offcanvas-xxl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(-100%)}}@media (max-width: 1399.98px){.offcanvas-xxl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(100%)}}@media (max-width: 1399.98px){.offcanvas-xxl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}}@media (max-width: 1399.98px){.offcanvas-xxl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}}@media (max-width: 1399.98px){.offcanvas-xxl.showing,.offcanvas-xxl.show:not(.hiding){transform:none}}@media (max-width: 1399.98px){.offcanvas-xxl.showing,.offcanvas-xxl.hiding,.offcanvas-xxl.show{visibility:visible}}@media (min-width: 1400px){.offcanvas-xxl{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-xxl .offcanvas-header{display:none}.offcanvas-xxl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}.offcanvas{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:transform .3s ease-in-out}@media (prefers-reduced-motion: reduce){.offcanvas{transition:none}}.offcanvas.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(-100%)}.offcanvas.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(100%)}.offcanvas.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas.showing,.offcanvas.show:not(.hiding){transform:none}.offcanvas.showing,.offcanvas.hiding,.offcanvas.show{visibility:visible}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;align-items:center;justify-content:space-between;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x)}.offcanvas-header .btn-close{padding:calc(var(--bs-offcanvas-padding-y) * .5) calc(var(--bs-offcanvas-padding-x) * .5);margin-top:calc(-.5 * var(--bs-offcanvas-padding-y));margin-right:calc(-.5 * var(--bs-offcanvas-padding-x));margin-bottom:calc(-.5 * var(--bs-offcanvas-padding-y))}.offcanvas-title{margin-bottom:0;line-height:1.5}.offcanvas-body{flex-grow:1;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);overflow-y:auto}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentcolor;opacity:.5}.placeholder.btn:before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{-webkit-mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,.8) 75%,#000 95%);mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,.8) 75%,#000 95%);-webkit-mask-size:200% 100%;mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{to{-webkit-mask-position:-200% 0%;mask-position:-200% 0%}}.clearfix:after{display:block;clear:both;content:""}.text-bg-primary{color:#fff!important;background-color:RGBA(13,110,253,var(--bs-bg-opacity, 1))!important}.text-bg-secondary{color:#fff!important;background-color:RGBA(108,117,125,var(--bs-bg-opacity, 1))!important}.text-bg-success{color:#fff!important;background-color:RGBA(25,135,84,var(--bs-bg-opacity, 1))!important}.text-bg-info{color:#000!important;background-color:RGBA(13,202,240,var(--bs-bg-opacity, 1))!important}.text-bg-warning{color:#000!important;background-color:RGBA(255,193,7,var(--bs-bg-opacity, 1))!important}.text-bg-danger{color:#fff!important;background-color:RGBA(220,53,69,var(--bs-bg-opacity, 1))!important}.text-bg-light{color:#000!important;background-color:RGBA(248,249,250,var(--bs-bg-opacity, 1))!important}.text-bg-dark{color:#fff!important;background-color:RGBA(33,37,41,var(--bs-bg-opacity, 1))!important}.link-primary{color:#0d6efd!important}.link-primary:hover,.link-primary:focus{color:#0a58ca!important}.link-secondary{color:#6c757d!important}.link-secondary:hover,.link-secondary:focus{color:#565e64!important}.link-success{color:#198754!important}.link-success:hover,.link-success:focus{color:#146c43!important}.link-info{color:#0dcaf0!important}.link-info:hover,.link-info:focus{color:#3dd5f3!important}.link-warning{color:#ffc107!important}.link-warning:hover,.link-warning:focus{color:#ffcd39!important}.link-danger{color:#dc3545!important}.link-danger:hover,.link-danger:focus{color:#b02a37!important}.link-light{color:#f8f9fa!important}.link-light:hover,.link-light:focus{color:#f9fafb!important}.link-dark{color:#212529!important}.link-dark:hover,.link-dark:focus{color:#1a1e21!important}.ratio{position:relative;width:100%}.ratio:before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio: 100%}.ratio-4x3{--bs-aspect-ratio: 75%}.ratio-16x9{--bs-aspect-ratio: 56.25%}.ratio-21x9{--bs-aspect-ratio: 42.8571428571%}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:sticky;top:0;z-index:1020}.sticky-bottom{position:sticky;bottom:0;z-index:1020}@media (min-width: 576px){.sticky-sm-top{position:sticky;top:0;z-index:1020}.sticky-sm-bottom{position:sticky;bottom:0;z-index:1020}}@media (min-width: 768px){.sticky-md-top{position:sticky;top:0;z-index:1020}.sticky-md-bottom{position:sticky;bottom:0;z-index:1020}}@media (min-width: 992px){.sticky-lg-top{position:sticky;top:0;z-index:1020}.sticky-lg-bottom{position:sticky;bottom:0;z-index:1020}}@media (min-width: 1200px){.sticky-xl-top{position:sticky;top:0;z-index:1020}.sticky-xl-bottom{position:sticky;bottom:0;z-index:1020}}@media (min-width: 1400px){.sticky-xxl-top{position:sticky;top:0;z-index:1020}.sticky-xxl-bottom{position:sticky;bottom:0;z-index:1020}}.hstack{display:flex;flex-direction:row;align-items:center;align-self:stretch}.vstack{display:flex;flex:1 1 auto;flex-direction:column;align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.stretched-link:after{position:absolute;inset:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;width:1px;min-height:1em;background-color:currentcolor;opacity:.25}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.float-start{float:left!important}.float-end{float:right!important}.float-none{float:none!important}.opacity-0{opacity:0!important}.opacity-25{opacity:.25!important}.opacity-50{opacity:.5!important}.opacity-75{opacity:.75!important}.opacity-100{opacity:1!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-visible{overflow:visible!important}.overflow-scroll{overflow:scroll!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-grid{display: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}.shadow{box-shadow:0 .5rem 1rem #00000026!important}.shadow-sm{box-shadow:0 .125rem .25rem #00000013!important}.shadow-lg{box-shadow:0 1rem 3rem #0000002d!important}.shadow-none{box-shadow:none!important}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:sticky!important}.top-0{top:0!important}.top-50{top:50%!important}.top-100{top:100%!important}.bottom-0{bottom:0!important}.bottom-50{bottom:50%!important}.bottom-100{bottom:100%!important}.start-0{left:0!important}.start-50{left:50%!important}.start-100{left:100%!important}.end-0{right:0!important}.end-50{right:50%!important}.end-100{right:100%!important}.translate-middle{transform:translate(-50%,-50%)!important}.translate-middle-x{transform:translate(-50%)!important}.translate-middle-y{transform:translateY(-50%)!important}.border{border:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-0{border:0!important}.border-top{border-top:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-top-0{border-top:0!important}.border-end{border-right:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-end-0{border-right:0!important}.border-bottom{border-bottom:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-bottom-0{border-bottom:0!important}.border-start{border-left:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-start-0{border-left:0!important}.border-primary{--bs-border-opacity: 1;border-color:rgba(var(--bs-primary-rgb),var(--bs-border-opacity))!important}.border-secondary{--bs-border-opacity: 1;border-color:rgba(var(--bs-secondary-rgb),var(--bs-border-opacity))!important}.border-success{--bs-border-opacity: 1;border-color:rgba(var(--bs-success-rgb),var(--bs-border-opacity))!important}.border-info{--bs-border-opacity: 1;border-color:rgba(var(--bs-info-rgb),var(--bs-border-opacity))!important}.border-warning{--bs-border-opacity: 1;border-color:rgba(var(--bs-warning-rgb),var(--bs-border-opacity))!important}.border-danger{--bs-border-opacity: 1;border-color:rgba(var(--bs-danger-rgb),var(--bs-border-opacity))!important}.border-light{--bs-border-opacity: 1;border-color:rgba(var(--bs-light-rgb),var(--bs-border-opacity))!important}.border-dark{--bs-border-opacity: 1;border-color:rgba(var(--bs-dark-rgb),var(--bs-border-opacity))!important}.border-white{--bs-border-opacity: 1;border-color:rgba(var(--bs-white-rgb),var(--bs-border-opacity))!important}.border-1{--bs-border-width: 1px}.border-2{--bs-border-width: 2px}.border-3{--bs-border-width: 3px}.border-4{--bs-border-width: 4px}.border-5{--bs-border-width: 5px}.border-opacity-10{--bs-border-opacity: .1}.border-opacity-25{--bs-border-opacity: .25}.border-opacity-50{--bs-border-opacity: .5}.border-opacity-75{--bs-border-opacity: .75}.border-opacity-100{--bs-border-opacity: 1}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.mw-100{max-width:100%!important}.vw-100{width:100vw!important}.min-vw-100{min-width:100vw!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mh-100{max-height:100%!important}.vh-100{height:100vh!important}.min-vh-100{min-height:100vh!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}.gap-0{gap:0!important}.gap-1{gap:.25rem!important}.gap-2{gap:.5rem!important}.gap-3{gap:1rem!important}.gap-4{gap:1.5rem!important}.gap-5{gap:3rem!important}.font-monospace{font-family:var(--bs-font-monospace)!important}.fs-1{font-size:calc(1.375rem + 1.5vw)!important}.fs-2{font-size:calc(1.325rem + .9vw)!important}.fs-3{font-size:calc(1.3rem + .6vw)!important}.fs-4{font-size:calc(1.275rem + .3vw)!important}.fs-5{font-size:1.25rem!important}.fs-6{font-size:1rem!important}.fst-italic{font-style:italic!important}.fst-normal{font-style:normal!important}.fw-light{font-weight:300!important}.fw-lighter{font-weight:lighter!important}.fw-normal{font-weight:400!important}.fw-bold{font-weight:700!important}.fw-semibold{font-weight:600!important}.fw-bolder{font-weight:bolder!important}.lh-1{line-height:1!important}.lh-sm{line-height:1.25!important}.lh-base{line-height:1.5!important}.lh-lg{line-height:2!important}.text-start{text-align:left!important}.text-end{text-align:right!important}.text-center{text-align:center!important}.text-decoration-none{text-decoration:none!important}.text-decoration-underline{text-decoration:underline!important}.text-decoration-line-through{text-decoration:line-through!important}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-break{word-wrap:break-word!important;word-break:break-word!important}.text-primary{--bs-text-opacity: 1;color:rgba(var(--bs-primary-rgb),var(--bs-text-opacity))!important}.text-secondary{--bs-text-opacity: 1;color:rgba(var(--bs-secondary-rgb),var(--bs-text-opacity))!important}.text-success{--bs-text-opacity: 1;color:rgba(var(--bs-success-rgb),var(--bs-text-opacity))!important}.text-info{--bs-text-opacity: 1;color:rgba(var(--bs-info-rgb),var(--bs-text-opacity))!important}.text-warning{--bs-text-opacity: 1;color:rgba(var(--bs-warning-rgb),var(--bs-text-opacity))!important}.text-danger{--bs-text-opacity: 1;color:rgba(var(--bs-danger-rgb),var(--bs-text-opacity))!important}.text-light{--bs-text-opacity: 1;color:rgba(var(--bs-light-rgb),var(--bs-text-opacity))!important}.text-dark{--bs-text-opacity: 1;color:rgba(var(--bs-dark-rgb),var(--bs-text-opacity))!important}.text-black{--bs-text-opacity: 1;color:rgba(var(--bs-black-rgb),var(--bs-text-opacity))!important}.text-white{--bs-text-opacity: 1;color:rgba(var(--bs-white-rgb),var(--bs-text-opacity))!important}.text-body{--bs-text-opacity: 1;color:rgba(var(--bs-body-color-rgb),var(--bs-text-opacity))!important}.text-muted{--bs-text-opacity: 1;color:#6c757d!important}.text-black-50{--bs-text-opacity: 1;color:#00000080!important}.text-white-50{--bs-text-opacity: 1;color:#ffffff80!important}.text-reset{--bs-text-opacity: 1;color:inherit!important}.text-opacity-25{--bs-text-opacity: .25}.text-opacity-50{--bs-text-opacity: .5}.text-opacity-75{--bs-text-opacity: .75}.text-opacity-100{--bs-text-opacity: 1}.bg-primary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-primary-rgb),var(--bs-bg-opacity))!important}.bg-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-rgb),var(--bs-bg-opacity))!important}.bg-success{--bs-bg-opacity: 1;background-color:rgba(var(--bs-success-rgb),var(--bs-bg-opacity))!important}.bg-info{--bs-bg-opacity: 1;background-color:rgba(var(--bs-info-rgb),var(--bs-bg-opacity))!important}.bg-warning{--bs-bg-opacity: 1;background-color:rgba(var(--bs-warning-rgb),var(--bs-bg-opacity))!important}.bg-danger{--bs-bg-opacity: 1;background-color:rgba(var(--bs-danger-rgb),var(--bs-bg-opacity))!important}.bg-light{--bs-bg-opacity: 1;background-color:rgba(var(--bs-light-rgb),var(--bs-bg-opacity))!important}.bg-dark{--bs-bg-opacity: 1;background-color:rgba(var(--bs-dark-rgb),var(--bs-bg-opacity))!important}.bg-black{--bs-bg-opacity: 1;background-color:rgba(var(--bs-black-rgb),var(--bs-bg-opacity))!important}.bg-white{--bs-bg-opacity: 1;background-color:rgba(var(--bs-white-rgb),var(--bs-bg-opacity))!important}.bg-body{--bs-bg-opacity: 1;background-color:rgba(var(--bs-body-bg-rgb),var(--bs-bg-opacity))!important}.bg-transparent{--bs-bg-opacity: 1;background-color:transparent!important}.bg-opacity-10{--bs-bg-opacity: .1}.bg-opacity-25{--bs-bg-opacity: .25}.bg-opacity-50{--bs-bg-opacity: .5}.bg-opacity-75{--bs-bg-opacity: .75}.bg-opacity-100{--bs-bg-opacity: 1}.bg-gradient{background-image:var(--bs-gradient)!important}.user-select-all{-webkit-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;user-select:none!important}.pe-none{pointer-events:none!important}.pe-auto{pointer-events:auto!important}.rounded{border-radius:var(--bs-border-radius)!important}.rounded-0{border-radius:0!important}.rounded-1{border-radius:var(--bs-border-radius-sm)!important}.rounded-2{border-radius:var(--bs-border-radius)!important}.rounded-3{border-radius:var(--bs-border-radius-lg)!important}.rounded-4{border-radius:var(--bs-border-radius-xl)!important}.rounded-5{border-radius:var(--bs-border-radius-2xl)!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:var(--bs-border-radius-pill)!important}.rounded-top{border-top-left-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-end{border-top-right-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-bottom{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-start{border-bottom-left-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media (min-width: 576px){.float-sm-start{float:left!important}.float-sm-end{float:right!important}.float-sm-none{float:none!important}.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-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}.gap-sm-0{gap:0!important}.gap-sm-1{gap:.25rem!important}.gap-sm-2{gap:.5rem!important}.gap-sm-3{gap:1rem!important}.gap-sm-4{gap:1.5rem!important}.gap-sm-5{gap:3rem!important}.text-sm-start{text-align:left!important}.text-sm-end{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width: 768px){.float-md-start{float:left!important}.float-md-end{float:right!important}.float-md-none{float:none!important}.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-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}.gap-md-0{gap:0!important}.gap-md-1{gap:.25rem!important}.gap-md-2{gap:.5rem!important}.gap-md-3{gap:1rem!important}.gap-md-4{gap:1.5rem!important}.gap-md-5{gap:3rem!important}.text-md-start{text-align:left!important}.text-md-end{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width: 992px){.float-lg-start{float:left!important}.float-lg-end{float:right!important}.float-lg-none{float:none!important}.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-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}.gap-lg-0{gap:0!important}.gap-lg-1{gap:.25rem!important}.gap-lg-2{gap:.5rem!important}.gap-lg-3{gap:1rem!important}.gap-lg-4{gap:1.5rem!important}.gap-lg-5{gap:3rem!important}.text-lg-start{text-align:left!important}.text-lg-end{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width: 1200px){.float-xl-start{float:left!important}.float-xl-end{float:right!important}.float-xl-none{float:none!important}.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-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}.gap-xl-0{gap:0!important}.gap-xl-1{gap:.25rem!important}.gap-xl-2{gap:.5rem!important}.gap-xl-3{gap:1rem!important}.gap-xl-4{gap:1.5rem!important}.gap-xl-5{gap:3rem!important}.text-xl-start{text-align:left!important}.text-xl-end{text-align:right!important}.text-xl-center{text-align:center!important}}@media (min-width: 1400px){.float-xxl-start{float:left!important}.float-xxl-end{float:right!important}.float-xxl-none{float:none!important}.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-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}.gap-xxl-0{gap:0!important}.gap-xxl-1{gap:.25rem!important}.gap-xxl-2{gap:.5rem!important}.gap-xxl-3{gap:1rem!important}.gap-xxl-4{gap:1.5rem!important}.gap-xxl-5{gap:3rem!important}.text-xxl-start{text-align:left!important}.text-xxl-end{text-align:right!important}.text-xxl-center{text-align:center!important}}@media (min-width: 1200px){.fs-1{font-size:2.5rem!important}.fs-2{font-size:2rem!important}.fs-3{font-size:1.75rem!important}.fs-4{font-size:1.5rem!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-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}} + */: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, .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, .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, .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-bg: #fff3cd;--bs-border-width: 1px;--bs-border-style: solid;--bs-border-color: #dee2e6;--bs-border-color-translucent: rgba(0, 0, 0, .175);--bs-border-radius: .375rem;--bs-border-radius-sm: .25rem;--bs-border-radius-lg: .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 .5rem 1rem rgba(0, 0, 0, .15);--bs-box-shadow-sm: 0 .125rem .25rem rgba(0, 0, 0, .075);--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, .175);--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, .075);--bs-focus-ring-width: .25rem;--bs-focus-ring-opacity: .25;--bs-focus-ring-color: rgba(13, 110, 253, .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: #adb5bd;--bs-body-color-rgb: 173, 181, 189;--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(173, 181, 189, .75);--bs-secondary-color-rgb: 173, 181, 189;--bs-secondary-bg: #343a40;--bs-secondary-bg-rgb: 52, 58, 64;--bs-tertiary-color: rgba(173, 181, 189, .5);--bs-tertiary-color-rgb: 173, 181, 189;--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-border-color: #495057;--bs-border-color-translucent: rgba(255, 255, 255, .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:.25}h6,.h6,h5,.h5,h4,.h4,h3,.h3,h2,.h2,h1,.h1{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2;color:var(--bs-heading-color)}h1,.h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width: 1200px){h1,.h1{font-size:2.5rem}}h2,.h2{font-size:calc(1.325rem + .9vw)}@media (min-width: 1200px){h2,.h2{font-size:2rem}}h3,.h3{font-size:calc(1.3rem + .6vw)}@media (min-width: 1200px){h3,.h3{font-size:1.75rem}}h4,.h4{font-size:calc(1.275rem + .3vw)}@media (min-width: 1200px){h4,.h4{font-size:1.5rem}}h5,.h5{font-size:1.25rem}h6,.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:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small,.small{font-size:.875em}mark,.mark{padding:.1875em;background-color:var(--bs-highlight-bg)}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.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:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:var(--bs-code-color);word-wrap:break-word}a>code{color:inherit}kbd{padding:.1875rem .375rem;font-size:.875em;color:var(--bs-body-bg);background-color:var(--bs-body-color);border-radius:.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:.5rem;padding-bottom:.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:.5rem;font-size:calc(1.275rem + .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]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::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}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media (min-width: 1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media (min-width: 1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media (min-width: 1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media (min-width: 1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media (min-width: 1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media (min-width: 1200px){.display-6{font-size:2.5rem}}.list-unstyled,.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:.875em;color:#6c757d}.blockquote-footer:before{content:"\2014\a0"}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:var(--bs-body-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:.875em;color:var(--bs-secondary-color)}.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-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-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-right:calc(-.5 * var(--bs-gutter-x));margin-left:calc(-.5 * var(--bs-gutter-x))}.row>*{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.3333333333%}.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.6666666667%}.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: .25rem}.g-1,.gy-1{--bs-gutter-y: .25rem}.g-2,.gx-2{--bs-gutter-x: .5rem}.g-2,.gy-2{--bs-gutter-y: .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.3333333333%}.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.6666666667%}.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: .25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y: .25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x: .5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y: .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.3333333333%}.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.6666666667%}.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: .25rem}.g-md-1,.gy-md-1{--bs-gutter-y: .25rem}.g-md-2,.gx-md-2{--bs-gutter-x: .5rem}.g-md-2,.gy-md-2{--bs-gutter-y: .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.3333333333%}.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.6666666667%}.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: .25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y: .25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x: .5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y: .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.3333333333%}.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.6666666667%}.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: .25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y: .25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x: .5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y: .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.3333333333%}.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.6666666667%}.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: .25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y: .25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x: .5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y: .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}}.table{--bs-table-color-type: initial;--bs-table-bg-type: initial;--bs-table-color-state: initial;--bs-table-bg-state: initial;--bs-table-color: var(--bs-body-color);--bs-table-bg: var(--bs-body-bg);--bs-table-border-color: var(--bs-border-color);--bs-table-accent-bg: transparent;--bs-table-striped-color: var(--bs-body-color);--bs-table-striped-bg: rgba(0, 0, 0, .05);--bs-table-active-color: var(--bs-body-color);--bs-table-active-bg: rgba(0, 0, 0, .1);--bs-table-hover-color: var(--bs-body-color);--bs-table-hover-bg: rgba(0, 0, 0, .075);width:100%;margin-bottom:1rem;vertical-align:top;border-color:var(--bs-table-border-color)}.table>:not(caption)>*>*{padding:.5rem;color:var(--bs-table-color-state, var(--bs-table-color-type, var(--bs-table-color)));background-color:var(--bs-table-bg);border-bottom-width:var(--bs-border-width);box-shadow:inset 0 0 0 9999px var(--bs-table-bg-state, var(--bs-table-bg-type, var(--bs-table-accent-bg)))}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table-group-divider{border-top:calc(var(--bs-border-width) * 2) solid currentcolor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem}.table-bordered>:not(caption)>*{border-width:var(--bs-border-width) 0}.table-bordered>:not(caption)>*>*{border-width:0 var(--bs-border-width)}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-color-type: var(--bs-table-striped-color);--bs-table-bg-type: var(--bs-table-striped-bg)}.table-striped-columns>:not(caption)>tr>:nth-child(even){--bs-table-color-type: var(--bs-table-striped-color);--bs-table-bg-type: var(--bs-table-striped-bg)}.table-active{--bs-table-color-state: var(--bs-table-active-color);--bs-table-bg-state: var(--bs-table-active-bg)}.table-hover>tbody>tr:hover>*{--bs-table-color-state: var(--bs-table-hover-color);--bs-table-bg-state: var(--bs-table-hover-bg)}.table-primary{--bs-table-color: #000;--bs-table-bg: #cfe2ff;--bs-table-border-color: #bacbe6;--bs-table-striped-bg: #c5d7f2;--bs-table-striped-color: #000;--bs-table-active-bg: #bacbe6;--bs-table-active-color: #000;--bs-table-hover-bg: #bfd1ec;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-secondary{--bs-table-color: #000;--bs-table-bg: #e2e3e5;--bs-table-border-color: #cbccce;--bs-table-striped-bg: #d7d8da;--bs-table-striped-color: #000;--bs-table-active-bg: #cbccce;--bs-table-active-color: #000;--bs-table-hover-bg: #d1d2d4;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-success{--bs-table-color: #000;--bs-table-bg: #d1e7dd;--bs-table-border-color: #bcd0c7;--bs-table-striped-bg: #c7dbd2;--bs-table-striped-color: #000;--bs-table-active-bg: #bcd0c7;--bs-table-active-color: #000;--bs-table-hover-bg: #c1d6cc;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-info{--bs-table-color: #000;--bs-table-bg: #cff4fc;--bs-table-border-color: #badce3;--bs-table-striped-bg: #c5e8ef;--bs-table-striped-color: #000;--bs-table-active-bg: #badce3;--bs-table-active-color: #000;--bs-table-hover-bg: #bfe2e9;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-warning{--bs-table-color: #000;--bs-table-bg: #fff3cd;--bs-table-border-color: #e6dbb9;--bs-table-striped-bg: #f2e7c3;--bs-table-striped-color: #000;--bs-table-active-bg: #e6dbb9;--bs-table-active-color: #000;--bs-table-hover-bg: #ece1be;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-danger{--bs-table-color: #000;--bs-table-bg: #f8d7da;--bs-table-border-color: #dfc2c4;--bs-table-striped-bg: #eccccf;--bs-table-striped-color: #000;--bs-table-active-bg: #dfc2c4;--bs-table-active-color: #000;--bs-table-hover-bg: #e5c7ca;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-light{--bs-table-color: #000;--bs-table-bg: #f8f9fa;--bs-table-border-color: #dfe0e1;--bs-table-striped-bg: #ecedee;--bs-table-striped-color: #000;--bs-table-active-bg: #dfe0e1;--bs-table-active-color: #000;--bs-table-hover-bg: #e5e6e7;--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-dark{--bs-table-color: #fff;--bs-table-bg: #212529;--bs-table-border-color: #373b3e;--bs-table-striped-bg: #2c3034;--bs-table-striped-color: #fff;--bs-table-active-bg: #373b3e;--bs-table-active-color: #fff;--bs-table-hover-bg: #323539;--bs-table-hover-color: #fff;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media (max-width: 575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width: 767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width: 991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width: 1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width: 1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(.375rem + var(--bs-border-width));padding-bottom:calc(.375rem + var(--bs-border-width));margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + var(--bs-border-width));padding-bottom:calc(.5rem + var(--bs-border-width));font-size:1.25rem}.col-form-label-sm{padding-top:calc(.25rem + var(--bs-border-width));padding-bottom:calc(.25rem + var(--bs-border-width));font-size:.875rem}.form-text{margin-top:.25rem;font-size:.875em;color:var(--bs-secondary-color)}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);background-color:var(--bs-body-bg);background-clip:padding-box;border:var(--bs-border-width) solid var(--bs-border-color);-webkit-appearance:none;appearance:none;border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:var(--bs-body-color);background-color:var(--bs-body-bg);border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem #0d6efd40}.form-control::-webkit-date-and-time-value{min-width:85px;height:1.5em;margin:0}.form-control::-webkit-datetime-edit{display:block;padding:0}.form-control::placeholder{color:var(--bs-secondary-color);opacity:1}.form-control:disabled{background-color:var(--bs-secondary-bg);opacity:1}.form-control::file-selector-button{padding:.375rem .75rem;margin:-.375rem -.75rem;margin-inline-end:.75rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--bs-border-width);border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:var(--bs-secondary-bg)}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:var(--bs-body-color);background-color:transparent;border:solid transparent;border-width:var(--bs-border-width) 0}.form-control-plaintext:focus{outline:0}.form-control-plaintext.form-control-sm,.form-control-plaintext.form-control-lg{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2));padding:.25rem .5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-.25rem -.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2));padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-.5rem -1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + .75rem + calc(var(--bs-border-width) * 2))}textarea.form-control-sm{min-height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2))}textarea.form-control-lg{min-height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2))}.form-control-color{width:3rem;height:calc(1.5em + .75rem + calc(var(--bs-border-width) * 2));padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{border:0!important;border-radius:var(--bs-border-radius)}.form-control-color::-webkit-color-swatch{border:0!important;border-radius:var(--bs-border-radius)}.form-control-color.form-control-sm{height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2))}.form-control-color.form-control-lg{height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2))}.form-select{--bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);background-color:var(--bs-body-bg);background-image:var(--bs-form-select-bg-img),var(--bs-form-select-bg-icon, none);background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;appearance:none}@media (prefers-reduced-motion: reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem #0d6efd40}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:var(--bs-secondary-bg)}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 var(--bs-body-color)}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}[data-bs-theme=dark] .form-select{--bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23adb5bd' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e")}.form-check{display:block;min-height:1.5rem;padding-left:1.5em;margin-bottom:.125rem}.form-check .form-check-input{float:left;margin-left:-1.5em}.form-check-reverse{padding-right:1.5em;padding-left:0;text-align:right}.form-check-reverse .form-check-input{float:right;margin-right:-1.5em;margin-left:0}.form-check-input{--bs-form-check-bg: var(--bs-body-bg);width:1em;height:1em;margin-top:.25em;vertical-align:top;background-color:var(--bs-form-check-bg);background-image:var(--bs-form-check-bg-image);background-repeat:no-repeat;background-position:center;background-size:contain;border:var(--bs-border-width) solid var(--bs-border-color);-webkit-appearance:none;appearance:none;-webkit-print-color-adjust:exact;print-color-adjust:exact}.form-check-input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem #0d6efd40}.form-check-input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox]{--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input[disabled]~.form-check-label,.form-check-input:disabled~.form-check-label{cursor:default;opacity:.5}.form-switch{padding-left:2.5em}.form-switch .form-check-input{--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");width:2em;margin-left:-2.5em;background-image:var(--bs-form-switch-bg);background-position:left center;border-radius:2em;transition:background-position .15s ease-in-out}@media (prefers-reduced-motion: reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-switch.form-check-reverse{padding-right:2.5em;padding-left:0}.form-switch.form-check-reverse .form-check-input{margin-right:-2.5em;margin-left:0}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.btn-check[disabled]+.btn,.btn-check:disabled+.btn{pointer-events:none;filter:none;opacity:.65}[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e")}.form-range{width:100%;height:1.5rem;padding:0;background-color:transparent;-webkit-appearance:none;appearance:none}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem #0d6efd40}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem #0d6efd40}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#0d6efd;border:0;border-radius:1rem;-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;appearance:none}@media (prefers-reduced-motion: reduce){.form-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-tertiary-bg);border-color:transparent;border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#0d6efd;border:0;border-radius:1rem;-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none}@media (prefers-reduced-motion: reduce){.form-range::-moz-range-thumb{-moz-transition:none;transition:none}}.form-range::-moz-range-thumb:active{background-color:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-tertiary-bg);border-color:transparent;border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:var(--bs-secondary-color)}.form-range:disabled::-moz-range-thumb{background-color:var(--bs-secondary-color)}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-control-plaintext,.form-floating>.form-select{height:calc(3.5rem + calc(var(--bs-border-width) * 2));min-height:calc(3.5rem + calc(var(--bs-border-width) * 2));line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;z-index:2;height:100%;padding:1rem .75rem;overflow:hidden;text-align:start;text-overflow:ellipsis;white-space:nowrap;pointer-events:none;border:var(--bs-border-width) solid transparent;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media (prefers-reduced-motion: reduce){.form-floating>label{transition:none}}.form-floating>.form-control,.form-floating>.form-control-plaintext{padding:1rem .75rem}.form-floating>.form-control::placeholder,.form-floating>.form-control-plaintext::placeholder{color:transparent}.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown),.form-floating>.form-control-plaintext:focus,.form-floating>.form-control-plaintext:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:-webkit-autofill,.form-floating>.form-control-plaintext:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-control-plaintext~label,.form-floating>.form-select~label{color:rgba(var(--bs-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translate(.15rem)}.form-floating>.form-control:focus~label:after,.form-floating>.form-control:not(:placeholder-shown)~label:after,.form-floating>.form-control-plaintext~label:after,.form-floating>.form-select~label:after{position:absolute;inset:1rem .375rem;z-index:-1;height:1.5em;content:"";background-color:var(--bs-body-bg);border-radius:var(--bs-border-radius)}.form-floating>.form-control:-webkit-autofill~label{color:rgba(var(--bs-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translate(.15rem)}.form-floating>.form-control-plaintext~label{border-width:var(--bs-border-width) 0}.form-floating>:disabled~label{color:#6c757d}.form-floating>:disabled~label:after{background-color:var(--bs-secondary-bg)}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-select,.input-group>.form-floating{position:relative;flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-select:focus,.input-group>.form-floating:focus-within{z-index:5}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:5}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);text-align:center;white-space:nowrap;background-color:var(--bs-tertiary-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius)}.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text,.input-group-lg>.btn{padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text,.input-group-sm>.btn{padding:.25rem .5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-control,.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-select{border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-control,.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-select{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:calc(var(--bs-border-width) * -1);border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.form-floating:not(:first-child)>.form-control,.input-group>.form-floating:not(:first-child)>.form-select{border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-valid-color)}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-success);border-radius:var(--bs-border-radius)}.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip,.is-valid~.valid-feedback,.is-valid~.valid-tooltip{display:block}.was-validated .form-control:valid,.form-control.is-valid{border-color:var(--bs-form-valid-border-color);padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.was-validated .form-control:valid:focus,.form-control.is-valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.was-validated .form-select:valid,.form-select.is-valid{border-color:var(--bs-form-valid-border-color)}.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"],.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"]{--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.was-validated .form-select:valid:focus,.form-select.is-valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.was-validated .form-control-color:valid,.form-control-color.is-valid{width:calc(3.75rem + 1.5em)}.was-validated .form-check-input:valid,.form-check-input.is-valid{border-color:var(--bs-form-valid-border-color)}.was-validated .form-check-input:valid:checked,.form-check-input.is-valid:checked{background-color:var(--bs-form-valid-color)}.was-validated .form-check-input:valid:focus,.form-check-input.is-valid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.was-validated .form-check-input:valid~.form-check-label,.form-check-input.is-valid~.form-check-label{color:var(--bs-form-valid-color)}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.was-validated .input-group>.form-control:not(:focus):valid,.input-group>.form-control:not(:focus).is-valid,.was-validated .input-group>.form-select:not(:focus):valid,.input-group>.form-select:not(:focus).is-valid,.was-validated .input-group>.form-floating:not(:focus-within):valid,.input-group>.form-floating:not(:focus-within).is-valid{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-invalid-color)}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-danger);border-radius:var(--bs-border-radius)}.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip,.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip{display:block}.was-validated .form-control:invalid,.form-control.is-invalid{border-color:var(--bs-form-invalid-border-color);padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.was-validated .form-control:invalid:focus,.form-control.is-invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.was-validated .form-select:invalid,.form-select.is-invalid{border-color:var(--bs-form-invalid-border-color)}.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"],.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"]{--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.was-validated .form-select:invalid:focus,.form-select.is-invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.was-validated .form-control-color:invalid,.form-control-color.is-invalid{width:calc(3.75rem + 1.5em)}.was-validated .form-check-input:invalid,.form-check-input.is-invalid{border-color:var(--bs-form-invalid-border-color)}.was-validated .form-check-input:invalid:checked,.form-check-input.is-invalid:checked{background-color:var(--bs-form-invalid-color)}.was-validated .form-check-input:invalid:focus,.form-check-input.is-invalid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.was-validated .form-check-input:invalid~.form-check-label,.form-check-input.is-invalid~.form-check-label{color:var(--bs-form-invalid-color)}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.was-validated .input-group>.form-control:not(:focus):invalid,.input-group>.form-control:not(:focus).is-invalid,.was-validated .input-group>.form-select:not(:focus):invalid,.input-group>.form-select:not(:focus).is-invalid,.was-validated .input-group>.form-floating:not(:focus-within):invalid,.input-group>.form-floating:not(:focus-within).is-invalid{z-index:4}.btn{--bs-btn-padding-x: .75rem;--bs-btn-padding-y: .375rem;--bs-btn-font-family: ;--bs-btn-font-size: 1rem;--bs-btn-font-weight: 400;--bs-btn-line-height: 1.5;--bs-btn-color: var(--bs-body-color);--bs-btn-bg: transparent;--bs-btn-border-width: var(--bs-border-width);--bs-btn-border-color: transparent;--bs-btn-border-radius: var(--bs-border-radius);--bs-btn-hover-border-color: transparent;--bs-btn-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);--bs-btn-disabled-opacity: .65;--bs-btn-focus-box-shadow: 0 0 0 .25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-family:var(--bs-btn-font-family);font-size:var(--bs-btn-font-size);font-weight:var(--bs-btn-font-weight);line-height:var(--bs-btn-line-height);color:var(--bs-btn-color);text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;user-select:none;border:var(--bs-btn-border-width) solid var(--bs-btn-border-color);border-radius:var(--bs-btn-border-radius);background-color:var(--bs-btn-bg);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.btn{transition:none}}.btn:hover{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color)}.btn-check+.btn:hover{color:var(--bs-btn-color);background-color:var(--bs-btn-bg);border-color:var(--bs-btn-border-color)}.btn:focus-visible{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:focus-visible+.btn{border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked+.btn,:not(.btn-check)+.btn:active,.btn:first-child:active,.btn.active,.btn.show{color:var(--bs-btn-active-color);background-color:var(--bs-btn-active-bg);border-color:var(--bs-btn-active-border-color)}.btn-check:checked+.btn:focus-visible,:not(.btn-check)+.btn:active:focus-visible,.btn:first-child:active:focus-visible,.btn.active:focus-visible,.btn.show:focus-visible{box-shadow:var(--bs-btn-focus-box-shadow)}.btn:disabled,.btn.disabled,fieldset:disabled .btn{color:var(--bs-btn-disabled-color);pointer-events:none;background-color:var(--bs-btn-disabled-bg);border-color:var(--bs-btn-disabled-border-color);opacity:var(--bs-btn-disabled-opacity)}.btn-primary{--bs-btn-color: #fff;--bs-btn-bg: #0d6efd;--bs-btn-border-color: #0d6efd;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #0b5ed7;--bs-btn-hover-border-color: #0a58ca;--bs-btn-focus-shadow-rgb: 49, 132, 253;--bs-btn-active-color: #fff;--bs-btn-active-bg: #0a58ca;--bs-btn-active-border-color: #0a53be;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #0d6efd;--bs-btn-disabled-border-color: #0d6efd}.btn-secondary{--bs-btn-color: #fff;--bs-btn-bg: #6c757d;--bs-btn-border-color: #6c757d;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #5c636a;--bs-btn-hover-border-color: #565e64;--bs-btn-focus-shadow-rgb: 130, 138, 145;--bs-btn-active-color: #fff;--bs-btn-active-bg: #565e64;--bs-btn-active-border-color: #51585e;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #6c757d;--bs-btn-disabled-border-color: #6c757d}.btn-success{--bs-btn-color: #fff;--bs-btn-bg: #198754;--bs-btn-border-color: #198754;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #157347;--bs-btn-hover-border-color: #146c43;--bs-btn-focus-shadow-rgb: 60, 153, 110;--bs-btn-active-color: #fff;--bs-btn-active-bg: #146c43;--bs-btn-active-border-color: #13653f;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #198754;--bs-btn-disabled-border-color: #198754}.btn-info{--bs-btn-color: #000;--bs-btn-bg: #0dcaf0;--bs-btn-border-color: #0dcaf0;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #31d2f2;--bs-btn-hover-border-color: #25cff2;--bs-btn-focus-shadow-rgb: 11, 172, 204;--bs-btn-active-color: #000;--bs-btn-active-bg: #3dd5f3;--bs-btn-active-border-color: #25cff2;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #0dcaf0;--bs-btn-disabled-border-color: #0dcaf0}.btn-warning{--bs-btn-color: #000;--bs-btn-bg: #ffc107;--bs-btn-border-color: #ffc107;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #ffca2c;--bs-btn-hover-border-color: #ffc720;--bs-btn-focus-shadow-rgb: 217, 164, 6;--bs-btn-active-color: #000;--bs-btn-active-bg: #ffcd39;--bs-btn-active-border-color: #ffc720;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #ffc107;--bs-btn-disabled-border-color: #ffc107}.btn-danger{--bs-btn-color: #fff;--bs-btn-bg: #dc3545;--bs-btn-border-color: #dc3545;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #bb2d3b;--bs-btn-hover-border-color: #b02a37;--bs-btn-focus-shadow-rgb: 225, 83, 97;--bs-btn-active-color: #fff;--bs-btn-active-bg: #b02a37;--bs-btn-active-border-color: #a52834;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #dc3545;--bs-btn-disabled-border-color: #dc3545}.btn-light{--bs-btn-color: #000;--bs-btn-bg: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #d3d4d5;--bs-btn-hover-border-color: #c6c7c8;--bs-btn-focus-shadow-rgb: 211, 212, 213;--bs-btn-active-color: #000;--bs-btn-active-bg: #c6c7c8;--bs-btn-active-border-color: #babbbc;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #f8f9fa;--bs-btn-disabled-border-color: #f8f9fa}.btn-dark{--bs-btn-color: #fff;--bs-btn-bg: #212529;--bs-btn-border-color: #212529;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #424649;--bs-btn-hover-border-color: #373b3e;--bs-btn-focus-shadow-rgb: 66, 70, 73;--bs-btn-active-color: #fff;--bs-btn-active-bg: #4d5154;--bs-btn-active-border-color: #373b3e;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #212529;--bs-btn-disabled-border-color: #212529}.btn-outline-primary{--bs-btn-color: #0d6efd;--bs-btn-border-color: #0d6efd;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #0d6efd;--bs-btn-hover-border-color: #0d6efd;--bs-btn-focus-shadow-rgb: 13, 110, 253;--bs-btn-active-color: #fff;--bs-btn-active-bg: #0d6efd;--bs-btn-active-border-color: #0d6efd;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #0d6efd;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #0d6efd;--bs-gradient: none}.btn-outline-secondary{--bs-btn-color: #6c757d;--bs-btn-border-color: #6c757d;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #6c757d;--bs-btn-hover-border-color: #6c757d;--bs-btn-focus-shadow-rgb: 108, 117, 125;--bs-btn-active-color: #fff;--bs-btn-active-bg: #6c757d;--bs-btn-active-border-color: #6c757d;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #6c757d;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #6c757d;--bs-gradient: none}.btn-outline-success{--bs-btn-color: #198754;--bs-btn-border-color: #198754;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #198754;--bs-btn-hover-border-color: #198754;--bs-btn-focus-shadow-rgb: 25, 135, 84;--bs-btn-active-color: #fff;--bs-btn-active-bg: #198754;--bs-btn-active-border-color: #198754;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #198754;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #198754;--bs-gradient: none}.btn-outline-info{--bs-btn-color: #0dcaf0;--bs-btn-border-color: #0dcaf0;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #0dcaf0;--bs-btn-hover-border-color: #0dcaf0;--bs-btn-focus-shadow-rgb: 13, 202, 240;--bs-btn-active-color: #000;--bs-btn-active-bg: #0dcaf0;--bs-btn-active-border-color: #0dcaf0;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #0dcaf0;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #0dcaf0;--bs-gradient: none}.btn-outline-warning{--bs-btn-color: #ffc107;--bs-btn-border-color: #ffc107;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #ffc107;--bs-btn-hover-border-color: #ffc107;--bs-btn-focus-shadow-rgb: 255, 193, 7;--bs-btn-active-color: #000;--bs-btn-active-bg: #ffc107;--bs-btn-active-border-color: #ffc107;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #ffc107;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #ffc107;--bs-gradient: none}.btn-outline-danger{--bs-btn-color: #dc3545;--bs-btn-border-color: #dc3545;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #dc3545;--bs-btn-hover-border-color: #dc3545;--bs-btn-focus-shadow-rgb: 220, 53, 69;--bs-btn-active-color: #fff;--bs-btn-active-bg: #dc3545;--bs-btn-active-border-color: #dc3545;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #dc3545;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #dc3545;--bs-gradient: none}.btn-outline-light{--bs-btn-color: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #f8f9fa;--bs-btn-hover-border-color: #f8f9fa;--bs-btn-focus-shadow-rgb: 248, 249, 250;--bs-btn-active-color: #000;--bs-btn-active-bg: #f8f9fa;--bs-btn-active-border-color: #f8f9fa;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #f8f9fa;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #f8f9fa;--bs-gradient: none}.btn-outline-dark{--bs-btn-color: #212529;--bs-btn-border-color: #212529;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #212529;--bs-btn-hover-border-color: #212529;--bs-btn-focus-shadow-rgb: 33, 37, 41;--bs-btn-active-color: #fff;--bs-btn-active-bg: #212529;--bs-btn-active-border-color: #212529;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #212529;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #212529;--bs-gradient: none}.btn-link{--bs-btn-font-weight: 400;--bs-btn-color: var(--bs-link-color);--bs-btn-bg: transparent;--bs-btn-border-color: transparent;--bs-btn-hover-color: var(--bs-link-hover-color);--bs-btn-hover-border-color: transparent;--bs-btn-active-color: var(--bs-link-hover-color);--bs-btn-active-border-color: transparent;--bs-btn-disabled-color: #6c757d;--bs-btn-disabled-border-color: transparent;--bs-btn-box-shadow: 0 0 0 #000;--bs-btn-focus-shadow-rgb: 49, 132, 253;text-decoration:underline}.btn-link:focus-visible{color:var(--bs-btn-color)}.btn-link:hover{color:var(--bs-btn-hover-color)}.btn-lg,.btn-group-lg>.btn{--bs-btn-padding-y: .5rem;--bs-btn-padding-x: 1rem;--bs-btn-font-size: 1.25rem;--bs-btn-border-radius: var(--bs-border-radius-lg)}.btn-sm,.btn-group-sm>.btn{--bs-btn-padding-y: .25rem;--bs-btn-padding-x: .5rem;--bs-btn-font-size: .875rem;--bs-btn-border-radius: var(--bs-border-radius-sm)}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion: reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion: reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media (prefers-reduced-motion: reduce){.collapsing.collapse-horizontal{transition:none}}.dropup,.dropend,.dropdown,.dropstart,.dropup-center,.dropdown-center{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle:after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty:after{margin-left:0}.dropdown-menu{--bs-dropdown-zindex: 1000;--bs-dropdown-min-width: 10rem;--bs-dropdown-padding-x: 0;--bs-dropdown-padding-y: .5rem;--bs-dropdown-spacer: .125rem;--bs-dropdown-font-size: 1rem;--bs-dropdown-color: var(--bs-body-color);--bs-dropdown-bg: var(--bs-body-bg);--bs-dropdown-border-color: var(--bs-border-color-translucent);--bs-dropdown-border-radius: var(--bs-border-radius);--bs-dropdown-border-width: var(--bs-border-width);--bs-dropdown-inner-border-radius: calc(var(--bs-border-radius) - var(--bs-border-width));--bs-dropdown-divider-bg: var(--bs-border-color-translucent);--bs-dropdown-divider-margin-y: .5rem;--bs-dropdown-box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .15);--bs-dropdown-link-color: var(--bs-body-color);--bs-dropdown-link-hover-color: var(--bs-body-color);--bs-dropdown-link-hover-bg: var(--bs-tertiary-bg);--bs-dropdown-link-active-color: #fff;--bs-dropdown-link-active-bg: #0d6efd;--bs-dropdown-link-disabled-color: var(--bs-tertiary-color);--bs-dropdown-item-padding-x: 1rem;--bs-dropdown-item-padding-y: .25rem;--bs-dropdown-header-color: #6c757d;--bs-dropdown-header-padding-x: 1rem;--bs-dropdown-header-padding-y: .5rem;position:absolute;z-index:var(--bs-dropdown-zindex);display:none;min-width:var(--bs-dropdown-min-width);padding:var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x);margin:0;font-size:var(--bs-dropdown-font-size);color:var(--bs-dropdown-color);text-align:left;list-style:none;background-color:var(--bs-dropdown-bg);background-clip:padding-box;border:var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color);border-radius:var(--bs-dropdown-border-radius)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:var(--bs-dropdown-spacer)}.dropdown-menu-start{--bs-position: start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position: end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media (min-width: 576px){.dropdown-menu-sm-start{--bs-position: start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position: end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media (min-width: 768px){.dropdown-menu-md-start{--bs-position: start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position: end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media (min-width: 992px){.dropdown-menu-lg-start{--bs-position: start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position: end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media (min-width: 1200px){.dropdown-menu-xl-start{--bs-position: start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position: end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media (min-width: 1400px){.dropdown-menu-xxl-start{--bs-position: start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position: end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:var(--bs-dropdown-spacer)}.dropup .dropdown-toggle:after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty:after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:var(--bs-dropdown-spacer)}.dropend .dropdown-toggle:after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty:after{margin-left:0}.dropend .dropdown-toggle:after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:var(--bs-dropdown-spacer)}.dropstart .dropdown-toggle:after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle:after{display:none}.dropstart .dropdown-toggle:before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty:after{margin-left:0}.dropstart .dropdown-toggle:before{vertical-align:0}.dropdown-divider{height:0;margin:var(--bs-dropdown-divider-margin-y) 0;overflow:hidden;border-top:1px solid var(--bs-dropdown-divider-bg);opacity:1}.dropdown-item{display:block;width:100%;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);clear:both;font-weight:400;color:var(--bs-dropdown-link-color);text-align:inherit;text-decoration:none;white-space:nowrap;background-color:transparent;border:0;border-radius:var(--bs-dropdown-item-border-radius, 0)}.dropdown-item:hover,.dropdown-item:focus{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}.dropdown-item.active,.dropdown-item:active{color:var(--bs-dropdown-link-active-color);text-decoration:none;background-color:var(--bs-dropdown-link-active-bg)}.dropdown-item.disabled,.dropdown-item:disabled{color:var(--bs-dropdown-link-disabled-color);pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x);margin-bottom:0;font-size:.875rem;color:var(--bs-dropdown-header-color);white-space:nowrap}.dropdown-item-text{display:block;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);color:var(--bs-dropdown-link-color)}.dropdown-menu-dark{--bs-dropdown-color: #dee2e6;--bs-dropdown-bg: #343a40;--bs-dropdown-border-color: var(--bs-border-color-translucent);--bs-dropdown-box-shadow: ;--bs-dropdown-link-color: #dee2e6;--bs-dropdown-link-hover-color: #fff;--bs-dropdown-divider-bg: var(--bs-border-color-translucent);--bs-dropdown-link-hover-bg: rgba(255, 255, 255, .15);--bs-dropdown-link-active-color: #fff;--bs-dropdown-link-active-bg: #0d6efd;--bs-dropdown-link-disabled-color: #adb5bd;--bs-dropdown-header-color: #adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;flex:1 1 auto}.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn:hover,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn.active{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group{border-radius:var(--bs-border-radius)}.btn-group>:not(.btn-check:first-child)+.btn,.btn-group>.btn-group:not(:first-child){margin-left:calc(var(--bs-border-width) * -1)}.btn-group>.btn:not(:last-child):not(.dropdown-toggle),.btn-group>.btn.dropdown-toggle-split:first-child,.btn-group>.btn-group:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn,.btn-group>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split:after,.dropup .dropdown-toggle-split:after,.dropend .dropdown-toggle-split:after{margin-left:0}.dropstart .dropdown-toggle-split:before{margin-right:0}.btn-sm+.dropdown-toggle-split,.btn-group-sm>.btn+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-lg+.dropdown-toggle-split,.btn-group-lg>.btn+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn:not(:first-child),.btn-group-vertical>.btn-group:not(:first-child){margin-top:calc(var(--bs-border-width) * -1)}.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle),.btn-group-vertical>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn~.btn,.btn-group-vertical>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{--bs-nav-link-padding-x: 1rem;--bs-nav-link-padding-y: .5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color: var(--bs-link-color);--bs-nav-link-hover-color: var(--bs-link-hover-color);--bs-nav-link-disabled-color: var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);font-size:var(--bs-nav-link-font-size);font-weight:var(--bs-nav-link-font-weight);color:var(--bs-nav-link-color);text-decoration:none;background:none;border:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media (prefers-reduced-motion: reduce){.nav-link{transition:none}}.nav-link:hover,.nav-link:focus{color:var(--bs-nav-link-hover-color)}.nav-link:focus-visible{outline:0;box-shadow:0 0 0 .25rem #0d6efd40}.nav-link.disabled{color:var(--bs-nav-link-disabled-color);pointer-events:none;cursor:default}.nav-tabs{--bs-nav-tabs-border-width: var(--bs-border-width);--bs-nav-tabs-border-color: var(--bs-border-color);--bs-nav-tabs-border-radius: var(--bs-border-radius);--bs-nav-tabs-link-hover-border-color: var(--bs-secondary-bg) var(--bs-secondary-bg) var(--bs-border-color);--bs-nav-tabs-link-active-color: var(--bs-emphasis-color);--bs-nav-tabs-link-active-bg: var(--bs-body-bg);--bs-nav-tabs-link-active-border-color: var(--bs-border-color) var(--bs-border-color) var(--bs-body-bg);border-bottom:var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color)}.nav-tabs .nav-link{margin-bottom:calc(-1 * var(--bs-nav-tabs-border-width));border:var(--bs-nav-tabs-border-width) solid transparent;border-top-left-radius:var(--bs-nav-tabs-border-radius);border-top-right-radius:var(--bs-nav-tabs-border-radius)}.nav-tabs .nav-link:hover,.nav-tabs .nav-link:focus{isolation:isolate;border-color:var(--bs-nav-tabs-link-hover-border-color)}.nav-tabs .nav-link.disabled,.nav-tabs .nav-link:disabled{color:var(--bs-nav-link-disabled-color);background-color:transparent;border-color:transparent}.nav-tabs .nav-link.active,.nav-tabs .nav-item.show .nav-link{color:var(--bs-nav-tabs-link-active-color);background-color:var(--bs-nav-tabs-link-active-bg);border-color:var(--bs-nav-tabs-link-active-border-color)}.nav-tabs .dropdown-menu{margin-top:calc(-1 * var(--bs-nav-tabs-border-width));border-top-left-radius:0;border-top-right-radius:0}.nav-pills{--bs-nav-pills-border-radius: var(--bs-border-radius);--bs-nav-pills-link-active-color: #fff;--bs-nav-pills-link-active-bg: #0d6efd}.nav-pills .nav-link{border-radius:var(--bs-nav-pills-border-radius)}.nav-pills .nav-link:disabled{color:var(--bs-nav-link-disabled-color);background-color:transparent;border-color:transparent}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:var(--bs-nav-pills-link-active-color);background-color:var(--bs-nav-pills-link-active-bg)}.nav-underline{--bs-nav-underline-gap: 1rem;--bs-nav-underline-border-width: .125rem;--bs-nav-underline-link-active-color: var(--bs-emphasis-color);gap:var(--bs-nav-underline-gap)}.nav-underline .nav-link{padding-right:0;padding-left:0;border-bottom:var(--bs-nav-underline-border-width) solid transparent}.nav-underline .nav-link:hover,.nav-underline .nav-link:focus{border-bottom-color:currentcolor}.nav-underline .nav-link.active,.nav-underline .show>.nav-link{font-weight:700;color:var(--bs-nav-underline-link-active-color);border-bottom-color:currentcolor}.nav-fill>.nav-link,.nav-fill .nav-item{flex:1 1 auto;text-align:center}.nav-justified>.nav-link,.nav-justified .nav-item{flex-basis:0;flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{--bs-navbar-padding-x: 0;--bs-navbar-padding-y: .5rem;--bs-navbar-color: rgba(var(--bs-emphasis-color-rgb), .65);--bs-navbar-hover-color: rgba(var(--bs-emphasis-color-rgb), .8);--bs-navbar-disabled-color: rgba(var(--bs-emphasis-color-rgb), .3);--bs-navbar-active-color: rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-padding-y: .3125rem;--bs-navbar-brand-margin-end: 1rem;--bs-navbar-brand-font-size: 1.25rem;--bs-navbar-brand-color: rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-hover-color: rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-nav-link-padding-x: .5rem;--bs-navbar-toggler-padding-y: .25rem;--bs-navbar-toggler-padding-x: .75rem;--bs-navbar-toggler-font-size: 1.25rem;--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2833, 37, 41, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");--bs-navbar-toggler-border-color: rgba(var(--bs-emphasis-color-rgb), .15);--bs-navbar-toggler-border-radius: var(--bs-border-radius);--bs-navbar-toggler-focus-width: .25rem;--bs-navbar-toggler-transition: box-shadow .15s ease-in-out;position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:var(--bs-navbar-padding-y) var(--bs-navbar-padding-x)}.navbar>.container,.navbar>.container-fluid,.navbar>.container-sm,.navbar>.container-md,.navbar>.container-lg,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:var(--bs-navbar-brand-padding-y);padding-bottom:var(--bs-navbar-brand-padding-y);margin-right:var(--bs-navbar-brand-margin-end);font-size:var(--bs-navbar-brand-font-size);color:var(--bs-navbar-brand-color);text-decoration:none;white-space:nowrap}.navbar-brand:hover,.navbar-brand:focus{color:var(--bs-navbar-brand-hover-color)}.navbar-nav{--bs-nav-link-padding-x: 0;--bs-nav-link-padding-y: .5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color: var(--bs-navbar-color);--bs-nav-link-hover-color: var(--bs-navbar-hover-color);--bs-nav-link-disabled-color: var(--bs-navbar-disabled-color);display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link.active,.navbar-nav .nav-link.show{color:var(--bs-navbar-active-color)}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-navbar-color)}.navbar-text a,.navbar-text a:hover,.navbar-text a:focus{color:var(--bs-navbar-active-color)}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x);font-size:var(--bs-navbar-toggler-font-size);line-height:1;color:var(--bs-navbar-color);background-color:transparent;border:var(--bs-border-width) solid var(--bs-navbar-toggler-border-color);border-radius:var(--bs-navbar-toggler-border-radius);transition:var(--bs-navbar-toggler-transition)}@media (prefers-reduced-motion: reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 var(--bs-navbar-toggler-focus-width)}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-image:var(--bs-navbar-toggler-icon-bg);background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height, 75vh);overflow-y:auto}@media (min-width: 576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-sm .offcanvas .offcanvas-header{display:none}.navbar-expand-sm .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width: 768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-md .offcanvas .offcanvas-header{display:none}.navbar-expand-md .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width: 992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-lg .offcanvas .offcanvas-header{display:none}.navbar-expand-lg .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width: 1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xl .offcanvas .offcanvas-header{display:none}.navbar-expand-xl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width: 1400px){.navbar-expand-xxl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xxl .offcanvas .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand .offcanvas .offcanvas-header{display:none}.navbar-expand .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}.navbar-dark,.navbar[data-bs-theme=dark]{--bs-navbar-color: rgba(255, 255, 255, .55);--bs-navbar-hover-color: rgba(255, 255, 255, .75);--bs-navbar-disabled-color: rgba(255, 255, 255, .25);--bs-navbar-active-color: #fff;--bs-navbar-brand-color: #fff;--bs-navbar-brand-hover-color: #fff;--bs-navbar-toggler-border-color: rgba(255, 255, 255, .1);--bs-navbar-toggler-icon-bg: 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")}[data-bs-theme=dark] .navbar-toggler-icon{--bs-navbar-toggler-icon-bg: 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")}.card{--bs-card-spacer-y: 1rem;--bs-card-spacer-x: 1rem;--bs-card-title-spacer-y: .5rem;--bs-card-title-color: ;--bs-card-subtitle-color: ;--bs-card-border-width: var(--bs-border-width);--bs-card-border-color: var(--bs-border-color-translucent);--bs-card-border-radius: var(--bs-border-radius);--bs-card-box-shadow: ;--bs-card-inner-border-radius: calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-card-cap-padding-y: .5rem;--bs-card-cap-padding-x: 1rem;--bs-card-cap-bg: rgba(var(--bs-body-color-rgb), .03);--bs-card-cap-color: ;--bs-card-height: ;--bs-card-color: ;--bs-card-bg: var(--bs-body-bg);--bs-card-img-overlay-padding: 1rem;--bs-card-group-margin: .75rem;position:relative;display:flex;flex-direction:column;min-width:0;height:var(--bs-card-height);color:var(--bs-body-color);word-wrap:break-word;background-color:var(--bs-card-bg);background-clip:border-box;border:var(--bs-card-border-width) solid var(--bs-card-border-color);border-radius:var(--bs-card-border-radius)}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:var(--bs-card-spacer-y) var(--bs-card-spacer-x);color:var(--bs-card-color)}.card-title{margin-bottom:var(--bs-card-title-spacer-y);color:var(--bs-card-title-color)}.card-subtitle{margin-top:calc(-.5 * var(--bs-card-title-spacer-y));margin-bottom:0;color:var(--bs-card-subtitle-color)}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:var(--bs-card-spacer-x)}.card-header{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);margin-bottom:0;color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-bottom:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-header:first-child{border-radius:var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius) 0 0}.card-footer{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-top:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-footer:last-child{border-radius:0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius)}.card-header-tabs{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-bottom:calc(-1 * var(--bs-card-cap-padding-y));margin-left:calc(-.5 * var(--bs-card-cap-padding-x));border-bottom:0}.card-header-tabs .nav-link.active{background-color:var(--bs-card-bg);border-bottom-color:var(--bs-card-bg)}.card-header-pills{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-left:calc(-.5 * var(--bs-card-cap-padding-x))}.card-img-overlay{position:absolute;inset:0;padding:var(--bs-card-img-overlay-padding);border-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-top,.card-img-bottom{width:100%}.card-img,.card-img-top{border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom{border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card-group>.card{margin-bottom:var(--bs-card-group-margin)}@media (min-width: 576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-img-top,.card-group>.card:not(:last-child) .card-header{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-img-bottom,.card-group>.card:not(:last-child) .card-footer{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-img-top,.card-group>.card:not(:first-child) .card-header{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-img-bottom,.card-group>.card:not(:first-child) .card-footer{border-bottom-left-radius:0}}.accordion{--bs-accordion-color: var(--bs-body-color);--bs-accordion-bg: var(--bs-body-bg);--bs-accordion-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out, border-radius .15s ease;--bs-accordion-border-color: var(--bs-border-color);--bs-accordion-border-width: var(--bs-border-width);--bs-accordion-border-radius: var(--bs-border-radius);--bs-accordion-inner-border-radius: calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-accordion-btn-padding-x: 1.25rem;--bs-accordion-btn-padding-y: 1rem;--bs-accordion-btn-color: var(--bs-body-color);--bs-accordion-btn-bg: var(--bs-accordion-bg);--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-icon-width: 1.25rem;--bs-accordion-btn-icon-transform: rotate(-180deg);--bs-accordion-btn-icon-transition: transform .2s ease-in-out;--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23052c65'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-focus-border-color: #86b7fe;--bs-accordion-btn-focus-box-shadow: 0 0 0 .25rem rgba(13, 110, 253, .25);--bs-accordion-body-padding-x: 1.25rem;--bs-accordion-body-padding-y: 1rem;--bs-accordion-active-color: var(--bs-primary-text-emphasis);--bs-accordion-active-bg: var(--bs-primary-bg-subtle)}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x);font-size:1rem;color:var(--bs-accordion-btn-color);text-align:left;background-color:var(--bs-accordion-btn-bg);border:0;border-radius:0;overflow-anchor:none;transition:var(--bs-accordion-transition)}@media (prefers-reduced-motion: reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:var(--bs-accordion-active-color);background-color:var(--bs-accordion-active-bg);box-shadow:inset 0 calc(-1 * var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color)}.accordion-button:not(.collapsed):after{background-image:var(--bs-accordion-btn-active-icon);transform:var(--bs-accordion-btn-icon-transform)}.accordion-button:after{flex-shrink:0;width:var(--bs-accordion-btn-icon-width);height:var(--bs-accordion-btn-icon-width);margin-left:auto;content:"";background-image:var(--bs-accordion-btn-icon);background-repeat:no-repeat;background-size:var(--bs-accordion-btn-icon-width);transition:var(--bs-accordion-btn-icon-transition)}@media (prefers-reduced-motion: reduce){.accordion-button:after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;border-color:var(--bs-accordion-btn-focus-border-color);outline:0;box-shadow:var(--bs-accordion-btn-focus-box-shadow)}.accordion-header{margin-bottom:0}.accordion-item{color:var(--bs-accordion-color);background-color:var(--bs-accordion-bg);border:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.accordion-item:first-of-type{border-top-left-radius:var(--bs-accordion-border-radius);border-top-right-radius:var(--bs-accordion-border-radius)}.accordion-item:first-of-type .accordion-button{border-top-left-radius:var(--bs-accordion-inner-border-radius);border-top-right-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-item:last-of-type .accordion-button.collapsed{border-bottom-right-radius:var(--bs-accordion-inner-border-radius);border-bottom-left-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:last-of-type .accordion-collapse{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-body{padding:var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x)}.accordion-flush .accordion-collapse{border-width:0}.accordion-flush .accordion-item{border-right:0;border-left:0;border-radius:0}.accordion-flush .accordion-item:first-child{border-top:0}.accordion-flush .accordion-item:last-child{border-bottom:0}.accordion-flush .accordion-item .accordion-button,.accordion-flush .accordion-item .accordion-button.collapsed{border-radius:0}[data-bs-theme=dark] .accordion-button:after{--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236ea8fe'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.breadcrumb{--bs-breadcrumb-padding-x: 0;--bs-breadcrumb-padding-y: 0;--bs-breadcrumb-margin-bottom: 1rem;--bs-breadcrumb-bg: ;--bs-breadcrumb-border-radius: ;--bs-breadcrumb-divider-color: var(--bs-secondary-color);--bs-breadcrumb-item-padding-x: .5rem;--bs-breadcrumb-item-active-color: var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding:var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x);margin-bottom:var(--bs-breadcrumb-margin-bottom);font-size:var(--bs-breadcrumb-font-size);list-style:none;background-color:var(--bs-breadcrumb-bg);border-radius:var(--bs-breadcrumb-border-radius)}.breadcrumb-item+.breadcrumb-item{padding-left:var(--bs-breadcrumb-item-padding-x)}.breadcrumb-item+.breadcrumb-item:before{float:left;padding-right:var(--bs-breadcrumb-item-padding-x);color:var(--bs-breadcrumb-divider-color);content:var(--bs-breadcrumb-divider, "/")}.breadcrumb-item.active{color:var(--bs-breadcrumb-item-active-color)}.pagination{--bs-pagination-padding-x: .75rem;--bs-pagination-padding-y: .375rem;--bs-pagination-font-size: 1rem;--bs-pagination-color: var(--bs-link-color);--bs-pagination-bg: var(--bs-body-bg);--bs-pagination-border-width: var(--bs-border-width);--bs-pagination-border-color: var(--bs-border-color);--bs-pagination-border-radius: var(--bs-border-radius);--bs-pagination-hover-color: var(--bs-link-hover-color);--bs-pagination-hover-bg: var(--bs-tertiary-bg);--bs-pagination-hover-border-color: var(--bs-border-color);--bs-pagination-focus-color: var(--bs-link-hover-color);--bs-pagination-focus-bg: var(--bs-secondary-bg);--bs-pagination-focus-box-shadow: 0 0 0 .25rem rgba(13, 110, 253, .25);--bs-pagination-active-color: #fff;--bs-pagination-active-bg: #0d6efd;--bs-pagination-active-border-color: #0d6efd;--bs-pagination-disabled-color: var(--bs-secondary-color);--bs-pagination-disabled-bg: var(--bs-secondary-bg);--bs-pagination-disabled-border-color: var(--bs-border-color);display:flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;padding:var(--bs-pagination-padding-y) var(--bs-pagination-padding-x);font-size:var(--bs-pagination-font-size);color:var(--bs-pagination-color);text-decoration:none;background-color:var(--bs-pagination-bg);border:var(--bs-pagination-border-width) solid var(--bs-pagination-border-color);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion: reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:var(--bs-pagination-hover-color);background-color:var(--bs-pagination-hover-bg);border-color:var(--bs-pagination-hover-border-color)}.page-link:focus{z-index:3;color:var(--bs-pagination-focus-color);background-color:var(--bs-pagination-focus-bg);outline:0;box-shadow:var(--bs-pagination-focus-box-shadow)}.page-link.active,.active>.page-link{z-index:3;color:var(--bs-pagination-active-color);background-color:var(--bs-pagination-active-bg);border-color:var(--bs-pagination-active-border-color)}.page-link.disabled,.disabled>.page-link{color:var(--bs-pagination-disabled-color);pointer-events:none;background-color:var(--bs-pagination-disabled-bg);border-color:var(--bs-pagination-disabled-border-color)}.page-item:not(:first-child) .page-link{margin-left:calc(var(--bs-border-width) * -1)}.page-item:first-child .page-link{border-top-left-radius:var(--bs-pagination-border-radius);border-bottom-left-radius:var(--bs-pagination-border-radius)}.page-item:last-child .page-link{border-top-right-radius:var(--bs-pagination-border-radius);border-bottom-right-radius:var(--bs-pagination-border-radius)}.pagination-lg{--bs-pagination-padding-x: 1.5rem;--bs-pagination-padding-y: .75rem;--bs-pagination-font-size: 1.25rem;--bs-pagination-border-radius: var(--bs-border-radius-lg)}.pagination-sm{--bs-pagination-padding-x: .5rem;--bs-pagination-padding-y: .25rem;--bs-pagination-font-size: .875rem;--bs-pagination-border-radius: var(--bs-border-radius-sm)}.badge{--bs-badge-padding-x: .65em;--bs-badge-padding-y: .35em;--bs-badge-font-size: .75em;--bs-badge-font-weight: 700;--bs-badge-color: #fff;--bs-badge-border-radius: var(--bs-border-radius);display:inline-block;padding:var(--bs-badge-padding-y) var(--bs-badge-padding-x);font-size:var(--bs-badge-font-size);font-weight:var(--bs-badge-font-weight);line-height:1;color:var(--bs-badge-color);text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:var(--bs-badge-border-radius)}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{--bs-alert-bg: transparent;--bs-alert-padding-x: 1rem;--bs-alert-padding-y: 1rem;--bs-alert-margin-bottom: 1rem;--bs-alert-color: inherit;--bs-alert-border-color: transparent;--bs-alert-border: var(--bs-border-width) solid var(--bs-alert-border-color);--bs-alert-border-radius: var(--bs-border-radius);--bs-alert-link-color: inherit;position:relative;padding:var(--bs-alert-padding-y) var(--bs-alert-padding-x);margin-bottom:var(--bs-alert-margin-bottom);color:var(--bs-alert-color);background-color:var(--bs-alert-bg);border:var(--bs-alert-border);border-radius:var(--bs-alert-border-radius)}.alert-heading{color:inherit}.alert-link{font-weight:700;color:var(--bs-alert-link-color)}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-primary{--bs-alert-color: var(--bs-primary-text-emphasis);--bs-alert-bg: var(--bs-primary-bg-subtle);--bs-alert-border-color: var(--bs-primary-border-subtle);--bs-alert-link-color: var(--bs-primary-text-emphasis)}.alert-secondary{--bs-alert-color: var(--bs-secondary-text-emphasis);--bs-alert-bg: var(--bs-secondary-bg-subtle);--bs-alert-border-color: var(--bs-secondary-border-subtle);--bs-alert-link-color: var(--bs-secondary-text-emphasis)}.alert-success{--bs-alert-color: var(--bs-success-text-emphasis);--bs-alert-bg: var(--bs-success-bg-subtle);--bs-alert-border-color: var(--bs-success-border-subtle);--bs-alert-link-color: var(--bs-success-text-emphasis)}.alert-info{--bs-alert-color: var(--bs-info-text-emphasis);--bs-alert-bg: var(--bs-info-bg-subtle);--bs-alert-border-color: var(--bs-info-border-subtle);--bs-alert-link-color: var(--bs-info-text-emphasis)}.alert-warning{--bs-alert-color: var(--bs-warning-text-emphasis);--bs-alert-bg: var(--bs-warning-bg-subtle);--bs-alert-border-color: var(--bs-warning-border-subtle);--bs-alert-link-color: var(--bs-warning-text-emphasis)}.alert-danger{--bs-alert-color: var(--bs-danger-text-emphasis);--bs-alert-bg: var(--bs-danger-bg-subtle);--bs-alert-border-color: var(--bs-danger-border-subtle);--bs-alert-link-color: var(--bs-danger-text-emphasis)}.alert-light{--bs-alert-color: var(--bs-light-text-emphasis);--bs-alert-bg: var(--bs-light-bg-subtle);--bs-alert-border-color: var(--bs-light-border-subtle);--bs-alert-link-color: var(--bs-light-text-emphasis)}.alert-dark{--bs-alert-color: var(--bs-dark-text-emphasis);--bs-alert-bg: var(--bs-dark-bg-subtle);--bs-alert-border-color: var(--bs-dark-border-subtle);--bs-alert-link-color: var(--bs-dark-text-emphasis)}@keyframes progress-bar-stripes{0%{background-position-x:1rem}}.progress,.progress-stacked{--bs-progress-height: 1rem;--bs-progress-font-size: .75rem;--bs-progress-bg: var(--bs-secondary-bg);--bs-progress-border-radius: var(--bs-border-radius);--bs-progress-box-shadow: var(--bs-box-shadow-inset);--bs-progress-bar-color: #fff;--bs-progress-bar-bg: #0d6efd;--bs-progress-bar-transition: width .6s ease;display:flex;height:var(--bs-progress-height);overflow:hidden;font-size:var(--bs-progress-font-size);background-color:var(--bs-progress-bg);border-radius:var(--bs-progress-border-radius)}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:var(--bs-progress-bar-color);text-align:center;white-space:nowrap;background-color:var(--bs-progress-bar-bg);transition:var(--bs-progress-bar-transition)}@media (prefers-reduced-motion: reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:var(--bs-progress-height) var(--bs-progress-height)}.progress-stacked>.progress{overflow:visible}.progress-stacked>.progress>.progress-bar{width:100%}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media (prefers-reduced-motion: reduce){.progress-bar-animated{animation:none}}.list-group{--bs-list-group-color: var(--bs-body-color);--bs-list-group-bg: var(--bs-body-bg);--bs-list-group-border-color: var(--bs-border-color);--bs-list-group-border-width: var(--bs-border-width);--bs-list-group-border-radius: var(--bs-border-radius);--bs-list-group-item-padding-x: 1rem;--bs-list-group-item-padding-y: .5rem;--bs-list-group-action-color: var(--bs-secondary-color);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-tertiary-bg);--bs-list-group-action-active-color: var(--bs-body-color);--bs-list-group-action-active-bg: var(--bs-secondary-bg);--bs-list-group-disabled-color: var(--bs-secondary-color);--bs-list-group-disabled-bg: var(--bs-body-bg);--bs-list-group-active-color: #fff;--bs-list-group-active-bg: #0d6efd;--bs-list-group-active-border-color: #0d6efd;display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:var(--bs-list-group-border-radius)}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>.list-group-item:before{content:counters(section,".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:var(--bs-list-group-action-color);text-align:inherit}.list-group-item-action:hover,.list-group-item-action:focus{z-index:1;color:var(--bs-list-group-action-hover-color);text-decoration:none;background-color:var(--bs-list-group-action-hover-bg)}.list-group-item-action:active{color:var(--bs-list-group-action-active-color);background-color:var(--bs-list-group-action-active-bg)}.list-group-item{position:relative;display:block;padding:var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x);color:var(--bs-list-group-color);text-decoration:none;background-color:var(--bs-list-group-bg);border:var(--bs-list-group-border-width) solid var(--bs-list-group-border-color)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:var(--bs-list-group-disabled-color);pointer-events:none;background-color:var(--bs-list-group-disabled-bg)}.list-group-item.active{z-index:2;color:var(--bs-list-group-active-color);background-color:var(--bs-list-group-active-bg);border-color:var(--bs-list-group-active-border-color)}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:calc(-1 * var(--bs-list-group-border-width));border-top-width:var(--bs-list-group-border-width)}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}@media (min-width: 576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width: 768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width: 992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width: 1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width: 1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 var(--bs-list-group-border-width)}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{--bs-list-group-color: var(--bs-primary-text-emphasis);--bs-list-group-bg: var(--bs-primary-bg-subtle);--bs-list-group-border-color: var(--bs-primary-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-primary-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-primary-border-subtle);--bs-list-group-active-color: var(--bs-primary-bg-subtle);--bs-list-group-active-bg: var(--bs-primary-text-emphasis);--bs-list-group-active-border-color: var(--bs-primary-text-emphasis)}.list-group-item-secondary{--bs-list-group-color: var(--bs-secondary-text-emphasis);--bs-list-group-bg: var(--bs-secondary-bg-subtle);--bs-list-group-border-color: var(--bs-secondary-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-secondary-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-secondary-border-subtle);--bs-list-group-active-color: var(--bs-secondary-bg-subtle);--bs-list-group-active-bg: var(--bs-secondary-text-emphasis);--bs-list-group-active-border-color: var(--bs-secondary-text-emphasis)}.list-group-item-success{--bs-list-group-color: var(--bs-success-text-emphasis);--bs-list-group-bg: var(--bs-success-bg-subtle);--bs-list-group-border-color: var(--bs-success-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-success-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-success-border-subtle);--bs-list-group-active-color: var(--bs-success-bg-subtle);--bs-list-group-active-bg: var(--bs-success-text-emphasis);--bs-list-group-active-border-color: var(--bs-success-text-emphasis)}.list-group-item-info{--bs-list-group-color: var(--bs-info-text-emphasis);--bs-list-group-bg: var(--bs-info-bg-subtle);--bs-list-group-border-color: var(--bs-info-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-info-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-info-border-subtle);--bs-list-group-active-color: var(--bs-info-bg-subtle);--bs-list-group-active-bg: var(--bs-info-text-emphasis);--bs-list-group-active-border-color: var(--bs-info-text-emphasis)}.list-group-item-warning{--bs-list-group-color: var(--bs-warning-text-emphasis);--bs-list-group-bg: var(--bs-warning-bg-subtle);--bs-list-group-border-color: var(--bs-warning-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-warning-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-warning-border-subtle);--bs-list-group-active-color: var(--bs-warning-bg-subtle);--bs-list-group-active-bg: var(--bs-warning-text-emphasis);--bs-list-group-active-border-color: var(--bs-warning-text-emphasis)}.list-group-item-danger{--bs-list-group-color: var(--bs-danger-text-emphasis);--bs-list-group-bg: var(--bs-danger-bg-subtle);--bs-list-group-border-color: var(--bs-danger-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-danger-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-danger-border-subtle);--bs-list-group-active-color: var(--bs-danger-bg-subtle);--bs-list-group-active-bg: var(--bs-danger-text-emphasis);--bs-list-group-active-border-color: var(--bs-danger-text-emphasis)}.list-group-item-light{--bs-list-group-color: var(--bs-light-text-emphasis);--bs-list-group-bg: var(--bs-light-bg-subtle);--bs-list-group-border-color: var(--bs-light-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-light-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-light-border-subtle);--bs-list-group-active-color: var(--bs-light-bg-subtle);--bs-list-group-active-bg: var(--bs-light-text-emphasis);--bs-list-group-active-border-color: var(--bs-light-text-emphasis)}.list-group-item-dark{--bs-list-group-color: var(--bs-dark-text-emphasis);--bs-list-group-bg: var(--bs-dark-bg-subtle);--bs-list-group-border-color: var(--bs-dark-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-dark-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-dark-border-subtle);--bs-list-group-active-color: var(--bs-dark-bg-subtle);--bs-list-group-active-bg: var(--bs-dark-text-emphasis);--bs-list-group-active-border-color: var(--bs-dark-text-emphasis)}.btn-close{--bs-btn-close-color: #000;--bs-btn-close-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e");--bs-btn-close-opacity: .5;--bs-btn-close-hover-opacity: .75;--bs-btn-close-focus-shadow: 0 0 0 .25rem rgba(13, 110, 253, .25);--bs-btn-close-focus-opacity: 1;--bs-btn-close-disabled-opacity: .25;--bs-btn-close-white-filter: invert(1) grayscale(100%) brightness(200%);box-sizing:content-box;width:1em;height:1em;padding:.25em;color:var(--bs-btn-close-color);background:transparent var(--bs-btn-close-bg) center/1em auto no-repeat;border:0;border-radius:.375rem;opacity:var(--bs-btn-close-opacity)}.btn-close:hover{color:var(--bs-btn-close-color);text-decoration:none;opacity:var(--bs-btn-close-hover-opacity)}.btn-close:focus{outline:0;box-shadow:var(--bs-btn-close-focus-shadow);opacity:var(--bs-btn-close-focus-opacity)}.btn-close:disabled,.btn-close.disabled{pointer-events:none;-webkit-user-select:none;user-select:none;opacity:var(--bs-btn-close-disabled-opacity)}.btn-close-white,[data-bs-theme=dark] .btn-close{filter:var(--bs-btn-close-white-filter)}.toast{--bs-toast-zindex: 1090;--bs-toast-padding-x: .75rem;--bs-toast-padding-y: .5rem;--bs-toast-spacing: 1.5rem;--bs-toast-max-width: 350px;--bs-toast-font-size: .875rem;--bs-toast-color: ;--bs-toast-bg: rgba(var(--bs-body-bg-rgb), .85);--bs-toast-border-width: var(--bs-border-width);--bs-toast-border-color: var(--bs-border-color-translucent);--bs-toast-border-radius: var(--bs-border-radius);--bs-toast-box-shadow: var(--bs-box-shadow);--bs-toast-header-color: var(--bs-secondary-color);--bs-toast-header-bg: rgba(var(--bs-body-bg-rgb), .85);--bs-toast-header-border-color: var(--bs-border-color-translucent);width:var(--bs-toast-max-width);max-width:100%;font-size:var(--bs-toast-font-size);color:var(--bs-toast-color);pointer-events:auto;background-color:var(--bs-toast-bg);background-clip:padding-box;border:var(--bs-toast-border-width) solid var(--bs-toast-border-color);box-shadow:var(--bs-toast-box-shadow);border-radius:var(--bs-toast-border-radius)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{--bs-toast-zindex: 1090;position:absolute;z-index:var(--bs-toast-zindex);width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:var(--bs-toast-spacing)}.toast-header{display:flex;align-items:center;padding:var(--bs-toast-padding-y) var(--bs-toast-padding-x);color:var(--bs-toast-header-color);background-color:var(--bs-toast-header-bg);background-clip:padding-box;border-bottom:var(--bs-toast-border-width) solid var(--bs-toast-header-border-color);border-top-left-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));border-top-right-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width))}.toast-header .btn-close{margin-right:calc(-.5 * var(--bs-toast-padding-x));margin-left:var(--bs-toast-padding-x)}.toast-body{padding:var(--bs-toast-padding-x);word-wrap:break-word}.modal{--bs-modal-zindex: 1055;--bs-modal-width: 500px;--bs-modal-padding: 1rem;--bs-modal-margin: .5rem;--bs-modal-color: ;--bs-modal-bg: var(--bs-body-bg);--bs-modal-border-color: var(--bs-border-color-translucent);--bs-modal-border-width: var(--bs-border-width);--bs-modal-border-radius: var(--bs-border-radius-lg);--bs-modal-box-shadow: 0 .125rem .25rem rgba(0, 0, 0, .075);--bs-modal-inner-border-radius: calc(var(--bs-border-radius-lg) - (var(--bs-border-width)));--bs-modal-header-padding-x: 1rem;--bs-modal-header-padding-y: 1rem;--bs-modal-header-padding: 1rem 1rem;--bs-modal-header-border-color: var(--bs-border-color);--bs-modal-header-border-width: var(--bs-border-width);--bs-modal-title-line-height: 1.5;--bs-modal-footer-gap: .5rem;--bs-modal-footer-bg: ;--bs-modal-footer-border-color: var(--bs-border-color);--bs-modal-footer-border-width: var(--bs-border-width);position:fixed;top:0;left:0;z-index:var(--bs-modal-zindex);display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:var(--bs-modal-margin);pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translateY(-50px)}@media (prefers-reduced-motion: reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - var(--bs-modal-margin) * 2)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - var(--bs-modal-margin) * 2)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;color:var(--bs-modal-color);pointer-events:auto;background-color:var(--bs-modal-bg);background-clip:padding-box;border:var(--bs-modal-border-width) solid var(--bs-modal-border-color);border-radius:var(--bs-modal-border-radius);outline:0}.modal-backdrop{--bs-backdrop-zindex: 1050;--bs-backdrop-bg: #000;--bs-backdrop-opacity: .5;position:fixed;top:0;left:0;z-index:var(--bs-backdrop-zindex);width:100vw;height:100vh;background-color:var(--bs-backdrop-bg)}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:var(--bs-backdrop-opacity)}.modal-header{display:flex;flex-shrink:0;align-items:center;justify-content:space-between;padding:var(--bs-modal-header-padding);border-bottom:var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color);border-top-left-radius:var(--bs-modal-inner-border-radius);border-top-right-radius:var(--bs-modal-inner-border-radius)}.modal-header .btn-close{padding:calc(var(--bs-modal-header-padding-y) * .5) calc(var(--bs-modal-header-padding-x) * .5);margin:calc(-.5 * var(--bs-modal-header-padding-y)) calc(-.5 * var(--bs-modal-header-padding-x)) calc(-.5 * var(--bs-modal-header-padding-y)) auto}.modal-title{margin-bottom:0;line-height:var(--bs-modal-title-line-height)}.modal-body{position:relative;flex:1 1 auto;padding:var(--bs-modal-padding)}.modal-footer{display:flex;flex-shrink:0;flex-wrap:wrap;align-items:center;justify-content:flex-end;padding:calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap) * .5);background-color:var(--bs-modal-footer-bg);border-top:var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color);border-bottom-right-radius:var(--bs-modal-inner-border-radius);border-bottom-left-radius:var(--bs-modal-inner-border-radius)}.modal-footer>*{margin:calc(var(--bs-modal-footer-gap) * .5)}@media (min-width: 576px){.modal{--bs-modal-margin: 1.75rem;--bs-modal-box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .15)}.modal-dialog{max-width:var(--bs-modal-width);margin-right:auto;margin-left:auto}.modal-sm{--bs-modal-width: 300px}}@media (min-width: 992px){.modal-lg,.modal-xl{--bs-modal-width: 800px}}@media (min-width: 1200px){.modal-xl{--bs-modal-width: 1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-header,.modal-fullscreen .modal-footer{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}@media (max-width: 575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-header,.modal-fullscreen-sm-down .modal-footer{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@media (max-width: 767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-header,.modal-fullscreen-md-down .modal-footer{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@media (max-width: 991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-header,.modal-fullscreen-lg-down .modal-footer{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@media (max-width: 1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-header,.modal-fullscreen-xl-down .modal-footer{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@media (max-width: 1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xxl-down .modal-header,.modal-fullscreen-xxl-down .modal-footer{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{--bs-tooltip-zindex: 1080;--bs-tooltip-max-width: 200px;--bs-tooltip-padding-x: .5rem;--bs-tooltip-padding-y: .25rem;--bs-tooltip-margin: ;--bs-tooltip-font-size: .875rem;--bs-tooltip-color: var(--bs-body-bg);--bs-tooltip-bg: var(--bs-emphasis-color);--bs-tooltip-border-radius: var(--bs-border-radius);--bs-tooltip-opacity: .9;--bs-tooltip-arrow-width: .8rem;--bs-tooltip-arrow-height: .4rem;z-index:var(--bs-tooltip-zindex);display:block;margin:var(--bs-tooltip-margin);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-tooltip-font-size);word-wrap:break-word;opacity:0}.tooltip.show{opacity:var(--bs-tooltip-opacity)}.tooltip .tooltip-arrow{display:block;width:var(--bs-tooltip-arrow-width);height:var(--bs-tooltip-arrow-height)}.tooltip .tooltip-arrow:before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-top .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow{bottom:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-top .tooltip-arrow:before,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow:before{top:-1px;border-width:var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-top-color:var(--bs-tooltip-bg)}.bs-tooltip-end .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow{left:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-end .tooltip-arrow:before,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow:before{right:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-right-color:var(--bs-tooltip-bg)}.bs-tooltip-bottom .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow{top:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-bottom .tooltip-arrow:before,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow:before{bottom:-1px;border-width:0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-bottom-color:var(--bs-tooltip-bg)}.bs-tooltip-start .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow{right:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-start .tooltip-arrow:before,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow:before{left:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) 0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-left-color:var(--bs-tooltip-bg)}.tooltip-inner{max-width:var(--bs-tooltip-max-width);padding:var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x);color:var(--bs-tooltip-color);text-align:center;background-color:var(--bs-tooltip-bg);border-radius:var(--bs-tooltip-border-radius)}.popover{--bs-popover-zindex: 1070;--bs-popover-max-width: 276px;--bs-popover-font-size: .875rem;--bs-popover-bg: var(--bs-body-bg);--bs-popover-border-width: var(--bs-border-width);--bs-popover-border-color: var(--bs-border-color-translucent);--bs-popover-border-radius: var(--bs-border-radius-lg);--bs-popover-inner-border-radius: calc(var(--bs-border-radius-lg) - var(--bs-border-width));--bs-popover-box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .15);--bs-popover-header-padding-x: 1rem;--bs-popover-header-padding-y: .5rem;--bs-popover-header-font-size: 1rem;--bs-popover-header-color: inherit;--bs-popover-header-bg: var(--bs-secondary-bg);--bs-popover-body-padding-x: 1rem;--bs-popover-body-padding-y: 1rem;--bs-popover-body-color: var(--bs-body-color);--bs-popover-arrow-width: 1rem;--bs-popover-arrow-height: .5rem;--bs-popover-arrow-border: var(--bs-popover-border-color);z-index:var(--bs-popover-zindex);display:block;max-width:var(--bs-popover-max-width);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-popover-font-size);word-wrap:break-word;background-color:var(--bs-popover-bg);background-clip:padding-box;border:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-radius:var(--bs-popover-border-radius)}.popover .popover-arrow{display:block;width:var(--bs-popover-arrow-width);height:var(--bs-popover-arrow-height)}.popover .popover-arrow:before,.popover .popover-arrow:after{position:absolute;display:block;content:"";border-color:transparent;border-style:solid;border-width:0}.bs-popover-top>.popover-arrow,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow{bottom:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-top>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow:before,.bs-popover-top>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow:after{border-width:var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-top>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow:before{bottom:0;border-top-color:var(--bs-popover-arrow-border)}.bs-popover-top>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow:after{bottom:var(--bs-popover-border-width);border-top-color:var(--bs-popover-bg)}.bs-popover-end>.popover-arrow,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow{left:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-end>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow:before,.bs-popover-end>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow:after{border-width:calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-end>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow:before{left:0;border-right-color:var(--bs-popover-arrow-border)}.bs-popover-end>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow:after{left:var(--bs-popover-border-width);border-right-color:var(--bs-popover-bg)}.bs-popover-bottom>.popover-arrow,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow{top:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-bottom>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow:before,.bs-popover-bottom>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow:after{border-width:0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-bottom>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow:before{top:0;border-bottom-color:var(--bs-popover-arrow-border)}.bs-popover-bottom>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow:after{top:var(--bs-popover-border-width);border-bottom-color:var(--bs-popover-bg)}.bs-popover-bottom .popover-header:before,.bs-popover-auto[data-popper-placement^=bottom] .popover-header:before{position:absolute;top:0;left:50%;display:block;width:var(--bs-popover-arrow-width);margin-left:calc(-.5 * var(--bs-popover-arrow-width));content:"";border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-header-bg)}.bs-popover-start>.popover-arrow,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow{right:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-start>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow:before,.bs-popover-start>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow:after{border-width:calc(var(--bs-popover-arrow-width) * .5) 0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-start>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow:before{right:0;border-left-color:var(--bs-popover-arrow-border)}.bs-popover-start>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow:after{right:var(--bs-popover-border-width);border-left-color:var(--bs-popover-bg)}.popover-header{padding:var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x);margin-bottom:0;font-size:var(--bs-popover-header-font-size);color:var(--bs-popover-header-color);background-color:var(--bs-popover-header-bg);border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-top-left-radius:var(--bs-popover-inner-border-radius);border-top-right-radius:var(--bs-popover-inner-border-radius)}.popover-header:empty{display:none}.popover-body{padding:var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x);color:var(--bs-popover-body-color)}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner:after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:transform .6s ease-in-out}@media (prefers-reduced-motion: reduce){.carousel-item{transition:none}}.carousel-item.active,.carousel-item-next,.carousel-item-prev{display:block}.carousel-item-next:not(.carousel-item-start),.active.carousel-item-end{transform:translate(100%)}.carousel-item-prev:not(.carousel-item-end),.active.carousel-item-start{transform:translate(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item.active,.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end{z-index:1;opacity:1}.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion: reduce){.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{transition:none}}.carousel-control-prev,.carousel-control-next{position:absolute;top:0;bottom:0;z-index:1;display:flex;align-items:center;justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:none;border:0;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion: reduce){.carousel-control-prev,.carousel-control-next{transition:none}}.carousel-control-prev:hover,.carousel-control-prev:focus,.carousel-control-next:hover,.carousel-control-next:focus{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-prev-icon,.carousel-control-next-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion: reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-prev-icon,.carousel-dark .carousel-control-next-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}[data-bs-theme=dark] .carousel .carousel-control-prev-icon,[data-bs-theme=dark] .carousel .carousel-control-next-icon,[data-bs-theme=dark].carousel .carousel-control-prev-icon,[data-bs-theme=dark].carousel .carousel-control-next-icon{filter:invert(1) grayscale(100)}[data-bs-theme=dark] .carousel .carousel-indicators [data-bs-target],[data-bs-theme=dark].carousel .carousel-indicators [data-bs-target]{background-color:#000}[data-bs-theme=dark] .carousel .carousel-caption,[data-bs-theme=dark].carousel .carousel-caption{color:#000}.spinner-grow,.spinner-border{display:inline-block;width:var(--bs-spinner-width);height:var(--bs-spinner-height);vertical-align:var(--bs-spinner-vertical-align);border-radius:50%;animation:var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name)}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{--bs-spinner-width: 2rem;--bs-spinner-height: 2rem;--bs-spinner-vertical-align: -.125em;--bs-spinner-border-width: .25em;--bs-spinner-animation-speed: .75s;--bs-spinner-animation-name: spinner-border;border:var(--bs-spinner-border-width) solid currentcolor;border-right-color:transparent}.spinner-border-sm{--bs-spinner-width: 1rem;--bs-spinner-height: 1rem;--bs-spinner-border-width: .2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{--bs-spinner-width: 2rem;--bs-spinner-height: 2rem;--bs-spinner-vertical-align: -.125em;--bs-spinner-animation-speed: .75s;--bs-spinner-animation-name: spinner-grow;background-color:currentcolor;opacity:0}.spinner-grow-sm{--bs-spinner-width: 1rem;--bs-spinner-height: 1rem}@media (prefers-reduced-motion: reduce){.spinner-border,.spinner-grow{--bs-spinner-animation-speed: 1.5s}}.offcanvas,.offcanvas-xxl,.offcanvas-xl,.offcanvas-lg,.offcanvas-md,.offcanvas-sm{--bs-offcanvas-zindex: 1045;--bs-offcanvas-width: 400px;--bs-offcanvas-height: 30vh;--bs-offcanvas-padding-x: 1rem;--bs-offcanvas-padding-y: 1rem;--bs-offcanvas-color: var(--bs-body-color);--bs-offcanvas-bg: var(--bs-body-bg);--bs-offcanvas-border-width: var(--bs-border-width);--bs-offcanvas-border-color: var(--bs-border-color-translucent);--bs-offcanvas-box-shadow: 0 .125rem .25rem rgba(0, 0, 0, .075);--bs-offcanvas-transition: transform .3s ease-in-out;--bs-offcanvas-title-line-height: 1.5}@media (max-width: 575.98px){.offcanvas-sm{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width: 575.98px) and (prefers-reduced-motion: reduce){.offcanvas-sm{transition:none}}@media (max-width: 575.98px){.offcanvas-sm.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(-100%)}}@media (max-width: 575.98px){.offcanvas-sm.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(100%)}}@media (max-width: 575.98px){.offcanvas-sm.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}}@media (max-width: 575.98px){.offcanvas-sm.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}}@media (max-width: 575.98px){.offcanvas-sm.showing,.offcanvas-sm.show:not(.hiding){transform:none}}@media (max-width: 575.98px){.offcanvas-sm.showing,.offcanvas-sm.hiding,.offcanvas-sm.show{visibility:visible}}@media (min-width: 576px){.offcanvas-sm{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-sm .offcanvas-header{display:none}.offcanvas-sm .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width: 767.98px){.offcanvas-md{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width: 767.98px) and (prefers-reduced-motion: reduce){.offcanvas-md{transition:none}}@media (max-width: 767.98px){.offcanvas-md.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(-100%)}}@media (max-width: 767.98px){.offcanvas-md.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(100%)}}@media (max-width: 767.98px){.offcanvas-md.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}}@media (max-width: 767.98px){.offcanvas-md.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}}@media (max-width: 767.98px){.offcanvas-md.showing,.offcanvas-md.show:not(.hiding){transform:none}}@media (max-width: 767.98px){.offcanvas-md.showing,.offcanvas-md.hiding,.offcanvas-md.show{visibility:visible}}@media (min-width: 768px){.offcanvas-md{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-md .offcanvas-header{display:none}.offcanvas-md .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width: 991.98px){.offcanvas-lg{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width: 991.98px) and (prefers-reduced-motion: reduce){.offcanvas-lg{transition:none}}@media (max-width: 991.98px){.offcanvas-lg.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(-100%)}}@media (max-width: 991.98px){.offcanvas-lg.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(100%)}}@media (max-width: 991.98px){.offcanvas-lg.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}}@media (max-width: 991.98px){.offcanvas-lg.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}}@media (max-width: 991.98px){.offcanvas-lg.showing,.offcanvas-lg.show:not(.hiding){transform:none}}@media (max-width: 991.98px){.offcanvas-lg.showing,.offcanvas-lg.hiding,.offcanvas-lg.show{visibility:visible}}@media (min-width: 992px){.offcanvas-lg{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-lg .offcanvas-header{display:none}.offcanvas-lg .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width: 1199.98px){.offcanvas-xl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width: 1199.98px) and (prefers-reduced-motion: reduce){.offcanvas-xl{transition:none}}@media (max-width: 1199.98px){.offcanvas-xl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(-100%)}}@media (max-width: 1199.98px){.offcanvas-xl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(100%)}}@media (max-width: 1199.98px){.offcanvas-xl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}}@media (max-width: 1199.98px){.offcanvas-xl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}}@media (max-width: 1199.98px){.offcanvas-xl.showing,.offcanvas-xl.show:not(.hiding){transform:none}}@media (max-width: 1199.98px){.offcanvas-xl.showing,.offcanvas-xl.hiding,.offcanvas-xl.show{visibility:visible}}@media (min-width: 1200px){.offcanvas-xl{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-xl .offcanvas-header{display:none}.offcanvas-xl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width: 1399.98px){.offcanvas-xxl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width: 1399.98px) and (prefers-reduced-motion: reduce){.offcanvas-xxl{transition:none}}@media (max-width: 1399.98px){.offcanvas-xxl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(-100%)}}@media (max-width: 1399.98px){.offcanvas-xxl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(100%)}}@media (max-width: 1399.98px){.offcanvas-xxl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}}@media (max-width: 1399.98px){.offcanvas-xxl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}}@media (max-width: 1399.98px){.offcanvas-xxl.showing,.offcanvas-xxl.show:not(.hiding){transform:none}}@media (max-width: 1399.98px){.offcanvas-xxl.showing,.offcanvas-xxl.hiding,.offcanvas-xxl.show{visibility:visible}}@media (min-width: 1400px){.offcanvas-xxl{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-xxl .offcanvas-header{display:none}.offcanvas-xxl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}.offcanvas{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}@media (prefers-reduced-motion: reduce){.offcanvas{transition:none}}.offcanvas.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(-100%)}.offcanvas.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(100%)}.offcanvas.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas.showing,.offcanvas.show:not(.hiding){transform:none}.offcanvas.showing,.offcanvas.hiding,.offcanvas.show{visibility:visible}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;align-items:center;justify-content:space-between;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x)}.offcanvas-header .btn-close{padding:calc(var(--bs-offcanvas-padding-y) * .5) calc(var(--bs-offcanvas-padding-x) * .5);margin-top:calc(-.5 * var(--bs-offcanvas-padding-y));margin-right:calc(-.5 * var(--bs-offcanvas-padding-x));margin-bottom:calc(-.5 * var(--bs-offcanvas-padding-y))}.offcanvas-title{margin-bottom:0;line-height:var(--bs-offcanvas-title-line-height)}.offcanvas-body{flex-grow:1;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);overflow-y:auto}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentcolor;opacity:.5}.placeholder.btn:before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{-webkit-mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,.8) 75%,#000 95%);mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,.8) 75%,#000 95%);-webkit-mask-size:200% 100%;mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{to{-webkit-mask-position:-200% 0%;mask-position:-200% 0%}}.clearfix:after{display:block;clear:both;content:""}.text-bg-primary{color:#fff!important;background-color:RGBA(13,110,253,var(--bs-bg-opacity, 1))!important}.text-bg-secondary{color:#fff!important;background-color:RGBA(108,117,125,var(--bs-bg-opacity, 1))!important}.text-bg-success{color:#fff!important;background-color:RGBA(25,135,84,var(--bs-bg-opacity, 1))!important}.text-bg-info{color:#000!important;background-color:RGBA(13,202,240,var(--bs-bg-opacity, 1))!important}.text-bg-warning{color:#000!important;background-color:RGBA(255,193,7,var(--bs-bg-opacity, 1))!important}.text-bg-danger{color:#fff!important;background-color:RGBA(220,53,69,var(--bs-bg-opacity, 1))!important}.text-bg-light{color:#000!important;background-color:RGBA(248,249,250,var(--bs-bg-opacity, 1))!important}.text-bg-dark{color:#fff!important;background-color:RGBA(33,37,41,var(--bs-bg-opacity, 1))!important}.link-primary{color:RGBA(var(--bs-primary-rgb),var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(var(--bs-primary-rgb),var(--bs-link-underline-opacity, 1))!important}.link-primary:hover,.link-primary:focus{color:RGBA(10,88,202,var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(10,88,202,var(--bs-link-underline-opacity, 1))!important}.link-secondary{color:RGBA(var(--bs-secondary-rgb),var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(var(--bs-secondary-rgb),var(--bs-link-underline-opacity, 1))!important}.link-secondary:hover,.link-secondary:focus{color:RGBA(86,94,100,var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(86,94,100,var(--bs-link-underline-opacity, 1))!important}.link-success{color:RGBA(var(--bs-success-rgb),var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(var(--bs-success-rgb),var(--bs-link-underline-opacity, 1))!important}.link-success:hover,.link-success:focus{color:RGBA(20,108,67,var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(20,108,67,var(--bs-link-underline-opacity, 1))!important}.link-info{color:RGBA(var(--bs-info-rgb),var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(var(--bs-info-rgb),var(--bs-link-underline-opacity, 1))!important}.link-info:hover,.link-info:focus{color:RGBA(61,213,243,var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(61,213,243,var(--bs-link-underline-opacity, 1))!important}.link-warning{color:RGBA(var(--bs-warning-rgb),var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(var(--bs-warning-rgb),var(--bs-link-underline-opacity, 1))!important}.link-warning:hover,.link-warning:focus{color:RGBA(255,205,57,var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(255,205,57,var(--bs-link-underline-opacity, 1))!important}.link-danger{color:RGBA(var(--bs-danger-rgb),var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(var(--bs-danger-rgb),var(--bs-link-underline-opacity, 1))!important}.link-danger:hover,.link-danger:focus{color:RGBA(176,42,55,var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(176,42,55,var(--bs-link-underline-opacity, 1))!important}.link-light{color:RGBA(var(--bs-light-rgb),var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(var(--bs-light-rgb),var(--bs-link-underline-opacity, 1))!important}.link-light:hover,.link-light:focus{color:RGBA(249,250,251,var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(249,250,251,var(--bs-link-underline-opacity, 1))!important}.link-dark{color:RGBA(var(--bs-dark-rgb),var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(var(--bs-dark-rgb),var(--bs-link-underline-opacity, 1))!important}.link-dark:hover,.link-dark:focus{color:RGBA(26,30,33,var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(26,30,33,var(--bs-link-underline-opacity, 1))!important}.link-body-emphasis{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity, 1))!important}.link-body-emphasis:hover,.link-body-emphasis:focus{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity, .75))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity, .75))!important}.focus-ring:focus{outline:0;box-shadow:var(--bs-focus-ring-x, 0) var(--bs-focus-ring-y, 0) var(--bs-focus-ring-blur, 0) var(--bs-focus-ring-width) var(--bs-focus-ring-color)}.icon-link{display:inline-flex;gap:.375rem;align-items:center;text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity, .5));text-underline-offset:.25em;-webkit-backface-visibility:hidden;backface-visibility:hidden}.icon-link>.bi{flex-shrink:0;width:1em;height:1em;fill:currentcolor;transition:.2s ease-in-out transform}@media (prefers-reduced-motion: reduce){.icon-link>.bi{transition:none}}.icon-link-hover:hover>.bi,.icon-link-hover:focus-visible>.bi{transform:var(--bs-icon-link-transform, translate3d(.25em, 0, 0))}.ratio{position:relative;width:100%}.ratio:before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio: 100%}.ratio-4x3{--bs-aspect-ratio: 75%}.ratio-16x9{--bs-aspect-ratio: 56.25%}.ratio-21x9{--bs-aspect-ratio: 42.8571428571%}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:sticky;top:0;z-index:1020}.sticky-bottom{position:sticky;bottom:0;z-index:1020}@media (min-width: 576px){.sticky-sm-top{position:sticky;top:0;z-index:1020}.sticky-sm-bottom{position:sticky;bottom:0;z-index:1020}}@media (min-width: 768px){.sticky-md-top{position:sticky;top:0;z-index:1020}.sticky-md-bottom{position:sticky;bottom:0;z-index:1020}}@media (min-width: 992px){.sticky-lg-top{position:sticky;top:0;z-index:1020}.sticky-lg-bottom{position:sticky;bottom:0;z-index:1020}}@media (min-width: 1200px){.sticky-xl-top{position:sticky;top:0;z-index:1020}.sticky-xl-bottom{position:sticky;bottom:0;z-index:1020}}@media (min-width: 1400px){.sticky-xxl-top{position:sticky;top:0;z-index:1020}.sticky-xxl-bottom{position:sticky;bottom:0;z-index:1020}}.hstack{display:flex;flex-direction:row;align-items:center;align-self:stretch}.vstack{display:flex;flex:1 1 auto;flex-direction:column;align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.visually-hidden:not(caption),.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption){position:absolute!important}.stretched-link:after{position:absolute;inset:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;width:1px;min-height:1em;background-color:currentcolor;opacity:.25}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.float-start{float:left!important}.float-end{float:right!important}.float-none{float:none!important}.object-fit-contain{object-fit:contain!important}.object-fit-cover{object-fit:cover!important}.object-fit-fill{object-fit:fill!important}.object-fit-scale{object-fit:scale-down!important}.object-fit-none{object-fit:none!important}.opacity-0{opacity:0!important}.opacity-25{opacity:.25!important}.opacity-50{opacity:.5!important}.opacity-75{opacity:.75!important}.opacity-100{opacity:1!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-visible{overflow:visible!important}.overflow-scroll{overflow:scroll!important}.overflow-x-auto{overflow-x:auto!important}.overflow-x-hidden{overflow-x:hidden!important}.overflow-x-visible{overflow-x:visible!important}.overflow-x-scroll{overflow-x:scroll!important}.overflow-y-auto{overflow-y:auto!important}.overflow-y-hidden{overflow-y:hidden!important}.overflow-y-visible{overflow-y:visible!important}.overflow-y-scroll{overflow-y:scroll!important}.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}.shadow{box-shadow:0 .5rem 1rem #00000026!important}.shadow-sm{box-shadow:0 .125rem .25rem #00000013!important}.shadow-lg{box-shadow:0 1rem 3rem #0000002d!important}.shadow-none{box-shadow:none!important}.focus-ring-primary{--bs-focus-ring-color: rgba(var(--bs-primary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-secondary{--bs-focus-ring-color: rgba(var(--bs-secondary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-success{--bs-focus-ring-color: rgba(var(--bs-success-rgb), var(--bs-focus-ring-opacity))}.focus-ring-info{--bs-focus-ring-color: rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity))}.focus-ring-warning{--bs-focus-ring-color: rgba(var(--bs-warning-rgb), var(--bs-focus-ring-opacity))}.focus-ring-danger{--bs-focus-ring-color: rgba(var(--bs-danger-rgb), var(--bs-focus-ring-opacity))}.focus-ring-light{--bs-focus-ring-color: rgba(var(--bs-light-rgb), var(--bs-focus-ring-opacity))}.focus-ring-dark{--bs-focus-ring-color: rgba(var(--bs-dark-rgb), var(--bs-focus-ring-opacity))}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:sticky!important}.top-0{top:0!important}.top-50{top:50%!important}.top-100{top:100%!important}.bottom-0{bottom:0!important}.bottom-50{bottom:50%!important}.bottom-100{bottom:100%!important}.start-0{left:0!important}.start-50{left:50%!important}.start-100{left:100%!important}.end-0{right:0!important}.end-50{right:50%!important}.end-100{right:100%!important}.translate-middle{transform:translate(-50%,-50%)!important}.translate-middle-x{transform:translate(-50%)!important}.translate-middle-y{transform:translateY(-50%)!important}.border{border:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-0{border:0!important}.border-top{border-top:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-top-0{border-top:0!important}.border-end{border-right:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-end-0{border-right:0!important}.border-bottom{border-bottom:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-bottom-0{border-bottom:0!important}.border-start{border-left:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-start-0{border-left:0!important}.border-primary{--bs-border-opacity: 1;border-color:rgba(var(--bs-primary-rgb),var(--bs-border-opacity))!important}.border-secondary{--bs-border-opacity: 1;border-color:rgba(var(--bs-secondary-rgb),var(--bs-border-opacity))!important}.border-success{--bs-border-opacity: 1;border-color:rgba(var(--bs-success-rgb),var(--bs-border-opacity))!important}.border-info{--bs-border-opacity: 1;border-color:rgba(var(--bs-info-rgb),var(--bs-border-opacity))!important}.border-warning{--bs-border-opacity: 1;border-color:rgba(var(--bs-warning-rgb),var(--bs-border-opacity))!important}.border-danger{--bs-border-opacity: 1;border-color:rgba(var(--bs-danger-rgb),var(--bs-border-opacity))!important}.border-light{--bs-border-opacity: 1;border-color:rgba(var(--bs-light-rgb),var(--bs-border-opacity))!important}.border-dark{--bs-border-opacity: 1;border-color:rgba(var(--bs-dark-rgb),var(--bs-border-opacity))!important}.border-black{--bs-border-opacity: 1;border-color:rgba(var(--bs-black-rgb),var(--bs-border-opacity))!important}.border-white{--bs-border-opacity: 1;border-color:rgba(var(--bs-white-rgb),var(--bs-border-opacity))!important}.border-primary-subtle{border-color:var(--bs-primary-border-subtle)!important}.border-secondary-subtle{border-color:var(--bs-secondary-border-subtle)!important}.border-success-subtle{border-color:var(--bs-success-border-subtle)!important}.border-info-subtle{border-color:var(--bs-info-border-subtle)!important}.border-warning-subtle{border-color:var(--bs-warning-border-subtle)!important}.border-danger-subtle{border-color:var(--bs-danger-border-subtle)!important}.border-light-subtle{border-color:var(--bs-light-border-subtle)!important}.border-dark-subtle{border-color:var(--bs-dark-border-subtle)!important}.border-1{border-width:1px!important}.border-2{border-width:2px!important}.border-3{border-width:3px!important}.border-4{border-width:4px!important}.border-5{border-width:5px!important}.border-opacity-10{--bs-border-opacity: .1}.border-opacity-25{--bs-border-opacity: .25}.border-opacity-50{--bs-border-opacity: .5}.border-opacity-75{--bs-border-opacity: .75}.border-opacity-100{--bs-border-opacity: 1}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.mw-100{max-width:100%!important}.vw-100{width:100vw!important}.min-vw-100{min-width:100vw!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mh-100{max-height:100%!important}.vh-100{height:100vh!important}.min-vh-100{min-height:100vh!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}.gap-0{gap:0!important}.gap-1{gap:.25rem!important}.gap-2{gap:.5rem!important}.gap-3{gap:1rem!important}.gap-4{gap:1.5rem!important}.gap-5{gap:3rem!important}.row-gap-0{row-gap:0!important}.row-gap-1{row-gap:.25rem!important}.row-gap-2{row-gap:.5rem!important}.row-gap-3{row-gap:1rem!important}.row-gap-4{row-gap:1.5rem!important}.row-gap-5{row-gap:3rem!important}.column-gap-0{column-gap:0!important}.column-gap-1{column-gap:.25rem!important}.column-gap-2{column-gap:.5rem!important}.column-gap-3{column-gap:1rem!important}.column-gap-4{column-gap:1.5rem!important}.column-gap-5{column-gap:3rem!important}.font-monospace{font-family:var(--bs-font-monospace)!important}.fs-1{font-size:calc(1.375rem + 1.5vw)!important}.fs-2{font-size:calc(1.325rem + .9vw)!important}.fs-3{font-size:calc(1.3rem + .6vw)!important}.fs-4{font-size:calc(1.275rem + .3vw)!important}.fs-5{font-size:1.25rem!important}.fs-6{font-size:1rem!important}.fst-italic{font-style:italic!important}.fst-normal{font-style:normal!important}.fw-lighter{font-weight:lighter!important}.fw-light{font-weight:300!important}.fw-normal{font-weight:400!important}.fw-medium{font-weight:500!important}.fw-semibold{font-weight:600!important}.fw-bold{font-weight:700!important}.fw-bolder{font-weight:bolder!important}.lh-1{line-height:1!important}.lh-sm{line-height:1.25!important}.lh-base{line-height:1.5!important}.lh-lg{line-height:2!important}.text-start{text-align:left!important}.text-end{text-align:right!important}.text-center{text-align:center!important}.text-decoration-none{text-decoration:none!important}.text-decoration-underline{text-decoration:underline!important}.text-decoration-line-through{text-decoration:line-through!important}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-break{word-wrap:break-word!important;word-break:break-word!important}.text-primary{--bs-text-opacity: 1;color:rgba(var(--bs-primary-rgb),var(--bs-text-opacity))!important}.text-secondary{--bs-text-opacity: 1;color:rgba(var(--bs-secondary-rgb),var(--bs-text-opacity))!important}.text-success{--bs-text-opacity: 1;color:rgba(var(--bs-success-rgb),var(--bs-text-opacity))!important}.text-info{--bs-text-opacity: 1;color:rgba(var(--bs-info-rgb),var(--bs-text-opacity))!important}.text-warning{--bs-text-opacity: 1;color:rgba(var(--bs-warning-rgb),var(--bs-text-opacity))!important}.text-danger{--bs-text-opacity: 1;color:rgba(var(--bs-danger-rgb),var(--bs-text-opacity))!important}.text-light{--bs-text-opacity: 1;color:rgba(var(--bs-light-rgb),var(--bs-text-opacity))!important}.text-dark{--bs-text-opacity: 1;color:rgba(var(--bs-dark-rgb),var(--bs-text-opacity))!important}.text-black{--bs-text-opacity: 1;color:rgba(var(--bs-black-rgb),var(--bs-text-opacity))!important}.text-white{--bs-text-opacity: 1;color:rgba(var(--bs-white-rgb),var(--bs-text-opacity))!important}.text-body{--bs-text-opacity: 1;color:rgba(var(--bs-body-color-rgb),var(--bs-text-opacity))!important}.text-muted{--bs-text-opacity: 1;color:var(--bs-secondary-color)!important}.text-black-50{--bs-text-opacity: 1;color:#00000080!important}.text-white-50{--bs-text-opacity: 1;color:#ffffff80!important}.text-body-secondary{--bs-text-opacity: 1;color:var(--bs-secondary-color)!important}.text-body-tertiary{--bs-text-opacity: 1;color:var(--bs-tertiary-color)!important}.text-body-emphasis{--bs-text-opacity: 1;color:var(--bs-emphasis-color)!important}.text-reset{--bs-text-opacity: 1;color:inherit!important}.text-opacity-25{--bs-text-opacity: .25}.text-opacity-50{--bs-text-opacity: .5}.text-opacity-75{--bs-text-opacity: .75}.text-opacity-100{--bs-text-opacity: 1}.text-primary-emphasis{color:var(--bs-primary-text-emphasis)!important}.text-secondary-emphasis{color:var(--bs-secondary-text-emphasis)!important}.text-success-emphasis{color:var(--bs-success-text-emphasis)!important}.text-info-emphasis{color:var(--bs-info-text-emphasis)!important}.text-warning-emphasis{color:var(--bs-warning-text-emphasis)!important}.text-danger-emphasis{color:var(--bs-danger-text-emphasis)!important}.text-light-emphasis{color:var(--bs-light-text-emphasis)!important}.text-dark-emphasis{color:var(--bs-dark-text-emphasis)!important}.link-opacity-10,.link-opacity-10-hover:hover{--bs-link-opacity: .1}.link-opacity-25,.link-opacity-25-hover:hover{--bs-link-opacity: .25}.link-opacity-50,.link-opacity-50-hover:hover{--bs-link-opacity: .5}.link-opacity-75,.link-opacity-75-hover:hover{--bs-link-opacity: .75}.link-opacity-100,.link-opacity-100-hover:hover{--bs-link-opacity: 1}.link-offset-1,.link-offset-1-hover:hover{text-underline-offset:.125em!important}.link-offset-2,.link-offset-2-hover:hover{text-underline-offset:.25em!important}.link-offset-3,.link-offset-3-hover:hover{text-underline-offset:.375em!important}.link-underline-primary{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-primary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-secondary{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-secondary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-success{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-success-rgb),var(--bs-link-underline-opacity))!important}.link-underline-info{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-info-rgb),var(--bs-link-underline-opacity))!important}.link-underline-warning{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-warning-rgb),var(--bs-link-underline-opacity))!important}.link-underline-danger{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-danger-rgb),var(--bs-link-underline-opacity))!important}.link-underline-light{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-light-rgb),var(--bs-link-underline-opacity))!important}.link-underline-dark{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-dark-rgb),var(--bs-link-underline-opacity))!important}.link-underline{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-underline-opacity, 1))!important}.link-underline-opacity-0,.link-underline-opacity-0-hover:hover{--bs-link-underline-opacity: 0}.link-underline-opacity-10,.link-underline-opacity-10-hover:hover{--bs-link-underline-opacity: .1}.link-underline-opacity-25,.link-underline-opacity-25-hover:hover{--bs-link-underline-opacity: .25}.link-underline-opacity-50,.link-underline-opacity-50-hover:hover{--bs-link-underline-opacity: .5}.link-underline-opacity-75,.link-underline-opacity-75-hover:hover{--bs-link-underline-opacity: .75}.link-underline-opacity-100,.link-underline-opacity-100-hover:hover{--bs-link-underline-opacity: 1}.bg-primary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-primary-rgb),var(--bs-bg-opacity))!important}.bg-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-rgb),var(--bs-bg-opacity))!important}.bg-success{--bs-bg-opacity: 1;background-color:rgba(var(--bs-success-rgb),var(--bs-bg-opacity))!important}.bg-info{--bs-bg-opacity: 1;background-color:rgba(var(--bs-info-rgb),var(--bs-bg-opacity))!important}.bg-warning{--bs-bg-opacity: 1;background-color:rgba(var(--bs-warning-rgb),var(--bs-bg-opacity))!important}.bg-danger{--bs-bg-opacity: 1;background-color:rgba(var(--bs-danger-rgb),var(--bs-bg-opacity))!important}.bg-light{--bs-bg-opacity: 1;background-color:rgba(var(--bs-light-rgb),var(--bs-bg-opacity))!important}.bg-dark{--bs-bg-opacity: 1;background-color:rgba(var(--bs-dark-rgb),var(--bs-bg-opacity))!important}.bg-black{--bs-bg-opacity: 1;background-color:rgba(var(--bs-black-rgb),var(--bs-bg-opacity))!important}.bg-white{--bs-bg-opacity: 1;background-color:rgba(var(--bs-white-rgb),var(--bs-bg-opacity))!important}.bg-body{--bs-bg-opacity: 1;background-color:rgba(var(--bs-body-bg-rgb),var(--bs-bg-opacity))!important}.bg-transparent{--bs-bg-opacity: 1;background-color:transparent!important}.bg-body-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-bg-rgb),var(--bs-bg-opacity))!important}.bg-body-tertiary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-tertiary-bg-rgb),var(--bs-bg-opacity))!important}.bg-opacity-10{--bs-bg-opacity: .1}.bg-opacity-25{--bs-bg-opacity: .25}.bg-opacity-50{--bs-bg-opacity: .5}.bg-opacity-75{--bs-bg-opacity: .75}.bg-opacity-100{--bs-bg-opacity: 1}.bg-primary-subtle{background-color:var(--bs-primary-bg-subtle)!important}.bg-secondary-subtle{background-color:var(--bs-secondary-bg-subtle)!important}.bg-success-subtle{background-color:var(--bs-success-bg-subtle)!important}.bg-info-subtle{background-color:var(--bs-info-bg-subtle)!important}.bg-warning-subtle{background-color:var(--bs-warning-bg-subtle)!important}.bg-danger-subtle{background-color:var(--bs-danger-bg-subtle)!important}.bg-light-subtle{background-color:var(--bs-light-bg-subtle)!important}.bg-dark-subtle{background-color:var(--bs-dark-bg-subtle)!important}.bg-gradient{background-image:var(--bs-gradient)!important}.user-select-all{-webkit-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;user-select:none!important}.pe-none{pointer-events:none!important}.pe-auto{pointer-events:auto!important}.rounded{border-radius:var(--bs-border-radius)!important}.rounded-0{border-radius:0!important}.rounded-1{border-radius:var(--bs-border-radius-sm)!important}.rounded-2{border-radius:var(--bs-border-radius)!important}.rounded-3{border-radius:var(--bs-border-radius-lg)!important}.rounded-4{border-radius:var(--bs-border-radius-xl)!important}.rounded-5{border-radius:var(--bs-border-radius-xxl)!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:var(--bs-border-radius-pill)!important}.rounded-top{border-top-left-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-top-0{border-top-left-radius:0!important;border-top-right-radius:0!important}.rounded-top-1{border-top-left-radius:var(--bs-border-radius-sm)!important;border-top-right-radius:var(--bs-border-radius-sm)!important}.rounded-top-2{border-top-left-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-top-3{border-top-left-radius:var(--bs-border-radius-lg)!important;border-top-right-radius:var(--bs-border-radius-lg)!important}.rounded-top-4{border-top-left-radius:var(--bs-border-radius-xl)!important;border-top-right-radius:var(--bs-border-radius-xl)!important}.rounded-top-5{border-top-left-radius:var(--bs-border-radius-xxl)!important;border-top-right-radius:var(--bs-border-radius-xxl)!important}.rounded-top-circle{border-top-left-radius:50%!important;border-top-right-radius:50%!important}.rounded-top-pill{border-top-left-radius:var(--bs-border-radius-pill)!important;border-top-right-radius:var(--bs-border-radius-pill)!important}.rounded-end{border-top-right-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-end-0{border-top-right-radius:0!important;border-bottom-right-radius:0!important}.rounded-end-1{border-top-right-radius:var(--bs-border-radius-sm)!important;border-bottom-right-radius:var(--bs-border-radius-sm)!important}.rounded-end-2{border-top-right-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-end-3{border-top-right-radius:var(--bs-border-radius-lg)!important;border-bottom-right-radius:var(--bs-border-radius-lg)!important}.rounded-end-4{border-top-right-radius:var(--bs-border-radius-xl)!important;border-bottom-right-radius:var(--bs-border-radius-xl)!important}.rounded-end-5{border-top-right-radius:var(--bs-border-radius-xxl)!important;border-bottom-right-radius:var(--bs-border-radius-xxl)!important}.rounded-end-circle{border-top-right-radius:50%!important;border-bottom-right-radius:50%!important}.rounded-end-pill{border-top-right-radius:var(--bs-border-radius-pill)!important;border-bottom-right-radius:var(--bs-border-radius-pill)!important}.rounded-bottom{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-bottom-0{border-bottom-right-radius:0!important;border-bottom-left-radius:0!important}.rounded-bottom-1{border-bottom-right-radius:var(--bs-border-radius-sm)!important;border-bottom-left-radius:var(--bs-border-radius-sm)!important}.rounded-bottom-2{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-bottom-3{border-bottom-right-radius:var(--bs-border-radius-lg)!important;border-bottom-left-radius:var(--bs-border-radius-lg)!important}.rounded-bottom-4{border-bottom-right-radius:var(--bs-border-radius-xl)!important;border-bottom-left-radius:var(--bs-border-radius-xl)!important}.rounded-bottom-5{border-bottom-right-radius:var(--bs-border-radius-xxl)!important;border-bottom-left-radius:var(--bs-border-radius-xxl)!important}.rounded-bottom-circle{border-bottom-right-radius:50%!important;border-bottom-left-radius:50%!important}.rounded-bottom-pill{border-bottom-right-radius:var(--bs-border-radius-pill)!important;border-bottom-left-radius:var(--bs-border-radius-pill)!important}.rounded-start{border-bottom-left-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-start-0{border-bottom-left-radius:0!important;border-top-left-radius:0!important}.rounded-start-1{border-bottom-left-radius:var(--bs-border-radius-sm)!important;border-top-left-radius:var(--bs-border-radius-sm)!important}.rounded-start-2{border-bottom-left-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-start-3{border-bottom-left-radius:var(--bs-border-radius-lg)!important;border-top-left-radius:var(--bs-border-radius-lg)!important}.rounded-start-4{border-bottom-left-radius:var(--bs-border-radius-xl)!important;border-top-left-radius:var(--bs-border-radius-xl)!important}.rounded-start-5{border-bottom-left-radius:var(--bs-border-radius-xxl)!important;border-top-left-radius:var(--bs-border-radius-xxl)!important}.rounded-start-circle{border-bottom-left-radius:50%!important;border-top-left-radius:50%!important}.rounded-start-pill{border-bottom-left-radius:var(--bs-border-radius-pill)!important;border-top-left-radius:var(--bs-border-radius-pill)!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}.z-n1{z-index:-1!important}.z-0{z-index:0!important}.z-1{z-index:1!important}.z-2{z-index:2!important}.z-3{z-index:3!important}@media (min-width: 576px){.float-sm-start{float:left!important}.float-sm-end{float:right!important}.float-sm-none{float:none!important}.object-fit-sm-contain{object-fit:contain!important}.object-fit-sm-cover{object-fit:cover!important}.object-fit-sm-fill{object-fit:fill!important}.object-fit-sm-scale{object-fit:scale-down!important}.object-fit-sm-none{object-fit:none!important}.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}.gap-sm-0{gap:0!important}.gap-sm-1{gap:.25rem!important}.gap-sm-2{gap:.5rem!important}.gap-sm-3{gap:1rem!important}.gap-sm-4{gap:1.5rem!important}.gap-sm-5{gap:3rem!important}.row-gap-sm-0{row-gap:0!important}.row-gap-sm-1{row-gap:.25rem!important}.row-gap-sm-2{row-gap:.5rem!important}.row-gap-sm-3{row-gap:1rem!important}.row-gap-sm-4{row-gap:1.5rem!important}.row-gap-sm-5{row-gap:3rem!important}.column-gap-sm-0{column-gap:0!important}.column-gap-sm-1{column-gap:.25rem!important}.column-gap-sm-2{column-gap:.5rem!important}.column-gap-sm-3{column-gap:1rem!important}.column-gap-sm-4{column-gap:1.5rem!important}.column-gap-sm-5{column-gap:3rem!important}.text-sm-start{text-align:left!important}.text-sm-end{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width: 768px){.float-md-start{float:left!important}.float-md-end{float:right!important}.float-md-none{float:none!important}.object-fit-md-contain{object-fit:contain!important}.object-fit-md-cover{object-fit:cover!important}.object-fit-md-fill{object-fit:fill!important}.object-fit-md-scale{object-fit:scale-down!important}.object-fit-md-none{object-fit:none!important}.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}.gap-md-0{gap:0!important}.gap-md-1{gap:.25rem!important}.gap-md-2{gap:.5rem!important}.gap-md-3{gap:1rem!important}.gap-md-4{gap:1.5rem!important}.gap-md-5{gap:3rem!important}.row-gap-md-0{row-gap:0!important}.row-gap-md-1{row-gap:.25rem!important}.row-gap-md-2{row-gap:.5rem!important}.row-gap-md-3{row-gap:1rem!important}.row-gap-md-4{row-gap:1.5rem!important}.row-gap-md-5{row-gap:3rem!important}.column-gap-md-0{column-gap:0!important}.column-gap-md-1{column-gap:.25rem!important}.column-gap-md-2{column-gap:.5rem!important}.column-gap-md-3{column-gap:1rem!important}.column-gap-md-4{column-gap:1.5rem!important}.column-gap-md-5{column-gap:3rem!important}.text-md-start{text-align:left!important}.text-md-end{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width: 992px){.float-lg-start{float:left!important}.float-lg-end{float:right!important}.float-lg-none{float:none!important}.object-fit-lg-contain{object-fit:contain!important}.object-fit-lg-cover{object-fit:cover!important}.object-fit-lg-fill{object-fit:fill!important}.object-fit-lg-scale{object-fit:scale-down!important}.object-fit-lg-none{object-fit:none!important}.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}.gap-lg-0{gap:0!important}.gap-lg-1{gap:.25rem!important}.gap-lg-2{gap:.5rem!important}.gap-lg-3{gap:1rem!important}.gap-lg-4{gap:1.5rem!important}.gap-lg-5{gap:3rem!important}.row-gap-lg-0{row-gap:0!important}.row-gap-lg-1{row-gap:.25rem!important}.row-gap-lg-2{row-gap:.5rem!important}.row-gap-lg-3{row-gap:1rem!important}.row-gap-lg-4{row-gap:1.5rem!important}.row-gap-lg-5{row-gap:3rem!important}.column-gap-lg-0{column-gap:0!important}.column-gap-lg-1{column-gap:.25rem!important}.column-gap-lg-2{column-gap:.5rem!important}.column-gap-lg-3{column-gap:1rem!important}.column-gap-lg-4{column-gap:1.5rem!important}.column-gap-lg-5{column-gap:3rem!important}.text-lg-start{text-align:left!important}.text-lg-end{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width: 1200px){.float-xl-start{float:left!important}.float-xl-end{float:right!important}.float-xl-none{float:none!important}.object-fit-xl-contain{object-fit:contain!important}.object-fit-xl-cover{object-fit:cover!important}.object-fit-xl-fill{object-fit:fill!important}.object-fit-xl-scale{object-fit:scale-down!important}.object-fit-xl-none{object-fit:none!important}.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}.gap-xl-0{gap:0!important}.gap-xl-1{gap:.25rem!important}.gap-xl-2{gap:.5rem!important}.gap-xl-3{gap:1rem!important}.gap-xl-4{gap:1.5rem!important}.gap-xl-5{gap:3rem!important}.row-gap-xl-0{row-gap:0!important}.row-gap-xl-1{row-gap:.25rem!important}.row-gap-xl-2{row-gap:.5rem!important}.row-gap-xl-3{row-gap:1rem!important}.row-gap-xl-4{row-gap:1.5rem!important}.row-gap-xl-5{row-gap:3rem!important}.column-gap-xl-0{column-gap:0!important}.column-gap-xl-1{column-gap:.25rem!important}.column-gap-xl-2{column-gap:.5rem!important}.column-gap-xl-3{column-gap:1rem!important}.column-gap-xl-4{column-gap:1.5rem!important}.column-gap-xl-5{column-gap:3rem!important}.text-xl-start{text-align:left!important}.text-xl-end{text-align:right!important}.text-xl-center{text-align:center!important}}@media (min-width: 1400px){.float-xxl-start{float:left!important}.float-xxl-end{float:right!important}.float-xxl-none{float:none!important}.object-fit-xxl-contain{object-fit:contain!important}.object-fit-xxl-cover{object-fit:cover!important}.object-fit-xxl-fill{object-fit:fill!important}.object-fit-xxl-scale{object-fit:scale-down!important}.object-fit-xxl-none{object-fit:none!important}.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}.gap-xxl-0{gap:0!important}.gap-xxl-1{gap:.25rem!important}.gap-xxl-2{gap:.5rem!important}.gap-xxl-3{gap:1rem!important}.gap-xxl-4{gap:1.5rem!important}.gap-xxl-5{gap:3rem!important}.row-gap-xxl-0{row-gap:0!important}.row-gap-xxl-1{row-gap:.25rem!important}.row-gap-xxl-2{row-gap:.5rem!important}.row-gap-xxl-3{row-gap:1rem!important}.row-gap-xxl-4{row-gap:1.5rem!important}.row-gap-xxl-5{row-gap:3rem!important}.column-gap-xxl-0{column-gap:0!important}.column-gap-xxl-1{column-gap:.25rem!important}.column-gap-xxl-2{column-gap:.5rem!important}.column-gap-xxl-3{column-gap:1rem!important}.column-gap-xxl-4{column-gap:1.5rem!important}.column-gap-xxl-5{column-gap:3rem!important}.text-xxl-start{text-align:left!important}.text-xxl-end{text-align:right!important}.text-xxl-center{text-align:center!important}}@media (min-width: 1200px){.fs-1{font-size:2.5rem!important}.fs-2{font-size:2rem!important}.fs-3{font-size:1.75rem!important}.fs-4{font-size:1.5rem!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}} diff --git a/src/KafkaFlow.Admin.Dashboard/ClientApp/src/app/api/models/consumer.ts b/src/KafkaFlow.Admin.Dashboard/ClientApp/src/app/api/models/consumer.ts index 238a83aca..618e77870 100644 --- a/src/KafkaFlow.Admin.Dashboard/ClientApp/src/app/api/models/consumer.ts +++ b/src/KafkaFlow.Admin.Dashboard/ClientApp/src/app/api/models/consumer.ts @@ -4,5 +4,4 @@ import { TopicPartitionAssignment } from './topic-partition-assignment'; export interface Consumer { assignments?: null | Array; name: string; - workersCount?: number; } diff --git a/src/KafkaFlow.Admin.Dashboard/ClientApp/src/app/api/models/topic-partition-assignment.ts b/src/KafkaFlow.Admin.Dashboard/ClientApp/src/app/api/models/topic-partition-assignment.ts index 049a70f96..4f27a1ff0 100644 --- a/src/KafkaFlow.Admin.Dashboard/ClientApp/src/app/api/models/topic-partition-assignment.ts +++ b/src/KafkaFlow.Admin.Dashboard/ClientApp/src/app/api/models/topic-partition-assignment.ts @@ -3,6 +3,7 @@ export interface TopicPartitionAssignment { instanceName: string; lag?: number; + workers: number; lastUpdate?: string; pausedPartitions?: null | Array; runningPartitions?: null | Array; diff --git a/src/KafkaFlow.Admin.Dashboard/ClientApp/src/app/consumer/consumer.component.html b/src/KafkaFlow.Admin.Dashboard/ClientApp/src/app/consumer/consumer.component.html index 1a44cf9d8..eff1e0c2a 100644 --- a/src/KafkaFlow.Admin.Dashboard/ClientApp/src/app/consumer/consumer.component.html +++ b/src/KafkaFlow.Admin.Dashboard/ClientApp/src/app/consumer/consumer.component.html @@ -15,11 +15,9 @@

Status: Start +

Lag: {{$any(consumer).lag}}

-

Workers: {{consumer.workersCount}} - -


@@ -33,6 +31,7 @@
Consumer instance + Workers Partitions Lag Status @@ -43,6 +42,7 @@
{{partitionAssignment.instanceName}} + {{partitionAssignment.workers}} {{hasRunningPartition(partitionAssignment) ? partitionAssignment.runningPartitions : partitionAssignment.pausedPartitions}} {{partitionAssignment.lag}} diff --git a/src/KafkaFlow.Admin.Dashboard/ClientApp/src/app/consumer/consumer.component.ts b/src/KafkaFlow.Admin.Dashboard/ClientApp/src/app/consumer/consumer.component.ts index f0bd55695..77f321fa0 100644 --- a/src/KafkaFlow.Admin.Dashboard/ClientApp/src/app/consumer/consumer.component.ts +++ b/src/KafkaFlow.Admin.Dashboard/ClientApp/src/app/consumer/consumer.component.ts @@ -77,12 +77,11 @@ export class ConsumerComponent implements OnInit { isActive = (date: string) => Math.abs((new Date().getTime() - new Date(date + 'Z').getTime()) / 1000) < 30; - openWorkersCountModal = (groupId: string, consumerName: string, workersCount?: number) => { + openWorkersCountModal = (groupId: string, consumerName: string) => { const modalRef = this.modalService.open(WorkersCountModalComponent); modalRef.componentInstance.groupId = groupId; modalRef.componentInstance.consumerName = consumerName; - modalRef.componentInstance.workersCount = workersCount; modalRef.result.then((newWorkersCount: number) => { diff --git a/src/KafkaFlow.Admin.Dashboard/ClientApp/src/app/consumer/shared/workers-count-modal/workers-count-modal.component.html b/src/KafkaFlow.Admin.Dashboard/ClientApp/src/app/consumer/shared/workers-count-modal/workers-count-modal.component.html index 1c2b79570..9d0f67bc3 100644 --- a/src/KafkaFlow.Admin.Dashboard/ClientApp/src/app/consumer/shared/workers-count-modal/workers-count-modal.component.html +++ b/src/KafkaFlow.Admin.Dashboard/ClientApp/src/app/consumer/shared/workers-count-modal/workers-count-modal.component.html @@ -8,10 +8,6 @@
public long Lag { get; set; } + + /// + /// Gets or sets the workers count + /// + public int Workers { get; set; } } } } diff --git a/src/KafkaFlow.Admin.Dashboard/TelemetryResponseAdapter.cs b/src/KafkaFlow.Admin.Dashboard/TelemetryResponseAdapter.cs index 7977d9aed..d86045671 100644 --- a/src/KafkaFlow.Admin.Dashboard/TelemetryResponseAdapter.cs +++ b/src/KafkaFlow.Admin.Dashboard/TelemetryResponseAdapter.cs @@ -28,10 +28,6 @@ internal static TelemetryResponse Adapt(this IEnumerable x.SentAt) - .First() - .WorkersCount, Assignments = consumerMetricsList .OrderBy(x => x.Topic) .Select( @@ -40,6 +36,7 @@ internal static TelemetryResponse Adapt(this IEnumerable (x.Key, x.Value))) { - if (this.dateTimeProvider.Now - metric.SentAt > this.expiryTime) + if (this.dateTimeProvider.UtcNow - metric.SentAt > this.expiryTime) { this.metrics.TryRemove(key, out _); } @@ -70,6 +70,6 @@ private void CleanExpiredItems() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private bool NeedsClean() => this.dateTimeProvider.Now - this.lastCleanDate > this.cleanRunInterval; + private bool NeedsCleaning() => this.dateTimeProvider.Now - this.lastCleanDate > this.cleanRunInterval; } } diff --git a/src/KafkaFlow.Admin/TelemetryScheduler.cs b/src/KafkaFlow.Admin/TelemetryScheduler.cs index 8da5ba82f..b3aaaec69 100644 --- a/src/KafkaFlow.Admin/TelemetryScheduler.cs +++ b/src/KafkaFlow.Admin/TelemetryScheduler.cs @@ -14,10 +14,12 @@ internal class TelemetryScheduler : ITelemetryScheduler private static readonly int ProcessId = Process.GetCurrentProcess().Id; private readonly Dictionary timers = new(); private readonly IDependencyResolver dependencyResolver; + private readonly ILogHandler logHandler; public TelemetryScheduler(IDependencyResolver dependencyResolver) { this.dependencyResolver = dependencyResolver; + this.logHandler = dependencyResolver.Resolve(); } public void Start(string telemetryId, string topicName, int topicPartition) @@ -53,41 +55,48 @@ public void Stop(string telemetryId) } } - private static void ProduceTelemetry( + private void ProduceTelemetry( string topicName, int partition, IEnumerable consumers, IMessageProducer producer) { - var items = consumers - .SelectMany( - c => - { - var consumerLag = c.GetTopicPartitionsLag(); + try + { + var items = consumers + .SelectMany( + c => + { + var consumerLag = c.GetTopicPartitionsLag(); - return c.Topics.Select( - topic => new ConsumerTelemetryMetric - { - ConsumerName = c.ConsumerName, - Topic = topic, - GroupId = c.GroupId, - InstanceName = $"{Environment.MachineName}-{ProcessId}", - PausedPartitions = c.PausedPartitions - .Where(p => p.Topic == topic) - .Select(p => p.Partition.Value), - RunningPartitions = c.RunningPartitions - .Where(p => p.Topic == topic) - .Select(p => p.Partition.Value), - WorkersCount = c.WorkersCount, - Status = c.Status, - Lag = consumerLag.Where(l => l.Topic == topic).Sum(l => l.Lag), - SentAt = DateTime.Now.ToUniversalTime(), - }); - }); + return c.Topics.Select( + topic => new ConsumerTelemetryMetric + { + ConsumerName = c.ConsumerName, + Topic = topic, + GroupId = c.GroupId, + InstanceName = $"{Environment.MachineName}-{ProcessId}", + PausedPartitions = c.PausedPartitions + .Where(p => p.Topic == topic) + .Select(p => p.Partition.Value), + RunningPartitions = c.RunningPartitions + .Where(p => p.Topic == topic) + .Select(p => p.Partition.Value), + WorkersCount = c.WorkersCount, + Status = c.Status, + Lag = consumerLag.Where(l => l.Topic == topic).Sum(l => l.Lag), + SentAt = DateTime.UtcNow, + }); + }); - foreach (var item in items) + foreach (var item in items) + { + producer.Produce(topicName, Guid.NewGuid().ToByteArray(), item, partition: partition); + } + } + catch (Exception e) { - producer.Produce(topicName, Guid.NewGuid().ToByteArray(), item, partition: partition); + this.logHandler.Warning("Error producing telemetry data", new { Exception = e }); } } } diff --git a/src/KafkaFlow.BatchConsume/BatchConsumeMessageContext.cs b/src/KafkaFlow.BatchConsume/BatchConsumeMessageContext.cs index 70264f101..86492a4f6 100644 --- a/src/KafkaFlow.BatchConsume/BatchConsumeMessageContext.cs +++ b/src/KafkaFlow.BatchConsume/BatchConsumeMessageContext.cs @@ -3,14 +3,17 @@ namespace KafkaFlow.BatchConsume using System; using System.Collections.Generic; - internal class BatchConsumeMessageContext : IMessageContext + internal class BatchConsumeMessageContext : IMessageContext, IDisposable { + private readonly IDependencyResolverScope batchDependencyScope; + public BatchConsumeMessageContext( IConsumerContext consumer, IReadOnlyCollection batchMessage) { this.ConsumerContext = consumer; this.Message = new Message(null, batchMessage); + this.batchDependencyScope = consumer.WorkerDependencyResolver.CreateScope(); this.Items = new Dictionary(); } @@ -22,11 +25,15 @@ public BatchConsumeMessageContext( public IProducerContext ProducerContext => null; + public IDependencyResolver DependencyResolver => this.batchDependencyScope.Resolver; + public IDictionary Items { get; } public IMessageContext SetMessage(object key, object value) => throw new NotSupportedException($"{nameof(BatchConsumeMessageContext)} does not allow change the message"); public IMessageContext TransformMessage(object message) => throw new NotImplementedException(); + + public void Dispose() => this.batchDependencyScope.Dispose(); } } diff --git a/src/KafkaFlow.TypedHandler/ConfigurationBuilderExtensions.cs b/src/KafkaFlow.TypedHandler/ConfigurationBuilderExtensions.cs index de119b733..9befd1a92 100644 --- a/src/KafkaFlow.TypedHandler/ConfigurationBuilderExtensions.cs +++ b/src/KafkaFlow.TypedHandler/ConfigurationBuilderExtensions.cs @@ -26,7 +26,7 @@ public static IConsumerMiddlewareConfigurationBuilder AddTypedHandlers( builder.Add( resolver => new TypedHandlerMiddleware(resolver, configuration), - MiddlewareLifetime.Scoped); + MiddlewareLifetime.Message); return builder; } diff --git a/src/KafkaFlow.UnitTests/ConfigurationBuilders/ConsumerConfigurationBuilderTests.cs b/src/KafkaFlow.UnitTests/ConfigurationBuilders/ConsumerConfigurationBuilderTests.cs index cd15608ae..6259d0311 100644 --- a/src/KafkaFlow.UnitTests/ConfigurationBuilders/ConsumerConfigurationBuilderTests.cs +++ b/src/KafkaFlow.UnitTests/ConfigurationBuilders/ConsumerConfigurationBuilderTests.cs @@ -56,7 +56,7 @@ public void Build_RequiredCalls_ReturnDefaultValues() // Assert configuration.Topics.Should().BeEquivalentTo(topic1); configuration.BufferSize.Should().Be(bufferSize); - configuration.WorkersCount.Should().Be(workers); + configuration.WorkersCountCalculator(null).Result.Should().Be(workers); configuration.GroupId.Should().Be(groupId); configuration.GetKafkaConfig().AutoOffsetReset.Should().BeNull(); configuration.GetKafkaConfig().EnableAutoOffsetStore.Should().Be(false); @@ -119,7 +119,7 @@ public void Build_AllCalls_ReturnPassedValues() configuration.Topics.Should().BeEquivalentTo(topic1, topic2); configuration.ConsumerName.Should().Be(name); configuration.BufferSize.Should().Be(bufferSize); - configuration.WorkersCount.Should().Be(workers); + configuration.WorkersCountCalculator(null).Result.Should().Be(workers); configuration.GroupId.Should().Be(groupId); configuration.GetKafkaConfig().AutoOffsetReset.Should().Be(offsetReset); configuration.AutoStoreOffsets.Should().Be(false); diff --git a/src/KafkaFlow.UnitTests/Consumer/ConsumerManagerTests.cs b/src/KafkaFlow.UnitTests/Consumer/ConsumerManagerTests.cs index cbad60c34..5fafd4bbf 100644 --- a/src/KafkaFlow.UnitTests/Consumer/ConsumerManagerTests.cs +++ b/src/KafkaFlow.UnitTests/Consumer/ConsumerManagerTests.cs @@ -30,24 +30,46 @@ public class ConsumerManagerTests [TestInitialize] public void Setup() { - this.consumerMock = new Mock(MockBehavior.Strict); - this.workerPoolMock = new Mock(MockBehavior.Strict); - this.feederMock = new Mock(MockBehavior.Strict); - this.logHandlerMock = new Mock(MockBehavior.Strict); + this.consumerMock = new Mock(); + this.workerPoolMock = new Mock(); + this.feederMock = new Mock(); + this.logHandlerMock = new Mock(); this.dependencyResolver = new Mock(); this.consumerMock - .Setup(x => x.OnPartitionsAssigned(It.IsAny, List>>())) - .Callback((Action, List> value) => this.onPartitionAssignedHandler = value); + .Setup( + x => x.OnPartitionsAssigned(It.IsAny, List>>())) + .Callback( + (Action, List> value) => + this.onPartitionAssignedHandler = value); this.consumerMock - .Setup(x => x.OnPartitionsRevoked(It.IsAny, List>>())) - .Callback((Action, List> value) => this.onPartitionRevokedHandler = value); + .Setup( + x => x.OnPartitionsRevoked( + It.IsAny, List>>())) + .Callback( + (Action, List> value) => + this.onPartitionRevokedHandler = value); + + var configurationMock = new Mock(); + + configurationMock + .SetupGet(x => x.WorkersCountCalculator) + .Returns(_ => Task.FromResult(10)); + + configurationMock + .SetupGet(x => x.WorkersCountEvaluationInterval) + .Returns(TimeSpan.FromMinutes(5)); + + this.consumerMock + .SetupGet(x => x.Configuration) + .Returns(configurationMock.Object); this.target = new ConsumerManager( this.consumerMock.Object, this.workerPoolMock.Object, this.feederMock.Object, + this.dependencyResolver.Object, this.logHandlerMock.Object); } @@ -58,8 +80,6 @@ public void ConstructorCalled_InitializeProperties() this.target.Consumer.Should().Be(this.consumerMock.Object); this.target.WorkerPool.Should().Be(this.workerPoolMock.Object); this.target.Feeder.Should().Be(this.feederMock.Object); - - this.consumerMock.VerifyAll(); } [TestMethod] @@ -88,38 +108,30 @@ public async Task StopAsync_StopDependencies() .Setup(x => x.StopAsync()) .Returns(Task.CompletedTask); - this.consumerMock - .Setup(x => x.Dispose()); - // Act await this.target.StopAsync(); // Assert this.feederMock.VerifyAll(); this.workerPoolMock.VerifyAll(); - this.consumerMock.VerifyAll(); + this.consumerMock.Verify(x => x.Dispose(), Times.Once()); } [TestMethod] public void OnPartitionsAssigned_StartWorkerPool() { // Arrange - IConsumer consumer = null; var partitions = this.fixture.Create>(); this.workerPoolMock - .Setup(x => x.StartAsync(partitions)) + .Setup(x => x.StartAsync(partitions, It.IsAny())) .Returns(Task.CompletedTask); - this.consumerMock - .SetupGet(x => x.Configuration) - .Returns(new Mock().Object); - this.logHandlerMock .Setup(x => x.Info(It.IsAny(), It.IsAny())); // Act - this.onPartitionAssignedHandler(this.dependencyResolver.Object, consumer, partitions); + this.onPartitionAssignedHandler(this.dependencyResolver.Object, Mock.Of>(), partitions); // Assert this.workerPoolMock.VerifyAll(); diff --git a/src/KafkaFlow.UnitTests/MemoryTelemetryStorageTests.cs b/src/KafkaFlow.UnitTests/MemoryTelemetryStorageTests.cs index e13828790..86e1b722b 100644 --- a/src/KafkaFlow.UnitTests/MemoryTelemetryStorageTests.cs +++ b/src/KafkaFlow.UnitTests/MemoryTelemetryStorageTests.cs @@ -47,7 +47,7 @@ public void Put_OneItem_ReturnsOneItem() var now = DateTime.Now; this.dateTimeProviderMock - .SetupGet(x => x.Now) + .SetupGet(x => x.UtcNow) .Returns(now); // Act @@ -64,7 +64,7 @@ public void PutTwoItems_SameInstanceGroupConsumer_ReplaceOlder() var now = DateTime.Now; this.dateTimeProviderMock - .SetupGet(x => x.Now) + .SetupGet(x => x.UtcNow) .Returns(now); var metric1 = new ConsumerTelemetryMetric @@ -99,7 +99,7 @@ public void PutTwoItems_DifferentInstanceGroupConsumer_ReturnsTwo() var now = DateTime.Now; this.dateTimeProviderMock - .SetupGet(x => x.Now) + .SetupGet(x => x.UtcNow) .Returns(now); var metric1 = new ConsumerTelemetryMetric diff --git a/src/KafkaFlow/Clusters/ClusterManager.cs b/src/KafkaFlow/Clusters/ClusterManager.cs index 0410bad6f..aeca278af 100644 --- a/src/KafkaFlow/Clusters/ClusterManager.cs +++ b/src/KafkaFlow/Clusters/ClusterManager.cs @@ -1,38 +1,103 @@ namespace KafkaFlow.Clusters { using System; + using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Confluent.Kafka; using Confluent.Kafka.Admin; using KafkaFlow.Configuration; + using TopicMetadata = KafkaFlow.TopicMetadata; + using TopicPartitionOffset = KafkaFlow.TopicPartitionOffset; - internal class ClusterManager : IClusterManager + internal class ClusterManager : IClusterManager, IDisposable { private readonly ILogHandler logHandler; - private readonly Lazy lazyAdminClientBuilder; + private readonly Lazy lazyAdminClient; private readonly ClusterConfiguration configuration; + private readonly ConcurrentDictionary topicMetadataCache = new(); + public ClusterManager(ILogHandler logHandler, ClusterConfiguration configuration) { this.logHandler = logHandler; this.configuration = configuration; - this.lazyAdminClientBuilder = new Lazy( + + this.lazyAdminClient = new Lazy( () => { - var adminConfig = new AdminClientConfig + var config = new AdminClientConfig { BootstrapServers = string.Join(",", configuration.Brokers), }; - adminConfig.ReadSecurityInformationFrom(configuration); - return new AdminClientBuilder(adminConfig); + config.ReadSecurityInformationFrom(configuration); + + return new AdminClientBuilder(config) + .Build(); }); } public string ClusterName => this.configuration.Name; + public ValueTask GetTopicMetadataAsync(string topicName) + { + return new ValueTask( + this.topicMetadataCache.GetOrAdd( + topicName, + _ => + { + var metadata = this.lazyAdminClient.Value.GetMetadata(topicName, TimeSpan.FromSeconds(30)); + + if (!metadata.Topics.Any()) + { + return new TopicMetadata(string.Empty, Array.Empty()); + } + + return new TopicMetadata( + metadata.Topics[0].Topic, + metadata.Topics[0] + .Partitions + .Select(p => new TopicPartitionMetadata(p.PartitionId)) + .ToList()); + })); + } + + public async Task> GetConsumerGroupOffsetsAsync( + string consumerGroup, + IEnumerable topicsName) + { + var topicsMetadata = new List<(string Name, TopicMetadata Metadata)>(); + + foreach (var name in topicsName) + { + topicsMetadata.Add((name, await this.GetTopicMetadataAsync(name))); + } + + var topics = + topicsMetadata + .SelectMany( + topic => topic.Metadata.Partitions.Select( + partition => new TopicPartition( + topic.Name, + new Partition(partition.Id)))) + .ToList(); + + var result = await this.lazyAdminClient.Value.ListConsumerGroupOffsetsAsync( + new[] { new ConsumerGroupTopicPartitions(consumerGroup, topics) }); + + if (!result.Any()) + { + return Enumerable.Empty(); + } + + return result[0] + .Partitions + .Select(p => new TopicPartitionOffset(p.Topic, p.Partition.Value, p.Offset.Value)) + .ToList(); + } + public async Task CreateIfNotExistsAsync(IEnumerable configurations) { try @@ -47,8 +112,7 @@ public async Task CreateIfNotExistsAsync(IEnumerable configu }) .ToArray(); - using var client = this.lazyAdminClientBuilder.Value.Build(); - await client.CreateTopicsAsync(topics); + await this.lazyAdminClient.Value.CreateTopicsAsync(topics); } catch (CreateTopicsException exception) { @@ -83,5 +147,13 @@ public async Task CreateIfNotExistsAsync(IEnumerable configu } } } + + public void Dispose() + { + if (this.lazyAdminClient.IsValueCreated) + { + this.lazyAdminClient.Value.Dispose(); + } + } } } diff --git a/src/KafkaFlow/Clusters/IClusterManager.cs b/src/KafkaFlow/Clusters/IClusterManager.cs index 52bb78e37..6d2f149b4 100644 --- a/src/KafkaFlow/Clusters/IClusterManager.cs +++ b/src/KafkaFlow/Clusters/IClusterManager.cs @@ -20,5 +20,25 @@ public interface IClusterManager /// Topics to create /// public Task CreateIfNotExistsAsync(IEnumerable configuration); + + /// + /// Retrieves the metadata for a specified topic. + /// This includes information about the topic as well as its partitions. + /// + /// The name of the topic for which to retrieve metadata. + /// A TopicMetadata object that contains information about the topic and its partitions. + ValueTask GetTopicMetadataAsync(string topicName); + + /// + /// Retrieves the offsets for a specified consumer group and a collection of topics. + /// The offsets indicate where the consumer group is in its consumption of the topics. + /// + /// The name of the consumer group for which to retrieve offsets. + /// A collection of topic names for which to retrieve offsets. + /// An enumerable collection of TopicPartitionOffset objects, + /// each of which contains offset information for a specific topic partition in the consumer group. + Task> GetConsumerGroupOffsetsAsync( + string consumerGroup, + IEnumerable topicsName); } } diff --git a/src/KafkaFlow/Configuration/ConsumerConfiguration.cs b/src/KafkaFlow/Configuration/ConsumerConfiguration.cs index 118873a71..5638f5492 100644 --- a/src/KafkaFlow/Configuration/ConsumerConfiguration.cs +++ b/src/KafkaFlow/Configuration/ConsumerConfiguration.cs @@ -2,12 +2,12 @@ namespace KafkaFlow.Configuration { using System; using System.Collections.Generic; + using System.Threading.Tasks; using Confluent.Kafka; internal class ConsumerConfiguration : IConsumerConfiguration { private readonly ConsumerConfig consumerConfig; - private int workersCount; public ConsumerConfiguration( ConsumerConfig consumerConfig, @@ -16,7 +16,8 @@ public ConsumerConfiguration( string consumerName, ClusterConfiguration clusterConfiguration, bool managementDisabled, - int workersCount, + Func> workersCountCalculator, + TimeSpan workersCountEvaluationInterval, int bufferSize, TimeSpan workerStopTimeout, Factory distributionStrategyFactory, @@ -52,7 +53,8 @@ public ConsumerConfiguration( this.ConsumerName = consumerName ?? Guid.NewGuid().ToString(); this.ClusterConfiguration = clusterConfiguration; this.ManagementDisabled = managementDisabled; - this.WorkersCount = workersCount; + this.WorkersCountCalculator = workersCountCalculator; + this.WorkersCountEvaluationInterval = workersCountEvaluationInterval; this.WorkerStopTimeout = workerStopTimeout; this.StatisticsHandlers = statisticsHandlers; this.PartitionsAssignedHandlers = partitionsAssignedHandlers; @@ -82,17 +84,9 @@ public ConsumerConfiguration( public bool ManagementDisabled { get; } - public int WorkersCount - { - get => this.workersCount; - set => - this.workersCount = value > 0 ? - value : - throw new ArgumentOutOfRangeException( - nameof(this.WorkersCount), - this.WorkersCount, - $"The {nameof(this.WorkersCount)} value must be greater than 0"); - } + public Func> WorkersCountCalculator { get; set; } + + public TimeSpan WorkersCountEvaluationInterval { get; } public string GroupId => this.consumerConfig.GroupId; diff --git a/src/KafkaFlow/Configuration/ConsumerConfigurationBuilder.cs b/src/KafkaFlow/Configuration/ConsumerConfigurationBuilder.cs index f7e601ed0..8531f04b7 100644 --- a/src/KafkaFlow/Configuration/ConsumerConfigurationBuilder.cs +++ b/src/KafkaFlow/Configuration/ConsumerConfigurationBuilder.cs @@ -4,6 +4,7 @@ namespace KafkaFlow.Configuration using System.Collections.Generic; using System.ComponentModel; using System.Linq; + using System.Threading.Tasks; using Confluent.Kafka; using KafkaFlow.Consumers.DistributionStrategies; @@ -27,7 +28,8 @@ internal sealed class ConsumerConfigurationBuilder : IConsumerConfigurationBuild private string groupId = string.Empty; private AutoOffsetReset? autoOffsetReset; private int? maxPollIntervalMs; - private int workersCount; + private Func> workersCountCalculator; + private TimeSpan workersCountEvaluationInterval = TimeSpan.FromMinutes(5); private int bufferSize; private TimeSpan workerStopTimeout = TimeSpan.FromSeconds(30); private bool autoStoreOffsets = true; @@ -119,12 +121,25 @@ public IConsumerConfigurationBuilder WithMaxPollIntervalMs(int maxPollIntervalMs return this; } - public IConsumerConfigurationBuilder WithWorkersCount(int workersCount) + public IConsumerConfigurationBuilder WithWorkersCount( + Func> calculator, + TimeSpan evaluationInterval) { - this.workersCount = workersCount; + this.workersCountCalculator = calculator; + this.workersCountEvaluationInterval = evaluationInterval; return this; } + public IConsumerConfigurationBuilder WithWorkersCount(Func> calculator) + { + return this.WithWorkersCount(calculator, TimeSpan.FromMinutes(5)); + } + + public IConsumerConfigurationBuilder WithWorkersCount(int workersCount) + { + return this.WithWorkersCount((_, _) => Task.FromResult(workersCount)); + } + public IConsumerConfigurationBuilder WithBufferSize(int size) { this.bufferSize = size; @@ -255,7 +270,8 @@ public IConsumerConfiguration Build(ClusterConfiguration clusterConfiguration) this.name, clusterConfiguration, this.disableManagement, - this.workersCount, + this.workersCountCalculator, + this.workersCountEvaluationInterval, this.bufferSize, this.workerStopTimeout, this.distributionStrategyFactory, diff --git a/src/KafkaFlow/Configuration/IConsumerConfiguration.cs b/src/KafkaFlow/Configuration/IConsumerConfiguration.cs index 101b98059..ef44288eb 100644 --- a/src/KafkaFlow/Configuration/IConsumerConfiguration.cs +++ b/src/KafkaFlow/Configuration/IConsumerConfiguration.cs @@ -2,6 +2,7 @@ namespace KafkaFlow.Configuration { using System; using System.Collections.Generic; + using System.Threading.Tasks; using Confluent.Kafka; /// @@ -45,9 +46,14 @@ public interface IConsumerConfiguration bool ManagementDisabled { get; } /// - /// Gets or sets the number of workers + /// Gets or sets the workers count calculator /// - int WorkersCount { get; set; } + Func> WorkersCountCalculator { get; set; } + + /// + /// Gets the time interval at which the workers count calculation is re-evaluated. + /// + TimeSpan WorkersCountEvaluationInterval { get; } /// /// Gets the consumer group diff --git a/src/KafkaFlow/Configuration/MiddlewareConfigurationBuilder.cs b/src/KafkaFlow/Configuration/MiddlewareConfigurationBuilder.cs index 642f3641d..02e900c82 100644 --- a/src/KafkaFlow/Configuration/MiddlewareConfigurationBuilder.cs +++ b/src/KafkaFlow/Configuration/MiddlewareConfigurationBuilder.cs @@ -50,7 +50,7 @@ private static InstanceLifetime ParseLifetime(MiddlewareLifetime lifetime) { return lifetime switch { - MiddlewareLifetime.Scoped => InstanceLifetime.Scoped, + MiddlewareLifetime.Scoped or MiddlewareLifetime.Message => InstanceLifetime.Scoped, MiddlewareLifetime.Singleton => InstanceLifetime.Singleton, MiddlewareLifetime.Transient or MiddlewareLifetime.Worker or diff --git a/src/KafkaFlow/ConsumerManagerFactory.cs b/src/KafkaFlow/ConsumerManagerFactory.cs index c7d56d60b..cb10ad4bf 100644 --- a/src/KafkaFlow/ConsumerManagerFactory.cs +++ b/src/KafkaFlow/ConsumerManagerFactory.cs @@ -1,6 +1,5 @@ namespace KafkaFlow { - using System.Linq; using KafkaFlow.Configuration; using KafkaFlow.Consumers; @@ -28,6 +27,7 @@ public IConsumerManager Create(IConsumerConfiguration configuration, IDependency consumer, consumerWorkerPool, feeder, + resolver, logHandler); return consumerManager; diff --git a/src/KafkaFlow/Consumers/Consumer.cs b/src/KafkaFlow/Consumers/Consumer.cs index 2f9831a3b..6e05c1b8c 100644 --- a/src/KafkaFlow/Consumers/Consumer.cs +++ b/src/KafkaFlow/Consumers/Consumer.cs @@ -1,6 +1,7 @@ namespace KafkaFlow.Consumers { using System; + using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -21,7 +22,7 @@ private readonly List, Lis private readonly List, Error>> errorsHandlers = new(); private readonly List, string>> statisticsHandlers = new(); - private readonly Dictionary committedOffsets = new(); + private readonly ConcurrentDictionary currentPartitionsOffsets = new(); private readonly ConsumerFlowManager flowManager; private IConsumer consumer; @@ -91,8 +92,7 @@ public ConsumerStatus Status public void OnPartitionsAssigned(Action, List> handler) => this.partitionsAssignedHandlers.Add(handler); - public void OnPartitionsRevoked( - Action, List> handler) => + public void OnPartitionsRevoked(Action, List> handler) => this.partitionsRevokedHandlers.Add(handler); public void OnError(Action, Error> handler) => @@ -120,14 +120,10 @@ public IEnumerable GetTopicPartitionsLag() return this.Assignment.Select( tp => { - if (!this.committedOffsets.TryGetValue(tp, out var offset)) - { - return new TopicPartitionLag(tp.Topic, tp.Partition.Value, 0); - } - - var offsetEnd = this.GetWatermarkOffsets(tp).High.Value; + var offset = Math.Max(0, this.currentPartitionsOffsets.GetOrAdd(tp, _ => this.GetPosition(tp))); + var offsetEnd = Math.Max(0, this.GetWatermarkOffsets(tp).High.Value); - return new TopicPartitionLag(tp.Topic, tp.Partition.Value, offsetEnd - offset); + return new TopicPartitionLag(tp.Topic, tp.Partition.Value, offset == 0 ? 0 : offsetEnd - offset); }); } @@ -137,7 +133,7 @@ public void Commit(IEnumerable offsetsValues) foreach (var offset in offsetsValues) { - this.committedOffsets[offset.TopicPartition] = offset.Offset.Value; + this.currentPartitionsOffsets[offset.TopicPartition] = offset.Offset.Value; } } @@ -224,7 +220,7 @@ private void EnsureConsumer() { this.Assignment = new List(); this.Subscription = new List(); - this.committedOffsets.Clear(); + this.currentPartitionsOffsets.Clear(); this.flowManager.Stop(); this.partitionsRevokedHandlers.ForEach(handler => handler(this.dependencyResolver, consumer, partitions)); diff --git a/src/KafkaFlow/Consumers/ConsumerContext.cs b/src/KafkaFlow/Consumers/ConsumerContext.cs index 282ee2eb5..ec5591802 100644 --- a/src/KafkaFlow/Consumers/ConsumerContext.cs +++ b/src/KafkaFlow/Consumers/ConsumerContext.cs @@ -8,20 +8,25 @@ internal class ConsumerContext : IConsumerContext { private readonly IConsumer consumer; private readonly IOffsetManager offsetManager; - private readonly ConsumeResult kafkaResult; + private readonly TopicPartitionOffset topicPartitionOffset; public ConsumerContext( IConsumer consumer, IOffsetManager offsetManager, ConsumeResult kafkaResult, CancellationToken workerStopped, - int workerId) + int workerId, + IDependencyResolver workerDependencyResolver, + IDependencyResolver consumerDependencyResolver) { this.WorkerStopped = workerStopped; this.WorkerId = workerId; + this.WorkerDependencyResolver = workerDependencyResolver; + this.ConsumerDependencyResolver = consumerDependencyResolver; this.consumer = consumer; this.offsetManager = offsetManager; - this.kafkaResult = kafkaResult; + this.topicPartitionOffset = kafkaResult.TopicPartitionOffset; + this.MessageTimestamp = kafkaResult.Message.Timestamp.UtcDateTime; } public string ConsumerName => this.consumer.Configuration.ConsumerName; @@ -30,22 +35,26 @@ public ConsumerContext( public int WorkerId { get; } - public string Topic => this.kafkaResult.Topic; + public IDependencyResolver WorkerDependencyResolver { get; } - public int Partition => this.kafkaResult.Partition.Value; + public IDependencyResolver ConsumerDependencyResolver { get; } - public long Offset => this.kafkaResult.Offset.Value; + public string Topic => this.topicPartitionOffset.Topic; + + public int Partition => this.topicPartitionOffset.Partition.Value; + + public long Offset => this.topicPartitionOffset.Offset.Value; public string GroupId => this.consumer.Configuration.GroupId; public bool ShouldStoreOffset { get; set; } = true; - public DateTime MessageTimestamp => this.kafkaResult.Message.Timestamp.UtcDateTime; + public DateTime MessageTimestamp { get; } - public void StoreOffset() => this.offsetManager.MarkAsProcessed(this.kafkaResult.TopicPartitionOffset); + public void StoreOffset() => this.offsetManager.MarkAsProcessed(this.topicPartitionOffset); public IOffsetsWatermark GetOffsetsWatermark() => - new OffsetsWatermark(this.consumer.GetWatermarkOffsets(this.kafkaResult.TopicPartition)); + new OffsetsWatermark(this.consumer.GetWatermarkOffsets(this.topicPartitionOffset.TopicPartition)); public void Pause() => this.consumer.FlowManager.Pause(this.consumer.Assignment); diff --git a/src/KafkaFlow/Consumers/ConsumerManager.cs b/src/KafkaFlow/Consumers/ConsumerManager.cs index 6bd6c7629..13fa0bc85 100644 --- a/src/KafkaFlow/Consumers/ConsumerManager.cs +++ b/src/KafkaFlow/Consumers/ConsumerManager.cs @@ -1,25 +1,38 @@ namespace KafkaFlow.Consumers { + using System; using System.Collections.Generic; using System.Linq; + using System.Threading; using System.Threading.Tasks; using Confluent.Kafka; + using KafkaFlow.Configuration; - internal class ConsumerManager : IConsumerManager + internal class ConsumerManager : IConsumerManager, IDisposable { + private readonly IDependencyResolver dependencyResolver; private readonly ILogHandler logHandler; + private readonly Timer evaluateWorkersCountTimer; public ConsumerManager( IConsumer consumer, IConsumerWorkerPool consumerWorkerPool, IWorkerPoolFeeder feeder, + IDependencyResolver dependencyResolver, ILogHandler logHandler) { + this.dependencyResolver = dependencyResolver; this.logHandler = logHandler; this.Consumer = consumer; this.WorkerPool = consumerWorkerPool; this.Feeder = feeder; + this.evaluateWorkersCountTimer = new Timer( + state => _ = this.EvaluateWorkersCountAsync(), + null, + Timeout.Infinite, + Timeout.Infinite); + this.Consumer.OnPartitionsAssigned((_, _, partitions) => this.OnPartitionAssigned(partitions)); this.Consumer.OnPartitionsRevoked((_, _, partitions) => this.OnPartitionRevoked(partitions)); } @@ -34,17 +47,64 @@ public Task StartAsync() { this.Feeder.Start(); + this.StartEvaluateWorkerCountTimer(); + return Task.CompletedTask; } public async Task StopAsync() { + this.StopEvaluateWorkerCountTimer(); + await this.Feeder.StopAsync().ConfigureAwait(false); await this.WorkerPool.StopAsync().ConfigureAwait(false); this.Consumer.Dispose(); } + public void Dispose() + { + this.evaluateWorkersCountTimer.Dispose(); + } + + private void StopEvaluateWorkerCountTimer() => this.evaluateWorkersCountTimer.Change(Timeout.Infinite, Timeout.Infinite); + + private void StartEvaluateWorkerCountTimer() => this.evaluateWorkersCountTimer.Change( + this.Consumer.Configuration.WorkersCountEvaluationInterval, + this.Consumer.Configuration.WorkersCountEvaluationInterval); + + private async Task EvaluateWorkersCountAsync() + { + var newWorkersCount = await this.CalculateWorkersCount(this.Consumer.Assignment); + + if (newWorkersCount == this.WorkerPool.CurrentWorkersCount) + { + return; + } + + await this.ChangeWorkersCountAsync(newWorkersCount); + } + + private async Task ChangeWorkersCountAsync(int workersCount) + { + try + { + this.StopEvaluateWorkerCountTimer(); + + await this.Feeder.StopAsync(); + await this.WorkerPool.StopAsync(); + + await this.WorkerPool.StartAsync(this.Consumer.Assignment, workersCount); + this.Feeder.Start(); + + this.StartEvaluateWorkerCountTimer(); + } + catch (Exception e) + { + this.logHandler.Error("Error changing workers count", e, null); + } + } + private void OnPartitionRevoked(IEnumerable topicPartitions) { this.logHandler.Warning( @@ -60,8 +120,10 @@ private void OnPartitionAssigned(IReadOnlyCollection partitions) "Partitions assigned", this.GetConsumerLogInfo(partitions)); + var workersCount = this.CalculateWorkersCount(partitions).GetAwaiter().GetResult(); + this.WorkerPool - .StartAsync(partitions) + .StartAsync(partitions, workersCount) .GetAwaiter() .GetResult(); } @@ -80,5 +142,32 @@ private void OnPartitionAssigned(IReadOnlyCollection partitions) Partitions = x.Select(y => y.Partition.Value), }), }; + + private async Task CalculateWorkersCount(IEnumerable partitions) + { + try + { + return await this.Consumer.Configuration.WorkersCountCalculator( + new WorkersCountContext( + this.Consumer.Configuration.ConsumerName, + this.Consumer.Configuration.GroupId, + partitions + .GroupBy( + x => x.Topic, + (topic, grouped) => new TopicPartitions( + topic, + grouped + .Select(x => x.Partition.Value) + .ToList())) + .ToList()), + this.dependencyResolver); + } + catch (Exception e) + { + this.logHandler.Error("Error calculating new workers count, using one worker as fallback", e, null); + + return 1; + } + } } } diff --git a/src/KafkaFlow/Consumers/ConsumerWorker.cs b/src/KafkaFlow/Consumers/ConsumerWorker.cs index cce7308ea..75e7f3b27 100644 --- a/src/KafkaFlow/Consumers/ConsumerWorker.cs +++ b/src/KafkaFlow/Consumers/ConsumerWorker.cs @@ -9,7 +9,7 @@ namespace KafkaFlow.Consumers internal class ConsumerWorker : IConsumerWorker { private readonly IConsumer consumer; - private readonly IDependencyResolver dependencyResolver; + private readonly IDependencyResolver consumerDependencyResolver; private readonly IOffsetManager offsetManager; private readonly IMiddlewareExecutor middlewareExecutor; private readonly ILogHandler logHandler; @@ -18,12 +18,13 @@ internal class ConsumerWorker : IConsumerWorker private readonly Channel> messagesBuffer; private CancellationTokenSource stopCancellationTokenSource; + private IDependencyResolverScope workerDependencyResolverScope; private Task backgroundTask; private Action onMessageFinishedHandler; public ConsumerWorker( IConsumer consumer, - IDependencyResolver dependencyResolver, + IDependencyResolver consumerDependencyResolver, int workerId, IOffsetManager offsetManager, IMiddlewareExecutor middlewareExecutor, @@ -31,7 +32,7 @@ public ConsumerWorker( { this.Id = workerId; this.consumer = consumer; - this.dependencyResolver = dependencyResolver; + this.consumerDependencyResolver = consumerDependencyResolver; this.offsetManager = offsetManager; this.middlewareExecutor = middlewareExecutor; this.logHandler = logHandler; @@ -51,6 +52,7 @@ public ValueTask EnqueueAsync( public Task StartAsync() { this.stopCancellationTokenSource = new CancellationTokenSource(); + this.workerDependencyResolverScope = this.consumerDependencyResolver.CreateScope(); this.backgroundTask = Task.Run( async () => @@ -93,10 +95,12 @@ public async Task StopAsync() if (this.stopCancellationTokenSource.Token.CanBeCanceled) { this.stopCancellationTokenSource.Cancel(); + this.stopCancellationTokenSource.Dispose(); } await this.backgroundTask.ConfigureAwait(false); this.backgroundTask.Dispose(); + this.workerDependencyResolverScope.Dispose(); } public void OnTaskCompleted(Action handler) @@ -108,29 +112,32 @@ private async Task ProcessMessageAsync(ConsumeResult message, Ca { try { + var messageScope = this.consumerDependencyResolver.CreateScope(); + var context = new MessageContext( new Message(message.Message.Key, message.Message.Value), new MessageHeaders(message.Message.Headers), + messageScope.Resolver, new ConsumerContext( this.consumer, this.offsetManager, message, cancellationToken, - this.Id), + this.Id, + this.workerDependencyResolverScope.Resolver, + this.consumerDependencyResolver), null); try { - var scope = this.dependencyResolver.CreateScope(); - this.offsetManager.OnOffsetProcessed( message.TopicPartitionOffset, - () => scope.Dispose()); + () => messageScope.Dispose()); await this.globalEvents.FireMessageConsumeStartedAsync(new MessageEventContext(context)); await this.middlewareExecutor - .Execute(scope.Resolver, context, _ => Task.CompletedTask) + .Execute(context, _ => Task.CompletedTask) .ConfigureAwait(false); await this.globalEvents.FireMessageConsumeCompletedAsync(new MessageEventContext(context)); diff --git a/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs b/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs index d953c4836..291951368 100644 --- a/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs +++ b/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs @@ -8,16 +8,14 @@ namespace KafkaFlow.Consumers using Confluent.Kafka; using KafkaFlow.Configuration; - internal class ConsumerWorkerPool : IConsumerWorkerPool + internal class ConsumerWorkerPool : IConsumerWorkerPool, IDisposable { private readonly IConsumer consumer; - private readonly IDependencyResolver dependencyResolver; + private readonly IDependencyResolver consumerDependencyResolver; private readonly IMiddlewareExecutor middlewareExecutor; private readonly ILogHandler logHandler; private readonly Factory distributionStrategyFactory; - - private readonly IReadOnlyList<(Action> handler, TimeSpan interval)> - pendingOffsetsHandlers; + private readonly IOffsetCommitter offsetCommitter; private TaskCompletionSource startedTaskSource = new(); private List workers = new(); @@ -27,58 +25,71 @@ internal class ConsumerWorkerPool : IConsumerWorkerPool public ConsumerWorkerPool( IConsumer consumer, - IDependencyResolver dependencyResolver, + IDependencyResolver consumerDependencyResolver, IMiddlewareExecutor middlewareExecutor, IConsumerConfiguration consumerConfiguration, ILogHandler logHandler) { this.consumer = consumer; - this.dependencyResolver = dependencyResolver; + this.consumerDependencyResolver = consumerDependencyResolver; this.middlewareExecutor = middlewareExecutor; this.logHandler = logHandler; - this.pendingOffsetsHandlers = consumerConfiguration.PendingOffsetsHandlers; this.distributionStrategyFactory = consumerConfiguration.DistributionStrategyFactory; - } - public async Task StartAsync(IEnumerable partitions) - { - IOffsetCommitter offsetCommitter = - this.consumer.Configuration.NoStoreOffsets ? - new NullOffsetCommitter() : - new OffsetCommitter( - this.consumer, - this.dependencyResolver, - this.pendingOffsetsHandlers, - this.logHandler); - - this.offsetManager = new OffsetManager( - offsetCommitter, - partitions); - - await Task.WhenAll( - Enumerable - .Range(0, this.consumer.Configuration.WorkersCount) - .Select( - workerId => - { - var worker = new ConsumerWorker( - this.consumer, - this.dependencyResolver, - workerId, - this.offsetManager, - this.middlewareExecutor, - this.logHandler); - - this.workers.Add(worker); - - return worker.StartAsync(); - })) - .ConfigureAwait(false); + this.offsetCommitter = this.consumer.Configuration.NoStoreOffsets ? + new NullOffsetCommitter() : + new OffsetCommitter( + this.consumer, + this.consumerDependencyResolver, + consumerConfiguration.PendingOffsetsHandlers, + this.logHandler); + } - this.distributionStrategy = this.distributionStrategyFactory(this.dependencyResolver); - this.distributionStrategy.Init(this.workers.AsReadOnly()); + public int CurrentWorkersCount { get; private set; } - this.startedTaskSource.TrySetResult(null); + public async Task StartAsync(IReadOnlyCollection partitions, int workersCount) + { + try + { + this.offsetManager = new OffsetManager(this.offsetCommitter, partitions); + + this.CurrentWorkersCount = workersCount; + + await Task.WhenAll( + Enumerable + .Range(0, this.CurrentWorkersCount) + .Select( + workerId => + { + var worker = new ConsumerWorker( + this.consumer, + this.consumerDependencyResolver, + workerId, + this.offsetManager, + this.middlewareExecutor, + this.logHandler); + + this.workers.Add(worker); + + return worker.StartAsync(); + })) + .ConfigureAwait(false); + + this.distributionStrategy = this.distributionStrategyFactory(this.consumerDependencyResolver); + this.distributionStrategy.Init(this.workers.AsReadOnly()); + + this.startedTaskSource.TrySetResult(null); + } + catch (Exception e) + { + this.logHandler.Error( + "Error starting WorkerPool", + e, + new + { + this.consumer.Configuration.ConsumerName, + }); + } } public async Task StopAsync() @@ -89,7 +100,10 @@ public async Task StopAsync() await Task.WhenAll(currentWorkers.Select(x => x.StopAsync())).ConfigureAwait(false); - this.offsetManager?.Dispose(); + this.middlewareExecutor.ClearWorkersMiddlewaresInstances(); + + this.offsetCommitter.CommitProcessedOffsets(); + this.offsetManager = null; } @@ -112,5 +126,10 @@ await worker .EnqueueAsync(message, stopCancellationToken) .ConfigureAwait(false); } + + public void Dispose() + { + this.offsetCommitter.Dispose(); + } } } diff --git a/src/KafkaFlow/Consumers/DistributionStrategies/BytesSumDistributionStrategy.cs b/src/KafkaFlow/Consumers/DistributionStrategies/BytesSumDistributionStrategy.cs index b68f9c5f6..5c5409839 100644 --- a/src/KafkaFlow/Consumers/DistributionStrategies/BytesSumDistributionStrategy.cs +++ b/src/KafkaFlow/Consumers/DistributionStrategies/BytesSumDistributionStrategy.cs @@ -23,15 +23,22 @@ public void Init(IReadOnlyList workers) /// public Task GetWorkerAsync(byte[] partitionKey, CancellationToken cancellationToken) { - if (partitionKey is null) + if (partitionKey is null || this.workers.Count == 1) { return Task.FromResult(this.workers[0]); } + var bytesSum = 0; + + for (int i = 0; i < partitionKey.Length; i++) + { + bytesSum += partitionKey[i]; + } + return Task.FromResult( cancellationToken.IsCancellationRequested ? null - : this.workers.ElementAtOrDefault(partitionKey.Sum(x => x) % this.workers.Count)); + : this.workers.ElementAtOrDefault(bytesSum % this.workers.Count)); } } } diff --git a/src/KafkaFlow/Consumers/IConsumerWorkerPool.cs b/src/KafkaFlow/Consumers/IConsumerWorkerPool.cs index 4c1b4626e..32f0c51f1 100644 --- a/src/KafkaFlow/Consumers/IConsumerWorkerPool.cs +++ b/src/KafkaFlow/Consumers/IConsumerWorkerPool.cs @@ -7,7 +7,9 @@ namespace KafkaFlow.Consumers internal interface IConsumerWorkerPool { - Task StartAsync(IEnumerable partitions); + int CurrentWorkersCount { get; } + + Task StartAsync(IReadOnlyCollection partitions, int workersCount); Task StopAsync(); diff --git a/src/KafkaFlow/Consumers/IOffsetCommitter.cs b/src/KafkaFlow/Consumers/IOffsetCommitter.cs index ae94f1ee5..2226113fb 100644 --- a/src/KafkaFlow/Consumers/IOffsetCommitter.cs +++ b/src/KafkaFlow/Consumers/IOffsetCommitter.cs @@ -6,5 +6,7 @@ namespace KafkaFlow.Consumers internal interface IOffsetCommitter : IDisposable { void MarkAsProcessed(TopicPartitionOffset tpo); + + void CommitProcessedOffsets(); } } diff --git a/src/KafkaFlow/Consumers/MessageConsumer.cs b/src/KafkaFlow/Consumers/MessageConsumer.cs index e1ee59098..262854764 100644 --- a/src/KafkaFlow/Consumers/MessageConsumer.cs +++ b/src/KafkaFlow/Consumers/MessageConsumer.cs @@ -41,7 +41,7 @@ public MessageConsumer( public string ClientInstanceName => this.consumerManager.Consumer.ClientInstanceName; - public int WorkersCount => this.consumerManager.Consumer.Configuration.WorkersCount; + public int WorkersCount => this.consumerManager.WorkerPool.CurrentWorkersCount; public IReadOnlyList PausedPartitions => this.consumerManager.Consumer.FlowManager?.PausedPartitions ?? @@ -121,12 +121,12 @@ public async Task OverrideOffsetsAndRestartAsync(IReadOnlyCollection Task.FromResult(workersCount); await this.InternalRestart().ConfigureAwait(false); this.logHandler.Info( - $"Total of workers in Kafkaflow consumer '{this.ConsumerName}' were updated", + $"Total of workers in KafkaFlow consumer '{this.ConsumerName}' were updated", new { workersCount }); } diff --git a/src/KafkaFlow/Consumers/NullOffsetCommitter.cs b/src/KafkaFlow/Consumers/NullOffsetCommitter.cs index 1184f812e..45f62eb4d 100644 --- a/src/KafkaFlow/Consumers/NullOffsetCommitter.cs +++ b/src/KafkaFlow/Consumers/NullOffsetCommitter.cs @@ -13,5 +13,10 @@ public void MarkAsProcessed(TopicPartitionOffset tpo) { // Do nothing } + + public void CommitProcessedOffsets() + { + // Do nothing + } } } diff --git a/src/KafkaFlow/Consumers/OffsetCommitter.cs b/src/KafkaFlow/Consumers/OffsetCommitter.cs index 95c4bc5fc..349c0a120 100644 --- a/src/KafkaFlow/Consumers/OffsetCommitter.cs +++ b/src/KafkaFlow/Consumers/OffsetCommitter.cs @@ -17,6 +17,8 @@ internal class OffsetCommitter : IOffsetCommitter private ConcurrentDictionary<(string, int), TopicPartitionOffset> offsetsToCommit = new(); + private readonly object commitSyncRoot = new(); + public OffsetCommitter( IConsumer consumer, IDependencyResolver resolver, @@ -62,6 +64,8 @@ public void MarkAsProcessed(TopicPartitionOffset tpo) (_, _) => tpo); } + public void CommitProcessedOffsets() => this.CommitHandler(); + private void PendingOffsetsHandler( IDependencyResolver resolver, Action> handler) @@ -74,53 +78,61 @@ private void PendingOffsetsHandler( private void CommitHandler() { - ConcurrentDictionary<(string, int), TopicPartitionOffset> offsets = null; - - try + lock (this.commitSyncRoot) { - if (!this.offsetsToCommit.Any()) + ConcurrentDictionary<(string, int), TopicPartitionOffset> offsets = null; + + try { - return; - } + if (!this.offsetsToCommit.Any()) + { + return; + } - offsets = Interlocked.Exchange( - ref this.offsetsToCommit, - new ConcurrentDictionary<(string, int), TopicPartitionOffset>()); + offsets = Interlocked.Exchange( + ref this.offsetsToCommit, + new ConcurrentDictionary<(string, int), TopicPartitionOffset>()); - this.consumer.Commit(offsets.Values); + this.consumer.Commit(offsets.Values); - if (!this.consumer.Configuration.ManagementDisabled) + if (!this.consumer.Configuration.ManagementDisabled) + { + this.LogOffsetsCommitted(offsets); + } + } + catch (Exception e) { - this.logHandler.Verbose( - "Offsets committed", - new - { - Offsets = offsets.GroupBy( - x => x.Key.Item1, - (topic, groupedOffsets) => new - { - Topic = topic, - Partitions = groupedOffsets.Select( - offset => new - { - Partition = offset.Value.Partition.Value, - Offset = offset.Value.Offset.Value, - }), - }), - }); + this.logHandler.Warning( + "Error Commiting Offsets", + new { ErrorMessage = e.Message }); + + if (offsets is not null) + { + this.RequeueFailedOffsets(offsets.Values); + } } } - catch (Exception e) - { - this.logHandler.Warning( - "Error Commiting Offsets", - new { ErrorMessage = e.Message }); + } - if (offsets is not null) + private void LogOffsetsCommitted(ConcurrentDictionary<(string, int), TopicPartitionOffset> offsets) + { + this.logHandler.Verbose( + "Offsets committed", + new { - this.RequeueFailedOffsets(offsets.Values); - } - } + Offsets = offsets.GroupBy( + x => x.Key.Item1, + (topic, groupedOffsets) => new + { + Topic = topic, + Partitions = groupedOffsets.Select( + offset => new + { + Partition = offset.Value.Partition.Value, + Offset = offset.Value.Offset.Value, + }), + }), + }); } private void RequeueFailedOffsets(IEnumerable offsets) diff --git a/src/KafkaFlow/Consumers/OffsetManager.cs b/src/KafkaFlow/Consumers/OffsetManager.cs index 67676b388..e3b0f34a3 100644 --- a/src/KafkaFlow/Consumers/OffsetManager.cs +++ b/src/KafkaFlow/Consumers/OffsetManager.cs @@ -6,7 +6,7 @@ namespace KafkaFlow.Consumers using System.Linq; using Confluent.Kafka; - internal class OffsetManager : IOffsetManager, IDisposable + internal class OffsetManager : IOffsetManager { private readonly ConcurrentDictionary> onProcessedActions = new(); @@ -54,18 +54,13 @@ public void OnOffsetProcessed(TopicPartitionOffset offset, Action action) public void Enqueue(TopicPartitionOffset offset) { if (this.partitionsOffsets.TryGetValue( - (offset.Topic, offset.Partition.Value), - out var offsets)) + (offset.Topic, offset.Partition.Value), + out var offsets)) { offsets.Enqueue(offset.Offset.Value); } } - public void Dispose() - { - this.committer.Dispose(); - } - private void ExecuteOffsetActions(TopicPartitionOffset offset) { if (!this.onProcessedActions.TryGetValue(offset, out var actions)) diff --git a/src/KafkaFlow/DateTimeProvider.cs b/src/KafkaFlow/DateTimeProvider.cs index adeb55036..a5570242b 100644 --- a/src/KafkaFlow/DateTimeProvider.cs +++ b/src/KafkaFlow/DateTimeProvider.cs @@ -4,7 +4,7 @@ namespace KafkaFlow internal class DateTimeProvider : IDateTimeProvider { - public DateTime Now => DateTime.Now; + public DateTime UtcNow => DateTime.UtcNow; public DateTime MinValue => DateTime.MinValue; } diff --git a/src/KafkaFlow/Extensions/ConfigurationBuilderExtensions.cs b/src/KafkaFlow/Extensions/ConfigurationBuilderExtensions.cs index 1d8841142..3048627ca 100644 --- a/src/KafkaFlow/Extensions/ConfigurationBuilderExtensions.cs +++ b/src/KafkaFlow/Extensions/ConfigurationBuilderExtensions.cs @@ -75,7 +75,7 @@ public static IConsumerConfigurationBuilder WithPartitionsAssignedHandler( /// public static IConsumerConfigurationBuilder WithPartitionsRevokedHandler( this IConsumerConfigurationBuilder builder, - Action> partitionsRevokedHandler) + Action> partitionsRevokedHandler) { return ((ConsumerConfigurationBuilder)builder).WithPartitionsRevokedHandler(partitionsRevokedHandler); } @@ -89,7 +89,7 @@ public static IConsumerConfigurationBuilder WithPartitionsRevokedHandler( /// public static IConsumerConfigurationBuilder WithPendingOffsetsStatisticsHandler( this IConsumerConfigurationBuilder builder, - Action> pendingOffsetsHandler, + Action> pendingOffsetsHandler, TimeSpan interval) { return ((ConsumerConfigurationBuilder)builder).WithPendingOffsetsStatisticsHandler(pendingOffsetsHandler, interval); diff --git a/src/KafkaFlow/IMiddlewareExecutor.cs b/src/KafkaFlow/IMiddlewareExecutor.cs index 44c25c9d7..3d03a4272 100644 --- a/src/KafkaFlow/IMiddlewareExecutor.cs +++ b/src/KafkaFlow/IMiddlewareExecutor.cs @@ -5,9 +5,8 @@ namespace KafkaFlow internal interface IMiddlewareExecutor { - Task Execute( - IDependencyResolver dependencyResolver, - IMessageContext context, - Func nextOperation); + Task Execute(IMessageContext context, Func nextOperation); + + void ClearWorkersMiddlewaresInstances(); } } diff --git a/src/KafkaFlow/MessageContext.cs b/src/KafkaFlow/MessageContext.cs index 6a524efe1..fd5317578 100644 --- a/src/KafkaFlow/MessageContext.cs +++ b/src/KafkaFlow/MessageContext.cs @@ -7,10 +7,12 @@ internal class MessageContext : IMessageContext public MessageContext( Message message, IMessageHeaders headers, + IDependencyResolver dependencyResolver, IConsumerContext consumer, IProducerContext producer) { this.Message = message; + this.DependencyResolver = dependencyResolver; this.Headers = headers ?? new MessageHeaders(); this.ConsumerContext = consumer; this.ProducerContext = producer; @@ -19,6 +21,8 @@ public MessageContext( public Message Message { get; } + public IDependencyResolver DependencyResolver { get; } + public IConsumerContext ConsumerContext { get; } public IProducerContext ProducerContext { get; } @@ -30,6 +34,7 @@ public MessageContext( public IMessageContext SetMessage(object key, object value) => new MessageContext( new Message(key, value), this.Headers, + this.DependencyResolver, this.ConsumerContext, this.ProducerContext); diff --git a/src/KafkaFlow/MiddlewareExecutor.cs b/src/KafkaFlow/MiddlewareExecutor.cs index a9fa3bc43..7f8a5547a 100644 --- a/src/KafkaFlow/MiddlewareExecutor.cs +++ b/src/KafkaFlow/MiddlewareExecutor.cs @@ -18,25 +18,20 @@ public MiddlewareExecutor(IReadOnlyList configurations) this.configurations = configurations; } - public Task Execute( - IDependencyResolver dependencyResolver, - IMessageContext context, - Func nextOperation) + public Task Execute(IMessageContext context, Func nextOperation) { - return this.ExecuteDefinition( - 0, - dependencyResolver, - context, - nextOperation); + return this.ExecuteDefinition(0, context, nextOperation); } + public void ClearWorkersMiddlewaresInstances() => this.workersMiddlewares.Clear(); + private static IMessageMiddleware CreateInstance( IDependencyResolver dependencyResolver, MiddlewareConfiguration configuration) { if (configuration.InstanceContainerId is null) { - return (IMessageMiddleware) dependencyResolver.Resolve(configuration.Type); + return (IMessageMiddleware)dependencyResolver.Resolve(configuration.Type); } var instanceContainer = dependencyResolver @@ -55,11 +50,7 @@ private static IMessageMiddleware CreateInstance( return instanceContainer.GetInstance(dependencyResolver); } - private Task ExecuteDefinition( - int index, - IDependencyResolver dependencyResolver, - IMessageContext context, - Func nextOperation) + private Task ExecuteDefinition(int index, IMessageContext context, Func nextOperation) { if (this.configurations.Count == index) { @@ -69,27 +60,25 @@ private Task ExecuteDefinition( var configuration = this.configurations[index]; return this - .ResolveInstance(dependencyResolver, index, context, configuration) + .ResolveInstance(index, context, configuration) .Invoke( context, - nextContext => this.ExecuteDefinition( - index + 1, - dependencyResolver, - nextContext, - nextOperation)); + nextContext => this.ExecuteDefinition(index + 1, nextContext, nextOperation)); } - private IMessageMiddleware ResolveInstance( - IDependencyResolver dependencyResolver, - int index, - IMessageContext context, - MiddlewareConfiguration configuration) + private IMessageMiddleware ResolveInstance(int index, IMessageContext context, MiddlewareConfiguration configuration) { return configuration.Lifetime switch { - MiddlewareLifetime.Worker => this.GetWorkerInstance(dependencyResolver, index, context, configuration), - MiddlewareLifetime.ConsumerOrProducer => this.GetConsumerOrProducerInstance(dependencyResolver, index, configuration), - _ => CreateInstance(dependencyResolver, configuration) + MiddlewareLifetime.Worker => this.GetWorkerInstance( + index, + context, + configuration), + MiddlewareLifetime.ConsumerOrProducer => this.GetConsumerOrProducerInstance( + context.ConsumerContext?.ConsumerDependencyResolver ?? context.ProducerContext?.DependencyResolver, + index, + configuration), + _ => CreateInstance(context.DependencyResolver, configuration) }; } @@ -104,14 +93,13 @@ private IMessageMiddleware GetConsumerOrProducerInstance( } private IMessageMiddleware GetWorkerInstance( - IDependencyResolver dependencyResolver, int index, IMessageContext context, MiddlewareConfiguration configuration) { return this.workersMiddlewares.SafeGetOrAdd( (index, context.ConsumerContext?.WorkerId ?? 0), - _ => CreateInstance(dependencyResolver, configuration)); + _ => CreateInstance(context.ConsumerContext.WorkerDependencyResolver, configuration)); } } } diff --git a/src/KafkaFlow/Producers/MessageProducer.cs b/src/KafkaFlow/Producers/MessageProducer.cs index 85fd3096e..124894916 100644 --- a/src/KafkaFlow/Producers/MessageProducer.cs +++ b/src/KafkaFlow/Producers/MessageProducer.cs @@ -8,7 +8,8 @@ namespace KafkaFlow.Producers internal class MessageProducer : IMessageProducer, IDisposable { - private readonly IDependencyResolver dependencyResolver; + private readonly IDependencyResolverScope producerDependencyScope; + private readonly ILogHandler logHandler; private readonly IProducerConfiguration configuration; private readonly MiddlewareExecutor middlewareExecutor; private readonly GlobalEvents globalEvents; @@ -21,10 +22,11 @@ public MessageProducer( IDependencyResolver dependencyResolver, IProducerConfiguration configuration) { - this.dependencyResolver = dependencyResolver; + this.producerDependencyScope = dependencyResolver.CreateScope(); + this.logHandler = dependencyResolver.Resolve(); this.configuration = configuration; this.middlewareExecutor = new MiddlewareExecutor(configuration.MiddlewaresConfigurations); - this.globalEvents = this.dependencyResolver.Resolve(); + this.globalEvents = dependencyResolver.Resolve(); } public string ProducerName => this.configuration.Name; @@ -38,29 +40,33 @@ public async Task> ProduceAsync( { DeliveryResult report = null; - using var scope = this.dependencyResolver.CreateScope(); + using var messageScope = this.producerDependencyScope.Resolver.CreateScope(); - var messageContext = this.CreateMessageContext(topic, messageKey, messageValue, headers); + var messageContext = this.CreateMessageContext( + topic, + messageKey, + messageValue, + headers, + messageScope.Resolver); await this.globalEvents.FireMessageProduceStartedAsync(new MessageEventContext(messageContext)); try { await this.middlewareExecutor - .Execute( - scope.Resolver, - messageContext, - async context => - { - report = await this - .InternalProduceAsync(context, partition) - .ConfigureAwait(false); - }) - .ConfigureAwait(false); + .Execute( + messageContext, + async context => + { + report = await this + .InternalProduceAsync(context, partition) + .ConfigureAwait(false); + }) + .ConfigureAwait(false); await this.globalEvents.FireMessageProduceCompletedAsync(new MessageEventContext(messageContext)); } - catch(Exception e) + catch (Exception e) { await this.globalEvents.FireMessageProduceErrorAsync(new MessageErrorEventContext(messageContext, e)); throw; @@ -97,15 +103,19 @@ public void Produce( Action> deliveryHandler = null, int? partition = null) { - var scope = this.dependencyResolver.CreateScope(); + var messageScope = this.producerDependencyScope.Resolver.CreateScope(); - var messageContext = this.CreateMessageContext(topic, messageKey, messageValue, headers); + var messageContext = this.CreateMessageContext( + topic, + messageKey, + messageValue, + headers, + messageScope.Resolver); this.globalEvents.FireMessageProduceStartedAsync(new MessageEventContext(messageContext)); this.middlewareExecutor .Execute( - scope.Resolver, messageContext, context => { @@ -144,7 +154,7 @@ public void Produce( }); } - scope.Dispose(); + messageScope.Dispose(); }); this.globalEvents.FireMessageProduceCompletedAsync(new MessageEventContext(messageContext)); @@ -239,9 +249,7 @@ private IProducer EnsureProducer() } else { - this.dependencyResolver - .Resolve() - .Warning("Kafka Producer Error", new { Error = error }); + this.logHandler.Warning("Kafka Producer Error", new { Error = error }); } }) .SetStatisticsHandler( @@ -255,7 +263,7 @@ private IProducer EnsureProducer() return this.producer = this.configuration.CustomFactory( producerBuilder.Build(), - this.dependencyResolver); + this.producerDependencyScope.Resolver); } } @@ -266,12 +274,10 @@ private void InvalidateProducer(Error error, DeliveryResult resu this.producer = null; } - this.dependencyResolver - .Resolve() - .Error( - "Kafka produce fatal error occurred. The producer will be recreated", - result is null ? new KafkaException(error) : new ProduceException(error, result), - new { Error = error }); + this.logHandler.Error( + "Kafka produce fatal error occurred. The producer will be recreated", + result is null ? new KafkaException(error) : new ProduceException(error, result), + new { Error = error }); } private async Task> InternalProduceAsync(IMessageContext context, int? partition) @@ -346,13 +352,15 @@ private MessageContext CreateMessageContext( string topic, object messageKey, object messageValue, - IMessageHeaders headers = null) + IMessageHeaders headers, + IDependencyResolver messageScopedResolver) { return new( new Message(messageKey, messageValue), headers, + messageScopedResolver, null, - new ProducerContext(topic)); + new ProducerContext(topic, this.producerDependencyScope.Resolver)); } } } diff --git a/src/KafkaFlow/Producers/ProducerContext.cs b/src/KafkaFlow/Producers/ProducerContext.cs index b42ffceea..98e8d17fc 100644 --- a/src/KafkaFlow/Producers/ProducerContext.cs +++ b/src/KafkaFlow/Producers/ProducerContext.cs @@ -2,9 +2,10 @@ namespace KafkaFlow.Producers { internal class ProducerContext : IProducerContext { - public ProducerContext(string topic) + public ProducerContext(string topic, IDependencyResolver producerDependencyResolver) { this.Topic = topic; + this.DependencyResolver = producerDependencyResolver; } public string Topic { get; } @@ -12,5 +13,7 @@ public ProducerContext(string topic) public int? Partition { get; set; } public long? Offset { get; set; } + + public IDependencyResolver DependencyResolver { get; } } } diff --git a/src/KafkaFlow/TopicMetadata.cs b/src/KafkaFlow/TopicMetadata.cs new file mode 100644 index 000000000..cf3397cdf --- /dev/null +++ b/src/KafkaFlow/TopicMetadata.cs @@ -0,0 +1,17 @@ +namespace KafkaFlow +{ + using System.Collections.Generic; + + public record TopicMetadata + { + public TopicMetadata(string name, IReadOnlyCollection partitions) + { + this.Name = name; + this.Partitions = partitions; + } + + public string Name { get; } + + public IReadOnlyCollection Partitions { get; } + } +} diff --git a/src/KafkaFlow/TopicPartitionMetadata.cs b/src/KafkaFlow/TopicPartitionMetadata.cs new file mode 100644 index 000000000..37ecd4a8e --- /dev/null +++ b/src/KafkaFlow/TopicPartitionMetadata.cs @@ -0,0 +1,12 @@ +namespace KafkaFlow +{ + public class TopicPartitionMetadata + { + public TopicPartitionMetadata(int Id) + { + this.Id = Id; + } + + public int Id { get; } + } +} diff --git a/src/KafkaFlow/TopicPartitionOffset.cs b/src/KafkaFlow/TopicPartitionOffset.cs new file mode 100644 index 000000000..1f463e203 --- /dev/null +++ b/src/KafkaFlow/TopicPartitionOffset.cs @@ -0,0 +1,36 @@ +namespace KafkaFlow +{ + /// + /// Represents a Kafka topic along with its partition and offset information. + /// + public class TopicPartitionOffset + { + /// + /// Initializes a new instance of the class with the specified topic name, partition number, and offset value. + /// + /// The name of the topic. + /// The id of the partition. + /// The offset value. + public TopicPartitionOffset(string topic, int partition, long offset) + { + this.Topic = topic; + this.Partition = partition; + this.Offset = offset; + } + + /// + /// Gets the name of the topic. + /// + public string Topic { get; } + + /// + /// Gets the id of the partition. + /// + public int Partition { get; } + + /// + /// Gets the offset value. + /// + public long Offset { get; } + } +} From efd9f8b15b92e39fdb1bfb031eb92e655d62f77b Mon Sep 17 00:00:00 2001 From: Filipe Esch Date: Tue, 11 Jul 2023 20:32:59 +0100 Subject: [PATCH 05/20] refactor: core simplification and better thread synchronization --- .../IConsumerContext.cs | 19 +++++- .../TopicPartitionOffset.cs | 4 +- .../BatchConsumeMiddleware.cs | 16 ++++- .../KafkaFlow.BatchConsume.csproj | 4 ++ src/KafkaFlow/ConsumerManagerFactory.cs | 16 ++++- src/KafkaFlow/Consumers/Consumer.cs | 2 +- src/KafkaFlow/Consumers/ConsumerContext.cs | 50 ++++++++++----- src/KafkaFlow/Consumers/ConsumerManager.cs | 5 ++ src/KafkaFlow/Consumers/ConsumerWorker.cs | 62 +++++++------------ src/KafkaFlow/Consumers/ConsumerWorkerPool.cs | 52 ++++++++++++---- src/KafkaFlow/Consumers/IConsumer.cs | 2 +- .../Consumers/IConsumerFlowManager.cs | 1 - src/KafkaFlow/Consumers/IConsumerWorker.cs | 10 ++- src/KafkaFlow/Consumers/IOffsetCommitter.cs | 3 - src/KafkaFlow/Consumers/IOffsetManager.cs | 7 +-- .../Consumers/NullOffsetCommitter.cs | 2 +- src/KafkaFlow/Consumers/OffsetCommitter.cs | 36 ++++++----- src/KafkaFlow/Consumers/OffsetManager.cs | 47 +++----------- src/KafkaFlow/Consumers/PartitionOffsets.cs | 34 +++++----- .../Consumers/WorkerPoolStoppedSubject.cs | 8 +++ src/KafkaFlow/Core/Observer/ISubject.cs | 8 +++ .../Core/Observer/ISubjectObserver.cs | 8 +++ src/KafkaFlow/Core/Observer/Subject.cs | 20 ++++++ src/KafkaFlow/IMiddlewareExecutor.cs | 2 - src/KafkaFlow/MiddlewareExecutor.cs | 11 +++- 25 files changed, 264 insertions(+), 165 deletions(-) rename src/{KafkaFlow => KafkaFlow.Abstractions}/TopicPartitionOffset.cs (88%) create mode 100644 src/KafkaFlow/Consumers/WorkerPoolStoppedSubject.cs create mode 100644 src/KafkaFlow/Core/Observer/ISubject.cs create mode 100644 src/KafkaFlow/Core/Observer/ISubjectObserver.cs create mode 100644 src/KafkaFlow/Core/Observer/Subject.cs diff --git a/src/KafkaFlow.Abstractions/IConsumerContext.cs b/src/KafkaFlow.Abstractions/IConsumerContext.cs index bd7fafc98..44b57e47c 100644 --- a/src/KafkaFlow.Abstractions/IConsumerContext.cs +++ b/src/KafkaFlow.Abstractions/IConsumerContext.cs @@ -2,6 +2,7 @@ namespace KafkaFlow { using System; using System.Threading; + using System.Threading.Tasks; /// /// Represents the message consumer @@ -38,6 +39,11 @@ public interface IConsumerContext /// long Offset { get; } + /// + /// Gets the object associated with the message + /// + TopicPartitionOffset TopicPartitionOffset { get; } + /// /// Gets the consumer group id from kafka consumer that received the message /// @@ -67,9 +73,11 @@ public interface IConsumerContext /// IDependencyResolver WorkerDependencyResolver { get; } - /// - /// Store the message offset when manual store option is used + /// Stores the message offset to eventually be committed. After this call, the framework considers the + /// message processing as finished and releases resources associated with the message. + /// By default, this method is automatically called when the message processing ends, unless + /// the consumer is set to manual store offsets or the flag is set to false. /// void StoreOffset(); @@ -88,5 +96,12 @@ public interface IConsumerContext /// Resume Kafka's message fetch /// void Resume(); + + /// + /// Gets a Task that completes when the method is invoked, + /// indicating the end of message processing. This allows async operations + /// to wait for the message to be fully processed and its offset stored. + /// + Task Completion { get; } } } diff --git a/src/KafkaFlow/TopicPartitionOffset.cs b/src/KafkaFlow.Abstractions/TopicPartitionOffset.cs similarity index 88% rename from src/KafkaFlow/TopicPartitionOffset.cs rename to src/KafkaFlow.Abstractions/TopicPartitionOffset.cs index 1f463e203..5b17cb138 100644 --- a/src/KafkaFlow/TopicPartitionOffset.cs +++ b/src/KafkaFlow.Abstractions/TopicPartitionOffset.cs @@ -3,10 +3,10 @@ namespace KafkaFlow /// /// Represents a Kafka topic along with its partition and offset information. /// - public class TopicPartitionOffset + public readonly struct TopicPartitionOffset { /// - /// Initializes a new instance of the class with the specified topic name, partition number, and offset value. + /// Initializes a new instance of the struct with the specified topic name, partition number, and offset value. /// /// The name of the topic. /// The id of the partition. diff --git a/src/KafkaFlow.BatchConsume/BatchConsumeMiddleware.cs b/src/KafkaFlow.BatchConsume/BatchConsumeMiddleware.cs index 4f61f6626..53105d97a 100644 --- a/src/KafkaFlow.BatchConsume/BatchConsumeMiddleware.cs +++ b/src/KafkaFlow.BatchConsume/BatchConsumeMiddleware.cs @@ -6,7 +6,7 @@ using System.Threading; using System.Threading.Tasks; - internal class BatchConsumeMiddleware : IMessageMiddleware, IDisposable + internal class BatchConsumeMiddleware : IMessageMiddleware, IDisposable, IAsyncDisposable { private readonly SemaphoreSlim dispatchSemaphore = new(1, 1); @@ -65,11 +65,16 @@ public async Task Invoke(IMessageContext context, MiddlewareDelegate next) } } - public void Dispose() + public async ValueTask DisposeAsync() { - this.dispatchTokenSource?.Dispose(); + this.dispatchTokenSource.Dispose(); + + await this.dispatchSemaphore.WaitAsync(); + this.dispatchSemaphore.Dispose(); } + public void Dispose() => this.DisposeAsync().GetAwaiter().GetResult(); + private async Task DispatchAsync(IMessageContext context, MiddlewareDelegate next) { await this.dispatchSemaphore.WaitAsync(); @@ -77,6 +82,11 @@ private async Task DispatchAsync(IMessageContext context, MiddlewareDelegate nex try { + if (!localBatch.Any()) + { + return; + } + var batchContext = new BatchConsumeMessageContext(context.ConsumerContext, localBatch); await next(batchContext).ConfigureAwait(false); diff --git a/src/KafkaFlow.BatchConsume/KafkaFlow.BatchConsume.csproj b/src/KafkaFlow.BatchConsume/KafkaFlow.BatchConsume.csproj index cd42c7410..997d1725c 100644 --- a/src/KafkaFlow.BatchConsume/KafkaFlow.BatchConsume.csproj +++ b/src/KafkaFlow.BatchConsume/KafkaFlow.BatchConsume.csproj @@ -11,4 +11,8 @@ + + + + diff --git a/src/KafkaFlow/ConsumerManagerFactory.cs b/src/KafkaFlow/ConsumerManagerFactory.cs index cb10ad4bf..1ce0f1f21 100644 --- a/src/KafkaFlow/ConsumerManagerFactory.cs +++ b/src/KafkaFlow/ConsumerManagerFactory.cs @@ -11,13 +11,26 @@ public IConsumerManager Create(IConsumerConfiguration configuration, IDependency var consumer = configuration.CustomFactory(new Consumer(configuration, resolver, logHandler), resolver); + IOffsetCommitter offsetCommitter = configuration.NoStoreOffsets ? + new NullOffsetCommitter() : + new OffsetCommitter( + consumer, + resolver, + configuration.PendingOffsetsHandlers, + logHandler); + + var middlewareExecutor = new MiddlewareExecutor(configuration.MiddlewaresConfigurations); + var consumerWorkerPool = new ConsumerWorkerPool( consumer, + offsetCommitter, resolver, - new MiddlewareExecutor(configuration.MiddlewaresConfigurations), + middlewareExecutor, configuration, logHandler); + consumerWorkerPool.WorkerPoolStopped.Subscribe(middlewareExecutor); + var feeder = new WorkerPoolFeeder( consumer, consumerWorkerPool, @@ -27,6 +40,7 @@ public IConsumerManager Create(IConsumerConfiguration configuration, IDependency consumer, consumerWorkerPool, feeder, + offsetCommitter, resolver, logHandler); diff --git a/src/KafkaFlow/Consumers/Consumer.cs b/src/KafkaFlow/Consumers/Consumer.cs index 6e05c1b8c..ecf4a47fe 100644 --- a/src/KafkaFlow/Consumers/Consumer.cs +++ b/src/KafkaFlow/Consumers/Consumer.cs @@ -127,7 +127,7 @@ public IEnumerable GetTopicPartitionsLag() }); } - public void Commit(IEnumerable offsetsValues) + public void Commit(IReadOnlyCollection offsetsValues) { this.consumer.Commit(offsetsValues); diff --git a/src/KafkaFlow/Consumers/ConsumerContext.cs b/src/KafkaFlow/Consumers/ConsumerContext.cs index ec5591802..356d001f9 100644 --- a/src/KafkaFlow/Consumers/ConsumerContext.cs +++ b/src/KafkaFlow/Consumers/ConsumerContext.cs @@ -2,48 +2,55 @@ namespace KafkaFlow.Consumers { using System; using System.Threading; + using System.Threading.Tasks; using Confluent.Kafka; + using TopicPartitionOffset = KafkaFlow.TopicPartitionOffset; internal class ConsumerContext : IConsumerContext { + private readonly TaskCompletionSource completionSource = new(); private readonly IConsumer consumer; private readonly IOffsetManager offsetManager; - private readonly TopicPartitionOffset topicPartitionOffset; + private readonly IConsumerWorker worker; + private readonly IDependencyResolverScope messageDependencyScope; public ConsumerContext( IConsumer consumer, IOffsetManager offsetManager, ConsumeResult kafkaResult, - CancellationToken workerStopped, - int workerId, - IDependencyResolver workerDependencyResolver, + IConsumerWorker worker, + IDependencyResolverScope messageDependencyScope, IDependencyResolver consumerDependencyResolver) { - this.WorkerStopped = workerStopped; - this.WorkerId = workerId; - this.WorkerDependencyResolver = workerDependencyResolver; this.ConsumerDependencyResolver = consumerDependencyResolver; this.consumer = consumer; this.offsetManager = offsetManager; - this.topicPartitionOffset = kafkaResult.TopicPartitionOffset; + this.worker = worker; + this.messageDependencyScope = messageDependencyScope; + this.TopicPartitionOffset = new TopicPartitionOffset( + kafkaResult.Topic, + kafkaResult.Partition.Value, + kafkaResult.Offset.Value); this.MessageTimestamp = kafkaResult.Message.Timestamp.UtcDateTime; } public string ConsumerName => this.consumer.Configuration.ConsumerName; - public CancellationToken WorkerStopped { get; } + public CancellationToken WorkerStopped => this.worker.StopCancellationToken; - public int WorkerId { get; } + public int WorkerId => this.worker.Id; - public IDependencyResolver WorkerDependencyResolver { get; } + public IDependencyResolver WorkerDependencyResolver => this.worker.WorkerDependencyResolver; public IDependencyResolver ConsumerDependencyResolver { get; } - public string Topic => this.topicPartitionOffset.Topic; + public string Topic => this.TopicPartitionOffset.Topic; - public int Partition => this.topicPartitionOffset.Partition.Value; + public int Partition => this.TopicPartitionOffset.Partition; - public long Offset => this.topicPartitionOffset.Offset.Value; + public long Offset => this.TopicPartitionOffset.Offset; + + public TopicPartitionOffset TopicPartitionOffset { get; } public string GroupId => this.consumer.Configuration.GroupId; @@ -51,10 +58,21 @@ public ConsumerContext( public DateTime MessageTimestamp { get; } - public void StoreOffset() => this.offsetManager.MarkAsProcessed(this.topicPartitionOffset); + public Task Completion => this.completionSource.Task; + + public void StoreOffset() + { + this.offsetManager.MarkAsProcessed(this); + this.messageDependencyScope.Dispose(); + this.completionSource.TrySetResult(this.TopicPartitionOffset); + } public IOffsetsWatermark GetOffsetsWatermark() => - new OffsetsWatermark(this.consumer.GetWatermarkOffsets(this.topicPartitionOffset.TopicPartition)); + new OffsetsWatermark( + this.consumer.GetWatermarkOffsets( + new TopicPartition( + this.TopicPartitionOffset.Topic, + this.TopicPartitionOffset.Partition))); public void Pause() => this.consumer.FlowManager.Pause(this.consumer.Assignment); diff --git a/src/KafkaFlow/Consumers/ConsumerManager.cs b/src/KafkaFlow/Consumers/ConsumerManager.cs index 13fa0bc85..84d8ad3b1 100644 --- a/src/KafkaFlow/Consumers/ConsumerManager.cs +++ b/src/KafkaFlow/Consumers/ConsumerManager.cs @@ -10,6 +10,7 @@ internal class ConsumerManager : IConsumerManager, IDisposable { + private readonly IOffsetCommitter offsetCommitter; private readonly IDependencyResolver dependencyResolver; private readonly ILogHandler logHandler; private readonly Timer evaluateWorkersCountTimer; @@ -18,9 +19,11 @@ public ConsumerManager( IConsumer consumer, IConsumerWorkerPool consumerWorkerPool, IWorkerPoolFeeder feeder, + IOffsetCommitter offsetCommitter, IDependencyResolver dependencyResolver, ILogHandler logHandler) { + this.offsetCommitter = offsetCommitter; this.dependencyResolver = dependencyResolver; this.logHandler = logHandler; this.Consumer = consumer; @@ -59,6 +62,8 @@ public async Task StopAsync() await this.Feeder.StopAsync().ConfigureAwait(false); await this.WorkerPool.StopAsync().ConfigureAwait(false); + this.offsetCommitter.Dispose(); + this.Consumer.Dispose(); } diff --git a/src/KafkaFlow/Consumers/ConsumerWorker.cs b/src/KafkaFlow/Consumers/ConsumerWorker.cs index 75e7f3b27..78da342c6 100644 --- a/src/KafkaFlow/Consumers/ConsumerWorker.cs +++ b/src/KafkaFlow/Consumers/ConsumerWorker.cs @@ -4,18 +4,16 @@ namespace KafkaFlow.Consumers using System.Threading; using System.Threading.Channels; using System.Threading.Tasks; - using Confluent.Kafka; internal class ConsumerWorker : IConsumerWorker { private readonly IConsumer consumer; private readonly IDependencyResolver consumerDependencyResolver; - private readonly IOffsetManager offsetManager; private readonly IMiddlewareExecutor middlewareExecutor; private readonly ILogHandler logHandler; private readonly GlobalEvents globalEvents; - private readonly Channel> messagesBuffer; + private readonly Channel messagesBuffer; private CancellationTokenSource stopCancellationTokenSource; private IDependencyResolverScope workerDependencyResolverScope; @@ -26,27 +24,29 @@ public ConsumerWorker( IConsumer consumer, IDependencyResolver consumerDependencyResolver, int workerId, - IOffsetManager offsetManager, IMiddlewareExecutor middlewareExecutor, ILogHandler logHandler) { this.Id = workerId; this.consumer = consumer; this.consumerDependencyResolver = consumerDependencyResolver; - this.offsetManager = offsetManager; this.middlewareExecutor = middlewareExecutor; this.logHandler = logHandler; - this.messagesBuffer = Channel.CreateBounded>(consumer.Configuration.BufferSize); - this.globalEvents = this.dependencyResolver.Resolve(); + this.messagesBuffer = Channel.CreateBounded(consumer.Configuration.BufferSize); + this.globalEvents = consumerDependencyResolver.Resolve(); } public int Id { get; } + public CancellationToken StopCancellationToken => this.stopCancellationTokenSource?.Token ?? default; + + public IDependencyResolver WorkerDependencyResolver => this.workerDependencyResolverScope.Resolver; + public ValueTask EnqueueAsync( - ConsumeResult message, - CancellationToken stopCancellationToken = default) + IMessageContext context, + CancellationToken stopCancellationToken) { - return this.messagesBuffer.Writer.WriteAsync(message, stopCancellationToken); + return this.messagesBuffer.Writer.WriteAsync(context, stopCancellationToken); } public Task StartAsync() @@ -59,18 +59,13 @@ public Task StartAsync() { try { - var cancellationTokenSource = new CancellationTokenSource(); - - this.stopCancellationTokenSource.Token.Register( - () => cancellationTokenSource.CancelAfter(this.consumer.Configuration.WorkerStopTimeout)); - try { while (await this.messagesBuffer.Reader.WaitToReadAsync(CancellationToken.None).ConfigureAwait(false)) { while (this.messagesBuffer.Reader.TryRead(out var message)) { - await this.ProcessMessageAsync(message, cancellationTokenSource.Token).ConfigureAwait(false); + await this.ProcessMessageAsync(message, this.stopCancellationTokenSource.Token).ConfigureAwait(false); } } } @@ -83,7 +78,8 @@ public Task StartAsync() { this.logHandler.Error("KafkaFlow consumer worker fatal error", ex, null); } - }); + }, + CancellationToken.None); return Task.CompletedTask; } @@ -94,13 +90,17 @@ public async Task StopAsync() if (this.stopCancellationTokenSource.Token.CanBeCanceled) { - this.stopCancellationTokenSource.Cancel(); - this.stopCancellationTokenSource.Dispose(); + this.stopCancellationTokenSource.CancelAfter(this.consumer.Configuration.WorkerStopTimeout); } await this.backgroundTask.ConfigureAwait(false); + } + + public void Dispose() + { this.backgroundTask.Dispose(); this.workerDependencyResolverScope.Dispose(); + this.stopCancellationTokenSource.Dispose(); } public void OnTaskCompleted(Action handler) @@ -108,32 +108,12 @@ public void OnTaskCompleted(Action handler) this.onMessageFinishedHandler = handler; } - private async Task ProcessMessageAsync(ConsumeResult message, CancellationToken cancellationToken) + private async Task ProcessMessageAsync(IMessageContext context, CancellationToken cancellationToken) { try { - var messageScope = this.consumerDependencyResolver.CreateScope(); - - var context = new MessageContext( - new Message(message.Message.Key, message.Message.Value), - new MessageHeaders(message.Message.Headers), - messageScope.Resolver, - new ConsumerContext( - this.consumer, - this.offsetManager, - message, - cancellationToken, - this.Id, - this.workerDependencyResolverScope.Resolver, - this.consumerDependencyResolver), - null); - try { - this.offsetManager.OnOffsetProcessed( - message.TopicPartitionOffset, - () => messageScope.Dispose()); - await this.globalEvents.FireMessageConsumeStartedAsync(new MessageEventContext(context)); await this.middlewareExecutor @@ -164,7 +144,7 @@ await this.middlewareExecutor if (this.consumer.Configuration.AutoStoreOffsets && context.ConsumerContext.ShouldStoreOffset) { - this.offsetManager.MarkAsProcessed(message.TopicPartitionOffset); + context.ConsumerContext.StoreOffset(); } this.onMessageFinishedHandler?.Invoke(); diff --git a/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs b/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs index 291951368..25fa208ba 100644 --- a/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs +++ b/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs @@ -7,6 +7,7 @@ namespace KafkaFlow.Consumers using System.Threading.Tasks; using Confluent.Kafka; using KafkaFlow.Configuration; + using KafkaFlow.Core.Observer; internal class ConsumerWorkerPool : IConsumerWorkerPool, IDisposable { @@ -17,6 +18,8 @@ internal class ConsumerWorkerPool : IConsumerWorkerPool, IDisposable private readonly Factory distributionStrategyFactory; private readonly IOffsetCommitter offsetCommitter; + private readonly WorkerPoolStoppedSubject workerPoolStoppedSubject = new(); + private TaskCompletionSource startedTaskSource = new(); private List workers = new(); @@ -25,28 +28,24 @@ internal class ConsumerWorkerPool : IConsumerWorkerPool, IDisposable public ConsumerWorkerPool( IConsumer consumer, + IOffsetCommitter offsetCommitter, IDependencyResolver consumerDependencyResolver, IMiddlewareExecutor middlewareExecutor, IConsumerConfiguration consumerConfiguration, ILogHandler logHandler) { this.consumer = consumer; + this.offsetCommitter = offsetCommitter; this.consumerDependencyResolver = consumerDependencyResolver; this.middlewareExecutor = middlewareExecutor; this.logHandler = logHandler; this.distributionStrategyFactory = consumerConfiguration.DistributionStrategyFactory; - - this.offsetCommitter = this.consumer.Configuration.NoStoreOffsets ? - new NullOffsetCommitter() : - new OffsetCommitter( - this.consumer, - this.consumerDependencyResolver, - consumerConfiguration.PendingOffsetsHandlers, - this.logHandler); } public int CurrentWorkersCount { get; private set; } + public ISubject WorkerPoolStopped => this.workerPoolStoppedSubject; + public async Task StartAsync(IReadOnlyCollection partitions, int workersCount) { try @@ -65,7 +64,6 @@ await Task.WhenAll( this.consumer, this.consumerDependencyResolver, workerId, - this.offsetManager, this.middlewareExecutor, this.logHandler); @@ -94,17 +92,24 @@ await Task.WhenAll( public async Task StopAsync() { + if (this.workers.Count == 0) + { + return; + } + var currentWorkers = this.workers; this.workers = new List(); this.startedTaskSource = new(); await Task.WhenAll(currentWorkers.Select(x => x.StopAsync())).ConfigureAwait(false); - this.middlewareExecutor.ClearWorkersMiddlewaresInstances(); + await this.offsetManager.WaitOffsetsCompletionAsync(); - this.offsetCommitter.CommitProcessedOffsets(); + currentWorkers.ForEach(worker => worker.Dispose()); this.offsetManager = null; + + this.workerPoolStoppedSubject.Notify(); } public async Task EnqueueAsync(ConsumeResult message, CancellationToken stopCancellationToken) @@ -120,16 +125,37 @@ public async Task EnqueueAsync(ConsumeResult message, Cancellati return; } - this.offsetManager?.Enqueue(message.TopicPartitionOffset); + var context = this.CreateMessageContext(message, worker); await worker - .EnqueueAsync(message, stopCancellationToken) + .EnqueueAsync(context, stopCancellationToken) .ConfigureAwait(false); + + this.offsetManager.Enqueue(context.ConsumerContext); } public void Dispose() { this.offsetCommitter.Dispose(); } + + private MessageContext CreateMessageContext(ConsumeResult message, IConsumerWorker worker) + { + var messageDependencyScope = this.consumerDependencyResolver.CreateScope(); + + var context = new MessageContext( + new Message(message.Message.Key, message.Message.Value), + new MessageHeaders(message.Message.Headers), + messageDependencyScope.Resolver, + new ConsumerContext( + this.consumer, + this.offsetManager, + message, + worker, + messageDependencyScope, + this.consumerDependencyResolver), + null); + return context; + } } } diff --git a/src/KafkaFlow/Consumers/IConsumer.cs b/src/KafkaFlow/Consumers/IConsumer.cs index 9d06fb9a0..4774289c7 100644 --- a/src/KafkaFlow/Consumers/IConsumer.cs +++ b/src/KafkaFlow/Consumers/IConsumer.cs @@ -84,7 +84,7 @@ List OffsetsForTimes( TimeSpan timeout); /// - void Commit(IEnumerable offsetsValues); + void Commit(IReadOnlyCollection offsetsValues); /// ValueTask> ConsumeAsync(CancellationToken cancellationToken); diff --git a/src/KafkaFlow/Consumers/IConsumerFlowManager.cs b/src/KafkaFlow/Consumers/IConsumerFlowManager.cs index 9d84316ce..3102da03a 100644 --- a/src/KafkaFlow/Consumers/IConsumerFlowManager.cs +++ b/src/KafkaFlow/Consumers/IConsumerFlowManager.cs @@ -1,6 +1,5 @@ namespace KafkaFlow.Consumers { - using System; using System.Collections.Generic; using Confluent.Kafka; diff --git a/src/KafkaFlow/Consumers/IConsumerWorker.cs b/src/KafkaFlow/Consumers/IConsumerWorker.cs index 7186b940b..bf997816a 100644 --- a/src/KafkaFlow/Consumers/IConsumerWorker.cs +++ b/src/KafkaFlow/Consumers/IConsumerWorker.cs @@ -1,12 +1,16 @@ namespace KafkaFlow.Consumers { + using System; using System.Threading; using System.Threading.Tasks; - using Confluent.Kafka; - internal interface IConsumerWorker : IWorker + internal interface IConsumerWorker : IWorker, IDisposable { - ValueTask EnqueueAsync(ConsumeResult message, CancellationToken stopCancellationToken = default); + CancellationToken StopCancellationToken { get; } + + IDependencyResolver WorkerDependencyResolver { get; } + + ValueTask EnqueueAsync(IMessageContext context, CancellationToken stopCancellationToken); Task StartAsync(); diff --git a/src/KafkaFlow/Consumers/IOffsetCommitter.cs b/src/KafkaFlow/Consumers/IOffsetCommitter.cs index 2226113fb..8130fda23 100644 --- a/src/KafkaFlow/Consumers/IOffsetCommitter.cs +++ b/src/KafkaFlow/Consumers/IOffsetCommitter.cs @@ -1,12 +1,9 @@ namespace KafkaFlow.Consumers { using System; - using Confluent.Kafka; internal interface IOffsetCommitter : IDisposable { void MarkAsProcessed(TopicPartitionOffset tpo); - - void CommitProcessedOffsets(); } } diff --git a/src/KafkaFlow/Consumers/IOffsetManager.cs b/src/KafkaFlow/Consumers/IOffsetManager.cs index ce98f834e..c3a4d5510 100644 --- a/src/KafkaFlow/Consumers/IOffsetManager.cs +++ b/src/KafkaFlow/Consumers/IOffsetManager.cs @@ -1,12 +1,11 @@ namespace KafkaFlow.Consumers { - using System; - using Confluent.Kafka; + using System.Threading.Tasks; internal interface IOffsetManager { - void MarkAsProcessed(TopicPartitionOffset offset); + void MarkAsProcessed(IConsumerContext offset); - void OnOffsetProcessed(TopicPartitionOffset offset, Action action); + Task WaitOffsetsCompletionAsync(); } } diff --git a/src/KafkaFlow/Consumers/NullOffsetCommitter.cs b/src/KafkaFlow/Consumers/NullOffsetCommitter.cs index 45f62eb4d..511590778 100644 --- a/src/KafkaFlow/Consumers/NullOffsetCommitter.cs +++ b/src/KafkaFlow/Consumers/NullOffsetCommitter.cs @@ -1,6 +1,6 @@ namespace KafkaFlow.Consumers { - using Confluent.Kafka; + using KafkaFlow; internal class NullOffsetCommitter : IOffsetCommitter { diff --git a/src/KafkaFlow/Consumers/OffsetCommitter.cs b/src/KafkaFlow/Consumers/OffsetCommitter.cs index 349c0a120..c51296881 100644 --- a/src/KafkaFlow/Consumers/OffsetCommitter.cs +++ b/src/KafkaFlow/Consumers/OffsetCommitter.cs @@ -5,7 +5,6 @@ namespace KafkaFlow.Consumers using System.Collections.Generic; using System.Linq; using System.Threading; - using Confluent.Kafka; internal class OffsetCommitter : IOffsetCommitter { @@ -15,14 +14,14 @@ internal class OffsetCommitter : IOffsetCommitter private readonly Timer commitTimer; private readonly IReadOnlyList statisticsTimers; - private ConcurrentDictionary<(string, int), TopicPartitionOffset> offsetsToCommit = new(); - private readonly object commitSyncRoot = new(); + private ConcurrentDictionary<(string, int), TopicPartitionOffset> offsetsToCommit = new(); + public OffsetCommitter( IConsumer consumer, IDependencyResolver resolver, - IReadOnlyList<(Action> handler, TimeSpan interval)> + IReadOnlyList<(Action> handler, TimeSpan interval)> pendingOffsetsHandlers, ILogHandler logHandler) { @@ -59,20 +58,22 @@ public void Dispose() public void MarkAsProcessed(TopicPartitionOffset tpo) { this.offsetsToCommit.AddOrUpdate( - (tpo.Topic, tpo.Partition.Value), + (tpo.Topic, tpo.Partition), tpo, (_, _) => tpo); } - public void CommitProcessedOffsets() => this.CommitHandler(); - private void PendingOffsetsHandler( IDependencyResolver resolver, - Action> handler) + Action> handler) { if (!this.offsetsToCommit.IsEmpty) { - handler(resolver, this.offsetsToCommit.Values); + handler( + resolver, + this.offsetsToCommit.Values.Select( + x => + new Confluent.Kafka.TopicPartitionOffset(x.Topic, x.Partition, x.Offset))); } } @@ -93,11 +94,14 @@ private void CommitHandler() ref this.offsetsToCommit, new ConcurrentDictionary<(string, int), TopicPartitionOffset>()); - this.consumer.Commit(offsets.Values); + this.consumer.Commit( + offsets.Values + .Select(x => new Confluent.Kafka.TopicPartitionOffset(x.Topic, x.Partition, x.Offset + 1)) + .ToList()); if (!this.consumer.Configuration.ManagementDisabled) { - this.LogOffsetsCommitted(offsets); + this.LogOffsetsCommitted(offsets.Values); } } catch (Exception e) @@ -114,22 +118,22 @@ private void CommitHandler() } } - private void LogOffsetsCommitted(ConcurrentDictionary<(string, int), TopicPartitionOffset> offsets) + private void LogOffsetsCommitted(IEnumerable offsets) { this.logHandler.Verbose( "Offsets committed", new { Offsets = offsets.GroupBy( - x => x.Key.Item1, + x => x.Topic, (topic, groupedOffsets) => new { Topic = topic, Partitions = groupedOffsets.Select( offset => new { - Partition = offset.Value.Partition.Value, - Offset = offset.Value.Offset.Value, + offset.Partition, + offset.Offset, }), }), }); @@ -139,7 +143,7 @@ private void RequeueFailedOffsets(IEnumerable offsets) { foreach (var tpo in offsets) { - this.offsetsToCommit.TryAdd((tpo.Topic, tpo.Partition.Value), tpo); + this.offsetsToCommit.TryAdd((tpo.Topic, tpo.Partition), tpo); } } } diff --git a/src/KafkaFlow/Consumers/OffsetManager.cs b/src/KafkaFlow/Consumers/OffsetManager.cs index e3b0f34a3..ac1b5d387 100644 --- a/src/KafkaFlow/Consumers/OffsetManager.cs +++ b/src/KafkaFlow/Consumers/OffsetManager.cs @@ -1,15 +1,12 @@ namespace KafkaFlow.Consumers { - using System; - using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; + using System.Threading.Tasks; using Confluent.Kafka; internal class OffsetManager : IOffsetManager { - private readonly ConcurrentDictionary> onProcessedActions = new(); - private readonly IOffsetCommitter committer; private readonly Dictionary<(string, int), PartitionOffsets> partitionsOffsets; @@ -23,57 +20,33 @@ public OffsetManager( _ => new PartitionOffsets()); } - public void MarkAsProcessed(TopicPartitionOffset offset) + public void MarkAsProcessed(IConsumerContext context) { - if (!this.partitionsOffsets.TryGetValue((offset.Topic, offset.Partition.Value), out var offsets)) + if (!this.partitionsOffsets.TryGetValue((context.Topic, context.Partition), out var offsets)) { return; } lock (offsets) { - if (offsets.ShouldCommit(offset.Offset.Value, out var lastProcessedOffset)) + if (offsets.ShouldCommit(context, out var lastProcessedContext)) { - this.committer.MarkAsProcessed( - new TopicPartitionOffset( - offset.TopicPartition, - new Offset(lastProcessedOffset + 1))); + this.committer.MarkAsProcessed(lastProcessedContext.TopicPartitionOffset); } } - - this.ExecuteOffsetActions(offset); } - public void OnOffsetProcessed(TopicPartitionOffset offset, Action action) - { - this.onProcessedActions - .SafeGetOrAdd(offset, _ => new()) - .Add(action); - } - - public void Enqueue(TopicPartitionOffset offset) + public void Enqueue(IConsumerContext context) { if (this.partitionsOffsets.TryGetValue( - (offset.Topic, offset.Partition.Value), + (context.Topic, context.Partition), out var offsets)) { - offsets.Enqueue(offset.Offset.Value); + offsets.Enqueue(context); } } - private void ExecuteOffsetActions(TopicPartitionOffset offset) - { - if (!this.onProcessedActions.TryGetValue(offset, out var actions)) - { - return; - } - - this.onProcessedActions.TryRemove(offset, out _); - - foreach (var action in actions) - { - action(); - } - } + public Task WaitOffsetsCompletionAsync() => + Task.WhenAll(this.partitionsOffsets.Select(x => x.Value.WaitContextsCompletionAsync())); } } diff --git a/src/KafkaFlow/Consumers/PartitionOffsets.cs b/src/KafkaFlow/Consumers/PartitionOffsets.cs index c2d031d87..f59a3c25d 100644 --- a/src/KafkaFlow/Consumers/PartitionOffsets.cs +++ b/src/KafkaFlow/Consumers/PartitionOffsets.cs @@ -3,47 +3,49 @@ namespace KafkaFlow.Consumers using System; using System.Collections.Generic; using System.Linq; - using System.Runtime.CompilerServices; + using System.Threading.Tasks; internal class PartitionOffsets { - private readonly SortedSet processedOffsets = new(); - private readonly LinkedList receivedOffsets = new(); + private readonly SortedDictionary processedContexts = new(); + private readonly LinkedList receivedContexts = new(); - public void Enqueue(long offset) + public void Enqueue(IConsumerContext context) { - lock (this.receivedOffsets) + lock (this.receivedContexts) { - this.receivedOffsets.AddLast(offset); + this.receivedContexts.AddLast(context); } } - public bool ShouldCommit(long offset, out long lastProcessedOffset) + public bool ShouldCommit(IConsumerContext context, out IConsumerContext lastProcessedContext) { - lastProcessedOffset = -1; - lock (this.receivedOffsets) + lastProcessedContext = null; + + lock (this.receivedContexts) { - if (!this.receivedOffsets.Any()) + if (!this.receivedContexts.Any()) { throw new InvalidOperationException( $"There is no offsets in the received queue. Call {nameof(this.Enqueue)} first"); } - if (offset != this.receivedOffsets.First.Value) + if (context.Offset != this.receivedContexts.First.Value.Offset) { - this.processedOffsets.Add(offset); + this.processedContexts.Add(context.Offset, context); return false; } do { - lastProcessedOffset = this.receivedOffsets.First.Value; - this.receivedOffsets.RemoveFirst(); - } - while (this.receivedOffsets.Count > 0 && this.processedOffsets.Remove(this.receivedOffsets.First.Value)); + lastProcessedContext = this.receivedContexts.First.Value; + this.receivedContexts.RemoveFirst(); + } while (this.receivedContexts.Count > 0 && this.processedContexts.Remove(this.receivedContexts.First.Value.Offset)); } return true; } + + public Task WaitContextsCompletionAsync() => Task.WhenAll(this.receivedContexts.Select(x => x.Completion)); } } diff --git a/src/KafkaFlow/Consumers/WorkerPoolStoppedSubject.cs b/src/KafkaFlow/Consumers/WorkerPoolStoppedSubject.cs new file mode 100644 index 000000000..1e9c8f4b5 --- /dev/null +++ b/src/KafkaFlow/Consumers/WorkerPoolStoppedSubject.cs @@ -0,0 +1,8 @@ +namespace KafkaFlow.Consumers +{ + using KafkaFlow.Core.Observer; + + internal class WorkerPoolStoppedSubject : Subject + { + } +} diff --git a/src/KafkaFlow/Core/Observer/ISubject.cs b/src/KafkaFlow/Core/Observer/ISubject.cs new file mode 100644 index 000000000..6ef85d132 --- /dev/null +++ b/src/KafkaFlow/Core/Observer/ISubject.cs @@ -0,0 +1,8 @@ +namespace KafkaFlow.Core.Observer +{ + internal interface ISubject + where T : ISubject + { + void Subscribe(ISubjectObserver observer); + } +} diff --git a/src/KafkaFlow/Core/Observer/ISubjectObserver.cs b/src/KafkaFlow/Core/Observer/ISubjectObserver.cs new file mode 100644 index 000000000..d5ae83925 --- /dev/null +++ b/src/KafkaFlow/Core/Observer/ISubjectObserver.cs @@ -0,0 +1,8 @@ +namespace KafkaFlow.Core.Observer +{ + internal interface ISubjectObserver + where T : ISubject + { + void OnNotification(); + } +} diff --git a/src/KafkaFlow/Core/Observer/Subject.cs b/src/KafkaFlow/Core/Observer/Subject.cs new file mode 100644 index 000000000..434f5b73a --- /dev/null +++ b/src/KafkaFlow/Core/Observer/Subject.cs @@ -0,0 +1,20 @@ +namespace KafkaFlow.Core.Observer +{ + using System.Collections.Generic; + + internal abstract class Subject : ISubject + where T : ISubject + { + private readonly List> observers = new(); + + public void Subscribe(ISubjectObserver observer) => this.observers.Add(observer); + + public void Notify() + { + foreach (var observer in this.observers) + { + observer.OnNotification(); + } + } + } +} diff --git a/src/KafkaFlow/IMiddlewareExecutor.cs b/src/KafkaFlow/IMiddlewareExecutor.cs index 3d03a4272..7f7580c04 100644 --- a/src/KafkaFlow/IMiddlewareExecutor.cs +++ b/src/KafkaFlow/IMiddlewareExecutor.cs @@ -6,7 +6,5 @@ namespace KafkaFlow internal interface IMiddlewareExecutor { Task Execute(IMessageContext context, Func nextOperation); - - void ClearWorkersMiddlewaresInstances(); } } diff --git a/src/KafkaFlow/MiddlewareExecutor.cs b/src/KafkaFlow/MiddlewareExecutor.cs index 7f8a5547a..e5288d819 100644 --- a/src/KafkaFlow/MiddlewareExecutor.cs +++ b/src/KafkaFlow/MiddlewareExecutor.cs @@ -5,8 +5,12 @@ namespace KafkaFlow using System.Linq; using System.Threading.Tasks; using KafkaFlow.Configuration; + using KafkaFlow.Consumers; + using KafkaFlow.Core.Observer; - internal class MiddlewareExecutor : IMiddlewareExecutor + internal class MiddlewareExecutor + : IMiddlewareExecutor, + ISubjectObserver { private readonly IReadOnlyList configurations; @@ -23,7 +27,10 @@ public Task Execute(IMessageContext context, Func nextOpe return this.ExecuteDefinition(0, context, nextOperation); } - public void ClearWorkersMiddlewaresInstances() => this.workersMiddlewares.Clear(); + void ISubjectObserver.OnNotification() + { + this.workersMiddlewares.Clear(); + } private static IMessageMiddleware CreateInstance( IDependencyResolver dependencyResolver, From 619cbee1e1033dec60a1f398d488e8db4778c645 Mon Sep 17 00:00:00 2001 From: Filipe Esch Date: Thu, 13 Jul 2023 11:14:41 +0100 Subject: [PATCH 06/20] feat: creates worker context and worker events --- .../{ => Consumers}/IWorker.cs | 12 +++ .../Consumers/WorkerStoppedSubject.cs | 19 +++++ .../Consumers/WorkerStoppingSubject.cs | 19 +++++ .../DependencyConfiguratorExtensions.cs | 29 +++++++ .../Observer/ISubject.cs | 17 ++++ .../Observer/ISubjectObserver.cs | 18 +++++ .../Observer/Subject.cs | 53 +++++++++++++ src/KafkaFlow.Abstractions/VoidObject.cs | 17 ++++ .../BatchConsumeExtensions.cs | 4 +- .../BatchConsumeMiddleware.cs | 78 +++++++++++++------ .../KafkaConfigurationBuilder.cs | 29 ++++--- src/KafkaFlow/ConsumerManagerFactory.cs | 10 --- src/KafkaFlow/Consumers/Consumer.cs | 15 +++- src/KafkaFlow/Consumers/ConsumerManager.cs | 29 +++---- src/KafkaFlow/Consumers/ConsumerWorker.cs | 26 ++++++- src/KafkaFlow/Consumers/ConsumerWorkerPool.cs | 38 +++++---- src/KafkaFlow/Consumers/IOffsetCommitter.cs | 8 +- src/KafkaFlow/Consumers/IOffsetManager.cs | 4 +- .../Consumers/IWorkerLifetimeContext.cs | 18 +++++ .../Consumers/NullOffsetCommitter.cs | 8 +- src/KafkaFlow/Consumers/NullOffsetManager.cs | 19 +++++ src/KafkaFlow/Consumers/OffsetCommitter.cs | 48 ++++++++---- src/KafkaFlow/Consumers/OffsetManager.cs | 7 +- src/KafkaFlow/Consumers/PartitionOffsets.cs | 5 +- .../Consumers/WorkerLifetimeContext.cs | 9 +++ .../Consumers/WorkerPoolStoppedSubject.cs | 8 +- src/KafkaFlow/Core/Observer/ISubject.cs | 8 -- .../Core/Observer/ISubjectObserver.cs | 8 -- src/KafkaFlow/Core/Observer/Subject.cs | 20 ----- src/KafkaFlow/MiddlewareExecutor.cs | 7 +- 30 files changed, 437 insertions(+), 153 deletions(-) rename src/KafkaFlow.Abstractions/{ => Consumers}/IWorker.cs (50%) create mode 100644 src/KafkaFlow.Abstractions/Consumers/WorkerStoppedSubject.cs create mode 100644 src/KafkaFlow.Abstractions/Consumers/WorkerStoppingSubject.cs create mode 100644 src/KafkaFlow.Abstractions/Observer/ISubject.cs create mode 100644 src/KafkaFlow.Abstractions/Observer/ISubjectObserver.cs create mode 100644 src/KafkaFlow.Abstractions/Observer/Subject.cs create mode 100644 src/KafkaFlow.Abstractions/VoidObject.cs create mode 100644 src/KafkaFlow/Consumers/IWorkerLifetimeContext.cs create mode 100644 src/KafkaFlow/Consumers/NullOffsetManager.cs create mode 100644 src/KafkaFlow/Consumers/WorkerLifetimeContext.cs delete mode 100644 src/KafkaFlow/Core/Observer/ISubject.cs delete mode 100644 src/KafkaFlow/Core/Observer/ISubjectObserver.cs delete mode 100644 src/KafkaFlow/Core/Observer/Subject.cs diff --git a/src/KafkaFlow.Abstractions/IWorker.cs b/src/KafkaFlow.Abstractions/Consumers/IWorker.cs similarity index 50% rename from src/KafkaFlow.Abstractions/IWorker.cs rename to src/KafkaFlow.Abstractions/Consumers/IWorker.cs index bc2e086d2..482218597 100644 --- a/src/KafkaFlow.Abstractions/IWorker.cs +++ b/src/KafkaFlow.Abstractions/Consumers/IWorker.cs @@ -1,6 +1,8 @@ namespace KafkaFlow { using System; + using KafkaFlow.Configuration; + using KafkaFlow.Observer; /// /// Represents the interface of a internal worker @@ -17,5 +19,15 @@ public interface IWorker /// /// to be executed void OnTaskCompleted(Action handler); + + /// + /// Gets the subject for worker stopping events where observers can subscribe to receive notifications. + /// + ISubject WorkerStopping { get; } + + /// + /// Gets the subject for worker stopped events where observers can subscribe to receive notifications. + /// + ISubject WorkerStopped { get; } } } diff --git a/src/KafkaFlow.Abstractions/Consumers/WorkerStoppedSubject.cs b/src/KafkaFlow.Abstractions/Consumers/WorkerStoppedSubject.cs new file mode 100644 index 000000000..4d92d1908 --- /dev/null +++ b/src/KafkaFlow.Abstractions/Consumers/WorkerStoppedSubject.cs @@ -0,0 +1,19 @@ +namespace KafkaFlow +{ + using KafkaFlow.Observer; + + /// + /// Represents a subject specific to worker stopped events where observers can subscribe to receive notifications. + /// + public class WorkerStoppedSubject : Subject + { + /// + /// Initializes a new instance of the class. + /// + /// The log handler object to be used + public WorkerStoppedSubject(ILogHandler logHandler) + : base(logHandler) + { + } + } +} diff --git a/src/KafkaFlow.Abstractions/Consumers/WorkerStoppingSubject.cs b/src/KafkaFlow.Abstractions/Consumers/WorkerStoppingSubject.cs new file mode 100644 index 000000000..816ce5f5f --- /dev/null +++ b/src/KafkaFlow.Abstractions/Consumers/WorkerStoppingSubject.cs @@ -0,0 +1,19 @@ +namespace KafkaFlow +{ + using KafkaFlow.Observer; + + /// + /// Represents a subject specific to worker stopping events where observers can subscribe to receive notifications. + /// + public class WorkerStoppingSubject : Subject + { + /// + /// Initializes a new instance of the class. + /// + /// The log handler object to be used + public WorkerStoppingSubject(ILogHandler logHandler) + : base(logHandler) + { + } + } +} diff --git a/src/KafkaFlow.Abstractions/Extensions/DependencyConfiguratorExtensions.cs b/src/KafkaFlow.Abstractions/Extensions/DependencyConfiguratorExtensions.cs index 8059be30c..f2021fed2 100644 --- a/src/KafkaFlow.Abstractions/Extensions/DependencyConfiguratorExtensions.cs +++ b/src/KafkaFlow.Abstractions/Extensions/DependencyConfiguratorExtensions.cs @@ -65,6 +65,35 @@ public static IDependencyConfigurator AddSingleton( InstanceLifetime.Singleton); } + /// + /// Registers a scoped type mapping where the returned instance will be given by the provided factory + /// + /// The object that this method was called on + /// Type that will be created + /// + public static IDependencyConfigurator AddScoped(this IDependencyConfigurator configurator) + where TService : class + { + return configurator.Add(InstanceLifetime.Scoped); + } + + /// + /// Registers a scoped type mapping where the returned instance will be given by the provided factory + /// + /// The object that this method was called on + /// A factory to create new instances of the service implementation + /// Type that will be created + /// + public static IDependencyConfigurator AddScoped( + this IDependencyConfigurator configurator, + Func factory) + { + return configurator.Add( + typeof(TService), + factory, + InstanceLifetime.Scoped); + } + /// /// Registers a transient type mapping /// diff --git a/src/KafkaFlow.Abstractions/Observer/ISubject.cs b/src/KafkaFlow.Abstractions/Observer/ISubject.cs new file mode 100644 index 000000000..669d24591 --- /dev/null +++ b/src/KafkaFlow.Abstractions/Observer/ISubject.cs @@ -0,0 +1,17 @@ +namespace KafkaFlow.Observer +{ + /// + /// Represents a subject in the observer design pattern that can be observed by observers. + /// + /// The type of the subject. + /// An argument type that will be passed to the observers + public interface ISubject + where TSubject : Subject + { + /// + /// Subscribes an observer to the subject. + /// + /// The observer to subscribe. + void Subscribe(ISubjectObserver observer); + } +} diff --git a/src/KafkaFlow.Abstractions/Observer/ISubjectObserver.cs b/src/KafkaFlow.Abstractions/Observer/ISubjectObserver.cs new file mode 100644 index 000000000..223cd863f --- /dev/null +++ b/src/KafkaFlow.Abstractions/Observer/ISubjectObserver.cs @@ -0,0 +1,18 @@ +namespace KafkaFlow.Observer +{ + using System.Threading.Tasks; + + /// + /// Represents an observer in the observer design pattern that can receive notifications from a subject. + /// + /// The type of the subject. + /// An argument type that will be passed to the observers + public interface ISubjectObserver + { + /// + /// Called when a notification is received from the subject. + /// + /// A task representing the asynchronous notification handling. + Task OnNotification(TSubject subject, TArg arg); + } +} diff --git a/src/KafkaFlow.Abstractions/Observer/Subject.cs b/src/KafkaFlow.Abstractions/Observer/Subject.cs new file mode 100644 index 000000000..31fb1bfe9 --- /dev/null +++ b/src/KafkaFlow.Abstractions/Observer/Subject.cs @@ -0,0 +1,53 @@ +namespace KafkaFlow.Observer +{ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + + /// + /// A generic implementation that should be extended to help the use of the notification system. + /// + /// The type of the subject. + /// An argument type that will be passed to the observers + public abstract class Subject : ISubject + where TSubject : Subject + { + private readonly ILogHandler logHandler; + private readonly List> observers = new(); + + /// + /// Initializes a new instance of the class. + /// + /// The log handler object to be used + protected Subject(ILogHandler logHandler) + { + this.logHandler = logHandler; + } + + /// + /// Subscribes an observer to the subject, allowing it to receive notifications. + /// + /// The observer to subscribe. + public void Subscribe(ISubjectObserver observer) => this.observers.Add(observer); + + /// + /// Notifies all subscribed observers asynchronously. + /// + /// The parameter passed by the client. + /// A task representing the asynchronous notification operation. + public async Task NotifyAsync(TArg arg) + { + foreach (var observer in this.observers) + { + try + { + await observer.OnNotification((TSubject)this, arg); + } + catch (Exception e) + { + this.logHandler.Error("Error notifying observer", e, new { Subject = this.GetType().Name }); + } + } + } + } +} diff --git a/src/KafkaFlow.Abstractions/VoidObject.cs b/src/KafkaFlow.Abstractions/VoidObject.cs new file mode 100644 index 000000000..d59912d4c --- /dev/null +++ b/src/KafkaFlow.Abstractions/VoidObject.cs @@ -0,0 +1,17 @@ +namespace KafkaFlow; + +/// +/// A type that represents an empty object that should be ignored +/// +public class VoidObject +{ + /// + /// Gets the unique instance value + /// + public static readonly VoidObject Value = new(); + + private VoidObject() + { + // Empty + } +} diff --git a/src/KafkaFlow.BatchConsume/BatchConsumeExtensions.cs b/src/KafkaFlow.BatchConsume/BatchConsumeExtensions.cs index 1bbe085da..932c66a51 100644 --- a/src/KafkaFlow.BatchConsume/BatchConsumeExtensions.cs +++ b/src/KafkaFlow.BatchConsume/BatchConsumeExtensions.cs @@ -3,6 +3,7 @@ namespace KafkaFlow.BatchConsume using System; using System.Collections.Generic; using KafkaFlow.Configuration; + using KafkaFlow.Consumers; /// /// no needed @@ -23,6 +24,7 @@ public static IConsumerMiddlewareConfigurationBuilder BatchConsume( { return builder.Add( resolver => new BatchConsumeMiddleware( + resolver.Resolve(), batchSize, batchTimeout, resolver.Resolve()), @@ -38,7 +40,7 @@ public static IReadOnlyCollection GetMessagesBatch(this IMessag { if (context is BatchConsumeMessageContext ctx) { - return (IReadOnlyCollection) ctx.Message.Value; + return (IReadOnlyCollection)ctx.Message.Value; } throw new InvalidOperationException($"This method can only be used on {nameof(BatchConsumeMessageContext)}"); diff --git a/src/KafkaFlow.BatchConsume/BatchConsumeMiddleware.cs b/src/KafkaFlow.BatchConsume/BatchConsumeMiddleware.cs index 53105d97a..1dfc23fa3 100644 --- a/src/KafkaFlow.BatchConsume/BatchConsumeMiddleware.cs +++ b/src/KafkaFlow.BatchConsume/BatchConsumeMiddleware.cs @@ -5,19 +5,28 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; - - internal class BatchConsumeMiddleware : IMessageMiddleware, IDisposable, IAsyncDisposable + using KafkaFlow.Configuration; + using KafkaFlow.Consumers; + using KafkaFlow.Observer; + + internal class BatchConsumeMiddleware + : IMessageMiddleware, + ISubjectObserver, + IDisposable { private readonly SemaphoreSlim dispatchSemaphore = new(1, 1); private readonly int batchSize; private readonly TimeSpan batchTimeout; private readonly ILogHandler logHandler; + private readonly IConsumerConfiguration consumerConfiguration; private readonly List batch; private CancellationTokenSource dispatchTokenSource; + private Task dispatchTask; public BatchConsumeMiddleware( + IWorkerLifetimeContext workerContext, int batchSize, TimeSpan batchTimeout, ILogHandler logHandler) @@ -26,6 +35,9 @@ public BatchConsumeMiddleware( this.batchTimeout = batchTimeout; this.logHandler = logHandler; this.batch = new(batchSize); + this.consumerConfiguration = workerContext.Consumer.Configuration; + + workerContext.Worker.WorkerStopped.Subscribe(this); } public async Task Invoke(IMessageContext context, MiddlewareDelegate next) @@ -35,49 +47,62 @@ public async Task Invoke(IMessageContext context, MiddlewareDelegate next) try { context.ConsumerContext.ShouldStoreOffset = false; - context.ConsumerContext.WorkerStopped.ThrowIfCancellationRequested(); this.batch.Add(context); if (this.batch.Count == 1) { - this.dispatchTokenSource = CancellationTokenSource.CreateLinkedTokenSource(context.ConsumerContext.WorkerStopped); - - this.dispatchTokenSource.CancelAfter(this.batchTimeout); - - this.dispatchTokenSource.Token.Register( - async _ => - { - this.dispatchTokenSource.Dispose(); - await this.DispatchAsync(context, next); - }, - null); - } - - if (this.batch.Count >= this.batchSize) - { - this.dispatchTokenSource.Cancel(); + this.ScheduleExecution(context, next); + return; } } finally { this.dispatchSemaphore.Release(); } + + if (this.batch.Count >= this.batchSize) + { + await this.TriggerDispatchAndWaitAsync(); + } } - public async ValueTask DisposeAsync() + public async Task OnNotification(WorkerStoppedSubject subject, VoidObject arg) => await this.TriggerDispatchAndWaitAsync(); + + public void Dispose() { - this.dispatchTokenSource.Dispose(); + this.dispatchTask?.Dispose(); + this.dispatchTokenSource?.Dispose(); + this.dispatchSemaphore.Dispose(); + } + private async Task TriggerDispatchAndWaitAsync() + { await this.dispatchSemaphore.WaitAsync(); - this.dispatchSemaphore.Dispose(); + this.dispatchTokenSource?.Cancel(); + this.dispatchSemaphore.Release(); + + await (this.dispatchTask ?? Task.CompletedTask); } - public void Dispose() => this.DisposeAsync().GetAwaiter().GetResult(); + private void ScheduleExecution(IMessageContext context, MiddlewareDelegate next) + { + this.dispatchTokenSource = CancellationTokenSource.CreateLinkedTokenSource(context.ConsumerContext.WorkerStopped); + + this.dispatchTask = Task + .Delay(this.batchTimeout, this.dispatchTokenSource.Token) + .ContinueWith( + _ => this.DispatchAsync(context, next), + CancellationToken.None); + } private async Task DispatchAsync(IMessageContext context, MiddlewareDelegate next) { await this.dispatchSemaphore.WaitAsync(); + + this.dispatchTokenSource.Dispose(); + this.dispatchTokenSource = null; + var localBatch = this.batch.ToList(); try @@ -113,9 +138,12 @@ private async Task DispatchAsync(IMessageContext context, MiddlewareDelegate nex this.dispatchSemaphore.Release(); } - foreach (var messageContext in localBatch) + if (this.consumerConfiguration.AutoStoreOffsets) { - messageContext.ConsumerContext.StoreOffset(); + foreach (var messageContext in localBatch) + { + messageContext.ConsumerContext.StoreOffset(); + } } } } diff --git a/src/KafkaFlow/Configuration/KafkaConfigurationBuilder.cs b/src/KafkaFlow/Configuration/KafkaConfigurationBuilder.cs index b1758da1e..73a022c0d 100644 --- a/src/KafkaFlow/Configuration/KafkaConfigurationBuilder.cs +++ b/src/KafkaFlow/Configuration/KafkaConfigurationBuilder.cs @@ -36,8 +36,9 @@ public KafkaConfiguration Build() foreach (var cluster in configuration.Clusters) { - this.dependencyConfigurator.AddSingleton(resolver => - new ClusterManager(resolver.Resolve(), cluster)); + this.dependencyConfigurator.AddSingleton( + resolver => + new ClusterManager(resolver.Resolve(), cluster)); } this.dependencyConfigurator @@ -46,19 +47,23 @@ public KafkaConfiguration Build() .AddSingleton(new ConsumerAccessor()) .AddSingleton(new ConsumerManagerFactory()) .AddSingleton() - .AddSingleton(r => - { - var logHandler = r.Resolve(); + .AddScoped() + .AddScoped(r => r.Resolve()) + .AddSingleton() + .AddSingleton( + r => + { + var logHandler = r.Resolve(); - var globalEvents = new GlobalEvents(logHandler); + var globalEvents = new GlobalEvents(logHandler); - foreach (var del in this.globalEventsConfigurators) - { - del.Invoke(globalEvents); - } + foreach (var del in this.globalEventsConfigurators) + { + del.Invoke(globalEvents); + } - return globalEvents; - }); + return globalEvents; + }); return configuration; } diff --git a/src/KafkaFlow/ConsumerManagerFactory.cs b/src/KafkaFlow/ConsumerManagerFactory.cs index 1ce0f1f21..cea52a8a7 100644 --- a/src/KafkaFlow/ConsumerManagerFactory.cs +++ b/src/KafkaFlow/ConsumerManagerFactory.cs @@ -11,19 +11,10 @@ public IConsumerManager Create(IConsumerConfiguration configuration, IDependency var consumer = configuration.CustomFactory(new Consumer(configuration, resolver, logHandler), resolver); - IOffsetCommitter offsetCommitter = configuration.NoStoreOffsets ? - new NullOffsetCommitter() : - new OffsetCommitter( - consumer, - resolver, - configuration.PendingOffsetsHandlers, - logHandler); - var middlewareExecutor = new MiddlewareExecutor(configuration.MiddlewaresConfigurations); var consumerWorkerPool = new ConsumerWorkerPool( consumer, - offsetCommitter, resolver, middlewareExecutor, configuration, @@ -40,7 +31,6 @@ public IConsumerManager Create(IConsumerConfiguration configuration, IDependency consumer, consumerWorkerPool, feeder, - offsetCommitter, resolver, logHandler); diff --git a/src/KafkaFlow/Consumers/Consumer.cs b/src/KafkaFlow/Consumers/Consumer.cs index ecf4a47fe..9c9ffb2ff 100644 --- a/src/KafkaFlow/Consumers/Consumer.cs +++ b/src/KafkaFlow/Consumers/Consumer.cs @@ -127,11 +127,20 @@ public IEnumerable GetTopicPartitionsLag() }); } - public void Commit(IReadOnlyCollection offsetsValues) + public void Commit(IReadOnlyCollection offsets) { - this.consumer.Commit(offsetsValues); + var validOffsets = offsets + .Where(x => x.Offset.Value >= 0) + .ToList(); + + if (!validOffsets.Any()) + { + return; + } + + this.consumer.Commit(validOffsets); - foreach (var offset in offsetsValues) + foreach (var offset in validOffsets) { this.currentPartitionsOffsets[offset.TopicPartition] = offset.Offset.Value; } diff --git a/src/KafkaFlow/Consumers/ConsumerManager.cs b/src/KafkaFlow/Consumers/ConsumerManager.cs index 84d8ad3b1..96a73e7b3 100644 --- a/src/KafkaFlow/Consumers/ConsumerManager.cs +++ b/src/KafkaFlow/Consumers/ConsumerManager.cs @@ -8,34 +8,26 @@ using Confluent.Kafka; using KafkaFlow.Configuration; - internal class ConsumerManager : IConsumerManager, IDisposable + internal class ConsumerManager : IConsumerManager { - private readonly IOffsetCommitter offsetCommitter; private readonly IDependencyResolver dependencyResolver; private readonly ILogHandler logHandler; - private readonly Timer evaluateWorkersCountTimer; + + private Timer evaluateWorkersCountTimer; public ConsumerManager( IConsumer consumer, IConsumerWorkerPool consumerWorkerPool, IWorkerPoolFeeder feeder, - IOffsetCommitter offsetCommitter, IDependencyResolver dependencyResolver, ILogHandler logHandler) { - this.offsetCommitter = offsetCommitter; this.dependencyResolver = dependencyResolver; this.logHandler = logHandler; this.Consumer = consumer; this.WorkerPool = consumerWorkerPool; this.Feeder = feeder; - this.evaluateWorkersCountTimer = new Timer( - state => _ = this.EvaluateWorkersCountAsync(), - null, - Timeout.Infinite, - Timeout.Infinite); - this.Consumer.OnPartitionsAssigned((_, _, partitions) => this.OnPartitionAssigned(partitions)); this.Consumer.OnPartitionsRevoked((_, _, partitions) => this.OnPartitionRevoked(partitions)); } @@ -50,7 +42,11 @@ public Task StartAsync() { this.Feeder.Start(); - this.StartEvaluateWorkerCountTimer(); + this.evaluateWorkersCountTimer = new Timer( + state => _ = this.EvaluateWorkersCountAsync(), + null, + this.Consumer.Configuration.WorkersCountEvaluationInterval, + this.Consumer.Configuration.WorkersCountEvaluationInterval); return Task.CompletedTask; } @@ -62,19 +58,18 @@ public async Task StopAsync() await this.Feeder.StopAsync().ConfigureAwait(false); await this.WorkerPool.StopAsync().ConfigureAwait(false); - this.offsetCommitter.Dispose(); - + this.evaluateWorkersCountTimer?.Dispose(); + this.evaluateWorkersCountTimer = null; this.Consumer.Dispose(); } public void Dispose() { - this.evaluateWorkersCountTimer.Dispose(); } - private void StopEvaluateWorkerCountTimer() => this.evaluateWorkersCountTimer.Change(Timeout.Infinite, Timeout.Infinite); + private void StopEvaluateWorkerCountTimer() => this.evaluateWorkersCountTimer?.Change(Timeout.Infinite, Timeout.Infinite); - private void StartEvaluateWorkerCountTimer() => this.evaluateWorkersCountTimer.Change( + private void StartEvaluateWorkerCountTimer() => this.evaluateWorkersCountTimer?.Change( this.Consumer.Configuration.WorkersCountEvaluationInterval, this.Consumer.Configuration.WorkersCountEvaluationInterval); diff --git a/src/KafkaFlow/Consumers/ConsumerWorker.cs b/src/KafkaFlow/Consumers/ConsumerWorker.cs index 78da342c6..afb8c6314 100644 --- a/src/KafkaFlow/Consumers/ConsumerWorker.cs +++ b/src/KafkaFlow/Consumers/ConsumerWorker.cs @@ -4,19 +4,22 @@ namespace KafkaFlow.Consumers using System.Threading; using System.Threading.Channels; using System.Threading.Tasks; + using KafkaFlow.Observer; internal class ConsumerWorker : IConsumerWorker { private readonly IConsumer consumer; - private readonly IDependencyResolver consumerDependencyResolver; + private readonly IDependencyResolverScope workerDependencyResolverScope; private readonly IMiddlewareExecutor middlewareExecutor; private readonly ILogHandler logHandler; private readonly GlobalEvents globalEvents; private readonly Channel messagesBuffer; + private readonly WorkerStoppingSubject workerStoppingSubject; + private readonly WorkerStoppedSubject workerStoppedSubject; + private CancellationTokenSource stopCancellationTokenSource; - private IDependencyResolverScope workerDependencyResolverScope; private Task backgroundTask; private Action onMessageFinishedHandler; @@ -29,11 +32,19 @@ public ConsumerWorker( { this.Id = workerId; this.consumer = consumer; - this.consumerDependencyResolver = consumerDependencyResolver; + this.workerDependencyResolverScope = consumerDependencyResolver.CreateScope(); this.middlewareExecutor = middlewareExecutor; this.logHandler = logHandler; this.messagesBuffer = Channel.CreateBounded(consumer.Configuration.BufferSize); this.globalEvents = consumerDependencyResolver.Resolve(); + + this.workerStoppingSubject = new(logHandler); + this.workerStoppedSubject = new(logHandler); + + var workerContext = this.workerDependencyResolverScope.Resolver.Resolve(); + + workerContext.Worker = this; + workerContext.Consumer = consumer; } public int Id { get; } @@ -42,6 +53,10 @@ public ConsumerWorker( public IDependencyResolver WorkerDependencyResolver => this.workerDependencyResolverScope.Resolver; + public ISubject WorkerStopping => this.workerStoppingSubject; + + public ISubject WorkerStopped => this.workerStoppedSubject; + public ValueTask EnqueueAsync( IMessageContext context, CancellationToken stopCancellationToken) @@ -52,7 +67,6 @@ public ValueTask EnqueueAsync( public Task StartAsync() { this.stopCancellationTokenSource = new CancellationTokenSource(); - this.workerDependencyResolverScope = this.consumerDependencyResolver.CreateScope(); this.backgroundTask = Task.Run( async () => @@ -86,6 +100,8 @@ public Task StartAsync() public async Task StopAsync() { + await this.workerStoppingSubject.NotifyAsync(VoidObject.Value); + this.messagesBuffer.Writer.TryComplete(); if (this.stopCancellationTokenSource.Token.CanBeCanceled) @@ -94,6 +110,8 @@ public async Task StopAsync() } await this.backgroundTask.ConfigureAwait(false); + + await this.workerStoppedSubject.NotifyAsync(VoidObject.Value); } public void Dispose() diff --git a/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs b/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs index 25fa208ba..59ec22cac 100644 --- a/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs +++ b/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs @@ -7,9 +7,9 @@ namespace KafkaFlow.Consumers using System.Threading.Tasks; using Confluent.Kafka; using KafkaFlow.Configuration; - using KafkaFlow.Core.Observer; + using KafkaFlow.Observer; - internal class ConsumerWorkerPool : IConsumerWorkerPool, IDisposable + internal class ConsumerWorkerPool : IConsumerWorkerPool { private readonly IConsumer consumer; private readonly IDependencyResolver consumerDependencyResolver; @@ -18,39 +18,50 @@ internal class ConsumerWorkerPool : IConsumerWorkerPool, IDisposable private readonly Factory distributionStrategyFactory; private readonly IOffsetCommitter offsetCommitter; - private readonly WorkerPoolStoppedSubject workerPoolStoppedSubject = new(); + private readonly WorkerPoolStoppedSubject workerPoolStoppedSubject; private TaskCompletionSource startedTaskSource = new(); private List workers = new(); private IDistributionStrategy distributionStrategy; - private OffsetManager offsetManager; + private IOffsetManager offsetManager; public ConsumerWorkerPool( IConsumer consumer, - IOffsetCommitter offsetCommitter, IDependencyResolver consumerDependencyResolver, IMiddlewareExecutor middlewareExecutor, IConsumerConfiguration consumerConfiguration, ILogHandler logHandler) { this.consumer = consumer; - this.offsetCommitter = offsetCommitter; this.consumerDependencyResolver = consumerDependencyResolver; this.middlewareExecutor = middlewareExecutor; this.logHandler = logHandler; this.distributionStrategyFactory = consumerConfiguration.DistributionStrategyFactory; + this.workerPoolStoppedSubject = new(logHandler); + + this.offsetCommitter = consumer.Configuration.NoStoreOffsets ? + new NullOffsetCommitter() : + new OffsetCommitter( + consumer, + consumerDependencyResolver, + consumer.Configuration.PendingOffsetsHandlers, + logHandler); } public int CurrentWorkersCount { get; private set; } - public ISubject WorkerPoolStopped => this.workerPoolStoppedSubject; + public ISubject WorkerPoolStopped => this.workerPoolStoppedSubject; public async Task StartAsync(IReadOnlyCollection partitions, int workersCount) { try { - this.offsetManager = new OffsetManager(this.offsetCommitter, partitions); + this.offsetManager = this.consumer.Configuration.NoStoreOffsets ? + new NullOffsetManager() : + new OffsetManager(this.offsetCommitter, partitions); + + await this.offsetCommitter.StartAsync(); this.CurrentWorkersCount = workersCount; @@ -103,13 +114,15 @@ public async Task StopAsync() await Task.WhenAll(currentWorkers.Select(x => x.StopAsync())).ConfigureAwait(false); - await this.offsetManager.WaitOffsetsCompletionAsync(); + await this.offsetManager.WaitContextsCompletionAsync(); currentWorkers.ForEach(worker => worker.Dispose()); this.offsetManager = null; - this.workerPoolStoppedSubject.Notify(); + await this.workerPoolStoppedSubject.NotifyAsync(VoidObject.Value); + + await this.offsetCommitter.StopAsync(); } public async Task EnqueueAsync(ConsumeResult message, CancellationToken stopCancellationToken) @@ -134,11 +147,6 @@ await worker this.offsetManager.Enqueue(context.ConsumerContext); } - public void Dispose() - { - this.offsetCommitter.Dispose(); - } - private MessageContext CreateMessageContext(ConsumeResult message, IConsumerWorker worker) { var messageDependencyScope = this.consumerDependencyResolver.CreateScope(); diff --git a/src/KafkaFlow/Consumers/IOffsetCommitter.cs b/src/KafkaFlow/Consumers/IOffsetCommitter.cs index 8130fda23..1cdbd06e5 100644 --- a/src/KafkaFlow/Consumers/IOffsetCommitter.cs +++ b/src/KafkaFlow/Consumers/IOffsetCommitter.cs @@ -1,9 +1,13 @@ namespace KafkaFlow.Consumers { - using System; + using System.Threading.Tasks; - internal interface IOffsetCommitter : IDisposable + internal interface IOffsetCommitter { void MarkAsProcessed(TopicPartitionOffset tpo); + + Task StartAsync(); + + Task StopAsync(); } } diff --git a/src/KafkaFlow/Consumers/IOffsetManager.cs b/src/KafkaFlow/Consumers/IOffsetManager.cs index c3a4d5510..aff5e27ab 100644 --- a/src/KafkaFlow/Consumers/IOffsetManager.cs +++ b/src/KafkaFlow/Consumers/IOffsetManager.cs @@ -4,8 +4,10 @@ namespace KafkaFlow.Consumers internal interface IOffsetManager { + void Enqueue(IConsumerContext context); + void MarkAsProcessed(IConsumerContext offset); - Task WaitOffsetsCompletionAsync(); + Task WaitContextsCompletionAsync(); } } diff --git a/src/KafkaFlow/Consumers/IWorkerLifetimeContext.cs b/src/KafkaFlow/Consumers/IWorkerLifetimeContext.cs new file mode 100644 index 000000000..73ea0391b --- /dev/null +++ b/src/KafkaFlow/Consumers/IWorkerLifetimeContext.cs @@ -0,0 +1,18 @@ +namespace KafkaFlow.Consumers +{ + /// + /// Provides access to the current consumer worker context. This interface only returns values when inside a middleware with Worker lifetime; otherwise, it will return null. + /// + public interface IWorkerLifetimeContext + { + /// + /// Gets the current worker in the context. + /// + IWorker Worker { get; } + + /// + /// Gets the current consumer in the context. + /// + IConsumer Consumer { get; } + } +} diff --git a/src/KafkaFlow/Consumers/NullOffsetCommitter.cs b/src/KafkaFlow/Consumers/NullOffsetCommitter.cs index 511590778..9d000c44b 100644 --- a/src/KafkaFlow/Consumers/NullOffsetCommitter.cs +++ b/src/KafkaFlow/Consumers/NullOffsetCommitter.cs @@ -1,5 +1,6 @@ namespace KafkaFlow.Consumers { + using System.Threading.Tasks; using KafkaFlow; internal class NullOffsetCommitter : IOffsetCommitter @@ -14,9 +15,8 @@ public void MarkAsProcessed(TopicPartitionOffset tpo) // Do nothing } - public void CommitProcessedOffsets() - { - // Do nothing - } + public Task StartAsync() => Task.CompletedTask; + + public Task StopAsync() => Task.CompletedTask; } } diff --git a/src/KafkaFlow/Consumers/NullOffsetManager.cs b/src/KafkaFlow/Consumers/NullOffsetManager.cs new file mode 100644 index 000000000..a9c4df3d3 --- /dev/null +++ b/src/KafkaFlow/Consumers/NullOffsetManager.cs @@ -0,0 +1,19 @@ +namespace KafkaFlow.Consumers +{ + using System.Threading.Tasks; + + internal class NullOffsetManager : IOffsetManager + { + public void Enqueue(IConsumerContext context) + { + // Do nothing + } + + public void MarkAsProcessed(IConsumerContext offset) + { + // Do nothing + } + + public Task WaitContextsCompletionAsync() => Task.CompletedTask; + } +} diff --git a/src/KafkaFlow/Consumers/OffsetCommitter.cs b/src/KafkaFlow/Consumers/OffsetCommitter.cs index c51296881..7c9d5eb70 100644 --- a/src/KafkaFlow/Consumers/OffsetCommitter.cs +++ b/src/KafkaFlow/Consumers/OffsetCommitter.cs @@ -5,17 +5,24 @@ namespace KafkaFlow.Consumers using System.Collections.Generic; using System.Linq; using System.Threading; + using System.Threading.Tasks; internal class OffsetCommitter : IOffsetCommitter { private readonly IConsumer consumer; - private readonly ILogHandler logHandler; + private readonly IDependencyResolver resolver; + + private readonly + IReadOnlyList<(Action> handler, TimeSpan interval)> + pendingOffsetsHandlers; - private readonly Timer commitTimer; - private readonly IReadOnlyList statisticsTimers; + private readonly ILogHandler logHandler; private readonly object commitSyncRoot = new(); + private Timer commitTimer; + private IReadOnlyList statisticsTimers; + private ConcurrentDictionary<(string, int), TopicPartitionOffset> offsetsToCommit = new(); public OffsetCommitter( @@ -26,25 +33,42 @@ public OffsetCommitter( ILogHandler logHandler) { this.consumer = consumer; + this.resolver = resolver; + this.pendingOffsetsHandlers = pendingOffsetsHandlers; this.logHandler = logHandler; + } + + public void FlushOffsets() => this.CommitHandler(); + + public void MarkAsProcessed(TopicPartitionOffset tpo) + { + this.offsetsToCommit.AddOrUpdate( + (tpo.Topic, tpo.Partition), + tpo, + (_, _) => tpo); + } + public Task StartAsync() + { this.commitTimer = new Timer( _ => this.CommitHandler(), null, - consumer.Configuration.AutoCommitInterval, - consumer.Configuration.AutoCommitInterval); + this.consumer.Configuration.AutoCommitInterval, + this.consumer.Configuration.AutoCommitInterval); - this.statisticsTimers = pendingOffsetsHandlers + this.statisticsTimers = this.pendingOffsetsHandlers .Select( s => new Timer( - _ => this.PendingOffsetsHandler(resolver, s.handler), + _ => this.PendingOffsetsHandler(this.resolver, s.handler), null, TimeSpan.Zero, s.interval)) .ToList(); + + return Task.CompletedTask; } - public void Dispose() + public Task StopAsync() { this.commitTimer.Dispose(); this.CommitHandler(); @@ -53,14 +77,8 @@ public void Dispose() { timer.Dispose(); } - } - public void MarkAsProcessed(TopicPartitionOffset tpo) - { - this.offsetsToCommit.AddOrUpdate( - (tpo.Topic, tpo.Partition), - tpo, - (_, _) => tpo); + return Task.CompletedTask; } private void PendingOffsetsHandler( diff --git a/src/KafkaFlow/Consumers/OffsetManager.cs b/src/KafkaFlow/Consumers/OffsetManager.cs index ac1b5d387..a4751fa9f 100644 --- a/src/KafkaFlow/Consumers/OffsetManager.cs +++ b/src/KafkaFlow/Consumers/OffsetManager.cs @@ -46,7 +46,10 @@ public void Enqueue(IConsumerContext context) } } - public Task WaitOffsetsCompletionAsync() => - Task.WhenAll(this.partitionsOffsets.Select(x => x.Value.WaitContextsCompletionAsync())); + public Task WaitContextsCompletionAsync() => + Task.WhenAll( + this.partitionsOffsets + .Select(x => x.Value.WaitContextsCompletionAsync()) + .ToList()); } } diff --git a/src/KafkaFlow/Consumers/PartitionOffsets.cs b/src/KafkaFlow/Consumers/PartitionOffsets.cs index f59a3c25d..9ab9dbae8 100644 --- a/src/KafkaFlow/Consumers/PartitionOffsets.cs +++ b/src/KafkaFlow/Consumers/PartitionOffsets.cs @@ -46,6 +46,9 @@ public bool ShouldCommit(IConsumerContext context, out IConsumerContext lastProc return true; } - public Task WaitContextsCompletionAsync() => Task.WhenAll(this.receivedContexts.Select(x => x.Completion)); + public Task WaitContextsCompletionAsync() => Task.WhenAll( + this.receivedContexts + .Select(x => x.Completion) + .ToList()); } } diff --git a/src/KafkaFlow/Consumers/WorkerLifetimeContext.cs b/src/KafkaFlow/Consumers/WorkerLifetimeContext.cs new file mode 100644 index 000000000..a31812b2d --- /dev/null +++ b/src/KafkaFlow/Consumers/WorkerLifetimeContext.cs @@ -0,0 +1,9 @@ +namespace KafkaFlow.Consumers +{ + internal class WorkerLifetimeContext : IWorkerLifetimeContext + { + public IWorker Worker { get; set; } + + public IConsumer Consumer { get; set; } + } +} diff --git a/src/KafkaFlow/Consumers/WorkerPoolStoppedSubject.cs b/src/KafkaFlow/Consumers/WorkerPoolStoppedSubject.cs index 1e9c8f4b5..0a3a5124c 100644 --- a/src/KafkaFlow/Consumers/WorkerPoolStoppedSubject.cs +++ b/src/KafkaFlow/Consumers/WorkerPoolStoppedSubject.cs @@ -1,8 +1,12 @@ namespace KafkaFlow.Consumers { - using KafkaFlow.Core.Observer; + using KafkaFlow.Observer; - internal class WorkerPoolStoppedSubject : Subject + internal class WorkerPoolStoppedSubject : Subject { + public WorkerPoolStoppedSubject(ILogHandler logHandler) + : base(logHandler) + { + } } } diff --git a/src/KafkaFlow/Core/Observer/ISubject.cs b/src/KafkaFlow/Core/Observer/ISubject.cs deleted file mode 100644 index 6ef85d132..000000000 --- a/src/KafkaFlow/Core/Observer/ISubject.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace KafkaFlow.Core.Observer -{ - internal interface ISubject - where T : ISubject - { - void Subscribe(ISubjectObserver observer); - } -} diff --git a/src/KafkaFlow/Core/Observer/ISubjectObserver.cs b/src/KafkaFlow/Core/Observer/ISubjectObserver.cs deleted file mode 100644 index d5ae83925..000000000 --- a/src/KafkaFlow/Core/Observer/ISubjectObserver.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace KafkaFlow.Core.Observer -{ - internal interface ISubjectObserver - where T : ISubject - { - void OnNotification(); - } -} diff --git a/src/KafkaFlow/Core/Observer/Subject.cs b/src/KafkaFlow/Core/Observer/Subject.cs deleted file mode 100644 index 434f5b73a..000000000 --- a/src/KafkaFlow/Core/Observer/Subject.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace KafkaFlow.Core.Observer -{ - using System.Collections.Generic; - - internal abstract class Subject : ISubject - where T : ISubject - { - private readonly List> observers = new(); - - public void Subscribe(ISubjectObserver observer) => this.observers.Add(observer); - - public void Notify() - { - foreach (var observer in this.observers) - { - observer.OnNotification(); - } - } - } -} diff --git a/src/KafkaFlow/MiddlewareExecutor.cs b/src/KafkaFlow/MiddlewareExecutor.cs index e5288d819..b759d6c37 100644 --- a/src/KafkaFlow/MiddlewareExecutor.cs +++ b/src/KafkaFlow/MiddlewareExecutor.cs @@ -6,11 +6,11 @@ namespace KafkaFlow using System.Threading.Tasks; using KafkaFlow.Configuration; using KafkaFlow.Consumers; - using KafkaFlow.Core.Observer; + using KafkaFlow.Observer; internal class MiddlewareExecutor : IMiddlewareExecutor, - ISubjectObserver + ISubjectObserver { private readonly IReadOnlyList configurations; @@ -27,9 +27,10 @@ public Task Execute(IMessageContext context, Func nextOpe return this.ExecuteDefinition(0, context, nextOperation); } - void ISubjectObserver.OnNotification() + public Task OnNotification(WorkerPoolStoppedSubject subject, VoidObject arg) { this.workersMiddlewares.Clear(); + return Task.CompletedTask; } private static IMessageMiddleware CreateInstance( From c15b0b2bbb75c490aa9813efef0e96be84fa05c7 Mon Sep 17 00:00:00 2001 From: Filipe Esch Date: Wed, 13 Sep 2023 11:23:33 +0100 Subject: [PATCH 07/20] feat: creates the ConsumerLagWorkerBalancer --- .../ConsumerLagWorkerBalancer.cs | 165 ++++++++++++++++++ .../ConfigurationBuilderExtensions.cs | 64 ++++++- 2 files changed, 224 insertions(+), 5 deletions(-) create mode 100644 src/KafkaFlow/Consumers/WorkersBalancers/ConsumerLagWorkerBalancer.cs diff --git a/src/KafkaFlow/Consumers/WorkersBalancers/ConsumerLagWorkerBalancer.cs b/src/KafkaFlow/Consumers/WorkersBalancers/ConsumerLagWorkerBalancer.cs new file mode 100644 index 000000000..911d4fb7a --- /dev/null +++ b/src/KafkaFlow/Consumers/WorkersBalancers/ConsumerLagWorkerBalancer.cs @@ -0,0 +1,165 @@ +namespace KafkaFlow.Consumers.WorkersBalancers +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + using KafkaFlow.Clusters; + using KafkaFlow.Configuration; + + /// + /// Represents a balancer that dynamically calculates the number of workers for a consumer based on the current lag. + /// The calculation employs a simple rule of three considering the total lag across all application instances, + /// the lag specific to the current instance, and a predetermined total number of consumer workers. + /// + internal class ConsumerLagWorkerBalancer + { + private const int DefaultWorkersCount = 1; + + private readonly IClusterManager clusterManager; + private readonly IConsumerAccessor consumerAccessor; + private readonly ILogHandler logHandler; + private readonly int totalConsumerWorkers; + private readonly int minInstanceWorkers; + private readonly int maxInstanceWorkers; + + public ConsumerLagWorkerBalancer( + IClusterManager clusterManager, + IConsumerAccessor consumerAccessor, + ILogHandler logHandler, + int totalConsumerWorkers, + int minInstanceWorkers, + int maxInstanceWorkers) + { + this.clusterManager = clusterManager; + this.consumerAccessor = consumerAccessor; + this.logHandler = logHandler; + this.totalConsumerWorkers = totalConsumerWorkers; + this.minInstanceWorkers = minInstanceWorkers; + this.maxInstanceWorkers = maxInstanceWorkers; + } + + public async Task GetWorkersCountAsync(WorkersCountContext context) + { + var workers = await this.CalculateAsync(context); + + this.logHandler.Info( + "New workers count calculated", + new + { + Workers = workers, + Consumer = context.ConsumerName, + }); + + return workers; + } + + private static long CalculateMyPartitionsLag( + WorkersCountContext context, + IEnumerable<(string Topic, int Partition, long Lag)> partitionsLag) + { + return partitionsLag + .Where( + partitionLag => context.AssignedTopicsPartitions + .Any( + topic => topic.Name == partitionLag.Topic && + topic.Partitions.Any(p => p == partitionLag.Partition))) + .Sum(partitionLag => partitionLag.Lag); + } + + private static IReadOnlyList<(string Topic, int Partition, long Lag)> CalculatePartitionsLag( + IEnumerable<(string Topic, int Partition, long Offset)> lastOffsets, + IEnumerable currentPartitionsOffset) + { + return lastOffsets + .Select( + last => + { + var currentOffset = currentPartitionsOffset + .Where(current => current.Topic == last.Topic && current.Partition == last.Partition) + .Select(current => current.Offset) + .FirstOrDefault(); + + var lastOffset = Math.Max(0, last.Offset); + currentOffset = Math.Max(0, currentOffset); + + return (last.Topic, last.Partition, lastOffset - currentOffset); + }) + .ToList(); + } + + private async Task CalculateAsync(WorkersCountContext context) + { + try + { + if (!context.AssignedTopicsPartitions.Any()) + { + return DefaultWorkersCount; + } + + var topicsMetadata = await this.GetTopicsMetadataAsync(context); + + var lastOffsets = this.GetPartitionsLastOffset(context.ConsumerName, topicsMetadata); + + var partitionsOffset = await this.clusterManager.GetConsumerGroupOffsetsAsync( + context.ConsumerGroupId, + context.AssignedTopicsPartitions.Select(t => t.Name)); + + var partitionsLag = CalculatePartitionsLag(lastOffsets, partitionsOffset); + var instanceLag = CalculateMyPartitionsLag(context, partitionsLag); + + decimal totalConsumerLag = partitionsLag.Sum(p => p.Lag); + + var ratio = instanceLag / Math.Max(1, totalConsumerLag); + + var workers = (int)Math.Round(this.totalConsumerWorkers * ratio); + + workers = Math.Min(workers, this.maxInstanceWorkers); + workers = Math.Max(workers, this.minInstanceWorkers); + + return workers; + } + catch (Exception e) + { + this.logHandler.Error( + "Error calculating new workers count, using 1 as fallback", + e, + new + { + context.ConsumerName, + }); + + return DefaultWorkersCount; + } + } + + private IEnumerable<(string TopicName, int Partition, long Offset)> GetPartitionsLastOffset( + string consumerName, + IEnumerable<(string Name, TopicMetadata Metadata)> topicsMetadata) + { + var consumer = this.consumerAccessor[consumerName]; + + return topicsMetadata.SelectMany( + topic => topic.Metadata.Partitions.Select( + partition => ( + topic.Name, + partition.Id, + consumer + .QueryWatermarkOffsets(new(topic.Name, new(partition.Id)), TimeSpan.FromSeconds(30)) + .High + .Value))); + } + + private async Task> GetTopicsMetadataAsync(WorkersCountContext context) + { + var topicsMetadata = new List<(string Name, TopicMetadata Metadata)>(context.AssignedTopicsPartitions.Count); + + foreach (var topic in context.AssignedTopicsPartitions) + { + topicsMetadata.Add((topic.Name, await this.clusterManager.GetTopicMetadataAsync(topic.Name))); + } + + return topicsMetadata; + } + } +} diff --git a/src/KafkaFlow/Extensions/ConfigurationBuilderExtensions.cs b/src/KafkaFlow/Extensions/ConfigurationBuilderExtensions.cs index 3048627ca..a5af5c77a 100644 --- a/src/KafkaFlow/Extensions/ConfigurationBuilderExtensions.cs +++ b/src/KafkaFlow/Extensions/ConfigurationBuilderExtensions.cs @@ -3,7 +3,10 @@ namespace KafkaFlow using System; using System.Collections.Generic; using Confluent.Kafka; + using KafkaFlow.Clusters; using KafkaFlow.Configuration; + using KafkaFlow.Consumers; + using KafkaFlow.Consumers.WorkersBalancers; /// /// Provides extension methods over and @@ -18,7 +21,7 @@ public static class ConfigurationBuilderExtensions /// public static IProducerConfigurationBuilder WithProducerConfig(this IProducerConfigurationBuilder builder, ProducerConfig config) { - return ((ProducerConfigurationBuilder) builder).WithProducerConfig(config); + return ((ProducerConfigurationBuilder)builder).WithProducerConfig(config); } /// @@ -40,7 +43,7 @@ public static IProducerConfigurationBuilder WithCompression( CompressionType compressionType, int? compressionLevel = -1) { - return ((ProducerConfigurationBuilder) builder).WithCompression(compressionType, compressionLevel); + return ((ProducerConfigurationBuilder)builder).WithCompression(compressionType, compressionLevel); } /// @@ -51,7 +54,7 @@ public static IProducerConfigurationBuilder WithCompression( /// public static IConsumerConfigurationBuilder WithConsumerConfig(this IConsumerConfigurationBuilder builder, ConsumerConfig config) { - return ((ConsumerConfigurationBuilder) builder).WithConsumerConfig(config); + return ((ConsumerConfigurationBuilder)builder).WithConsumerConfig(config); } /// @@ -105,7 +108,7 @@ public static IConsumerConfigurationBuilder WithCustomFactory( this IConsumerConfigurationBuilder builder, ConsumerCustomFactory decoratorFactory) { - return ((ConsumerConfigurationBuilder) builder).WithCustomFactory(decoratorFactory); + return ((ConsumerConfigurationBuilder)builder).WithCustomFactory(decoratorFactory); } /// @@ -118,7 +121,58 @@ public static IProducerConfigurationBuilder WithCustomFactory( this IProducerConfigurationBuilder builder, ProducerCustomFactory decoratorFactory) { - return ((ProducerConfigurationBuilder) builder).WithCustomFactory(decoratorFactory); + return ((ProducerConfigurationBuilder)builder).WithCustomFactory(decoratorFactory); + } + + /// + /// Configures the consumer to use the consumer's lag as a metric for dynamically calculating the number of workers for each application instance. + /// + /// The consumer's configuration builder. + /// The total number of workers to be distributed across all application instances. The sum of workers across all instances will approximate this number. + /// The minimum number of workers for each application instance. + /// The maximum number of workers for each application instance. + /// The interval at which the number of workers will be recalculated based on consumer's lag. + /// + public static IConsumerConfigurationBuilder WithConsumerLagWorkerBalancer( + this IConsumerConfigurationBuilder builder, + int totalWorkers, + int minInstanceWorkers, + int maxInstanceWorkers, + TimeSpan evaluationInterval) + { + return builder.WithWorkersCount( + (context, resolver) => + new ConsumerLagWorkerBalancer( + resolver.Resolve(), + resolver.Resolve(), + resolver.Resolve(), + totalWorkers, + minInstanceWorkers, + maxInstanceWorkers) + .GetWorkersCountAsync(context), + evaluationInterval); + } + + /// + /// Configures the consumer to use the consumer's lag as a metric for dynamically calculating the number of workers for each application instance. + /// The number of workers will be re-evaluated every 5 minutes. + /// + /// The consumer's configuration builder. + /// The total number of workers to be distributed across all application instances. The sum of workers across all instances will approximate this number. + /// The minimum number of workers for each application instance. + /// The maximum number of workers for each application instance. + /// + public static IConsumerConfigurationBuilder WithConsumerLagWorkerBalancer( + this IConsumerConfigurationBuilder builder, + int totalWorkers, + int minInstanceWorkers, + int maxInstanceWorkers) + { + return builder.WithConsumerLagWorkerBalancer( + totalWorkers, + minInstanceWorkers, + maxInstanceWorkers, + TimeSpan.FromMinutes(5)); } } } From 0eb5c6c178ccdcf45029e929e69bf2e7957def90 Mon Sep 17 00:00:00 2001 From: Filipe Esch Date: Wed, 13 Sep 2023 15:26:59 +0100 Subject: [PATCH 08/20] refactor: rename StoreOffset to Complete --- .../PauseConsumerOnExceptionMiddleware.cs | 2 +- .../IConsumerConfigurationBuilder.cs | 11 +- .../Configuration/WorkersCountContext.cs | 12 ++ .../IConsumerContext.cs | 31 ++-- src/KafkaFlow.Abstractions/IMessageContext.cs | 10 -- .../MiddlewareLifetime.cs | 7 - src/KafkaFlow.Admin/MemoryTelemetryStorage.cs | 4 +- .../BatchConsumeExtensions.cs | 2 +- .../BatchConsumeMessageContext.cs | 4 +- .../BatchConsumeMiddleware.cs | 23 +-- .../KafkaFlow.BatchConsume.csproj | 3 - .../GzipMessageCompressor.cs | 1 - .../ConfigurationBuilderExtensions.cs | 4 - .../BatchConsumeMiddlewareTests.cs | 48 ++++- .../ConsumerConfigurationBuilderTests.cs | 10 +- .../Consumer/ConsumerManagerTests.cs | 2 +- .../ConsumerContextTests.cs | 47 ----- src/KafkaFlow.UnitTests/ExtensionHelpers.cs | 14 ++ .../MemoryTelemetryStorageTests.cs | 6 +- .../OffsetCommitterTests.cs | 94 +++++----- src/KafkaFlow.UnitTests/OffsetManagerTests.cs | 54 ++++-- .../PartitionOffsetsTests.cs | 169 ++++++++---------- .../Configuration/ConsumerConfiguration.cs | 14 +- .../ConsumerConfigurationBuilder.cs | 19 +- .../Configuration/IConsumerConfiguration.cs | 9 +- .../KafkaConfigurationBuilder.cs | 4 +- .../MiddlewareConfigurationBuilder.cs | 2 +- .../PendingOffsetsStatisticsHandler.cs | 33 ++++ src/KafkaFlow/ConsumerManagerFactory.cs | 12 +- src/KafkaFlow/Consumers/Consumer.cs | 5 + src/KafkaFlow/Consumers/ConsumerContext.cs | 11 +- src/KafkaFlow/Consumers/ConsumerManager.cs | 4 - ...ontext.cs => ConsumerMiddlewareContext.cs} | 2 +- src/KafkaFlow/Consumers/ConsumerWorker.cs | 20 ++- src/KafkaFlow/Consumers/ConsumerWorkerPool.cs | 3 +- ...ntext.cs => IConsumerMiddlewareContext.cs} | 5 +- src/KafkaFlow/Consumers/IOffsetCommitter.cs | 4 + .../Consumers/NullOffsetCommitter.cs | 4 + src/KafkaFlow/Consumers/OffsetCommitter.cs | 28 ++- src/KafkaFlow/Consumers/OffsetManager.cs | 4 +- src/KafkaFlow/Consumers/PartitionOffsets.cs | 8 +- src/KafkaFlow/KafkaBus.cs | 6 +- src/KafkaFlow/MessageContext.cs | 2 - 43 files changed, 399 insertions(+), 358 deletions(-) delete mode 100644 src/KafkaFlow.UnitTests/ConsumerContextTests.cs create mode 100644 src/KafkaFlow.UnitTests/ExtensionHelpers.cs create mode 100644 src/KafkaFlow/Configuration/PendingOffsetsStatisticsHandler.cs rename src/KafkaFlow/Consumers/{WorkerLifetimeContext.cs => ConsumerMiddlewareContext.cs} (65%) rename src/KafkaFlow/Consumers/{IWorkerLifetimeContext.cs => IConsumerMiddlewareContext.cs} (58%) diff --git a/samples/KafkaFlow.Sample.PauseConsumerOnError/PauseConsumerOnExceptionMiddleware.cs b/samples/KafkaFlow.Sample.PauseConsumerOnError/PauseConsumerOnExceptionMiddleware.cs index d78811488..b45b0ec4b 100644 --- a/samples/KafkaFlow.Sample.PauseConsumerOnError/PauseConsumerOnExceptionMiddleware.cs +++ b/samples/KafkaFlow.Sample.PauseConsumerOnError/PauseConsumerOnExceptionMiddleware.cs @@ -21,7 +21,7 @@ public async Task Invoke(IMessageContext context, MiddlewareDelegate next) } catch (Exception exception) { - context.ConsumerContext.ShouldStoreOffset = false; + context.ConsumerContext.AutoMessageCompletion = false; this.logHandler.Error("Error handling message", exception, new { diff --git a/src/KafkaFlow.Abstractions/Configuration/IConsumerConfigurationBuilder.cs b/src/KafkaFlow.Abstractions/Configuration/IConsumerConfigurationBuilder.cs index 472ee87ee..830eb0555 100644 --- a/src/KafkaFlow.Abstractions/Configuration/IConsumerConfigurationBuilder.cs +++ b/src/KafkaFlow.Abstractions/Configuration/IConsumerConfigurationBuilder.cs @@ -152,16 +152,11 @@ IConsumerConfigurationBuilder WithWorkDistributionStrategy() where T : class, IDistributionStrategy; /// - /// Offsets will be stored after the execution of the handler and middlewares automatically, this is the default behaviour + /// Configures the consumer for manual message completion. + /// The client should call the to mark the message processing as finished /// /// - IConsumerConfigurationBuilder WithAutoStoreOffsets(); - - /// - /// The client should call the - /// - /// - IConsumerConfigurationBuilder WithManualStoreOffsets(); + IConsumerConfigurationBuilder WithManualMessageCompletion(); /// /// No offsets will be stored on Kafka diff --git a/src/KafkaFlow.Abstractions/Configuration/WorkersCountContext.cs b/src/KafkaFlow.Abstractions/Configuration/WorkersCountContext.cs index 1a476f02f..a54a4b82f 100644 --- a/src/KafkaFlow.Abstractions/Configuration/WorkersCountContext.cs +++ b/src/KafkaFlow.Abstractions/Configuration/WorkersCountContext.cs @@ -7,6 +7,12 @@ namespace KafkaFlow.Configuration /// public class WorkersCountContext { + /// + /// Initializes a new instance of the class. + /// + /// The consumer's name + /// The consumer's group id + /// The consumer's assigned partition public WorkersCountContext( string consumerName, string consumerGroupId, @@ -17,8 +23,14 @@ public WorkersCountContext( this.AssignedTopicsPartitions = assignedTopicsPartitions; } + /// + /// Gets the consumer's name + /// public string ConsumerName { get; } + /// + /// Gets the consumer's group id + /// public string ConsumerGroupId { get; } /// diff --git a/src/KafkaFlow.Abstractions/IConsumerContext.cs b/src/KafkaFlow.Abstractions/IConsumerContext.cs index 44b57e47c..b185d9c2b 100644 --- a/src/KafkaFlow.Abstractions/IConsumerContext.cs +++ b/src/KafkaFlow.Abstractions/IConsumerContext.cs @@ -55,7 +55,12 @@ public interface IConsumerContext DateTime MessageTimestamp { get; } /// - /// Gets or sets a value indicating whether if the framework should store the current offset in the end when auto store offset is used + /// Gets or sets a value indicating whether if the framework should invoke the method after the message has been processed + /// + bool AutoMessageCompletion { get; set; } + + /// + /// Gets or sets a value indicating whether if the message offset must be stored when the message is marked as completed /// bool ShouldStoreOffset { get; set; } @@ -74,12 +79,19 @@ public interface IConsumerContext IDependencyResolver WorkerDependencyResolver { get; } /// - /// Stores the message offset to eventually be committed. After this call, the framework considers the - /// message processing as finished and releases resources associated with the message. - /// By default, this method is automatically called when the message processing ends, unless - /// the consumer is set to manual store offsets or the flag is set to false. + /// Gets a Task that completes when the method is invoked, + /// indicating the end of message processing. This allows async operations + /// to wait for the message to be fully processed and its offset stored. /// - void StoreOffset(); + Task Completion { get; } + + /// + /// Signals the completion of message processing and stores the message offset to eventually be committed. + /// After this call, the framework marks the message processing as finished and releases resources associated with the message. + /// By default, this method is automatically invoked when message processing concludes, unless + /// the consumer is configured for manual message completion or the flag is set to false. + /// + void Complete(); /// /// Get offset watermark data @@ -96,12 +108,5 @@ public interface IConsumerContext /// Resume Kafka's message fetch /// void Resume(); - - /// - /// Gets a Task that completes when the method is invoked, - /// indicating the end of message processing. This allows async operations - /// to wait for the message to be fully processed and its offset stored. - /// - Task Completion { get; } } } diff --git a/src/KafkaFlow.Abstractions/IMessageContext.cs b/src/KafkaFlow.Abstractions/IMessageContext.cs index 5661bb44b..f34ec0fb1 100644 --- a/src/KafkaFlow.Abstractions/IMessageContext.cs +++ b/src/KafkaFlow.Abstractions/IMessageContext.cs @@ -1,6 +1,5 @@ namespace KafkaFlow { - using System; using System.Collections.Generic; /// @@ -40,7 +39,6 @@ public interface IMessageContext /// IDependencyResolver DependencyResolver { get; } - /// /// Creates a new with the new message /// @@ -48,13 +46,5 @@ public interface IMessageContext /// The new message value /// A new message context containing the new values IMessageContext SetMessage(object key, object value); - - /// - /// Deprecated - /// - /// key - /// - [Obsolete("This method should no longer be used, use the " + nameof(SetMessage) + "() instead.", true)] - IMessageContext TransformMessage(object message); } } diff --git a/src/KafkaFlow.Abstractions/MiddlewareLifetime.cs b/src/KafkaFlow.Abstractions/MiddlewareLifetime.cs index e17fa8de3..4263ac7c5 100644 --- a/src/KafkaFlow.Abstractions/MiddlewareLifetime.cs +++ b/src/KafkaFlow.Abstractions/MiddlewareLifetime.cs @@ -13,13 +13,6 @@ public enum MiddlewareLifetime /// Singleton, - /// - /// Obsolete. Please use Message instead. Indicates a new middleware instance is instantiated for each message scope. - /// This instance will be disposed when the message scope ends. - /// - [Obsolete("Use Message lifetime instead")] - Scoped, - /// /// Indicates a new middleware instance is instantiated for each individual message scope, ensuring isolated processing. /// This instance will be disposed when the message scope ends. diff --git a/src/KafkaFlow.Admin/MemoryTelemetryStorage.cs b/src/KafkaFlow.Admin/MemoryTelemetryStorage.cs index 5d7a06257..081856304 100644 --- a/src/KafkaFlow.Admin/MemoryTelemetryStorage.cs +++ b/src/KafkaFlow.Admin/MemoryTelemetryStorage.cs @@ -52,7 +52,7 @@ private void TryCleanItems() return; } - this.lastCleanDate = this.dateTimeProvider.Now; + this.lastCleanDate = this.dateTimeProvider.UtcNow; this.CleanExpiredItems(); } @@ -70,6 +70,6 @@ private void CleanExpiredItems() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private bool NeedsCleaning() => this.dateTimeProvider.Now - this.lastCleanDate > this.cleanRunInterval; + private bool NeedsCleaning() => this.dateTimeProvider.UtcNow - this.lastCleanDate > this.cleanRunInterval; } } diff --git a/src/KafkaFlow.BatchConsume/BatchConsumeExtensions.cs b/src/KafkaFlow.BatchConsume/BatchConsumeExtensions.cs index 932c66a51..9e3326156 100644 --- a/src/KafkaFlow.BatchConsume/BatchConsumeExtensions.cs +++ b/src/KafkaFlow.BatchConsume/BatchConsumeExtensions.cs @@ -24,7 +24,7 @@ public static IConsumerMiddlewareConfigurationBuilder BatchConsume( { return builder.Add( resolver => new BatchConsumeMiddleware( - resolver.Resolve(), + resolver.Resolve(), batchSize, batchTimeout, resolver.Resolve()), diff --git a/src/KafkaFlow.BatchConsume/BatchConsumeMessageContext.cs b/src/KafkaFlow.BatchConsume/BatchConsumeMessageContext.cs index 86492a4f6..9bc92fe33 100644 --- a/src/KafkaFlow.BatchConsume/BatchConsumeMessageContext.cs +++ b/src/KafkaFlow.BatchConsume/BatchConsumeMessageContext.cs @@ -30,9 +30,7 @@ public BatchConsumeMessageContext( public IDictionary Items { get; } public IMessageContext SetMessage(object key, object value) => - throw new NotSupportedException($"{nameof(BatchConsumeMessageContext)} does not allow change the message"); - - public IMessageContext TransformMessage(object message) => throw new NotImplementedException(); + throw new NotSupportedException($"{nameof(BatchConsumeMessageContext)} does not allow to change the message"); public void Dispose() => this.batchDependencyScope.Dispose(); } diff --git a/src/KafkaFlow.BatchConsume/BatchConsumeMiddleware.cs b/src/KafkaFlow.BatchConsume/BatchConsumeMiddleware.cs index 1dfc23fa3..70cc87530 100644 --- a/src/KafkaFlow.BatchConsume/BatchConsumeMiddleware.cs +++ b/src/KafkaFlow.BatchConsume/BatchConsumeMiddleware.cs @@ -26,7 +26,7 @@ internal class BatchConsumeMiddleware private Task dispatchTask; public BatchConsumeMiddleware( - IWorkerLifetimeContext workerContext, + IConsumerMiddlewareContext middlewareContext, int batchSize, TimeSpan batchTimeout, ILogHandler logHandler) @@ -35,9 +35,9 @@ public BatchConsumeMiddleware( this.batchTimeout = batchTimeout; this.logHandler = logHandler; this.batch = new(batchSize); - this.consumerConfiguration = workerContext.Consumer.Configuration; + this.consumerConfiguration = middlewareContext.Consumer.Configuration; - workerContext.Worker.WorkerStopped.Subscribe(this); + middlewareContext.Worker.WorkerStopped.Subscribe(this); } public async Task Invoke(IMessageContext context, MiddlewareDelegate next) @@ -46,7 +46,7 @@ public async Task Invoke(IMessageContext context, MiddlewareDelegate next) try { - context.ConsumerContext.ShouldStoreOffset = false; + context.ConsumerContext.AutoMessageCompletion = false; this.batch.Add(context); @@ -118,7 +118,10 @@ private async Task DispatchAsync(IMessageContext context, MiddlewareDelegate nex } catch (OperationCanceledException) when (context.ConsumerContext.WorkerStopped.IsCancellationRequested) { - return; + foreach (var messageContext in localBatch) + { + messageContext.ConsumerContext.ShouldStoreOffset = false; + } } catch (Exception ex) { @@ -136,13 +139,13 @@ private async Task DispatchAsync(IMessageContext context, MiddlewareDelegate nex { this.batch.Clear(); this.dispatchSemaphore.Release(); - } - if (this.consumerConfiguration.AutoStoreOffsets) - { - foreach (var messageContext in localBatch) + if (this.consumerConfiguration.AutoMessageCompletion) { - messageContext.ConsumerContext.StoreOffset(); + foreach (var messageContext in localBatch) + { + messageContext.ConsumerContext.Complete(); + } } } } diff --git a/src/KafkaFlow.BatchConsume/KafkaFlow.BatchConsume.csproj b/src/KafkaFlow.BatchConsume/KafkaFlow.BatchConsume.csproj index 997d1725c..8a6dcb8a2 100644 --- a/src/KafkaFlow.BatchConsume/KafkaFlow.BatchConsume.csproj +++ b/src/KafkaFlow.BatchConsume/KafkaFlow.BatchConsume.csproj @@ -11,8 +11,5 @@ - - - diff --git a/src/KafkaFlow.Compressor.Gzip/GzipMessageCompressor.cs b/src/KafkaFlow.Compressor.Gzip/GzipMessageCompressor.cs index f49237c59..f1fef5ebd 100644 --- a/src/KafkaFlow.Compressor.Gzip/GzipMessageCompressor.cs +++ b/src/KafkaFlow.Compressor.Gzip/GzipMessageCompressor.cs @@ -7,7 +7,6 @@ /// /// A GZIP message compressor /// - [Obsolete("Compressors should only be used in backward compatibility scenarios, in the vast majority of cases native compression (producer.WithCompression()) should be used instead")] public class GzipMessageCompressor : IMessageCompressor { /// diff --git a/src/KafkaFlow.Compressor/ConfigurationBuilderExtensions.cs b/src/KafkaFlow.Compressor/ConfigurationBuilderExtensions.cs index eb5e83f5b..204f5311e 100644 --- a/src/KafkaFlow.Compressor/ConfigurationBuilderExtensions.cs +++ b/src/KafkaFlow.Compressor/ConfigurationBuilderExtensions.cs @@ -14,7 +14,6 @@ public static class ConfigurationBuilderExtensions /// The middleware configuration builder /// The compressor type /// - [Obsolete("Compressors should only be used in backward compatibility scenarios, in the vast majority of cases native compression (producer.WithCompression()) should be used instead")] public static IConsumerMiddlewareConfigurationBuilder AddCompressor(this IConsumerMiddlewareConfigurationBuilder middlewares) where T : class, IMessageCompressor { @@ -29,7 +28,6 @@ public static IConsumerMiddlewareConfigurationBuilder AddCompressor(this ICon /// The compressor type that implements /// A factory to create the instance /// - [Obsolete("Compressors should only be used in backward compatibility scenarios, in the vast majority of cases native compression (producer.WithCompression()) should be used instead")] public static IConsumerMiddlewareConfigurationBuilder AddCompressor( this IConsumerMiddlewareConfigurationBuilder middlewares, Factory factory) @@ -45,7 +43,6 @@ public static IConsumerMiddlewareConfigurationBuilder AddCompressor( /// The middleware configuration builder /// The compressor type that implements /// - [Obsolete("Compressors should only be used in backward compatibility scenarios, in the vast majority of cases native compression (producer.WithCompression()) should be used instead")] public static IProducerMiddlewareConfigurationBuilder AddCompressor(this IProducerMiddlewareConfigurationBuilder middlewares) where T : class, IMessageCompressor { @@ -61,7 +58,6 @@ public static IProducerMiddlewareConfigurationBuilder AddCompressor(this IPro /// The compressor type that implements /// A factory to create the instance /// - [Obsolete("Compressors should only be used in backward compatibility scenarios, in the vast majority of cases native compression (producer.WithCompression()) should be used instead")] public static IProducerMiddlewareConfigurationBuilder AddCompressor( this IProducerMiddlewareConfigurationBuilder middlewares, Factory factory) diff --git a/src/KafkaFlow.UnitTests/BatchConsume/BatchConsumeMiddlewareTests.cs b/src/KafkaFlow.UnitTests/BatchConsume/BatchConsumeMiddlewareTests.cs index 5e75f3c4d..e55e85ae8 100644 --- a/src/KafkaFlow.UnitTests/BatchConsume/BatchConsumeMiddlewareTests.cs +++ b/src/KafkaFlow.UnitTests/BatchConsume/BatchConsumeMiddlewareTests.cs @@ -4,6 +4,8 @@ namespace KafkaFlow.UnitTests.BatchConsume using System.Threading.Tasks; using FluentAssertions; using KafkaFlow.BatchConsume; + using KafkaFlow.Configuration; + using KafkaFlow.Consumers; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -30,7 +32,33 @@ public void Setup() this.logHandlerMock = new Mock(); + var middlewareContextMock = new Mock(); + var workerMock = new Mock(); + var consumerMock = new Mock(); + var consumerConfigurationMock = new Mock(); + + middlewareContextMock + .SetupGet(x => x.Worker) + .Returns(workerMock.Object); + + middlewareContextMock + .SetupGet(x => x.Consumer) + .Returns(consumerMock.Object); + + consumerMock + .SetupGet(x => x.Configuration) + .Returns(consumerConfigurationMock.Object); + + workerMock + .SetupGet(x => x.WorkerStopped) + .Returns(new WorkerStoppedSubject(this.logHandlerMock.Object)); + + consumerConfigurationMock + .SetupGet(x => x.AutoMessageCompletion) + .Returns(true); + this.target = new BatchConsumeMiddleware( + middlewareContextMock.Object, BatchSize, this.batchTimeout, this.logHandlerMock.Object); @@ -43,6 +71,10 @@ public async Task AddAsync_LessThanBatchSize_CallNextOnTimeout() var consumerContext = new Mock(); var context = new Mock(); + consumerContext + .SetupGet(x => x.WorkerDependencyResolver) + .Returns(Mock.Of()); + context .Setup(x => x.ConsumerContext) .Returns(consumerContext.Object); @@ -54,7 +86,7 @@ public async Task AddAsync_LessThanBatchSize_CallNextOnTimeout() this.timesNextWasCalled.Should().Be(0); await this.WaitBatchTimeoutAsync(); this.timesNextWasCalled.Should().Be(1); - consumerContext.Verify(x => x.StoreOffset(), Times.Once); + consumerContext.Verify(x => x.Complete(), Times.Once); } [TestMethod] @@ -64,6 +96,10 @@ public async Task AddAsync_ExactlyBatchSize_CallNextInstantly() var consumerContext = new Mock(); var contextMock = new Mock(); + consumerContext + .SetupGet(x => x.WorkerDependencyResolver) + .Returns(Mock.Of()); + contextMock .Setup(x => x.ConsumerContext) .Returns(consumerContext.Object); @@ -79,7 +115,7 @@ public async Task AddAsync_ExactlyBatchSize_CallNextInstantly() // Assert this.timesNextWasCalled.Should().Be(1); this.nextContext.GetMessagesBatch().Should().HaveCount(BatchSize); - consumerContext.Verify(x => x.StoreOffset(), Times.Exactly(BatchSize)); + consumerContext.Verify(x => x.Complete(), Times.Exactly(BatchSize)); } [TestMethod] @@ -89,6 +125,10 @@ public async Task AddAsync_MoreThanBatchSize_CallNextInstantlyThenCallWhenTimeou var consumerContext = new Mock(); var contextMock = new Mock(); + consumerContext + .SetupGet(x => x.WorkerDependencyResolver) + .Returns(Mock.Of()); + contextMock .Setup(x => x.ConsumerContext) .Returns(consumerContext.Object); @@ -104,11 +144,11 @@ public async Task AddAsync_MoreThanBatchSize_CallNextInstantlyThenCallWhenTimeou // Assert this.timesNextWasCalled.Should().Be(1); this.nextContext.GetMessagesBatch().Should().HaveCount(BatchSize); - consumerContext.Verify(x => x.StoreOffset(), Times.Exactly(BatchSize)); + consumerContext.Verify(x => x.Complete(), Times.Exactly(BatchSize)); await this.WaitBatchTimeoutAsync(); this.timesNextWasCalled.Should().Be(2); - consumerContext.Verify(x => x.StoreOffset(), Times.Exactly(BatchSize + 1)); + consumerContext.Verify(x => x.Complete(), Times.Exactly(BatchSize + 1)); } [TestMethod] diff --git a/src/KafkaFlow.UnitTests/ConfigurationBuilders/ConsumerConfigurationBuilderTests.cs b/src/KafkaFlow.UnitTests/ConfigurationBuilders/ConsumerConfigurationBuilderTests.cs index 6259d0311..88efc9d1f 100644 --- a/src/KafkaFlow.UnitTests/ConfigurationBuilders/ConsumerConfigurationBuilderTests.cs +++ b/src/KafkaFlow.UnitTests/ConfigurationBuilders/ConsumerConfigurationBuilderTests.cs @@ -56,12 +56,12 @@ public void Build_RequiredCalls_ReturnDefaultValues() // Assert configuration.Topics.Should().BeEquivalentTo(topic1); configuration.BufferSize.Should().Be(bufferSize); - configuration.WorkersCountCalculator(null).Result.Should().Be(workers); + configuration.WorkersCountCalculator(null, null).Result.Should().Be(workers); configuration.GroupId.Should().Be(groupId); configuration.GetKafkaConfig().AutoOffsetReset.Should().BeNull(); configuration.GetKafkaConfig().EnableAutoOffsetStore.Should().Be(false); configuration.GetKafkaConfig().EnableAutoCommit.Should().Be(false); - configuration.AutoStoreOffsets.Should().Be(true); + configuration.AutoMessageCompletion.Should().Be(true); configuration.AutoCommitInterval.Should().Be(TimeSpan.FromSeconds(5)); configuration.StatisticsHandlers.Should().BeEmpty(); configuration.PartitionsAssignedHandlers.Should().BeEmpty(); @@ -101,7 +101,7 @@ public void Build_AllCalls_ReturnPassedValues() .WithWorkersCount(workers) .WithGroupId(groupId) .WithAutoOffsetReset(offsetReset) - .WithManualStoreOffsets() + .WithManualMessageCompletion() .WithAutoCommitIntervalMs(autoCommitInterval) .WithMaxPollIntervalMs(maxPollIntervalMs) .WithConsumerConfig(consumerConfig) @@ -119,10 +119,10 @@ public void Build_AllCalls_ReturnPassedValues() configuration.Topics.Should().BeEquivalentTo(topic1, topic2); configuration.ConsumerName.Should().Be(name); configuration.BufferSize.Should().Be(bufferSize); - configuration.WorkersCountCalculator(null).Result.Should().Be(workers); + configuration.WorkersCountCalculator(null, null).Result.Should().Be(workers); configuration.GroupId.Should().Be(groupId); configuration.GetKafkaConfig().AutoOffsetReset.Should().Be(offsetReset); - configuration.AutoStoreOffsets.Should().Be(false); + configuration.AutoMessageCompletion.Should().Be(false); configuration.GetKafkaConfig().EnableAutoOffsetStore.Should().Be(false); configuration.GetKafkaConfig().EnableAutoCommit.Should().Be(false); configuration.AutoCommitInterval.Should().Be(TimeSpan.FromMilliseconds(autoCommitInterval)); diff --git a/src/KafkaFlow.UnitTests/Consumer/ConsumerManagerTests.cs b/src/KafkaFlow.UnitTests/Consumer/ConsumerManagerTests.cs index 5fafd4bbf..d8492f775 100644 --- a/src/KafkaFlow.UnitTests/Consumer/ConsumerManagerTests.cs +++ b/src/KafkaFlow.UnitTests/Consumer/ConsumerManagerTests.cs @@ -55,7 +55,7 @@ public void Setup() configurationMock .SetupGet(x => x.WorkersCountCalculator) - .Returns(_ => Task.FromResult(10)); + .Returns((_, _) => Task.FromResult(10)); configurationMock .SetupGet(x => x.WorkersCountEvaluationInterval) diff --git a/src/KafkaFlow.UnitTests/ConsumerContextTests.cs b/src/KafkaFlow.UnitTests/ConsumerContextTests.cs deleted file mode 100644 index 259dea856..000000000 --- a/src/KafkaFlow.UnitTests/ConsumerContextTests.cs +++ /dev/null @@ -1,47 +0,0 @@ -namespace KafkaFlow.UnitTests -{ - using System; - using System.Threading; - using Confluent.Kafka; - using FluentAssertions; - using KafkaFlow.Consumers; - using Microsoft.VisualStudio.TestTools.UnitTesting; - - [TestClass] - public class ConsumerContextTests - { - [TestMethod] - public void MessageTimestamp_ConsumeResultHasMessageTimestamp_ReturnsMessageTimestampFromResult() - { - // Arrange - var expectedMessageTimestamp = new DateTime( - 2020, - 1, - 1, - 0, - 0, - 0); - - var consumerResult = new ConsumeResult - { - Message = new Message - { - Timestamp = new Timestamp(expectedMessageTimestamp), - }, - }; - - var target = new ConsumerContext( - null, - null, - consumerResult, - CancellationToken.None, - 0); - - // Act - var messageTimestamp = target.MessageTimestamp; - - // Assert - messageTimestamp.Should().Be(expectedMessageTimestamp.ToUniversalTime()); - } - } -} diff --git a/src/KafkaFlow.UnitTests/ExtensionHelpers.cs b/src/KafkaFlow.UnitTests/ExtensionHelpers.cs new file mode 100644 index 000000000..50c81f1e2 --- /dev/null +++ b/src/KafkaFlow.UnitTests/ExtensionHelpers.cs @@ -0,0 +1,14 @@ +namespace KafkaFlow.UnitTests +{ + using System; + using System.Threading.Tasks; + + public static class ExtensionHelpers + { + public static TaskCompletionSource WithTimeout(this TaskCompletionSource taskCompletionSource, int milliseconds) + { + Task.Delay(milliseconds).ContinueWith(_ => taskCompletionSource.TrySetException(new TimeoutException())); + return taskCompletionSource; + } + } +} diff --git a/src/KafkaFlow.UnitTests/MemoryTelemetryStorageTests.cs b/src/KafkaFlow.UnitTests/MemoryTelemetryStorageTests.cs index 86e1b722b..bb7bf0f66 100644 --- a/src/KafkaFlow.UnitTests/MemoryTelemetryStorageTests.cs +++ b/src/KafkaFlow.UnitTests/MemoryTelemetryStorageTests.cs @@ -18,7 +18,7 @@ public class MemoryTelemetryStorageTests [TestInitialize] public void Setup() { - this.dateTimeProviderMock = new(MockBehavior.Strict); + this.dateTimeProviderMock = new(); this.dateTimeProviderMock .SetupGet(x => x.MinValue) @@ -133,7 +133,7 @@ public void PutTwoItems_ExpiryOne_ReturnsOne() var now = new DateTime(2000, 01, 01); this.dateTimeProviderMock - .SetupGet(x => x.Now) + .SetupGet(x => x.UtcNow) .Returns(now); var metric1 = new ConsumerTelemetryMetric @@ -155,7 +155,7 @@ public void PutTwoItems_ExpiryOne_ReturnsOne() }; this.dateTimeProviderMock - .SetupGet(x => x.Now) + .SetupGet(x => x.UtcNow) .Returns(now.AddSeconds(2)); // Act diff --git a/src/KafkaFlow.UnitTests/OffsetCommitterTests.cs b/src/KafkaFlow.UnitTests/OffsetCommitterTests.cs index 4f2d71db2..71b8c44c8 100644 --- a/src/KafkaFlow.UnitTests/OffsetCommitterTests.cs +++ b/src/KafkaFlow.UnitTests/OffsetCommitterTests.cs @@ -4,6 +4,7 @@ namespace KafkaFlow.UnitTests using System.Collections.Generic; using System.Linq; using System.Threading; + using System.Threading.Tasks; using Confluent.Kafka; using FluentAssertions; using KafkaFlow.Consumers; @@ -16,20 +17,15 @@ public class OffsetCommitterTests private const int TestTimeout = 5000; private Mock consumerMock; - private Mock dependencyResolverMock; - - private Mock logHandlerMock; private TopicPartition topicPartition; private OffsetCommitter offsetCommitter; [TestInitialize] - public void Setup() + public async Task Setup() { this.consumerMock = new Mock(); - this.logHandlerMock = new Mock(); - this.dependencyResolverMock = new Mock(); this.topicPartition = new TopicPartition("topic-A", new Partition(1)); this.consumerMock @@ -38,74 +34,83 @@ public void Setup() this.offsetCommitter = new OffsetCommitter( this.consumerMock.Object, - this.dependencyResolverMock.Object, - new List<(Action>, TimeSpan)>(), - this.logHandlerMock.Object); + Mock.Of(), + Mock.Of()); + + await this.offsetCommitter.StartAsync(); } [TestCleanup] - public void Cleanup() + public async Task Cleanup() { - this.offsetCommitter.Dispose(); + await this.offsetCommitter.StopAsync(); } [TestMethod] - public void MarkAsProcessed_ShouldCommit() + public async Task MarkAsProcessed_ShouldCommit() { // Arrange - var offset = new TopicPartitionOffset(this.topicPartition, new Offset(1)); - var expectedOffsets = new[] { offset }; + var expectedOffsets = new[] { new TopicPartitionOffset(this.topicPartition, new Offset(2)) }; - var ready = new ManualResetEvent(false); + var ready = new TaskCompletionSource().WithTimeout(TestTimeout); this.consumerMock - .Setup(c => c.Commit(It.Is>(l => l.SequenceEqual(expectedOffsets)))) - .Callback((IEnumerable _) => { ready.Set(); }); + .Setup(c => c.Commit(It.Is>(l => l.SequenceEqual(expectedOffsets)))) + .Callback((IEnumerable _) => ready.SetResult()); // Act - this.offsetCommitter.MarkAsProcessed(offset); - ready.WaitOne(TestTimeout); + this.offsetCommitter.MarkAsProcessed( + new KafkaFlow.TopicPartitionOffset( + this.topicPartition.Topic, + this.topicPartition.Partition, + 1)); + + await ready.Task; // Assert - this.consumerMock.Verify( - c => c.Commit(It.Is>(l => l.SequenceEqual(expectedOffsets))), - Times.Once); + this.consumerMock.VerifyAll(); } [TestMethod] - public void PendingOffsetsState_ShouldExecuteHandlers() + public async Task PendingOffsetsState_ShouldExecuteHandlers() { // Arrange - var ready = new ManualResetEvent(false); + var ready = new TaskCompletionSource().WithTimeout(TestTimeout); - using var committer = new OffsetCommitter( + var committer = new OffsetCommitter( this.consumerMock.Object, - this.dependencyResolverMock.Object, - new List<(Action> handler, TimeSpan interval)> - { - ((_, _) => ready.Set(), TimeSpan.FromMilliseconds(100)), - }, - this.logHandlerMock.Object); + Mock.Of(), + Mock.Of()); + + committer.PendingOffsetsStatisticsHandlers.Add(new((_, _) => ready.TrySetResult(), TimeSpan.FromMilliseconds(100))); + + await committer.StartAsync(); // Act - committer.MarkAsProcessed(new TopicPartitionOffset(this.topicPartition, new Offset(1))); + committer.MarkAsProcessed( + new KafkaFlow.TopicPartitionOffset( + this.topicPartition.Topic, + this.topicPartition.Partition, + 1)); // Assert - ready.WaitOne(TestTimeout).Should().BeTrue(); + await ready.Task; + + // Cleanup + await committer.StopAsync(); } [TestMethod] - public void MarkAsProcessed_WithFailure_ShouldRequeueFailedOffsetAndCommit() + public async Task MarkAsProcessed_WithFailure_ShouldRequeueFailedOffsetAndCommit() { // Arrange - var offset = new TopicPartitionOffset(this.topicPartition, new Offset(2)); - var expectedOffsets = new[] { offset }; + var expectedOffsets = new[] { new TopicPartitionOffset(this.topicPartition, new Offset(2)) }; - var ready = new ManualResetEvent(false); + var ready = new TaskCompletionSource().WithTimeout(TestTimeout); var hasThrown = false; this.consumerMock - .Setup(c => c.Commit(It.Is>(l => l.SequenceEqual(expectedOffsets)))) + .Setup(c => c.Commit(It.Is>(l => l.SequenceEqual(expectedOffsets)))) .Callback( (IEnumerable _) => { @@ -115,16 +120,21 @@ public void MarkAsProcessed_WithFailure_ShouldRequeueFailedOffsetAndCommit() throw new InvalidOperationException(); } - ready.Set(); + ready.TrySetResult(); }); // Act - this.offsetCommitter.MarkAsProcessed(offset); - ready.WaitOne(TestTimeout); + this.offsetCommitter.MarkAsProcessed( + new KafkaFlow.TopicPartitionOffset( + this.topicPartition.Topic, + this.topicPartition.Partition, + 1)); + + await ready.Task; // Assert this.consumerMock.Verify( - c => c.Commit(It.Is>(l => l.SequenceEqual(expectedOffsets))), + c => c.Commit(It.Is>(l => l.SequenceEqual(expectedOffsets))), Times.Exactly(2)); } } diff --git a/src/KafkaFlow.UnitTests/OffsetManagerTests.cs b/src/KafkaFlow.UnitTests/OffsetManagerTests.cs index b557ff483..631de1336 100644 --- a/src/KafkaFlow.UnitTests/OffsetManagerTests.cs +++ b/src/KafkaFlow.UnitTests/OffsetManagerTests.cs @@ -1,17 +1,20 @@ namespace KafkaFlow.UnitTests { + using System; using System.Collections.Generic; using Confluent.Kafka; + using FluentAssertions; using KafkaFlow.Consumers; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; + using TopicPartitionOffset = KafkaFlow.TopicPartitionOffset; [TestClass] public class OffsetManagerTests { private Mock committerMock; - private TopicPartition topicPartition; private OffsetManager target; + private TopicPartition topicPartition; [TestInitialize] public void Setup() @@ -25,30 +28,27 @@ public void Setup() } [TestMethod] - public void MarkAsProcessed_WithInvalidTopicPartition_ShouldDoNothing() + public void MarkAsProcessed_WithNotQueuedContext_ShouldThrowInvalidOperation() { - // Arrange - this.target.Enqueue(new TopicPartitionOffset(this.topicPartition, new Offset(1))); - // Act - this.target.MarkAsProcessed(new TopicPartitionOffset(new TopicPartition("topic-B", new Partition(1)), new Offset(1))); + Action act = () => this.target.MarkAsProcessed(this.MockConsumerContext(1)); // Assert - this.committerMock.Verify(c => c.MarkAsProcessed(It.IsAny()), Times.Never()); + act.Should().Throw(); } [TestMethod] public void MarkAsProcessed_WithGaps_ShouldStoreOffsetJustOnce() { // Arrange - this.target.Enqueue(new TopicPartitionOffset(this.topicPartition, new Offset(1))); - this.target.Enqueue(new TopicPartitionOffset(this.topicPartition, new Offset(2))); - this.target.Enqueue(new TopicPartitionOffset(this.topicPartition, new Offset(3))); + this.target.Enqueue(this.MockConsumerContext(1)); + this.target.Enqueue(this.MockConsumerContext(2)); + this.target.Enqueue(this.MockConsumerContext(3)); // Act - this.target.MarkAsProcessed(new TopicPartitionOffset(this.topicPartition, new Offset(3))); - this.target.MarkAsProcessed(new TopicPartitionOffset(this.topicPartition, new Offset(2))); - this.target.MarkAsProcessed(new TopicPartitionOffset(this.topicPartition, new Offset(1))); + this.target.MarkAsProcessed(this.MockConsumerContext(3)); + this.target.MarkAsProcessed(this.MockConsumerContext(2)); + this.target.MarkAsProcessed(this.MockConsumerContext(1)); // Assert this.committerMock.Verify( @@ -56,9 +56,33 @@ public void MarkAsProcessed_WithGaps_ShouldStoreOffsetJustOnce() c.MarkAsProcessed( It.Is( p => - p.Partition.Equals(this.topicPartition.Partition) && - p.Offset.Value.Equals(4))), + p.Partition == this.topicPartition.Partition && + p.Offset == 3)), Times.Once); } + + private IConsumerContext MockConsumerContext(int offset) + { + var mock = new Mock(); + var tpo = new TopicPartitionOffset(this.topicPartition.Topic, this.topicPartition.Partition, offset); + + mock + .SetupGet(x => x.Offset) + .Returns(tpo.Offset); + + mock + .SetupGet(x => x.Partition) + .Returns(tpo.Partition); + + mock + .SetupGet(x => x.Topic) + .Returns(tpo.Topic); + + mock + .SetupGet(x => x.TopicPartitionOffset) + .Returns(tpo); + + return mock.Object; + } } } diff --git a/src/KafkaFlow.UnitTests/PartitionOffsetsTests.cs b/src/KafkaFlow.UnitTests/PartitionOffsetsTests.cs index fdd46c766..e3a4b168c 100644 --- a/src/KafkaFlow.UnitTests/PartitionOffsetsTests.cs +++ b/src/KafkaFlow.UnitTests/PartitionOffsetsTests.cs @@ -1,192 +1,169 @@ namespace KafkaFlow.UnitTests { using System; - using System.Collections.Concurrent; using System.Collections.Generic; - using System.Linq; - using System.Threading; using System.Threading.Tasks; using FluentAssertions; using KafkaFlow.Consumers; using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; [TestClass] public class PartitionOffsetsTests { [TestMethod] - public void ShouldUpdate_WithoutAddingOffsets_ThrowsException() + public void TryDequeue_WithoutEnqueuing_ThrowsException() { // Arrange var offsets = new PartitionOffsets(); // Act - Func act = () => offsets.ShouldCommit(1, out _); + Func act = () => offsets.TryDequeue(MockConsumerContext(1)); // Assert act.Should().Throw(); } [TestMethod] - public void ShouldUpdateOffset_NextOffset_ShouldUpdate() + public void TryDequeue_WithSequencedContext_SetDequeuedContext() { // Arrange var offsets = new PartitionOffsets(); - offsets.Enqueue(1); + + var context = MockConsumerContext(1); + + offsets.Enqueue(context); // Act - var shouldUpdate = offsets.ShouldCommit(1, out var offset); + var isCommitAllowed = offsets.TryDequeue(context); // Assert - Assert.IsTrue(shouldUpdate); - Assert.AreEqual(1, offset); + Assert.IsTrue(isCommitAllowed); + Assert.AreEqual(1, offsets.DequeuedContext.Offset); } [TestMethod] - public void ShouldUpdateOffset_WithOneGap_ShouldNotUpdate() + public void TryDequeue_WithNonSequencedContexts_UnsetDequeuedContext() { // Arrange var offsets = new PartitionOffsets(); - offsets.Enqueue(1); + offsets.Enqueue(MockConsumerContext(1)); // Act - var shouldUpdate = offsets.ShouldCommit(2, out var offset); + var isCommitAllowed = offsets.TryDequeue(MockConsumerContext(2)); // Assert - Assert.IsFalse(shouldUpdate); - Assert.AreEqual(-1, offset); + Assert.IsFalse(isCommitAllowed); + Assert.IsNull(offsets.DequeuedContext); } [TestMethod] - public void ShouldUpdateOffset_WithManyGaps_ShouldUpdate() + public void TryDequeue_WithUnorderedSequence_SetDequeuedContextWhenAllowed() { // Arrange var offsets = new PartitionOffsets(); - offsets.Enqueue(1); - offsets.Enqueue(2); - offsets.Enqueue(4); - offsets.Enqueue(5); - offsets.Enqueue(7); - offsets.Enqueue(8); - offsets.Enqueue(15); - offsets.Enqueue(20); - offsets.Enqueue(50); + + var context1 = MockConsumerContext(1); + var context2 = MockConsumerContext(2); + var context4 = MockConsumerContext(4); + var context5 = MockConsumerContext(5); + + offsets.Enqueue(context1); + offsets.Enqueue(context2); + offsets.Enqueue(context4); + offsets.Enqueue(context5); // Act var results = new[] { new { - ShouldUpdateResult = offsets.ShouldCommit(7, out long offset), - ShouldUpdateExpected = false, - LastOffsetResult = offset, - LastOffsetExpected = -1, - }, - new - { - ShouldUpdateResult = offsets.ShouldCommit(1, out offset), - ShouldUpdateExpected = true, - LastOffsetResult = offset, - LastOffsetExpected = 1, - }, - new - { - ShouldUpdateResult = offsets.ShouldCommit(2, out offset), - ShouldUpdateExpected = true, - LastOffsetResult = offset, - LastOffsetExpected = 2, - }, - new - { - ShouldUpdateResult = offsets.ShouldCommit(20, out offset), - ShouldUpdateExpected = false, - LastOffsetResult = offset, - LastOffsetExpected = -1, - }, - new - { - ShouldUpdateResult = offsets.ShouldCommit(5, out offset), - ShouldUpdateExpected = false, - LastOffsetResult = offset, - LastOffsetExpected = -1, - }, - new - { - ShouldUpdateResult = offsets.ShouldCommit(8, out offset), - ShouldUpdateExpected = false, - LastOffsetResult = offset, - LastOffsetExpected = -1, + Dequeued = offsets.TryDequeue(context5), + ExcpectedDequeuedResult = false, + DequeuedContextOffset = offsets.DequeuedContext?.Offset, + ExpectedDequeuedContextOffset = -1, }, new { - ShouldUpdateResult = offsets.ShouldCommit(4, out offset), - ShouldUpdateExpected = true, - LastOffsetResult = offset, - LastOffsetExpected = 8, + Dequeued = offsets.TryDequeue(context1), + ExcpectedDequeuedResult = true, + DequeuedContextOffset = offsets.DequeuedContext?.Offset, + ExpectedDequeuedContextOffset = 1, }, new { - ShouldUpdateResult = offsets.ShouldCommit(15, out offset), - ShouldUpdateExpected = true, - LastOffsetResult = offset, - LastOffsetExpected = 20, + Dequeued = offsets.TryDequeue(context2), + ExcpectedDequeuedResult = true, + DequeuedContextOffset = offsets.DequeuedContext?.Offset, + ExpectedDequeuedContextOffset = 2, }, new { - ShouldUpdateResult = offsets.ShouldCommit(50, out offset), - ShouldUpdateExpected = true, - LastOffsetResult = offset, - LastOffsetExpected = 50, + Dequeued = offsets.TryDequeue(context4), + ExcpectedDequeuedResult = true, + DequeuedContextOffset = offsets.DequeuedContext?.Offset, + ExpectedDequeuedContextOffset = 5, }, }; // Assert foreach (var result in results) { - Assert.AreEqual(result.ShouldUpdateExpected, result.ShouldUpdateResult); - Assert.AreEqual(result.LastOffsetExpected, result.LastOffsetResult); + Assert.AreEqual(result.ExcpectedDequeuedResult, result.Dequeued); + Assert.AreEqual(result.ExpectedDequeuedContextOffset, result.DequeuedContextOffset ?? -1); } } [TestMethod] - public void ShouldUpdateOffset_WithManyConcurrentOffsets_ShouldUpdate() + public void TryDequeue_WithConcurrentCalls_RemainTheLastDequeuedContext() { // Arrange - const int count = 1_000; + const int count = 100; + const int lastOffset = count - 1; var target = new PartitionOffsets(); - var offsetsCommitted = new ConcurrentBag(); + var contexts = new IConsumerContext[count]; - var waitHandle = new ManualResetEvent(false); + var taskCompletionSource = new TaskCompletionSource(); - for (var i = 0; i < count; i += 2) + for (var i = 0; i < count; i++) { - target.Enqueue(i); + contexts[i] = MockConsumerContext(i); + target.Enqueue(contexts[i]); } // Act var tasks = new List(); - for (var i = 0; i < count; i += 2) + for (var i = 0; i < count; i++) { - var offset = i; tasks.Add( - Task.Run( - () => + Task.Factory.StartNew( + async index => { - waitHandle.WaitOne(); + await taskCompletionSource.Task; - if (target.ShouldCommit(offset, out var lastProcessedOffset)) - { - offsetsCommitted.Add(lastProcessedOffset); - } - })); + target.TryDequeue(contexts[(int)index]); + }, + i)); } - waitHandle.Set(); + taskCompletionSource.SetResult(); Task.WaitAll(tasks.ToArray()); // Assert - Assert.AreEqual(count - 2, offsetsCommitted.Max()); + Assert.AreEqual(lastOffset, target.DequeuedContext.Offset); + } + + private static IConsumerContext MockConsumerContext(int offset) + { + var mock = new Mock(); + + mock + .SetupGet(x => x.Offset) + .Returns(offset); + + return mock.Object; } } } diff --git a/src/KafkaFlow/Configuration/ConsumerConfiguration.cs b/src/KafkaFlow/Configuration/ConsumerConfiguration.cs index 5638f5492..a74de9d43 100644 --- a/src/KafkaFlow/Configuration/ConsumerConfiguration.cs +++ b/src/KafkaFlow/Configuration/ConsumerConfiguration.cs @@ -22,15 +22,14 @@ public ConsumerConfiguration( TimeSpan workerStopTimeout, Factory distributionStrategyFactory, IReadOnlyList middlewaresConfigurations, - bool autoStoreOffsets, + bool autoMessageCompletion, bool noStoreOffsets, ConsumerInitialState initialState, TimeSpan autoCommitInterval, IReadOnlyList> statisticsHandlers, IReadOnlyList>> partitionsAssignedHandlers, IReadOnlyList>> partitionsRevokedHandlers, - IReadOnlyList<(Action> handler, TimeSpan interval)> - pendingOffsetsHandlers, + IReadOnlyList pendingOffsetsStatisticsHandlers, ConsumerCustomFactory customFactory) { this.consumerConfig = consumerConfig ?? throw new ArgumentNullException(nameof(consumerConfig)); @@ -44,7 +43,7 @@ public ConsumerConfiguration( distributionStrategyFactory ?? throw new ArgumentNullException(nameof(distributionStrategyFactory)); this.MiddlewaresConfigurations = middlewaresConfigurations ?? throw new ArgumentNullException(nameof(middlewaresConfigurations)); - this.AutoStoreOffsets = autoStoreOffsets; + this.AutoMessageCompletion = autoMessageCompletion; this.NoStoreOffsets = noStoreOffsets; this.InitialState = initialState; this.AutoCommitInterval = autoCommitInterval; @@ -59,7 +58,7 @@ public ConsumerConfiguration( this.StatisticsHandlers = statisticsHandlers; this.PartitionsAssignedHandlers = partitionsAssignedHandlers; this.PartitionsRevokedHandlers = partitionsRevokedHandlers; - this.PendingOffsetsHandlers = pendingOffsetsHandlers; + this.PendingOffsetsStatisticsHandlers = pendingOffsetsStatisticsHandlers; this.CustomFactory = customFactory; this.BufferSize = bufferSize > 0 ? @@ -94,7 +93,7 @@ public ConsumerConfiguration( public TimeSpan WorkerStopTimeout { get; } - public bool AutoStoreOffsets { get; } + public bool AutoMessageCompletion { get; } public bool NoStoreOffsets { get; } @@ -108,8 +107,7 @@ public ConsumerConfiguration( public IReadOnlyList>> PartitionsRevokedHandlers { get; } - public IReadOnlyList<(Action> handler, TimeSpan interval)> - PendingOffsetsHandlers { get; } + public IReadOnlyList PendingOffsetsStatisticsHandlers { get; } public ConsumerCustomFactory CustomFactory { get; } diff --git a/src/KafkaFlow/Configuration/ConsumerConfigurationBuilder.cs b/src/KafkaFlow/Configuration/ConsumerConfigurationBuilder.cs index 8531f04b7..e1c027151 100644 --- a/src/KafkaFlow/Configuration/ConsumerConfigurationBuilder.cs +++ b/src/KafkaFlow/Configuration/ConsumerConfigurationBuilder.cs @@ -14,8 +14,7 @@ internal sealed class ConsumerConfigurationBuilder : IConsumerConfigurationBuild private readonly List topicsPartitions = new(); private readonly List> statisticsHandlers = new(); - private readonly List<(Action>, TimeSpan interval)> - pendingOffsetsStatisticsHandlers = new(); + private readonly List pendingOffsetsStatisticsHandlers = new(); private readonly List>> partitionAssignedHandlers = new(); private readonly List>> partitionRevokedHandlers = new(); @@ -32,7 +31,7 @@ internal sealed class ConsumerConfigurationBuilder : IConsumerConfigurationBuild private TimeSpan workersCountEvaluationInterval = TimeSpan.FromMinutes(5); private int bufferSize; private TimeSpan workerStopTimeout = TimeSpan.FromSeconds(30); - private bool autoStoreOffsets = true; + private bool autoMessageCompletion = true; private bool noStoreOffsets; private ConsumerInitialState initialState = ConsumerInitialState.Running; private int statisticsInterval; @@ -174,15 +173,9 @@ public IConsumerConfigurationBuilder WithWorkDistributionStrategy() return this; } - public IConsumerConfigurationBuilder WithAutoStoreOffsets() + public IConsumerConfigurationBuilder WithManualMessageCompletion() { - this.autoStoreOffsets = true; - return this; - } - - public IConsumerConfigurationBuilder WithManualStoreOffsets() - { - this.autoStoreOffsets = false; + this.autoMessageCompletion = false; return this; } @@ -234,7 +227,7 @@ public IConsumerConfigurationBuilder WithPendingOffsetsStatisticsHandler( Action> pendingOffsetsHandler, TimeSpan interval) { - this.pendingOffsetsStatisticsHandlers.Add((pendingOffsetsHandler, interval)); + this.pendingOffsetsStatisticsHandlers.Add(new(pendingOffsetsHandler, interval)); return this; } @@ -276,7 +269,7 @@ public IConsumerConfiguration Build(ClusterConfiguration clusterConfiguration) this.workerStopTimeout, this.distributionStrategyFactory, middlewareConfiguration, - this.autoStoreOffsets, + this.autoMessageCompletion, this.noStoreOffsets, this.initialState, this.autoCommitInterval, diff --git a/src/KafkaFlow/Configuration/IConsumerConfiguration.cs b/src/KafkaFlow/Configuration/IConsumerConfiguration.cs index ef44288eb..4099867b9 100644 --- a/src/KafkaFlow/Configuration/IConsumerConfiguration.cs +++ b/src/KafkaFlow/Configuration/IConsumerConfiguration.cs @@ -72,9 +72,9 @@ public interface IConsumerConfiguration TimeSpan WorkerStopTimeout { get; } /// - /// Gets a value indicating whether if the application should store store at the end + /// Gets a value indicating whether if the application should manual complete the message at the end /// - bool AutoStoreOffsets { get; } + bool AutoMessageCompletion { get; } /// /// Gets a value indicating that no offsets will be stored on Kafka @@ -104,10 +104,7 @@ public interface IConsumerConfiguration /// /// Gets the handlers that will be called when there are pending offsets /// - IReadOnlyList<(Action> handler, TimeSpan interval)> PendingOffsetsHandlers - { - get; - } + IReadOnlyList PendingOffsetsStatisticsHandlers { get; } /// /// Gets the custom factory used to create a new diff --git a/src/KafkaFlow/Configuration/KafkaConfigurationBuilder.cs b/src/KafkaFlow/Configuration/KafkaConfigurationBuilder.cs index 73a022c0d..c194cc501 100644 --- a/src/KafkaFlow/Configuration/KafkaConfigurationBuilder.cs +++ b/src/KafkaFlow/Configuration/KafkaConfigurationBuilder.cs @@ -47,8 +47,8 @@ public KafkaConfiguration Build() .AddSingleton(new ConsumerAccessor()) .AddSingleton(new ConsumerManagerFactory()) .AddSingleton() - .AddScoped() - .AddScoped(r => r.Resolve()) + .AddScoped() + .AddScoped(r => r.Resolve()) .AddSingleton() .AddSingleton( r => diff --git a/src/KafkaFlow/Configuration/MiddlewareConfigurationBuilder.cs b/src/KafkaFlow/Configuration/MiddlewareConfigurationBuilder.cs index 02e900c82..95cf0a893 100644 --- a/src/KafkaFlow/Configuration/MiddlewareConfigurationBuilder.cs +++ b/src/KafkaFlow/Configuration/MiddlewareConfigurationBuilder.cs @@ -50,7 +50,7 @@ private static InstanceLifetime ParseLifetime(MiddlewareLifetime lifetime) { return lifetime switch { - MiddlewareLifetime.Scoped or MiddlewareLifetime.Message => InstanceLifetime.Scoped, + MiddlewareLifetime.Message => InstanceLifetime.Scoped, MiddlewareLifetime.Singleton => InstanceLifetime.Singleton, MiddlewareLifetime.Transient or MiddlewareLifetime.Worker or diff --git a/src/KafkaFlow/Configuration/PendingOffsetsStatisticsHandler.cs b/src/KafkaFlow/Configuration/PendingOffsetsStatisticsHandler.cs new file mode 100644 index 000000000..6df2d96dc --- /dev/null +++ b/src/KafkaFlow/Configuration/PendingOffsetsStatisticsHandler.cs @@ -0,0 +1,33 @@ +namespace KafkaFlow.Configuration +{ + using System; + using System.Collections.Generic; + using Confluent.Kafka; + + /// + /// Represents a handler for pending offsets statistics. + /// + public class PendingOffsetsStatisticsHandler + { + /// + /// Initializes a new instance of the class with the specified handler and interval. + /// + /// The action to handle pending offsets statistics. + /// The interval at which the handler should be executed. + public PendingOffsetsStatisticsHandler(Action> handler, TimeSpan interval) + { + this.Handler = handler; + this.Interval = interval; + } + + /// + /// Gets the action that handles pending offsets statistics. + /// + public Action> Handler { get; } + + /// + /// Gets the interval at which the handler should be executed. + /// + public TimeSpan Interval { get; } + } +} diff --git a/src/KafkaFlow/ConsumerManagerFactory.cs b/src/KafkaFlow/ConsumerManagerFactory.cs index cea52a8a7..a3c752bc2 100644 --- a/src/KafkaFlow/ConsumerManagerFactory.cs +++ b/src/KafkaFlow/ConsumerManagerFactory.cs @@ -5,17 +5,19 @@ namespace KafkaFlow internal class ConsumerManagerFactory : IConsumerManagerFactory { - public IConsumerManager Create(IConsumerConfiguration configuration, IDependencyResolver resolver) + public IConsumerManager Create(IConsumerConfiguration configuration, IDependencyResolver consumerDependencyResolver) { - var logHandler = resolver.Resolve(); + var logHandler = consumerDependencyResolver.Resolve(); - var consumer = configuration.CustomFactory(new Consumer(configuration, resolver, logHandler), resolver); + var consumer = configuration.CustomFactory( + new Consumer(configuration, consumerDependencyResolver, logHandler), + consumerDependencyResolver); var middlewareExecutor = new MiddlewareExecutor(configuration.MiddlewaresConfigurations); var consumerWorkerPool = new ConsumerWorkerPool( consumer, - resolver, + consumerDependencyResolver, middlewareExecutor, configuration, logHandler); @@ -31,7 +33,7 @@ public IConsumerManager Create(IConsumerConfiguration configuration, IDependency consumer, consumerWorkerPool, feeder, - resolver, + consumerDependencyResolver, logHandler); return consumerManager; diff --git a/src/KafkaFlow/Consumers/Consumer.cs b/src/KafkaFlow/Consumers/Consumer.cs index 9c9ffb2ff..e19583156 100644 --- a/src/KafkaFlow/Consumers/Consumer.cs +++ b/src/KafkaFlow/Consumers/Consumer.cs @@ -54,6 +54,11 @@ public Consumer( this.OnPartitionsRevoked((resolver, _, topicPartitions) => handler(resolver, topicPartitions)); } + var middlewareContext = this.dependencyResolver.Resolve(); + + middlewareContext.Worker = null; + middlewareContext.Consumer = this; + this.RegisterLogErrorHandler(); } diff --git a/src/KafkaFlow/Consumers/ConsumerContext.cs b/src/KafkaFlow/Consumers/ConsumerContext.cs index 356d001f9..794dd7031 100644 --- a/src/KafkaFlow/Consumers/ConsumerContext.cs +++ b/src/KafkaFlow/Consumers/ConsumerContext.cs @@ -27,6 +27,7 @@ public ConsumerContext( this.offsetManager = offsetManager; this.worker = worker; this.messageDependencyScope = messageDependencyScope; + this.AutoMessageCompletion = this.consumer.Configuration.AutoMessageCompletion; this.TopicPartitionOffset = new TopicPartitionOffset( kafkaResult.Topic, kafkaResult.Partition.Value, @@ -54,15 +55,21 @@ public ConsumerContext( public string GroupId => this.consumer.Configuration.GroupId; + public bool AutoMessageCompletion { get; set; } + public bool ShouldStoreOffset { get; set; } = true; public DateTime MessageTimestamp { get; } public Task Completion => this.completionSource.Task; - public void StoreOffset() + public void Complete() { - this.offsetManager.MarkAsProcessed(this); + if (this.ShouldStoreOffset) + { + this.offsetManager.MarkAsProcessed(this); + } + this.messageDependencyScope.Dispose(); this.completionSource.TrySetResult(this.TopicPartitionOffset); } diff --git a/src/KafkaFlow/Consumers/ConsumerManager.cs b/src/KafkaFlow/Consumers/ConsumerManager.cs index 96a73e7b3..a8c34bea3 100644 --- a/src/KafkaFlow/Consumers/ConsumerManager.cs +++ b/src/KafkaFlow/Consumers/ConsumerManager.cs @@ -63,10 +63,6 @@ public async Task StopAsync() this.Consumer.Dispose(); } - public void Dispose() - { - } - private void StopEvaluateWorkerCountTimer() => this.evaluateWorkersCountTimer?.Change(Timeout.Infinite, Timeout.Infinite); private void StartEvaluateWorkerCountTimer() => this.evaluateWorkersCountTimer?.Change( diff --git a/src/KafkaFlow/Consumers/WorkerLifetimeContext.cs b/src/KafkaFlow/Consumers/ConsumerMiddlewareContext.cs similarity index 65% rename from src/KafkaFlow/Consumers/WorkerLifetimeContext.cs rename to src/KafkaFlow/Consumers/ConsumerMiddlewareContext.cs index a31812b2d..82faf1e34 100644 --- a/src/KafkaFlow/Consumers/WorkerLifetimeContext.cs +++ b/src/KafkaFlow/Consumers/ConsumerMiddlewareContext.cs @@ -1,6 +1,6 @@ namespace KafkaFlow.Consumers { - internal class WorkerLifetimeContext : IWorkerLifetimeContext + internal class ConsumerMiddlewareContext : IConsumerMiddlewareContext { public IWorker Worker { get; set; } diff --git a/src/KafkaFlow/Consumers/ConsumerWorker.cs b/src/KafkaFlow/Consumers/ConsumerWorker.cs index afb8c6314..81ade8577 100644 --- a/src/KafkaFlow/Consumers/ConsumerWorker.cs +++ b/src/KafkaFlow/Consumers/ConsumerWorker.cs @@ -41,10 +41,10 @@ public ConsumerWorker( this.workerStoppingSubject = new(logHandler); this.workerStoppedSubject = new(logHandler); - var workerContext = this.workerDependencyResolverScope.Resolver.Resolve(); + var middlewareContext = this.workerDependencyResolverScope.Resolver.Resolve(); - workerContext.Worker = this; - workerContext.Consumer = consumer; + middlewareContext.Worker = this; + middlewareContext.Consumer = consumer; } public int Id { get; } @@ -142,7 +142,7 @@ await this.middlewareExecutor } catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) { - return; + context.ConsumerContext.ShouldStoreOffset = false; } catch (Exception ex) { @@ -159,13 +159,15 @@ await this.middlewareExecutor context.ConsumerContext.ConsumerName, }); } - - if (this.consumer.Configuration.AutoStoreOffsets && context.ConsumerContext.ShouldStoreOffset) + finally { - context.ConsumerContext.StoreOffset(); - } + if (context.ConsumerContext.AutoMessageCompletion) + { + context.ConsumerContext.Complete(); + } - this.onMessageFinishedHandler?.Invoke(); + this.onMessageFinishedHandler?.Invoke(); + } } catch (Exception ex) { diff --git a/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs b/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs index 59ec22cac..f82f494b9 100644 --- a/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs +++ b/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs @@ -45,8 +45,9 @@ public ConsumerWorkerPool( new OffsetCommitter( consumer, consumerDependencyResolver, - consumer.Configuration.PendingOffsetsHandlers, logHandler); + + this.offsetCommitter.PendingOffsetsStatisticsHandlers.AddRange(consumer.Configuration.PendingOffsetsStatisticsHandlers); } public int CurrentWorkersCount { get; private set; } diff --git a/src/KafkaFlow/Consumers/IWorkerLifetimeContext.cs b/src/KafkaFlow/Consumers/IConsumerMiddlewareContext.cs similarity index 58% rename from src/KafkaFlow/Consumers/IWorkerLifetimeContext.cs rename to src/KafkaFlow/Consumers/IConsumerMiddlewareContext.cs index 73ea0391b..cdb5f40aa 100644 --- a/src/KafkaFlow/Consumers/IWorkerLifetimeContext.cs +++ b/src/KafkaFlow/Consumers/IConsumerMiddlewareContext.cs @@ -1,12 +1,13 @@ namespace KafkaFlow.Consumers { /// - /// Provides access to the current consumer worker context. This interface only returns values when inside a middleware with Worker lifetime; otherwise, it will return null. + /// Provides access to the current consumer's middleware context. /// - public interface IWorkerLifetimeContext + public interface IConsumerMiddlewareContext { /// /// Gets the current worker in the context. + /// This property only returns values when inside a middleware with Worker lifetime; otherwise, it will return null. /// IWorker Worker { get; } diff --git a/src/KafkaFlow/Consumers/IOffsetCommitter.cs b/src/KafkaFlow/Consumers/IOffsetCommitter.cs index 1cdbd06e5..2986b610e 100644 --- a/src/KafkaFlow/Consumers/IOffsetCommitter.cs +++ b/src/KafkaFlow/Consumers/IOffsetCommitter.cs @@ -1,9 +1,13 @@ namespace KafkaFlow.Consumers { + using System.Collections.Generic; using System.Threading.Tasks; + using KafkaFlow.Configuration; internal interface IOffsetCommitter { + List PendingOffsetsStatisticsHandlers { get; } + void MarkAsProcessed(TopicPartitionOffset tpo); Task StartAsync(); diff --git a/src/KafkaFlow/Consumers/NullOffsetCommitter.cs b/src/KafkaFlow/Consumers/NullOffsetCommitter.cs index 9d000c44b..27228989c 100644 --- a/src/KafkaFlow/Consumers/NullOffsetCommitter.cs +++ b/src/KafkaFlow/Consumers/NullOffsetCommitter.cs @@ -1,10 +1,14 @@ namespace KafkaFlow.Consumers { + using System.Collections.Generic; using System.Threading.Tasks; using KafkaFlow; + using KafkaFlow.Configuration; internal class NullOffsetCommitter : IOffsetCommitter { + public List PendingOffsetsStatisticsHandlers { get; } = new(); + public void Dispose() { // Do nothing diff --git a/src/KafkaFlow/Consumers/OffsetCommitter.cs b/src/KafkaFlow/Consumers/OffsetCommitter.cs index 7c9d5eb70..f93e6ac99 100644 --- a/src/KafkaFlow/Consumers/OffsetCommitter.cs +++ b/src/KafkaFlow/Consumers/OffsetCommitter.cs @@ -6,16 +6,13 @@ namespace KafkaFlow.Consumers using System.Linq; using System.Threading; using System.Threading.Tasks; + using KafkaFlow.Configuration; internal class OffsetCommitter : IOffsetCommitter { private readonly IConsumer consumer; private readonly IDependencyResolver resolver; - private readonly - IReadOnlyList<(Action> handler, TimeSpan interval)> - pendingOffsetsHandlers; - private readonly ILogHandler logHandler; private readonly object commitSyncRoot = new(); @@ -28,17 +25,14 @@ private readonly public OffsetCommitter( IConsumer consumer, IDependencyResolver resolver, - IReadOnlyList<(Action> handler, TimeSpan interval)> - pendingOffsetsHandlers, ILogHandler logHandler) { this.consumer = consumer; this.resolver = resolver; - this.pendingOffsetsHandlers = pendingOffsetsHandlers; this.logHandler = logHandler; } - public void FlushOffsets() => this.CommitHandler(); + public List PendingOffsetsStatisticsHandlers { get; } = new(); public void MarkAsProcessed(TopicPartitionOffset tpo) { @@ -56,13 +50,13 @@ public Task StartAsync() this.consumer.Configuration.AutoCommitInterval, this.consumer.Configuration.AutoCommitInterval); - this.statisticsTimers = this.pendingOffsetsHandlers + this.statisticsTimers = this.PendingOffsetsStatisticsHandlers .Select( - s => new Timer( - _ => this.PendingOffsetsHandler(this.resolver, s.handler), + handler => new Timer( + _ => this.PendingOffsetsHandler(handler), null, - TimeSpan.Zero, - s.interval)) + handler.Interval, + handler.Interval)) .ToList(); return Task.CompletedTask; @@ -81,14 +75,12 @@ public Task StopAsync() return Task.CompletedTask; } - private void PendingOffsetsHandler( - IDependencyResolver resolver, - Action> handler) + private void PendingOffsetsHandler(PendingOffsetsStatisticsHandler handler) { if (!this.offsetsToCommit.IsEmpty) { - handler( - resolver, + handler.Handler( + this.resolver, this.offsetsToCommit.Values.Select( x => new Confluent.Kafka.TopicPartitionOffset(x.Topic, x.Partition, x.Offset))); diff --git a/src/KafkaFlow/Consumers/OffsetManager.cs b/src/KafkaFlow/Consumers/OffsetManager.cs index a4751fa9f..657091486 100644 --- a/src/KafkaFlow/Consumers/OffsetManager.cs +++ b/src/KafkaFlow/Consumers/OffsetManager.cs @@ -29,9 +29,9 @@ public void MarkAsProcessed(IConsumerContext context) lock (offsets) { - if (offsets.ShouldCommit(context, out var lastProcessedContext)) + if (offsets.TryDequeue(context)) { - this.committer.MarkAsProcessed(lastProcessedContext.TopicPartitionOffset); + this.committer.MarkAsProcessed(offsets.DequeuedContext.TopicPartitionOffset); } } } diff --git a/src/KafkaFlow/Consumers/PartitionOffsets.cs b/src/KafkaFlow/Consumers/PartitionOffsets.cs index 9ab9dbae8..36fa60314 100644 --- a/src/KafkaFlow/Consumers/PartitionOffsets.cs +++ b/src/KafkaFlow/Consumers/PartitionOffsets.cs @@ -10,6 +10,8 @@ internal class PartitionOffsets private readonly SortedDictionary processedContexts = new(); private readonly LinkedList receivedContexts = new(); + public IConsumerContext DequeuedContext { get; private set; } + public void Enqueue(IConsumerContext context) { lock (this.receivedContexts) @@ -18,9 +20,9 @@ public void Enqueue(IConsumerContext context) } } - public bool ShouldCommit(IConsumerContext context, out IConsumerContext lastProcessedContext) + public bool TryDequeue(IConsumerContext context) { - lastProcessedContext = null; + this.DequeuedContext = null; lock (this.receivedContexts) { @@ -38,7 +40,7 @@ public bool ShouldCommit(IConsumerContext context, out IConsumerContext lastProc do { - lastProcessedContext = this.receivedContexts.First.Value; + this.DequeuedContext = this.receivedContexts.First.Value; this.receivedContexts.RemoveFirst(); } while (this.receivedContexts.Count > 0 && this.processedContexts.Remove(this.receivedContexts.First.Value.Offset)); } diff --git a/src/KafkaFlow/KafkaBus.cs b/src/KafkaFlow/KafkaBus.cs index bc0f128b7..8ac7a699c 100644 --- a/src/KafkaFlow/KafkaBus.cs +++ b/src/KafkaFlow/KafkaBus.cs @@ -50,16 +50,16 @@ public async Task StartAsync(CancellationToken stopCancellationToken = default) foreach (var consumerConfiguration in cluster.Consumers) { - var dependencyScope = this.dependencyResolver.CreateScope(); + var consumerDependencyScope = this.dependencyResolver.CreateScope(); var consumerManager = - this.consumerManagerFactory.Create(consumerConfiguration, dependencyScope.Resolver); + this.consumerManagerFactory.Create(consumerConfiguration, consumerDependencyScope.Resolver); this.consumerManagers.Add(consumerManager); this.Consumers.Add( new MessageConsumer( consumerManager, - dependencyScope.Resolver.Resolve())); + consumerDependencyScope.Resolver.Resolve())); if (consumerConfiguration.InitialState == ConsumerInitialState.Running) { diff --git a/src/KafkaFlow/MessageContext.cs b/src/KafkaFlow/MessageContext.cs index fd5317578..b86d0e67b 100644 --- a/src/KafkaFlow/MessageContext.cs +++ b/src/KafkaFlow/MessageContext.cs @@ -37,7 +37,5 @@ public MessageContext( this.DependencyResolver, this.ConsumerContext, this.ProducerContext); - - public IMessageContext TransformMessage(object message) => throw new System.NotImplementedException(); } } From dea630c74216370b9935b08e56c86db433e23d28 Mon Sep 17 00:00:00 2001 From: Filipe Esch Date: Mon, 2 Oct 2023 15:15:01 +0100 Subject: [PATCH 09/20] refactor: remove unused namespaces --- src/KafkaFlow.Abstractions/Consumers/IWorker.cs | 1 - src/KafkaFlow.Abstractions/MiddlewareLifetime.cs | 2 -- src/KafkaFlow.Admin.WebApi/Adapters/ConsumerResponseAdapter.cs | 2 -- src/KafkaFlow.Admin.WebApi/Contracts/GroupResponse.cs | 1 - src/KafkaFlow.Admin.WebApi/Contracts/GroupsResponse.cs | 1 - src/KafkaFlow.Admin.WebApi/Controllers/ConsumersController.cs | 1 - src/KafkaFlow.Admin.WebApi/Controllers/GroupsController.cs | 1 - src/KafkaFlow.Compressor.Gzip/GzipMessageCompressor.cs | 1 - src/KafkaFlow.Compressor/ConfigurationBuilderExtensions.cs | 1 - src/KafkaFlow.IntegrationTests/CompressionSerializationTest.cs | 1 - src/KafkaFlow.IntegrationTests/CompressionTest.cs | 1 - src/KafkaFlow.IntegrationTests/ConsumerTest.cs | 1 - src/KafkaFlow.UnitTests/OffsetCommitterTests.cs | 2 -- 13 files changed, 16 deletions(-) diff --git a/src/KafkaFlow.Abstractions/Consumers/IWorker.cs b/src/KafkaFlow.Abstractions/Consumers/IWorker.cs index 482218597..a90dc7209 100644 --- a/src/KafkaFlow.Abstractions/Consumers/IWorker.cs +++ b/src/KafkaFlow.Abstractions/Consumers/IWorker.cs @@ -1,7 +1,6 @@ namespace KafkaFlow { using System; - using KafkaFlow.Configuration; using KafkaFlow.Observer; /// diff --git a/src/KafkaFlow.Abstractions/MiddlewareLifetime.cs b/src/KafkaFlow.Abstractions/MiddlewareLifetime.cs index 4263ac7c5..0b3f28966 100644 --- a/src/KafkaFlow.Abstractions/MiddlewareLifetime.cs +++ b/src/KafkaFlow.Abstractions/MiddlewareLifetime.cs @@ -1,7 +1,5 @@ namespace KafkaFlow { - using System; - /// /// Specifies the lifetime of a middleware /// diff --git a/src/KafkaFlow.Admin.WebApi/Adapters/ConsumerResponseAdapter.cs b/src/KafkaFlow.Admin.WebApi/Adapters/ConsumerResponseAdapter.cs index 5ebe0082f..1bef549f9 100644 --- a/src/KafkaFlow.Admin.WebApi/Adapters/ConsumerResponseAdapter.cs +++ b/src/KafkaFlow.Admin.WebApi/Adapters/ConsumerResponseAdapter.cs @@ -1,7 +1,5 @@ namespace KafkaFlow.Admin.WebApi.Adapters { - using System; - using System.Linq; using KafkaFlow.Admin.WebApi.Contracts; using KafkaFlow.Consumers; diff --git a/src/KafkaFlow.Admin.WebApi/Contracts/GroupResponse.cs b/src/KafkaFlow.Admin.WebApi/Contracts/GroupResponse.cs index 007d0c72a..4669f2fc4 100644 --- a/src/KafkaFlow.Admin.WebApi/Contracts/GroupResponse.cs +++ b/src/KafkaFlow.Admin.WebApi/Contracts/GroupResponse.cs @@ -2,7 +2,6 @@ namespace KafkaFlow.Admin.WebApi.Contracts { using System.Collections.Generic; using System.ComponentModel.DataAnnotations; - using KafkaFlow.Consumers; using Newtonsoft.Json; /// diff --git a/src/KafkaFlow.Admin.WebApi/Contracts/GroupsResponse.cs b/src/KafkaFlow.Admin.WebApi/Contracts/GroupsResponse.cs index 60ece5aa4..79e97c03c 100644 --- a/src/KafkaFlow.Admin.WebApi/Contracts/GroupsResponse.cs +++ b/src/KafkaFlow.Admin.WebApi/Contracts/GroupsResponse.cs @@ -1,7 +1,6 @@ namespace KafkaFlow.Admin.WebApi.Contracts { using System.Collections.Generic; - using KafkaFlow.Consumers; /// /// The response of the consumer groups diff --git a/src/KafkaFlow.Admin.WebApi/Controllers/ConsumersController.cs b/src/KafkaFlow.Admin.WebApi/Controllers/ConsumersController.cs index 557645965..7ef6f33f3 100644 --- a/src/KafkaFlow.Admin.WebApi/Controllers/ConsumersController.cs +++ b/src/KafkaFlow.Admin.WebApi/Controllers/ConsumersController.cs @@ -3,7 +3,6 @@ namespace KafkaFlow.Admin.WebApi.Controllers using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; - using KafkaFlow.Admin.Messages; using KafkaFlow.Admin.WebApi.Adapters; using KafkaFlow.Admin.WebApi.Contracts; using KafkaFlow.Consumers; diff --git a/src/KafkaFlow.Admin.WebApi/Controllers/GroupsController.cs b/src/KafkaFlow.Admin.WebApi/Controllers/GroupsController.cs index 5424b5d31..0ed3a5b2a 100644 --- a/src/KafkaFlow.Admin.WebApi/Controllers/GroupsController.cs +++ b/src/KafkaFlow.Admin.WebApi/Controllers/GroupsController.cs @@ -3,7 +3,6 @@ namespace KafkaFlow.Admin.WebApi.Controllers using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; - using KafkaFlow.Admin.Messages; using KafkaFlow.Admin.WebApi.Adapters; using KafkaFlow.Admin.WebApi.Contracts; using KafkaFlow.Consumers; diff --git a/src/KafkaFlow.Compressor.Gzip/GzipMessageCompressor.cs b/src/KafkaFlow.Compressor.Gzip/GzipMessageCompressor.cs index f1fef5ebd..bcc46d9ae 100644 --- a/src/KafkaFlow.Compressor.Gzip/GzipMessageCompressor.cs +++ b/src/KafkaFlow.Compressor.Gzip/GzipMessageCompressor.cs @@ -1,6 +1,5 @@ namespace KafkaFlow.Compressor.Gzip { - using System; using System.IO; using System.IO.Compression; diff --git a/src/KafkaFlow.Compressor/ConfigurationBuilderExtensions.cs b/src/KafkaFlow.Compressor/ConfigurationBuilderExtensions.cs index 204f5311e..1f748f112 100644 --- a/src/KafkaFlow.Compressor/ConfigurationBuilderExtensions.cs +++ b/src/KafkaFlow.Compressor/ConfigurationBuilderExtensions.cs @@ -1,6 +1,5 @@ namespace KafkaFlow.Compressor { - using System; using KafkaFlow.Configuration; /// diff --git a/src/KafkaFlow.IntegrationTests/CompressionSerializationTest.cs b/src/KafkaFlow.IntegrationTests/CompressionSerializationTest.cs index 4358ebe05..02be99616 100644 --- a/src/KafkaFlow.IntegrationTests/CompressionSerializationTest.cs +++ b/src/KafkaFlow.IntegrationTests/CompressionSerializationTest.cs @@ -10,7 +10,6 @@ namespace KafkaFlow.IntegrationTests using KafkaFlow.IntegrationTests.Core.Handlers; using KafkaFlow.IntegrationTests.Core.Messages; using KafkaFlow.IntegrationTests.Core.Producers; - using KafkaFlow.Producers; [TestClass] public class CompressionSerializationTest diff --git a/src/KafkaFlow.IntegrationTests/CompressionTest.cs b/src/KafkaFlow.IntegrationTests/CompressionTest.cs index 6e4898344..86b45d4a1 100644 --- a/src/KafkaFlow.IntegrationTests/CompressionTest.cs +++ b/src/KafkaFlow.IntegrationTests/CompressionTest.cs @@ -9,7 +9,6 @@ namespace KafkaFlow.IntegrationTests using KafkaFlow.IntegrationTests.Core; using KafkaFlow.IntegrationTests.Core.Handlers; using KafkaFlow.IntegrationTests.Core.Producers; - using KafkaFlow.Producers; [TestClass] public class CompressionTest diff --git a/src/KafkaFlow.IntegrationTests/ConsumerTest.cs b/src/KafkaFlow.IntegrationTests/ConsumerTest.cs index c762ff527..d80752cf3 100644 --- a/src/KafkaFlow.IntegrationTests/ConsumerTest.cs +++ b/src/KafkaFlow.IntegrationTests/ConsumerTest.cs @@ -11,7 +11,6 @@ namespace KafkaFlow.IntegrationTests using KafkaFlow.IntegrationTests.Core.Handlers; using KafkaFlow.IntegrationTests.Core.Messages; using KafkaFlow.IntegrationTests.Core.Producers; - using KafkaFlow.Producers; [TestClass] public class ConsumerTest diff --git a/src/KafkaFlow.UnitTests/OffsetCommitterTests.cs b/src/KafkaFlow.UnitTests/OffsetCommitterTests.cs index 71b8c44c8..1df3b351c 100644 --- a/src/KafkaFlow.UnitTests/OffsetCommitterTests.cs +++ b/src/KafkaFlow.UnitTests/OffsetCommitterTests.cs @@ -3,10 +3,8 @@ namespace KafkaFlow.UnitTests using System; using System.Collections.Generic; using System.Linq; - using System.Threading; using System.Threading.Tasks; using Confluent.Kafka; - using FluentAssertions; using KafkaFlow.Consumers; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; From 569fb99893d94029118cf6b14fd6059d525bbce7 Mon Sep 17 00:00:00 2001 From: Filipe Esch Date: Tue, 19 Sep 2023 15:37:53 +0100 Subject: [PATCH 10/20] docs: add dynamic workers documentation --- .../_category_.json | 8 +++ .../consumer-lag-based-worker-balancer.md | 52 +++++++++++++++++++ .../dynamic-workers-configuration.md | 46 ++++++++++++++++ 3 files changed, 106 insertions(+) create mode 100644 website/docs/guides/consumers/built-in-workers-algorithms/_category_.json create mode 100644 website/docs/guides/consumers/built-in-workers-algorithms/consumer-lag-based-worker-balancer.md create mode 100644 website/docs/guides/consumers/dynamic-workers-configuration.md diff --git a/website/docs/guides/consumers/built-in-workers-algorithms/_category_.json b/website/docs/guides/consumers/built-in-workers-algorithms/_category_.json new file mode 100644 index 000000000..c43922f18 --- /dev/null +++ b/website/docs/guides/consumers/built-in-workers-algorithms/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "Built-in Dynamic Workers Algorithms", + "position": 4, + "link": { + "type": "generated-index" + } + } + \ No newline at end of file diff --git a/website/docs/guides/consumers/built-in-workers-algorithms/consumer-lag-based-worker-balancer.md b/website/docs/guides/consumers/built-in-workers-algorithms/consumer-lag-based-worker-balancer.md new file mode 100644 index 000000000..d41b32073 --- /dev/null +++ b/website/docs/guides/consumers/built-in-workers-algorithms/consumer-lag-based-worker-balancer.md @@ -0,0 +1,52 @@ +--- +sidebar_position: 1 +--- + +# Consumer Lag-Based Worker Balancer + +The `WithConsumerLagWorkerBalancer` method in KafkaFlow is a powerful feature that allows you to dynamically calculate the number of workers for each application instance based on the consumer's lag. This feature is designed to optimize message processing, especially in scenarios where some application instances have more partitions and naturally need to deal with higher message throughput. By adjusting the number of workers based on message lag, this feature helps ensure efficient message processing and load balancing across all application instances. + +In this documentation, you'll find an overview of how this feature works, a use case example, and step-by-step instructions on how to configure it. + +:::info +This method replaces the call of `WithWorkersCount` in the consumer's setup. +::: + +## Use Case Example + +### Balancing Message Lag Across Application Instances + +Consider a scenario where you have a Kafka consumer application deployed in a distributed environment. In this environment, some application instances may have more partitions assigned to them, resulting in a higher message throughput potential. However, variations in message lag across partitions can lead to uneven workloads. + +Here's how the `WithConsumerLagWorkerBalancer` feature can help: + +- **Total Workers**: You specify the `totalWorkers`, which represents the total number of workers to be distributed across all application instances. + +- **Minimum and Maximum Instance Workers**: You set the `minInstanceWorkers` and `maxInstanceWorkers` parameters, defining the minimum and maximum number of workers allowed for each application instance. + +- **Evaluation Interval**: You define an `evaluationInterval` that determines how often the number of workers should be recalculated based on the consumer's lag. + +With this configuration, the `WithConsumerLagWorkerBalancer` feature dynamically adjusts the number of worker threads for each application instance based on the lag in the Kafka topic. Application instances with partitions experiencing higher lag will have more workers allocated to help balance the message lag across all instances. + +### Benefits in Elastic Infrastructure + +This feature is particularly valuable in elastic infrastructure environments like Kubernetes, where you need to manage the total number of workers across all application instances to prevent overloading dependencies. By dynamically adjusting worker counts, the feature ensures that each instance scales its resources efficiently, improving overall application performance and resource utilization. + +## How to Configure + +Configuring Consumer Lag-Based Worker Balancer is straightforward with the fluent interface provided by KafkaFlow. Here's a simple example: + +```csharp +.AddConsumer( + consumer => consumer + ... + .WithConsumerLagWorkerBalancer( + 50, // The total number of workers to be distributed across all application instances. + 3, // The minimum number of workers for each application instance. + 20) // The maximum number of workers for each application instance. + ... + ) +) +``` + +With this configuration, KafkaFlow will dynamically adjust the number of worker threads for each application instance, ensuring efficient message processing while considering the lag in the Kafka topic. This feature provides a powerful way to optimize resource allocation in your Kafka-based applications, making them more adaptive to varying message loads and distribution across partitions. diff --git a/website/docs/guides/consumers/dynamic-workers-configuration.md b/website/docs/guides/consumers/dynamic-workers-configuration.md new file mode 100644 index 000000000..3941d13bb --- /dev/null +++ b/website/docs/guides/consumers/dynamic-workers-configuration.md @@ -0,0 +1,46 @@ +--- +sidebar_position: 3 +--- + +# Dynamic Worker Configuration + +In this section, we will learn how Dynamic Worker Configuration works and how to configure it. In version 3 of KafkaFlow, we have introduced a new feature that allows you to dynamically configure the number of workers for a specific consumer based on a custom algorithm. This feature enables greater flexibility in managing worker threads, as each application instance can have a different number of workers, depending on the algorithm you define. + +This documentation page explains how to use and configure this feature effectively. + +## Use Case Example + +Imagine a scenario where your application's message load varies throughout the day. During peak hours, you want to allocate more worker threads to process messages quickly, and during off-peak hours, you want to reduce the number of worker threads to save resources. This dynamic adjustment can be achieved using the custom dynamic worker configuration feature. + +## How to Configure + +Configuring Dynamic Worker Configuration is straightforward with the fluent interface provided by KafkaFlow. Here's a simple example: + +```csharp +.AddConsumer( + consumer => consumer + ... + .WithWorkersCount( + (context, resolver) => + { + // Implement a custom logic to calculate the number of workers + if (IsPeakHour(DateTime.UtcNow)) + { + return Task.FromResult(10); // High worker count during peak hours + } + else + { + return Task.FromResult(2); // Lower worker count during off-peak hours + } + }, + TimeSpan.FromMinutes(15)); // Evaluate the worker count every 15 minutes + ... + ) +) +``` + +In this example, the number of worker threads is adjusted dynamically based on whether it's a peak hour or off-peak hour. You can implement your custom logic in the `WithWorkersCount`` method to suit your application's specific requirements. + +That's it! Your KafkaFlow consumer will now dynamically adjust the number of worker threads based on your custom logic and the specified evaluation interval. + +This feature provides a powerful way to optimize resource utilization and throughput in your Kafka-based applications. From 8c01d8c4a67a650cef5f1fe21c0552d66d2bc8c1 Mon Sep 17 00:00:00 2001 From: Ailton Silva Date: Tue, 3 Oct 2023 09:59:42 -0300 Subject: [PATCH 11/20] feat: add event notification feature --- .../Consumers/IWorker.cs | 16 +- .../Consumers/WorkerStoppedSubject.cs | 19 -- .../Consumers/WorkerStoppingSubject.cs | 19 -- .../Observer/ISubject.cs | 17 -- .../Observer/ISubjectObserver.cs | 18 -- .../Observer/Subject.cs | 53 ----- src/KafkaFlow.Abstractions/VoidObject.cs | 17 -- .../BatchConsumeMiddleware.cs | 10 +- .../BatchConsumeMiddlewareTests.cs | 2 +- src/KafkaFlow.UnitTests/EventTests.cs | 204 ++++++++++++++++++ src/KafkaFlow/ConsumerManagerFactory.cs | 2 +- src/KafkaFlow/Consumers/ConsumerWorker.cs | 29 ++- src/KafkaFlow/Consumers/ConsumerWorkerPool.cs | 9 +- .../FreeWorkerDistributionStrategy.cs | 2 +- .../Consumers/WorkerPoolStoppedSubject.cs | 12 -- src/KafkaFlow/MiddlewareExecutor.cs | 8 +- 16 files changed, 234 insertions(+), 203 deletions(-) delete mode 100644 src/KafkaFlow.Abstractions/Consumers/WorkerStoppedSubject.cs delete mode 100644 src/KafkaFlow.Abstractions/Consumers/WorkerStoppingSubject.cs delete mode 100644 src/KafkaFlow.Abstractions/Observer/ISubject.cs delete mode 100644 src/KafkaFlow.Abstractions/Observer/ISubjectObserver.cs delete mode 100644 src/KafkaFlow.Abstractions/Observer/Subject.cs delete mode 100644 src/KafkaFlow.Abstractions/VoidObject.cs create mode 100644 src/KafkaFlow.UnitTests/EventTests.cs delete mode 100644 src/KafkaFlow/Consumers/WorkerPoolStoppedSubject.cs diff --git a/src/KafkaFlow.Abstractions/Consumers/IWorker.cs b/src/KafkaFlow.Abstractions/Consumers/IWorker.cs index a90dc7209..f54a374ac 100644 --- a/src/KafkaFlow.Abstractions/Consumers/IWorker.cs +++ b/src/KafkaFlow.Abstractions/Consumers/IWorker.cs @@ -1,8 +1,5 @@ namespace KafkaFlow { - using System; - using KafkaFlow.Observer; - /// /// Represents the interface of a internal worker /// @@ -14,19 +11,18 @@ public interface IWorker int Id { get; } /// - /// This handler is called immediately after a worker completes the consumption of a message + /// Gets the subject for worker stopping events where observers can subscribe to receive notifications. /// - /// to be executed - void OnTaskCompleted(Action handler); + IEvent WorkerStopping { get; } /// - /// Gets the subject for worker stopping events where observers can subscribe to receive notifications. + /// Gets the subject for worker stopped events where observers can subscribe to receive notifications. /// - ISubject WorkerStopping { get; } + IEvent WorkerStopped { get; } /// - /// Gets the subject for worker stopped events where observers can subscribe to receive notifications. + /// Gets the subject for worker consumption completed events where observers can subscribe to receive notifications. /// - ISubject WorkerStopped { get; } + IEvent WorkerProcessingEnded { get; } } } diff --git a/src/KafkaFlow.Abstractions/Consumers/WorkerStoppedSubject.cs b/src/KafkaFlow.Abstractions/Consumers/WorkerStoppedSubject.cs deleted file mode 100644 index 4d92d1908..000000000 --- a/src/KafkaFlow.Abstractions/Consumers/WorkerStoppedSubject.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace KafkaFlow -{ - using KafkaFlow.Observer; - - /// - /// Represents a subject specific to worker stopped events where observers can subscribe to receive notifications. - /// - public class WorkerStoppedSubject : Subject - { - /// - /// Initializes a new instance of the class. - /// - /// The log handler object to be used - public WorkerStoppedSubject(ILogHandler logHandler) - : base(logHandler) - { - } - } -} diff --git a/src/KafkaFlow.Abstractions/Consumers/WorkerStoppingSubject.cs b/src/KafkaFlow.Abstractions/Consumers/WorkerStoppingSubject.cs deleted file mode 100644 index 816ce5f5f..000000000 --- a/src/KafkaFlow.Abstractions/Consumers/WorkerStoppingSubject.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace KafkaFlow -{ - using KafkaFlow.Observer; - - /// - /// Represents a subject specific to worker stopping events where observers can subscribe to receive notifications. - /// - public class WorkerStoppingSubject : Subject - { - /// - /// Initializes a new instance of the class. - /// - /// The log handler object to be used - public WorkerStoppingSubject(ILogHandler logHandler) - : base(logHandler) - { - } - } -} diff --git a/src/KafkaFlow.Abstractions/Observer/ISubject.cs b/src/KafkaFlow.Abstractions/Observer/ISubject.cs deleted file mode 100644 index 669d24591..000000000 --- a/src/KafkaFlow.Abstractions/Observer/ISubject.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace KafkaFlow.Observer -{ - /// - /// Represents a subject in the observer design pattern that can be observed by observers. - /// - /// The type of the subject. - /// An argument type that will be passed to the observers - public interface ISubject - where TSubject : Subject - { - /// - /// Subscribes an observer to the subject. - /// - /// The observer to subscribe. - void Subscribe(ISubjectObserver observer); - } -} diff --git a/src/KafkaFlow.Abstractions/Observer/ISubjectObserver.cs b/src/KafkaFlow.Abstractions/Observer/ISubjectObserver.cs deleted file mode 100644 index 223cd863f..000000000 --- a/src/KafkaFlow.Abstractions/Observer/ISubjectObserver.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace KafkaFlow.Observer -{ - using System.Threading.Tasks; - - /// - /// Represents an observer in the observer design pattern that can receive notifications from a subject. - /// - /// The type of the subject. - /// An argument type that will be passed to the observers - public interface ISubjectObserver - { - /// - /// Called when a notification is received from the subject. - /// - /// A task representing the asynchronous notification handling. - Task OnNotification(TSubject subject, TArg arg); - } -} diff --git a/src/KafkaFlow.Abstractions/Observer/Subject.cs b/src/KafkaFlow.Abstractions/Observer/Subject.cs deleted file mode 100644 index 31fb1bfe9..000000000 --- a/src/KafkaFlow.Abstractions/Observer/Subject.cs +++ /dev/null @@ -1,53 +0,0 @@ -namespace KafkaFlow.Observer -{ - using System; - using System.Collections.Generic; - using System.Threading.Tasks; - - /// - /// A generic implementation that should be extended to help the use of the notification system. - /// - /// The type of the subject. - /// An argument type that will be passed to the observers - public abstract class Subject : ISubject - where TSubject : Subject - { - private readonly ILogHandler logHandler; - private readonly List> observers = new(); - - /// - /// Initializes a new instance of the class. - /// - /// The log handler object to be used - protected Subject(ILogHandler logHandler) - { - this.logHandler = logHandler; - } - - /// - /// Subscribes an observer to the subject, allowing it to receive notifications. - /// - /// The observer to subscribe. - public void Subscribe(ISubjectObserver observer) => this.observers.Add(observer); - - /// - /// Notifies all subscribed observers asynchronously. - /// - /// The parameter passed by the client. - /// A task representing the asynchronous notification operation. - public async Task NotifyAsync(TArg arg) - { - foreach (var observer in this.observers) - { - try - { - await observer.OnNotification((TSubject)this, arg); - } - catch (Exception e) - { - this.logHandler.Error("Error notifying observer", e, new { Subject = this.GetType().Name }); - } - } - } - } -} diff --git a/src/KafkaFlow.Abstractions/VoidObject.cs b/src/KafkaFlow.Abstractions/VoidObject.cs deleted file mode 100644 index d59912d4c..000000000 --- a/src/KafkaFlow.Abstractions/VoidObject.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace KafkaFlow; - -/// -/// A type that represents an empty object that should be ignored -/// -public class VoidObject -{ - /// - /// Gets the unique instance value - /// - public static readonly VoidObject Value = new(); - - private VoidObject() - { - // Empty - } -} diff --git a/src/KafkaFlow.BatchConsume/BatchConsumeMiddleware.cs b/src/KafkaFlow.BatchConsume/BatchConsumeMiddleware.cs index 70cc87530..a6f0621df 100644 --- a/src/KafkaFlow.BatchConsume/BatchConsumeMiddleware.cs +++ b/src/KafkaFlow.BatchConsume/BatchConsumeMiddleware.cs @@ -7,12 +7,8 @@ using System.Threading.Tasks; using KafkaFlow.Configuration; using KafkaFlow.Consumers; - using KafkaFlow.Observer; - internal class BatchConsumeMiddleware - : IMessageMiddleware, - ISubjectObserver, - IDisposable + internal class BatchConsumeMiddleware : IMessageMiddleware, IDisposable { private readonly SemaphoreSlim dispatchSemaphore = new(1, 1); @@ -37,7 +33,7 @@ public BatchConsumeMiddleware( this.batch = new(batchSize); this.consumerConfiguration = middlewareContext.Consumer.Configuration; - middlewareContext.Worker.WorkerStopped.Subscribe(this); + middlewareContext.Worker.WorkerStopped.Subscribe(() => this.TriggerDispatchAndWaitAsync()); } public async Task Invoke(IMessageContext context, MiddlewareDelegate next) @@ -67,8 +63,6 @@ public async Task Invoke(IMessageContext context, MiddlewareDelegate next) } } - public async Task OnNotification(WorkerStoppedSubject subject, VoidObject arg) => await this.TriggerDispatchAndWaitAsync(); - public void Dispose() { this.dispatchTask?.Dispose(); diff --git a/src/KafkaFlow.UnitTests/BatchConsume/BatchConsumeMiddlewareTests.cs b/src/KafkaFlow.UnitTests/BatchConsume/BatchConsumeMiddlewareTests.cs index e55e85ae8..2269db974 100644 --- a/src/KafkaFlow.UnitTests/BatchConsume/BatchConsumeMiddlewareTests.cs +++ b/src/KafkaFlow.UnitTests/BatchConsume/BatchConsumeMiddlewareTests.cs @@ -51,7 +51,7 @@ public void Setup() workerMock .SetupGet(x => x.WorkerStopped) - .Returns(new WorkerStoppedSubject(this.logHandlerMock.Object)); + .Returns(new Event(this.logHandlerMock.Object)); consumerConfigurationMock .SetupGet(x => x.AutoMessageCompletion) diff --git a/src/KafkaFlow.UnitTests/EventTests.cs b/src/KafkaFlow.UnitTests/EventTests.cs new file mode 100644 index 000000000..53aabdee0 --- /dev/null +++ b/src/KafkaFlow.UnitTests/EventTests.cs @@ -0,0 +1,204 @@ +namespace KafkaFlow.UnitTests +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + + [TestClass] + public class EventTests + { + private readonly Event target; + private readonly Event typedTarget; + + public EventTests() + { + var log = new Mock(); + this.target = new Event(log.Object); + this.typedTarget = new Event(log.Object); + } + + [TestMethod] + public async Task FireAsync_EventSubscribed_CallDelegateWithSuccess() + { + // Arrange + var numberOfCalls = 0; + + this.target.Subscribe(() => + { + numberOfCalls++; + return Task.CompletedTask; + }); + + // Act + await this.target.FireAsync(); + + // Assert + Assert.AreEqual(1, numberOfCalls); + } + + [TestMethod] + public async Task FireAsync_EventWithMultipleObservers_CallAllDelegatesWithSuccess() + { + // Arrange + var numberOfCalls = 0; + + this.target.Subscribe(() => + { + numberOfCalls++; + return Task.CompletedTask; + }); + + this.target.Subscribe(() => + { + numberOfCalls++; + return Task.CompletedTask; + }); + + // Act + await this.target.FireAsync(); + + // Assert + Assert.AreEqual(2, numberOfCalls); + } + + [TestMethod] + public async Task FireAsync_EventWithMultipleObserversAndErrors_CallAllDelegatesAndContinueWithoutErrors() + { + // Arrange + var numberOfCalls = 0; + + this.target.Subscribe(() => throw new NotImplementedException()); + + this.target.Subscribe(() => + { + numberOfCalls++; + return Task.CompletedTask; + }); + + // Act + await this.target.FireAsync(); + + // Assert + Assert.AreEqual(1, numberOfCalls); + } + + [TestMethod] + public async Task FireAsync_EventSubscribedWithArgument_CallDelegateWithSuccess() + { + // Arrange + var expectedArgument = Guid.NewGuid().ToString(); + var receivedArgument = string.Empty; + + this.typedTarget.Subscribe(arg => + { + receivedArgument = arg; + return Task.CompletedTask; + }); + + // Act + await this.typedTarget.FireAsync(expectedArgument); + + // Assert + Assert.AreEqual(expectedArgument, receivedArgument); + } + + [TestMethod] + public async Task FireAsync_EventWithMultipleObserversAndArgument_CallAllDelegatesWithSuccess() + { + // Arrange + var expectedArgument = Guid.NewGuid().ToString(); + var receivedArguments = new List(); + + this.typedTarget.Subscribe(arg => + { + receivedArguments.Add(arg); + return Task.CompletedTask; + }); + + this.typedTarget.Subscribe(arg => + { + receivedArguments.Add(arg); + return Task.CompletedTask; + }); + + // Act + await this.typedTarget.FireAsync(expectedArgument); + + // Assert + Assert.AreEqual(2, receivedArguments.Count); + Assert.IsTrue(receivedArguments.All(x => x == expectedArgument)); + } + + [TestMethod] + public async Task FireAsync_TypedEventWithMultipleObserversAndErrors_CallAllDelegatesAndContinueWithoutErrors() + { + // Arrange + var numberOfCalls = 0; + + this.typedTarget.Subscribe(_ => throw new NotImplementedException()); + + this.typedTarget.Subscribe(_ => + { + numberOfCalls++; + return Task.CompletedTask; + }); + + // Act + await this.typedTarget.FireAsync(Guid.NewGuid().ToString()); + + // Assert + Assert.AreEqual(1, numberOfCalls); + } + + [TestMethod] + public async Task FireAsync_DuplicatedEventHandler_CallHandlerOnce() + { + // Arrange + var expectedArgument = Guid.NewGuid().ToString(); + var receivedArguments = new List(); + + Func handler = (arg) => + { + receivedArguments.Add(arg); + return Task.CompletedTask; + }; + + this.typedTarget.Subscribe(handler); + this.typedTarget.Subscribe(handler); + + // Act + await this.typedTarget.FireAsync(expectedArgument); + + // Assert + Assert.AreEqual(1, receivedArguments.Count); + Assert.IsTrue(receivedArguments.All(x => x == expectedArgument)); + } + + [TestMethod] + public async Task FireAsync_UnsubscribeEventHandler_DoesNotCallHandler() + { + // Arrange + var expectedArgument = Guid.NewGuid().ToString(); + var receivedArguments = new List(); + + Func handler = (arg) => + { + receivedArguments.Add(arg); + return Task.CompletedTask; + }; + + var subscription = this.typedTarget.Subscribe(handler); + + subscription.Cancel(); + + // Act + await this.typedTarget.FireAsync(expectedArgument); + + // Assert + Assert.AreEqual(0, receivedArguments.Count); + } + } +} diff --git a/src/KafkaFlow/ConsumerManagerFactory.cs b/src/KafkaFlow/ConsumerManagerFactory.cs index a3c752bc2..33bce7adb 100644 --- a/src/KafkaFlow/ConsumerManagerFactory.cs +++ b/src/KafkaFlow/ConsumerManagerFactory.cs @@ -22,7 +22,7 @@ public IConsumerManager Create(IConsumerConfiguration configuration, IDependency configuration, logHandler); - consumerWorkerPool.WorkerPoolStopped.Subscribe(middlewareExecutor); + consumerWorkerPool.WorkerPoolStopped.Subscribe(() => middlewareExecutor.OnWorkerPoolStopped()); var feeder = new WorkerPoolFeeder( consumer, diff --git a/src/KafkaFlow/Consumers/ConsumerWorker.cs b/src/KafkaFlow/Consumers/ConsumerWorker.cs index 81ade8577..ea0dfa6c1 100644 --- a/src/KafkaFlow/Consumers/ConsumerWorker.cs +++ b/src/KafkaFlow/Consumers/ConsumerWorker.cs @@ -4,7 +4,6 @@ namespace KafkaFlow.Consumers using System.Threading; using System.Threading.Channels; using System.Threading.Tasks; - using KafkaFlow.Observer; internal class ConsumerWorker : IConsumerWorker { @@ -16,12 +15,12 @@ internal class ConsumerWorker : IConsumerWorker private readonly Channel messagesBuffer; - private readonly WorkerStoppingSubject workerStoppingSubject; - private readonly WorkerStoppedSubject workerStoppedSubject; + private readonly Event workerStoppingEvent; + private readonly Event workerStoppedEvent; + private readonly Event workerProcessingEnded; private CancellationTokenSource stopCancellationTokenSource; private Task backgroundTask; - private Action onMessageFinishedHandler; public ConsumerWorker( IConsumer consumer, @@ -38,8 +37,9 @@ public ConsumerWorker( this.messagesBuffer = Channel.CreateBounded(consumer.Configuration.BufferSize); this.globalEvents = consumerDependencyResolver.Resolve(); - this.workerStoppingSubject = new(logHandler); - this.workerStoppedSubject = new(logHandler); + this.workerStoppingEvent = new(logHandler); + this.workerStoppedEvent = new(logHandler); + this.workerProcessingEnded = new Event(logHandler); var middlewareContext = this.workerDependencyResolverScope.Resolver.Resolve(); @@ -53,9 +53,11 @@ public ConsumerWorker( public IDependencyResolver WorkerDependencyResolver => this.workerDependencyResolverScope.Resolver; - public ISubject WorkerStopping => this.workerStoppingSubject; + public IEvent WorkerStopping => this.workerStoppingEvent; - public ISubject WorkerStopped => this.workerStoppedSubject; + public IEvent WorkerStopped => this.workerStoppedEvent; + + public IEvent WorkerProcessingEnded => this.workerProcessingEnded; public ValueTask EnqueueAsync( IMessageContext context, @@ -100,7 +102,7 @@ public Task StartAsync() public async Task StopAsync() { - await this.workerStoppingSubject.NotifyAsync(VoidObject.Value); + await this.workerStoppingEvent.FireAsync(); this.messagesBuffer.Writer.TryComplete(); @@ -111,7 +113,7 @@ public async Task StopAsync() await this.backgroundTask.ConfigureAwait(false); - await this.workerStoppedSubject.NotifyAsync(VoidObject.Value); + await this.workerStoppedEvent.FireAsync(); } public void Dispose() @@ -121,11 +123,6 @@ public void Dispose() this.stopCancellationTokenSource.Dispose(); } - public void OnTaskCompleted(Action handler) - { - this.onMessageFinishedHandler = handler; - } - private async Task ProcessMessageAsync(IMessageContext context, CancellationToken cancellationToken) { try @@ -166,7 +163,7 @@ await this.middlewareExecutor context.ConsumerContext.Complete(); } - this.onMessageFinishedHandler?.Invoke(); + await this.workerProcessingEnded.FireAsync(context); } } catch (Exception ex) diff --git a/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs b/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs index f82f494b9..5774d2c9e 100644 --- a/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs +++ b/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs @@ -7,7 +7,6 @@ namespace KafkaFlow.Consumers using System.Threading.Tasks; using Confluent.Kafka; using KafkaFlow.Configuration; - using KafkaFlow.Observer; internal class ConsumerWorkerPool : IConsumerWorkerPool { @@ -18,7 +17,7 @@ internal class ConsumerWorkerPool : IConsumerWorkerPool private readonly Factory distributionStrategyFactory; private readonly IOffsetCommitter offsetCommitter; - private readonly WorkerPoolStoppedSubject workerPoolStoppedSubject; + private readonly Event workerPoolStoppedSubject; private TaskCompletionSource startedTaskSource = new(); private List workers = new(); @@ -38,7 +37,7 @@ public ConsumerWorkerPool( this.middlewareExecutor = middlewareExecutor; this.logHandler = logHandler; this.distributionStrategyFactory = consumerConfiguration.DistributionStrategyFactory; - this.workerPoolStoppedSubject = new(logHandler); + this.workerPoolStoppedSubject = new Event(logHandler); this.offsetCommitter = consumer.Configuration.NoStoreOffsets ? new NullOffsetCommitter() : @@ -52,7 +51,7 @@ public ConsumerWorkerPool( public int CurrentWorkersCount { get; private set; } - public ISubject WorkerPoolStopped => this.workerPoolStoppedSubject; + public IEvent WorkerPoolStopped => this.workerPoolStoppedSubject; public async Task StartAsync(IReadOnlyCollection partitions, int workersCount) { @@ -121,7 +120,7 @@ public async Task StopAsync() this.offsetManager = null; - await this.workerPoolStoppedSubject.NotifyAsync(VoidObject.Value); + await this.workerPoolStoppedSubject.FireAsync(); await this.offsetCommitter.StopAsync(); } diff --git a/src/KafkaFlow/Consumers/DistributionStrategies/FreeWorkerDistributionStrategy.cs b/src/KafkaFlow/Consumers/DistributionStrategies/FreeWorkerDistributionStrategy.cs index 4db57f195..e9761ae90 100644 --- a/src/KafkaFlow/Consumers/DistributionStrategies/FreeWorkerDistributionStrategy.cs +++ b/src/KafkaFlow/Consumers/DistributionStrategies/FreeWorkerDistributionStrategy.cs @@ -18,7 +18,7 @@ public void Init(IReadOnlyList workers) { foreach (var worker in workers) { - worker.OnTaskCompleted(() => this.freeWorkers.Writer.WriteAsync(worker)); + worker.WorkerProcessingEnded.Subscribe(_ => Task.FromResult(this.freeWorkers.Writer.WriteAsync(worker))); this.freeWorkers.Writer.TryWrite(worker); } } diff --git a/src/KafkaFlow/Consumers/WorkerPoolStoppedSubject.cs b/src/KafkaFlow/Consumers/WorkerPoolStoppedSubject.cs deleted file mode 100644 index 0a3a5124c..000000000 --- a/src/KafkaFlow/Consumers/WorkerPoolStoppedSubject.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace KafkaFlow.Consumers -{ - using KafkaFlow.Observer; - - internal class WorkerPoolStoppedSubject : Subject - { - public WorkerPoolStoppedSubject(ILogHandler logHandler) - : base(logHandler) - { - } - } -} diff --git a/src/KafkaFlow/MiddlewareExecutor.cs b/src/KafkaFlow/MiddlewareExecutor.cs index b759d6c37..b2710ff9d 100644 --- a/src/KafkaFlow/MiddlewareExecutor.cs +++ b/src/KafkaFlow/MiddlewareExecutor.cs @@ -5,12 +5,8 @@ namespace KafkaFlow using System.Linq; using System.Threading.Tasks; using KafkaFlow.Configuration; - using KafkaFlow.Consumers; - using KafkaFlow.Observer; - internal class MiddlewareExecutor - : IMiddlewareExecutor, - ISubjectObserver + internal class MiddlewareExecutor : IMiddlewareExecutor { private readonly IReadOnlyList configurations; @@ -27,7 +23,7 @@ public Task Execute(IMessageContext context, Func nextOpe return this.ExecuteDefinition(0, context, nextOperation); } - public Task OnNotification(WorkerPoolStoppedSubject subject, VoidObject arg) + internal Task OnWorkerPoolStopped() { this.workersMiddlewares.Clear(); return Task.CompletedTask; From fc8a0b39fc2f82772acd1ee516ff7a1a39fadd8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sousa?= Date: Tue, 19 Sep 2023 22:17:18 +0100 Subject: [PATCH 12/20] refactor!: merge projects into core framework --- .github/workflows/deploy-website.yml | 12 --- .github/workflows/test-deploy-website.yml | 12 --- .../KafkaFlow.Sample.BatchOperations.csproj | 2 - .../PrintConsoleMiddleware.cs | 2 +- .../Program.cs | 5 +- ...KafkaFlow.Sample.ConsumerThrottling.csproj | 2 - .../Program.cs | 4 +- .../KafkaFlow.Sample.FlowControl.csproj | 1 - .../KafkaFlow.Sample.FlowControl/Program.cs | 2 +- ...fkaFlow.Sample.PauseConsumerOnError.csproj | 2 - .../MessageHandler.cs | 2 +- .../Program.cs | 3 +- .../Handlers/AvroMessageHandler.cs | 31 +++--- .../Handlers/AvroMessageHandler2.cs | 2 +- .../Handlers/JsonMessageHandler.cs | 2 +- .../Handlers/ProtobufMessageHandler.cs | 2 +- .../KafkaFlow.Sample.SchemaRegistry.csproj | 2 - .../Program.cs | 5 +- .../KafkaFlow.Sample/KafkaFlow.Sample.csproj | 3 - .../KafkaFlow.Sample/PrintConsoleHandler.cs | 2 +- samples/KafkaFlow.Sample/Program.cs | 3 +- .../{IMessageCompressor.cs => ICompressor.cs} | 9 +- src/KafkaFlow.Abstractions/IDecompressor.cs | 15 +++ src/KafkaFlow.Abstractions/IDeserializer.cs | 21 ++++ .../IMessageHandler.cs | 2 +- src/KafkaFlow.Abstractions/ISerializer.cs | 10 -- .../ISerializerContext.cs | 2 +- .../ClusterConfigurationBuilderExtensions.cs | 5 +- .../ChangeConsumerWorkersCountHandler.cs | 2 +- .../ConsumerTelemetryMetricHandler.cs | 2 +- .../Handlers/PauseConsumerByNameHandler.cs | 2 +- .../Handlers/PauseConsumersByGroupHandler.cs | 2 +- .../Handlers/ResetConsumerOffsetHandler.cs | 2 +- .../Handlers/RestartConsumerByNameHandler.cs | 2 +- .../Handlers/ResumeConsumerByNameHandler.cs | 2 +- .../Handlers/ResumeConsumersByGroupHandler.cs | 2 +- .../RewindConsumerOffsetToDateTimeHandler.cs | 2 +- .../Handlers/StartConsumerByNameHandler.cs | 2 +- .../Handlers/StopConsumerByNameHandler.cs | 2 +- src/KafkaFlow.Admin/KafkaFlow.Admin.csproj | 2 - src/KafkaFlow.BatchConsume/AssemblyInfo.cs | 4 - .../KafkaFlow.BatchConsume.csproj | 15 --- .../GzipMessageCompressor.cs | 16 +--- .../GzipMessageDecompressor.cs | 25 +++++ .../KafkaFlow.Compressor.Gzip.csproj | 1 + .../ConfigurationBuilderExtensions.cs | 68 ------------- .../KafkaFlow.Compressor.csproj | 13 --- .../Core/Bootstrapper.cs | 22 ++--- .../Core/Handlers/AvroMessageHandler.cs | 2 +- .../Handlers/ConfluentJsonMessageHandler.cs | 2 +- .../ConfluentProtobufMessageHandler.cs | 2 +- .../Core/Handlers/MessageHandler.cs | 2 +- .../Core/Handlers/MessageHandler1.cs | 2 +- .../Core/Handlers/MessageHandler2.cs | 2 +- .../Core/Handlers/PauseResumeHandler.cs | 2 +- .../GlobalEventsTest.cs | 2 +- .../KafkaFlow.IntegrationTests.csproj | 3 - .../OpenTelemetryTests.cs | 2 +- .../KafkaFlow.SchemaRegistry.csproj | 4 +- .../SchemaRegistryTypeResolver.cs | 1 + .../JsonCoreDeserializer.cs | 40 ++++++++ .../JsonCoreSerializer.cs | 11 +-- .../NewtonsoftJsonDeserializer.cs | 51 ++++++++++ .../NewtonsoftJsonSerializer.cs | 16 ---- .../ProtobufNetDeserializer.cs | 19 ++++ .../ProtobufNetSerializer.cs | 7 -- .../ConfluentAvroDeserializer.cs | 42 ++++++++ .../ConfluentAvroSerializer.cs | 14 --- .../ConsumerConfigurationBuilderExtensions.cs | 7 +- ...alizer.SchemaRegistry.ConfluentAvro.csproj | 1 - .../ProducerConfigurationBuilderExtensions.cs | 1 + .../ConfluentJsonDeserializer.cs | 39 ++++++++ .../ConfluentJsonSerializer.cs | 14 --- .../ConsumerConfigurationBuilderExtensions.cs | 5 +- ...alizer.SchemaRegistry.ConfluentJson.csproj | 1 - .../ProducerConfigurationBuilderExtensions.cs | 1 + .../ConfluentProtobufDeserializer.cs | 27 ++++++ .../ConfluentProtobufSerializer.cs | 14 --- .../ConsumerConfigurationBuilderExtensions.cs | 7 +- ...er.SchemaRegistry.ConfluentProtobuf.csproj | 1 - .../ProducerConfigurationBuilderExtensions.cs | 1 + .../KafkaFlow.Serializer.csproj | 19 ---- src/KafkaFlow.TypedHandler/AssemblyInfo.cs | 4 - .../ConfigurationBuilderExtensions.cs | 34 ------- .../KafkaFlow.TypedHandler.csproj | 13 --- .../BatchConsumeMiddlewareTests.cs | 2 +- .../CompressorConsumerMiddlewareTests.cs | 18 ++-- .../CompressorProducerMiddlewareTests.cs | 8 +- .../KafkaFlow.UnitTests.csproj | 4 - .../NewtonsoftJsonDeserializerTests.cs | 48 ++++++++++ .../NewtonsoftJsonSerializerTests.cs | 17 ---- .../SerializerConsumerMiddlewareTests.cs | 22 +++-- .../SerializerProducerMiddlewareTests.cs | 2 + .../TypedHandler/HandlerTypeMappingTests.cs | 2 +- src/KafkaFlow.sln | 28 ------ .../Batching}/BatchConsumeMessageContext.cs | 2 +- .../Batching}/BatchConsumeMiddleware.cs | 2 +- .../Batching/BatchingExtensions.cs} | 9 +- .../ConfigurationBuilderExtensions.cs | 87 +++++++++++++++++ src/KafkaFlow/KafkaFlow.csproj | 2 + .../CompressorProducerMiddleware.cs | 8 +- .../DecompressorConsumerMiddleware.cs} | 16 ++-- ...ConsumerMiddlewareConfigurationBuilder.cs} | 96 ++++++++++--------- .../ProducerMiddlewareConfigurationBuilder.cs | 2 + .../DeserializerConsumerMiddleware.cs} | 19 ++-- .../Resolvers}/DefaultTypeResolver.cs | 2 +- .../Resolvers}/IMessageTypeResolver.cs | 2 +- .../Resolvers}/SingleMessageTypeResolver.cs | 2 +- .../SerializerProducerMiddleware.cs | 3 +- .../TypedHandlerConfiguration.cs | 2 +- .../TypedHandlerConfigurationBuilder.cs | 4 +- .../TypedHandler}/HandlerExecutor.cs | 2 +- .../TypedHandler}/HandlerTypeMapping.cs | 2 +- .../TypedHandler}/TypedHandlerMiddleware.cs | 3 +- 114 files changed, 626 insertions(+), 558 deletions(-) rename src/KafkaFlow.Abstractions/{IMessageCompressor.cs => ICompressor.cs} (55%) create mode 100644 src/KafkaFlow.Abstractions/IDecompressor.cs create mode 100644 src/KafkaFlow.Abstractions/IDeserializer.cs rename src/{KafkaFlow.TypedHandler => KafkaFlow.Abstractions}/IMessageHandler.cs (96%) delete mode 100644 src/KafkaFlow.BatchConsume/AssemblyInfo.cs delete mode 100644 src/KafkaFlow.BatchConsume/KafkaFlow.BatchConsume.csproj create mode 100644 src/KafkaFlow.Compressor.Gzip/GzipMessageDecompressor.cs delete mode 100644 src/KafkaFlow.Compressor/ConfigurationBuilderExtensions.cs delete mode 100644 src/KafkaFlow.Compressor/KafkaFlow.Compressor.csproj create mode 100644 src/KafkaFlow.Serializer.JsonCore/JsonCoreDeserializer.cs create mode 100644 src/KafkaFlow.Serializer.NewtonsoftJson/NewtonsoftJsonDeserializer.cs create mode 100644 src/KafkaFlow.Serializer.ProtobufNet/ProtobufNetDeserializer.cs create mode 100644 src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConfluentAvroDeserializer.cs create mode 100644 src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ConfluentJsonDeserializer.cs create mode 100644 src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConfluentProtobufDeserializer.cs delete mode 100644 src/KafkaFlow.Serializer/KafkaFlow.Serializer.csproj delete mode 100644 src/KafkaFlow.TypedHandler/AssemblyInfo.cs delete mode 100644 src/KafkaFlow.TypedHandler/ConfigurationBuilderExtensions.cs delete mode 100644 src/KafkaFlow.TypedHandler/KafkaFlow.TypedHandler.csproj create mode 100644 src/KafkaFlow.UnitTests/Serializers/NewtonsoftJsonDeserializerTests.cs rename src/{KafkaFlow.BatchConsume => KafkaFlow/Batching}/BatchConsumeMessageContext.cs (97%) rename src/{KafkaFlow.BatchConsume => KafkaFlow/Batching}/BatchConsumeMiddleware.cs (99%) rename src/{KafkaFlow.BatchConsume/BatchConsumeExtensions.cs => KafkaFlow/Batching/BatchingExtensions.cs} (90%) rename src/{KafkaFlow.Compressor => KafkaFlow/Middlewares/Compressor}/CompressorProducerMiddleware.cs (79%) rename src/{KafkaFlow.Compressor/CompressorConsumerMiddleware.cs => KafkaFlow/Middlewares/Compressor/DecompressorConsumerMiddleware.cs} (57%) rename src/{KafkaFlow.Serializer/ConsumerMiddlewareConfigurationBuilderExtensions.cs => KafkaFlow/Middlewares/Serializer/Configuration/ConsumerMiddlewareConfigurationBuilder.cs} (62%) rename src/{KafkaFlow.Serializer => KafkaFlow/Middlewares/Serializer/Configuration}/ProducerMiddlewareConfigurationBuilder.cs (98%) rename src/{KafkaFlow.Serializer/SerializerConsumerMiddleware.cs => KafkaFlow/Middlewares/Serializer/DeserializerConsumerMiddleware.cs} (78%) rename src/{KafkaFlow.Serializer => KafkaFlow/Middlewares/Serializer/Resolvers}/DefaultTypeResolver.cs (94%) rename src/{KafkaFlow.Serializer => KafkaFlow/Middlewares/Serializer/Resolvers}/IMessageTypeResolver.cs (93%) rename src/{KafkaFlow.Serializer => KafkaFlow/Middlewares/Serializer/Resolvers}/SingleMessageTypeResolver.cs (94%) rename src/{KafkaFlow.Serializer => KafkaFlow/Middlewares/Serializer}/SerializerProducerMiddleware.cs (95%) rename src/{KafkaFlow.TypedHandler => KafkaFlow/Middlewares/TypedHandler/Configuration}/TypedHandlerConfiguration.cs (79%) rename src/{KafkaFlow.TypedHandler => KafkaFlow/Middlewares/TypedHandler/Configuration}/TypedHandlerConfigurationBuilder.cs (98%) rename src/{KafkaFlow.TypedHandler => KafkaFlow/Middlewares/TypedHandler}/HandlerExecutor.cs (95%) rename src/{KafkaFlow.TypedHandler => KafkaFlow/Middlewares/TypedHandler}/HandlerTypeMapping.cs (95%) rename src/{KafkaFlow.TypedHandler => KafkaFlow/Middlewares/TypedHandler}/TypedHandlerMiddleware.cs (93%) diff --git a/.github/workflows/deploy-website.yml b/.github/workflows/deploy-website.yml index c0680e8f1..c05e1d333 100644 --- a/.github/workflows/deploy-website.yml +++ b/.github/workflows/deploy-website.yml @@ -36,12 +36,6 @@ jobs: - run: xmldocmd-docusaurus ./drop/KafkaFlow.Admin.dll website/docs/reference/KafkaFlow.Admin --type-folders shell: bash - - run: xmldocmd-docusaurus ./drop/KafkaFlow.BatchConsume.dll website/docs/reference/KafkaFlow.BatchConsume --type-folders - shell: bash - - - run: xmldocmd-docusaurus ./drop/KafkaFlow.Compressor.dll website/docs/reference/KafkaFlow.Compressor --type-folders - shell: bash - - run: xmldocmd-docusaurus ./drop/KafkaFlow.Extensions.Hosting.dll website/docs/reference/KafkaFlow.Extensions.Hosting --type-folders shell: bash @@ -57,9 +51,6 @@ jobs: - run: xmldocmd-docusaurus ./drop/KafkaFlow.SchemaRegistry.dll website/docs/reference/KafkaFlow.SchemaRegistry --type-folders shell: bash - - run: xmldocmd-docusaurus ./drop/KafkaFlow.Serializer.dll website/docs/reference/KafkaFlow.Serializer --type-folders - shell: bash - - run: xmldocmd-docusaurus ./drop/KafkaFlow.Serializer.JsonCore.dll website/docs/reference/KafkaFlow.Serializer.JsonCore --type-folders shell: bash @@ -78,9 +69,6 @@ jobs: - run: xmldocmd-docusaurus ./drop/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf.dll website/docs/reference/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf --type-folders shell: bash - - run: xmldocmd-docusaurus ./drop/KafkaFlow.TypedHandler.dll website/docs/reference/KafkaFlow.TypedHandler --type-folders - shell: bash - - run: xmldocmd-docusaurus ./drop/KafkaFlow.Unity.dll website/docs/reference/KafkaFlow.Unity --type-folders shell: bash diff --git a/.github/workflows/test-deploy-website.yml b/.github/workflows/test-deploy-website.yml index 33863e76b..7d925c2c3 100644 --- a/.github/workflows/test-deploy-website.yml +++ b/.github/workflows/test-deploy-website.yml @@ -30,12 +30,6 @@ jobs: - run: xmldocmd-docusaurus ./drop/KafkaFlow.Admin.dll website/docs/reference/KafkaFlow.Admin --type-folders shell: bash - - run: xmldocmd-docusaurus ./drop/KafkaFlow.BatchConsume.dll website/docs/reference/KafkaFlow.BatchConsume --type-folders - shell: bash - - - run: xmldocmd-docusaurus ./drop/KafkaFlow.Compressor.dll website/docs/reference/KafkaFlow.Compressor --type-folders - shell: bash - - run: xmldocmd-docusaurus ./drop/KafkaFlow.Extensions.Hosting.dll website/docs/reference/KafkaFlow.Extensions.Hosting --type-folders shell: bash @@ -51,9 +45,6 @@ jobs: - run: xmldocmd-docusaurus ./drop/KafkaFlow.SchemaRegistry.dll website/docs/reference/KafkaFlow.SchemaRegistry --type-folders shell: bash - - run: xmldocmd-docusaurus ./drop/KafkaFlow.Serializer.dll website/docs/reference/KafkaFlow.Serializer --type-folders - shell: bash - - run: xmldocmd-docusaurus ./drop/KafkaFlow.Serializer.JsonCore.dll website/docs/reference/KafkaFlow.Serializer.JsonCore --type-folders shell: bash @@ -72,9 +63,6 @@ jobs: - run: xmldocmd-docusaurus ./drop/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf.dll website/docs/reference/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf --type-folders shell: bash - - run: xmldocmd-docusaurus ./drop/KafkaFlow.TypedHandler.dll website/docs/reference/KafkaFlow.TypedHandler --type-folders - shell: bash - - run: xmldocmd-docusaurus ./drop/KafkaFlow.Unity.dll website/docs/reference/KafkaFlow.Unity --type-folders shell: bash diff --git a/samples/KafkaFlow.Sample.BatchOperations/KafkaFlow.Sample.BatchOperations.csproj b/samples/KafkaFlow.Sample.BatchOperations/KafkaFlow.Sample.BatchOperations.csproj index f51dbe58e..6336785ab 100644 --- a/samples/KafkaFlow.Sample.BatchOperations/KafkaFlow.Sample.BatchOperations.csproj +++ b/samples/KafkaFlow.Sample.BatchOperations/KafkaFlow.Sample.BatchOperations.csproj @@ -22,11 +22,9 @@ - - diff --git a/samples/KafkaFlow.Sample.BatchOperations/PrintConsoleMiddleware.cs b/samples/KafkaFlow.Sample.BatchOperations/PrintConsoleMiddleware.cs index 317098b43..438689b7a 100644 --- a/samples/KafkaFlow.Sample.BatchOperations/PrintConsoleMiddleware.cs +++ b/samples/KafkaFlow.Sample.BatchOperations/PrintConsoleMiddleware.cs @@ -1,7 +1,7 @@ using System; using System.Linq; using System.Threading.Tasks; -using KafkaFlow.BatchConsume; +using KafkaFlow.Batching; namespace KafkaFlow.Sample.BatchOperations; diff --git a/samples/KafkaFlow.Sample.BatchOperations/Program.cs b/samples/KafkaFlow.Sample.BatchOperations/Program.cs index 1515286ed..65fc08fc2 100644 --- a/samples/KafkaFlow.Sample.BatchOperations/Program.cs +++ b/samples/KafkaFlow.Sample.BatchOperations/Program.cs @@ -1,7 +1,6 @@ using System; using System.Linq; using KafkaFlow; -using KafkaFlow.BatchConsume; using KafkaFlow.Producers; using KafkaFlow.Sample.BatchOperations; using KafkaFlow.Serializer; @@ -35,8 +34,8 @@ .WithWorkersCount(1) .AddMiddlewares( middlewares => middlewares - .AddSerializer() - .BatchConsume(10, TimeSpan.FromSeconds(10)) + .AddDeserializer() + .AddBatching(10, TimeSpan.FromSeconds(10)) .Add() ) ) diff --git a/samples/KafkaFlow.Sample.ConsumerThrottling/KafkaFlow.Sample.ConsumerThrottling.csproj b/samples/KafkaFlow.Sample.ConsumerThrottling/KafkaFlow.Sample.ConsumerThrottling.csproj index 25d305383..ba75e35c2 100644 --- a/samples/KafkaFlow.Sample.ConsumerThrottling/KafkaFlow.Sample.ConsumerThrottling.csproj +++ b/samples/KafkaFlow.Sample.ConsumerThrottling/KafkaFlow.Sample.ConsumerThrottling.csproj @@ -22,8 +22,6 @@ - - diff --git a/samples/KafkaFlow.Sample.ConsumerThrottling/Program.cs b/samples/KafkaFlow.Sample.ConsumerThrottling/Program.cs index 3e6699c70..d6396e9dc 100644 --- a/samples/KafkaFlow.Sample.ConsumerThrottling/Program.cs +++ b/samples/KafkaFlow.Sample.ConsumerThrottling/Program.cs @@ -48,7 +48,7 @@ The ThrottleConsumer mechanism works by checking the lag of "consumerA" every 1 .WithWorkersCount(1) .AddMiddlewares( middlewares => middlewares - .AddSerializer() + .AddDeserializer() .Add() ) ) @@ -68,7 +68,7 @@ The ThrottleConsumer mechanism works by checking the lag of "consumerA" every 1 .AddAction(a => a.AboveThreshold(10).ApplyDelay(1_000)) .AddAction(a => a.AboveThreshold(20).ApplyDelay(5_000)) .AddAction(a => a.AboveThreshold(30).ApplyDelay(10_000))) - .AddSerializer() + .AddDeserializer() .Add() ) ) diff --git a/samples/KafkaFlow.Sample.FlowControl/KafkaFlow.Sample.FlowControl.csproj b/samples/KafkaFlow.Sample.FlowControl/KafkaFlow.Sample.FlowControl.csproj index e4a1914e1..20946db23 100644 --- a/samples/KafkaFlow.Sample.FlowControl/KafkaFlow.Sample.FlowControl.csproj +++ b/samples/KafkaFlow.Sample.FlowControl/KafkaFlow.Sample.FlowControl.csproj @@ -26,7 +26,6 @@ - diff --git a/samples/KafkaFlow.Sample.FlowControl/Program.cs b/samples/KafkaFlow.Sample.FlowControl/Program.cs index 87a783ce1..26ed362fd 100644 --- a/samples/KafkaFlow.Sample.FlowControl/Program.cs +++ b/samples/KafkaFlow.Sample.FlowControl/Program.cs @@ -35,7 +35,7 @@ .WithWorkersCount(1) .AddMiddlewares( m => m - .AddSingleTypeSerializer() + .AddSingleTypeDeserializer() .Add() ) ); diff --git a/samples/KafkaFlow.Sample.PauseConsumerOnError/KafkaFlow.Sample.PauseConsumerOnError.csproj b/samples/KafkaFlow.Sample.PauseConsumerOnError/KafkaFlow.Sample.PauseConsumerOnError.csproj index f6f6d1e42..7a55c9fd7 100644 --- a/samples/KafkaFlow.Sample.PauseConsumerOnError/KafkaFlow.Sample.PauseConsumerOnError.csproj +++ b/samples/KafkaFlow.Sample.PauseConsumerOnError/KafkaFlow.Sample.PauseConsumerOnError.csproj @@ -14,8 +14,6 @@ - - diff --git a/samples/KafkaFlow.Sample.PauseConsumerOnError/MessageHandler.cs b/samples/KafkaFlow.Sample.PauseConsumerOnError/MessageHandler.cs index 114dae019..77b597265 100644 --- a/samples/KafkaFlow.Sample.PauseConsumerOnError/MessageHandler.cs +++ b/samples/KafkaFlow.Sample.PauseConsumerOnError/MessageHandler.cs @@ -1,4 +1,4 @@ -using KafkaFlow.TypedHandler; +using KafkaFlow.Middlewares.TypedHandler; namespace KafkaFlow.Sample.PauseConsumerOnError; diff --git a/samples/KafkaFlow.Sample.PauseConsumerOnError/Program.cs b/samples/KafkaFlow.Sample.PauseConsumerOnError/Program.cs index 478aa838b..35a2ce5b6 100644 --- a/samples/KafkaFlow.Sample.PauseConsumerOnError/Program.cs +++ b/samples/KafkaFlow.Sample.PauseConsumerOnError/Program.cs @@ -2,7 +2,6 @@ using KafkaFlow.Producers; using KafkaFlow.Sample.PauseConsumerOnError; using KafkaFlow.Serializer; -using KafkaFlow.TypedHandler; using Microsoft.Extensions.DependencyInjection; var services = new ServiceCollection(); @@ -33,7 +32,7 @@ middlewares => middlewares .Add() - .AddSerializer() + .AddDeserializer() .AddTypedHandlers(h => h.AddHandler()) ) ) diff --git a/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/AvroMessageHandler.cs b/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/AvroMessageHandler.cs index f7f70e702..0893f1225 100644 --- a/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/AvroMessageHandler.cs +++ b/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/AvroMessageHandler.cs @@ -1,20 +1,21 @@ -namespace KafkaFlow.Sample.SchemaRegistry.Handlers; - -using System; -using System.Threading.Tasks; -using global::SchemaRegistry; -using TypedHandler; - -public class AvroMessageHandler : IMessageHandler +namespace KafkaFlow.Sample.SchemaRegistry.Handlers { - public Task Handle(IMessageContext context, AvroLogMessage message) + using System; + using System.Threading.Tasks; + using KafkaFlow.Middlewares.TypedHandler; + using global::SchemaRegistry; + + public class AvroMessageHandler : IMessageHandler { - Console.WriteLine( - "Partition: {0} | Offset: {1} | Message: {2} | Avro", - context.ConsumerContext.Partition, - context.ConsumerContext.Offset, - message.Severity.ToString()); + public Task Handle(IMessageContext context, AvroLogMessage message) + { + Console.WriteLine( + "Partition: {0} | Offset: {1} | Message: {2} | Avro", + context.ConsumerContext.Partition, + context.ConsumerContext.Offset, + message.Severity.ToString()); - return Task.CompletedTask; + return Task.CompletedTask; + } } } \ No newline at end of file diff --git a/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/AvroMessageHandler2.cs b/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/AvroMessageHandler2.cs index ab35a60e3..65660f5f3 100644 --- a/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/AvroMessageHandler2.cs +++ b/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/AvroMessageHandler2.cs @@ -3,7 +3,7 @@ using System; using System.Threading.Tasks; using global::SchemaRegistry; -using TypedHandler; +using KafkaFlow.Middlewares.TypedHandler; public class AvroMessageHandler2 : IMessageHandler { diff --git a/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/JsonMessageHandler.cs b/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/JsonMessageHandler.cs index f17b98a8b..39b446434 100644 --- a/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/JsonMessageHandler.cs +++ b/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/JsonMessageHandler.cs @@ -3,7 +3,7 @@ using System; using System.Threading.Tasks; using global::SchemaRegistry; -using TypedHandler; +using KafkaFlow.Middlewares.TypedHandler; public class JsonMessageHandler : IMessageHandler { diff --git a/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/ProtobufMessageHandler.cs b/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/ProtobufMessageHandler.cs index aee7c1cd9..e1158c9c8 100644 --- a/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/ProtobufMessageHandler.cs +++ b/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/ProtobufMessageHandler.cs @@ -1,7 +1,7 @@  using System; using System.Threading.Tasks; -using KafkaFlow.TypedHandler; +using KafkaFlow.Middlewares.TypedHandler; using SchemaRegistry; namespace KafkaFlow.Sample.SchemaRegistry.Handlers; diff --git a/samples/KafkaFlow.Sample.SchemaRegistry/KafkaFlow.Sample.SchemaRegistry.csproj b/samples/KafkaFlow.Sample.SchemaRegistry/KafkaFlow.Sample.SchemaRegistry.csproj index 220139cdf..ddef38718 100644 --- a/samples/KafkaFlow.Sample.SchemaRegistry/KafkaFlow.Sample.SchemaRegistry.csproj +++ b/samples/KafkaFlow.Sample.SchemaRegistry/KafkaFlow.Sample.SchemaRegistry.csproj @@ -24,8 +24,6 @@ - - diff --git a/samples/KafkaFlow.Sample.SchemaRegistry/Program.cs b/samples/KafkaFlow.Sample.SchemaRegistry/Program.cs index bc539818d..926879042 100644 --- a/samples/KafkaFlow.Sample.SchemaRegistry/Program.cs +++ b/samples/KafkaFlow.Sample.SchemaRegistry/Program.cs @@ -5,7 +5,6 @@ using KafkaFlow; using KafkaFlow.Producers; using KafkaFlow.Sample.SchemaRegistry.Handlers; -using KafkaFlow.TypedHandler; using Microsoft.Extensions.DependencyInjection; using SchemaRegistry; @@ -74,7 +73,7 @@ .WithAutoOffsetReset(AutoOffsetReset.Latest) .AddMiddlewares( middlewares => middlewares - .AddSchemaRegistryAvroSerializer() + .AddSchemaRegistryAvroDeserializer() .AddTypedHandlers( handlers => handlers .AddHandler() @@ -103,7 +102,7 @@ .WithAutoOffsetReset(AutoOffsetReset.Latest) .AddMiddlewares( middlewares => middlewares - .AddSchemaRegistryProtobufSerializer() + .AddSchemaRegistryProtobufDeserializer() .AddTypedHandlers(handlers => handlers.AddHandler()) ) ) diff --git a/samples/KafkaFlow.Sample/KafkaFlow.Sample.csproj b/samples/KafkaFlow.Sample/KafkaFlow.Sample.csproj index dcf23e1b3..a6743af44 100644 --- a/samples/KafkaFlow.Sample/KafkaFlow.Sample.csproj +++ b/samples/KafkaFlow.Sample/KafkaFlow.Sample.csproj @@ -19,13 +19,10 @@ - - - diff --git a/samples/KafkaFlow.Sample/PrintConsoleHandler.cs b/samples/KafkaFlow.Sample/PrintConsoleHandler.cs index 11276440c..57a1a48b8 100644 --- a/samples/KafkaFlow.Sample/PrintConsoleHandler.cs +++ b/samples/KafkaFlow.Sample/PrintConsoleHandler.cs @@ -1,6 +1,6 @@ using System; using System.Threading.Tasks; -using KafkaFlow.TypedHandler; +using KafkaFlow.Middlewares.TypedHandler; namespace KafkaFlow.Sample; diff --git a/samples/KafkaFlow.Sample/Program.cs b/samples/KafkaFlow.Sample/Program.cs index 874962de1..b0be4f2c7 100644 --- a/samples/KafkaFlow.Sample/Program.cs +++ b/samples/KafkaFlow.Sample/Program.cs @@ -4,7 +4,6 @@ using KafkaFlow.Producers; using KafkaFlow.Sample; using KafkaFlow.Serializer; -using KafkaFlow.TypedHandler; using Microsoft.Extensions.DependencyInjection; var services = new ServiceCollection(); @@ -33,7 +32,7 @@ .WithWorkersCount(3) .AddMiddlewares( middlewares => middlewares - .AddSerializer() + .AddDeserializer() .AddTypedHandlers(h => h.AddHandler()) ) ) diff --git a/src/KafkaFlow.Abstractions/IMessageCompressor.cs b/src/KafkaFlow.Abstractions/ICompressor.cs similarity index 55% rename from src/KafkaFlow.Abstractions/IMessageCompressor.cs rename to src/KafkaFlow.Abstractions/ICompressor.cs index 53fffb40f..8b1d6a1b5 100644 --- a/src/KafkaFlow.Abstractions/IMessageCompressor.cs +++ b/src/KafkaFlow.Abstractions/ICompressor.cs @@ -3,7 +3,7 @@ namespace KafkaFlow /// /// Used to create a message compressor /// - public interface IMessageCompressor + public interface ICompressor { /// /// Compress the given message @@ -11,12 +11,5 @@ public interface IMessageCompressor /// The message to be compressed /// The compressed message byte[] Compress(byte[] message); - - /// - /// Decompress the given message - /// - /// The message to be decompressed - /// The decompressed message - byte[] Decompress(byte[] message); } } diff --git a/src/KafkaFlow.Abstractions/IDecompressor.cs b/src/KafkaFlow.Abstractions/IDecompressor.cs new file mode 100644 index 000000000..69e140ffb --- /dev/null +++ b/src/KafkaFlow.Abstractions/IDecompressor.cs @@ -0,0 +1,15 @@ +namespace KafkaFlow +{ + /// + /// Used to create a message decompressor + /// + public interface IDecompressor + { + /// + /// Decompress the given message + /// + /// The message to be decompressed + /// The decompressed message + byte[] Decompress(byte[] message); + } +} diff --git a/src/KafkaFlow.Abstractions/IDeserializer.cs b/src/KafkaFlow.Abstractions/IDeserializer.cs new file mode 100644 index 000000000..0ecfd2c86 --- /dev/null +++ b/src/KafkaFlow.Abstractions/IDeserializer.cs @@ -0,0 +1,21 @@ +namespace KafkaFlow +{ + using System; + using System.IO; + using System.Threading.Tasks; + + /// + /// Used to implement a message serializer + /// + public interface IDeserializer + { + /// + /// Deserializes the given message + /// + /// A stream to read the data to be deserialized + /// The type to be created + /// An object containing metadata + /// The deserialized message + Task DeserializeAsync(Stream input, Type type, ISerializerContext context); + } +} diff --git a/src/KafkaFlow.TypedHandler/IMessageHandler.cs b/src/KafkaFlow.Abstractions/IMessageHandler.cs similarity index 96% rename from src/KafkaFlow.TypedHandler/IMessageHandler.cs rename to src/KafkaFlow.Abstractions/IMessageHandler.cs index 7c7f181f8..611ba91f6 100644 --- a/src/KafkaFlow.TypedHandler/IMessageHandler.cs +++ b/src/KafkaFlow.Abstractions/IMessageHandler.cs @@ -1,4 +1,4 @@ -namespace KafkaFlow.TypedHandler +namespace KafkaFlow { using System.Threading.Tasks; diff --git a/src/KafkaFlow.Abstractions/ISerializer.cs b/src/KafkaFlow.Abstractions/ISerializer.cs index 0b0951997..23cd9b73a 100644 --- a/src/KafkaFlow.Abstractions/ISerializer.cs +++ b/src/KafkaFlow.Abstractions/ISerializer.cs @@ -1,6 +1,5 @@ namespace KafkaFlow { - using System; using System.IO; using System.Threading.Tasks; @@ -17,14 +16,5 @@ public interface ISerializer /// An object containing metadata /// The serialized message Task SerializeAsync(object message, Stream output, ISerializerContext context); - - /// - /// Deserializes the given message - /// - /// A stream to read the data to be deserialized - /// The type to be created - /// An object containing metadata - /// The deserialized message - Task DeserializeAsync(Stream input, Type type, ISerializerContext context); } } diff --git a/src/KafkaFlow.Abstractions/ISerializerContext.cs b/src/KafkaFlow.Abstractions/ISerializerContext.cs index 7c8d7a459..5fc5b42e9 100644 --- a/src/KafkaFlow.Abstractions/ISerializerContext.cs +++ b/src/KafkaFlow.Abstractions/ISerializerContext.cs @@ -1,7 +1,7 @@ namespace KafkaFlow { /// - /// A context that can have some metadata to help with serialization process + /// Context for serialization and deserialization operations. /// public interface ISerializerContext { diff --git a/src/KafkaFlow.Admin/Extensions/ClusterConfigurationBuilderExtensions.cs b/src/KafkaFlow.Admin/Extensions/ClusterConfigurationBuilderExtensions.cs index 4e8c00477..608649536 100644 --- a/src/KafkaFlow.Admin/Extensions/ClusterConfigurationBuilderExtensions.cs +++ b/src/KafkaFlow.Admin/Extensions/ClusterConfigurationBuilderExtensions.cs @@ -6,7 +6,6 @@ using KafkaFlow.Admin.Handlers; using KafkaFlow.Configuration; using KafkaFlow.Serializer; - using KafkaFlow.TypedHandler; /// /// No needed @@ -54,7 +53,7 @@ public static IClusterConfigurationBuilder EnableAdminMessages( .DisableManagement() .AddMiddlewares( middlewares => middlewares - .AddSerializer() + .AddDeserializer() .AddTypedHandlers( handlers => handlers .WithHandlerLifetime(InstanceLifetime.Singleton) @@ -123,7 +122,7 @@ public static IClusterConfigurationBuilder EnableTelemetry( .WithAutoOffsetReset(AutoOffsetReset.Latest) .AddMiddlewares( middlewares => middlewares - .AddSerializer() + .AddDeserializer() .AddTypedHandlers( handlers => handlers .WithHandlerLifetime(InstanceLifetime.Singleton) diff --git a/src/KafkaFlow.Admin/Handlers/ChangeConsumerWorkersCountHandler.cs b/src/KafkaFlow.Admin/Handlers/ChangeConsumerWorkersCountHandler.cs index 370f418c6..4dbf0f7a0 100644 --- a/src/KafkaFlow.Admin/Handlers/ChangeConsumerWorkersCountHandler.cs +++ b/src/KafkaFlow.Admin/Handlers/ChangeConsumerWorkersCountHandler.cs @@ -3,7 +3,7 @@ namespace KafkaFlow.Admin.Handlers using System.Threading.Tasks; using KafkaFlow.Admin.Messages; using KafkaFlow.Consumers; - using KafkaFlow.TypedHandler; + using KafkaFlow.Middlewares.TypedHandler; internal class ChangeConsumerWorkersCountHandler : IMessageHandler { diff --git a/src/KafkaFlow.Admin/Handlers/ConsumerTelemetryMetricHandler.cs b/src/KafkaFlow.Admin/Handlers/ConsumerTelemetryMetricHandler.cs index 0e7c038c9..e2b7fe36b 100644 --- a/src/KafkaFlow.Admin/Handlers/ConsumerTelemetryMetricHandler.cs +++ b/src/KafkaFlow.Admin/Handlers/ConsumerTelemetryMetricHandler.cs @@ -2,7 +2,7 @@ namespace KafkaFlow.Admin.Handlers { using System.Threading.Tasks; using KafkaFlow.Admin.Messages; - using KafkaFlow.TypedHandler; + using KafkaFlow.Middlewares.TypedHandler; internal class ConsumerTelemetryMetricHandler : IMessageHandler { diff --git a/src/KafkaFlow.Admin/Handlers/PauseConsumerByNameHandler.cs b/src/KafkaFlow.Admin/Handlers/PauseConsumerByNameHandler.cs index c8bd71843..9afc8efdf 100644 --- a/src/KafkaFlow.Admin/Handlers/PauseConsumerByNameHandler.cs +++ b/src/KafkaFlow.Admin/Handlers/PauseConsumerByNameHandler.cs @@ -5,7 +5,7 @@ namespace KafkaFlow.Admin.Handlers using KafkaFlow.Admin.Extensions; using KafkaFlow.Admin.Messages; using KafkaFlow.Consumers; - using KafkaFlow.TypedHandler; + using KafkaFlow.Middlewares.TypedHandler; internal class PauseConsumerByNameHandler : IMessageHandler { diff --git a/src/KafkaFlow.Admin/Handlers/PauseConsumersByGroupHandler.cs b/src/KafkaFlow.Admin/Handlers/PauseConsumersByGroupHandler.cs index a7aac4f2f..376393842 100644 --- a/src/KafkaFlow.Admin/Handlers/PauseConsumersByGroupHandler.cs +++ b/src/KafkaFlow.Admin/Handlers/PauseConsumersByGroupHandler.cs @@ -5,7 +5,7 @@ namespace KafkaFlow.Admin.Handlers using KafkaFlow.Admin.Extensions; using KafkaFlow.Admin.Messages; using KafkaFlow.Consumers; - using KafkaFlow.TypedHandler; + using KafkaFlow.Middlewares.TypedHandler; internal class PauseConsumersByGroupHandler : IMessageHandler { diff --git a/src/KafkaFlow.Admin/Handlers/ResetConsumerOffsetHandler.cs b/src/KafkaFlow.Admin/Handlers/ResetConsumerOffsetHandler.cs index ca732a741..2d9c60008 100644 --- a/src/KafkaFlow.Admin/Handlers/ResetConsumerOffsetHandler.cs +++ b/src/KafkaFlow.Admin/Handlers/ResetConsumerOffsetHandler.cs @@ -7,7 +7,7 @@ namespace KafkaFlow.Admin.Handlers using KafkaFlow.Admin.Extensions; using KafkaFlow.Admin.Messages; using KafkaFlow.Consumers; - using KafkaFlow.TypedHandler; + using KafkaFlow.Middlewares.TypedHandler; internal class ResetConsumerOffsetHandler : IMessageHandler { diff --git a/src/KafkaFlow.Admin/Handlers/RestartConsumerByNameHandler.cs b/src/KafkaFlow.Admin/Handlers/RestartConsumerByNameHandler.cs index 82316a519..3525bf490 100644 --- a/src/KafkaFlow.Admin/Handlers/RestartConsumerByNameHandler.cs +++ b/src/KafkaFlow.Admin/Handlers/RestartConsumerByNameHandler.cs @@ -3,7 +3,7 @@ namespace KafkaFlow.Admin.Handlers using System.Threading.Tasks; using KafkaFlow.Admin.Messages; using KafkaFlow.Consumers; - using KafkaFlow.TypedHandler; + using KafkaFlow.Middlewares.TypedHandler; internal class RestartConsumerByNameHandler : IMessageHandler { diff --git a/src/KafkaFlow.Admin/Handlers/ResumeConsumerByNameHandler.cs b/src/KafkaFlow.Admin/Handlers/ResumeConsumerByNameHandler.cs index dfbd14f11..e8eb336ff 100644 --- a/src/KafkaFlow.Admin/Handlers/ResumeConsumerByNameHandler.cs +++ b/src/KafkaFlow.Admin/Handlers/ResumeConsumerByNameHandler.cs @@ -5,7 +5,7 @@ namespace KafkaFlow.Admin.Handlers using KafkaFlow.Admin.Extensions; using KafkaFlow.Admin.Messages; using KafkaFlow.Consumers; - using KafkaFlow.TypedHandler; + using KafkaFlow.Middlewares.TypedHandler; internal class ResumeConsumerByNameHandler : IMessageHandler { diff --git a/src/KafkaFlow.Admin/Handlers/ResumeConsumersByGroupHandler.cs b/src/KafkaFlow.Admin/Handlers/ResumeConsumersByGroupHandler.cs index 5aa6f3898..553d2ca23 100644 --- a/src/KafkaFlow.Admin/Handlers/ResumeConsumersByGroupHandler.cs +++ b/src/KafkaFlow.Admin/Handlers/ResumeConsumersByGroupHandler.cs @@ -5,7 +5,7 @@ namespace KafkaFlow.Admin.Handlers using KafkaFlow.Admin.Extensions; using KafkaFlow.Admin.Messages; using KafkaFlow.Consumers; - using KafkaFlow.TypedHandler; + using KafkaFlow.Middlewares.TypedHandler; internal class ResumeConsumersByGroupHandler : IMessageHandler { diff --git a/src/KafkaFlow.Admin/Handlers/RewindConsumerOffsetToDateTimeHandler.cs b/src/KafkaFlow.Admin/Handlers/RewindConsumerOffsetToDateTimeHandler.cs index 83712ab40..b5895ef56 100644 --- a/src/KafkaFlow.Admin/Handlers/RewindConsumerOffsetToDateTimeHandler.cs +++ b/src/KafkaFlow.Admin/Handlers/RewindConsumerOffsetToDateTimeHandler.cs @@ -7,7 +7,7 @@ namespace KafkaFlow.Admin.Handlers using KafkaFlow.Admin.Extensions; using KafkaFlow.Admin.Messages; using KafkaFlow.Consumers; - using KafkaFlow.TypedHandler; + using KafkaFlow.Middlewares.TypedHandler; internal class RewindConsumerOffsetToDateTimeHandler : IMessageHandler { diff --git a/src/KafkaFlow.Admin/Handlers/StartConsumerByNameHandler.cs b/src/KafkaFlow.Admin/Handlers/StartConsumerByNameHandler.cs index 4189c2814..b7ad5fa08 100644 --- a/src/KafkaFlow.Admin/Handlers/StartConsumerByNameHandler.cs +++ b/src/KafkaFlow.Admin/Handlers/StartConsumerByNameHandler.cs @@ -3,7 +3,7 @@ namespace KafkaFlow.Admin.Handlers using System.Threading.Tasks; using KafkaFlow.Admin.Messages; using KafkaFlow.Consumers; - using KafkaFlow.TypedHandler; + using KafkaFlow.Middlewares.TypedHandler; internal class StartConsumerByNameHandler : IMessageHandler { diff --git a/src/KafkaFlow.Admin/Handlers/StopConsumerByNameHandler.cs b/src/KafkaFlow.Admin/Handlers/StopConsumerByNameHandler.cs index 203f4faf7..92a9fc0a0 100644 --- a/src/KafkaFlow.Admin/Handlers/StopConsumerByNameHandler.cs +++ b/src/KafkaFlow.Admin/Handlers/StopConsumerByNameHandler.cs @@ -3,7 +3,7 @@ namespace KafkaFlow.Admin.Handlers using System.Threading.Tasks; using KafkaFlow.Admin.Messages; using KafkaFlow.Consumers; - using KafkaFlow.TypedHandler; + using KafkaFlow.Middlewares.TypedHandler; internal class StopConsumerByNameHandler : IMessageHandler { diff --git a/src/KafkaFlow.Admin/KafkaFlow.Admin.csproj b/src/KafkaFlow.Admin/KafkaFlow.Admin.csproj index 58d220888..3b7ecf40f 100644 --- a/src/KafkaFlow.Admin/KafkaFlow.Admin.csproj +++ b/src/KafkaFlow.Admin/KafkaFlow.Admin.csproj @@ -9,8 +9,6 @@ - - diff --git a/src/KafkaFlow.BatchConsume/AssemblyInfo.cs b/src/KafkaFlow.BatchConsume/AssemblyInfo.cs deleted file mode 100644 index f8402e685..000000000 --- a/src/KafkaFlow.BatchConsume/AssemblyInfo.cs +++ /dev/null @@ -1,4 +0,0 @@ -using System.Runtime.CompilerServices; - -[assembly: InternalsVisibleTo("KafkaFlow.UnitTests")] -[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] diff --git a/src/KafkaFlow.BatchConsume/KafkaFlow.BatchConsume.csproj b/src/KafkaFlow.BatchConsume/KafkaFlow.BatchConsume.csproj deleted file mode 100644 index 8a6dcb8a2..000000000 --- a/src/KafkaFlow.BatchConsume/KafkaFlow.BatchConsume.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - netstandard2.0 - KafkaFlow.BatchConsume - A KafkaFlow middleware to consume messages in batches - - - - - - - - - diff --git a/src/KafkaFlow.Compressor.Gzip/GzipMessageCompressor.cs b/src/KafkaFlow.Compressor.Gzip/GzipMessageCompressor.cs index bcc46d9ae..3f795c6af 100644 --- a/src/KafkaFlow.Compressor.Gzip/GzipMessageCompressor.cs +++ b/src/KafkaFlow.Compressor.Gzip/GzipMessageCompressor.cs @@ -6,7 +6,7 @@ /// /// A GZIP message compressor /// - public class GzipMessageCompressor : IMessageCompressor + public class GzipMessageCompressor : ICompressor { /// public byte[] Compress(byte[] message) @@ -21,19 +21,5 @@ public byte[] Compress(byte[] message) return outputStream.ToArray(); } - - /// - public byte[] Decompress(byte[] message) - { - using var outputStream = new MemoryStream(); - using var inputStream = new MemoryStream(message); - - using (var gzipStream = new GZipStream(inputStream, CompressionMode.Decompress)) - { - gzipStream.CopyTo(outputStream); - } - - return outputStream.ToArray(); - } } } diff --git a/src/KafkaFlow.Compressor.Gzip/GzipMessageDecompressor.cs b/src/KafkaFlow.Compressor.Gzip/GzipMessageDecompressor.cs new file mode 100644 index 000000000..19baffaf0 --- /dev/null +++ b/src/KafkaFlow.Compressor.Gzip/GzipMessageDecompressor.cs @@ -0,0 +1,25 @@ +namespace KafkaFlow.Compressor.Gzip +{ + using System.IO; + using System.IO.Compression; + + /// + /// A GZIP message decompressor + /// + public class GzipMessageDecompressor : IDecompressor + { + /// + public byte[] Decompress(byte[] message) + { + using var outputStream = new MemoryStream(); + using var inputStream = new MemoryStream(message); + + using (var gzipStream = new GZipStream(inputStream, CompressionMode.Decompress)) + { + gzipStream.CopyTo(outputStream); + } + + return outputStream.ToArray(); + } + } +} diff --git a/src/KafkaFlow.Compressor.Gzip/KafkaFlow.Compressor.Gzip.csproj b/src/KafkaFlow.Compressor.Gzip/KafkaFlow.Compressor.Gzip.csproj index 54f7ece59..7d2c63f51 100644 --- a/src/KafkaFlow.Compressor.Gzip/KafkaFlow.Compressor.Gzip.csproj +++ b/src/KafkaFlow.Compressor.Gzip/KafkaFlow.Compressor.Gzip.csproj @@ -8,5 +8,6 @@ + \ No newline at end of file diff --git a/src/KafkaFlow.Compressor/ConfigurationBuilderExtensions.cs b/src/KafkaFlow.Compressor/ConfigurationBuilderExtensions.cs deleted file mode 100644 index 1f748f112..000000000 --- a/src/KafkaFlow.Compressor/ConfigurationBuilderExtensions.cs +++ /dev/null @@ -1,68 +0,0 @@ -namespace KafkaFlow.Compressor -{ - using KafkaFlow.Configuration; - - /// - /// Extension methods for and . - /// - public static class ConfigurationBuilderExtensions - { - /// - /// Registers a middleware to decompress the message - /// - /// The middleware configuration builder - /// The compressor type - /// - public static IConsumerMiddlewareConfigurationBuilder AddCompressor(this IConsumerMiddlewareConfigurationBuilder middlewares) - where T : class, IMessageCompressor - { - middlewares.DependencyConfigurator.AddTransient(); - return middlewares.AddCompressor(resolver => resolver.Resolve()); - } - - /// - /// Registers a middleware to decompress the message - /// - /// The middleware configuration builder - /// The compressor type that implements - /// A factory to create the instance - /// - public static IConsumerMiddlewareConfigurationBuilder AddCompressor( - this IConsumerMiddlewareConfigurationBuilder middlewares, - Factory factory) - where T : class, IMessageCompressor - { - return middlewares.Add(resolver => new CompressorConsumerMiddleware(factory(resolver))); - } - - /// - /// Registers a middleware to compress the message - /// It is highly recommended to use the producer native compression ('WithCompression()' method) instead of using the compressor middleware - /// - /// The middleware configuration builder - /// The compressor type that implements - /// - public static IProducerMiddlewareConfigurationBuilder AddCompressor(this IProducerMiddlewareConfigurationBuilder middlewares) - where T : class, IMessageCompressor - { - middlewares.DependencyConfigurator.AddTransient(); - return middlewares.AddCompressor(resolver => resolver.Resolve()); - } - - /// - /// Registers a middleware to compress the message - /// It is highly recommended to use the producer native compression ('WithCompression()' method) instead of using the compressor middleware - /// - /// The middleware configuration builder - /// The compressor type that implements - /// A factory to create the instance - /// - public static IProducerMiddlewareConfigurationBuilder AddCompressor( - this IProducerMiddlewareConfigurationBuilder middlewares, - Factory factory) - where T : class, IMessageCompressor - { - return middlewares.Add(resolver => new CompressorProducerMiddleware(factory(resolver))); - } - } -} diff --git a/src/KafkaFlow.Compressor/KafkaFlow.Compressor.csproj b/src/KafkaFlow.Compressor/KafkaFlow.Compressor.csproj deleted file mode 100644 index d9ceb3efe..000000000 --- a/src/KafkaFlow.Compressor/KafkaFlow.Compressor.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - netstandard2.0 - KafkaFlow.Compressor - Compression middleware for KafkaFlow - - - - - - - diff --git a/src/KafkaFlow.IntegrationTests/Core/Bootstrapper.cs b/src/KafkaFlow.IntegrationTests/Core/Bootstrapper.cs index f743478d6..23edee91c 100644 --- a/src/KafkaFlow.IntegrationTests/Core/Bootstrapper.cs +++ b/src/KafkaFlow.IntegrationTests/Core/Bootstrapper.cs @@ -9,7 +9,6 @@ namespace KafkaFlow.IntegrationTests.Core using global::Microsoft.Extensions.Configuration; using global::Microsoft.Extensions.DependencyInjection; using global::Microsoft.Extensions.Hosting; - using KafkaFlow.Compressor; using KafkaFlow.Compressor.Gzip; using KafkaFlow.IntegrationTests.Core.Handlers; using KafkaFlow.IntegrationTests.Core.Messages; @@ -17,7 +16,6 @@ namespace KafkaFlow.IntegrationTests.Core using KafkaFlow.IntegrationTests.Core.Producers; using KafkaFlow.Serializer; using KafkaFlow.Serializer.SchemaRegistry; - using KafkaFlow.TypedHandler; using AutoOffsetReset = KafkaFlow.AutoOffsetReset; internal static class Bootstrapper @@ -130,7 +128,7 @@ private static void SetupServices(HostBuilderContext context, IServiceCollection .WithConsumerConfig(defaultConfig) .AddMiddlewares( middlewares => middlewares - .AddSerializer() + .AddDeserializer() .AddTypedHandlers( handlers => handlers .WithHandlerLifetime(InstanceLifetime.Singleton) @@ -158,7 +156,7 @@ private static void SetupServices(HostBuilderContext context, IServiceCollection .WithConsumerConfig(defaultConfig) .AddMiddlewares( middlewares => middlewares - .AddSerializer() + .AddDeserializer() .AddTypedHandlers( handlers => handlers .WithHandlerLifetime(InstanceLifetime.Singleton) @@ -186,7 +184,7 @@ private static void SetupServices(HostBuilderContext context, IServiceCollection .WithConsumerConfig(defaultConfig) .AddMiddlewares( middlewares => middlewares - .AddSerializer() + .AddDeserializer() .AddTypedHandlers( handlers => handlers .WithHandlerLifetime(InstanceLifetime.Singleton) @@ -210,7 +208,7 @@ private static void SetupServices(HostBuilderContext context, IServiceCollection .WithAutoOffsetReset(AutoOffsetReset.Latest) .AddMiddlewares( middlewares => middlewares - .AddSingleTypeSerializer(typeof(TestMessage1)) + .AddSingleTypeDeserializer(typeof(TestMessage1)) .AddTypedHandlers( handlers => handlers @@ -231,7 +229,7 @@ private static void SetupServices(HostBuilderContext context, IServiceCollection }) .AddMiddlewares( middlewares => middlewares - .AddSingleTypeSerializer() + .AddSingleTypeDeserializer() .AddTypedHandlers( handlers => handlers @@ -246,7 +244,7 @@ private static void SetupServices(HostBuilderContext context, IServiceCollection .WithAutoOffsetReset(AutoOffsetReset.Latest) .AddMiddlewares( middlewares => middlewares - .AddSerializer() + .AddDeserializer() .AddTypedHandlers( handlers => handlers @@ -261,7 +259,7 @@ private static void SetupServices(HostBuilderContext context, IServiceCollection .WithAutoOffsetReset(AutoOffsetReset.Latest) .AddMiddlewares( middlewares => middlewares - .AddCompressor() + .AddDecompressor() .Add())) .AddConsumer( consumer => consumer @@ -272,7 +270,7 @@ private static void SetupServices(HostBuilderContext context, IServiceCollection .WithAutoOffsetReset(AutoOffsetReset.Latest) .AddMiddlewares( middlewares => middlewares - .AddSerializer(_ => new JsonCoreSerializer()) + .AddDeserializer(_ => new JsonCoreDeserializer()) .AddTypedHandlers( handlers => handlers @@ -288,8 +286,8 @@ private static void SetupServices(HostBuilderContext context, IServiceCollection .WithAutoCommitIntervalMs(1) .AddMiddlewares( middlewares => middlewares - .AddCompressor() - .AddSerializer() + .AddDecompressor() + .AddDeserializer() .AddTypedHandlers( handlers => handlers diff --git a/src/KafkaFlow.IntegrationTests/Core/Handlers/AvroMessageHandler.cs b/src/KafkaFlow.IntegrationTests/Core/Handlers/AvroMessageHandler.cs index 23994a0d9..feb76b1f8 100644 --- a/src/KafkaFlow.IntegrationTests/Core/Handlers/AvroMessageHandler.cs +++ b/src/KafkaFlow.IntegrationTests/Core/Handlers/AvroMessageHandler.cs @@ -1,7 +1,7 @@ namespace KafkaFlow.IntegrationTests.Core.Handlers { using System.Threading.Tasks; - using KafkaFlow.TypedHandler; + using KafkaFlow.Middlewares.TypedHandler; using MessageTypes; internal class AvroMessageHandler : IMessageHandler diff --git a/src/KafkaFlow.IntegrationTests/Core/Handlers/ConfluentJsonMessageHandler.cs b/src/KafkaFlow.IntegrationTests/Core/Handlers/ConfluentJsonMessageHandler.cs index f049242a5..22e12e1cc 100644 --- a/src/KafkaFlow.IntegrationTests/Core/Handlers/ConfluentJsonMessageHandler.cs +++ b/src/KafkaFlow.IntegrationTests/Core/Handlers/ConfluentJsonMessageHandler.cs @@ -2,7 +2,7 @@ namespace KafkaFlow.IntegrationTests.Core.Handlers { using System.Threading.Tasks; using KafkaFlow.IntegrationTests.Core.Messages; - using KafkaFlow.TypedHandler; + using KafkaFlow.Middlewares.TypedHandler; internal class ConfluentJsonMessageHandler : IMessageHandler { diff --git a/src/KafkaFlow.IntegrationTests/Core/Handlers/ConfluentProtobufMessageHandler.cs b/src/KafkaFlow.IntegrationTests/Core/Handlers/ConfluentProtobufMessageHandler.cs index 192e09bbb..697efca9f 100644 --- a/src/KafkaFlow.IntegrationTests/Core/Handlers/ConfluentProtobufMessageHandler.cs +++ b/src/KafkaFlow.IntegrationTests/Core/Handlers/ConfluentProtobufMessageHandler.cs @@ -2,7 +2,7 @@ namespace KafkaFlow.IntegrationTests.Core.Handlers { using System.Threading.Tasks; using KafkaFlow.IntegrationTests.Core.Messages; - using KafkaFlow.TypedHandler; + using KafkaFlow.Middlewares.TypedHandler; internal class ConfluentProtobufMessageHandler : IMessageHandler { diff --git a/src/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler.cs b/src/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler.cs index a5f77c0ae..f2d1bb484 100644 --- a/src/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler.cs +++ b/src/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler.cs @@ -2,7 +2,7 @@ namespace KafkaFlow.IntegrationTests.Core.Handlers { using System.Threading.Tasks; using KafkaFlow.IntegrationTests.Core.Messages; - using KafkaFlow.TypedHandler; + using KafkaFlow.Middlewares.TypedHandler; internal class MessageHandler : IMessageHandler { diff --git a/src/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler1.cs b/src/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler1.cs index c33518e09..1b01e1ea0 100644 --- a/src/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler1.cs +++ b/src/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler1.cs @@ -2,7 +2,7 @@ namespace KafkaFlow.IntegrationTests.Core.Handlers { using System.Threading.Tasks; using KafkaFlow.IntegrationTests.Core.Messages; - using KafkaFlow.TypedHandler; + using KafkaFlow.Middlewares.TypedHandler; internal class MessageHandler1 : IMessageHandler { diff --git a/src/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler2.cs b/src/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler2.cs index 38534e1c0..f47f02638 100644 --- a/src/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler2.cs +++ b/src/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler2.cs @@ -3,7 +3,7 @@ namespace KafkaFlow.IntegrationTests.Core.Handlers using System; using System.Threading.Tasks; using KafkaFlow.IntegrationTests.Core.Messages; - using KafkaFlow.TypedHandler; + using KafkaFlow.Middlewares.TypedHandler; internal class MessageHandler2 : IMessageHandler { diff --git a/src/KafkaFlow.IntegrationTests/Core/Handlers/PauseResumeHandler.cs b/src/KafkaFlow.IntegrationTests/Core/Handlers/PauseResumeHandler.cs index f58772786..05ccf1350 100644 --- a/src/KafkaFlow.IntegrationTests/Core/Handlers/PauseResumeHandler.cs +++ b/src/KafkaFlow.IntegrationTests/Core/Handlers/PauseResumeHandler.cs @@ -2,7 +2,7 @@ namespace KafkaFlow.IntegrationTests.Core.Handlers { using System.Threading.Tasks; using KafkaFlow.IntegrationTests.Core.Messages; - using KafkaFlow.TypedHandler; + using KafkaFlow.Middlewares.TypedHandler; internal class PauseResumeHandler : IMessageHandler { diff --git a/src/KafkaFlow.IntegrationTests/GlobalEventsTest.cs b/src/KafkaFlow.IntegrationTests/GlobalEventsTest.cs index d9055fd00..c1452a340 100644 --- a/src/KafkaFlow.IntegrationTests/GlobalEventsTest.cs +++ b/src/KafkaFlow.IntegrationTests/GlobalEventsTest.cs @@ -222,7 +222,7 @@ private void ConfigureConsumer(IConsumerConfigurationBuilder consumerConfigur .WithAutoOffsetReset(KafkaFlow.AutoOffsetReset.Earliest) .AddMiddlewares( middlewares => middlewares - .AddSerializer() + .AddDeserializer() .Add()) .WithPartitionsAssignedHandler((_, _) => { diff --git a/src/KafkaFlow.IntegrationTests/KafkaFlow.IntegrationTests.csproj b/src/KafkaFlow.IntegrationTests/KafkaFlow.IntegrationTests.csproj index bb3a336e7..f58a8a198 100644 --- a/src/KafkaFlow.IntegrationTests/KafkaFlow.IntegrationTests.csproj +++ b/src/KafkaFlow.IntegrationTests/KafkaFlow.IntegrationTests.csproj @@ -32,7 +32,6 @@ - @@ -40,8 +39,6 @@ - - diff --git a/src/KafkaFlow.IntegrationTests/OpenTelemetryTests.cs b/src/KafkaFlow.IntegrationTests/OpenTelemetryTests.cs index 53c3f2ec3..a0df1c528 100644 --- a/src/KafkaFlow.IntegrationTests/OpenTelemetryTests.cs +++ b/src/KafkaFlow.IntegrationTests/OpenTelemetryTests.cs @@ -180,7 +180,7 @@ private async Task GetServiceProvider() .WithAutoOffsetReset(AutoOffsetReset.Latest) .AddMiddlewares( middlewares => middlewares - .AddCompressor() + .AddDecompressor() .Add()) .WithPartitionsAssignedHandler((_, _) => { diff --git a/src/KafkaFlow.SchemaRegistry/KafkaFlow.SchemaRegistry.csproj b/src/KafkaFlow.SchemaRegistry/KafkaFlow.SchemaRegistry.csproj index b1241a6fb..d7aa2a489 100644 --- a/src/KafkaFlow.SchemaRegistry/KafkaFlow.SchemaRegistry.csproj +++ b/src/KafkaFlow.SchemaRegistry/KafkaFlow.SchemaRegistry.csproj @@ -9,12 +9,12 @@ - + - + diff --git a/src/KafkaFlow.SchemaRegistry/SchemaRegistryTypeResolver.cs b/src/KafkaFlow.SchemaRegistry/SchemaRegistryTypeResolver.cs index f0dd56cd9..3861d1ef6 100644 --- a/src/KafkaFlow.SchemaRegistry/SchemaRegistryTypeResolver.cs +++ b/src/KafkaFlow.SchemaRegistry/SchemaRegistryTypeResolver.cs @@ -6,6 +6,7 @@ namespace KafkaFlow using System.Linq; using System.Threading; using System.Threading.Tasks; + using KafkaFlow.Middlewares.Serializer.Resolvers; /// /// The message type resolver to be used with schema registry serializers diff --git a/src/KafkaFlow.Serializer.JsonCore/JsonCoreDeserializer.cs b/src/KafkaFlow.Serializer.JsonCore/JsonCoreDeserializer.cs new file mode 100644 index 000000000..521b3be16 --- /dev/null +++ b/src/KafkaFlow.Serializer.JsonCore/JsonCoreDeserializer.cs @@ -0,0 +1,40 @@ +namespace KafkaFlow.Serializer +{ + using System; + using System.IO; + using System.Text.Json; + using System.Threading.Tasks; + + /// + /// A message deserializer using System.Text.Json library + /// + public class JsonCoreDeserializer : IDeserializer + { + private readonly JsonSerializerOptions serializerOptions; + + /// + /// Initializes a new instance of the class. + /// + /// Json serializer options + public JsonCoreDeserializer(JsonSerializerOptions options) + { + this.serializerOptions = options; + } + + /// + /// Initializes a new instance of the class. + /// + public JsonCoreDeserializer() + : this(new JsonSerializerOptions()) + { + } + + /// + public async Task DeserializeAsync(Stream input, Type type, ISerializerContext context) + { + return await JsonSerializer + .DeserializeAsync(input, type, this.serializerOptions) + .ConfigureAwait(false); + } + } +} diff --git a/src/KafkaFlow.Serializer.JsonCore/JsonCoreSerializer.cs b/src/KafkaFlow.Serializer.JsonCore/JsonCoreSerializer.cs index 5bb840360..e0069dd7e 100644 --- a/src/KafkaFlow.Serializer.JsonCore/JsonCoreSerializer.cs +++ b/src/KafkaFlow.Serializer.JsonCore/JsonCoreSerializer.cs @@ -1,6 +1,5 @@ namespace KafkaFlow.Serializer { - using System; using System.IO; using System.Text.Json; using System.Threading.Tasks; @@ -59,13 +58,5 @@ public Task SerializeAsync(object message, Stream output, ISerializerContext con return Task.CompletedTask; } - - /// - public async Task DeserializeAsync(Stream input, Type type, ISerializerContext context) - { - return await JsonSerializer - .DeserializeAsync(input, type, this.serializerOptions) - .ConfigureAwait(false); - } } -} \ No newline at end of file +} diff --git a/src/KafkaFlow.Serializer.NewtonsoftJson/NewtonsoftJsonDeserializer.cs b/src/KafkaFlow.Serializer.NewtonsoftJson/NewtonsoftJsonDeserializer.cs new file mode 100644 index 000000000..f0b05dcff --- /dev/null +++ b/src/KafkaFlow.Serializer.NewtonsoftJson/NewtonsoftJsonDeserializer.cs @@ -0,0 +1,51 @@ +namespace KafkaFlow.Serializer +{ + using System; + using System.IO; + using System.Text; + using System.Threading.Tasks; + using Newtonsoft.Json; + + /// + /// A message deserializer using NewtonsoftJson library + /// + public class NewtonsoftJsonDeserializer : IDeserializer + { + private const int DefaultBufferSize = 1024; + + private static readonly UTF8Encoding UTF8NoBom = new (false); + private readonly JsonSerializerSettings settings; + + /// + /// Initializes a new instance of the class. + /// + /// Json serializer settings + public NewtonsoftJsonDeserializer(JsonSerializerSettings settings) + { + this.settings = settings; + } + + /// + /// Initializes a new instance of the class. + /// + public NewtonsoftJsonDeserializer() + : this(new JsonSerializerSettings()) + { + } + + /// + public Task DeserializeAsync(Stream input, Type type, ISerializerContext context) + { + using var sr = new StreamReader( + input, + UTF8NoBom, + true, + DefaultBufferSize, + true); + + var serializer = JsonSerializer.CreateDefault(this.settings); + + return Task.FromResult(serializer.Deserialize(sr, type)); + } + } +} diff --git a/src/KafkaFlow.Serializer.NewtonsoftJson/NewtonsoftJsonSerializer.cs b/src/KafkaFlow.Serializer.NewtonsoftJson/NewtonsoftJsonSerializer.cs index bbc943482..8ca731d2c 100644 --- a/src/KafkaFlow.Serializer.NewtonsoftJson/NewtonsoftJsonSerializer.cs +++ b/src/KafkaFlow.Serializer.NewtonsoftJson/NewtonsoftJsonSerializer.cs @@ -1,6 +1,5 @@ namespace KafkaFlow.Serializer { - using System; using System.IO; using System.Text; using System.Threading.Tasks; @@ -43,20 +42,5 @@ public Task SerializeAsync(object message, Stream output, ISerializerContext con return Task.CompletedTask; } - - /// - public Task DeserializeAsync(Stream input, Type type, ISerializerContext context) - { - using var sr = new StreamReader( - input, - UTF8NoBom, - true, - DefaultBufferSize, - true); - - var serializer = JsonSerializer.CreateDefault(this.settings); - - return Task.FromResult(serializer.Deserialize(sr, type)); - } } } diff --git a/src/KafkaFlow.Serializer.ProtobufNet/ProtobufNetDeserializer.cs b/src/KafkaFlow.Serializer.ProtobufNet/ProtobufNetDeserializer.cs new file mode 100644 index 000000000..c4838c35a --- /dev/null +++ b/src/KafkaFlow.Serializer.ProtobufNet/ProtobufNetDeserializer.cs @@ -0,0 +1,19 @@ +namespace KafkaFlow.Serializer +{ + using System; + using System.IO; + using System.Threading.Tasks; + using ProtoBuf; + + /// + /// A message deserializer using protobuf-net library + /// + public class ProtobufNetDeserializer : IDeserializer + { + /// + public Task DeserializeAsync(Stream input, Type type, ISerializerContext context) + { + return Task.FromResult(Serializer.Deserialize(type, input)); + } + } +} diff --git a/src/KafkaFlow.Serializer.ProtobufNet/ProtobufNetSerializer.cs b/src/KafkaFlow.Serializer.ProtobufNet/ProtobufNetSerializer.cs index 50ff531a9..12d8a706d 100644 --- a/src/KafkaFlow.Serializer.ProtobufNet/ProtobufNetSerializer.cs +++ b/src/KafkaFlow.Serializer.ProtobufNet/ProtobufNetSerializer.cs @@ -1,6 +1,5 @@ namespace KafkaFlow.Serializer { - using System; using System.IO; using System.Threading.Tasks; using ProtoBuf; @@ -17,11 +16,5 @@ public Task SerializeAsync(object message, Stream output, ISerializerContext con return Task.CompletedTask; } - - /// - public Task DeserializeAsync(Stream input, Type type, ISerializerContext context) - { - return Task.FromResult(Serializer.Deserialize(type, input)); - } } } diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConfluentAvroDeserializer.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConfluentAvroDeserializer.cs new file mode 100644 index 000000000..3f29adc7d --- /dev/null +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConfluentAvroDeserializer.cs @@ -0,0 +1,42 @@ +namespace KafkaFlow.Serializer.SchemaRegistry +{ + using System; + using System.IO; + using System.Threading.Tasks; + using Confluent.SchemaRegistry; + using Confluent.SchemaRegistry.Serdes; + + /// + /// A message serializer using Apache.Avro library + /// + public class ConfluentAvroDeserializer : IDeserializer + { + private readonly ISchemaRegistryClient schemaRegistryClient; + + /// + /// Initializes a new instance of the class. + /// + /// The to be used by the framework + public ConfluentAvroDeserializer(IDependencyResolver resolver) + { + this.schemaRegistryClient = + resolver.Resolve() ?? + throw new InvalidOperationException( + $"No schema registry configuration was found. Set it using {nameof(ClusterConfigurationBuilderExtensions.WithSchemaRegistry)} on cluster configuration"); + } + + /// + public Task DeserializeAsync(Stream input, Type type, ISerializerContext context) + { + return ConfluentDeserializerWrapper + .GetOrCreateDeserializer( + type, + () => Activator + .CreateInstance( + typeof(AvroDeserializer<>).MakeGenericType(type), + this.schemaRegistryClient, + null)) + .DeserializeAsync(input, context); + } + } +} diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConfluentAvroSerializer.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConfluentAvroSerializer.cs index 4fe5c2099..e0e2eb49e 100644 --- a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConfluentAvroSerializer.cs +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConfluentAvroSerializer.cs @@ -43,19 +43,5 @@ public Task SerializeAsync(object message, Stream output, ISerializerContext con this.serializerConfig)) .SerializeAsync(message, output, context); } - - /// - public Task DeserializeAsync(Stream input, Type type, ISerializerContext context) - { - return ConfluentDeserializerWrapper - .GetOrCreateDeserializer( - type, - () => Activator - .CreateInstance( - typeof(AvroDeserializer<>).MakeGenericType(type), - this.schemaRegistryClient, - null)) - .DeserializeAsync(input, context); - } } } diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConsumerConfigurationBuilderExtensions.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConsumerConfigurationBuilderExtensions.cs index 81ac47435..859e852f5 100644 --- a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConsumerConfigurationBuilderExtensions.cs +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConsumerConfigurationBuilderExtensions.cs @@ -2,6 +2,7 @@ { using Confluent.SchemaRegistry; using KafkaFlow.Configuration; + using KafkaFlow.Middlewares.Serializer; using KafkaFlow.Serializer.SchemaRegistry; /// @@ -14,12 +15,12 @@ public static class ConsumerConfigurationBuilderExtensions /// /// The middleware configuration builder /// - public static IConsumerMiddlewareConfigurationBuilder AddSchemaRegistryAvroSerializer( + public static IConsumerMiddlewareConfigurationBuilder AddSchemaRegistryAvroDeserializer( this IConsumerMiddlewareConfigurationBuilder middlewares) { return middlewares.Add( - resolver => new SerializerConsumerMiddleware( - new ConfluentAvroSerializer(resolver), + resolver => new DeserializerConsumerMiddleware( + new ConfluentAvroDeserializer(resolver), new SchemaRegistryTypeResolver(new ConfluentAvroTypeNameResolver(resolver.Resolve())))); } } diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro.csproj b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro.csproj index 355666973..e65dfa824 100644 --- a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro.csproj +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro.csproj @@ -10,7 +10,6 @@ - diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ProducerConfigurationBuilderExtensions.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ProducerConfigurationBuilderExtensions.cs index d60a7a39c..54bf6bac7 100644 --- a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ProducerConfigurationBuilderExtensions.cs +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ProducerConfigurationBuilderExtensions.cs @@ -3,6 +3,7 @@ using Confluent.SchemaRegistry; using Confluent.SchemaRegistry.Serdes; using KafkaFlow.Configuration; + using KafkaFlow.Middlewares.Serializer; using KafkaFlow.Serializer.SchemaRegistry; /// diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ConfluentJsonDeserializer.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ConfluentJsonDeserializer.cs new file mode 100644 index 000000000..0ec931348 --- /dev/null +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ConfluentJsonDeserializer.cs @@ -0,0 +1,39 @@ +namespace KafkaFlow.Serializer.SchemaRegistry +{ + using System; + using System.IO; + using System.Threading.Tasks; + using Confluent.SchemaRegistry.Serdes; + using NJsonSchema.Generation; + + /// + /// A json message serializer integrated with the confluent schema registry + /// + public class ConfluentJsonDeserializer : IDeserializer + { + private readonly JsonSchemaGeneratorSettings schemaGeneratorSettings; + + /// + /// Initializes a new instance of the class. + /// + /// An instance of + public ConfluentJsonDeserializer(JsonSchemaGeneratorSettings schemaGeneratorSettings = null) + { + this.schemaGeneratorSettings = schemaGeneratorSettings; + } + + /// + public Task DeserializeAsync(Stream input, Type type, ISerializerContext context) + { + return ConfluentDeserializerWrapper + .GetOrCreateDeserializer( + type, + () => Activator + .CreateInstance( + typeof(JsonDeserializer<>).MakeGenericType(type), + null, + this.schemaGeneratorSettings)) + .DeserializeAsync(input, context); + } + } +} diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ConfluentJsonSerializer.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ConfluentJsonSerializer.cs index 4b827857e..fa2763903 100644 --- a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ConfluentJsonSerializer.cs +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ConfluentJsonSerializer.cs @@ -62,19 +62,5 @@ public Task SerializeAsync(object message, Stream output, ISerializerContext con this.schemaGeneratorSettings)) .SerializeAsync(message, output, context); } - - /// - public Task DeserializeAsync(Stream input, Type type, ISerializerContext context) - { - return ConfluentDeserializerWrapper - .GetOrCreateDeserializer( - type, - () => Activator - .CreateInstance( - typeof(JsonDeserializer<>).MakeGenericType(type), - null, - this.schemaGeneratorSettings)) - .DeserializeAsync(input, context); - } } } diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ConsumerConfigurationBuilderExtensions.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ConsumerConfigurationBuilderExtensions.cs index 06c8c04b9..4700b797b 100644 --- a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ConsumerConfigurationBuilderExtensions.cs +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ConsumerConfigurationBuilderExtensions.cs @@ -1,6 +1,7 @@ namespace KafkaFlow { using KafkaFlow.Configuration; + using KafkaFlow.Middlewares.Serializer.Resolvers; using KafkaFlow.Serializer.SchemaRegistry; /// @@ -17,8 +18,8 @@ public static class ConsumerConfigurationBuilderExtensions public static IConsumerMiddlewareConfigurationBuilder AddSchemaRegistryJsonSerializer( this IConsumerMiddlewareConfigurationBuilder middlewares) { - return middlewares.AddSerializer( - resolver => new ConfluentJsonSerializer(resolver), + return middlewares.AddDeserializer( + resolver => new ConfluentJsonDeserializer(), _ => new SingleMessageTypeResolver(typeof(TMessage))); } } diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson.csproj b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson.csproj index c7e599371..305788443 100644 --- a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson.csproj +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson.csproj @@ -15,7 +15,6 @@ - diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ProducerConfigurationBuilderExtensions.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ProducerConfigurationBuilderExtensions.cs index 1708eea73..208595450 100644 --- a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ProducerConfigurationBuilderExtensions.cs +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ProducerConfigurationBuilderExtensions.cs @@ -2,6 +2,7 @@ { using Confluent.SchemaRegistry.Serdes; using KafkaFlow.Configuration; + using KafkaFlow.Middlewares.Serializer.Resolvers; using KafkaFlow.Serializer.SchemaRegistry; /// diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConfluentProtobufDeserializer.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConfluentProtobufDeserializer.cs new file mode 100644 index 000000000..3722dc35d --- /dev/null +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConfluentProtobufDeserializer.cs @@ -0,0 +1,27 @@ +namespace KafkaFlow.Serializer.SchemaRegistry +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Threading.Tasks; + using Confluent.SchemaRegistry.Serdes; + + /// + /// A protobuf message serializer integrated with the confluent schema registry + /// + public class ConfluentProtobufDeserializer : IDeserializer + { + /// + public Task DeserializeAsync(Stream input, Type type, ISerializerContext context) + { + return ConfluentDeserializerWrapper + .GetOrCreateDeserializer( + type, + () => Activator + .CreateInstance( + typeof(ProtobufDeserializer<>).MakeGenericType(type), + (IEnumerable>)null)) + .DeserializeAsync(input, context); + } + } +} diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConfluentProtobufSerializer.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConfluentProtobufSerializer.cs index 5285501cd..d29699d71 100644 --- a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConfluentProtobufSerializer.cs +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConfluentProtobufSerializer.cs @@ -1,7 +1,6 @@ namespace KafkaFlow.Serializer.SchemaRegistry { using System; - using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using Confluent.SchemaRegistry; @@ -42,18 +41,5 @@ public Task SerializeAsync(object message, Stream output, ISerializerContext con this.serializerConfig)) .SerializeAsync(message, output, context); } - - /// - public Task DeserializeAsync(Stream input, Type type, ISerializerContext context) - { - return ConfluentDeserializerWrapper - .GetOrCreateDeserializer( - type, - () => Activator - .CreateInstance( - typeof(ProtobufDeserializer<>).MakeGenericType(type), - (IEnumerable>)null)) - .DeserializeAsync(input, context); - } } } diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConsumerConfigurationBuilderExtensions.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConsumerConfigurationBuilderExtensions.cs index ce3b0e4c3..59012f3d8 100644 --- a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConsumerConfigurationBuilderExtensions.cs +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConsumerConfigurationBuilderExtensions.cs @@ -2,6 +2,7 @@ { using Confluent.SchemaRegistry; using KafkaFlow.Configuration; + using KafkaFlow.Middlewares.Serializer; using KafkaFlow.Serializer.SchemaRegistry; /// @@ -14,12 +15,12 @@ public static class ConsumerConfigurationBuilderExtensions /// /// The middleware configuration builder /// - public static IConsumerMiddlewareConfigurationBuilder AddSchemaRegistryProtobufSerializer( + public static IConsumerMiddlewareConfigurationBuilder AddSchemaRegistryProtobufDeserializer( this IConsumerMiddlewareConfigurationBuilder middlewares) { return middlewares.Add( - resolver => new SerializerConsumerMiddleware( - new ConfluentProtobufSerializer(resolver), + resolver => new DeserializerConsumerMiddleware( + new ConfluentProtobufDeserializer(), new SchemaRegistryTypeResolver(new ConfluentProtobufTypeNameResolver(resolver.Resolve())))); } } diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf.csproj b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf.csproj index f2eac2e3b..418a3ccd7 100644 --- a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf.csproj +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf.csproj @@ -16,6 +16,5 @@ - diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ProducerConfigurationBuilderExtensions.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ProducerConfigurationBuilderExtensions.cs index fc59f5e3d..af83cd19d 100644 --- a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ProducerConfigurationBuilderExtensions.cs +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ProducerConfigurationBuilderExtensions.cs @@ -3,6 +3,7 @@ using Confluent.SchemaRegistry; using Confluent.SchemaRegistry.Serdes; using KafkaFlow.Configuration; + using KafkaFlow.Middlewares.Serializer; using KafkaFlow.Serializer.SchemaRegistry; /// diff --git a/src/KafkaFlow.Serializer/KafkaFlow.Serializer.csproj b/src/KafkaFlow.Serializer/KafkaFlow.Serializer.csproj deleted file mode 100644 index 2a0a1c219..000000000 --- a/src/KafkaFlow.Serializer/KafkaFlow.Serializer.csproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - netstandard2.0 - KafkaFlow.Serializer - Serializer middleware for KafkaFlow - KafkaFlow - - - - - - - - - - - - diff --git a/src/KafkaFlow.TypedHandler/AssemblyInfo.cs b/src/KafkaFlow.TypedHandler/AssemblyInfo.cs deleted file mode 100644 index f8402e685..000000000 --- a/src/KafkaFlow.TypedHandler/AssemblyInfo.cs +++ /dev/null @@ -1,4 +0,0 @@ -using System.Runtime.CompilerServices; - -[assembly: InternalsVisibleTo("KafkaFlow.UnitTests")] -[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] diff --git a/src/KafkaFlow.TypedHandler/ConfigurationBuilderExtensions.cs b/src/KafkaFlow.TypedHandler/ConfigurationBuilderExtensions.cs deleted file mode 100644 index 9befd1a92..000000000 --- a/src/KafkaFlow.TypedHandler/ConfigurationBuilderExtensions.cs +++ /dev/null @@ -1,34 +0,0 @@ -namespace KafkaFlow.TypedHandler -{ - using System; - using KafkaFlow.Configuration; - - /// - /// Extension methods over - /// - public static class ConfigurationBuilderExtensions - { - /// - /// Adds typed handler middleware - /// - /// Instance of - /// A handler to configure the middleware - /// - public static IConsumerMiddlewareConfigurationBuilder AddTypedHandlers( - this IConsumerMiddlewareConfigurationBuilder builder, - Action configure) - { - var typedHandlerBuilder = new TypedHandlerConfigurationBuilder(builder.DependencyConfigurator); - - configure(typedHandlerBuilder); - - var configuration = typedHandlerBuilder.Build(); - - builder.Add( - resolver => new TypedHandlerMiddleware(resolver, configuration), - MiddlewareLifetime.Message); - - return builder; - } - } -} diff --git a/src/KafkaFlow.TypedHandler/KafkaFlow.TypedHandler.csproj b/src/KafkaFlow.TypedHandler/KafkaFlow.TypedHandler.csproj deleted file mode 100644 index 260ab8c41..000000000 --- a/src/KafkaFlow.TypedHandler/KafkaFlow.TypedHandler.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - netstandard2.0 - KafkaFlow.TypedHandler - A KafkaFlow middleware to execute a handler class when a specific message arrives - - - - - - - diff --git a/src/KafkaFlow.UnitTests/BatchConsume/BatchConsumeMiddlewareTests.cs b/src/KafkaFlow.UnitTests/BatchConsume/BatchConsumeMiddlewareTests.cs index 2269db974..819b324ed 100644 --- a/src/KafkaFlow.UnitTests/BatchConsume/BatchConsumeMiddlewareTests.cs +++ b/src/KafkaFlow.UnitTests/BatchConsume/BatchConsumeMiddlewareTests.cs @@ -3,7 +3,7 @@ namespace KafkaFlow.UnitTests.BatchConsume using System; using System.Threading.Tasks; using FluentAssertions; - using KafkaFlow.BatchConsume; + using KafkaFlow.Batching; using KafkaFlow.Configuration; using KafkaFlow.Consumers; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/src/KafkaFlow.UnitTests/Compressors/CompressorConsumerMiddlewareTests.cs b/src/KafkaFlow.UnitTests/Compressors/CompressorConsumerMiddlewareTests.cs index ce2808cb2..57ced96cb 100644 --- a/src/KafkaFlow.UnitTests/Compressors/CompressorConsumerMiddlewareTests.cs +++ b/src/KafkaFlow.UnitTests/Compressors/CompressorConsumerMiddlewareTests.cs @@ -3,7 +3,9 @@ namespace KafkaFlow.UnitTests.Compressors using System; using System.Threading.Tasks; using FluentAssertions; - using KafkaFlow.Compressor; + + using KafkaFlow.Middlewares.Compressor; + using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -11,16 +13,16 @@ namespace KafkaFlow.UnitTests.Compressors public class CompressorConsumerMiddlewareTests { private Mock contextMock; - private Mock compressorMock; + private Mock decompressorMock; private bool nextCalled; - private CompressorConsumerMiddleware target; + private DecompressorConsumerMiddleware target; [TestInitialize] public void Setup() { this.contextMock = new Mock(); - this.compressorMock = new Mock(); - this.target = new CompressorConsumerMiddleware(this.compressorMock.Object); + this.decompressorMock = new Mock(); + this.target = new DecompressorConsumerMiddleware(this.decompressorMock.Object); } [TestMethod] @@ -38,7 +40,7 @@ public void Invoke_NotByteArrayMessage_ThrowsInvalidOperationException() act.Should().Throw(); this.nextCalled.Should().BeFalse(); this.contextMock.Verify(x => x.SetMessage(It.IsAny(), It.IsAny()), Times.Never); - this.compressorMock.Verify(x => x.Decompress(It.IsAny()), Times.Never); + this.decompressorMock.Verify(x => x.Decompress(It.IsAny()), Times.Never); } [TestMethod] @@ -55,7 +57,7 @@ public async Task Invoke_ValidMessage_CallNext() .SetupGet(x => x.Message) .Returns(compressedMessage); - this.compressorMock + this.decompressorMock .Setup(x => x.Decompress((byte[]) compressedMessage.Value)) .Returns(uncompressedValue); @@ -76,7 +78,7 @@ await this.target.Invoke( resultContext.Should().NotBeNull(); resultContext.Should().Be(transformedContextMock.Object); this.contextMock.VerifyAll(); - this.compressorMock.VerifyAll(); + this.decompressorMock.VerifyAll(); } private Task SetNextCalled() diff --git a/src/KafkaFlow.UnitTests/Compressors/CompressorProducerMiddlewareTests.cs b/src/KafkaFlow.UnitTests/Compressors/CompressorProducerMiddlewareTests.cs index 54b135a70..24c41eed2 100644 --- a/src/KafkaFlow.UnitTests/Compressors/CompressorProducerMiddlewareTests.cs +++ b/src/KafkaFlow.UnitTests/Compressors/CompressorProducerMiddlewareTests.cs @@ -3,7 +3,9 @@ namespace KafkaFlow.UnitTests.Compressors using System; using System.Threading.Tasks; using FluentAssertions; - using KafkaFlow.Compressor; + + using KafkaFlow.Middlewares.Compressor; + using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -11,7 +13,7 @@ namespace KafkaFlow.UnitTests.Compressors public class CompressorProducerMiddlewareTests { private Mock contextMock; - private Mock compressorMock; + private Mock compressorMock; private CompressorProducerMiddleware target; @@ -19,7 +21,7 @@ public class CompressorProducerMiddlewareTests public void Setup() { this.contextMock = new Mock(); - this.compressorMock = new Mock(); + this.compressorMock = new Mock(); this.target = new CompressorProducerMiddleware(this.compressorMock.Object); } diff --git a/src/KafkaFlow.UnitTests/KafkaFlow.UnitTests.csproj b/src/KafkaFlow.UnitTests/KafkaFlow.UnitTests.csproj index 6e905e545..681188711 100644 --- a/src/KafkaFlow.UnitTests/KafkaFlow.UnitTests.csproj +++ b/src/KafkaFlow.UnitTests/KafkaFlow.UnitTests.csproj @@ -31,16 +31,12 @@ - - - - diff --git a/src/KafkaFlow.UnitTests/Serializers/NewtonsoftJsonDeserializerTests.cs b/src/KafkaFlow.UnitTests/Serializers/NewtonsoftJsonDeserializerTests.cs new file mode 100644 index 000000000..88fa963e8 --- /dev/null +++ b/src/KafkaFlow.UnitTests/Serializers/NewtonsoftJsonDeserializerTests.cs @@ -0,0 +1,48 @@ +namespace KafkaFlow.UnitTests.Serializers +{ + using System; + using System.IO; + using System.Text; + using System.Threading.Tasks; + using AutoFixture; + using FluentAssertions; + using KafkaFlow.Serializer; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Newtonsoft.Json; + + [TestClass] + public class NewtonsoftJsonDeserializerTests + { + private readonly Mock contextMock = new (); + private readonly NewtonsoftJsonDeserializer deserializer = new (); + + private readonly Fixture fixture = new(); + + [TestMethod] + public async Task DeserializeAsync_ValidPayload_ObjectGenerated() + { + // Arrange + var message = this.fixture.Create(); + using var input = new MemoryStream(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(message))); + + // Act + var result = await this.deserializer.DeserializeAsync(input, typeof(TestMessage), this.contextMock.Object); + + // Assert + result.Should().NotBeNull(); + result.Should().BeOfType(); + } + + private class TestMessage + { + public int IntegerField { get; set; } + + public string StringField { get; set; } + + public double DoubleField { get; set; } + + public DateTime DateTimeField { get; set; } + } + } +} diff --git a/src/KafkaFlow.UnitTests/Serializers/NewtonsoftJsonSerializerTests.cs b/src/KafkaFlow.UnitTests/Serializers/NewtonsoftJsonSerializerTests.cs index 3e3a5997e..93673ed05 100644 --- a/src/KafkaFlow.UnitTests/Serializers/NewtonsoftJsonSerializerTests.cs +++ b/src/KafkaFlow.UnitTests/Serializers/NewtonsoftJsonSerializerTests.cs @@ -2,14 +2,12 @@ namespace KafkaFlow.UnitTests.Serializers { using System; using System.IO; - using System.Text; using System.Threading.Tasks; using AutoFixture; using FluentAssertions; using KafkaFlow.Serializer; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; - using Newtonsoft.Json; [TestClass] public class NewtonsoftJsonSerializerTests @@ -34,21 +32,6 @@ public async Task SerializeAsync_ValidPayload_JsonByteArrayGenerated() output.Position.Should().BeGreaterThan(0); } - [TestMethod] - public async Task DeserializeAsync_ValidPayload_ObjectGenerated() - { - // Arrange - var message = this.fixture.Create(); - using var input = new MemoryStream(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(message))); - - // Act - var result = await this.serializer.DeserializeAsync(input, typeof(TestMessage), this.contextMock.Object); - - // Assert - result.Should().NotBeNull(); - result.Should().BeOfType(); - } - private class TestMessage { public int IntegerField { get; set; } diff --git a/src/KafkaFlow.UnitTests/Serializers/SerializerConsumerMiddlewareTests.cs b/src/KafkaFlow.UnitTests/Serializers/SerializerConsumerMiddlewareTests.cs index cf0f1398b..6c05b0201 100644 --- a/src/KafkaFlow.UnitTests/Serializers/SerializerConsumerMiddlewareTests.cs +++ b/src/KafkaFlow.UnitTests/Serializers/SerializerConsumerMiddlewareTests.cs @@ -4,6 +4,8 @@ namespace KafkaFlow.UnitTests.Serializers using System.IO; using System.Threading.Tasks; using FluentAssertions; + using KafkaFlow.Middlewares.Serializer; + using KafkaFlow.Middlewares.Serializer.Resolvers; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -11,22 +13,22 @@ namespace KafkaFlow.UnitTests.Serializers public class SerializerConsumerMiddlewareTests { private Mock contextMock; - private Mock serializerMock; + private Mock deserializerMock; private Mock typeResolverMock; private bool nextCalled; - private SerializerConsumerMiddleware target; + private DeserializerConsumerMiddleware target; [TestInitialize] public void Setup() { this.contextMock = new Mock(); - this.serializerMock = new Mock(); + this.deserializerMock = new Mock(); this.typeResolverMock = new Mock(); - this.target = new SerializerConsumerMiddleware( - this.serializerMock.Object, + this.target = new DeserializerConsumerMiddleware( + this.deserializerMock.Object, this.typeResolverMock.Object); } @@ -49,7 +51,7 @@ public async Task Invoke_NullMessageType_ReturnWithoutCallingNext() this.nextCalled.Should().BeFalse(); this.typeResolverMock.VerifyAll(); this.contextMock.Verify(x => x.SetMessage(It.IsAny(), It.IsAny()), Times.Never); - this.serializerMock.Verify( + this.deserializerMock.Verify( x => x.DeserializeAsync(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); } @@ -67,7 +69,7 @@ public async Task Invoke_NullMessage_CallNext() // Assert this.nextCalled.Should().BeTrue(); - this.serializerMock.Verify( + this.deserializerMock.Verify( x => x.DeserializeAsync(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); this.typeResolverMock.Verify(x => x.OnConsumeAsync(It.IsAny()), Times.Never); @@ -88,7 +90,7 @@ public void Invoke_NotByteArrayMessage_ThrowsInvalidOperationException() act.Should().Throw(); this.nextCalled.Should().BeFalse(); this.contextMock.Verify(x => x.SetMessage(It.IsAny(), It.IsAny()), Times.Never); - this.serializerMock.Verify( + this.deserializerMock.Verify( x => x.DeserializeAsync(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); this.typeResolverMock.Verify(x => x.OnConsumeAsync(It.IsAny()), Times.Never); @@ -122,7 +124,7 @@ public async Task Invoke_ValidMessage_Deserialize() .Setup(x => x.OnConsumeAsync(this.contextMock.Object)) .ReturnsAsync(messageType); - this.serializerMock + this.deserializerMock .Setup(x => x.DeserializeAsync(It.IsAny(), messageType, It.IsAny())) .ReturnsAsync(deserializedMessage); @@ -143,7 +145,7 @@ await this.target.Invoke( resultContext.Should().NotBeNull(); resultContext.Should().Be(transformedContextMock.Object); this.contextMock.VerifyAll(); - this.serializerMock.VerifyAll(); + this.deserializerMock.VerifyAll(); this.typeResolverMock.VerifyAll(); } diff --git a/src/KafkaFlow.UnitTests/Serializers/SerializerProducerMiddlewareTests.cs b/src/KafkaFlow.UnitTests/Serializers/SerializerProducerMiddlewareTests.cs index 74030a595..c828b4504 100644 --- a/src/KafkaFlow.UnitTests/Serializers/SerializerProducerMiddlewareTests.cs +++ b/src/KafkaFlow.UnitTests/Serializers/SerializerProducerMiddlewareTests.cs @@ -5,6 +5,8 @@ namespace KafkaFlow.UnitTests.Serializers using System.Threading.Tasks; using AutoFixture; using FluentAssertions; + using KafkaFlow.Middlewares.Serializer; + using KafkaFlow.Middlewares.Serializer.Resolvers; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; diff --git a/src/KafkaFlow.UnitTests/TypedHandler/HandlerTypeMappingTests.cs b/src/KafkaFlow.UnitTests/TypedHandler/HandlerTypeMappingTests.cs index 48f4ba6ca..90856c544 100644 --- a/src/KafkaFlow.UnitTests/TypedHandler/HandlerTypeMappingTests.cs +++ b/src/KafkaFlow.UnitTests/TypedHandler/HandlerTypeMappingTests.cs @@ -1,7 +1,7 @@ namespace KafkaFlow.UnitTests.TypedHandler { using FluentAssertions; - using KafkaFlow.TypedHandler; + using KafkaFlow.Middlewares.TypedHandler; using Microsoft.VisualStudio.TestTools.UnitTesting; [TestClass] diff --git a/src/KafkaFlow.sln b/src/KafkaFlow.sln index 73f4d6c43..b78e82c70 100644 --- a/src/KafkaFlow.sln +++ b/src/KafkaFlow.sln @@ -25,12 +25,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Compression", "Compression" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Abstractions", "KafkaFlow.Abstractions\KafkaFlow.Abstractions.csproj", "{88808771-56BE-422B-94DC-7AB070F64E98}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.TypedHandler", "KafkaFlow.TypedHandler\KafkaFlow.TypedHandler.csproj", "{E47EF9E0-A1C7-4FF0-AEC5-143F52ED0FBE}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Serializer", "KafkaFlow.Serializer\KafkaFlow.Serializer.csproj", "{B7197114-B1C7-49EC-8740-1E09233B2C40}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Compressor", "KafkaFlow.Compressor\KafkaFlow.Compressor.csproj", "{D29EC709-33DE-4045-8F3B-EC6619CDB429}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.IntegrationTests", "KafkaFlow.IntegrationTests\KafkaFlow.IntegrationTests.csproj", "{36F459F4-8323-472A-A8C5-8C9D89F92012}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Serializer.NewtonsoftJson", "KafkaFlow.Serializer.NewtonsoftJson\KafkaFlow.Serializer.NewtonsoftJson.csproj", "{FC622AB0-6481-4249-8D83-27BC39912103}" @@ -59,8 +53,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Serializer.Schema EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Middlewares", "Middlewares", "{ED24B548-6F37-4283-A35B-F6015BFB7A34}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.BatchConsume", "KafkaFlow.BatchConsume\KafkaFlow.BatchConsume.csproj", "{C891D0DB-BE19-4D20-9E2F-61D413210F8D}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Sample.BatchOperations", "..\samples\KafkaFlow.Sample.BatchOperations\KafkaFlow.Sample.BatchOperations.csproj", "{DE8A8871-B19E-489D-8292-386A06A4CDFA}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Extensions.Hosting", "KafkaFlow.Extensions.Hosting\KafkaFlow.Extensions.Hosting.csproj", "{7913342E-80FD-4094-B892-18DAA2E6948F}" @@ -127,18 +119,6 @@ Global {88808771-56BE-422B-94DC-7AB070F64E98}.Debug|Any CPU.Build.0 = Debug|Any CPU {88808771-56BE-422B-94DC-7AB070F64E98}.Release|Any CPU.ActiveCfg = Release|Any CPU {88808771-56BE-422B-94DC-7AB070F64E98}.Release|Any CPU.Build.0 = Release|Any CPU - {E47EF9E0-A1C7-4FF0-AEC5-143F52ED0FBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E47EF9E0-A1C7-4FF0-AEC5-143F52ED0FBE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E47EF9E0-A1C7-4FF0-AEC5-143F52ED0FBE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E47EF9E0-A1C7-4FF0-AEC5-143F52ED0FBE}.Release|Any CPU.Build.0 = Release|Any CPU - {B7197114-B1C7-49EC-8740-1E09233B2C40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B7197114-B1C7-49EC-8740-1E09233B2C40}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B7197114-B1C7-49EC-8740-1E09233B2C40}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B7197114-B1C7-49EC-8740-1E09233B2C40}.Release|Any CPU.Build.0 = Release|Any CPU - {D29EC709-33DE-4045-8F3B-EC6619CDB429}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D29EC709-33DE-4045-8F3B-EC6619CDB429}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D29EC709-33DE-4045-8F3B-EC6619CDB429}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D29EC709-33DE-4045-8F3B-EC6619CDB429}.Release|Any CPU.Build.0 = Release|Any CPU {36F459F4-8323-472A-A8C5-8C9D89F92012}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {36F459F4-8323-472A-A8C5-8C9D89F92012}.Debug|Any CPU.Build.0 = Debug|Any CPU {36F459F4-8323-472A-A8C5-8C9D89F92012}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -179,10 +159,6 @@ Global {2E63A019-F8AD-4EC3-A80A-F560DEC7C5B4}.Debug|Any CPU.Build.0 = Debug|Any CPU {2E63A019-F8AD-4EC3-A80A-F560DEC7C5B4}.Release|Any CPU.ActiveCfg = Release|Any CPU {2E63A019-F8AD-4EC3-A80A-F560DEC7C5B4}.Release|Any CPU.Build.0 = Release|Any CPU - {C891D0DB-BE19-4D20-9E2F-61D413210F8D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C891D0DB-BE19-4D20-9E2F-61D413210F8D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C891D0DB-BE19-4D20-9E2F-61D413210F8D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C891D0DB-BE19-4D20-9E2F-61D413210F8D}.Release|Any CPU.Build.0 = Release|Any CPU {DE8A8871-B19E-489D-8292-386A06A4CDFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DE8A8871-B19E-489D-8292-386A06A4CDFA}.Debug|Any CPU.Build.0 = Debug|Any CPU {DE8A8871-B19E-489D-8292-386A06A4CDFA}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -252,9 +228,6 @@ Global {ADAAA63C-E17C-4F1B-A062-3CCA071D75C2} = {ED24B548-6F37-4283-A35B-F6015BFB7A34} {0A782A83-B66D-4B99-9BE2-2B18AAD2E03C} = {ED24B548-6F37-4283-A35B-F6015BFB7A34} {88808771-56BE-422B-94DC-7AB070F64E98} = {068CB250-2804-4C7E-9490-17F432B9CE21} - {E47EF9E0-A1C7-4FF0-AEC5-143F52ED0FBE} = {ED24B548-6F37-4283-A35B-F6015BFB7A34} - {B7197114-B1C7-49EC-8740-1E09233B2C40} = {ADAAA63C-E17C-4F1B-A062-3CCA071D75C2} - {D29EC709-33DE-4045-8F3B-EC6619CDB429} = {0A782A83-B66D-4B99-9BE2-2B18AAD2E03C} {36F459F4-8323-472A-A8C5-8C9D89F92012} = {7A9B997B-DAAC-4004-94F3-32F6B88E0068} {FC622AB0-6481-4249-8D83-27BC39912103} = {ADAAA63C-E17C-4F1B-A062-3CCA071D75C2} {B86A51E3-7AC9-4EF8-BD2A-1ACC9EF0F5AE} = {292BCEDD-55B4-49BB-B8B2-24CD834FF2AA} @@ -265,7 +238,6 @@ Global {827620D3-2258-410E-A79E-E782ED42284C} = {58483813-0D7C-423E-8E7D-8FBF3E6CDB6D} {15C12D0C-FE8A-41F9-BBCF-5A963F05D5C7} = {303AE78F-6C96-4DF4-AC89-5C4FD53AFF0B} {2E63A019-F8AD-4EC3-A80A-F560DEC7C5B4} = {ADAAA63C-E17C-4F1B-A062-3CCA071D75C2} - {C891D0DB-BE19-4D20-9E2F-61D413210F8D} = {ED24B548-6F37-4283-A35B-F6015BFB7A34} {DE8A8871-B19E-489D-8292-386A06A4CDFA} = {303AE78F-6C96-4DF4-AC89-5C4FD53AFF0B} {7913342E-80FD-4094-B892-18DAA2E6948F} = {068CB250-2804-4C7E-9490-17F432B9CE21} {98C9826C-76F6-4C21-8A32-D55C2647905B} = {ADAAA63C-E17C-4F1B-A062-3CCA071D75C2} diff --git a/src/KafkaFlow.BatchConsume/BatchConsumeMessageContext.cs b/src/KafkaFlow/Batching/BatchConsumeMessageContext.cs similarity index 97% rename from src/KafkaFlow.BatchConsume/BatchConsumeMessageContext.cs rename to src/KafkaFlow/Batching/BatchConsumeMessageContext.cs index 9bc92fe33..41b994201 100644 --- a/src/KafkaFlow.BatchConsume/BatchConsumeMessageContext.cs +++ b/src/KafkaFlow/Batching/BatchConsumeMessageContext.cs @@ -1,4 +1,4 @@ -namespace KafkaFlow.BatchConsume +namespace KafkaFlow.Batching { using System; using System.Collections.Generic; diff --git a/src/KafkaFlow.BatchConsume/BatchConsumeMiddleware.cs b/src/KafkaFlow/Batching/BatchConsumeMiddleware.cs similarity index 99% rename from src/KafkaFlow.BatchConsume/BatchConsumeMiddleware.cs rename to src/KafkaFlow/Batching/BatchConsumeMiddleware.cs index a6f0621df..70e1f323e 100644 --- a/src/KafkaFlow.BatchConsume/BatchConsumeMiddleware.cs +++ b/src/KafkaFlow/Batching/BatchConsumeMiddleware.cs @@ -1,4 +1,4 @@ -namespace KafkaFlow.BatchConsume +namespace KafkaFlow.Batching { using System; using System.Collections.Generic; diff --git a/src/KafkaFlow.BatchConsume/BatchConsumeExtensions.cs b/src/KafkaFlow/Batching/BatchingExtensions.cs similarity index 90% rename from src/KafkaFlow.BatchConsume/BatchConsumeExtensions.cs rename to src/KafkaFlow/Batching/BatchingExtensions.cs index 9e3326156..00b100aa4 100644 --- a/src/KafkaFlow.BatchConsume/BatchConsumeExtensions.cs +++ b/src/KafkaFlow/Batching/BatchingExtensions.cs @@ -1,14 +1,15 @@ -namespace KafkaFlow.BatchConsume +namespace KafkaFlow { using System; using System.Collections.Generic; + using KafkaFlow.Batching; using KafkaFlow.Configuration; using KafkaFlow.Consumers; /// /// no needed /// - public static class BatchConsumeExtensions + public static class BatchingExtensions { /// /// Accumulates a group of messages to be passed as a batch to the next middleware as just one message @@ -17,7 +18,7 @@ public static class BatchConsumeExtensions /// The maximum size of the batch, when this limit is reached the next middleware will be called /// The maximum time the middleware will wait to call the next middleware /// - public static IConsumerMiddlewareConfigurationBuilder BatchConsume( + public static IConsumerMiddlewareConfigurationBuilder AddBatching( this IConsumerMiddlewareConfigurationBuilder builder, int batchSize, TimeSpan batchTimeout) @@ -32,7 +33,7 @@ public static IConsumerMiddlewareConfigurationBuilder BatchConsume( } /// - /// Gets the accumulated grouped by BatchConsume middleware + /// Gets the accumulated grouped by batching middleware /// /// The message context /// All the contexts in the batch diff --git a/src/KafkaFlow/Extensions/ConfigurationBuilderExtensions.cs b/src/KafkaFlow/Extensions/ConfigurationBuilderExtensions.cs index a5af5c77a..8189c22b5 100644 --- a/src/KafkaFlow/Extensions/ConfigurationBuilderExtensions.cs +++ b/src/KafkaFlow/Extensions/ConfigurationBuilderExtensions.cs @@ -7,6 +7,8 @@ namespace KafkaFlow using KafkaFlow.Configuration; using KafkaFlow.Consumers; using KafkaFlow.Consumers.WorkersBalancers; + using KafkaFlow.Middlewares.Compressor; + using KafkaFlow.Middlewares.TypedHandler; /// /// Provides extension methods over and @@ -174,5 +176,90 @@ public static IConsumerConfigurationBuilder WithConsumerLagWorkerBalancer( maxInstanceWorkers, TimeSpan.FromMinutes(5)); } + + /// + /// Adds typed handler middleware + /// + /// Instance of + /// A handler to configure the middleware + /// + public static IConsumerMiddlewareConfigurationBuilder AddTypedHandlers( + this IConsumerMiddlewareConfigurationBuilder builder, + Action configure) + { + var typedHandlerBuilder = new TypedHandlerConfigurationBuilder(builder.DependencyConfigurator); + + configure(typedHandlerBuilder); + + var configuration = typedHandlerBuilder.Build(); + + builder.Add( + resolver => new TypedHandlerMiddleware(resolver, configuration), + MiddlewareLifetime.Message); + + return builder; + } + + /// + /// Registers a middleware to decompress the message + /// + /// The middleware configuration builder + /// The compressor type + /// + [Obsolete("Compressors should only be used in backward compatibility scenarios, in the vast majority of cases native compression (producer.WithCompression()) should be used instead")] + public static IConsumerMiddlewareConfigurationBuilder AddDecompressor(this IConsumerMiddlewareConfigurationBuilder middlewares) + where T : class, IDecompressor + { + middlewares.DependencyConfigurator.AddTransient(); + return middlewares.AddDecompressor(resolver => resolver.Resolve()); + } + + /// + /// Registers a middleware to decompress the message + /// + /// The middleware configuration builder + /// The decompressor type that implements + /// A factory to create the instance + /// + [Obsolete("Compressors should only be used in backward compatibility scenarios, in the vast majority of cases native compression (producer.WithCompression()) should be used instead")] + public static IConsumerMiddlewareConfigurationBuilder AddDecompressor( + this IConsumerMiddlewareConfigurationBuilder middlewares, + Factory factory) + where T : class, IDecompressor + { + return middlewares.Add(resolver => new DecompressorConsumerMiddleware(factory(resolver))); + } + + /// + /// Registers a middleware to compress the message + /// It is highly recommended to use the producer native compression ('WithCompression()' method) instead of using the compressor middleware + /// + /// The middleware configuration builder + /// The compressor type that implements + /// + [Obsolete("Compressors should only be used in backward compatibility scenarios, in the vast majority of cases native compression (producer.WithCompression()) should be used instead")] + public static IProducerMiddlewareConfigurationBuilder AddCompressor(this IProducerMiddlewareConfigurationBuilder middlewares) + where T : class, ICompressor + { + middlewares.DependencyConfigurator.AddTransient(); + return middlewares.AddCompressor(resolver => resolver.Resolve()); + } + + /// + /// Registers a middleware to compress the message + /// It is highly recommended to use the producer native compression ('WithCompression()' method) instead of using the compressor middleware + /// + /// The middleware configuration builder + /// The compressor type that implements + /// A factory to create the instance + /// + [Obsolete("Compressors should only be used in backward compatibility scenarios, in the vast majority of cases native compression (producer.WithCompression()) should be used instead")] + public static IProducerMiddlewareConfigurationBuilder AddCompressor( + this IProducerMiddlewareConfigurationBuilder middlewares, + Factory factory) + where T : class, ICompressor + { + return middlewares.Add(resolver => new CompressorProducerMiddleware(factory(resolver))); + } } } diff --git a/src/KafkaFlow/KafkaFlow.csproj b/src/KafkaFlow/KafkaFlow.csproj index ddf21310f..a05e5e9e3 100644 --- a/src/KafkaFlow/KafkaFlow.csproj +++ b/src/KafkaFlow/KafkaFlow.csproj @@ -8,7 +8,9 @@ + + diff --git a/src/KafkaFlow.Compressor/CompressorProducerMiddleware.cs b/src/KafkaFlow/Middlewares/Compressor/CompressorProducerMiddleware.cs similarity index 79% rename from src/KafkaFlow.Compressor/CompressorProducerMiddleware.cs rename to src/KafkaFlow/Middlewares/Compressor/CompressorProducerMiddleware.cs index 89fa47d78..ed3ca3d42 100644 --- a/src/KafkaFlow.Compressor/CompressorProducerMiddleware.cs +++ b/src/KafkaFlow/Middlewares/Compressor/CompressorProducerMiddleware.cs @@ -1,4 +1,4 @@ -namespace KafkaFlow.Compressor +namespace KafkaFlow.Middlewares.Compressor { using System; using System.Threading.Tasks; @@ -8,13 +8,13 @@ /// public class CompressorProducerMiddleware : IMessageMiddleware { - private readonly IMessageCompressor compressor; + private readonly ICompressor compressor; /// /// Initializes a new instance of the class. /// - /// Instance of - public CompressorProducerMiddleware(IMessageCompressor compressor) + /// Instance of + public CompressorProducerMiddleware(ICompressor compressor) { this.compressor = compressor; } diff --git a/src/KafkaFlow.Compressor/CompressorConsumerMiddleware.cs b/src/KafkaFlow/Middlewares/Compressor/DecompressorConsumerMiddleware.cs similarity index 57% rename from src/KafkaFlow.Compressor/CompressorConsumerMiddleware.cs rename to src/KafkaFlow/Middlewares/Compressor/DecompressorConsumerMiddleware.cs index 033babbdc..d52ae8360 100644 --- a/src/KafkaFlow.Compressor/CompressorConsumerMiddleware.cs +++ b/src/KafkaFlow/Middlewares/Compressor/DecompressorConsumerMiddleware.cs @@ -1,4 +1,4 @@ -namespace KafkaFlow.Compressor +namespace KafkaFlow.Middlewares.Compressor { using System; using System.Threading.Tasks; @@ -6,17 +6,17 @@ /// /// Middleware to decompress the messages when consuming /// - public class CompressorConsumerMiddleware : IMessageMiddleware + public class DecompressorConsumerMiddleware : IMessageMiddleware { - private readonly IMessageCompressor compressor; + private readonly IDecompressor decompressor; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - /// Instance of - public CompressorConsumerMiddleware(IMessageCompressor compressor) + /// Instance of + public DecompressorConsumerMiddleware(IDecompressor decompressor) { - this.compressor = compressor; + this.decompressor = decompressor; } /// @@ -28,7 +28,7 @@ public Task Invoke(IMessageContext context, MiddlewareDelegate next) $"{nameof(context.Message.Value)} must be a byte array to be decompressed and it is '{context.Message.Value.GetType().FullName}'"); } - var data = this.compressor.Decompress(rawData); + var data = this.decompressor.Decompress(rawData); return next(context.SetMessage(context.Message.Key, data)); } diff --git a/src/KafkaFlow.Serializer/ConsumerMiddlewareConfigurationBuilderExtensions.cs b/src/KafkaFlow/Middlewares/Serializer/Configuration/ConsumerMiddlewareConfigurationBuilder.cs similarity index 62% rename from src/KafkaFlow.Serializer/ConsumerMiddlewareConfigurationBuilderExtensions.cs rename to src/KafkaFlow/Middlewares/Serializer/Configuration/ConsumerMiddlewareConfigurationBuilder.cs index dc80a5ead..bae8b29c6 100644 --- a/src/KafkaFlow.Serializer/ConsumerMiddlewareConfigurationBuilderExtensions.cs +++ b/src/KafkaFlow/Middlewares/Serializer/Configuration/ConsumerMiddlewareConfigurationBuilder.cs @@ -2,29 +2,31 @@ { using System; using KafkaFlow.Configuration; + using KafkaFlow.Middlewares.Serializer; + using KafkaFlow.Middlewares.Serializer.Resolvers; /// /// No needed /// - public static class ConsumerMiddlewareConfigurationBuilderExtensions + public static class ConsumerMiddlewareConfigurationBuilder { /// /// Registers a middleware to deserialize messages /// /// The middleware configuration builder - /// A class that implements + /// A class that implements /// A class that implements /// - public static IConsumerMiddlewareConfigurationBuilder AddSerializer( + public static IConsumerMiddlewareConfigurationBuilder AddDeserializer( this IConsumerMiddlewareConfigurationBuilder middlewares) - where TSerializer : class, ISerializer + where TDeserializer : class, IDeserializer where TResolver : class, IMessageTypeResolver { middlewares.DependencyConfigurator.AddTransient(); - middlewares.DependencyConfigurator.AddTransient(); + middlewares.DependencyConfigurator.AddTransient(); - return middlewares.AddSerializer( - resolver => resolver.Resolve(), + return middlewares.AddDeserializer( + resolver => resolver.Resolve(), resolver => resolver.Resolve()); } @@ -32,20 +34,20 @@ public static IConsumerMiddlewareConfigurationBuilder AddSerializer /// The middleware configuration builder - /// A class that implements + /// A class that implements /// A class that implements - /// A factory to create a + /// A factory to create a /// A factory to create a /// - public static IConsumerMiddlewareConfigurationBuilder AddSerializer( + public static IConsumerMiddlewareConfigurationBuilder AddDeserializer( this IConsumerMiddlewareConfigurationBuilder middlewares, - Factory serializerFactory, + Factory serializerFactory, Factory resolverFactory) - where TSerializer : class, ISerializer + where TDeserializer : class, IDeserializer where TResolver : class, IMessageTypeResolver { return middlewares.Add( - resolver => new SerializerConsumerMiddleware( + resolver => new DeserializerConsumerMiddleware( serializerFactory(resolver), resolverFactory(resolver))); } @@ -54,32 +56,32 @@ public static IConsumerMiddlewareConfigurationBuilder AddSerializer /// The middleware configuration builder - /// A class that implements + /// A class that implements /// - public static IConsumerMiddlewareConfigurationBuilder AddSerializer( + public static IConsumerMiddlewareConfigurationBuilder AddDeserializer( this IConsumerMiddlewareConfigurationBuilder middlewares) - where TSerializer : class, ISerializer + where TDeserializer : class, IDeserializer { - middlewares.DependencyConfigurator.AddTransient(); + middlewares.DependencyConfigurator.AddTransient(); - return middlewares.AddSerializer( - resolver => resolver.Resolve(), + return middlewares.AddDeserializer( + resolver => resolver.Resolve(), _ => new DefaultTypeResolver()); } /// /// Register a middleware to deserialize messages /// - /// A class that implements + /// A class that implements /// The middleware configuration builder - /// A factory to create a + /// A factory to create a /// - public static IConsumerMiddlewareConfigurationBuilder AddSerializer( + public static IConsumerMiddlewareConfigurationBuilder AddDeserializer( this IConsumerMiddlewareConfigurationBuilder middlewares, - Factory serializerFactory) - where TSerializer : class, ISerializer + Factory serializerFactory) + where TDeserializer : class, IDeserializer { - return middlewares.AddSerializer( + return middlewares.AddDeserializer( serializerFactory, _ => new DefaultTypeResolver()); } @@ -88,16 +90,16 @@ public static IConsumerMiddlewareConfigurationBuilder AddSerializer /// Register a middleware to deserialize the message to a fixed type /// /// The middleware configuration builder - /// A factory to create a + /// A factory to create a /// The message type - /// A class that implements + /// A class that implements /// - public static IConsumerMiddlewareConfigurationBuilder AddSingleTypeSerializer( + public static IConsumerMiddlewareConfigurationBuilder AddSingleTypeDeserializer( this IConsumerMiddlewareConfigurationBuilder middlewares, - Factory serializerFactory) - where TSerializer : class, ISerializer + Factory serializerFactory) + where TDeserializer : class, IDeserializer { - return middlewares.AddSerializer( + return middlewares.AddDeserializer( serializerFactory, _ => new SingleMessageTypeResolver(typeof(TMessage))); } @@ -107,13 +109,13 @@ public static IConsumerMiddlewareConfigurationBuilder AddSingleTypeSerializer /// The middleware configuration builder /// The message type - /// A class that implements + /// A class that implements /// - public static IConsumerMiddlewareConfigurationBuilder AddSingleTypeSerializer( + public static IConsumerMiddlewareConfigurationBuilder AddSingleTypeDeserializer( this IConsumerMiddlewareConfigurationBuilder middlewares) - where TSerializer : class, ISerializer + where TDeserializer : class, IDeserializer { - return middlewares.AddSingleTypeSerializer(typeof(TMessage)); + return middlewares.AddSingleTypeDeserializer(typeof(TMessage)); } /// @@ -121,17 +123,17 @@ public static IConsumerMiddlewareConfigurationBuilder AddSingleTypeSerializer /// The middleware configuration builder /// The message type - /// A class that implements + /// A class that implements /// - public static IConsumerMiddlewareConfigurationBuilder AddSingleTypeSerializer( + public static IConsumerMiddlewareConfigurationBuilder AddSingleTypeDeserializer( this IConsumerMiddlewareConfigurationBuilder middlewares, Type messageType) - where TSerializer : class, ISerializer + where TDeserializer : class, IDeserializer { - middlewares.DependencyConfigurator.AddTransient(); + middlewares.DependencyConfigurator.AddTransient(); - return middlewares.AddSerializer( - resolver => resolver.Resolve(), + return middlewares.AddDeserializer( + resolver => resolver.Resolve(), _ => new SingleMessageTypeResolver(messageType)); } @@ -139,17 +141,17 @@ public static IConsumerMiddlewareConfigurationBuilder AddSingleTypeSerializer /// The middleware configuration builder - /// A factory to create a + /// A factory to create a /// The message type - /// A class that implements + /// A class that implements /// - public static IConsumerMiddlewareConfigurationBuilder AddSingleTypeSerializer( + public static IConsumerMiddlewareConfigurationBuilder AddSingleTypeDeserializer( this IConsumerMiddlewareConfigurationBuilder middlewares, - Factory serializerFactory, + Factory serializerFactory, Type messageType) - where TSerializer : class, ISerializer + where TDeserializer : class, IDeserializer { - return middlewares.AddSerializer( + return middlewares.AddDeserializer( serializerFactory, _ => new SingleMessageTypeResolver(messageType)); } diff --git a/src/KafkaFlow.Serializer/ProducerMiddlewareConfigurationBuilder.cs b/src/KafkaFlow/Middlewares/Serializer/Configuration/ProducerMiddlewareConfigurationBuilder.cs similarity index 98% rename from src/KafkaFlow.Serializer/ProducerMiddlewareConfigurationBuilder.cs rename to src/KafkaFlow/Middlewares/Serializer/Configuration/ProducerMiddlewareConfigurationBuilder.cs index 4c05e5ae1..83b667532 100644 --- a/src/KafkaFlow.Serializer/ProducerMiddlewareConfigurationBuilder.cs +++ b/src/KafkaFlow/Middlewares/Serializer/Configuration/ProducerMiddlewareConfigurationBuilder.cs @@ -2,6 +2,8 @@ { using System; using KafkaFlow.Configuration; + using KafkaFlow.Middlewares.Serializer; + using KafkaFlow.Middlewares.Serializer.Resolvers; /// /// No needed diff --git a/src/KafkaFlow.Serializer/SerializerConsumerMiddleware.cs b/src/KafkaFlow/Middlewares/Serializer/DeserializerConsumerMiddleware.cs similarity index 78% rename from src/KafkaFlow.Serializer/SerializerConsumerMiddleware.cs rename to src/KafkaFlow/Middlewares/Serializer/DeserializerConsumerMiddleware.cs index a00a81d6b..191ae420a 100644 --- a/src/KafkaFlow.Serializer/SerializerConsumerMiddleware.cs +++ b/src/KafkaFlow/Middlewares/Serializer/DeserializerConsumerMiddleware.cs @@ -1,27 +1,28 @@ -namespace KafkaFlow +namespace KafkaFlow.Middlewares.Serializer { using System; using System.IO; using System.Threading.Tasks; + using KafkaFlow.Middlewares.Serializer.Resolvers; /// /// Middleware to deserialize messages when consuming /// - public class SerializerConsumerMiddleware : IMessageMiddleware + public class DeserializerConsumerMiddleware : IMessageMiddleware { - private readonly ISerializer serializer; + private readonly IDeserializer deserializer; private readonly IMessageTypeResolver typeResolver; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - /// Instance of + /// Instance of /// Instance of - public SerializerConsumerMiddleware( - ISerializer serializer, + public DeserializerConsumerMiddleware( + IDeserializer deserializer, IMessageTypeResolver typeResolver) { - this.serializer = serializer; + this.deserializer = deserializer; this.typeResolver = typeResolver; } @@ -61,7 +62,7 @@ public async Task Invoke(IMessageContext context, MiddlewareDelegate next) using var stream = new MemoryStream(rawData); - var data = await this.serializer + var data = await this.deserializer .DeserializeAsync( stream, messageType, diff --git a/src/KafkaFlow.Serializer/DefaultTypeResolver.cs b/src/KafkaFlow/Middlewares/Serializer/Resolvers/DefaultTypeResolver.cs similarity index 94% rename from src/KafkaFlow.Serializer/DefaultTypeResolver.cs rename to src/KafkaFlow/Middlewares/Serializer/Resolvers/DefaultTypeResolver.cs index 6613db2c9..b1bf40385 100644 --- a/src/KafkaFlow.Serializer/DefaultTypeResolver.cs +++ b/src/KafkaFlow/Middlewares/Serializer/Resolvers/DefaultTypeResolver.cs @@ -1,4 +1,4 @@ -namespace KafkaFlow +namespace KafkaFlow.Middlewares.Serializer.Resolvers { using System; using System.Threading.Tasks; diff --git a/src/KafkaFlow.Serializer/IMessageTypeResolver.cs b/src/KafkaFlow/Middlewares/Serializer/Resolvers/IMessageTypeResolver.cs similarity index 93% rename from src/KafkaFlow.Serializer/IMessageTypeResolver.cs rename to src/KafkaFlow/Middlewares/Serializer/Resolvers/IMessageTypeResolver.cs index a7b9190d8..44aba2ebf 100644 --- a/src/KafkaFlow.Serializer/IMessageTypeResolver.cs +++ b/src/KafkaFlow/Middlewares/Serializer/Resolvers/IMessageTypeResolver.cs @@ -1,4 +1,4 @@ -namespace KafkaFlow +namespace KafkaFlow.Middlewares.Serializer.Resolvers { using System; using System.Threading.Tasks; diff --git a/src/KafkaFlow.Serializer/SingleMessageTypeResolver.cs b/src/KafkaFlow/Middlewares/Serializer/Resolvers/SingleMessageTypeResolver.cs similarity index 94% rename from src/KafkaFlow.Serializer/SingleMessageTypeResolver.cs rename to src/KafkaFlow/Middlewares/Serializer/Resolvers/SingleMessageTypeResolver.cs index ee4cbc35c..bc75f6144 100644 --- a/src/KafkaFlow.Serializer/SingleMessageTypeResolver.cs +++ b/src/KafkaFlow/Middlewares/Serializer/Resolvers/SingleMessageTypeResolver.cs @@ -1,4 +1,4 @@ -namespace KafkaFlow +namespace KafkaFlow.Middlewares.Serializer.Resolvers { using System; using System.Threading.Tasks; diff --git a/src/KafkaFlow.Serializer/SerializerProducerMiddleware.cs b/src/KafkaFlow/Middlewares/Serializer/SerializerProducerMiddleware.cs similarity index 95% rename from src/KafkaFlow.Serializer/SerializerProducerMiddleware.cs rename to src/KafkaFlow/Middlewares/Serializer/SerializerProducerMiddleware.cs index 2adf0f443..b91f6fcb3 100644 --- a/src/KafkaFlow.Serializer/SerializerProducerMiddleware.cs +++ b/src/KafkaFlow/Middlewares/Serializer/SerializerProducerMiddleware.cs @@ -1,6 +1,7 @@ -namespace KafkaFlow +namespace KafkaFlow.Middlewares.Serializer { using System.Threading.Tasks; + using KafkaFlow.Middlewares.Serializer.Resolvers; using Microsoft.IO; /// diff --git a/src/KafkaFlow.TypedHandler/TypedHandlerConfiguration.cs b/src/KafkaFlow/Middlewares/TypedHandler/Configuration/TypedHandlerConfiguration.cs similarity index 79% rename from src/KafkaFlow.TypedHandler/TypedHandlerConfiguration.cs rename to src/KafkaFlow/Middlewares/TypedHandler/Configuration/TypedHandlerConfiguration.cs index 2f33874de..22d5407e2 100644 --- a/src/KafkaFlow.TypedHandler/TypedHandlerConfiguration.cs +++ b/src/KafkaFlow/Middlewares/TypedHandler/Configuration/TypedHandlerConfiguration.cs @@ -1,4 +1,4 @@ -namespace KafkaFlow.TypedHandler +namespace KafkaFlow.Middlewares.TypedHandler.Configuration { using System; diff --git a/src/KafkaFlow.TypedHandler/TypedHandlerConfigurationBuilder.cs b/src/KafkaFlow/Middlewares/TypedHandler/Configuration/TypedHandlerConfigurationBuilder.cs similarity index 98% rename from src/KafkaFlow.TypedHandler/TypedHandlerConfigurationBuilder.cs rename to src/KafkaFlow/Middlewares/TypedHandler/Configuration/TypedHandlerConfigurationBuilder.cs index f51775f90..acea49420 100644 --- a/src/KafkaFlow.TypedHandler/TypedHandlerConfigurationBuilder.cs +++ b/src/KafkaFlow/Middlewares/TypedHandler/Configuration/TypedHandlerConfigurationBuilder.cs @@ -1,10 +1,12 @@ -namespace KafkaFlow.TypedHandler +namespace KafkaFlow { using System; using System.Collections.Generic; using System.Linq; using System.Reflection; + using KafkaFlow.Middlewares.TypedHandler.Configuration; + /// /// Builder class for typed handler configuration /// diff --git a/src/KafkaFlow.TypedHandler/HandlerExecutor.cs b/src/KafkaFlow/Middlewares/TypedHandler/HandlerExecutor.cs similarity index 95% rename from src/KafkaFlow.TypedHandler/HandlerExecutor.cs rename to src/KafkaFlow/Middlewares/TypedHandler/HandlerExecutor.cs index 4a301ff08..0af39ecd0 100644 --- a/src/KafkaFlow.TypedHandler/HandlerExecutor.cs +++ b/src/KafkaFlow/Middlewares/TypedHandler/HandlerExecutor.cs @@ -1,4 +1,4 @@ -namespace KafkaFlow.TypedHandler +namespace KafkaFlow.Middlewares.TypedHandler { using System; using System.Collections.Concurrent; diff --git a/src/KafkaFlow.TypedHandler/HandlerTypeMapping.cs b/src/KafkaFlow/Middlewares/TypedHandler/HandlerTypeMapping.cs similarity index 95% rename from src/KafkaFlow.TypedHandler/HandlerTypeMapping.cs rename to src/KafkaFlow/Middlewares/TypedHandler/HandlerTypeMapping.cs index cc581f753..986ee1c2a 100644 --- a/src/KafkaFlow.TypedHandler/HandlerTypeMapping.cs +++ b/src/KafkaFlow/Middlewares/TypedHandler/HandlerTypeMapping.cs @@ -1,4 +1,4 @@ -namespace KafkaFlow.TypedHandler +namespace KafkaFlow.Middlewares.TypedHandler { using System; using System.Collections.Generic; diff --git a/src/KafkaFlow.TypedHandler/TypedHandlerMiddleware.cs b/src/KafkaFlow/Middlewares/TypedHandler/TypedHandlerMiddleware.cs similarity index 93% rename from src/KafkaFlow.TypedHandler/TypedHandlerMiddleware.cs rename to src/KafkaFlow/Middlewares/TypedHandler/TypedHandlerMiddleware.cs index 7269228db..37d308491 100644 --- a/src/KafkaFlow.TypedHandler/TypedHandlerMiddleware.cs +++ b/src/KafkaFlow/Middlewares/TypedHandler/TypedHandlerMiddleware.cs @@ -1,7 +1,8 @@ -namespace KafkaFlow.TypedHandler +namespace KafkaFlow.Middlewares.TypedHandler { using System.Linq; using System.Threading.Tasks; + using KafkaFlow.Middlewares.TypedHandler.Configuration; internal class TypedHandlerMiddleware : IMessageMiddleware { From e51f120128dfd8787addcfc52a51eb3aba305182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sim=C3=A3o=20Ribeiro?= Date: Mon, 23 Oct 2023 18:43:02 +0100 Subject: [PATCH 13/20] feat: adapt open telemetry to release 3.0 Include peer.service tag for producer and consumer spans Close consumer span when Complete() is invoked to have a correctly time closing for both single and batch consumers --- src/KafkaFlow.Abstractions/IMessageContext.cs | 5 +++++ .../ActivitySourceAccessor.cs | 3 ++- .../OpenTelemetryConsumerEventsHandler.cs | 4 ++-- .../OpenTelemetryProducerEventsHandler.cs | 2 +- .../BatchConsume/BatchConsumeMiddlewareTests.cs | 7 +++++++ .../Batching/BatchConsumeMessageContext.cs | 6 +++++- src/KafkaFlow/Batching/BatchConsumeMiddleware.cs | 2 +- src/KafkaFlow/Consumers/ConsumerWorker.cs | 13 +++++++++++-- src/KafkaFlow/Consumers/ConsumerWorkerPool.cs | 3 ++- src/KafkaFlow/MessageContext.cs | 9 +++++++-- src/KafkaFlow/Producers/MessageProducer.cs | 3 ++- website/docs/guides/global-events.md | 6 +----- 12 files changed, 46 insertions(+), 17 deletions(-) diff --git a/src/KafkaFlow.Abstractions/IMessageContext.cs b/src/KafkaFlow.Abstractions/IMessageContext.cs index f34ec0fb1..8b39dba96 100644 --- a/src/KafkaFlow.Abstractions/IMessageContext.cs +++ b/src/KafkaFlow.Abstractions/IMessageContext.cs @@ -39,6 +39,11 @@ public interface IMessageContext /// IDependencyResolver DependencyResolver { get; } + /// + /// Gets the brokers associated with the message + /// + public IReadOnlyCollection Brokers { get; } + /// /// Creates a new with the new message /// diff --git a/src/KafkaFlow.OpenTelemetry/ActivitySourceAccessor.cs b/src/KafkaFlow.OpenTelemetry/ActivitySourceAccessor.cs index 66c801536..8a9294e9e 100644 --- a/src/KafkaFlow.OpenTelemetry/ActivitySourceAccessor.cs +++ b/src/KafkaFlow.OpenTelemetry/ActivitySourceAccessor.cs @@ -18,6 +18,7 @@ internal static class ActivitySourceAccessor internal static void SetGenericTags(Activity activity) { activity?.SetTag(Conventions.AttributeMessagingSystem, MessagingSystemId); + activity?.SetTag(Conventions.AttributePeerService, string.Join(",", bootstrapServers ?? Enumerable.Empty())); } } -} +} \ No newline at end of file diff --git a/src/KafkaFlow.OpenTelemetry/OpenTelemetryConsumerEventsHandler.cs b/src/KafkaFlow.OpenTelemetry/OpenTelemetryConsumerEventsHandler.cs index cea4febc2..f884f8540 100644 --- a/src/KafkaFlow.OpenTelemetry/OpenTelemetryConsumerEventsHandler.cs +++ b/src/KafkaFlow.OpenTelemetry/OpenTelemetryConsumerEventsHandler.cs @@ -39,7 +39,7 @@ public static Task OnConsumeStarted(IMessageContext context) context?.Items.Add(ActivitySourceAccessor.ActivityString, activity); - ActivitySourceAccessor.SetGenericTags(activity); + ActivitySourceAccessor.SetGenericTags(activity, context?.Brokers); if (activity != null && activity.IsAllDataRequested) { @@ -84,7 +84,7 @@ private static IEnumerable ExtractTraceContextIntoBasicProperties(IMessa private static void SetConsumerTags(IMessageContext context, Activity activity) { - var messageKey = Encoding.UTF8.GetString(context.Message.Key as byte[]); + string messageKey = context.Message.Key != null ? Encoding.UTF8.GetString(context.Message.Key as byte[]) : string.Empty; activity.SetTag(ActivitySourceAccessor.AttributeMessagingOperation, ProcessString); activity.SetTag(AttributeMessagingSourceName, context.ConsumerContext.Topic); diff --git a/src/KafkaFlow.OpenTelemetry/OpenTelemetryProducerEventsHandler.cs b/src/KafkaFlow.OpenTelemetry/OpenTelemetryProducerEventsHandler.cs index 403e257d1..09275f938 100644 --- a/src/KafkaFlow.OpenTelemetry/OpenTelemetryProducerEventsHandler.cs +++ b/src/KafkaFlow.OpenTelemetry/OpenTelemetryProducerEventsHandler.cs @@ -49,7 +49,7 @@ public static Task OnProducerStarted(IMessageContext context) // Inject the ActivityContext into the message headers to propagate trace context to the receiving service. Propagator.Inject(new PropagationContext(contextToInject, Baggage.Current), context, InjectTraceContextIntoBasicProperties); - ActivitySourceAccessor.SetGenericTags(activity); + ActivitySourceAccessor.SetGenericTags(activity, context?.Brokers); if (activity != null && activity.IsAllDataRequested) { diff --git a/src/KafkaFlow.UnitTests/BatchConsume/BatchConsumeMiddlewareTests.cs b/src/KafkaFlow.UnitTests/BatchConsume/BatchConsumeMiddlewareTests.cs index 819b324ed..0f8b27be7 100644 --- a/src/KafkaFlow.UnitTests/BatchConsume/BatchConsumeMiddlewareTests.cs +++ b/src/KafkaFlow.UnitTests/BatchConsume/BatchConsumeMiddlewareTests.cs @@ -1,7 +1,9 @@ namespace KafkaFlow.UnitTests.BatchConsume { using System; + using System.Collections.Generic; using System.Threading.Tasks; + using AutoFixture; using FluentAssertions; using KafkaFlow.Batching; using KafkaFlow.Configuration; @@ -16,6 +18,7 @@ public class BatchConsumeMiddlewareTests private readonly TimeSpan batchTimeout = TimeSpan.FromMilliseconds(1000); private readonly TimeSpan waitForTaskExecution = TimeSpan.FromMilliseconds(100); + private readonly Fixture fixture = new(); private Mock logHandlerMock; @@ -37,6 +40,10 @@ public void Setup() var consumerMock = new Mock(); var consumerConfigurationMock = new Mock(); + var clusterConfig = this.fixture.Create(); + + consumerConfigurationMock.SetupGet(x => x.ClusterConfiguration).Returns(clusterConfig); + middlewareContextMock .SetupGet(x => x.Worker) .Returns(workerMock.Object); diff --git a/src/KafkaFlow/Batching/BatchConsumeMessageContext.cs b/src/KafkaFlow/Batching/BatchConsumeMessageContext.cs index 41b994201..b398876ae 100644 --- a/src/KafkaFlow/Batching/BatchConsumeMessageContext.cs +++ b/src/KafkaFlow/Batching/BatchConsumeMessageContext.cs @@ -9,12 +9,14 @@ internal class BatchConsumeMessageContext : IMessageContext, IDisposable public BatchConsumeMessageContext( IConsumerContext consumer, - IReadOnlyCollection batchMessage) + IReadOnlyCollection batchMessage, + IReadOnlyCollection brokers) { this.ConsumerContext = consumer; this.Message = new Message(null, batchMessage); this.batchDependencyScope = consumer.WorkerDependencyResolver.CreateScope(); this.Items = new Dictionary(); + this.Brokers = brokers; } public Message Message { get; } @@ -29,6 +31,8 @@ public BatchConsumeMessageContext( public IDictionary Items { get; } + public IReadOnlyCollection Brokers { get; } + public IMessageContext SetMessage(object key, object value) => throw new NotSupportedException($"{nameof(BatchConsumeMessageContext)} does not allow to change the message"); diff --git a/src/KafkaFlow/Batching/BatchConsumeMiddleware.cs b/src/KafkaFlow/Batching/BatchConsumeMiddleware.cs index 70e1f323e..c371bb80f 100644 --- a/src/KafkaFlow/Batching/BatchConsumeMiddleware.cs +++ b/src/KafkaFlow/Batching/BatchConsumeMiddleware.cs @@ -106,7 +106,7 @@ private async Task DispatchAsync(IMessageContext context, MiddlewareDelegate nex return; } - var batchContext = new BatchConsumeMessageContext(context.ConsumerContext, localBatch); + var batchContext = new BatchConsumeMessageContext(context.ConsumerContext, localBatch, this.consumerConfiguration.ClusterConfiguration.Brokers); await next(batchContext).ConfigureAwait(false); } diff --git a/src/KafkaFlow/Consumers/ConsumerWorker.cs b/src/KafkaFlow/Consumers/ConsumerWorker.cs index ea0dfa6c1..a40f2143a 100644 --- a/src/KafkaFlow/Consumers/ConsumerWorker.cs +++ b/src/KafkaFlow/Consumers/ConsumerWorker.cs @@ -131,11 +131,20 @@ private async Task ProcessMessageAsync(IMessageContext context, CancellationToke { await this.globalEvents.FireMessageConsumeStartedAsync(new MessageEventContext(context)); + _= context.ConsumerContext.Completion.ContinueWith( + async task => + { + if (task.IsFaulted) + { + await this.globalEvents.FireMessageConsumeErrorAsync(new MessageErrorEventContext(context, task.Exception)); + } + + await this.globalEvents.FireMessageConsumeCompletedAsync(new MessageEventContext(context)); + }); + await this.middlewareExecutor .Execute(context, _ => Task.CompletedTask) .ConfigureAwait(false); - - await this.globalEvents.FireMessageConsumeCompletedAsync(new MessageEventContext(context)); } catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) { diff --git a/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs b/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs index 5774d2c9e..587d6aaaf 100644 --- a/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs +++ b/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs @@ -162,7 +162,8 @@ private MessageContext CreateMessageContext(ConsumeResult messag worker, messageDependencyScope, this.consumerDependencyResolver), - null); + null, + this.consumer.Configuration.ClusterConfiguration.Brokers); return context; } } diff --git a/src/KafkaFlow/MessageContext.cs b/src/KafkaFlow/MessageContext.cs index b86d0e67b..e59f50bb4 100644 --- a/src/KafkaFlow/MessageContext.cs +++ b/src/KafkaFlow/MessageContext.cs @@ -9,7 +9,8 @@ public MessageContext( IMessageHeaders headers, IDependencyResolver dependencyResolver, IConsumerContext consumer, - IProducerContext producer) + IProducerContext producer, + IReadOnlyCollection brokers) { this.Message = message; this.DependencyResolver = dependencyResolver; @@ -17,6 +18,7 @@ public MessageContext( this.ConsumerContext = consumer; this.ProducerContext = producer; this.Items = new Dictionary(); + this.Brokers = brokers; } public Message Message { get; } @@ -31,11 +33,14 @@ public MessageContext( public IDictionary Items { get; } + public IReadOnlyCollection Brokers { get; } + public IMessageContext SetMessage(object key, object value) => new MessageContext( new Message(key, value), this.Headers, this.DependencyResolver, this.ConsumerContext, - this.ProducerContext); + this.ProducerContext, + this.Brokers); } } diff --git a/src/KafkaFlow/Producers/MessageProducer.cs b/src/KafkaFlow/Producers/MessageProducer.cs index 124894916..ab12773d3 100644 --- a/src/KafkaFlow/Producers/MessageProducer.cs +++ b/src/KafkaFlow/Producers/MessageProducer.cs @@ -360,7 +360,8 @@ private MessageContext CreateMessageContext( headers, messageScopedResolver, null, - new ProducerContext(topic, this.producerDependencyScope.Resolver)); + new ProducerContext(topic, this.producerDependencyScope.Resolver), + this.configuration.Cluster.Brokers); } } } diff --git a/website/docs/guides/global-events.md b/website/docs/guides/global-events.md index 87803b12d..b8eae9c2f 100644 --- a/website/docs/guides/global-events.md +++ b/website/docs/guides/global-events.md @@ -4,7 +4,7 @@ sidebar_position: 9 # Global Events -In this section, we will delve into the concept of Global Events in KafkaFlow, which provides a mechanism to subscribe to various events that are triggered during the message production and consumption processes. +In this section, we will delve into the concept of Global Events in KafkaFlow, which provides a mechanism to subscribe to various events that are triggered during the message production and consumption processes. KafkaFlow offers a range of Global Events that can be subscribed to. These events can be used to monitor and react to different stages of message handling. Below is a list of available events: - [Message Produce Started Event](#message-produce-started-event) @@ -82,10 +82,6 @@ services.AddKafka( The Message Consume Completed Event signals the successful completion of message consumption. By subscribing to this event, you can track when messages have been successfully processed. -:::info -Please note that the current event is not compatible with Batch Consume in the current version (v2). However, this limitation is expected to be addressed in future releases (v3+). -:::info - ```csharp services.AddKafka( kafka => kafka From e7a2e3749c1dbd1d958a9102417db794f7168861 Mon Sep 17 00:00:00 2001 From: Filipe Esch Date: Tue, 10 Oct 2023 10:35:07 +0100 Subject: [PATCH 14/20] feat: evolve worker distribution strategy --- .../IConsumerConfigurationBuilder.cs | 14 ++-- .../IDistributionStrategy.cs | 26 -------- .../IWorkerDistributionStrategy.cs | 23 +++++++ .../KafkaFlow.Abstractions.csproj | 5 ++ .../WorkerDistributionContext.cs | 57 +++++++++++++++++ .../Configuration/ConsumerConfiguration.cs | 4 +- .../ConsumerConfigurationBuilder.cs | 10 +-- .../Configuration/IConsumerConfiguration.cs | 2 +- src/KafkaFlow/Consumers/ConsumerWorkerPool.cs | 16 +++-- .../BytesSumDistributionStrategy.cs | 64 +++++++++---------- .../FreeWorkerDistributionStrategy.cs | 48 +++++++------- 11 files changed, 165 insertions(+), 104 deletions(-) delete mode 100644 src/KafkaFlow.Abstractions/IDistributionStrategy.cs create mode 100644 src/KafkaFlow.Abstractions/IWorkerDistributionStrategy.cs create mode 100644 src/KafkaFlow.Abstractions/WorkerDistributionContext.cs diff --git a/src/KafkaFlow.Abstractions/Configuration/IConsumerConfigurationBuilder.cs b/src/KafkaFlow.Abstractions/Configuration/IConsumerConfigurationBuilder.cs index 830eb0555..68ece2959 100644 --- a/src/KafkaFlow.Abstractions/Configuration/IConsumerConfigurationBuilder.cs +++ b/src/KafkaFlow.Abstractions/Configuration/IConsumerConfigurationBuilder.cs @@ -137,19 +137,19 @@ IConsumerConfigurationBuilder WithWorkersCount( /// /// Sets the strategy to choose a worker when a message arrives /// - /// A class that implements the interface + /// A class that implements the interface /// A factory to create the instance /// - IConsumerConfigurationBuilder WithWorkDistributionStrategy(Factory factory) - where T : class, IDistributionStrategy; + IConsumerConfigurationBuilder WithWorkerDistributionStrategy(Factory factory) + where T : class, IWorkerDistributionStrategy; /// /// Sets the strategy to choose a worker when a message arrives /// - /// A class that implements the interface + /// A class that implements the interface /// - IConsumerConfigurationBuilder WithWorkDistributionStrategy() - where T : class, IDistributionStrategy; + IConsumerConfigurationBuilder WithWorkerDistributionStrategy() + where T : class, IWorkerDistributionStrategy; /// /// Configures the consumer for manual message completion. @@ -192,4 +192,4 @@ IConsumerConfigurationBuilder WithWorkDistributionStrategy() /// IConsumerConfigurationBuilder WithStatisticsIntervalMs(int statisticsIntervalMs); } -} +} \ No newline at end of file diff --git a/src/KafkaFlow.Abstractions/IDistributionStrategy.cs b/src/KafkaFlow.Abstractions/IDistributionStrategy.cs deleted file mode 100644 index 591ade02d..000000000 --- a/src/KafkaFlow.Abstractions/IDistributionStrategy.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace KafkaFlow -{ - using System.Collections.Generic; - using System.Threading; - using System.Threading.Tasks; - - /// - /// An interface used to create a distribution strategy - /// - public interface IDistributionStrategy - { - /// - /// Initializes the distribution strategy, this method is called when a consumer is started - /// - /// List of workers to be initialized - void Init(IReadOnlyList workers); - - /// - /// Gets an available worker to process the message - /// - /// Message partition key - /// A that is cancelled when the consumers stops - /// - Task GetWorkerAsync(byte[] partitionKey, CancellationToken cancellationToken); - } -} diff --git a/src/KafkaFlow.Abstractions/IWorkerDistributionStrategy.cs b/src/KafkaFlow.Abstractions/IWorkerDistributionStrategy.cs new file mode 100644 index 000000000..c883b2f7a --- /dev/null +++ b/src/KafkaFlow.Abstractions/IWorkerDistributionStrategy.cs @@ -0,0 +1,23 @@ +namespace KafkaFlow; + +using System.Collections.Generic; +using System.Threading.Tasks; + +/// +/// An interface used to create a distribution strategy +/// +public interface IWorkerDistributionStrategy +{ + /// + /// Initializes the distribution strategy, this method is called when a consumer is started + /// + /// List of workers to be initialized + void Initialize(IReadOnlyList workers); + + /// + /// Retrieves an available worker based on the provided distribution strategy context. + /// + /// The distribution strategy context containing message and consumer details. + /// The selected instance. + ValueTask GetWorkerAsync(WorkerDistributionContext context); +} diff --git a/src/KafkaFlow.Abstractions/KafkaFlow.Abstractions.csproj b/src/KafkaFlow.Abstractions/KafkaFlow.Abstractions.csproj index 50e3dd839..283ef9c6b 100644 --- a/src/KafkaFlow.Abstractions/KafkaFlow.Abstractions.csproj +++ b/src/KafkaFlow.Abstractions/KafkaFlow.Abstractions.csproj @@ -7,4 +7,9 @@ Contains all KafkaFlow extendable interfaces + + + + + diff --git a/src/KafkaFlow.Abstractions/WorkerDistributionContext.cs b/src/KafkaFlow.Abstractions/WorkerDistributionContext.cs new file mode 100644 index 000000000..43c3ce04d --- /dev/null +++ b/src/KafkaFlow.Abstractions/WorkerDistributionContext.cs @@ -0,0 +1,57 @@ +namespace KafkaFlow; + +using System; +using System.Threading; + +/// +/// Represents a strategy context for distributing workers based on specific message and consumer details. +/// +public ref struct WorkerDistributionContext +{ + /// + /// Initializes a new instance of the struct. + /// + /// Name of the consumer. + /// Topic associated with the message. + /// Partition of the topic. + /// Raw key of the message. + /// A cancellation token that is cancelled when the consumer has stopped + public WorkerDistributionContext( + string consumerName, + string topic, + int partition, + ReadOnlyMemory? rawMessageKey, + CancellationToken consumerStoppedCancellationToken) + { + this.ConsumerName = consumerName; + this.Topic = topic; + this.Partition = partition; + this.RawMessageKey = rawMessageKey; + this.ConsumerStoppedCancellationToken = consumerStoppedCancellationToken; + } + + /// + /// Gets the name of the consumer. + /// + public string ConsumerName { get; } + + /// + /// Gets the topic associated with the message. + /// + public string Topic { get; } + + /// + /// Gets the partition number of the topic. + /// + public int Partition { get; } + + /// + /// Gets the raw key of the message. + /// + public ReadOnlyMemory? RawMessageKey { get; } + + /// + /// Gets the cancellation token that is cancelled when the consumer has stopped + /// + public CancellationToken ConsumerStoppedCancellationToken { get; } +} diff --git a/src/KafkaFlow/Configuration/ConsumerConfiguration.cs b/src/KafkaFlow/Configuration/ConsumerConfiguration.cs index a74de9d43..01eca3090 100644 --- a/src/KafkaFlow/Configuration/ConsumerConfiguration.cs +++ b/src/KafkaFlow/Configuration/ConsumerConfiguration.cs @@ -20,7 +20,7 @@ public ConsumerConfiguration( TimeSpan workersCountEvaluationInterval, int bufferSize, TimeSpan workerStopTimeout, - Factory distributionStrategyFactory, + Factory distributionStrategyFactory, IReadOnlyList middlewaresConfigurations, bool autoMessageCompletion, bool noStoreOffsets, @@ -69,7 +69,7 @@ public ConsumerConfiguration( "The value must be greater than 0"); } - public Factory DistributionStrategyFactory { get; } + public Factory DistributionStrategyFactory { get; } public IReadOnlyList MiddlewaresConfigurations { get; } diff --git a/src/KafkaFlow/Configuration/ConsumerConfigurationBuilder.cs b/src/KafkaFlow/Configuration/ConsumerConfigurationBuilder.cs index e1c027151..b0544080b 100644 --- a/src/KafkaFlow/Configuration/ConsumerConfigurationBuilder.cs +++ b/src/KafkaFlow/Configuration/ConsumerConfigurationBuilder.cs @@ -36,7 +36,7 @@ internal sealed class ConsumerConfigurationBuilder : IConsumerConfigurationBuild private ConsumerInitialState initialState = ConsumerInitialState.Running; private int statisticsInterval; - private Factory distributionStrategyFactory = _ => new BytesSumDistributionStrategy(); + private Factory distributionStrategyFactory = _ => new BytesSumDistributionStrategy(); private TimeSpan autoCommitInterval = TimeSpan.FromSeconds(5); private ConsumerCustomFactory customFactory = (consumer, _) => consumer; @@ -157,15 +157,15 @@ public IConsumerConfigurationBuilder WithWorkerStopTimeout(TimeSpan timeout) return this; } - public IConsumerConfigurationBuilder WithWorkDistributionStrategy(Factory factory) - where T : class, IDistributionStrategy + public IConsumerConfigurationBuilder WithWorkerDistributionStrategy(Factory factory) + where T : class, IWorkerDistributionStrategy { this.distributionStrategyFactory = factory; return this; } - public IConsumerConfigurationBuilder WithWorkDistributionStrategy() - where T : class, IDistributionStrategy + public IConsumerConfigurationBuilder WithWorkerDistributionStrategy() + where T : class, IWorkerDistributionStrategy { this.DependencyConfigurator.AddTransient(); this.distributionStrategyFactory = resolver => resolver.Resolve(); diff --git a/src/KafkaFlow/Configuration/IConsumerConfiguration.cs b/src/KafkaFlow/Configuration/IConsumerConfiguration.cs index 4099867b9..21f5b6896 100644 --- a/src/KafkaFlow/Configuration/IConsumerConfiguration.cs +++ b/src/KafkaFlow/Configuration/IConsumerConfiguration.cs @@ -13,7 +13,7 @@ public interface IConsumerConfiguration /// /// Gets the consumer worker distribution strategy /// - Factory DistributionStrategyFactory { get; } + Factory DistributionStrategyFactory { get; } /// /// Gets the consumer middlewares configurations diff --git a/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs b/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs index 587d6aaaf..2c45bc2fe 100644 --- a/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs +++ b/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs @@ -14,7 +14,7 @@ internal class ConsumerWorkerPool : IConsumerWorkerPool private readonly IDependencyResolver consumerDependencyResolver; private readonly IMiddlewareExecutor middlewareExecutor; private readonly ILogHandler logHandler; - private readonly Factory distributionStrategyFactory; + private readonly Factory distributionStrategyFactory; private readonly IOffsetCommitter offsetCommitter; private readonly Event workerPoolStoppedSubject; @@ -22,7 +22,7 @@ internal class ConsumerWorkerPool : IConsumerWorkerPool private TaskCompletionSource startedTaskSource = new(); private List workers = new(); - private IDistributionStrategy distributionStrategy; + private IWorkerDistributionStrategy distributionStrategy; private IOffsetManager offsetManager; public ConsumerWorkerPool( @@ -85,7 +85,7 @@ await Task.WhenAll( .ConfigureAwait(false); this.distributionStrategy = this.distributionStrategyFactory(this.consumerDependencyResolver); - this.distributionStrategy.Init(this.workers.AsReadOnly()); + this.distributionStrategy.Initialize(this.workers.AsReadOnly()); this.startedTaskSource.TrySetResult(null); } @@ -130,7 +130,13 @@ public async Task EnqueueAsync(ConsumeResult message, Cancellati await this.startedTaskSource.Task.ConfigureAwait(false); var worker = (IConsumerWorker)await this.distributionStrategy - .GetWorkerAsync(message.Message.Key, stopCancellationToken) + .GetWorkerAsync( + new WorkerDistributionContext( + this.consumer.Configuration.ConsumerName, + message.Topic, + message.Partition.Value, + message.Message.Key, + stopCancellationToken)) .ConfigureAwait(false); if (worker is null) @@ -167,4 +173,4 @@ private MessageContext CreateMessageContext(ConsumeResult messag return context; } } -} +} \ No newline at end of file diff --git a/src/KafkaFlow/Consumers/DistributionStrategies/BytesSumDistributionStrategy.cs b/src/KafkaFlow/Consumers/DistributionStrategies/BytesSumDistributionStrategy.cs index 5c5409839..6581cbb6d 100644 --- a/src/KafkaFlow/Consumers/DistributionStrategies/BytesSumDistributionStrategy.cs +++ b/src/KafkaFlow/Consumers/DistributionStrategies/BytesSumDistributionStrategy.cs @@ -1,44 +1,42 @@ -namespace KafkaFlow.Consumers.DistributionStrategies +namespace KafkaFlow.Consumers.DistributionStrategies; + +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +/// +/// This strategy sums all bytes in the partition key and apply a mod operator with the total number of workers, the resulting number is the worker ID to be chosen +/// This algorithm is fast and creates a good work balance. Messages with the same partition key are always delivered in the same worker, so, message order is guaranteed +/// Set an optimal message buffer value to avoid idle workers (it will depends how many messages with the same partition key are consumed) +/// +public class BytesSumDistributionStrategy : IWorkerDistributionStrategy { - using System.Collections.Generic; - using System.Linq; - using System.Threading; - using System.Threading.Tasks; + private IReadOnlyList workers; - /// - /// This strategy sums all bytes in the partition key and apply a mod operator with the total number of workers, the resulting number is the worker ID to be chosen - /// This algorithm is fast and creates a good work balance. Messages with the same partition key are always delivered in the same worker, so, message order is guaranteed - /// Set an optimal message buffer value to avoid idle workers (it will depends how many messages with the same partition key are consumed) - /// - public class BytesSumDistributionStrategy : IDistributionStrategy + /// + public void Initialize(IReadOnlyList workers) { - private IReadOnlyList workers; + this.workers = workers; + } - /// - public void Init(IReadOnlyList workers) + /// + public ValueTask GetWorkerAsync(WorkerDistributionContext context) + { + if (context.RawMessageKey is null || this.workers.Count == 1) { - this.workers = workers; + return new ValueTask(this.workers[0]); } - /// - public Task GetWorkerAsync(byte[] partitionKey, CancellationToken cancellationToken) - { - if (partitionKey is null || this.workers.Count == 1) - { - return Task.FromResult(this.workers[0]); - } + var bytesSum = 0; - var bytesSum = 0; - - for (int i = 0; i < partitionKey.Length; i++) - { - bytesSum += partitionKey[i]; - } - - return Task.FromResult( - cancellationToken.IsCancellationRequested - ? null - : this.workers.ElementAtOrDefault(bytesSum % this.workers.Count)); + for (var i = 0; i < context.RawMessageKey.Value.Length; i++) + { + bytesSum += context.RawMessageKey.Value.Span[i]; } + + return new ValueTask( + context.ConsumerStoppedCancellationToken.IsCancellationRequested + ? null + : this.workers.ElementAtOrDefault(bytesSum % this.workers.Count)); } } diff --git a/src/KafkaFlow/Consumers/DistributionStrategies/FreeWorkerDistributionStrategy.cs b/src/KafkaFlow/Consumers/DistributionStrategies/FreeWorkerDistributionStrategy.cs index e9761ae90..9511a868a 100644 --- a/src/KafkaFlow/Consumers/DistributionStrategies/FreeWorkerDistributionStrategy.cs +++ b/src/KafkaFlow/Consumers/DistributionStrategies/FreeWorkerDistributionStrategy.cs @@ -1,32 +1,30 @@ -namespace KafkaFlow.Consumers.DistributionStrategies +namespace KafkaFlow.Consumers.DistributionStrategies; + +using System.Collections.Generic; +using System.Threading.Channels; +using System.Threading.Tasks; + +/// +/// This strategy chooses the first free worker to process the message. When a worker finishes the processing, it notifies the worker pool that it is free to get a new message +/// This is the fastest and resource-friendly strategy (the message buffer is not used) but messages with the same partition key can be delivered in different workers, so, no message order guarantee +/// +public class FreeWorkerDistributionStrategy : IWorkerDistributionStrategy { - using System.Collections.Generic; - using System.Threading; - using System.Threading.Channels; - using System.Threading.Tasks; + private readonly Channel freeWorkers = Channel.CreateUnbounded(); - /// - /// This strategy chooses the first free worker to process the message. When a worker finishes the processing, it notifies the worker pool that it is free to get a new message - /// This is the fastest and resource-friendly strategy (the message buffer is not used) but messages with the same partition key can be delivered in different workers, so, no message order guarantee - /// - public class FreeWorkerDistributionStrategy : IDistributionStrategy + /// + public void Initialize(IReadOnlyList workers) { - private readonly Channel freeWorkers = Channel.CreateUnbounded(); - - /// - public void Init(IReadOnlyList workers) + foreach (var worker in workers) { - foreach (var worker in workers) - { - worker.WorkerProcessingEnded.Subscribe(_ => Task.FromResult(this.freeWorkers.Writer.WriteAsync(worker))); - this.freeWorkers.Writer.TryWrite(worker); - } + worker.WorkerProcessingEnded.Subscribe(_ => Task.FromResult(this.freeWorkers.Writer.WriteAsync(worker))); + this.freeWorkers.Writer.TryWrite(worker); } + } - /// - public Task GetWorkerAsync(byte[] partitionKey, CancellationToken cancellationToken) - { - return this.freeWorkers.Reader.ReadAsync(cancellationToken).AsTask(); - } + /// + public ValueTask GetWorkerAsync(WorkerDistributionContext context) + { + return this.freeWorkers.Reader.ReadAsync(context.ConsumerStoppedCancellationToken); } -} +} \ No newline at end of file From e64e9fcf8b1cc42983ce8e119e802db0c5ae406b Mon Sep 17 00:00:00 2001 From: Joel Oliveira Date: Wed, 22 Nov 2023 16:59:40 +0000 Subject: [PATCH 15/20] docs: update documentation with changes from v3 --- .../create-your-first-application.md | 8 +-- website/docs/getting-started/installation.md | 2 +- website/docs/getting-started/packages.md | 55 +++++++++---------- .../docs/guides/consumers/add-consumers.md | 2 - .../middlewares/batch-consume-middleware.md | 14 ++--- .../middlewares/compressor-middleware.md | 6 +- .../consumer-throttling-middleware.md | 2 +- .../middlewares/serializer-middleware.md | 18 ++---- .../middlewares/typed-handler-middleware.md | 2 +- 9 files changed, 42 insertions(+), 67 deletions(-) diff --git a/website/docs/getting-started/create-your-first-application.md b/website/docs/getting-started/create-your-first-application.md index e8b1e295c..b1a0e671a 100644 --- a/website/docs/getting-started/create-your-first-application.md +++ b/website/docs/getting-started/create-your-first-application.md @@ -58,8 +58,6 @@ Inside the _Producer_ project directory, run the following commands to install t dotnet add package KafkaFlow dotnet add package KafkaFlow.Microsoft.DependencyInjection dotnet add package KafkaFlow.LogHandler.Console -dotnet add package KafkaFlow.TypedHandler -dotnet add package KafkaFlow.Serializer dotnet add package KafkaFlow.Serializer.JsonCore dotnet add package Microsoft.Extensions.DependencyInjection ``` @@ -153,8 +151,6 @@ Inside the _Consumer_ project directory, run the following commands to install t dotnet add package KafkaFlow dotnet add package KafkaFlow.Microsoft.DependencyInjection dotnet add package KafkaFlow.LogHandler.Console -dotnet add package KafkaFlow.TypedHandler -dotnet add package KafkaFlow.Serializer dotnet add package KafkaFlow.Serializer.JsonCore dotnet add package Microsoft.Extensions.DependencyInjection ``` @@ -165,7 +161,6 @@ Create a new class file named _HelloMessageHandler.cs_ and add the following exa ```csharp using KafkaFlow; -using KafkaFlow.TypedHandler; using Producer; namespace Consumer; @@ -193,7 +188,6 @@ Replace the content of the _Program.cs_ with the following example. using KafkaFlow; using KafkaFlow.Serializer; using Microsoft.Extensions.DependencyInjection; -using KafkaFlow.TypedHandler; using Consumer; const string topicName = "sample-topic"; @@ -210,7 +204,7 @@ services.AddKafka(kafka => kafka .WithBufferSize(100) .WithWorkersCount(10) .AddMiddlewares(middlewares => middlewares - .AddSerializer() + .AddDeserializer() .AddTypedHandlers(h => h.AddHandler()) ) ) diff --git a/website/docs/getting-started/installation.md b/website/docs/getting-started/installation.md index 000abed77..08b40a7f7 100644 --- a/website/docs/getting-started/installation.md +++ b/website/docs/getting-started/installation.md @@ -59,7 +59,7 @@ public void ConfigureServices(IServiceCollection services) .WithBufferSize(100) .WithWorkersCount(10) .AddMiddlewares(middlewares => middlewares - .AddSerializer() + .AddDeserializer() .AddTypedHandlers(handlers => handlers .AddHandler()) ) diff --git a/website/docs/getting-started/packages.md b/website/docs/getting-started/packages.md index 198e8595e..74ef92e4b 100644 --- a/website/docs/getting-started/packages.md +++ b/website/docs/getting-started/packages.md @@ -6,39 +6,34 @@ sidebar_position: 4 ## Core -| Package | NuGet Stable | Downloads | -| ------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [KafkaFlow](https://www.nuget.org/packages/KafkaFlow/) | [![KafkaFlow](https://img.shields.io/nuget/v/KafkaFlow.svg)](https://www.nuget.org/packages/KafkaFlow/) | [![KafkaFlow](https://img.shields.io/nuget/dt/KafkaFlow.svg)](https://www.nuget.org/packages/KafkaFlow/) | -| [KafkaFlow.Abstractions](https://www.nuget.org/packages/KafkaFlow.Abstractions/) | [![KafkaFlow.Abstractions](https://img.shields.io/nuget/v/KafkaFlow.Abstractions.svg)](https://www.nuget.org/packages/KafkaFlow.Abstractions/) | [![KafkaFlow](https://img.shields.io/nuget/dt/KafkaFlow.Abstractions.svg)](https://www.nuget.org/packages/KafkaFlow.Abstractions/) | -| [KafkaFlow.Extensions.Hosting](https://www.nuget.org/packages/KafkaFlow.Extensions.Hosting/) | [![KafkaFlow.Extensions.Hosting](https://img.shields.io/nuget/v/KafkaFlow.Extensions.Hosting.svg)](https://www.nuget.org/packages/KafkaFlow.Extensions.Hosting/) | [![KafkaFlow](https://img.shields.io/nuget/dt/KafkaFlow.Extensions.Hosting.svg)](https://www.nuget.org/packages/KafkaFlow.Extensions.Hosting/) | -| [KafkaFlow.LogHandler.Console](https://www.nuget.org/packages/KafkaFlow.LogHandler.Console/) | [![KafkaFlow.LogHandler.Console](https://img.shields.io/nuget/v/KafkaFlow.LogHandler.Console.svg)](https://www.nuget.org/packages/KafkaFlow.LogHandler.Console/) | [![KafkaFlow.LogHandler.Console](https://img.shields.io/nuget/dt/KafkaFlow.LogHandler.Console.svg)](https://www.nuget.org/packages/KafkaFlow.LogHandler.Console/) | +| Package | NuGet Stable | Downloads | +| -------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [KafkaFlow](https://www.nuget.org/packages/KafkaFlow/) | [![KafkaFlow](https://img.shields.io/nuget/v/KafkaFlow.svg)](https://www.nuget.org/packages/KafkaFlow/) | [![KafkaFlow](https://img.shields.io/nuget/dt/KafkaFlow.svg)](https://www.nuget.org/packages/KafkaFlow/) | +| [KafkaFlow.Abstractions](https://www.nuget.org/packages/KafkaFlow.Abstractions/) | [![KafkaFlow.Abstractions](https://img.shields.io/nuget/v/KafkaFlow.Abstractions.svg)](https://www.nuget.org/packages/KafkaFlow.Abstractions/) | [![KafkaFlow](https://img.shields.io/nuget/dt/KafkaFlow.Abstractions.svg)](https://www.nuget.org/packages/KafkaFlow.Abstractions/) | +| [KafkaFlow.Extensions.Hosting](https://www.nuget.org/packages/KafkaFlow.Extensions.Hosting/) | [![KafkaFlow.Extensions.Hosting](https://img.shields.io/nuget/v/KafkaFlow.Extensions.Hosting.svg)](https://www.nuget.org/packages/KafkaFlow.Extensions.Hosting/) | [![KafkaFlow](https://img.shields.io/nuget/dt/KafkaFlow.Extensions.Hosting.svg)](https://www.nuget.org/packages/KafkaFlow.Extensions.Hosting/) | +| [KafkaFlow.LogHandler.Console](https://www.nuget.org/packages/KafkaFlow.LogHandler.Console/) | [![KafkaFlow.LogHandler.Console](https://img.shields.io/nuget/v/KafkaFlow.LogHandler.Console.svg)](https://www.nuget.org/packages/KafkaFlow.LogHandler.Console/) | [![KafkaFlow.LogHandler.Console](https://img.shields.io/nuget/dt/KafkaFlow.LogHandler.Console.svg)](https://www.nuget.org/packages/KafkaFlow.LogHandler.Console/) | ## Serialization -| Package | NuGet Stable | Downloads | -| ---------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [KafkaFlow.Serializer](https://www.nuget.org/packages/KafkaFlow.Serializer/) | [![KafkaFlow.Serializer](https://img.shields.io/nuget/v/KafkaFlow.Serializer.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer/) | [![KafkaFlow.Serializer](https://img.shields.io/nuget/dt/KafkaFlow.Serializer.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer/) | -| [KafkaFlow.SchemaRegistry](https://www.nuget.org/packages/KafkaFlow.SchemaRegistry/) | [![KafkaFlow.SchemaRegistry](https://img.shields.io/nuget/v/KafkaFlow.SchemaRegistry.svg)](https://www.nuget.org/packages/KafkaFlow.SchemaRegistry/) | [![KafkaFlow.SchemaRegistry](https://img.shields.io/nuget/dt/KafkaFlow.SchemaRegistry.svg)](https://www.nuget.org/packages/KafkaFlow.SchemaRegistry/) | -| [KafkaFlow.Serializer.ProtobufNet](https://www.nuget.org/packages/KafkaFlow.Serializer.ProtobufNet/) | [![KafkaFlow.Serializer.ProtobufNet](https://img.shields.io/nuget/v/KafkaFlow.Serializer.ProtobufNet.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.ProtobufNet/) | [![KafkaFlow.Serializer.ProtobufNet](https://img.shields.io/nuget/dt/KafkaFlow.Serializer.ProtobufNet.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.ProtobufNet/) | -| [KafkaFlow.Serializer.JsonCore](https://www.nuget.org/packages/KafkaFlow.Serializer.JsonCore/) | [![KafkaFlow.Serializer.JsonCore](https://img.shields.io/nuget/v/KafkaFlow.Serializer.JsonCore.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.JsonCore/) | [![KafkaFlow.Serializer.JsonCore](https://img.shields.io/nuget/dt/KafkaFlow.Serializer.JsonCore.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.JsonCore/) | -| [KafkaFlow.Serializer.NewtonsoftJson](https://www.nuget.org/packages/KafkaFlow.Serializer.NewtonsoftJson/) | [![KafkaFlow.Serializer.NewtonsoftJson](https://img.shields.io/nuget/v/KafkaFlow.Serializer.NewtonsoftJson.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.NewtonsoftJson/) | [![KafkaFlow.Serializer.NewtonsoftJson](https://img.shields.io/nuget/dt/KafkaFlow.Serializer.NewtonsoftJson.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.NewtonsoftJson/) | -| [KafkaFlow.Serializer.SchemaRegistry.ConfluentJson](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/) | [![KafkaFlow.Serializer.SchemaRegistry.ConfluentJson](https://img.shields.io/nuget/v/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/) | [![KafkaFlow.Serializer.SchemaRegistry.ConfluentJson](https://img.shields.io/nuget/dt/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/) | -| [KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/) | [![KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro](https://img.shields.io/nuget/v/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/) | [![KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro](https://img.shields.io/nuget/dt/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/) | -| [KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/) | [![KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf](https://img.shields.io/nuget/v/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/) | [![KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf](https://img.shields.io/nuget/dt/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/) | +| Package | NuGet Stable | Downloads | +| ---------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [KafkaFlow.SchemaRegistry](https://www.nuget.org/packages/KafkaFlow.SchemaRegistry/) | [![KafkaFlow.SchemaRegistry](https://img.shields.io/nuget/v/KafkaFlow.SchemaRegistry.svg)](https://www.nuget.org/packages/KafkaFlow.SchemaRegistry/) | [![KafkaFlow.SchemaRegistry](https://img.shields.io/nuget/dt/KafkaFlow.SchemaRegistry.svg)](https://www.nuget.org/packages/KafkaFlow.SchemaRegistry/) | +| [KafkaFlow.Serializer.ProtobufNet](https://www.nuget.org/packages/KafkaFlow.Serializer.ProtobufNet/) | [![KafkaFlow.Serializer.ProtobufNet](https://img.shields.io/nuget/v/KafkaFlow.Serializer.ProtobufNet.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.ProtobufNet/) | [![KafkaFlow.Serializer.ProtobufNet](https://img.shields.io/nuget/dt/KafkaFlow.Serializer.ProtobufNet.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.ProtobufNet/) | +| [KafkaFlow.Serializer.JsonCore](https://www.nuget.org/packages/KafkaFlow.Serializer.JsonCore/) | [![KafkaFlow.Serializer.JsonCore](https://img.shields.io/nuget/v/KafkaFlow.Serializer.JsonCore.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.JsonCore/) | [![KafkaFlow.Serializer.JsonCore](https://img.shields.io/nuget/dt/KafkaFlow.Serializer.JsonCore.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.JsonCore/) | +| [KafkaFlow.Serializer.NewtonsoftJson](https://www.nuget.org/packages/KafkaFlow.Serializer.NewtonsoftJson/) | [![KafkaFlow.Serializer.NewtonsoftJson](https://img.shields.io/nuget/v/KafkaFlow.Serializer.NewtonsoftJson.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.NewtonsoftJson/) | [![KafkaFlow.Serializer.NewtonsoftJson](https://img.shields.io/nuget/dt/KafkaFlow.Serializer.NewtonsoftJson.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.NewtonsoftJson/) | +| [KafkaFlow.Serializer.SchemaRegistry.ConfluentJson](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/) | [![KafkaFlow.Serializer.SchemaRegistry.ConfluentJson](https://img.shields.io/nuget/v/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/) | [![KafkaFlow.Serializer.SchemaRegistry.ConfluentJson](https://img.shields.io/nuget/dt/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/) | +| [KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/) | [![KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro](https://img.shields.io/nuget/v/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/) | [![KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro](https://img.shields.io/nuget/dt/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/) | +| [KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/) | [![KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf](https://img.shields.io/nuget/v/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/) | [![KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf](https://img.shields.io/nuget/dt/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/) | ## Compression -| Package | NuGet Stable | Downloads | -| ------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [KafkaFlow.Compressor](https://www.nuget.org/packages/KafkaFlow.Compressor/) | [![KafkaFlow.Compressor](https://img.shields.io/nuget/v/KafkaFlow.Compressor.svg)](https://www.nuget.org/packages/KafkaFlow.Compressor/) | [![KafkaFlow.Compressor](https://img.shields.io/nuget/dt/KafkaFlow.Compressor.svg)](https://www.nuget.org/packages/KafkaFlow.Compressor/) | -| [KafkaFlow.Compressor.Gzip](https://www.nuget.org/packages/KafkaFlow.Compressor.Gzip/) | [![KafkaFlow.Compressor.Gzip](https://img.shields.io/nuget/v/KafkaFlow.Compressor.Gzip.svg)](https://www.nuget.org/packages/KafkaFlow.Compressor.Gzip/) | [![KafkaFlow.Compressor.Gzip](https://img.shields.io/nuget/dt/KafkaFlow.Compressor.Gzip.svg)](https://www.nuget.org/packages/KafkaFlow.Compressor.Gzip/) | +| Package | NuGet Stable | Downloads | +| -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [KafkaFlow.Compressor.Gzip](https://www.nuget.org/packages/KafkaFlow.Compressor.Gzip/) | [![KafkaFlow.Compressor.Gzip](https://img.shields.io/nuget/v/KafkaFlow.Compressor.Gzip.svg)](https://www.nuget.org/packages/KafkaFlow.Compressor.Gzip/) | [![KafkaFlow.Compressor.Gzip](https://img.shields.io/nuget/dt/KafkaFlow.Compressor.Gzip.svg)](https://www.nuget.org/packages/KafkaFlow.Compressor.Gzip/) | + + -## Middlewares -| Package | NuGet Stable | Downloads | -| ------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [KafkaFlow.TypedHandler](https://www.nuget.org/packages/KafkaFlow.TypedHandler/) | [![KafkaFlow.TypedHandler](https://img.shields.io/nuget/v/KafkaFlow.TypedHandler.svg)](https://www.nuget.org/packages/KafkaFlow.TypedHandler/) | [![KafkaFlow.TypedHandler](https://img.shields.io/nuget/dt/KafkaFlow.TypedHandler.svg)](https://www.nuget.org/packages/KafkaFlow.TypedHandler/) | -| [KafkaFlow.BatchConsume](https://www.nuget.org/packages/KafkaFlow.BatchConsume/) | [![KafkaFlow.BatchConsume](https://img.shields.io/nuget/v/KafkaFlow.BatchConsume.svg)](https://www.nuget.org/packages/KafkaFlow.BatchConsume/) | [![KafkaFlow.BatchConsume](https://img.shields.io/nuget/dt/KafkaFlow.BatchConsume.svg)](https://www.nuget.org/packages/KafkaFlow.BatchConsume/) | ## Dependency Injection @@ -49,8 +44,8 @@ sidebar_position: 4 ## Administration -| Package | NuGet Stable | Downloads | -| ------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [KafkaFlow.Admin](https://www.nuget.org/packages/KafkaFlow.Admin/) | [![KafkaFlow.Admin](https://img.shields.io/nuget/v/KafkaFlow.Admin.svg)](https://www.nuget.org/packages/KafkaFlow.Admin/) | [![KafkaFlow.Admin](https://img.shields.io/nuget/dt/KafkaFlow.Admin.svg)](https://www.nuget.org/packages/KafkaFlow.Admin/) | -| [KafkaFlow.Admin.WebApi](https://www.nuget.org/packages/KafkaFlow.Admin.WebApi/) | [![KafkaFlow.Admin.WebApi](https://img.shields.io/nuget/v/KafkaFlow.Admin.WebApi.svg)](https://www.nuget.org/packages/KafkaFlow.Admin.WebApi/) | [![KafkaFlow.Admin.WebApi](https://img.shields.io/nuget/dt/KafkaFlow.Admin.WebApi.svg)](https://www.nuget.org/packages/KafkaFlow.Admin.WebApi/) | -| [KafkaFlow.Admin.Dashboard](https://www.nuget.org/packages/KafkaFlow.Admin.Dashboard/) | [![KafkaFlow.Admin.Dashboard](https://img.shields.io/nuget/v/KafkaFlow.Admin.Dashboard.svg)](https://www.nuget.org/packages/KafkaFlow.Admin.Dashboard/) | [![KafkaFlow.Admin.Dashboard](https://img.shields.io/nuget/dt/KafkaFlow.Admin.Dashboard.svg)](https://www.nuget.org/packages/KafkaFlow.Admin.Dashboard/) | \ No newline at end of file +| Package | NuGet Stable | Downloads | +| -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [KafkaFlow.Admin](https://www.nuget.org/packages/KafkaFlow.Admin/) | [![KafkaFlow.Admin](https://img.shields.io/nuget/v/KafkaFlow.Admin.svg)](https://www.nuget.org/packages/KafkaFlow.Admin/) | [![KafkaFlow.Admin](https://img.shields.io/nuget/dt/KafkaFlow.Admin.svg)](https://www.nuget.org/packages/KafkaFlow.Admin/) | +| [KafkaFlow.Admin.WebApi](https://www.nuget.org/packages/KafkaFlow.Admin.WebApi/) | [![KafkaFlow.Admin.WebApi](https://img.shields.io/nuget/v/KafkaFlow.Admin.WebApi.svg)](https://www.nuget.org/packages/KafkaFlow.Admin.WebApi/) | [![KafkaFlow.Admin.WebApi](https://img.shields.io/nuget/dt/KafkaFlow.Admin.WebApi.svg)](https://www.nuget.org/packages/KafkaFlow.Admin.WebApi/) | +| [KafkaFlow.Admin.Dashboard](https://www.nuget.org/packages/KafkaFlow.Admin.Dashboard/) | [![KafkaFlow.Admin.Dashboard](https://img.shields.io/nuget/v/KafkaFlow.Admin.Dashboard.svg)](https://www.nuget.org/packages/KafkaFlow.Admin.Dashboard/) | [![KafkaFlow.Admin.Dashboard](https://img.shields.io/nuget/dt/KafkaFlow.Admin.Dashboard.svg)](https://www.nuget.org/packages/KafkaFlow.Admin.Dashboard/) | \ No newline at end of file diff --git a/website/docs/guides/consumers/add-consumers.md b/website/docs/guides/consumers/add-consumers.md index 50f1aadf1..89bf3b824 100644 --- a/website/docs/guides/consumers/add-consumers.md +++ b/website/docs/guides/consumers/add-consumers.md @@ -45,7 +45,6 @@ Using the `Topic()` or `Topics()` methods, the consumer will trigger the automat using KafkaFlow; using KafkaFlow.Serializer; using Microsoft.Extensions.DependencyInjection; -using KafkaFlow.TypedHandler; services.AddKafka(kafka => kafka .AddCluster(cluster => cluster @@ -68,7 +67,6 @@ The client application can specify the topic partitions manually using the `Manu using KafkaFlow; using KafkaFlow.Serializer; using Microsoft.Extensions.DependencyInjection; -using KafkaFlow.TypedHandler; services.AddKafka(kafka => kafka .AddCluster(cluster => cluster diff --git a/website/docs/guides/middlewares/batch-consume-middleware.md b/website/docs/guides/middlewares/batch-consume-middleware.md index 6fcbeb2d7..248294597 100644 --- a/website/docs/guides/middlewares/batch-consume-middleware.md +++ b/website/docs/guides/middlewares/batch-consume-middleware.md @@ -10,15 +10,9 @@ The Batch Consume Middleware is used to accumulate a number of messages or wait ## How to use it -Install the [KafkaFlow.BatchConsume](https://www.nuget.org/packages/KafkaFlow.BatchConsume) package. +On the configuration, use the `AddBatching` extension method to add the middleware to your consumer middlewares. -```bash -dotnet add package KafkaFlow.BatchConsume -``` - -On the configuration, use the `BatchConsume` extension method to add the middleware to your consumer middlewares. - -The `BatchConsume` method has two arguments: +The `AddBatching` method has two arguments: - The first one must define the maximum batch size. - The second one defines the `TimeSpan` that the Middleware waits for new messages to be part of the batch. @@ -33,7 +27,7 @@ services.AddKafka(kafka => kafka .AddMiddlewares( middlewares => middlewares ... - .BatchConsume(100, TimeSpan.FromSeconds(10)) // Configuration of the BatchConsumeMiddleware + .AddBatching(100, TimeSpan.FromSeconds(10)) // Configuration of the BatchConsumeMiddleware .Add() // Middleware to process the batch ) ) @@ -48,7 +42,7 @@ When using the `Batch Consume` middleware, the `IServiceScopeFactory` should be ::: ```csharp -using KafkaFlow.BatchConsume; +using KafkaFlow; internal class HandlingMiddleware : IMessageMiddleware { diff --git a/website/docs/guides/middlewares/compressor-middleware.md b/website/docs/guides/middlewares/compressor-middleware.md index 819b70127..8490e8617 100644 --- a/website/docs/guides/middlewares/compressor-middleware.md +++ b/website/docs/guides/middlewares/compressor-middleware.md @@ -14,13 +14,13 @@ If you want to build your own way of compress and decompress messages, you can f ## Add a Compressor Middleware -Install the [KafkaFlow.Compressor](https://www.nuget.org/packages/KafkaFlow.Compressor/) package and add the `AddCompressor` extension method to your producer/consumer middlewares to use it. +Add the `AddCompressor`/`AddDecompressor` extension method to your producer/consumer middlewares to use it. -The method receives a class that implements the `IMessageCompressor` interface as a generic argument. This class will be used in the compress/decompress process. +The method receives a class that implements the `ICompressor`/`IDecompressor` interface as a generic argument. This class will be used in the compress/decompress process. A class instance can be provided as an argument through a factory method too. -Install the [KafkaFlow.Compressor.Gzip](https://www.nuget.org/packages/KafkaFlow.Compressor.Gzip/) package to use the `GzipMessageCompressor` that uses the GZIP algorithm. +Install the [KafkaFlow.Compressor.Gzip](https://www.nuget.org/packages/KafkaFlow.Compressor.Gzip/) package to use the `GzipMessageCompressor`/`GzipMessageDecompressor` that uses the GZIP algorithm. ```csharp public class Startup diff --git a/website/docs/guides/middlewares/consumer-throttling-middleware.md b/website/docs/guides/middlewares/consumer-throttling-middleware.md index 2c4014b62..63a65892e 100644 --- a/website/docs/guides/middlewares/consumer-throttling-middleware.md +++ b/website/docs/guides/middlewares/consumer-throttling-middleware.md @@ -30,7 +30,7 @@ Configuring Consumer Throttling is straightforward with the fluent interface pro .AddAction(a => a.AboveThreshold(10).ApplyDelay(100)) .AddAction(a => a.AboveThreshold(100).ApplyDelay(1_000)) .AddAction(a => a.AboveThreshold(1_000).ApplyDelay(10_000))) - .AddSerializer() + .AddDeserializer() ) ) ``` diff --git a/website/docs/guides/middlewares/serializer-middleware.md b/website/docs/guides/middlewares/serializer-middleware.md index 674d92294..829b51311 100644 --- a/website/docs/guides/middlewares/serializer-middleware.md +++ b/website/docs/guides/middlewares/serializer-middleware.md @@ -15,21 +15,15 @@ You can use one of the following common serializers or build your own: ## How to use it -Install the [KafkaFlow.Serializer](https://www.nuget.org/packages/KafkaFlow.Serializer) package. +On the configuration, add the `AddSerializer`/`AddDeserializer` extension method to your producer/consumer middlewares to use it. -```bash -dotnet add package KafkaFlow.Serializer -``` - -On the configuration, add the `AddSerializer` extension method to your producer/consumer middlewares to use it. - -The `AddSerializer` method has two arguments: - - The first one must implement the `IMessageSerializer` interface. +The `AddSerializer`/`AddDeserializer` method has two arguments: + - The first one must implement the `ISerializer`/`IDeserializer` interface. - The second one is optional and must implement the `IMessageTypeResolver` interface. If the parameter is not provided, then the `DefaultTypeResolver` will be used. Both classes can be provided as an argument through a factory method too. :::tip -For topics that have just one message type, use the `AddSingleTypeSerializer` method. +For topics that have just one message type, use the `AddSingleTypeSerializer`/`AddSingleTypeDeserializer` method. :::tip @@ -87,7 +81,7 @@ public class Startup ) .AddConsumer( ... - .AddMiddlewares(middlewares => middlewares.AddSchemaRegistryAvroSerializer() + .AddMiddlewares(middlewares => middlewares.AddSchemaRegistryAvroDeserializer() ) ) ); @@ -108,7 +102,7 @@ You can see a detailed explanation [here](https://docs.confluent.io/platform/cur A type resolver is needed to instruct the middleware where to find the destination message type in the message metadata when consuming and where to store it when producing. -The framework has the `DefaultTypeResolver` that will be used omitting the second type parameter in the `AddSerializer` method. You can create your own implementation of `IMessageTypeResolver` to allow communication with other frameworks. +The framework has the `DefaultTypeResolver` that will be used omitting the second type parameter in the `AddSerializer`/`AddDeserializer` method. You can create your own implementation of `IMessageTypeResolver` to allow communication with other frameworks. ```csharp public class SampleMessageTypeResolver : IMessageTypeResolver diff --git a/website/docs/guides/middlewares/typed-handler-middleware.md b/website/docs/guides/middlewares/typed-handler-middleware.md index e0144299e..63b827d91 100644 --- a/website/docs/guides/middlewares/typed-handler-middleware.md +++ b/website/docs/guides/middlewares/typed-handler-middleware.md @@ -24,7 +24,7 @@ When using a Schema Registry, the schema is read from it, and the first 5 bytes #### Without Schema Registry Using other serializers with no Schema Registry, the `DefaultTypeResolver` is used by default. The `DefaultTypeResolver` uses the header `Message-Type` to identify the message type based on the Type fully qualified name. -It's also possible to write your own `TypeResolver` implementing the `IMessageTypeResolver` interface and using it in the `AddSerializer` method in the consumer/producer middleware. +It's also possible to write your own `TypeResolver` implementing the `IMessageTypeResolver` interface and using it in the `AddSerializer`/`AddDeserializer` method in the consumer/producer middleware. ## Configure Typed Handler From 4e46c350215be15faf8ba99fb64797290f032296 Mon Sep 17 00:00:00 2001 From: Joel Oliveira Date: Mon, 20 Nov 2023 10:23:34 +0000 Subject: [PATCH 16/20] docs: added migration guide from v2 to v3 --- website/docs/guides/migration/_category_.json | 7 + .../docs/guides/migration/from-v2-to-v3.md | 305 ++++++++++++++++++ 2 files changed, 312 insertions(+) create mode 100644 website/docs/guides/migration/_category_.json create mode 100644 website/docs/guides/migration/from-v2-to-v3.md diff --git a/website/docs/guides/migration/_category_.json b/website/docs/guides/migration/_category_.json new file mode 100644 index 000000000..a4ef91bb6 --- /dev/null +++ b/website/docs/guides/migration/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "Migration", + "position": 11, + "link": { + "type": "generated-index" + } + } \ No newline at end of file diff --git a/website/docs/guides/migration/from-v2-to-v3.md b/website/docs/guides/migration/from-v2-to-v3.md new file mode 100644 index 000000000..ae8322ae3 --- /dev/null +++ b/website/docs/guides/migration/from-v2-to-v3.md @@ -0,0 +1,305 @@ +--- +sidebar_position: 1 +--- + +# From v2 to v3 + +KafkaFlow version 3 brings several significant changes and improvements. This guide will help you navigate through the migration process from version 2 to version 3. + +## Table of Contents + +- [Prerequisites](#prerequisites) +- [Update package references](#update-package-references) +- [Breaking Changes](#breaking-changes) + - [1. Update to .NET 6 with Admin Packages](#1-update-to-net-6-with-admin-packages) + - [2. UI Dashboard URL Change](#2-ui-dashboard-url-change) + - [3. Removed Packages and Core Changes](#3-removed-packages-and-core-changes) + - [3.1 Removed Packages](#31-removed-packages) + - [3.2 Serializer and Compressor Interface Segregation](#32-serializer-and-compressor-interface-segregation) + - [3.3 Consumer Batching Configuration](#33-consumer-batching-configuration) + - [3.4. Async Support for Message Type Resolvers and Schema Registry Resolvers](#34-async-support-for-message-type-resolvers-and-schema-registry-resolvers) +- [New Features](#new-features) + - [1. Dynamic Workers Calculation](#1-dynamic-workers-calculation) + - [1.1 Dynamic Worker Pool Scaling Configuration](#11-dynamic-worker-pool-scaling-configuration) + - [1.2 Improved Mechanism for Signalling Message Processing Completion](#12-improved-mechanism-for-signalling-message-processing-completion) + - [1.3 Expose Worker Events to Client Applications](#13-expose-worker-events-to-client-applications) + - [1.4 Improve Dependency Injection Scope Management](#14-improve-dependency-injection-scope-management) + - [2. Improved Worker Distribution Strategy](#2-improved-worker-distribution-strategy) +- [Conclusion](#conclusion) + + +## Prerequisites + +As .NET Core 3.1 has reached the end of support in its lifecycle, we have updated references to Core Packages (`Microsoft.*` and `System.*`) to version 6. + +While the KafkaFlow core and most of the extension packages are still targeting `netstandard2.0` which supports a range of runtimes, we recommend with this v3 update to target at least .NET 6 in applications using KafkaFlow. + +## Update package references + +To update to KafkaFlow v3, change the `Version` related to KafkaFlow packages to the latest v3 available in each project referencing KafkaFlow packages. + +``` + +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- + ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + +``` + +## Breaking Changes + +The update to v3 introduces some breaking changes. Please consider them when updating KafkaFlow. + +### 1. Update to .NET 6 with Admin Packages + +> Related Issues: [#298](https://github.com/Farfetch/kafkaflow/issues/298) [#322](https://github.com/Farfetch/kafkaflow/issues/322) + +The target frameworks for ASP.NET Admin projects were updated from `netcoreapp3.1` to `.net6.0`. + +If you are using the Admin packages (`KafkaFlow.Admin.Dashboard` and `KafkaFlow.Admin.WebApi `) you will need to target the .NET 6 runtime. + +### 2. UI Dashboard URL Change + +> Related Issues: [#303](https://github.com/Farfetch/kafkaflow/issues/303) + +To be in conformity with KafkaFlow naming conventions, the UI Dashboard URL has changed from `/kafka-flow` to `/kafkaflow`. Update any bookmarks or references accordingly. + +### 3. Removed Packages and Core Changes + +#### 3.1 Removed Packages + +> Related Issues: [#301](https://github.com/Farfetch/kafkaflow/issues/301) + +Because some KafkaFlow extension packages contained elements that belong to the core of KafkaFlow, these packages were removed and moved to the core library. +Most of these packages contained only interfaces or core functionalities that were moved to the core library while the concrete implementations continue to exist as separate packages to keep KafkaFlow's modular design. + +Here is the list of KafkaFlow packages that no longer exist in v3. In case you are referencing any of these packages, please remove those references since their references were moved to the core KafkaFlow package: + +- KafkaFlow.TypedHandler +- KafkaFlow.Compressor +- KafkaFlow.Serializer +- KafkaFlow.BatchConsume + +#### 3.2 Serializer and Compressor Interface Segregation + +> Related Issues: [#432](https://github.com/Farfetch/kafkaflow/issues/432), [#433](https://github.com/Farfetch/kafkaflow/issues/433) + +Before KafkaFlow v3, references were used on the consumer side, for example, `AddSerializer()` or `.AddCompressor()`. While this convention was used for simplicity's sake to keep the same nomenclature as in the producer counterpart, the nomenclature can be error-prone since on the consumer side the behavior when using `AddSerializer()` is adding a middleware for deserializing the message. + +To fix this, on KafkaFlow v3, the `IDeserializer` and `IDecompressor` were created to segregate from the `ISerializer` and `ICompressor` interfaces. + +In case you are configuring the consumer to deserialize and/or decompress a message similar to this configuration: + +```csharp +.AddConsumer( + consumerBuilder => consumerBuilder + .Topic("test-topic") + .WithGroupId("group1") + .AddMiddlewares( + middlewares => middlewares + .AddCompressor() + .AddSerializer() + ) +) +``` + +The following changes need to be made when updating to KafkaFlow v3. + +```csharp +.AddConsumer( + consumerBuilder => consumerBuilder + .Topic("test-topic") + .WithGroupId("group1") + .AddMiddlewares( + middlewares => middlewares + .AddDecompressor() + .AddDeserializer() + ) +) +``` + +Not only the `.AddSerializer()` and `.AddCompressor()` were renamed to `.AddDeserializer()` and `.AddDecompressor()`, but also the concrete implementations like `JsonCoreSerializer` and `GzipMessageCompressor` were renamed to `JsonCoreDeserializer` and `GzipMessageDecompressor`. Please be aware that this change is only on the **consumer side**. + +Having this segregation contributes to a more consistent name scheme together with the middleware behavior. Nevertheless, other changes related to this topic were made, here is a complete list of changes related to the segregation of `ISerializer` and `ICompressor` interfaces (**consumer configuration** only): + +Related to Deserialization: + +- `IDeserializer` interface created. +- `.AddSerializer()` renamed to `.AddDeserializer()`. +- Created `JsonCoreDeserializer `, `ProtobufNetDeserializer`, `ConfluentProtobufDeserializer`, `NewtonsoftJsonDeserializer`, `ConfluentJsonDeserializer` and `ConfluentAvroDeserializer` that implements the `.DeserializeAsync()` method. +- `.AddSingleTypeDeserializer()` renamed to `.AddSingleTypeDeserializer()` +- `.AddSingleTypeSerializer()` renamed to `.AddSchemaRegistryAvroDeserializer()` + +Related to Decompression: + +- `IDecompressor` interface created. +- `.AddCompressor()` renamed to `.AddDecompressor()`. +- Created `GzipMessageDecompressor` that implements the `.Decompress()` method. + +#### 3.3 Consumer Batching Configuration + +Consumer batching configuration renamed from `.BatchConsume()` to `.AddBatching()`. Update your configuration accordingly. + +#### 3.4. Async Support for Message Type Resolvers and Schema Registry Resolvers + +> Related Issues: [#302](https://github.com/Farfetch/kafkaflow/issues/302), [#305](https://github.com/Farfetch/kafkaflow/issues/305) + +In both `IMessageTypeResolvers` and `ISchemaRegistryTypeNameResolver` the interface methods only supported sync calls before KafkaFlow v3. +To accommodate some use cases where calls to these methods can be parallelized, the methods defined in this interface were refactored to support the Async pattern. + +If your application has a concrete implementation of these interfaces, please make sure to update your code accordingly by using the async/await pattern. Here is the list of changes related to this subject: + +- `Resolve()` renamed to `ResolveAsync()` in `ISchemaRegistryTypeNameResolver` and now returns a `Task`. +- `OnConsume()` renamed to `OnConsumeAsync()` in `IMessageTypeResolver` and returns a `ValueTask`. +- `OnProduce()` renamed to `OnProduceAsync()` in `IMessageTypeResolver` and returns a `ValueTask`. + +## New Features + +Additionally, with the update to v3, some quality-of-life features were added to KafkaFlow core, mainly related to how workers are configured. + +### 1. Dynamic Workers Calculation + +One important feature added to KafkaFlow v3 was the ability to calculate how many workers are handling the message consumption dynamically. Please check the feature documentation [here](https://farfetch.github.io/kafkaflow/docs/guides/consumers/dynamic-workers-configuration). + +In load scenarios where the consumer needs to ramp up message consumption to reduce the consumer lag, increasing the number of workers can be a valid strategy in this scenario. + +Before, the number of workers was determined statically by configuration at the time of application startup. With KafkaFlow v3, a new method was introduced that supports calculating the number of available workers periodically. This allows the application to adapt constantly and also being able to scale the number of workers during the application's lifetime. + +To accommodate this requirement multiple changes were made to the core of KafkaFlow, next we will go through some of these changes. + +### 1.1 Dynamic Worker Pool Scaling Configuration + +> Related Issues: [#429](https://github.com/Farfetch/kafkaflow/issues/429) + +Two new overrides were added to the consumer configuration. Nevertheless, the previous method of statically determining the worker count is still available. + +The new overrides added were: + +- `WithWorkersCount(Func> calculator)` +- `WithWorkersCount(Func> calculator, TimeSpan evaluationInterval)` + +The difference between both overrides is that the first works with a predefined frequency of 5 minutes between calls to the delegate that returns the number of workers. While in the second override that frequency can be user-defined. + +Additionally, the delegate receives a `WorkersCountContext` that sends some consumer-related context to the callback like the Consumer Name, the Consumer Group Key and the Consumer Partitions Assignment. Also, the `IDependencyResolver` is made available in case some dependencies need to be resolved to determine the worker count. + +This means that a consumer worker count can be configured like this: + +```csharp +.AddConsumer( + consumerBuilder => consumerBuilder + .Topic("test-topic") + .WithGroupId("group1") + .WithWorkersCount((context, resolver) => { + // Use whatever logic to determine the worker count + return GetWorkerCount(context, resolver); + }, TimeSpan.FromMinutes(15)) +) +``` + +### 1.2 Improved Mechanism for Signalling Message Processing Completion + +> Related Issues: [#426](https://github.com/Farfetch/kafkaflow/issues/426) + +For the KafkaFlow engine to adapt to the dynamic change of workers, the way the messages are signaled as completed also needed to be updated because the workers can only be scaled after all the messages in the worker's buffers are signaled as completed. + +To achieve this, a new method in the message context was provided to signal the message completion `.Complete()`. Additionally, a new property called `AutoMessageCompletion` was added to signal if KafkaFlow should signal the message as completed automatically which is the default behavior. This property is useful for scenarios where we don't want to complete the message right away, for example in Batch Consume scenarios. + +### 1.3 Expose Worker Events to Client Applications + +> Related Issues: [#427](https://github.com/Farfetch/kafkaflow/issues/427) + +KafkaFlow now exposes some events related to its internal functionality. The events that are being published are the following: + +- MessageProduceStarted +- MessageProduceCompleted +- MessageProduceError +- MessageConsumeStarted +- MessageConsumeCompleted +- MessageConsumeError +- WorkerStopping +- WorkerStopped +- WorkerProcessingEnded + +While worker-related events are available through the `IWorker` reference, the message-related events can be subscribed using the `.SubscribeGlobalEvents()` configuration method. + +```csharp +services.AddKafka( + kafka => kafka + .UseConsoleLog() + .SubscribeGlobalEvents(hub => + { + hub.MessageConsumeStarted.Subscribe(eventContext => Console.WriteLine("Message Consume Started")); + + hub.MessageConsumeError.Subscribe(eventContext => Console.WriteLine("Message Consume Error")); + + hub.MessageConsumeCompleted.Subscribe(eventContext => Console.WriteLine("Message Consume Completed")); + + hub.MessageProduceStarted.Subscribe(eventContext => Console.WriteLine("Message Produce Started")); + + hub.MessageProduceError.Subscribe(eventContext => Console.WriteLine("Message Produce Error")); + + hub.MessageProduceCompleted.Subscribe(eventContext => Console.WriteLine("Message Produce Completed")); + }) +); +``` + +### 1.4 Improve Dependency Injection Scope Management + +> Related Issues: [#428](https://github.com/Farfetch/kafkaflow/issues/428) + +Some improvements were made to the way the dependency scopes are managed to provide more fine-grained control over dependency lifecycles. Here are some changes that were made in this context: + +- `IMessageContext` now exposes a property `DependencyResolver` which is intrinsically tied to the scope of a single processed message. +- `IConsumerContext` introduces two properties: `ConsumerDependencyResolver` and `WorkerDependencyResolver`. The former will resolve dependencies tied to the lifecycle of a single consumer, whereas the latter caters to a single worker's lifecycle. + +## 2. Improved Worker Distribution Strategy + +> Related Issues: [#440](https://github.com/Farfetch/kafkaflow/issues/440) + +KafkaFlow v2 already provided a method to define the worker to handle a message when consuming using the `IDistributionStrategy` interface. However, the only context provided by this method was the partition key of the message, which sometimes can be insufficient to determine how to distribute messages across workers in more complex scenarios. + +With KafkaFlow v3 this interface got renamed to `IWorkerDistributionStrategy` and now the method `.GetWorkerAsync()` receives a `WorkerDistributionContext` structure. Properties like message topic and partition are now part of the context which provides more flexibility when choosing the worker to handle a message. + +## Conclusion + +Please ensure you review and adapt your codebase according to these changes. If you encounter any issues or need assistance, feel free to [reach out](https://github.com/Farfetch/kafkaflow#get-in-touch) to the KafkaFlow community. Thank you for using KafkaFlow! From f3366d01a610df0c581708659064ffff48c87fc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Pereira=20Rodrigues?= Date: Tue, 21 Nov 2023 16:17:57 +0000 Subject: [PATCH 17/20] refactor: adopt common .NET conventions This refactor aims the following - Have all usings outside namespace - Replace private variables this to use _ - Move tests folder to root - Move sln file to root --- .editorconfig | 95 +++++++ .github/workflows/build.yml | 6 +- .github/workflows/deploy-website.yml | 2 +- .github/workflows/publish.yml | 2 +- .github/workflows/test-deploy-website.yml | 2 +- KafkaFlow.sln | 265 ++++++++++++++++++ Makefile | 10 +- .../PrintConsoleMiddleware.cs | 3 +- samples/KafkaFlow.Sample.Dashboard/Startup.cs | 2 +- .../MessageHandler.cs | 2 - .../PauseConsumerOnExceptionMiddleware.cs | 14 +- .../Handlers/AvroMessageHandler.cs | 11 +- .../Handlers/AvroMessageHandler2.cs | 7 +- .../Handlers/JsonMessageHandler.cs | 7 +- .../Handlers/ProtobufMessageHandler.cs | 4 +- .../Avro/SchemaRegistry/AvroLogMessage.cs | 10 +- .../Avro/SchemaRegistry/AvroLogMessage2.cs | 8 +- .../MessageTypes/Json/JsonLogMessage.cs | 24 +- .../Program.cs | 12 +- samples/KafkaFlow.Sample.WebApi/Program.cs | 1 - .../KafkaFlow.Sample/PrintConsoleHandler.cs | 1 - samples/KafkaFlow.Sample/TestMessage.cs | 2 +- .../IClusterConfigurationBuilder.cs | 6 +- .../IConsumerConfigurationBuilder.cs | 10 +- .../IKafkaConfigurationBuilder.cs | 4 +- .../IProducerConfigurationBuilder.cs | 4 +- .../Configuration/TopicPartitions.cs | 4 +- .../Configuration/WorkersCountContext.cs | 4 +- src/KafkaFlow.Abstractions/Delegates.cs | 4 +- .../DependencyConfiguratorExtensions.cs | 4 +- .../DependencyResolverExtensions.cs | 2 +- .../Extensions/DictionaryExtensions.cs | 6 +- .../Extensions/MessageHeaderExtensions.cs | 4 +- .../IConsumerContext.cs | 8 +- .../IDateTimeProvider.cs | 4 +- .../IDependencyConfigurator.cs | 4 +- .../IDependencyResolver.cs | 6 +- .../IDependencyResolverScope.cs | 4 +- src/KafkaFlow.Abstractions/IDeserializer.cs | 8 +- src/KafkaFlow.Abstractions/IEvent.cs | 10 +- src/KafkaFlow.Abstractions/ILogHandler.cs | 4 +- src/KafkaFlow.Abstractions/IMessageContext.cs | 4 +- src/KafkaFlow.Abstractions/IMessageHandler.cs | 4 +- src/KafkaFlow.Abstractions/IMessageHeaders.cs | 4 +- .../IMessageMiddleware.cs | 4 +- src/KafkaFlow.Abstractions/ISerializer.cs | 6 +- .../IWorkerDistributionStrategy.cs | 4 +- .../MessageErrorEventContext.cs | 6 +- src/KafkaFlow.Abstractions/NullLogHandler.cs | 4 +- .../WorkerDistributionContext.cs | 4 +- .../ApplicationBuilderExtensions.cs | 20 +- .../DashboardConfiguration.cs | 8 +- .../DashboardConfigurationBuilder.cs | 20 +- .../IDashboardConfigurationBuilder.cs | 6 +- .../KafkaFlow.Admin.Dashboard.csproj | 2 +- .../TelemetryResponse.cs | 10 +- .../TelemetryResponseAdapter.cs | 8 +- .../Adapters/ConsumerResponseAdapter.cs | 6 +- .../Adapters/TelemetryResponseAdapter.cs | 10 +- .../Contracts/ConsumerResponse.cs | 106 +++---- .../Contracts/ConsumersResponse.cs | 4 +- .../Contracts/GroupResponse.cs | 8 +- .../Contracts/GroupsResponse.cs | 4 +- .../Contracts/RewindOffsetsToDateRequest.cs | 4 +- .../Contracts/TelemetryResponse.cs | 10 +- .../Controllers/ConsumersController.cs | 60 ++-- .../Controllers/GroupsController.cs | 30 +- .../Controllers/TelemetryController.cs | 16 +- src/KafkaFlow.Admin/AdminProducer.cs | 18 +- src/KafkaFlow.Admin/ConsumerAdmin.cs | 36 +-- .../ClusterConfigurationBuilderExtensions.cs | 16 +- .../Extensions/MessageConsumerExtensions.cs | 10 +- .../ChangeConsumerWorkersCountHandler.cs | 15 +- .../ConsumerTelemetryMetricHandler.cs | 13 +- .../Handlers/PauseConsumerByNameHandler.cs | 19 +- .../Handlers/PauseConsumersByGroupHandler.cs | 19 +- .../Handlers/ResetConsumerOffsetHandler.cs | 23 +- .../Handlers/RestartConsumerByNameHandler.cs | 15 +- .../Handlers/ResumeConsumerByNameHandler.cs | 19 +- .../Handlers/ResumeConsumersByGroupHandler.cs | 19 +- .../RewindConsumerOffsetToDateTimeHandler.cs | 23 +- .../Handlers/StartConsumerByNameHandler.cs | 15 +- .../Handlers/StopConsumerByNameHandler.cs | 15 +- src/KafkaFlow.Admin/IAdminProducer.cs | 6 +- src/KafkaFlow.Admin/IConsumerAdmin.cs | 8 +- src/KafkaFlow.Admin/ITelemetryStorage.cs | 6 +- src/KafkaFlow.Admin/MemoryTelemetryStorage.cs | 50 ++-- .../Messages/ChangeConsumerWorkersCount.cs | 4 +- .../Messages/ConsumerTelemetryMetric.cs | 10 +- .../Messages/PauseConsumerByName.cs | 6 +- .../Messages/PauseConsumersByGroup.cs | 6 +- .../Messages/ResetConsumerOffset.cs | 6 +- .../Messages/RestartConsumerByName.cs | 4 +- .../Messages/ResumeConsumerByName.cs | 6 +- .../Messages/ResumeConsumersByGroup.cs | 6 +- .../RewindConsumerOffsetToDateTime.cs | 8 +- .../Messages/StartConsumerByName.cs | 4 +- .../Messages/StopConsumerByName.cs | 4 +- src/KafkaFlow.Admin/TelemetryScheduler.cs | 46 +-- .../GzipMessageCompressor.cs | 8 +- .../GzipMessageDecompressor.cs | 8 +- .../KafkaFlowHostedService.cs | 18 +- .../ServiceCollectionExtensions.cs | 10 +- .../CompressionTest.cs | 44 --- .../ProducerTest.cs | 40 --- .../ConsoleLogHandler.cs | 8 +- .../ExtensionMethods.cs | 4 +- .../ExtensionMethods.cs | 4 +- .../MicrosoftLogHandler.cs | 22 +- .../MicrosoftDependencyConfigurator.cs | 22 +- .../MicrosoftDependencyResolver.cs | 20 +- .../MicrosoftDependencyResolverScope.cs | 10 +- .../ServiceCollectionExtensions.cs | 8 +- .../ServiceProviderExtensions.cs | 8 +- .../ActivitySourceAccessor.cs | 12 +- .../ExtensionMethods.cs | 6 +- .../OpenTelemetryConsumerEventsHandler.cs | 28 +- .../OpenTelemetryProducerEventsHandler.cs | 28 +- .../ClusterConfigurationBuilderExtensions.cs | 8 +- .../ConfluentDeserializerWrapper.cs | 32 +-- .../ConfluentSerializerWrapper.cs | 26 +- .../ISchemaRegistryTypeNameResolver.cs | 4 +- .../SchemaRegistryTypeResolver.cs | 38 +-- .../JsonCoreDeserializer.cs | 18 +- .../JsonCoreSerializer.cs | 26 +- .../NewtonsoftJsonDeserializer.cs | 25 +- .../NewtonsoftJsonSerializer.cs | 23 +- .../ProtobufNetDeserializer.cs | 13 +- .../ProtobufNetSerializer.cs | 11 +- .../ConfluentAvroDeserializer.cs | 20 +- .../ConfluentAvroSerializer.cs | 26 +- .../ConfluentAvroTypeNameResolver.cs | 14 +- .../ConsumerConfigurationBuilderExtensions.cs | 12 +- .../ProducerConfigurationBuilderExtensions.cs | 14 +- .../ConfluentJsonDeserializer.cs | 20 +- .../ConfluentJsonSerializer.cs | 34 +-- .../ConsumerConfigurationBuilderExtensions.cs | 10 +- .../ProducerConfigurationBuilderExtensions.cs | 12 +- .../ConfluentProtobufDeserializer.cs | 14 +- .../ConfluentProtobufSerializer.cs | 26 +- .../ConfluentProtobufTypeNameResolver.cs | 18 +- .../ConsumerConfigurationBuilderExtensions.cs | 12 +- .../ProducerConfigurationBuilderExtensions.cs | 14 +- .../Consumer/ConsumerManagerTests.cs | 167 ----------- .../SchemaRegistryTypeResolverTests.cs | 47 ---- src/KafkaFlow.UnitTests/OffsetManagerTests.cs | 88 ------ .../UnityDependencyConfigurator.cs | 37 ++- .../UnityDependencyResolver.cs | 20 +- .../UnityDependencyResolverScope.cs | 10 +- src/KafkaFlow.sln | 259 ----------------- .../Batching/BatchConsumeMessageContext.cs | 14 +- .../Batching/BatchConsumeMiddleware.cs | 92 +++--- src/KafkaFlow/Batching/BatchingExtensions.cs | 12 +- src/KafkaFlow/Clusters/ClusterManager.cs | 54 ++-- .../Clusters/ClusterManagerAccessor.cs | 14 +- src/KafkaFlow/Clusters/IClusterManager.cs | 8 +- .../Clusters/IClusterManagerAccessor.cs | 4 +- .../Configuration/ClusterConfiguration.cs | 44 +-- .../ClusterConfigurationBuilder.cs | 58 ++-- .../Configuration/ConsumerConfiguration.cs | 31 +- .../ConsumerConfigurationBuilder.cs | 183 ++++++------ .../Configuration/IConsumerConfiguration.cs | 17 +- .../IMiddlewareInstanceContainer.cs | 4 +- .../Configuration/IProducerConfiguration.cs | 9 +- .../Configuration/KafkaConfiguration.cs | 10 +- .../KafkaConfigurationBuilder.cs | 44 +-- .../Configuration/KafkaFlowConfigurator.cs | 16 +- .../Configuration/MiddlewareConfiguration.cs | 4 +- .../MiddlewareConfigurationBuilder.cs | 18 +- .../MiddlewareInstanceContainer.cs | 26 +- .../PendingOffsetsStatisticsHandler.cs | 11 +- .../Configuration/ProducerConfiguration.cs | 9 +- .../ProducerConfigurationBuilder.cs | 75 +++-- src/KafkaFlow/ConsumerManagerFactory.cs | 6 +- src/KafkaFlow/Consumers/Consumer.cs | 153 +++++----- src/KafkaFlow/Consumers/ConsumerAccessor.cs | 12 +- src/KafkaFlow/Consumers/ConsumerContext.cs | 55 ++-- .../Consumers/ConsumerFlowManager.cs | 82 +++--- src/KafkaFlow/Consumers/ConsumerManager.cs | 55 ++-- src/KafkaFlow/Consumers/ConsumerWorker.cs | 112 ++++---- src/KafkaFlow/Consumers/ConsumerWorkerPool.cs | 120 ++++---- .../BytesSumDistributionStrategy.cs | 14 +- .../FreeWorkerDistributionStrategy.cs | 14 +- src/KafkaFlow/Consumers/IConsumer.cs | 57 ++-- src/KafkaFlow/Consumers/IConsumerAccessor.cs | 4 +- .../Consumers/IConsumerFlowManager.cs | 6 +- src/KafkaFlow/Consumers/IConsumerManager.cs | 4 +- src/KafkaFlow/Consumers/IConsumerWorker.cs | 8 +- .../Consumers/IConsumerWorkerPool.cs | 10 +- src/KafkaFlow/Consumers/IMessageConsumer.cs | 31 +- src/KafkaFlow/Consumers/IOffsetCommitter.cs | 8 +- src/KafkaFlow/Consumers/IOffsetManager.cs | 4 +- src/KafkaFlow/Consumers/IWorkerPoolFeeder.cs | 4 +- src/KafkaFlow/Consumers/MessageConsumer.cs | 115 ++++---- .../Consumers/NullOffsetCommitter.cs | 9 +- src/KafkaFlow/Consumers/NullOffsetManager.cs | 4 +- src/KafkaFlow/Consumers/OffsetCommitter.cs | 72 ++--- src/KafkaFlow/Consumers/OffsetManager.cs | 26 +- src/KafkaFlow/Consumers/OffsetsWatermark.cs | 18 +- src/KafkaFlow/Consumers/PartitionOffsets.cs | 35 +-- src/KafkaFlow/Consumers/WorkerPoolFeeder.cs | 44 +-- .../ConsumerLagWorkerBalancer.cs | 54 ++-- src/KafkaFlow/DateTimeProvider.cs | 4 +- src/KafkaFlow/Delegates.cs | 6 +- src/KafkaFlow/Event.cs | 36 +-- src/KafkaFlow/EventSubscription.cs | 12 +- .../ConfigurationBuilderExtensions.cs | 24 +- .../Extensions/ConfigurationExtensions.cs | 14 +- src/KafkaFlow/GlobalEvents.cs | 57 ++-- src/KafkaFlow/IConsumerManagerFactory.cs | 6 +- src/KafkaFlow/IKafkaBus.cs | 10 +- src/KafkaFlow/IMiddlewareExecutor.cs | 6 +- src/KafkaFlow/KafkaBus.cs | 54 ++-- src/KafkaFlow/MessageContext.cs | 4 +- src/KafkaFlow/MessageHeaders.cs | 24 +- src/KafkaFlow/MiddlewareExecutor.cs | 30 +- .../CompressorProducerMiddleware.cs | 14 +- .../DecompressorConsumerMiddleware.cs | 14 +- ...merThrottlingActionConfigurationBuilder.cs | 4 +- .../ConsumerThrottlingConfiguration.cs | 6 +- .../ConsumerThrottlingConfigurationBuilder.cs | 26 +- ...hrottlingConfigurationBuilderExtensions.cs | 14 +- ...erThrottlingActionsConfigurationBuilder.cs | 4 +- ...merThrottlingMetricConfigurationBuilder.cs | 4 +- ...lingThresholdActionConfigurationBuilder.cs | 4 +- .../ConsumerThrottlingDelayAction.cs | 12 +- .../ConsumerThrottlingKafkaLagMetric.cs | 16 +- .../ConsumerThrottlingMiddleware.cs | 38 +-- .../ConsumerThrottlingThreshold.cs | 10 +- .../IConsumerThrottlingAction.cs | 4 +- .../IConsumerThrottlingMetric.cs | 4 +- .../IConsumerThrottlingThreshold.cs | 4 +- .../ConsumerMiddlewareConfigurationBuilder.cs | 12 +- .../ProducerMiddlewareConfigurationBuilder.cs | 12 +- .../DeserializerConsumerMiddleware.cs | 24 +- .../Resolvers/DefaultTypeResolver.cs | 8 +- .../Resolvers/IMessageTypeResolver.cs | 8 +- .../Resolvers/SingleMessageTypeResolver.cs | 12 +- .../SerializerProducerMiddleware.cs | 26 +- .../TypedHandlerConfiguration.cs | 4 +- .../TypedHandlerConfigurationBuilder.cs | 42 +-- .../TypedHandler/HandlerExecutor.cs | 18 +- .../TypedHandler/HandlerTypeMapping.cs | 20 +- .../TypedHandler/TypedHandlerMiddleware.cs | 22 +- .../Producers/BatchProduceException.cs | 6 +- .../Producers/BatchProduceExtension.cs | 8 +- src/KafkaFlow/Producers/BatchProduceItem.cs | 4 +- src/KafkaFlow/Producers/IMessageProducer.cs | 8 +- src/KafkaFlow/Producers/IProducerAccessor.cs | 4 +- src/KafkaFlow/Producers/MessageProducer.cs | 98 +++---- .../Producers/MessageProducerWrapper.cs | 22 +- src/KafkaFlow/Producers/ProducerAccessor.cs | 16 +- src/KafkaFlow/TopicMetadata.cs | 4 +- src/KafkaFlow/TopicPartitionMetadata.cs | 4 +- src/StyleCopAnalyzersDefault.ruleset | 18 +- src/stylecop.json | 4 + .../CompressionSerializationTest.cs | 36 +-- .../CompressionTest.cs | 44 +++ .../ConsumerTest.cs | 56 ++-- .../Core/Bootstrapper.cs | 39 ++- .../ErrorExecutingMiddlewareException.cs | 6 +- .../PartitionAssignmentException.cs | 6 +- .../Core/Handlers/AvroMessageHandler.cs | 7 +- .../Handlers/ConfluentJsonMessageHandler.cs | 7 +- .../ConfluentProtobufMessageHandler.cs | 7 +- .../Core/Handlers/MessageHandler.cs | 7 +- .../Core/Handlers/MessageHandler1.cs | 7 +- .../Core/Handlers/MessageHandler2.cs | 9 +- .../Core/Handlers/MessageStorage.cs | 58 ++-- .../Core/Handlers/PauseResumeHandler.cs | 7 +- .../Core/Messages/ITestMessage.cs | 6 +- .../Core/Messages/LogMessages2.cs | 6 +- .../Core/Messages/PauseResumeMessage.cs | 8 +- .../Core/Messages/TestMessage1.cs | 8 +- .../Core/Messages/TestMessage2.cs | 8 +- .../Core/Messages/TestMessage3.cs | 6 +- .../Core/Messages/TestProtoMessage.cs | 0 .../Core/Messages/logmessages2.avsc | 0 .../Core/Middlewares/GzipMiddleware.cs | 12 +- .../Core/Producers/AvroProducer.cs | 0 .../Core/Producers/ConfluentJsonProducer.cs | 0 .../Producers/ConfluentProtobufProducer.cs | 0 .../Core/Producers/GzipProducer.cs | 0 .../Core/Producers/JsonGzipProducer.cs | 0 .../Core/Producers/JsonProducer.cs | 0 .../Core/Producers/JsonProducer2.cs | 0 .../Core/Producers/ProtobufGzipProducer.cs | 0 .../Core/Producers/ProtobufGzipProducer2.cs | 0 .../Core/Producers/ProtobufProducer.cs | 0 .../Core/TraceLogHandler.cs | 8 +- .../GlobalEventsTest.cs | 74 ++--- .../KafkaFlow.IntegrationTests.csproj | 20 +- .../OpenTelemetryTests.cs | 87 +++--- .../ProducerTest.cs | 40 +++ .../SerializationTest.cs | 50 ++-- .../conf/appsettings.json | 0 .../Controllers/ConsumersControllerTests.cs | 154 +++++----- .../Controllers/GroupsControllerTests.cs | 54 ++-- .../Controllers/TelemetryControllerTests.cs | 42 +-- .../BatchConsumeMiddlewareTests.cs | 85 +++--- .../CompressorConsumerMiddlewareTests.cs | 58 ++-- .../CompressorProducerMiddlewareTests.cs | 52 ++-- .../ConsumerConfigurationBuilderTests.cs | 62 ++-- .../KafkaConfigurationBuilderTests.cs | 10 +- .../ProducerConfigurationBuilderTests.cs | 62 ++-- .../Consumer/ConsumerManagerTests.cs | 166 +++++++++++ .../Consumer/WorkerPoolFeederTests.cs | 94 +++---- .../DummyObjects/DummyProtobufObject.cs | 0 .../DummyObjects/DummyProtobufObject.proto | 0 .../KafkaFlow.UnitTests/EventTests.cs | 66 ++--- .../KafkaFlow.UnitTests/ExtensionHelpers.cs | 6 +- .../KafkaFlow.UnitTests.csproj | 18 +- .../LogHandlers/MicrosoftLogHandlerTests.cs | 10 +- .../MemoryTelemetryStorageTests.cs | 66 ++--- .../MessageHeadersTests.cs | 18 +- .../ConfluentAvroTypeNameResolverTests.cs | 28 +- .../ConfluentProtobufTypeNameResolverTests.cs | 31 +- .../SchemaRegistryTypeResolverTests.cs | 47 ++++ .../OffsetCommitterTests.cs | 77 +++-- .../KafkaFlow.UnitTests/OffsetManagerTests.cs | 87 ++++++ .../PartitionOffsetsTests.cs | 16 +- .../Serializers/JsonCoreSerializerTests.cs | 26 +- .../NewtonsoftJsonDeserializerTests.cs | 32 +-- .../NewtonsoftJsonSerializerTests.cs | 28 +- .../SerializerConsumerMiddlewareTests.cs | 102 +++---- .../SerializerProducerMiddlewareTests.cs | 66 ++--- .../TypedHandler/HandlerTypeMappingTests.cs | 20 +- 327 files changed, 3925 insertions(+), 3872 deletions(-) create mode 100644 .editorconfig create mode 100644 KafkaFlow.sln delete mode 100644 src/KafkaFlow.IntegrationTests/CompressionTest.cs delete mode 100644 src/KafkaFlow.IntegrationTests/ProducerTest.cs delete mode 100644 src/KafkaFlow.UnitTests/Consumer/ConsumerManagerTests.cs delete mode 100644 src/KafkaFlow.UnitTests/Middlewares/Serialization/SchemaRegistryTypeResolverTests.cs delete mode 100644 src/KafkaFlow.UnitTests/OffsetManagerTests.cs delete mode 100644 src/KafkaFlow.sln rename {src => tests}/KafkaFlow.IntegrationTests/CompressionSerializationTest.cs (52%) create mode 100644 tests/KafkaFlow.IntegrationTests/CompressionTest.cs rename {src => tests}/KafkaFlow.IntegrationTests/ConsumerTest.cs (70%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Bootstrapper.cs (95%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Exceptions/ErrorExecutingMiddlewareException.cs (76%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Exceptions/PartitionAssignmentException.cs (78%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Handlers/AvroMessageHandler.cs (75%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Handlers/ConfluentJsonMessageHandler.cs (70%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Handlers/ConfluentProtobufMessageHandler.cs (71%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler.cs (70%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler1.cs (70%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler2.cs (70%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Handlers/MessageStorage.cs (64%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Handlers/PauseResumeHandler.cs (77%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Messages/ITestMessage.cs (68%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Messages/LogMessages2.cs (94%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Messages/PauseResumeMessage.cs (73%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Messages/TestMessage1.cs (72%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Messages/TestMessage2.cs (72%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Messages/TestMessage3.cs (72%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Messages/TestProtoMessage.cs (100%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Messages/logmessages2.avsc (100%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Middlewares/GzipMiddleware.cs (76%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Producers/AvroProducer.cs (100%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Producers/ConfluentJsonProducer.cs (100%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Producers/ConfluentProtobufProducer.cs (100%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Producers/GzipProducer.cs (100%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Producers/JsonGzipProducer.cs (100%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Producers/JsonProducer.cs (100%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Producers/JsonProducer2.cs (100%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Producers/ProtobufGzipProducer.cs (100%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Producers/ProtobufGzipProducer2.cs (100%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/Producers/ProtobufProducer.cs (100%) rename {src => tests}/KafkaFlow.IntegrationTests/Core/TraceLogHandler.cs (94%) rename {src => tests}/KafkaFlow.IntegrationTests/GlobalEventsTest.cs (87%) rename {src => tests}/KafkaFlow.IntegrationTests/KafkaFlow.IntegrationTests.csproj (57%) rename {src => tests}/KafkaFlow.IntegrationTests/OpenTelemetryTests.cs (80%) create mode 100644 tests/KafkaFlow.IntegrationTests/ProducerTest.cs rename {src => tests}/KafkaFlow.IntegrationTests/SerializationTest.cs (59%) rename {src => tests}/KafkaFlow.IntegrationTests/conf/appsettings.json (100%) rename {src => tests}/KafkaFlow.UnitTests/Admin.WebApi/Controllers/ConsumersControllerTests.cs (67%) rename {src => tests}/KafkaFlow.UnitTests/Admin.WebApi/Controllers/GroupsControllerTests.cs (51%) rename {src => tests}/KafkaFlow.UnitTests/Admin.WebApi/Controllers/TelemetryControllerTests.cs (83%) rename {src => tests}/KafkaFlow.UnitTests/BatchConsume/BatchConsumeMiddlewareTests.cs (64%) rename {src => tests}/KafkaFlow.UnitTests/Compressors/CompressorConsumerMiddlewareTests.cs (54%) rename {src => tests}/KafkaFlow.UnitTests/Compressors/CompressorProducerMiddlewareTests.cs (62%) rename {src => tests}/KafkaFlow.UnitTests/ConfigurationBuilders/ConsumerConfigurationBuilderTests.cs (72%) rename {src => tests}/KafkaFlow.UnitTests/ConfigurationBuilders/KafkaConfigurationBuilderTests.cs (75%) rename {src => tests}/KafkaFlow.UnitTests/ConfigurationBuilders/ProducerConfigurationBuilderTests.cs (66%) create mode 100644 tests/KafkaFlow.UnitTests/Consumer/ConsumerManagerTests.cs rename {src => tests}/KafkaFlow.UnitTests/Consumer/WorkerPoolFeederTests.cs (67%) rename {src => tests}/KafkaFlow.UnitTests/DummyObjects/DummyProtobufObject.cs (100%) rename {src => tests}/KafkaFlow.UnitTests/DummyObjects/DummyProtobufObject.proto (100%) rename {src => tests}/KafkaFlow.UnitTests/EventTests.cs (73%) rename {src => tests}/KafkaFlow.UnitTests/ExtensionHelpers.cs (88%) rename {src => tests}/KafkaFlow.UnitTests/KafkaFlow.UnitTests.csproj (55%) rename {src => tests}/KafkaFlow.UnitTests/LogHandlers/MicrosoftLogHandlerTests.cs (79%) rename {src => tests}/KafkaFlow.UnitTests/MemoryTelemetryStorageTests.cs (71%) rename {src => tests}/KafkaFlow.UnitTests/MessageHeadersTests.cs (74%) rename {src => tests}/KafkaFlow.UnitTests/Middlewares/Serialization/ConfluentAvroTypeNameResolverTests.cs (52%) rename {src => tests}/KafkaFlow.UnitTests/Middlewares/Serialization/ConfluentProtobufTypeNameResolverTests.cs (50%) create mode 100644 tests/KafkaFlow.UnitTests/Middlewares/Serialization/SchemaRegistryTypeResolverTests.cs rename {src => tests}/KafkaFlow.UnitTests/OffsetCommitterTests.cs (53%) create mode 100644 tests/KafkaFlow.UnitTests/OffsetManagerTests.cs rename {src => tests}/KafkaFlow.UnitTests/PartitionOffsetsTests.cs (95%) rename {src => tests}/KafkaFlow.UnitTests/Serializers/JsonCoreSerializerTests.cs (69%) rename {src => tests}/KafkaFlow.UnitTests/Serializers/NewtonsoftJsonDeserializerTests.cs (54%) rename {src => tests}/KafkaFlow.UnitTests/Serializers/NewtonsoftJsonSerializerTests.cs (56%) rename {src => tests}/KafkaFlow.UnitTests/Serializers/SerializerConsumerMiddlewareTests.cs (55%) rename {src => tests}/KafkaFlow.UnitTests/Serializers/SerializerProducerMiddlewareTests.cs (53%) rename {src => tests}/KafkaFlow.UnitTests/TypedHandler/HandlerTypeMappingTests.cs (52%) diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..2e3356a89 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,95 @@ +# editorconfig.org + +[*.cs] +# Naming rules for fields +dotnet_naming_rule.private_fields_with_underscore.symbols = private_field +dotnet_naming_rule.private_fields_with_underscore.style = prefix_underscore +dotnet_naming_rule.private_fields_with_underscore.severity = warning + +dotnet_naming_symbols.private_field.applicable_kinds = field +dotnet_naming_symbols.private_field.applicable_accessibilities = private +dotnet_naming_symbols.private_field.required_modifiers = + +dotnet_naming_style.prefix_underscore.capitalization = camel_case +dotnet_naming_style.prefix_underscore.required_prefix = _ + +# Naming rules for properties +dotnet_naming_rule.private_properties_with_underscore.symbols = private_property +dotnet_naming_rule.private_properties_with_underscore.style = prefix_underscore +dotnet_naming_rule.private_properties_with_underscore.severity = warning + +dotnet_naming_symbols.private_property.applicable_kinds = property +dotnet_naming_symbols.private_property.applicable_accessibilities = private +dotnet_naming_symbols.private_property.required_modifiers = + +dotnet_naming_style.prefix_underscore.capitalization = camel_case +dotnet_naming_style.prefix_underscore.required_prefix = _ + +# Do not use 'this.' for private fields +dotnet_diagnostic.DOTNET_Naming_Style_DoNotUseThisForPrivateFields.severity = warning +dotnet_diagnostic.DOTNET_Naming_Style_DoNotUseThisForPrivateFields.symbols = field_like + +dotnet_naming_rule.style_dotnet_naming_rule_DotNetNamingStyle.DoNotUseThisForPrivateFields.symbols = field_like +dotnet_naming_rule.style_dotnet_naming_rule_DotNetNamingStyle.DoNotUseThisForPrivateFields.style = this_prefix +dotnet_naming_rule.style_dotnet_naming_rule_DotNetNamingStyle.DoNotUseThisForPrivateFields.severity = warning + +# name all constant fields using PascalCase +dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = warning +dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style + +dotnet_naming_symbols.constant_fields.applicable_kinds = field +dotnet_naming_symbols.constant_fields.required_modifiers = const + +dotnet_naming_style.pascal_case_style.capitalization = pascal_case + +# static fields should have s_ prefix +dotnet_naming_rule.static_fields_should_have_prefix.severity = warning +dotnet_naming_rule.static_fields_should_have_prefix.symbols = static_fields +dotnet_naming_rule.static_fields_should_have_prefix.style = static_prefix_style + +dotnet_naming_symbols.static_fields.applicable_kinds = field +dotnet_naming_symbols.static_fields.required_modifiers = static + +dotnet_naming_symbols.static_fields.applicable_accessibilities = private, internal, private_protected +dotnet_naming_style.static_prefix_style.required_prefix = s_ + +dotnet_naming_style.static_prefix_style.capitalization = camel_case + +csharp_indent_labels = one_less_than_current +csharp_using_directive_placement = outside_namespace:silent +csharp_prefer_simple_using_statement = true:suggestion +csharp_prefer_braces = true:silent +csharp_style_namespace_declarations = block_scoped:silent +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_top_level_statements = true:silent +csharp_style_prefer_primary_constructors = true:suggestion +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_local_functions = false:silent + +[*.{cs,vb}] +dotnet_style_operator_placement_when_wrapping = beginning_of_line +tab_width = 4 +indent_size = 4 +end_of_line = crlf +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_object_initializer = true:suggestion +dotnet_style_prefer_collection_expression = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_prefer_simplified_boolean_expressions = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:silent +dotnet_style_prefer_conditional_expression_over_return = true:silent +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_compound_assignment = true:suggestion +dotnet_style_prefer_simplified_interpolation = true:suggestion \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index da12de419..e4ccca1dd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -47,14 +47,14 @@ jobs: npm run build:prod - name: Build Framework - run: dotnet build ./src/KafkaFlow.sln -c Release + run: dotnet build KafkaFlow.sln -c Release - name: UnitTest run: | - dotnet test src/KafkaFlow.UnitTests/KafkaFlow.UnitTests.csproj -c Release --logger "console;verbosity=detailed" + dotnet test tests/KafkaFlow.UnitTests/KafkaFlow.UnitTests.csproj -c Release --logger "console;verbosity=detailed" - name: IntegrationTest run: | make init_broker - dotnet test src/KafkaFlow.IntegrationTests/KafkaFlow.IntegrationTests.csproj -c Release --logger "console;verbosity=detailed" + dotnet test tests/KafkaFlow.IntegrationTests/KafkaFlow.IntegrationTests.csproj -c Release --logger "console;verbosity=detailed" make shutdown_broker diff --git a/.github/workflows/deploy-website.yml b/.github/workflows/deploy-website.yml index c05e1d333..a08f864bd 100644 --- a/.github/workflows/deploy-website.yml +++ b/.github/workflows/deploy-website.yml @@ -25,7 +25,7 @@ jobs: shell: bash - name: .NET Publish - run: dotnet publish src/KafkaFlow.sln -c Release -o ./drop + run: dotnet publish KafkaFlow.sln -c Release -o ./drop - run: dotnet tool list --global shell: bash diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 4aeb7dd27..c45e828a2 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -29,7 +29,7 @@ jobs: npm run build:prod - name: Pack - run: dotnet pack ./src/KafkaFlow.sln -c Release /p:Version=${{ github.event.release.tag_name }} -o ./drop + run: dotnet pack ./KafkaFlow.sln -c Release /p:Version=${{ github.event.release.tag_name }} -o ./drop - name: Publish run: dotnet nuget push ./drop/**/*.nupkg -k ${{ secrets.NUGET_PUBLISH_KEY }} -s https://api.nuget.org/v3/index.json --skip-duplicate diff --git a/.github/workflows/test-deploy-website.yml b/.github/workflows/test-deploy-website.yml index 7d925c2c3..419cf8daa 100644 --- a/.github/workflows/test-deploy-website.yml +++ b/.github/workflows/test-deploy-website.yml @@ -19,7 +19,7 @@ jobs: shell: bash - name: .NET Publish - run: dotnet publish src/KafkaFlow.sln -c Release -o ./drop + run: dotnet publish KafkaFlow.sln -c Release -o ./drop - run: dotnet tool list --global shell: bash diff --git a/KafkaFlow.sln b/KafkaFlow.sln new file mode 100644 index 000000000..f376d8ef2 --- /dev/null +++ b/KafkaFlow.sln @@ -0,0 +1,265 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.7.34031.279 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Framework", "Framework", "{068CB250-2804-4C7E-9490-17F432B9CE21}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{7A9B997B-DAAC-4004-94F3-32F6B88E0068}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{303AE78F-6C96-4DF4-AC89-5C4FD53AFF0B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Serialization", "Serialization", "{ADAAA63C-E17C-4F1B-A062-3CCA071D75C2}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Compression", "Compression", "{0A782A83-B66D-4B99-9BE2-2B18AAD2E03C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DependencyResolvers", "DependencyResolvers", "{292BCEDD-55B4-49BB-B8B2-24CD834FF2AA}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "LogHandlers", "LogHandlers", "{EF626895-FDAE-4B28-9110-BA85671CBBF2}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Admin", "Admin", "{58483813-0D7C-423E-8E7D-8FBF3E6CDB6D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Middlewares", "Middlewares", "{ED24B548-6F37-4283-A35B-F6015BFB7A34}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Deploy", "Deploy", "{4A6A390C-A63A-4371-86BB-28481AD6D4C0}" + ProjectSection(SolutionItems) = preProject + .github\workflows\build.yml = .github\workflows\build.yml + .github\workflows\publish.yml = .github\workflows\publish.yml + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Telemetry", "Telemetry", "{96F5D441-B8DE-4ABC-BEF2-F758D1B2BA39}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Admin", "src\KafkaFlow.Admin\KafkaFlow.Admin.csproj", "{A30B89BE-418D-47CC-88C0-600AC8B0A5B4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Admin.Dashboard", "src\KafkaFlow.Admin.Dashboard\KafkaFlow.Admin.Dashboard.csproj", "{0829B33A-5942-4DA7-BBD4-77EF2DF1C39C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Admin.WebApi", "src\KafkaFlow.Admin.WebApi\KafkaFlow.Admin.WebApi.csproj", "{09D8AD16-45E4-4443-BCF6-7981FF69A3A3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Microsoft.DependencyInjection", "src\KafkaFlow.Microsoft.DependencyInjection\KafkaFlow.Microsoft.DependencyInjection.csproj", "{9BF4C82B-3E20-450C-BDFF-549575DB231A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Unity", "src\KafkaFlow.Unity\KafkaFlow.Unity.csproj", "{0F461CEC-CC0D-4557-A4E7-98262CA976AE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow", "src\KafkaFlow\KafkaFlow.csproj", "{1FF13D3E-803F-402E-BBBE-3688ABCBE58C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Abstractions", "src\KafkaFlow.Abstractions\KafkaFlow.Abstractions.csproj", "{966B54E9-1ADB-40C3-9D17-8987182834A7}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Extensions.Hosting", "src\KafkaFlow.Extensions.Hosting\KafkaFlow.Extensions.Hosting.csproj", "{2D5469E0-CACB-49AB-A3C2-2758C5A3303A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.LogHandler.Console", "src\KafkaFlow.LogHandler.Console\KafkaFlow.LogHandler.Console.csproj", "{D05610E6-865A-487E-8FE3-8F64A38098CD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.LogHandler.Microsoft", "src\KafkaFlow.LogHandler.Microsoft\KafkaFlow.LogHandler.Microsoft.csproj", "{6E1A8664-805C-4513-9D2A-3648A2C0FC0E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Compressor.Gzip", "src\KafkaFlow.Compressor.Gzip\KafkaFlow.Compressor.Gzip.csproj", "{21A3E0A6-94DD-44BA-8707-14D18AA0B037}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.SchemaRegistry", "src\KafkaFlow.SchemaRegistry\KafkaFlow.SchemaRegistry.csproj", "{B2955BD4-8A74-4C00-8559-2357D2C3A48F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Serializer.JsonCore", "src\KafkaFlow.Serializer.JsonCore\KafkaFlow.Serializer.JsonCore.csproj", "{3AA3BB1D-B1BB-4B30-AF5C-FE554ECC4025}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Serializer.NewtonsoftJson", "src\KafkaFlow.Serializer.NewtonsoftJson\KafkaFlow.Serializer.NewtonsoftJson.csproj", "{CEFFB532-0F13-4BEC-B119-B61CC0C024C3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Serializer.ProtobufNet", "src\KafkaFlow.Serializer.ProtobufNet\KafkaFlow.Serializer.ProtobufNet.csproj", "{794CDAEA-4EBE-4B39-B42F-D40B2C6C10EF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro", "src\KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro\KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro.csproj", "{28246082-79FB-468E-91D8-D400C7CBCADB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Serializer.SchemaRegistry.ConfluentJson", "src\KafkaFlow.Serializer.SchemaRegistry.ConfluentJson\KafkaFlow.Serializer.SchemaRegistry.ConfluentJson.csproj", "{1027A158-B83B-4BB0-A8B3-D387252F5982}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf", "src\KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf\KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf.csproj", "{B1791758-EB49-41F0-BEAB-AC83160E2BEE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Sample", "samples\KafkaFlow.Sample\KafkaFlow.Sample.csproj", "{237C8A3F-F2AF-420C-873E-D3DF504DC7A2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Sample.BatchOperations", "samples\KafkaFlow.Sample.BatchOperations\KafkaFlow.Sample.BatchOperations.csproj", "{D2A5BB81-28E8-4C72-9E11-379DFCE5C311}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Sample.ConsumerThrottling", "samples\KafkaFlow.Sample.ConsumerThrottling\KafkaFlow.Sample.ConsumerThrottling.csproj", "{FD1DD2C6-A7B5-4BF3-8BD3-DCE9BF1EE2B0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Sample.Dashboard", "samples\KafkaFlow.Sample.Dashboard\KafkaFlow.Sample.Dashboard.csproj", "{CD3788D9-EAF3-428E-A237-FE24A7D76CC0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Sample.FlowControl", "samples\KafkaFlow.Sample.FlowControl\KafkaFlow.Sample.FlowControl.csproj", "{BC33650E-E774-48B5-B35D-01B1E04BBC05}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Sample.PauseConsumerOnError", "samples\KafkaFlow.Sample.PauseConsumerOnError\KafkaFlow.Sample.PauseConsumerOnError.csproj", "{7FCF5FC3-F59C-4A89-A511-EF98201181F3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Sample.SchemaRegistry", "samples\KafkaFlow.Sample.SchemaRegistry\KafkaFlow.Sample.SchemaRegistry.csproj", "{FD052A19-B9B3-4A74-A9C0-6EA0C26A8D1B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Sample.WebApi", "samples\KafkaFlow.Sample.WebApi\KafkaFlow.Sample.WebApi.csproj", "{5E722C8E-2C81-42DF-B70E-7AC0AEBD1593}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.OpenTelemetry", "src\KafkaFlow.OpenTelemetry\KafkaFlow.OpenTelemetry.csproj", "{0C98213A-A553-40DC-BEA9-137BDE4A7398}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.UnitTests", "tests\KafkaFlow.UnitTests\KafkaFlow.UnitTests.csproj", "{1755E8DB-970C-4A24-8B7C-A2BEC1410BEE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.IntegrationTests", "tests\KafkaFlow.IntegrationTests\KafkaFlow.IntegrationTests.csproj", "{80080C1D-579E-4AB2-935D-5CFFC51843D8}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A97E7FE2-FFFD-4E23-B004-86BDB9AFAFF0}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B4704AE9-D85C-472E-93E7-1CB0839364F4}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A30B89BE-418D-47CC-88C0-600AC8B0A5B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A30B89BE-418D-47CC-88C0-600AC8B0A5B4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A30B89BE-418D-47CC-88C0-600AC8B0A5B4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A30B89BE-418D-47CC-88C0-600AC8B0A5B4}.Release|Any CPU.Build.0 = Release|Any CPU + {0829B33A-5942-4DA7-BBD4-77EF2DF1C39C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0829B33A-5942-4DA7-BBD4-77EF2DF1C39C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0829B33A-5942-4DA7-BBD4-77EF2DF1C39C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0829B33A-5942-4DA7-BBD4-77EF2DF1C39C}.Release|Any CPU.Build.0 = Release|Any CPU + {09D8AD16-45E4-4443-BCF6-7981FF69A3A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {09D8AD16-45E4-4443-BCF6-7981FF69A3A3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {09D8AD16-45E4-4443-BCF6-7981FF69A3A3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {09D8AD16-45E4-4443-BCF6-7981FF69A3A3}.Release|Any CPU.Build.0 = Release|Any CPU + {9BF4C82B-3E20-450C-BDFF-549575DB231A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9BF4C82B-3E20-450C-BDFF-549575DB231A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9BF4C82B-3E20-450C-BDFF-549575DB231A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9BF4C82B-3E20-450C-BDFF-549575DB231A}.Release|Any CPU.Build.0 = Release|Any CPU + {0F461CEC-CC0D-4557-A4E7-98262CA976AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0F461CEC-CC0D-4557-A4E7-98262CA976AE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0F461CEC-CC0D-4557-A4E7-98262CA976AE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0F461CEC-CC0D-4557-A4E7-98262CA976AE}.Release|Any CPU.Build.0 = Release|Any CPU + {1FF13D3E-803F-402E-BBBE-3688ABCBE58C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1FF13D3E-803F-402E-BBBE-3688ABCBE58C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1FF13D3E-803F-402E-BBBE-3688ABCBE58C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1FF13D3E-803F-402E-BBBE-3688ABCBE58C}.Release|Any CPU.Build.0 = Release|Any CPU + {966B54E9-1ADB-40C3-9D17-8987182834A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {966B54E9-1ADB-40C3-9D17-8987182834A7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {966B54E9-1ADB-40C3-9D17-8987182834A7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {966B54E9-1ADB-40C3-9D17-8987182834A7}.Release|Any CPU.Build.0 = Release|Any CPU + {2D5469E0-CACB-49AB-A3C2-2758C5A3303A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2D5469E0-CACB-49AB-A3C2-2758C5A3303A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2D5469E0-CACB-49AB-A3C2-2758C5A3303A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2D5469E0-CACB-49AB-A3C2-2758C5A3303A}.Release|Any CPU.Build.0 = Release|Any CPU + {D05610E6-865A-487E-8FE3-8F64A38098CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D05610E6-865A-487E-8FE3-8F64A38098CD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D05610E6-865A-487E-8FE3-8F64A38098CD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D05610E6-865A-487E-8FE3-8F64A38098CD}.Release|Any CPU.Build.0 = Release|Any CPU + {6E1A8664-805C-4513-9D2A-3648A2C0FC0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6E1A8664-805C-4513-9D2A-3648A2C0FC0E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6E1A8664-805C-4513-9D2A-3648A2C0FC0E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6E1A8664-805C-4513-9D2A-3648A2C0FC0E}.Release|Any CPU.Build.0 = Release|Any CPU + {21A3E0A6-94DD-44BA-8707-14D18AA0B037}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {21A3E0A6-94DD-44BA-8707-14D18AA0B037}.Debug|Any CPU.Build.0 = Debug|Any CPU + {21A3E0A6-94DD-44BA-8707-14D18AA0B037}.Release|Any CPU.ActiveCfg = Release|Any CPU + {21A3E0A6-94DD-44BA-8707-14D18AA0B037}.Release|Any CPU.Build.0 = Release|Any CPU + {B2955BD4-8A74-4C00-8559-2357D2C3A48F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B2955BD4-8A74-4C00-8559-2357D2C3A48F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B2955BD4-8A74-4C00-8559-2357D2C3A48F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B2955BD4-8A74-4C00-8559-2357D2C3A48F}.Release|Any CPU.Build.0 = Release|Any CPU + {3AA3BB1D-B1BB-4B30-AF5C-FE554ECC4025}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3AA3BB1D-B1BB-4B30-AF5C-FE554ECC4025}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3AA3BB1D-B1BB-4B30-AF5C-FE554ECC4025}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3AA3BB1D-B1BB-4B30-AF5C-FE554ECC4025}.Release|Any CPU.Build.0 = Release|Any CPU + {CEFFB532-0F13-4BEC-B119-B61CC0C024C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CEFFB532-0F13-4BEC-B119-B61CC0C024C3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CEFFB532-0F13-4BEC-B119-B61CC0C024C3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CEFFB532-0F13-4BEC-B119-B61CC0C024C3}.Release|Any CPU.Build.0 = Release|Any CPU + {794CDAEA-4EBE-4B39-B42F-D40B2C6C10EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {794CDAEA-4EBE-4B39-B42F-D40B2C6C10EF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {794CDAEA-4EBE-4B39-B42F-D40B2C6C10EF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {794CDAEA-4EBE-4B39-B42F-D40B2C6C10EF}.Release|Any CPU.Build.0 = Release|Any CPU + {28246082-79FB-468E-91D8-D400C7CBCADB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {28246082-79FB-468E-91D8-D400C7CBCADB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {28246082-79FB-468E-91D8-D400C7CBCADB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {28246082-79FB-468E-91D8-D400C7CBCADB}.Release|Any CPU.Build.0 = Release|Any CPU + {1027A158-B83B-4BB0-A8B3-D387252F5982}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1027A158-B83B-4BB0-A8B3-D387252F5982}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1027A158-B83B-4BB0-A8B3-D387252F5982}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1027A158-B83B-4BB0-A8B3-D387252F5982}.Release|Any CPU.Build.0 = Release|Any CPU + {B1791758-EB49-41F0-BEAB-AC83160E2BEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B1791758-EB49-41F0-BEAB-AC83160E2BEE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B1791758-EB49-41F0-BEAB-AC83160E2BEE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B1791758-EB49-41F0-BEAB-AC83160E2BEE}.Release|Any CPU.Build.0 = Release|Any CPU + {237C8A3F-F2AF-420C-873E-D3DF504DC7A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {237C8A3F-F2AF-420C-873E-D3DF504DC7A2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {237C8A3F-F2AF-420C-873E-D3DF504DC7A2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {237C8A3F-F2AF-420C-873E-D3DF504DC7A2}.Release|Any CPU.Build.0 = Release|Any CPU + {D2A5BB81-28E8-4C72-9E11-379DFCE5C311}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D2A5BB81-28E8-4C72-9E11-379DFCE5C311}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D2A5BB81-28E8-4C72-9E11-379DFCE5C311}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D2A5BB81-28E8-4C72-9E11-379DFCE5C311}.Release|Any CPU.Build.0 = Release|Any CPU + {FD1DD2C6-A7B5-4BF3-8BD3-DCE9BF1EE2B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FD1DD2C6-A7B5-4BF3-8BD3-DCE9BF1EE2B0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FD1DD2C6-A7B5-4BF3-8BD3-DCE9BF1EE2B0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FD1DD2C6-A7B5-4BF3-8BD3-DCE9BF1EE2B0}.Release|Any CPU.Build.0 = Release|Any CPU + {CD3788D9-EAF3-428E-A237-FE24A7D76CC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CD3788D9-EAF3-428E-A237-FE24A7D76CC0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CD3788D9-EAF3-428E-A237-FE24A7D76CC0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CD3788D9-EAF3-428E-A237-FE24A7D76CC0}.Release|Any CPU.Build.0 = Release|Any CPU + {BC33650E-E774-48B5-B35D-01B1E04BBC05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BC33650E-E774-48B5-B35D-01B1E04BBC05}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BC33650E-E774-48B5-B35D-01B1E04BBC05}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BC33650E-E774-48B5-B35D-01B1E04BBC05}.Release|Any CPU.Build.0 = Release|Any CPU + {7FCF5FC3-F59C-4A89-A511-EF98201181F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7FCF5FC3-F59C-4A89-A511-EF98201181F3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7FCF5FC3-F59C-4A89-A511-EF98201181F3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7FCF5FC3-F59C-4A89-A511-EF98201181F3}.Release|Any CPU.Build.0 = Release|Any CPU + {FD052A19-B9B3-4A74-A9C0-6EA0C26A8D1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FD052A19-B9B3-4A74-A9C0-6EA0C26A8D1B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FD052A19-B9B3-4A74-A9C0-6EA0C26A8D1B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FD052A19-B9B3-4A74-A9C0-6EA0C26A8D1B}.Release|Any CPU.Build.0 = Release|Any CPU + {5E722C8E-2C81-42DF-B70E-7AC0AEBD1593}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5E722C8E-2C81-42DF-B70E-7AC0AEBD1593}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5E722C8E-2C81-42DF-B70E-7AC0AEBD1593}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5E722C8E-2C81-42DF-B70E-7AC0AEBD1593}.Release|Any CPU.Build.0 = Release|Any CPU + {0C98213A-A553-40DC-BEA9-137BDE4A7398}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0C98213A-A553-40DC-BEA9-137BDE4A7398}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0C98213A-A553-40DC-BEA9-137BDE4A7398}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0C98213A-A553-40DC-BEA9-137BDE4A7398}.Release|Any CPU.Build.0 = Release|Any CPU + {1755E8DB-970C-4A24-8B7C-A2BEC1410BEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1755E8DB-970C-4A24-8B7C-A2BEC1410BEE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1755E8DB-970C-4A24-8B7C-A2BEC1410BEE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1755E8DB-970C-4A24-8B7C-A2BEC1410BEE}.Release|Any CPU.Build.0 = Release|Any CPU + {80080C1D-579E-4AB2-935D-5CFFC51843D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {80080C1D-579E-4AB2-935D-5CFFC51843D8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {80080C1D-579E-4AB2-935D-5CFFC51843D8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {80080C1D-579E-4AB2-935D-5CFFC51843D8}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {068CB250-2804-4C7E-9490-17F432B9CE21} = {A97E7FE2-FFFD-4E23-B004-86BDB9AFAFF0} + {ADAAA63C-E17C-4F1B-A062-3CCA071D75C2} = {ED24B548-6F37-4283-A35B-F6015BFB7A34} + {0A782A83-B66D-4B99-9BE2-2B18AAD2E03C} = {ED24B548-6F37-4283-A35B-F6015BFB7A34} + {292BCEDD-55B4-49BB-B8B2-24CD834FF2AA} = {A97E7FE2-FFFD-4E23-B004-86BDB9AFAFF0} + {EF626895-FDAE-4B28-9110-BA85671CBBF2} = {A97E7FE2-FFFD-4E23-B004-86BDB9AFAFF0} + {58483813-0D7C-423E-8E7D-8FBF3E6CDB6D} = {A97E7FE2-FFFD-4E23-B004-86BDB9AFAFF0} + {ED24B548-6F37-4283-A35B-F6015BFB7A34} = {A97E7FE2-FFFD-4E23-B004-86BDB9AFAFF0} + {96F5D441-B8DE-4ABC-BEF2-F758D1B2BA39} = {A97E7FE2-FFFD-4E23-B004-86BDB9AFAFF0} + {A30B89BE-418D-47CC-88C0-600AC8B0A5B4} = {58483813-0D7C-423E-8E7D-8FBF3E6CDB6D} + {0829B33A-5942-4DA7-BBD4-77EF2DF1C39C} = {58483813-0D7C-423E-8E7D-8FBF3E6CDB6D} + {09D8AD16-45E4-4443-BCF6-7981FF69A3A3} = {58483813-0D7C-423E-8E7D-8FBF3E6CDB6D} + {9BF4C82B-3E20-450C-BDFF-549575DB231A} = {292BCEDD-55B4-49BB-B8B2-24CD834FF2AA} + {0F461CEC-CC0D-4557-A4E7-98262CA976AE} = {292BCEDD-55B4-49BB-B8B2-24CD834FF2AA} + {1FF13D3E-803F-402E-BBBE-3688ABCBE58C} = {068CB250-2804-4C7E-9490-17F432B9CE21} + {966B54E9-1ADB-40C3-9D17-8987182834A7} = {068CB250-2804-4C7E-9490-17F432B9CE21} + {2D5469E0-CACB-49AB-A3C2-2758C5A3303A} = {068CB250-2804-4C7E-9490-17F432B9CE21} + {D05610E6-865A-487E-8FE3-8F64A38098CD} = {EF626895-FDAE-4B28-9110-BA85671CBBF2} + {6E1A8664-805C-4513-9D2A-3648A2C0FC0E} = {EF626895-FDAE-4B28-9110-BA85671CBBF2} + {21A3E0A6-94DD-44BA-8707-14D18AA0B037} = {0A782A83-B66D-4B99-9BE2-2B18AAD2E03C} + {B2955BD4-8A74-4C00-8559-2357D2C3A48F} = {ADAAA63C-E17C-4F1B-A062-3CCA071D75C2} + {3AA3BB1D-B1BB-4B30-AF5C-FE554ECC4025} = {ADAAA63C-E17C-4F1B-A062-3CCA071D75C2} + {CEFFB532-0F13-4BEC-B119-B61CC0C024C3} = {ADAAA63C-E17C-4F1B-A062-3CCA071D75C2} + {794CDAEA-4EBE-4B39-B42F-D40B2C6C10EF} = {ADAAA63C-E17C-4F1B-A062-3CCA071D75C2} + {28246082-79FB-468E-91D8-D400C7CBCADB} = {ADAAA63C-E17C-4F1B-A062-3CCA071D75C2} + {1027A158-B83B-4BB0-A8B3-D387252F5982} = {ADAAA63C-E17C-4F1B-A062-3CCA071D75C2} + {B1791758-EB49-41F0-BEAB-AC83160E2BEE} = {ADAAA63C-E17C-4F1B-A062-3CCA071D75C2} + {237C8A3F-F2AF-420C-873E-D3DF504DC7A2} = {303AE78F-6C96-4DF4-AC89-5C4FD53AFF0B} + {D2A5BB81-28E8-4C72-9E11-379DFCE5C311} = {303AE78F-6C96-4DF4-AC89-5C4FD53AFF0B} + {FD1DD2C6-A7B5-4BF3-8BD3-DCE9BF1EE2B0} = {303AE78F-6C96-4DF4-AC89-5C4FD53AFF0B} + {CD3788D9-EAF3-428E-A237-FE24A7D76CC0} = {303AE78F-6C96-4DF4-AC89-5C4FD53AFF0B} + {BC33650E-E774-48B5-B35D-01B1E04BBC05} = {303AE78F-6C96-4DF4-AC89-5C4FD53AFF0B} + {7FCF5FC3-F59C-4A89-A511-EF98201181F3} = {303AE78F-6C96-4DF4-AC89-5C4FD53AFF0B} + {FD052A19-B9B3-4A74-A9C0-6EA0C26A8D1B} = {303AE78F-6C96-4DF4-AC89-5C4FD53AFF0B} + {5E722C8E-2C81-42DF-B70E-7AC0AEBD1593} = {303AE78F-6C96-4DF4-AC89-5C4FD53AFF0B} + {0C98213A-A553-40DC-BEA9-137BDE4A7398} = {96F5D441-B8DE-4ABC-BEF2-F758D1B2BA39} + {1755E8DB-970C-4A24-8B7C-A2BEC1410BEE} = {7A9B997B-DAAC-4004-94F3-32F6B88E0068} + {80080C1D-579E-4AB2-935D-5CFFC51843D8} = {7A9B997B-DAAC-4004-94F3-32F6B88E0068} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {6AE955B5-16B0-41CF-9F12-66D15B3DD1AB} + EndGlobalSection +EndGlobal diff --git a/Makefile b/Makefile index 85210eef3..6f2f5a2b1 100644 --- a/Makefile +++ b/Makefile @@ -11,20 +11,20 @@ shutdown_broker: docker-compose -f docker-compose.yml down restore: - dotnet restore src/KafkaFlow.sln + dotnet restore KafkaFlow.sln build: - dotnet build src/KafkaFlow.sln + dotnet build KafkaFlow.sln unit_tests: @echo command | date @echo Running unit tests - dotnet test src/KafkaFlow.UnitTests/KafkaFlow.UnitTests.csproj --framework netcoreapp2.1 --logger "console;verbosity=detailed" - dotnet test src/KafkaFlow.UnitTests/KafkaFlow.UnitTests.csproj --framework netcoreapp3.1 --logger "console;verbosity=detailed" + dotnet test tests/KafkaFlow.UnitTests/KafkaFlow.UnitTests.csproj --framework netcoreapp2.1 --logger "console;verbosity=detailed" + dotnet test tests/KafkaFlow.UnitTests/KafkaFlow.UnitTests.csproj --framework netcoreapp3.1 --logger "console;verbosity=detailed" integration_tests: @echo command | date make init_broker @echo Running integration tests - dotnet test src/KafkaFlow.IntegrationTests/KafkaFlow.IntegrationTests.csproj -c Release --framework netcoreapp3.1 --logger "console;verbosity=detailed" + dotnet test tests/KafkaFlow.IntegrationTests/KafkaFlow.IntegrationTests.csproj -c Release --framework netcoreapp3.1 --logger "console;verbosity=detailed" make shutdown_broker diff --git a/samples/KafkaFlow.Sample.BatchOperations/PrintConsoleMiddleware.cs b/samples/KafkaFlow.Sample.BatchOperations/PrintConsoleMiddleware.cs index 438689b7a..ff6309d39 100644 --- a/samples/KafkaFlow.Sample.BatchOperations/PrintConsoleMiddleware.cs +++ b/samples/KafkaFlow.Sample.BatchOperations/PrintConsoleMiddleware.cs @@ -1,7 +1,6 @@ using System; using System.Linq; using System.Threading.Tasks; -using KafkaFlow.Batching; namespace KafkaFlow.Sample.BatchOperations; @@ -13,7 +12,7 @@ public Task Invoke(IMessageContext context, MiddlewareDelegate next) var text = string.Join( '\n', - batch.Select(ctx => ((SampleBatchMessage) ctx.Message.Value).Text)); + batch.Select(ctx => ((SampleBatchMessage)ctx.Message.Value).Text)); Console.WriteLine(text); diff --git a/samples/KafkaFlow.Sample.Dashboard/Startup.cs b/samples/KafkaFlow.Sample.Dashboard/Startup.cs index 289b2bef6..db465fdcc 100644 --- a/samples/KafkaFlow.Sample.Dashboard/Startup.cs +++ b/samples/KafkaFlow.Sample.Dashboard/Startup.cs @@ -1,4 +1,3 @@ -namespace KafkaFlow.Sample.Dashboard; using KafkaFlow.Admin.Dashboard; using Microsoft.AspNetCore.Builder; @@ -6,6 +5,7 @@ namespace KafkaFlow.Sample.Dashboard; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +namespace KafkaFlow.Sample.Dashboard; public class Startup { // This method gets called by the runtime. Use this method to add services to the container. diff --git a/samples/KafkaFlow.Sample.PauseConsumerOnError/MessageHandler.cs b/samples/KafkaFlow.Sample.PauseConsumerOnError/MessageHandler.cs index 77b597265..a5248185a 100644 --- a/samples/KafkaFlow.Sample.PauseConsumerOnError/MessageHandler.cs +++ b/samples/KafkaFlow.Sample.PauseConsumerOnError/MessageHandler.cs @@ -1,5 +1,3 @@ -using KafkaFlow.Middlewares.TypedHandler; - namespace KafkaFlow.Sample.PauseConsumerOnError; public class MessageHandler : IMessageHandler diff --git a/samples/KafkaFlow.Sample.PauseConsumerOnError/PauseConsumerOnExceptionMiddleware.cs b/samples/KafkaFlow.Sample.PauseConsumerOnError/PauseConsumerOnExceptionMiddleware.cs index b45b0ec4b..885221775 100644 --- a/samples/KafkaFlow.Sample.PauseConsumerOnError/PauseConsumerOnExceptionMiddleware.cs +++ b/samples/KafkaFlow.Sample.PauseConsumerOnError/PauseConsumerOnExceptionMiddleware.cs @@ -4,13 +4,13 @@ namespace KafkaFlow.Sample.PauseConsumerOnError; public class PauseConsumerOnExceptionMiddleware : IMessageMiddleware { - private readonly IConsumerAccessor consumerAccessor; - private readonly ILogHandler logHandler; + private readonly IConsumerAccessor _consumerAccessor; + private readonly ILogHandler _logHandler; public PauseConsumerOnExceptionMiddleware(IConsumerAccessor consumerAccessor, ILogHandler logHandler) { - this.consumerAccessor = consumerAccessor; - this.logHandler = logHandler; + _consumerAccessor = consumerAccessor; + _logHandler = logHandler; } public async Task Invoke(IMessageContext context, MiddlewareDelegate next) @@ -22,7 +22,7 @@ public async Task Invoke(IMessageContext context, MiddlewareDelegate next) catch (Exception exception) { context.ConsumerContext.AutoMessageCompletion = false; - this.logHandler.Error("Error handling message", exception, + _logHandler.Error("Error handling message", exception, new { context.Message, @@ -31,10 +31,10 @@ public async Task Invoke(IMessageContext context, MiddlewareDelegate next) context.ConsumerContext.ConsumerName, }); - var consumer = this.consumerAccessor[context.ConsumerContext.ConsumerName]; + var consumer = _consumerAccessor[context.ConsumerContext.ConsumerName]; consumer.Pause(consumer.Assignment); - this.logHandler.Warning("Consumer stopped", context.ConsumerContext.ConsumerName); + _logHandler.Warning("Consumer stopped", context.ConsumerContext.ConsumerName); } } } \ No newline at end of file diff --git a/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/AvroMessageHandler.cs b/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/AvroMessageHandler.cs index 0893f1225..35338d6d0 100644 --- a/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/AvroMessageHandler.cs +++ b/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/AvroMessageHandler.cs @@ -1,10 +1,9 @@ -namespace KafkaFlow.Sample.SchemaRegistry.Handlers -{ - using System; - using System.Threading.Tasks; - using KafkaFlow.Middlewares.TypedHandler; - using global::SchemaRegistry; +using System; +using System.Threading.Tasks; +using global::SchemaRegistry; +namespace KafkaFlow.Sample.SchemaRegistry.Handlers +{ public class AvroMessageHandler : IMessageHandler { public Task Handle(IMessageContext context, AvroLogMessage message) diff --git a/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/AvroMessageHandler2.cs b/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/AvroMessageHandler2.cs index 65660f5f3..0f772f0a3 100644 --- a/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/AvroMessageHandler2.cs +++ b/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/AvroMessageHandler2.cs @@ -1,9 +1,8 @@ -namespace KafkaFlow.Sample.SchemaRegistry.Handlers; - -using System; +using System; using System.Threading.Tasks; using global::SchemaRegistry; -using KafkaFlow.Middlewares.TypedHandler; + +namespace KafkaFlow.Sample.SchemaRegistry.Handlers; public class AvroMessageHandler2 : IMessageHandler { diff --git a/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/JsonMessageHandler.cs b/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/JsonMessageHandler.cs index 39b446434..774449a3c 100644 --- a/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/JsonMessageHandler.cs +++ b/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/JsonMessageHandler.cs @@ -1,9 +1,8 @@ -namespace KafkaFlow.Sample.SchemaRegistry.Handlers; - -using System; +using System; using System.Threading.Tasks; using global::SchemaRegistry; -using KafkaFlow.Middlewares.TypedHandler; + +namespace KafkaFlow.Sample.SchemaRegistry.Handlers; public class JsonMessageHandler : IMessageHandler { diff --git a/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/ProtobufMessageHandler.cs b/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/ProtobufMessageHandler.cs index e1158c9c8..768f7c1d5 100644 --- a/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/ProtobufMessageHandler.cs +++ b/samples/KafkaFlow.Sample.SchemaRegistry/Handlers/ProtobufMessageHandler.cs @@ -1,7 +1,5 @@ - -using System; +using System; using System.Threading.Tasks; -using KafkaFlow.Middlewares.TypedHandler; using SchemaRegistry; namespace KafkaFlow.Sample.SchemaRegistry.Handlers; diff --git a/samples/KafkaFlow.Sample.SchemaRegistry/MessageTypes/Avro/SchemaRegistry/AvroLogMessage.cs b/samples/KafkaFlow.Sample.SchemaRegistry/MessageTypes/Avro/SchemaRegistry/AvroLogMessage.cs index 81ecc9a29..cb325ee1a 100644 --- a/samples/KafkaFlow.Sample.SchemaRegistry/MessageTypes/Avro/SchemaRegistry/AvroLogMessage.cs +++ b/samples/KafkaFlow.Sample.SchemaRegistry/MessageTypes/Avro/SchemaRegistry/AvroLogMessage.cs @@ -18,8 +18,10 @@ namespace SchemaRegistry /// public partial class AvroLogMessage : ISpecificRecord { - public static Schema _SCHEMA = Avro.Schema.Parse(@"{""type"":""record"",""name"":""AvroLogMessage"",""doc"":""A simple log message."",""namespace"":""SchemaRegistry"",""fields"":[{""name"":""Severity"",""type"":{""type"":""enum"",""name"":""LogLevel"",""doc"":""Enumerates the set of allowable log levels."",""namespace"":""SchemaRegistry"",""symbols"":[""None"",""Verbose"",""Info"",""Warning"",""Error""]}}]}"); - private SchemaRegistry.LogLevel _Severity; + public static Schema _SCHEMA = Avro.Schema.Parse(@"{""type"":""record"",""name"":""AvroLogMessage"",""doc"":""A simple log message."",""namespace"":""SchemaRegistry"",""fields"":[{""name"":""Severity"",""type"":{""type"":""enum"",""name"":""LogLevel"",""doc"":""Enumerates the set of allowable log levels."",""namespace"":""SchemaRegistry"",""symbols"":[""None"",""Verbose"",""Info"",""Warning"",""Error""]}}]}") + ; + private SchemaRegistry.LogLevel _severity; + public virtual Schema Schema { get @@ -31,11 +33,11 @@ public SchemaRegistry.LogLevel Severity { get { - return this._Severity; + return _severity; } set { - this._Severity = value; + _severity = value; } } public virtual object Get(int fieldPos) diff --git a/samples/KafkaFlow.Sample.SchemaRegistry/MessageTypes/Avro/SchemaRegistry/AvroLogMessage2.cs b/samples/KafkaFlow.Sample.SchemaRegistry/MessageTypes/Avro/SchemaRegistry/AvroLogMessage2.cs index 695a07862..e90b8e3f7 100644 --- a/samples/KafkaFlow.Sample.SchemaRegistry/MessageTypes/Avro/SchemaRegistry/AvroLogMessage2.cs +++ b/samples/KafkaFlow.Sample.SchemaRegistry/MessageTypes/Avro/SchemaRegistry/AvroLogMessage2.cs @@ -20,7 +20,9 @@ public partial class AvroLogMessage2 : ISpecificRecord { public static Schema _SCHEMA = Avro.Schema.Parse("{\"type\":\"record\",\"name\":\"AvroLogMessage2\",\"doc\":\"A simple log message.\",\"namespac" + "e\":\"SchemaRegistry\",\"fields\":[{\"name\":\"Message\",\"type\":\"string\"}]}"); - private string _Message; + + private string _message; + public virtual Schema Schema { get @@ -32,11 +34,11 @@ public string Message { get { - return this._Message; + return _message; } set { - this._Message = value; + _message = value; } } public virtual object Get(int fieldPos) diff --git a/samples/KafkaFlow.Sample.SchemaRegistry/MessageTypes/Json/JsonLogMessage.cs b/samples/KafkaFlow.Sample.SchemaRegistry/MessageTypes/Json/JsonLogMessage.cs index 886adb834..95d0c1cbe 100644 --- a/samples/KafkaFlow.Sample.SchemaRegistry/MessageTypes/Json/JsonLogMessage.cs +++ b/samples/KafkaFlow.Sample.SchemaRegistry/MessageTypes/Json/JsonLogMessage.cs @@ -1,16 +1,16 @@ +using Newtonsoft.Json; + namespace SchemaRegistry { - using Newtonsoft.Json; + /// + /// A simple log message. + /// + public class JsonLogMessage + { + [JsonProperty] + public string Message { get; set; } - /// - /// A simple log message. - /// - public class JsonLogMessage - { - [JsonProperty] - public string Message { get; set; } - - [JsonProperty] - public string Type { get; set; } - } + [JsonProperty] + public string Type { get; set; } + } } diff --git a/samples/KafkaFlow.Sample.SchemaRegistry/Program.cs b/samples/KafkaFlow.Sample.SchemaRegistry/Program.cs index 926879042..ba5b18d80 100644 --- a/samples/KafkaFlow.Sample.SchemaRegistry/Program.cs +++ b/samples/KafkaFlow.Sample.SchemaRegistry/Program.cs @@ -22,7 +22,7 @@ .UseConsoleLog() .AddCluster( cluster => cluster - .WithBrokers(new[] {"localhost:9092"}) + .WithBrokers(new[] { "localhost:9092" }) .WithSchemaRegistry(config => config.Url = "localhost:8081") .CreateTopicIfNotExists(avroTopic, 1, 1) .CreateTopicIfNotExists(jsonTopic, 1, 1) @@ -79,7 +79,7 @@ .AddHandler() .AddHandler()) ) - ) + ) .AddConsumer( consumer => consumer .Topic(jsonTopic) @@ -128,16 +128,16 @@ await Task.WhenAll( producers[avroProducerName].ProduceAsync( Guid.NewGuid().ToString(), - new AvroLogMessage {Severity = LogLevel.Info}), + new AvroLogMessage { Severity = LogLevel.Info }), producers[avroProducerName].ProduceAsync( Guid.NewGuid().ToString(), - new AvroLogMessage2 {Message = Guid.NewGuid().ToString()}), + new AvroLogMessage2 { Message = Guid.NewGuid().ToString() }), producers[jsonProducerName].ProduceAsync( Guid.NewGuid().ToString(), - new JsonLogMessage {Message = Guid.NewGuid().ToString()}), + new JsonLogMessage { Message = Guid.NewGuid().ToString() }), producers[protobufProducerName].ProduceAsync( Guid.NewGuid().ToString(), - new ProtobufLogMessage {Message = Guid.NewGuid().ToString()}) + new ProtobufLogMessage { Message = Guid.NewGuid().ToString() }) ); } diff --git a/samples/KafkaFlow.Sample.WebApi/Program.cs b/samples/KafkaFlow.Sample.WebApi/Program.cs index d50287655..f91ad3a4b 100644 --- a/samples/KafkaFlow.Sample.WebApi/Program.cs +++ b/samples/KafkaFlow.Sample.WebApi/Program.cs @@ -44,4 +44,3 @@ await kafkaBus.StartAsync(); await app.RunAsync(); - \ No newline at end of file diff --git a/samples/KafkaFlow.Sample/PrintConsoleHandler.cs b/samples/KafkaFlow.Sample/PrintConsoleHandler.cs index 57a1a48b8..a2341a744 100644 --- a/samples/KafkaFlow.Sample/PrintConsoleHandler.cs +++ b/samples/KafkaFlow.Sample/PrintConsoleHandler.cs @@ -1,6 +1,5 @@ using System; using System.Threading.Tasks; -using KafkaFlow.Middlewares.TypedHandler; namespace KafkaFlow.Sample; diff --git a/samples/KafkaFlow.Sample/TestMessage.cs b/samples/KafkaFlow.Sample/TestMessage.cs index e363575bc..a9b8c5c6d 100644 --- a/samples/KafkaFlow.Sample/TestMessage.cs +++ b/samples/KafkaFlow.Sample/TestMessage.cs @@ -5,6 +5,6 @@ namespace KafkaFlow.Sample; [DataContract] public class TestMessage { - [DataMember(Order = 1)] + [DataMember(Order = 1)] public string Text { get; set; } } \ No newline at end of file diff --git a/src/KafkaFlow.Abstractions/Configuration/IClusterConfigurationBuilder.cs b/src/KafkaFlow.Abstractions/Configuration/IClusterConfigurationBuilder.cs index 41325ef45..c216693de 100644 --- a/src/KafkaFlow.Abstractions/Configuration/IClusterConfigurationBuilder.cs +++ b/src/KafkaFlow.Abstractions/Configuration/IClusterConfigurationBuilder.cs @@ -1,8 +1,8 @@ +using System; +using System.Collections.Generic; + namespace KafkaFlow.Configuration { - using System; - using System.Collections.Generic; - /// /// A interface to build the cluster configuration /// diff --git a/src/KafkaFlow.Abstractions/Configuration/IConsumerConfigurationBuilder.cs b/src/KafkaFlow.Abstractions/Configuration/IConsumerConfigurationBuilder.cs index 68ece2959..809bca56e 100644 --- a/src/KafkaFlow.Abstractions/Configuration/IConsumerConfigurationBuilder.cs +++ b/src/KafkaFlow.Abstractions/Configuration/IConsumerConfigurationBuilder.cs @@ -1,9 +1,9 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + namespace KafkaFlow.Configuration { - using System; - using System.Collections.Generic; - using System.Threading.Tasks; - /// /// Used to build the consumer configuration /// @@ -192,4 +192,4 @@ IConsumerConfigurationBuilder WithWorkerDistributionStrategy() /// IConsumerConfigurationBuilder WithStatisticsIntervalMs(int statisticsIntervalMs); } -} \ No newline at end of file +} diff --git a/src/KafkaFlow.Abstractions/Configuration/IKafkaConfigurationBuilder.cs b/src/KafkaFlow.Abstractions/Configuration/IKafkaConfigurationBuilder.cs index 1b26034b0..828e20df2 100644 --- a/src/KafkaFlow.Abstractions/Configuration/IKafkaConfigurationBuilder.cs +++ b/src/KafkaFlow.Abstractions/Configuration/IKafkaConfigurationBuilder.cs @@ -1,7 +1,7 @@ +using System; + namespace KafkaFlow.Configuration { - using System; - /// /// A builder to configure KafkaFlow /// diff --git a/src/KafkaFlow.Abstractions/Configuration/IProducerConfigurationBuilder.cs b/src/KafkaFlow.Abstractions/Configuration/IProducerConfigurationBuilder.cs index a5293b67a..7e2a8f64c 100644 --- a/src/KafkaFlow.Abstractions/Configuration/IProducerConfigurationBuilder.cs +++ b/src/KafkaFlow.Abstractions/Configuration/IProducerConfigurationBuilder.cs @@ -1,7 +1,7 @@ +using System; + namespace KafkaFlow.Configuration { - using System; - /// /// Used to build the producer configuration /// diff --git a/src/KafkaFlow.Abstractions/Configuration/TopicPartitions.cs b/src/KafkaFlow.Abstractions/Configuration/TopicPartitions.cs index 4dd58b2e2..b8c3b4939 100644 --- a/src/KafkaFlow.Abstractions/Configuration/TopicPartitions.cs +++ b/src/KafkaFlow.Abstractions/Configuration/TopicPartitions.cs @@ -1,7 +1,7 @@ +using System.Collections.Generic; + namespace KafkaFlow.Configuration { - using System.Collections.Generic; - public class TopicPartitions { public TopicPartitions(string name, IEnumerable partitions) diff --git a/src/KafkaFlow.Abstractions/Configuration/WorkersCountContext.cs b/src/KafkaFlow.Abstractions/Configuration/WorkersCountContext.cs index a54a4b82f..800587f1c 100644 --- a/src/KafkaFlow.Abstractions/Configuration/WorkersCountContext.cs +++ b/src/KafkaFlow.Abstractions/Configuration/WorkersCountContext.cs @@ -1,7 +1,7 @@ +using System.Collections.Generic; + namespace KafkaFlow.Configuration { - using System.Collections.Generic; - /// /// A metadata class with some context information help to calculate the number of workers /// diff --git a/src/KafkaFlow.Abstractions/Delegates.cs b/src/KafkaFlow.Abstractions/Delegates.cs index fd7edde9e..f9fb9710d 100644 --- a/src/KafkaFlow.Abstractions/Delegates.cs +++ b/src/KafkaFlow.Abstractions/Delegates.cs @@ -1,7 +1,7 @@ +using System.Threading.Tasks; + namespace KafkaFlow { - using System.Threading.Tasks; - /// /// The delegate used to call the next middleware /// diff --git a/src/KafkaFlow.Abstractions/Extensions/DependencyConfiguratorExtensions.cs b/src/KafkaFlow.Abstractions/Extensions/DependencyConfiguratorExtensions.cs index f2021fed2..c316a28b9 100644 --- a/src/KafkaFlow.Abstractions/Extensions/DependencyConfiguratorExtensions.cs +++ b/src/KafkaFlow.Abstractions/Extensions/DependencyConfiguratorExtensions.cs @@ -1,7 +1,7 @@ +using System; + namespace KafkaFlow { - using System; - /// /// Provides extension methods over /// diff --git a/src/KafkaFlow.Abstractions/Extensions/DependencyResolverExtensions.cs b/src/KafkaFlow.Abstractions/Extensions/DependencyResolverExtensions.cs index 50a1467a7..37d716ff5 100644 --- a/src/KafkaFlow.Abstractions/Extensions/DependencyResolverExtensions.cs +++ b/src/KafkaFlow.Abstractions/Extensions/DependencyResolverExtensions.cs @@ -11,6 +11,6 @@ public static class DependencyResolverExtensions /// Instance of /// The type to be resolved /// - public static T Resolve(this IDependencyResolver resolver) => (T) resolver.Resolve(typeof(T)); + public static T Resolve(this IDependencyResolver resolver) => (T)resolver.Resolve(typeof(T)); } } diff --git a/src/KafkaFlow.Abstractions/Extensions/DictionaryExtensions.cs b/src/KafkaFlow.Abstractions/Extensions/DictionaryExtensions.cs index 029649868..7dd803ed7 100644 --- a/src/KafkaFlow.Abstractions/Extensions/DictionaryExtensions.cs +++ b/src/KafkaFlow.Abstractions/Extensions/DictionaryExtensions.cs @@ -1,8 +1,8 @@ +using System; +using System.Collections.Generic; + namespace KafkaFlow { - using System; - using System.Collections.Generic; - /// /// No needed /// diff --git a/src/KafkaFlow.Abstractions/Extensions/MessageHeaderExtensions.cs b/src/KafkaFlow.Abstractions/Extensions/MessageHeaderExtensions.cs index 7f25f2e62..169bfa707 100644 --- a/src/KafkaFlow.Abstractions/Extensions/MessageHeaderExtensions.cs +++ b/src/KafkaFlow.Abstractions/Extensions/MessageHeaderExtensions.cs @@ -1,7 +1,7 @@ +using System.Text; + namespace KafkaFlow { - using System.Text; - /// /// Provides extension methods over /// diff --git a/src/KafkaFlow.Abstractions/IConsumerContext.cs b/src/KafkaFlow.Abstractions/IConsumerContext.cs index b185d9c2b..fbc7ed656 100644 --- a/src/KafkaFlow.Abstractions/IConsumerContext.cs +++ b/src/KafkaFlow.Abstractions/IConsumerContext.cs @@ -1,9 +1,9 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + namespace KafkaFlow { - using System; - using System.Threading; - using System.Threading.Tasks; - /// /// Represents the message consumer /// diff --git a/src/KafkaFlow.Abstractions/IDateTimeProvider.cs b/src/KafkaFlow.Abstractions/IDateTimeProvider.cs index b235eeb4a..73b28d39b 100644 --- a/src/KafkaFlow.Abstractions/IDateTimeProvider.cs +++ b/src/KafkaFlow.Abstractions/IDateTimeProvider.cs @@ -1,7 +1,7 @@ +using System; + namespace KafkaFlow { - using System; - /// /// Provides access to DateTime static members /// diff --git a/src/KafkaFlow.Abstractions/IDependencyConfigurator.cs b/src/KafkaFlow.Abstractions/IDependencyConfigurator.cs index 5f8212664..47d52ce46 100644 --- a/src/KafkaFlow.Abstractions/IDependencyConfigurator.cs +++ b/src/KafkaFlow.Abstractions/IDependencyConfigurator.cs @@ -1,7 +1,7 @@ +using System; + namespace KafkaFlow { - using System; - /// /// Represents the interface to be implemented by custom dependency configurator /// diff --git a/src/KafkaFlow.Abstractions/IDependencyResolver.cs b/src/KafkaFlow.Abstractions/IDependencyResolver.cs index 597afff92..92457ae9c 100644 --- a/src/KafkaFlow.Abstractions/IDependencyResolver.cs +++ b/src/KafkaFlow.Abstractions/IDependencyResolver.cs @@ -1,8 +1,8 @@ +using System; +using System.Collections.Generic; + namespace KafkaFlow { - using System; - using System.Collections.Generic; - /// /// Represents the interface of a dependency injection resolver /// diff --git a/src/KafkaFlow.Abstractions/IDependencyResolverScope.cs b/src/KafkaFlow.Abstractions/IDependencyResolverScope.cs index 74c932245..08462f942 100644 --- a/src/KafkaFlow.Abstractions/IDependencyResolverScope.cs +++ b/src/KafkaFlow.Abstractions/IDependencyResolverScope.cs @@ -1,7 +1,7 @@ +using System; + namespace KafkaFlow { - using System; - /// /// Represents the interface of a dependency injection resolver scope /// diff --git a/src/KafkaFlow.Abstractions/IDeserializer.cs b/src/KafkaFlow.Abstractions/IDeserializer.cs index 0ecfd2c86..fbf10eea3 100644 --- a/src/KafkaFlow.Abstractions/IDeserializer.cs +++ b/src/KafkaFlow.Abstractions/IDeserializer.cs @@ -1,9 +1,9 @@ +using System; +using System.IO; +using System.Threading.Tasks; + namespace KafkaFlow { - using System; - using System.IO; - using System.Threading.Tasks; - /// /// Used to implement a message serializer /// diff --git a/src/KafkaFlow.Abstractions/IEvent.cs b/src/KafkaFlow.Abstractions/IEvent.cs index f9a055b4f..176c33f29 100644 --- a/src/KafkaFlow.Abstractions/IEvent.cs +++ b/src/KafkaFlow.Abstractions/IEvent.cs @@ -1,8 +1,8 @@ -namespace KafkaFlow -{ - using System; - using System.Threading.Tasks; +using System; +using System.Threading.Tasks; +namespace KafkaFlow +{ /// /// Represents an Event to be subscribed. /// @@ -29,4 +29,4 @@ public interface IEvent /// Event subscription reference IEventSubscription Subscribe(Func handler); } -} \ No newline at end of file +} diff --git a/src/KafkaFlow.Abstractions/ILogHandler.cs b/src/KafkaFlow.Abstractions/ILogHandler.cs index b426491ee..70afdd3c2 100644 --- a/src/KafkaFlow.Abstractions/ILogHandler.cs +++ b/src/KafkaFlow.Abstractions/ILogHandler.cs @@ -1,7 +1,7 @@ +using System; + namespace KafkaFlow { - using System; - /// /// An interface used to create a log handler /// diff --git a/src/KafkaFlow.Abstractions/IMessageContext.cs b/src/KafkaFlow.Abstractions/IMessageContext.cs index 8b39dba96..2011e1b71 100644 --- a/src/KafkaFlow.Abstractions/IMessageContext.cs +++ b/src/KafkaFlow.Abstractions/IMessageContext.cs @@ -1,7 +1,7 @@ +using System.Collections.Generic; + namespace KafkaFlow { - using System.Collections.Generic; - /// /// A context that contains the message and metadata /// diff --git a/src/KafkaFlow.Abstractions/IMessageHandler.cs b/src/KafkaFlow.Abstractions/IMessageHandler.cs index 611ba91f6..329784013 100644 --- a/src/KafkaFlow.Abstractions/IMessageHandler.cs +++ b/src/KafkaFlow.Abstractions/IMessageHandler.cs @@ -1,7 +1,7 @@ +using System.Threading.Tasks; + namespace KafkaFlow { - using System.Threading.Tasks; - /// /// Used to create a message handler /// diff --git a/src/KafkaFlow.Abstractions/IMessageHeaders.cs b/src/KafkaFlow.Abstractions/IMessageHeaders.cs index 25067ca04..8424c6f9b 100644 --- a/src/KafkaFlow.Abstractions/IMessageHeaders.cs +++ b/src/KafkaFlow.Abstractions/IMessageHeaders.cs @@ -1,7 +1,7 @@ +using System.Collections.Generic; + namespace KafkaFlow { - using System.Collections.Generic; - /// /// Represents a collection of message headers /// diff --git a/src/KafkaFlow.Abstractions/IMessageMiddleware.cs b/src/KafkaFlow.Abstractions/IMessageMiddleware.cs index 1f5891970..92633e265 100644 --- a/src/KafkaFlow.Abstractions/IMessageMiddleware.cs +++ b/src/KafkaFlow.Abstractions/IMessageMiddleware.cs @@ -1,7 +1,7 @@ +using System.Threading.Tasks; + namespace KafkaFlow { - using System.Threading.Tasks; - /// /// Used to create a message middleware /// diff --git a/src/KafkaFlow.Abstractions/ISerializer.cs b/src/KafkaFlow.Abstractions/ISerializer.cs index 23cd9b73a..42f026a44 100644 --- a/src/KafkaFlow.Abstractions/ISerializer.cs +++ b/src/KafkaFlow.Abstractions/ISerializer.cs @@ -1,8 +1,8 @@ +using System.IO; +using System.Threading.Tasks; + namespace KafkaFlow { - using System.IO; - using System.Threading.Tasks; - /// /// Used to implement a message serializer /// diff --git a/src/KafkaFlow.Abstractions/IWorkerDistributionStrategy.cs b/src/KafkaFlow.Abstractions/IWorkerDistributionStrategy.cs index c883b2f7a..cb4af966f 100644 --- a/src/KafkaFlow.Abstractions/IWorkerDistributionStrategy.cs +++ b/src/KafkaFlow.Abstractions/IWorkerDistributionStrategy.cs @@ -1,8 +1,8 @@ -namespace KafkaFlow; - using System.Collections.Generic; using System.Threading.Tasks; +namespace KafkaFlow; + /// /// An interface used to create a distribution strategy /// diff --git a/src/KafkaFlow.Abstractions/MessageErrorEventContext.cs b/src/KafkaFlow.Abstractions/MessageErrorEventContext.cs index fb5f38f2a..57229a862 100644 --- a/src/KafkaFlow.Abstractions/MessageErrorEventContext.cs +++ b/src/KafkaFlow.Abstractions/MessageErrorEventContext.cs @@ -1,7 +1,7 @@ -namespace KafkaFlow -{ - using System; +using System; +namespace KafkaFlow +{ /// /// Represents the errors in message context used in the events /// diff --git a/src/KafkaFlow.Abstractions/NullLogHandler.cs b/src/KafkaFlow.Abstractions/NullLogHandler.cs index 45da09d88..e7a8a496f 100644 --- a/src/KafkaFlow.Abstractions/NullLogHandler.cs +++ b/src/KafkaFlow.Abstractions/NullLogHandler.cs @@ -1,7 +1,7 @@ +using System; + namespace KafkaFlow { - using System; - /// /// A log handler that does nothing /// diff --git a/src/KafkaFlow.Abstractions/WorkerDistributionContext.cs b/src/KafkaFlow.Abstractions/WorkerDistributionContext.cs index 43c3ce04d..d5ce00c59 100644 --- a/src/KafkaFlow.Abstractions/WorkerDistributionContext.cs +++ b/src/KafkaFlow.Abstractions/WorkerDistributionContext.cs @@ -1,8 +1,8 @@ -namespace KafkaFlow; - using System; using System.Threading; +namespace KafkaFlow; + /// /// Represents a strategy context for distributing workers based on specific message and consumer details. /// diff --git a/src/KafkaFlow.Admin.Dashboard/ApplicationBuilderExtensions.cs b/src/KafkaFlow.Admin.Dashboard/ApplicationBuilderExtensions.cs index f525b9a1a..8181c8e96 100644 --- a/src/KafkaFlow.Admin.Dashboard/ApplicationBuilderExtensions.cs +++ b/src/KafkaFlow.Admin.Dashboard/ApplicationBuilderExtensions.cs @@ -1,15 +1,15 @@ +using System; +using System.Globalization; +using System.Reflection; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.FileProviders; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; + namespace KafkaFlow.Admin.Dashboard { - using System; - using System.Globalization; - using System.Reflection; - using Microsoft.AspNetCore.Builder; - using Microsoft.AspNetCore.Http; - using Microsoft.Extensions.DependencyInjection; - using Microsoft.Extensions.FileProviders; - using Newtonsoft.Json; - using Newtonsoft.Json.Serialization; - /// /// Extension methods over IApplicationBuilder /// diff --git a/src/KafkaFlow.Admin.Dashboard/DashboardConfiguration.cs b/src/KafkaFlow.Admin.Dashboard/DashboardConfiguration.cs index 53f455329..cc6489e9a 100644 --- a/src/KafkaFlow.Admin.Dashboard/DashboardConfiguration.cs +++ b/src/KafkaFlow.Admin.Dashboard/DashboardConfiguration.cs @@ -1,9 +1,9 @@ +using System; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; + namespace KafkaFlow.Admin.Dashboard { - using System; - using Microsoft.AspNetCore.Builder; - using Microsoft.AspNetCore.Http; - internal class DashboardConfiguration { public DashboardConfiguration( diff --git a/src/KafkaFlow.Admin.Dashboard/DashboardConfigurationBuilder.cs b/src/KafkaFlow.Admin.Dashboard/DashboardConfigurationBuilder.cs index 4c0e1e61f..f72a65624 100644 --- a/src/KafkaFlow.Admin.Dashboard/DashboardConfigurationBuilder.cs +++ b/src/KafkaFlow.Admin.Dashboard/DashboardConfigurationBuilder.cs @@ -1,31 +1,31 @@ +using System; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; + namespace KafkaFlow.Admin.Dashboard { - using System; - using Microsoft.AspNetCore.Builder; - using Microsoft.AspNetCore.Http; - internal class DashboardConfigurationBuilder : IDashboardConfigurationBuilder { - private readonly PathString basePath = "/kafkaflow"; + private readonly PathString _basePath = "/kafkaflow"; - private Action requestHandler = _ => { }; - private Action endpointHandler = _ => { }; + private Action _requestHandler = _ => { }; + private Action _endpointHandler = _ => { }; public IDashboardConfigurationBuilder ConfigureRequestPipeline(Action requestHandler) { - this.requestHandler = requestHandler; + _requestHandler = requestHandler; return this; } public IDashboardConfigurationBuilder ConfigureEndpoint(Action endpointHandler) { - this.endpointHandler = endpointHandler; + _endpointHandler = endpointHandler; return this; } public DashboardConfiguration Build() { - return new(this.basePath, this.requestHandler, this.endpointHandler); + return new(_basePath, _requestHandler, _endpointHandler); } } } diff --git a/src/KafkaFlow.Admin.Dashboard/IDashboardConfigurationBuilder.cs b/src/KafkaFlow.Admin.Dashboard/IDashboardConfigurationBuilder.cs index ea0b82c7c..8ab61c8ef 100644 --- a/src/KafkaFlow.Admin.Dashboard/IDashboardConfigurationBuilder.cs +++ b/src/KafkaFlow.Admin.Dashboard/IDashboardConfigurationBuilder.cs @@ -1,8 +1,8 @@ +using System; +using Microsoft.AspNetCore.Builder; + namespace KafkaFlow.Admin.Dashboard { - using System; - using Microsoft.AspNetCore.Builder; - /// /// Used to build the dashboard configuration /// diff --git a/src/KafkaFlow.Admin.Dashboard/KafkaFlow.Admin.Dashboard.csproj b/src/KafkaFlow.Admin.Dashboard/KafkaFlow.Admin.Dashboard.csproj index 8c6e2431a..c7ae07915 100644 --- a/src/KafkaFlow.Admin.Dashboard/KafkaFlow.Admin.Dashboard.csproj +++ b/src/KafkaFlow.Admin.Dashboard/KafkaFlow.Admin.Dashboard.csproj @@ -39,5 +39,5 @@ - + diff --git a/src/KafkaFlow.Admin.Dashboard/TelemetryResponse.cs b/src/KafkaFlow.Admin.Dashboard/TelemetryResponse.cs index 774a88c06..75a4705bd 100644 --- a/src/KafkaFlow.Admin.Dashboard/TelemetryResponse.cs +++ b/src/KafkaFlow.Admin.Dashboard/TelemetryResponse.cs @@ -1,10 +1,10 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using Newtonsoft.Json; + namespace KafkaFlow.Admin.Dashboard { - using System; - using System.Collections.Generic; - using System.ComponentModel.DataAnnotations; - using Newtonsoft.Json; - /// /// The response of telemetry data /// diff --git a/src/KafkaFlow.Admin.Dashboard/TelemetryResponseAdapter.cs b/src/KafkaFlow.Admin.Dashboard/TelemetryResponseAdapter.cs index d86045671..21c2f934f 100644 --- a/src/KafkaFlow.Admin.Dashboard/TelemetryResponseAdapter.cs +++ b/src/KafkaFlow.Admin.Dashboard/TelemetryResponseAdapter.cs @@ -1,9 +1,9 @@ +using System.Collections.Generic; +using System.Linq; +using KafkaFlow.Admin.Messages; + namespace KafkaFlow.Admin.Dashboard { - using System.Collections.Generic; - using System.Linq; - using KafkaFlow.Admin.Messages; - internal static class TelemetryResponseAdapter { internal static TelemetryResponse Adapt(this IEnumerable metrics) diff --git a/src/KafkaFlow.Admin.WebApi/Adapters/ConsumerResponseAdapter.cs b/src/KafkaFlow.Admin.WebApi/Adapters/ConsumerResponseAdapter.cs index 1bef549f9..68b798bdc 100644 --- a/src/KafkaFlow.Admin.WebApi/Adapters/ConsumerResponseAdapter.cs +++ b/src/KafkaFlow.Admin.WebApi/Adapters/ConsumerResponseAdapter.cs @@ -1,8 +1,8 @@ +using KafkaFlow.Admin.WebApi.Contracts; +using KafkaFlow.Consumers; + namespace KafkaFlow.Admin.WebApi.Adapters { - using KafkaFlow.Admin.WebApi.Contracts; - using KafkaFlow.Consumers; - internal static class ConsumerResponseAdapter { internal static ConsumerResponse Adapt(this IMessageConsumer consumer) diff --git a/src/KafkaFlow.Admin.WebApi/Adapters/TelemetryResponseAdapter.cs b/src/KafkaFlow.Admin.WebApi/Adapters/TelemetryResponseAdapter.cs index a4abd4720..1b6493038 100644 --- a/src/KafkaFlow.Admin.WebApi/Adapters/TelemetryResponseAdapter.cs +++ b/src/KafkaFlow.Admin.WebApi/Adapters/TelemetryResponseAdapter.cs @@ -1,10 +1,10 @@ +using System.Collections.Generic; +using System.Linq; +using KafkaFlow.Admin.Messages; +using KafkaFlow.Admin.WebApi.Contracts; + namespace KafkaFlow.Admin.WebApi.Adapters { - using System.Collections.Generic; - using System.Linq; - using KafkaFlow.Admin.Messages; - using KafkaFlow.Admin.WebApi.Contracts; - internal static class TelemetryResponseAdapter { internal static TelemetryResponse Adapt(this IEnumerable metrics) diff --git a/src/KafkaFlow.Admin.WebApi/Contracts/ConsumerResponse.cs b/src/KafkaFlow.Admin.WebApi/Contracts/ConsumerResponse.cs index c3c6cf6cb..ea7587cf8 100644 --- a/src/KafkaFlow.Admin.WebApi/Contracts/ConsumerResponse.cs +++ b/src/KafkaFlow.Admin.WebApi/Contracts/ConsumerResponse.cs @@ -1,69 +1,69 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using Newtonsoft.Json; + namespace KafkaFlow.Admin.WebApi.Contracts { - using System.Collections.Generic; - using System.ComponentModel.DataAnnotations; - using Newtonsoft.Json; - /// /// The response of the consumers /// public class ConsumerResponse { - /// - /// Gets or sets the consumer´s name - /// - [Required] - [JsonProperty(Required = Required.DisallowNull)] - public string ConsumerName { get; set; } + /// + /// Gets or sets the consumer´s name + /// + [Required] + [JsonProperty(Required = Required.DisallowNull)] + public string ConsumerName { get; set; } - /// - /// Gets or sets a value indicating whether the consumer is able to be manageable or not - /// - public bool ManagementDisabled { get; set; } + /// + /// Gets or sets a value indicating whether the consumer is able to be manageable or not + /// + public bool ManagementDisabled { get; set; } - /// - /// Gets or sets the group id - /// - [Required] - [JsonProperty(Required = Required.DisallowNull)] - public string GroupId { get; set; } + /// + /// Gets or sets the group id + /// + [Required] + [JsonProperty(Required = Required.DisallowNull)] + public string GroupId { get; set; } - /// - /// Gets or sets the current number of workers allocated by the consumer - /// - public int WorkersCount { get; set; } + /// + /// Gets or sets the current number of workers allocated by the consumer + /// + public int WorkersCount { get; set; } - /// - /// Gets or sets the current topics subscription - /// - public IEnumerable Subscription { get; set; } + /// + /// Gets or sets the current topics subscription + /// + public IEnumerable Subscription { get; set; } - /// - /// Gets or sets the (dynamic) group member id of this consumer (as set by the broker). - /// - [Required] - [JsonProperty(Required = Required.DisallowNull)] - public string MemberId { get; set; } + /// + /// Gets or sets the (dynamic) group member id of this consumer (as set by the broker). + /// + [Required] + [JsonProperty(Required = Required.DisallowNull)] + public string MemberId { get; set; } - /// - /// Gets or sets the name of this client instance. - /// Contains (but is not equal to) the client.id configuration parameter. - /// - /// - /// This name will be unique across all client - /// instances in a given application which allows - /// log messages to be associated with the - /// corresponding instance. - /// - [Required] - [JsonProperty(Required = Required.DisallowNull)] - public string ClientInstanceName { get; set; } + /// + /// Gets or sets the name of this client instance. + /// Contains (but is not equal to) the client.id configuration parameter. + /// + /// + /// This name will be unique across all client + /// instances in a given application which allows + /// log messages to be associated with the + /// corresponding instance. + /// + [Required] + [JsonProperty(Required = Required.DisallowNull)] + public string ClientInstanceName { get; set; } - /// - /// Gets or sets the current consumer status - /// - [Required] - [JsonProperty(Required = Required.DisallowNull)] - public string Status { get; set; } + /// + /// Gets or sets the current consumer status + /// + [Required] + [JsonProperty(Required = Required.DisallowNull)] + public string Status { get; set; } } } diff --git a/src/KafkaFlow.Admin.WebApi/Contracts/ConsumersResponse.cs b/src/KafkaFlow.Admin.WebApi/Contracts/ConsumersResponse.cs index 2ac630bf1..ab7ef5c51 100644 --- a/src/KafkaFlow.Admin.WebApi/Contracts/ConsumersResponse.cs +++ b/src/KafkaFlow.Admin.WebApi/Contracts/ConsumersResponse.cs @@ -1,7 +1,7 @@ +using System.Collections.Generic; + namespace KafkaFlow.Admin.WebApi.Contracts { - using System.Collections.Generic; - /// /// The response of the consumers /// diff --git a/src/KafkaFlow.Admin.WebApi/Contracts/GroupResponse.cs b/src/KafkaFlow.Admin.WebApi/Contracts/GroupResponse.cs index 4669f2fc4..461d80009 100644 --- a/src/KafkaFlow.Admin.WebApi/Contracts/GroupResponse.cs +++ b/src/KafkaFlow.Admin.WebApi/Contracts/GroupResponse.cs @@ -1,9 +1,9 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using Newtonsoft.Json; + namespace KafkaFlow.Admin.WebApi.Contracts { - using System.Collections.Generic; - using System.ComponentModel.DataAnnotations; - using Newtonsoft.Json; - /// /// The response of the consumer group /// diff --git a/src/KafkaFlow.Admin.WebApi/Contracts/GroupsResponse.cs b/src/KafkaFlow.Admin.WebApi/Contracts/GroupsResponse.cs index 79e97c03c..875d03dfa 100644 --- a/src/KafkaFlow.Admin.WebApi/Contracts/GroupsResponse.cs +++ b/src/KafkaFlow.Admin.WebApi/Contracts/GroupsResponse.cs @@ -1,7 +1,7 @@ +using System.Collections.Generic; + namespace KafkaFlow.Admin.WebApi.Contracts { - using System.Collections.Generic; - /// /// The response of the consumer groups /// diff --git a/src/KafkaFlow.Admin.WebApi/Contracts/RewindOffsetsToDateRequest.cs b/src/KafkaFlow.Admin.WebApi/Contracts/RewindOffsetsToDateRequest.cs index c11cfe5cd..c34050651 100644 --- a/src/KafkaFlow.Admin.WebApi/Contracts/RewindOffsetsToDateRequest.cs +++ b/src/KafkaFlow.Admin.WebApi/Contracts/RewindOffsetsToDateRequest.cs @@ -1,7 +1,7 @@ +using System; + namespace KafkaFlow.Admin.WebApi.Contracts { - using System; - /// /// The request to rewind offsets to a point in time /// diff --git a/src/KafkaFlow.Admin.WebApi/Contracts/TelemetryResponse.cs b/src/KafkaFlow.Admin.WebApi/Contracts/TelemetryResponse.cs index 778833ce0..195d30365 100644 --- a/src/KafkaFlow.Admin.WebApi/Contracts/TelemetryResponse.cs +++ b/src/KafkaFlow.Admin.WebApi/Contracts/TelemetryResponse.cs @@ -1,10 +1,10 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using Newtonsoft.Json; + namespace KafkaFlow.Admin.WebApi.Contracts { - using System; - using System.Collections.Generic; - using System.ComponentModel.DataAnnotations; - using Newtonsoft.Json; - /// /// The response of telemetry data /// diff --git a/src/KafkaFlow.Admin.WebApi/Controllers/ConsumersController.cs b/src/KafkaFlow.Admin.WebApi/Controllers/ConsumersController.cs index 7ef6f33f3..2d050b539 100644 --- a/src/KafkaFlow.Admin.WebApi/Controllers/ConsumersController.cs +++ b/src/KafkaFlow.Admin.WebApi/Controllers/ConsumersController.cs @@ -1,13 +1,13 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using KafkaFlow.Admin.WebApi.Adapters; +using KafkaFlow.Admin.WebApi.Contracts; +using KafkaFlow.Consumers; +using Microsoft.AspNetCore.Mvc; + namespace KafkaFlow.Admin.WebApi.Controllers { - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - using KafkaFlow.Admin.WebApi.Adapters; - using KafkaFlow.Admin.WebApi.Contracts; - using KafkaFlow.Consumers; - using Microsoft.AspNetCore.Mvc; - /// /// Consumers controller /// @@ -15,8 +15,8 @@ namespace KafkaFlow.Admin.WebApi.Controllers [ApiController] public class ConsumersController : ControllerBase { - private readonly IConsumerAccessor consumers; - private readonly IConsumerAdmin consumerAdmin; + private readonly IConsumerAccessor _consumers; + private readonly IConsumerAdmin _consumerAdmin; /// /// Initializes a new instance of the class. @@ -25,8 +25,8 @@ public class ConsumersController : ControllerBase /// The admin messages consumer public ConsumersController(IConsumerAccessor consumers, IConsumerAdmin consumerAdmin) { - this.consumers = consumers; - this.consumerAdmin = consumerAdmin; + _consumers = consumers; + _consumerAdmin = consumerAdmin; } /// @@ -41,7 +41,7 @@ public IActionResult GetConsumersByGroupId([FromRoute] string groupId) return this.Ok( new ConsumersResponse { - Consumers = this.consumers + Consumers = _consumers .All .Where(x => x.GroupId == groupId) .Select(x => x.Adapt()), @@ -62,7 +62,7 @@ public IActionResult GetConsumerByGroupIdName( [FromRoute] string groupId, [FromRoute] string consumerName) { - var consumer = this.consumers.All + var consumer = _consumers.All .FirstOrDefault(x => x.GroupId == groupId && x.ConsumerName == consumerName); if (consumer is null) @@ -89,7 +89,7 @@ public async Task PauseConsumer( [FromRoute] string consumerName, [FromQuery] IList topics) { - var consumer = this.consumers.All + var consumer = _consumers.All .FirstOrDefault(x => x.GroupId == groupId && x.ConsumerName == consumerName); if (consumer is null) @@ -97,7 +97,7 @@ public async Task PauseConsumer( return this.NotFound(); } - await this.consumerAdmin.PauseConsumerAsync(consumerName, topics); + await _consumerAdmin.PauseConsumerAsync(consumerName, topics); return this.Accepted(); } @@ -118,7 +118,7 @@ public async Task ResumeConsumer( [FromRoute] string consumerName, [FromQuery] IList topics) { - var consumer = this.consumers.All + var consumer = _consumers.All .FirstOrDefault(x => x.GroupId == groupId && x.ConsumerName == consumerName); if (consumer is null) @@ -126,7 +126,7 @@ public async Task ResumeConsumer( return this.NotFound(); } - await this.consumerAdmin.ResumeConsumerAsync(consumerName, topics); + await _consumerAdmin.ResumeConsumerAsync(consumerName, topics); return this.Accepted(); } @@ -145,14 +145,14 @@ public async Task StartConsumer( [FromRoute] string groupId, [FromRoute] string consumerName) { - var consumer = this.consumers.All.FirstOrDefault(x => x.GroupId == groupId && x.ConsumerName == consumerName); + var consumer = _consumers.All.FirstOrDefault(x => x.GroupId == groupId && x.ConsumerName == consumerName); if (consumer is null) { return this.NotFound(); } - await this.consumerAdmin.StartConsumerAsync(consumerName); + await _consumerAdmin.StartConsumerAsync(consumerName); return this.Accepted(); } @@ -171,14 +171,14 @@ public async Task StopConsumer( [FromRoute] string groupId, [FromRoute] string consumerName) { - var consumer = this.consumers.All.FirstOrDefault(x => x.GroupId == groupId && x.ConsumerName == consumerName); + var consumer = _consumers.All.FirstOrDefault(x => x.GroupId == groupId && x.ConsumerName == consumerName); if (consumer is null) { return this.NotFound(); } - await this.consumerAdmin.StopConsumerAsync(consumerName); + await _consumerAdmin.StopConsumerAsync(consumerName); return this.Accepted(); } @@ -197,7 +197,7 @@ public async Task RestartConsumer( [FromRoute] string groupId, [FromRoute] string consumerName) { - var consumer = this.consumers.All + var consumer = _consumers.All .FirstOrDefault(x => x.GroupId == groupId && x.ConsumerName == consumerName); if (consumer is null) @@ -205,7 +205,7 @@ public async Task RestartConsumer( return this.NotFound(); } - await this.consumerAdmin.RestartConsumerAsync(consumerName); + await _consumerAdmin.RestartConsumerAsync(consumerName); return this.Accepted(); } @@ -234,7 +234,7 @@ public async Task ResetOffsets( return this.BadRequest(); } - var consumer = this.consumers.All + var consumer = _consumers.All .FirstOrDefault(x => x.GroupId == groupId && x.ConsumerName == consumerName); if (consumer is null) @@ -242,7 +242,7 @@ public async Task ResetOffsets( return this.NotFound(); } - await this.consumerAdmin.ResetOffsetsAsync(consumerName, topics); + await _consumerAdmin.ResetOffsetsAsync(consumerName, topics); return this.Accepted(); } @@ -271,7 +271,7 @@ public async Task RewindOffsets( return this.BadRequest(); } - var consumer = this.consumers.All + var consumer = _consumers.All .FirstOrDefault(x => x.GroupId == groupId && x.ConsumerName == consumerName); if (consumer is null) @@ -279,7 +279,7 @@ public async Task RewindOffsets( return this.NotFound(); } - await this.consumerAdmin.RewindOffsetsAsync(consumerName, request.Date, topics); + await _consumerAdmin.RewindOffsetsAsync(consumerName, request.Date, topics); return this.Accepted(); } @@ -306,7 +306,7 @@ public async Task ChangeWorkersCount( return this.BadRequest(); } - var consumer = this.consumers.All + var consumer = _consumers.All .FirstOrDefault(x => x.GroupId == groupId && x.ConsumerName == consumerName); if (consumer is null) @@ -314,7 +314,7 @@ public async Task ChangeWorkersCount( return this.NotFound(); } - await this.consumerAdmin.ChangeWorkersCountAsync(consumerName, request.WorkersCount); + await _consumerAdmin.ChangeWorkersCountAsync(consumerName, request.WorkersCount); return this.Accepted(); } diff --git a/src/KafkaFlow.Admin.WebApi/Controllers/GroupsController.cs b/src/KafkaFlow.Admin.WebApi/Controllers/GroupsController.cs index 0ed3a5b2a..9c6f1609b 100644 --- a/src/KafkaFlow.Admin.WebApi/Controllers/GroupsController.cs +++ b/src/KafkaFlow.Admin.WebApi/Controllers/GroupsController.cs @@ -1,13 +1,13 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using KafkaFlow.Admin.WebApi.Adapters; +using KafkaFlow.Admin.WebApi.Contracts; +using KafkaFlow.Consumers; +using Microsoft.AspNetCore.Mvc; + namespace KafkaFlow.Admin.WebApi.Controllers { - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - using KafkaFlow.Admin.WebApi.Adapters; - using KafkaFlow.Admin.WebApi.Contracts; - using KafkaFlow.Consumers; - using Microsoft.AspNetCore.Mvc; - /// /// Groups controller /// @@ -15,8 +15,8 @@ namespace KafkaFlow.Admin.WebApi.Controllers [ApiController] public class GroupsController : ControllerBase { - private readonly IConsumerAccessor consumers; - private readonly IConsumerAdmin consumerAdmin; + private readonly IConsumerAccessor _consumers; + private readonly IConsumerAdmin _consumerAdmin; /// /// Initializes a new instance of the class. @@ -25,8 +25,8 @@ public class GroupsController : ControllerBase /// The admin messages consumer public GroupsController(IConsumerAccessor consumers, IConsumerAdmin consumerAdmin) { - this.consumers = consumers; - this.consumerAdmin = consumerAdmin; + _consumers = consumers; + _consumerAdmin = consumerAdmin; } /// @@ -40,7 +40,7 @@ public IActionResult GetAllGroups() return this.Ok( new GroupsResponse { - Groups = this.consumers.All + Groups = _consumers.All .GroupBy(x => x.GroupId) .Select( x => new GroupResponse @@ -64,7 +64,7 @@ public async Task PauseGroup( [FromRoute] string groupId, [FromQuery] IList topics) { - await this.consumerAdmin.PauseConsumerGroupAsync(groupId, topics); + await _consumerAdmin.PauseConsumerGroupAsync(groupId, topics); return this.Accepted(); } @@ -82,7 +82,7 @@ public async Task ResumeGroup( [FromRoute] string groupId, [FromQuery] IList topics) { - await this.consumerAdmin.ResumeConsumerGroupAsync(groupId, topics); + await _consumerAdmin.ResumeConsumerGroupAsync(groupId, topics); return this.Accepted(); } diff --git a/src/KafkaFlow.Admin.WebApi/Controllers/TelemetryController.cs b/src/KafkaFlow.Admin.WebApi/Controllers/TelemetryController.cs index 2cc39ef3c..b2a8e0362 100644 --- a/src/KafkaFlow.Admin.WebApi/Controllers/TelemetryController.cs +++ b/src/KafkaFlow.Admin.WebApi/Controllers/TelemetryController.cs @@ -1,9 +1,9 @@ +using KafkaFlow.Admin.WebApi.Adapters; +using KafkaFlow.Admin.WebApi.Contracts; +using Microsoft.AspNetCore.Mvc; + namespace KafkaFlow.Admin.WebApi.Controllers { - using KafkaFlow.Admin.WebApi.Adapters; - using KafkaFlow.Admin.WebApi.Contracts; - using Microsoft.AspNetCore.Mvc; - /// /// Telemetry controller /// @@ -11,7 +11,7 @@ namespace KafkaFlow.Admin.WebApi.Controllers [ApiController] public class TelemetryController : ControllerBase { - private readonly ITelemetryStorage storage; + private readonly ITelemetryStorage _storage; /// /// Initializes a new instance of the class. @@ -19,18 +19,18 @@ public class TelemetryController : ControllerBase /// The telemetry storage public TelemetryController(ITelemetryStorage storage) { - this.storage = storage; + _storage = storage; } /// /// Get telemetry data from all the consumer groups /// /// A telemetry response - [HttpGet(Name=nameof(GetTelemetry))] + [HttpGet(Name = nameof(GetTelemetry))] [ProducesResponseType(typeof(TelemetryResponse), 200)] public IActionResult GetTelemetry() { - var metrics = this.storage.Get(); + var metrics = _storage.Get(); return this.Ok(metrics.Adapt()); } diff --git a/src/KafkaFlow.Admin/AdminProducer.cs b/src/KafkaFlow.Admin/AdminProducer.cs index 6718240ba..da9d056d2 100644 --- a/src/KafkaFlow.Admin/AdminProducer.cs +++ b/src/KafkaFlow.Admin/AdminProducer.cs @@ -1,21 +1,21 @@ +using System; +using System.Threading.Tasks; +using KafkaFlow.Admin.Messages; + namespace KafkaFlow.Admin { - using System; - using System.Threading.Tasks; - using KafkaFlow.Admin.Messages; - internal class AdminProducer : IAdminProducer { - private readonly IMessageProducer producer; - private readonly int topicPartition; + private readonly IMessageProducer _producer; + private readonly int _topicPartition; public AdminProducer(IMessageProducer producer, int topicPartition) { - this.producer = producer; - this.topicPartition = topicPartition; + _producer = producer; + _topicPartition = topicPartition; } public Task ProduceAsync(IAdminMessage message) => - this.producer.ProduceAsync(Guid.NewGuid().ToString(), message, partition: this.topicPartition); + _producer.ProduceAsync(Guid.NewGuid().ToString(), message, partition: _topicPartition); } } diff --git a/src/KafkaFlow.Admin/ConsumerAdmin.cs b/src/KafkaFlow.Admin/ConsumerAdmin.cs index 408286e94..51af3bc81 100644 --- a/src/KafkaFlow.Admin/ConsumerAdmin.cs +++ b/src/KafkaFlow.Admin/ConsumerAdmin.cs @@ -1,24 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using KafkaFlow.Admin.Messages; + namespace KafkaFlow.Admin { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - using KafkaFlow.Admin.Messages; - internal class ConsumerAdmin : IConsumerAdmin { - private readonly IAdminProducer producer; + private readonly IAdminProducer _producer; public ConsumerAdmin(IAdminProducer producer) { - this.producer = producer; + _producer = producer; } public async Task PauseConsumerGroupAsync(string groupId, IEnumerable topics) { - await this.producer.ProduceAsync( + await _producer.ProduceAsync( new PauseConsumersByGroup { GroupId = groupId, @@ -28,7 +28,7 @@ await this.producer.ProduceAsync( public async Task ResumeConsumerGroupAsync(string groupId, IEnumerable topics) { - await this.producer.ProduceAsync( + await _producer.ProduceAsync( new ResumeConsumersByGroup { GroupId = groupId, @@ -38,7 +38,7 @@ await this.producer.ProduceAsync( public async Task PauseConsumerAsync(string consumerName, IEnumerable topics) { - await this.producer.ProduceAsync( + await _producer.ProduceAsync( new PauseConsumerByName { ConsumerName = consumerName, @@ -48,7 +48,7 @@ await this.producer.ProduceAsync( public async Task ResumeConsumerAsync(string consumerName, IEnumerable topics) { - await this.producer.ProduceAsync( + await _producer.ProduceAsync( new ResumeConsumerByName { ConsumerName = consumerName, @@ -58,22 +58,22 @@ await this.producer.ProduceAsync( public async Task StartConsumerAsync(string consumerName) { - await this.producer.ProduceAsync(new StartConsumerByName { ConsumerName = consumerName }); + await _producer.ProduceAsync(new StartConsumerByName { ConsumerName = consumerName }); } public async Task StopConsumerAsync(string consumerName) { - await this.producer.ProduceAsync(new StopConsumerByName { ConsumerName = consumerName }); + await _producer.ProduceAsync(new StopConsumerByName { ConsumerName = consumerName }); } public async Task RestartConsumerAsync(string consumerName) { - await this.producer.ProduceAsync(new RestartConsumerByName { ConsumerName = consumerName }); + await _producer.ProduceAsync(new RestartConsumerByName { ConsumerName = consumerName }); } public async Task ResetOffsetsAsync(string consumerName, IEnumerable topics) { - await this.producer.ProduceAsync( + await _producer.ProduceAsync( new ResetConsumerOffset { ConsumerName = consumerName, @@ -83,7 +83,7 @@ await this.producer.ProduceAsync( public async Task RewindOffsetsAsync(string consumerName, DateTime pointInTime, IEnumerable topics) { - await this.producer.ProduceAsync( + await _producer.ProduceAsync( new RewindConsumerOffsetToDateTime { ConsumerName = consumerName, @@ -94,7 +94,7 @@ await this.producer.ProduceAsync( public async Task ChangeWorkersCountAsync(string consumerName, int workersCount) { - await this.producer.ProduceAsync( + await _producer.ProduceAsync( new ChangeConsumerWorkersCount { ConsumerName = consumerName, diff --git a/src/KafkaFlow.Admin/Extensions/ClusterConfigurationBuilderExtensions.cs b/src/KafkaFlow.Admin/Extensions/ClusterConfigurationBuilderExtensions.cs index 608649536..ee3b51163 100644 --- a/src/KafkaFlow.Admin/Extensions/ClusterConfigurationBuilderExtensions.cs +++ b/src/KafkaFlow.Admin/Extensions/ClusterConfigurationBuilderExtensions.cs @@ -1,12 +1,12 @@ -namespace KafkaFlow -{ - using System; - using System.Reflection; - using KafkaFlow.Admin; - using KafkaFlow.Admin.Handlers; - using KafkaFlow.Configuration; - using KafkaFlow.Serializer; +using System; +using System.Reflection; +using KafkaFlow.Admin; +using KafkaFlow.Admin.Handlers; +using KafkaFlow.Configuration; +using KafkaFlow.Serializer; +namespace KafkaFlow +{ /// /// No needed /// diff --git a/src/KafkaFlow.Admin/Extensions/MessageConsumerExtensions.cs b/src/KafkaFlow.Admin/Extensions/MessageConsumerExtensions.cs index 8c7524298..8f4bdbab0 100644 --- a/src/KafkaFlow.Admin/Extensions/MessageConsumerExtensions.cs +++ b/src/KafkaFlow.Admin/Extensions/MessageConsumerExtensions.cs @@ -1,10 +1,10 @@ +using System.Collections.Generic; +using System.Linq; +using Confluent.Kafka; +using KafkaFlow.Consumers; + namespace KafkaFlow.Admin.Extensions { - using System.Collections.Generic; - using System.Linq; - using Confluent.Kafka; - using KafkaFlow.Consumers; - internal static class MessageConsumerExtensions { public static IReadOnlyList FilterAssigment(this IMessageConsumer consumer, IList topics) diff --git a/src/KafkaFlow.Admin/Handlers/ChangeConsumerWorkersCountHandler.cs b/src/KafkaFlow.Admin/Handlers/ChangeConsumerWorkersCountHandler.cs index 4dbf0f7a0..ef46f59ae 100644 --- a/src/KafkaFlow.Admin/Handlers/ChangeConsumerWorkersCountHandler.cs +++ b/src/KafkaFlow.Admin/Handlers/ChangeConsumerWorkersCountHandler.cs @@ -1,19 +1,18 @@ +using System.Threading.Tasks; +using KafkaFlow.Admin.Messages; +using KafkaFlow.Consumers; + namespace KafkaFlow.Admin.Handlers { - using System.Threading.Tasks; - using KafkaFlow.Admin.Messages; - using KafkaFlow.Consumers; - using KafkaFlow.Middlewares.TypedHandler; - internal class ChangeConsumerWorkersCountHandler : IMessageHandler { - private readonly IConsumerAccessor consumerAccessor; + private readonly IConsumerAccessor _consumerAccessor; - public ChangeConsumerWorkersCountHandler(IConsumerAccessor consumerAccessor) => this.consumerAccessor = consumerAccessor; + public ChangeConsumerWorkersCountHandler(IConsumerAccessor consumerAccessor) => _consumerAccessor = consumerAccessor; public Task Handle(IMessageContext context, ChangeConsumerWorkersCount message) { - var consumer = this.consumerAccessor[message.ConsumerName]; + var consumer = _consumerAccessor[message.ConsumerName]; return consumer?.ChangeWorkersCountAndRestartAsync(message.WorkersCount) ?? diff --git a/src/KafkaFlow.Admin/Handlers/ConsumerTelemetryMetricHandler.cs b/src/KafkaFlow.Admin/Handlers/ConsumerTelemetryMetricHandler.cs index e2b7fe36b..e57c832ec 100644 --- a/src/KafkaFlow.Admin/Handlers/ConsumerTelemetryMetricHandler.cs +++ b/src/KafkaFlow.Admin/Handlers/ConsumerTelemetryMetricHandler.cs @@ -1,18 +1,17 @@ +using System.Threading.Tasks; +using KafkaFlow.Admin.Messages; + namespace KafkaFlow.Admin.Handlers { - using System.Threading.Tasks; - using KafkaFlow.Admin.Messages; - using KafkaFlow.Middlewares.TypedHandler; - internal class ConsumerTelemetryMetricHandler : IMessageHandler { - private readonly ITelemetryStorage storage; + private readonly ITelemetryStorage _storage; - public ConsumerTelemetryMetricHandler(ITelemetryStorage storage) => this.storage = storage; + public ConsumerTelemetryMetricHandler(ITelemetryStorage storage) => _storage = storage; public Task Handle(IMessageContext context, ConsumerTelemetryMetric message) { - this.storage.Put(message); + _storage.Put(message); return Task.CompletedTask; } } diff --git a/src/KafkaFlow.Admin/Handlers/PauseConsumerByNameHandler.cs b/src/KafkaFlow.Admin/Handlers/PauseConsumerByNameHandler.cs index 9afc8efdf..b76e6da5f 100644 --- a/src/KafkaFlow.Admin/Handlers/PauseConsumerByNameHandler.cs +++ b/src/KafkaFlow.Admin/Handlers/PauseConsumerByNameHandler.cs @@ -1,21 +1,20 @@ +using System.Linq; +using System.Threading.Tasks; +using KafkaFlow.Admin.Extensions; +using KafkaFlow.Admin.Messages; +using KafkaFlow.Consumers; + namespace KafkaFlow.Admin.Handlers { - using System.Linq; - using System.Threading.Tasks; - using KafkaFlow.Admin.Extensions; - using KafkaFlow.Admin.Messages; - using KafkaFlow.Consumers; - using KafkaFlow.Middlewares.TypedHandler; - internal class PauseConsumerByNameHandler : IMessageHandler { - private readonly IConsumerAccessor consumerAccessor; + private readonly IConsumerAccessor _consumerAccessor; - public PauseConsumerByNameHandler(IConsumerAccessor consumerAccessor) => this.consumerAccessor = consumerAccessor; + public PauseConsumerByNameHandler(IConsumerAccessor consumerAccessor) => _consumerAccessor = consumerAccessor; public Task Handle(IMessageContext context, PauseConsumerByName message) { - var consumer = this.consumerAccessor[message.ConsumerName]; + var consumer = _consumerAccessor[message.ConsumerName]; var assignment = consumer.FilterAssigment(message.Topics); diff --git a/src/KafkaFlow.Admin/Handlers/PauseConsumersByGroupHandler.cs b/src/KafkaFlow.Admin/Handlers/PauseConsumersByGroupHandler.cs index 376393842..cf92366b9 100644 --- a/src/KafkaFlow.Admin/Handlers/PauseConsumersByGroupHandler.cs +++ b/src/KafkaFlow.Admin/Handlers/PauseConsumersByGroupHandler.cs @@ -1,21 +1,20 @@ +using System.Linq; +using System.Threading.Tasks; +using KafkaFlow.Admin.Extensions; +using KafkaFlow.Admin.Messages; +using KafkaFlow.Consumers; + namespace KafkaFlow.Admin.Handlers { - using System.Linq; - using System.Threading.Tasks; - using KafkaFlow.Admin.Extensions; - using KafkaFlow.Admin.Messages; - using KafkaFlow.Consumers; - using KafkaFlow.Middlewares.TypedHandler; - internal class PauseConsumersByGroupHandler : IMessageHandler { - private readonly IConsumerAccessor consumerAccessor; + private readonly IConsumerAccessor _consumerAccessor; - public PauseConsumersByGroupHandler(IConsumerAccessor consumerAccessor) => this.consumerAccessor = consumerAccessor; + public PauseConsumersByGroupHandler(IConsumerAccessor consumerAccessor) => _consumerAccessor = consumerAccessor; public Task Handle(IMessageContext context, PauseConsumersByGroup message) { - var consumers = this.consumerAccessor.All.Where(x => x.GroupId == message.GroupId); + var consumers = _consumerAccessor.All.Where(x => x.GroupId == message.GroupId); foreach (var consumer in consumers) { diff --git a/src/KafkaFlow.Admin/Handlers/ResetConsumerOffsetHandler.cs b/src/KafkaFlow.Admin/Handlers/ResetConsumerOffsetHandler.cs index 2d9c60008..1735e5c10 100644 --- a/src/KafkaFlow.Admin/Handlers/ResetConsumerOffsetHandler.cs +++ b/src/KafkaFlow.Admin/Handlers/ResetConsumerOffsetHandler.cs @@ -1,23 +1,22 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Confluent.Kafka; +using KafkaFlow.Admin.Extensions; +using KafkaFlow.Admin.Messages; +using KafkaFlow.Consumers; + namespace KafkaFlow.Admin.Handlers { - using System; - using System.Linq; - using System.Threading.Tasks; - using Confluent.Kafka; - using KafkaFlow.Admin.Extensions; - using KafkaFlow.Admin.Messages; - using KafkaFlow.Consumers; - using KafkaFlow.Middlewares.TypedHandler; - internal class ResetConsumerOffsetHandler : IMessageHandler { - private readonly IConsumerAccessor consumerAccessor; + private readonly IConsumerAccessor _consumerAccessor; - public ResetConsumerOffsetHandler(IConsumerAccessor consumerAccessor) => this.consumerAccessor = consumerAccessor; + public ResetConsumerOffsetHandler(IConsumerAccessor consumerAccessor) => _consumerAccessor = consumerAccessor; public Task Handle(IMessageContext context, ResetConsumerOffset message) { - var consumer = this.consumerAccessor[message.ConsumerName]; + var consumer = _consumerAccessor[message.ConsumerName]; if (consumer is null) { diff --git a/src/KafkaFlow.Admin/Handlers/RestartConsumerByNameHandler.cs b/src/KafkaFlow.Admin/Handlers/RestartConsumerByNameHandler.cs index 3525bf490..50759b6eb 100644 --- a/src/KafkaFlow.Admin/Handlers/RestartConsumerByNameHandler.cs +++ b/src/KafkaFlow.Admin/Handlers/RestartConsumerByNameHandler.cs @@ -1,19 +1,18 @@ +using System.Threading.Tasks; +using KafkaFlow.Admin.Messages; +using KafkaFlow.Consumers; + namespace KafkaFlow.Admin.Handlers { - using System.Threading.Tasks; - using KafkaFlow.Admin.Messages; - using KafkaFlow.Consumers; - using KafkaFlow.Middlewares.TypedHandler; - internal class RestartConsumerByNameHandler : IMessageHandler { - private readonly IConsumerAccessor consumerAccessor; + private readonly IConsumerAccessor _consumerAccessor; - public RestartConsumerByNameHandler(IConsumerAccessor consumerAccessor) => this.consumerAccessor = consumerAccessor; + public RestartConsumerByNameHandler(IConsumerAccessor consumerAccessor) => _consumerAccessor = consumerAccessor; public Task Handle(IMessageContext context, RestartConsumerByName message) { - var consumer = this.consumerAccessor[message.ConsumerName]; + var consumer = _consumerAccessor[message.ConsumerName]; return consumer?.RestartAsync() ?? Task.CompletedTask; } diff --git a/src/KafkaFlow.Admin/Handlers/ResumeConsumerByNameHandler.cs b/src/KafkaFlow.Admin/Handlers/ResumeConsumerByNameHandler.cs index e8eb336ff..730f5e711 100644 --- a/src/KafkaFlow.Admin/Handlers/ResumeConsumerByNameHandler.cs +++ b/src/KafkaFlow.Admin/Handlers/ResumeConsumerByNameHandler.cs @@ -1,21 +1,20 @@ +using System.Linq; +using System.Threading.Tasks; +using KafkaFlow.Admin.Extensions; +using KafkaFlow.Admin.Messages; +using KafkaFlow.Consumers; + namespace KafkaFlow.Admin.Handlers { - using System.Linq; - using System.Threading.Tasks; - using KafkaFlow.Admin.Extensions; - using KafkaFlow.Admin.Messages; - using KafkaFlow.Consumers; - using KafkaFlow.Middlewares.TypedHandler; - internal class ResumeConsumerByNameHandler : IMessageHandler { - private readonly IConsumerAccessor consumerAccessor; + private readonly IConsumerAccessor _consumerAccessor; - public ResumeConsumerByNameHandler(IConsumerAccessor consumerAccessor) => this.consumerAccessor = consumerAccessor; + public ResumeConsumerByNameHandler(IConsumerAccessor consumerAccessor) => _consumerAccessor = consumerAccessor; public Task Handle(IMessageContext context, ResumeConsumerByName message) { - var consumer = this.consumerAccessor[message.ConsumerName]; + var consumer = _consumerAccessor[message.ConsumerName]; var assignment = consumer.FilterAssigment(message.Topics); diff --git a/src/KafkaFlow.Admin/Handlers/ResumeConsumersByGroupHandler.cs b/src/KafkaFlow.Admin/Handlers/ResumeConsumersByGroupHandler.cs index 553d2ca23..2f82c181d 100644 --- a/src/KafkaFlow.Admin/Handlers/ResumeConsumersByGroupHandler.cs +++ b/src/KafkaFlow.Admin/Handlers/ResumeConsumersByGroupHandler.cs @@ -1,21 +1,20 @@ +using System.Linq; +using System.Threading.Tasks; +using KafkaFlow.Admin.Extensions; +using KafkaFlow.Admin.Messages; +using KafkaFlow.Consumers; + namespace KafkaFlow.Admin.Handlers { - using System.Linq; - using System.Threading.Tasks; - using KafkaFlow.Admin.Extensions; - using KafkaFlow.Admin.Messages; - using KafkaFlow.Consumers; - using KafkaFlow.Middlewares.TypedHandler; - internal class ResumeConsumersByGroupHandler : IMessageHandler { - private readonly IConsumerAccessor consumerAccessor; + private readonly IConsumerAccessor _consumerAccessor; - public ResumeConsumersByGroupHandler(IConsumerAccessor consumerAccessor) => this.consumerAccessor = consumerAccessor; + public ResumeConsumersByGroupHandler(IConsumerAccessor consumerAccessor) => _consumerAccessor = consumerAccessor; public Task Handle(IMessageContext context, ResumeConsumersByGroup message) { - var consumers = this.consumerAccessor.All.Where(x => x.GroupId == message.GroupId); + var consumers = _consumerAccessor.All.Where(x => x.GroupId == message.GroupId); foreach (var consumer in consumers) { diff --git a/src/KafkaFlow.Admin/Handlers/RewindConsumerOffsetToDateTimeHandler.cs b/src/KafkaFlow.Admin/Handlers/RewindConsumerOffsetToDateTimeHandler.cs index b5895ef56..8ade85e63 100644 --- a/src/KafkaFlow.Admin/Handlers/RewindConsumerOffsetToDateTimeHandler.cs +++ b/src/KafkaFlow.Admin/Handlers/RewindConsumerOffsetToDateTimeHandler.cs @@ -1,23 +1,22 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Confluent.Kafka; +using KafkaFlow.Admin.Extensions; +using KafkaFlow.Admin.Messages; +using KafkaFlow.Consumers; + namespace KafkaFlow.Admin.Handlers { - using System; - using System.Linq; - using System.Threading.Tasks; - using Confluent.Kafka; - using KafkaFlow.Admin.Extensions; - using KafkaFlow.Admin.Messages; - using KafkaFlow.Consumers; - using KafkaFlow.Middlewares.TypedHandler; - internal class RewindConsumerOffsetToDateTimeHandler : IMessageHandler { - private readonly IConsumerAccessor consumerAccessor; + private readonly IConsumerAccessor _consumerAccessor; - public RewindConsumerOffsetToDateTimeHandler(IConsumerAccessor consumerAccessor) => this.consumerAccessor = consumerAccessor; + public RewindConsumerOffsetToDateTimeHandler(IConsumerAccessor consumerAccessor) => _consumerAccessor = consumerAccessor; public Task Handle(IMessageContext context, RewindConsumerOffsetToDateTime message) { - var consumer = this.consumerAccessor[message.ConsumerName]; + var consumer = _consumerAccessor[message.ConsumerName]; if (consumer is null) { diff --git a/src/KafkaFlow.Admin/Handlers/StartConsumerByNameHandler.cs b/src/KafkaFlow.Admin/Handlers/StartConsumerByNameHandler.cs index b7ad5fa08..12ab3185b 100644 --- a/src/KafkaFlow.Admin/Handlers/StartConsumerByNameHandler.cs +++ b/src/KafkaFlow.Admin/Handlers/StartConsumerByNameHandler.cs @@ -1,19 +1,18 @@ +using System.Threading.Tasks; +using KafkaFlow.Admin.Messages; +using KafkaFlow.Consumers; + namespace KafkaFlow.Admin.Handlers { - using System.Threading.Tasks; - using KafkaFlow.Admin.Messages; - using KafkaFlow.Consumers; - using KafkaFlow.Middlewares.TypedHandler; - internal class StartConsumerByNameHandler : IMessageHandler { - private readonly IConsumerAccessor consumerAccessor; + private readonly IConsumerAccessor _consumerAccessor; - public StartConsumerByNameHandler(IConsumerAccessor consumerAccessor) => this.consumerAccessor = consumerAccessor; + public StartConsumerByNameHandler(IConsumerAccessor consumerAccessor) => _consumerAccessor = consumerAccessor; public async Task Handle(IMessageContext context, StartConsumerByName message) { - var consumer = this.consumerAccessor[message.ConsumerName]; + var consumer = _consumerAccessor[message.ConsumerName]; await consumer.StartAsync(); } diff --git a/src/KafkaFlow.Admin/Handlers/StopConsumerByNameHandler.cs b/src/KafkaFlow.Admin/Handlers/StopConsumerByNameHandler.cs index 92a9fc0a0..fd83135ae 100644 --- a/src/KafkaFlow.Admin/Handlers/StopConsumerByNameHandler.cs +++ b/src/KafkaFlow.Admin/Handlers/StopConsumerByNameHandler.cs @@ -1,19 +1,18 @@ +using System.Threading.Tasks; +using KafkaFlow.Admin.Messages; +using KafkaFlow.Consumers; + namespace KafkaFlow.Admin.Handlers { - using System.Threading.Tasks; - using KafkaFlow.Admin.Messages; - using KafkaFlow.Consumers; - using KafkaFlow.Middlewares.TypedHandler; - internal class StopConsumerByNameHandler : IMessageHandler { - private readonly IConsumerAccessor consumerAccessor; + private readonly IConsumerAccessor _consumerAccessor; - public StopConsumerByNameHandler(IConsumerAccessor consumerAccessor) => this.consumerAccessor = consumerAccessor; + public StopConsumerByNameHandler(IConsumerAccessor consumerAccessor) => _consumerAccessor = consumerAccessor; public async Task Handle(IMessageContext context, StopConsumerByName message) { - var consumer = this.consumerAccessor[message.ConsumerName]; + var consumer = _consumerAccessor[message.ConsumerName]; await consumer.StopAsync(); } diff --git a/src/KafkaFlow.Admin/IAdminProducer.cs b/src/KafkaFlow.Admin/IAdminProducer.cs index 6149e01af..7a7ec4910 100644 --- a/src/KafkaFlow.Admin/IAdminProducer.cs +++ b/src/KafkaFlow.Admin/IAdminProducer.cs @@ -1,8 +1,8 @@ +using System.Threading.Tasks; +using KafkaFlow.Admin.Messages; + namespace KafkaFlow.Admin { - using System.Threading.Tasks; - using KafkaFlow.Admin.Messages; - /// /// A special producer to publish admin messages /// diff --git a/src/KafkaFlow.Admin/IConsumerAdmin.cs b/src/KafkaFlow.Admin/IConsumerAdmin.cs index 624b4fb95..90d3a4a3a 100644 --- a/src/KafkaFlow.Admin/IConsumerAdmin.cs +++ b/src/KafkaFlow.Admin/IConsumerAdmin.cs @@ -1,9 +1,9 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + namespace KafkaFlow.Admin { - using System; - using System.Collections.Generic; - using System.Threading.Tasks; - /// /// Expose Consumer administration features /// diff --git a/src/KafkaFlow.Admin/ITelemetryStorage.cs b/src/KafkaFlow.Admin/ITelemetryStorage.cs index e9c81043b..02494b589 100644 --- a/src/KafkaFlow.Admin/ITelemetryStorage.cs +++ b/src/KafkaFlow.Admin/ITelemetryStorage.cs @@ -1,8 +1,8 @@ +using System.Collections.Generic; +using KafkaFlow.Admin.Messages; + namespace KafkaFlow.Admin { - using System.Collections.Generic; - using KafkaFlow.Admin.Messages; - /// /// Used to implement a telemetry data storage provider /// diff --git a/src/KafkaFlow.Admin/MemoryTelemetryStorage.cs b/src/KafkaFlow.Admin/MemoryTelemetryStorage.cs index 081856304..92cef9b91 100644 --- a/src/KafkaFlow.Admin/MemoryTelemetryStorage.cs +++ b/src/KafkaFlow.Admin/MemoryTelemetryStorage.cs @@ -1,37 +1,37 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using KafkaFlow.Admin.Messages; + namespace KafkaFlow.Admin { - using System; - using System.Collections.Concurrent; - using System.Collections.Generic; - using System.Linq; - using System.Runtime.CompilerServices; - using KafkaFlow.Admin.Messages; - internal class MemoryTelemetryStorage : ITelemetryStorage { - private readonly IDateTimeProvider dateTimeProvider; - private readonly TimeSpan cleanRunInterval; - private readonly TimeSpan expiryTime; - private readonly object cleanSyncRoot = new(); + private readonly IDateTimeProvider _dateTimeProvider; + private readonly TimeSpan _cleanRunInterval; + private readonly TimeSpan _expiryTime; + private readonly object _cleanSyncRoot = new(); - private readonly ConcurrentDictionary<(string, string, string, string), ConsumerTelemetryMetric> metrics = new(); + private readonly ConcurrentDictionary<(string, string, string, string), ConsumerTelemetryMetric> _metrics = new(); - private DateTime lastCleanDate; + private DateTime _lastCleanDate; public MemoryTelemetryStorage(TimeSpan cleanRunInterval, TimeSpan expiryTime, IDateTimeProvider dateTimeProvider) { - this.cleanRunInterval = cleanRunInterval; - this.expiryTime = expiryTime; - this.dateTimeProvider = dateTimeProvider; - this.lastCleanDate = dateTimeProvider.MinValue; + _cleanRunInterval = cleanRunInterval; + _expiryTime = expiryTime; + _dateTimeProvider = dateTimeProvider; + _lastCleanDate = dateTimeProvider.MinValue; } - public IEnumerable Get() => this.metrics.Values; + public IEnumerable Get() => _metrics.Values; public void Put(ConsumerTelemetryMetric telemetryMetric) { this.TryCleanItems(); - this.metrics[BuildKey(telemetryMetric)] = telemetryMetric; + _metrics[BuildKey(telemetryMetric)] = telemetryMetric; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -45,14 +45,14 @@ private void TryCleanItems() return; } - lock (this.cleanSyncRoot) + lock (_cleanSyncRoot) { if (!this.NeedsCleaning()) { return; } - this.lastCleanDate = this.dateTimeProvider.UtcNow; + _lastCleanDate = _dateTimeProvider.UtcNow; this.CleanExpiredItems(); } @@ -60,16 +60,16 @@ private void TryCleanItems() private void CleanExpiredItems() { - foreach (var (key, metric) in this.metrics.Select(x=> (x.Key, x.Value))) + foreach (var (key, metric) in _metrics.Select(x => (x.Key, x.Value))) { - if (this.dateTimeProvider.UtcNow - metric.SentAt > this.expiryTime) + if (_dateTimeProvider.UtcNow - metric.SentAt > _expiryTime) { - this.metrics.TryRemove(key, out _); + _metrics.TryRemove(key, out _); } } } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private bool NeedsCleaning() => this.dateTimeProvider.UtcNow - this.lastCleanDate > this.cleanRunInterval; + private bool NeedsCleaning() => _dateTimeProvider.UtcNow - _lastCleanDate > _cleanRunInterval; } } diff --git a/src/KafkaFlow.Admin/Messages/ChangeConsumerWorkersCount.cs b/src/KafkaFlow.Admin/Messages/ChangeConsumerWorkersCount.cs index daccb7d61..21a95c2a9 100644 --- a/src/KafkaFlow.Admin/Messages/ChangeConsumerWorkersCount.cs +++ b/src/KafkaFlow.Admin/Messages/ChangeConsumerWorkersCount.cs @@ -1,7 +1,7 @@ +using System.Runtime.Serialization; + namespace KafkaFlow.Admin.Messages { - using System.Runtime.Serialization; - /// /// A message to change the worker count /// diff --git a/src/KafkaFlow.Admin/Messages/ConsumerTelemetryMetric.cs b/src/KafkaFlow.Admin/Messages/ConsumerTelemetryMetric.cs index 38d5f1605..adfd01965 100644 --- a/src/KafkaFlow.Admin/Messages/ConsumerTelemetryMetric.cs +++ b/src/KafkaFlow.Admin/Messages/ConsumerTelemetryMetric.cs @@ -1,10 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using KafkaFlow.Consumers; + namespace KafkaFlow.Admin.Messages { - using System; - using System.Collections.Generic; - using System.Runtime.Serialization; - using KafkaFlow.Consumers; - /// /// A message that contains data related to consumers partition assigment /// diff --git a/src/KafkaFlow.Admin/Messages/PauseConsumerByName.cs b/src/KafkaFlow.Admin/Messages/PauseConsumerByName.cs index 14ea13ea6..3a3b32748 100644 --- a/src/KafkaFlow.Admin/Messages/PauseConsumerByName.cs +++ b/src/KafkaFlow.Admin/Messages/PauseConsumerByName.cs @@ -1,8 +1,8 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; + namespace KafkaFlow.Admin.Messages { - using System.Collections.Generic; - using System.Runtime.Serialization; - /// /// A message that pauses a consumer /// diff --git a/src/KafkaFlow.Admin/Messages/PauseConsumersByGroup.cs b/src/KafkaFlow.Admin/Messages/PauseConsumersByGroup.cs index 982e34c12..a484d15dd 100644 --- a/src/KafkaFlow.Admin/Messages/PauseConsumersByGroup.cs +++ b/src/KafkaFlow.Admin/Messages/PauseConsumersByGroup.cs @@ -1,8 +1,8 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; + namespace KafkaFlow.Admin.Messages { - using System.Collections.Generic; - using System.Runtime.Serialization; - /// /// The message that pauses an entire consumer group /// diff --git a/src/KafkaFlow.Admin/Messages/ResetConsumerOffset.cs b/src/KafkaFlow.Admin/Messages/ResetConsumerOffset.cs index c46e1edf1..e0116a982 100644 --- a/src/KafkaFlow.Admin/Messages/ResetConsumerOffset.cs +++ b/src/KafkaFlow.Admin/Messages/ResetConsumerOffset.cs @@ -1,8 +1,8 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; + namespace KafkaFlow.Admin.Messages { - using System.Collections.Generic; - using System.Runtime.Serialization; - /// /// The message that rewind the offset of all partitions/topics of a consumer to the beginning /// diff --git a/src/KafkaFlow.Admin/Messages/RestartConsumerByName.cs b/src/KafkaFlow.Admin/Messages/RestartConsumerByName.cs index 777c4cbec..cfefa0cea 100644 --- a/src/KafkaFlow.Admin/Messages/RestartConsumerByName.cs +++ b/src/KafkaFlow.Admin/Messages/RestartConsumerByName.cs @@ -1,7 +1,7 @@ +using System.Runtime.Serialization; + namespace KafkaFlow.Admin.Messages { - using System.Runtime.Serialization; - /// /// The message that destroy and recreates the internal consumer /// diff --git a/src/KafkaFlow.Admin/Messages/ResumeConsumerByName.cs b/src/KafkaFlow.Admin/Messages/ResumeConsumerByName.cs index 220a34e59..da723ea5e 100644 --- a/src/KafkaFlow.Admin/Messages/ResumeConsumerByName.cs +++ b/src/KafkaFlow.Admin/Messages/ResumeConsumerByName.cs @@ -1,8 +1,8 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; + namespace KafkaFlow.Admin.Messages { - using System.Collections.Generic; - using System.Runtime.Serialization; - /// /// The message that resume a paused consumer /// diff --git a/src/KafkaFlow.Admin/Messages/ResumeConsumersByGroup.cs b/src/KafkaFlow.Admin/Messages/ResumeConsumersByGroup.cs index c11467f7f..71f9b5f00 100644 --- a/src/KafkaFlow.Admin/Messages/ResumeConsumersByGroup.cs +++ b/src/KafkaFlow.Admin/Messages/ResumeConsumersByGroup.cs @@ -1,8 +1,8 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; + namespace KafkaFlow.Admin.Messages { - using System.Collections.Generic; - using System.Runtime.Serialization; - /// /// The message that resume a paused consumer group /// diff --git a/src/KafkaFlow.Admin/Messages/RewindConsumerOffsetToDateTime.cs b/src/KafkaFlow.Admin/Messages/RewindConsumerOffsetToDateTime.cs index d675ea05b..cb0417d4e 100644 --- a/src/KafkaFlow.Admin/Messages/RewindConsumerOffsetToDateTime.cs +++ b/src/KafkaFlow.Admin/Messages/RewindConsumerOffsetToDateTime.cs @@ -1,9 +1,9 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; + namespace KafkaFlow.Admin.Messages { - using System; - using System.Collections.Generic; - using System.Runtime.Serialization; - /// /// The message that rewind a consumer to a point in time /// diff --git a/src/KafkaFlow.Admin/Messages/StartConsumerByName.cs b/src/KafkaFlow.Admin/Messages/StartConsumerByName.cs index af7c519ee..d8ebf3640 100644 --- a/src/KafkaFlow.Admin/Messages/StartConsumerByName.cs +++ b/src/KafkaFlow.Admin/Messages/StartConsumerByName.cs @@ -1,7 +1,7 @@ +using System.Runtime.Serialization; + namespace KafkaFlow.Admin.Messages { - using System.Runtime.Serialization; - /// /// The message that starts a consumer /// diff --git a/src/KafkaFlow.Admin/Messages/StopConsumerByName.cs b/src/KafkaFlow.Admin/Messages/StopConsumerByName.cs index 68fbe1ce0..aea85c140 100644 --- a/src/KafkaFlow.Admin/Messages/StopConsumerByName.cs +++ b/src/KafkaFlow.Admin/Messages/StopConsumerByName.cs @@ -1,7 +1,7 @@ +using System.Runtime.Serialization; + namespace KafkaFlow.Admin.Messages { - using System.Runtime.Serialization; - /// /// The message that stops a consumer /// diff --git a/src/KafkaFlow.Admin/TelemetryScheduler.cs b/src/KafkaFlow.Admin/TelemetryScheduler.cs index b3aaaec69..c59ec2c7c 100644 --- a/src/KafkaFlow.Admin/TelemetryScheduler.cs +++ b/src/KafkaFlow.Admin/TelemetryScheduler.cs @@ -1,45 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using KafkaFlow.Admin.Messages; +using KafkaFlow.Consumers; +using KafkaFlow.Producers; + namespace KafkaFlow.Admin { - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.Linq; - using System.Threading; - using KafkaFlow.Admin.Messages; - using KafkaFlow.Consumers; - using KafkaFlow.Producers; - internal class TelemetryScheduler : ITelemetryScheduler { - private static readonly int ProcessId = Process.GetCurrentProcess().Id; - private readonly Dictionary timers = new(); - private readonly IDependencyResolver dependencyResolver; - private readonly ILogHandler logHandler; + private static readonly int s_processId = Process.GetCurrentProcess().Id; + private readonly Dictionary _timers = new(); + private readonly IDependencyResolver _dependencyResolver; + private readonly ILogHandler _logHandler; public TelemetryScheduler(IDependencyResolver dependencyResolver) { - this.dependencyResolver = dependencyResolver; - this.logHandler = dependencyResolver.Resolve(); + _dependencyResolver = dependencyResolver; + _logHandler = dependencyResolver.Resolve(); } public void Start(string telemetryId, string topicName, int topicPartition) { this.Stop(telemetryId); - var consumers = this.dependencyResolver + var consumers = _dependencyResolver .Resolve() .All .Where( c => !c.ManagementDisabled && c.ClusterName.Equals( - this.dependencyResolver + _dependencyResolver .Resolve()[telemetryId] .ClusterName)) .ToList(); - var producer = this.dependencyResolver.Resolve().GetProducer(telemetryId); + var producer = _dependencyResolver.Resolve().GetProducer(telemetryId); - this.timers[telemetryId] = new Timer( + _timers[telemetryId] = new Timer( _ => ProduceTelemetry(topicName, topicPartition, consumers, producer), null, TimeSpan.Zero, @@ -48,10 +48,10 @@ public void Start(string telemetryId, string topicName, int topicPartition) public void Stop(string telemetryId) { - if (this.timers.TryGetValue(telemetryId, out var timer)) + if (_timers.TryGetValue(telemetryId, out var timer)) { timer.Dispose(); - this.timers.Remove(telemetryId); + _timers.Remove(telemetryId); } } @@ -75,7 +75,7 @@ private void ProduceTelemetry( ConsumerName = c.ConsumerName, Topic = topic, GroupId = c.GroupId, - InstanceName = $"{Environment.MachineName}-{ProcessId}", + InstanceName = $"{Environment.MachineName}-{s_processId}", PausedPartitions = c.PausedPartitions .Where(p => p.Topic == topic) .Select(p => p.Partition.Value), @@ -96,7 +96,7 @@ private void ProduceTelemetry( } catch (Exception e) { - this.logHandler.Warning("Error producing telemetry data", new { Exception = e }); + _logHandler.Warning("Error producing telemetry data", new { Exception = e }); } } } diff --git a/src/KafkaFlow.Compressor.Gzip/GzipMessageCompressor.cs b/src/KafkaFlow.Compressor.Gzip/GzipMessageCompressor.cs index 3f795c6af..3e430d094 100644 --- a/src/KafkaFlow.Compressor.Gzip/GzipMessageCompressor.cs +++ b/src/KafkaFlow.Compressor.Gzip/GzipMessageCompressor.cs @@ -1,8 +1,8 @@ -namespace KafkaFlow.Compressor.Gzip -{ - using System.IO; - using System.IO.Compression; +using System.IO; +using System.IO.Compression; +namespace KafkaFlow.Compressor.Gzip +{ /// /// A GZIP message compressor /// diff --git a/src/KafkaFlow.Compressor.Gzip/GzipMessageDecompressor.cs b/src/KafkaFlow.Compressor.Gzip/GzipMessageDecompressor.cs index 19baffaf0..0d04f998c 100644 --- a/src/KafkaFlow.Compressor.Gzip/GzipMessageDecompressor.cs +++ b/src/KafkaFlow.Compressor.Gzip/GzipMessageDecompressor.cs @@ -1,8 +1,8 @@ -namespace KafkaFlow.Compressor.Gzip -{ - using System.IO; - using System.IO.Compression; +using System.IO; +using System.IO.Compression; +namespace KafkaFlow.Compressor.Gzip +{ /// /// A GZIP message decompressor /// diff --git a/src/KafkaFlow.Extensions.Hosting/KafkaFlowHostedService.cs b/src/KafkaFlow.Extensions.Hosting/KafkaFlowHostedService.cs index 7a08e6b68..ac265ee8e 100644 --- a/src/KafkaFlow.Extensions.Hosting/KafkaFlowHostedService.cs +++ b/src/KafkaFlow.Extensions.Hosting/KafkaFlowHostedService.cs @@ -1,18 +1,18 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using global::Microsoft.Extensions.Hosting; + namespace KafkaFlow { - using System; - using System.Threading; - using System.Threading.Tasks; - using global::Microsoft.Extensions.Hosting; - internal class KafkaFlowHostedService : IHostedService { - private readonly IKafkaBus kafkaBus; + private readonly IKafkaBus _kafkaBus; - public KafkaFlowHostedService(IServiceProvider serviceProvider) => this.kafkaBus = serviceProvider.CreateKafkaBus(); + public KafkaFlowHostedService(IServiceProvider serviceProvider) => _kafkaBus = serviceProvider.CreateKafkaBus(); - public Task StartAsync(CancellationToken cancellationToken) => this.kafkaBus.StartAsync(cancellationToken); + public Task StartAsync(CancellationToken cancellationToken) => _kafkaBus.StartAsync(cancellationToken); - public Task StopAsync(CancellationToken cancellationToken) => this.kafkaBus.StopAsync(); + public Task StopAsync(CancellationToken cancellationToken) => _kafkaBus.StopAsync(); } } diff --git a/src/KafkaFlow.Extensions.Hosting/ServiceCollectionExtensions.cs b/src/KafkaFlow.Extensions.Hosting/ServiceCollectionExtensions.cs index 89c81754b..fab8199e1 100644 --- a/src/KafkaFlow.Extensions.Hosting/ServiceCollectionExtensions.cs +++ b/src/KafkaFlow.Extensions.Hosting/ServiceCollectionExtensions.cs @@ -1,9 +1,9 @@ -namespace KafkaFlow -{ - using System; - using global::Microsoft.Extensions.DependencyInjection; - using KafkaFlow.Configuration; +using System; +using global::Microsoft.Extensions.DependencyInjection; +using KafkaFlow.Configuration; +namespace KafkaFlow +{ /// /// No needed /// diff --git a/src/KafkaFlow.IntegrationTests/CompressionTest.cs b/src/KafkaFlow.IntegrationTests/CompressionTest.cs deleted file mode 100644 index 86b45d4a1..000000000 --- a/src/KafkaFlow.IntegrationTests/CompressionTest.cs +++ /dev/null @@ -1,44 +0,0 @@ -namespace KafkaFlow.IntegrationTests -{ - using System; - using System.Linq; - using System.Threading.Tasks; - using AutoFixture; - using global::Microsoft.Extensions.DependencyInjection; - using global::Microsoft.VisualStudio.TestTools.UnitTesting; - using KafkaFlow.IntegrationTests.Core; - using KafkaFlow.IntegrationTests.Core.Handlers; - using KafkaFlow.IntegrationTests.Core.Producers; - - [TestClass] - public class CompressionTest - { - private readonly Fixture fixture = new(); - - private IServiceProvider provider; - - [TestInitialize] - public void Setup() - { - this.provider = Bootstrapper.GetServiceProvider(); - MessageStorage.Clear(); - } - - [TestMethod] - public async Task GzipTest() - { - // Arrange - var producer = this.provider.GetRequiredService>(); - var messages = this.fixture.CreateMany(10).ToList(); - - // Act - await Task.WhenAll(messages.Select(m => producer.ProduceAsync(Guid.NewGuid().ToString(), m))); - - // Assert - foreach (var message in messages) - { - await MessageStorage.AssertMessageAsync(message); - } - } - } -} diff --git a/src/KafkaFlow.IntegrationTests/ProducerTest.cs b/src/KafkaFlow.IntegrationTests/ProducerTest.cs deleted file mode 100644 index 00f4e58db..000000000 --- a/src/KafkaFlow.IntegrationTests/ProducerTest.cs +++ /dev/null @@ -1,40 +0,0 @@ -namespace KafkaFlow.IntegrationTests -{ - using System; - using System.Threading.Tasks; - using AutoFixture; - using KafkaFlow.IntegrationTests.Core; - using KafkaFlow.IntegrationTests.Core.Handlers; - using KafkaFlow.IntegrationTests.Core.Producers; - using Microsoft.Extensions.DependencyInjection; - using Microsoft.VisualStudio.TestTools.UnitTesting; - - [TestClass] - public class ProducerTest - { - private readonly Fixture fixture = new(); - - private IServiceProvider provider; - - [TestInitialize] - public void Setup() - { - this.provider = Bootstrapper.GetServiceProvider(); - MessageStorage.Clear(); - } - - [TestMethod] - public async Task ProduceNullKeyTest() - { - // Arrange - var producer = this.provider.GetRequiredService>(); - var message = this.fixture.Create(); - - // Act - await producer.ProduceAsync(null, message); - - // Assert - await MessageStorage.AssertMessageAsync(message); - } - } -} diff --git a/src/KafkaFlow.LogHandler.Console/ConsoleLogHandler.cs b/src/KafkaFlow.LogHandler.Console/ConsoleLogHandler.cs index a22ec1660..7f85f2b5a 100644 --- a/src/KafkaFlow.LogHandler.Console/ConsoleLogHandler.cs +++ b/src/KafkaFlow.LogHandler.Console/ConsoleLogHandler.cs @@ -1,8 +1,8 @@ -namespace KafkaFlow -{ - using System; - using System.Text.Json; +using System; +using System.Text.Json; +namespace KafkaFlow +{ internal class ConsoleLogHandler : ILogHandler { public void Error(string message, Exception ex, object data) diff --git a/src/KafkaFlow.LogHandler.Console/ExtensionMethods.cs b/src/KafkaFlow.LogHandler.Console/ExtensionMethods.cs index 1b6b36b00..435144b9d 100644 --- a/src/KafkaFlow.LogHandler.Console/ExtensionMethods.cs +++ b/src/KafkaFlow.LogHandler.Console/ExtensionMethods.cs @@ -1,7 +1,7 @@ +using KafkaFlow.Configuration; + namespace KafkaFlow { - using KafkaFlow.Configuration; - /// /// No needed /// diff --git a/src/KafkaFlow.LogHandler.Microsoft/ExtensionMethods.cs b/src/KafkaFlow.LogHandler.Microsoft/ExtensionMethods.cs index 6a0814444..762fda7ad 100644 --- a/src/KafkaFlow.LogHandler.Microsoft/ExtensionMethods.cs +++ b/src/KafkaFlow.LogHandler.Microsoft/ExtensionMethods.cs @@ -1,7 +1,7 @@ +using KafkaFlow.Configuration; + namespace KafkaFlow { - using KafkaFlow.Configuration; - /// /// No needed /// diff --git a/src/KafkaFlow.LogHandler.Microsoft/MicrosoftLogHandler.cs b/src/KafkaFlow.LogHandler.Microsoft/MicrosoftLogHandler.cs index aa399d2ce..e2468608e 100644 --- a/src/KafkaFlow.LogHandler.Microsoft/MicrosoftLogHandler.cs +++ b/src/KafkaFlow.LogHandler.Microsoft/MicrosoftLogHandler.cs @@ -1,36 +1,36 @@ -namespace KafkaFlow -{ - using System; - using System.Text.Json; - using Microsoft.Extensions.Logging; +using System; +using System.Text.Json; +using Microsoft.Extensions.Logging; +namespace KafkaFlow +{ internal class MicrosoftLogHandler : ILogHandler { - private readonly ILogger logger; + private readonly ILogger _logger; public MicrosoftLogHandler(ILoggerFactory loggerFactory) { - this.logger = loggerFactory.CreateLogger("KafkaFlow"); + _logger = loggerFactory.CreateLogger("KafkaFlow"); } public void Error(string message, Exception ex, object data) { - this.logger.LogError(ex, "{Message} | Data: {Data}", message, JsonSerializer.Serialize(data)); + _logger.LogError(ex, "{Message} | Data: {Data}", message, JsonSerializer.Serialize(data)); } public void Warning(string message, object data) { - this.logger.LogWarning("{Message} | Data: {Data}", message, JsonSerializer.Serialize(data)); + _logger.LogWarning("{Message} | Data: {Data}", message, JsonSerializer.Serialize(data)); } public void Info(string message, object data) { - this.logger.LogInformation("{Message} | Data: {Data}", message, JsonSerializer.Serialize(data)); + _logger.LogInformation("{Message} | Data: {Data}", message, JsonSerializer.Serialize(data)); } public void Verbose(string message, object data) { - this.logger.LogDebug("{Message} | Data: {Data}", message, JsonSerializer.Serialize(data)); + _logger.LogDebug("{Message} | Data: {Data}", message, JsonSerializer.Serialize(data)); } } } diff --git a/src/KafkaFlow.Microsoft.DependencyInjection/MicrosoftDependencyConfigurator.cs b/src/KafkaFlow.Microsoft.DependencyInjection/MicrosoftDependencyConfigurator.cs index 7d0b993d3..d7cec29e3 100644 --- a/src/KafkaFlow.Microsoft.DependencyInjection/MicrosoftDependencyConfigurator.cs +++ b/src/KafkaFlow.Microsoft.DependencyInjection/MicrosoftDependencyConfigurator.cs @@ -1,16 +1,16 @@ +using System; +using Microsoft.Extensions.DependencyInjection; + namespace KafkaFlow { - using System; - using Microsoft.Extensions.DependencyInjection; - internal class MicrosoftDependencyConfigurator : IDependencyConfigurator { - private readonly IServiceCollection services; + private readonly IServiceCollection _services; public MicrosoftDependencyConfigurator(IServiceCollection services) { - this.services = services; - this.services.AddSingleton(provider => new MicrosoftDependencyResolver(provider)); + _services = services; + _services.AddSingleton(provider => new MicrosoftDependencyResolver(provider)); } public IDependencyConfigurator Add( @@ -18,7 +18,7 @@ public IDependencyConfigurator Add( Type implementationType, InstanceLifetime lifetime) { - this.services.Add( + _services.Add( ServiceDescriptor.Describe( serviceType, implementationType, @@ -31,7 +31,7 @@ public IDependencyConfigurator Add(InstanceLifetime l where TService : class where TImplementation : class, TService { - this.services.Add( + _services.Add( ServiceDescriptor.Describe( typeof(TService), typeof(TImplementation), @@ -43,7 +43,7 @@ public IDependencyConfigurator Add(InstanceLifetime l public IDependencyConfigurator Add(InstanceLifetime lifetime) where TService : class { - this.services.Add( + _services.Add( ServiceDescriptor.Describe( typeof(TService), typeof(TService), @@ -55,7 +55,7 @@ public IDependencyConfigurator Add(InstanceLifetime lifetime) public IDependencyConfigurator Add(TImplementation service) where TImplementation : class { - this.services.AddSingleton(service); + _services.AddSingleton(service); return this; } @@ -64,7 +64,7 @@ public IDependencyConfigurator Add( Func factory, InstanceLifetime lifetime) { - this.services.Add( + _services.Add( ServiceDescriptor.Describe( serviceType, provider => factory(new MicrosoftDependencyResolver(provider)), diff --git a/src/KafkaFlow.Microsoft.DependencyInjection/MicrosoftDependencyResolver.cs b/src/KafkaFlow.Microsoft.DependencyInjection/MicrosoftDependencyResolver.cs index e0f3033dd..39a186681 100644 --- a/src/KafkaFlow.Microsoft.DependencyInjection/MicrosoftDependencyResolver.cs +++ b/src/KafkaFlow.Microsoft.DependencyInjection/MicrosoftDependencyResolver.cs @@ -1,31 +1,31 @@ -namespace KafkaFlow -{ - using System; - using System.Collections.Generic; - using global::Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using global::Microsoft.Extensions.DependencyInjection; +namespace KafkaFlow +{ internal class MicrosoftDependencyResolver : IDependencyResolver { - private readonly IServiceProvider serviceProvider; + private readonly IServiceProvider _serviceProvider; public MicrosoftDependencyResolver(IServiceProvider serviceProvider) { - this.serviceProvider = serviceProvider; + _serviceProvider = serviceProvider; } public object Resolve(Type type) { - return this.serviceProvider.GetService(type); + return _serviceProvider.GetService(type); } public IEnumerable ResolveAll(Type type) { - return this.serviceProvider.GetServices(type); + return _serviceProvider.GetServices(type); } public IDependencyResolverScope CreateScope() { - return new MicrosoftDependencyResolverScope(this.serviceProvider.CreateScope()); + return new MicrosoftDependencyResolverScope(_serviceProvider.CreateScope()); } } } diff --git a/src/KafkaFlow.Microsoft.DependencyInjection/MicrosoftDependencyResolverScope.cs b/src/KafkaFlow.Microsoft.DependencyInjection/MicrosoftDependencyResolverScope.cs index 20adbd8f8..6cd745d47 100644 --- a/src/KafkaFlow.Microsoft.DependencyInjection/MicrosoftDependencyResolverScope.cs +++ b/src/KafkaFlow.Microsoft.DependencyInjection/MicrosoftDependencyResolverScope.cs @@ -1,14 +1,14 @@ +using global::Microsoft.Extensions.DependencyInjection; + namespace KafkaFlow { - using global::Microsoft.Extensions.DependencyInjection; - internal class MicrosoftDependencyResolverScope : IDependencyResolverScope { - private readonly IServiceScope scope; + private readonly IServiceScope _scope; public MicrosoftDependencyResolverScope(IServiceScope scope) { - this.scope = scope; + _scope = scope; this.Resolver = new MicrosoftDependencyResolver(scope.ServiceProvider); } @@ -16,7 +16,7 @@ public MicrosoftDependencyResolverScope(IServiceScope scope) public void Dispose() { - this.scope.Dispose(); + _scope.Dispose(); } } } diff --git a/src/KafkaFlow.Microsoft.DependencyInjection/ServiceCollectionExtensions.cs b/src/KafkaFlow.Microsoft.DependencyInjection/ServiceCollectionExtensions.cs index 905fce15a..296bc6c6d 100644 --- a/src/KafkaFlow.Microsoft.DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/KafkaFlow.Microsoft.DependencyInjection/ServiceCollectionExtensions.cs @@ -1,9 +1,9 @@ +using System; +using global::Microsoft.Extensions.DependencyInjection; +using KafkaFlow.Configuration; + namespace KafkaFlow { - using System; - using global::Microsoft.Extensions.DependencyInjection; - using KafkaFlow.Configuration; - /// /// Extension methods over IServiceCollection /// diff --git a/src/KafkaFlow.Microsoft.DependencyInjection/ServiceProviderExtensions.cs b/src/KafkaFlow.Microsoft.DependencyInjection/ServiceProviderExtensions.cs index dc872e585..098084edc 100644 --- a/src/KafkaFlow.Microsoft.DependencyInjection/ServiceProviderExtensions.cs +++ b/src/KafkaFlow.Microsoft.DependencyInjection/ServiceProviderExtensions.cs @@ -1,9 +1,9 @@ +using System; +using global::Microsoft.Extensions.DependencyInjection; +using KafkaFlow.Configuration; + namespace KafkaFlow { - using System; - using global::Microsoft.Extensions.DependencyInjection; - using KafkaFlow.Configuration; - /// /// Extension methods over IServiceProvider /// diff --git a/src/KafkaFlow.OpenTelemetry/ActivitySourceAccessor.cs b/src/KafkaFlow.OpenTelemetry/ActivitySourceAccessor.cs index 8a9294e9e..1cac5d4b9 100644 --- a/src/KafkaFlow.OpenTelemetry/ActivitySourceAccessor.cs +++ b/src/KafkaFlow.OpenTelemetry/ActivitySourceAccessor.cs @@ -1,10 +1,12 @@ extern alias SemanticConventions; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using Conventions = SemanticConventions::OpenTelemetry.Trace.TraceSemanticConventions; + namespace KafkaFlow.OpenTelemetry { - using System.Diagnostics; - using Conventions = SemanticConventions::OpenTelemetry.Trace.TraceSemanticConventions; - internal static class ActivitySourceAccessor { internal const string ActivityString = "otel_activity"; @@ -13,9 +15,9 @@ internal static class ActivitySourceAccessor internal const string AttributeMessagingKafkaMessageKey = "messaging.kafka.message.key"; internal const string AttributeMessagingKafkaMessageOffset = "messaging.kafka.message.offset"; - internal static readonly ActivitySource ActivitySource = new(KafkaFlowInstrumentation.ActivitySourceName, KafkaFlowInstrumentation.Version); + internal static readonly ActivitySource s_activitySource = new(KafkaFlowInstrumentation.ActivitySourceName, KafkaFlowInstrumentation.Version); - internal static void SetGenericTags(Activity activity) + internal static void SetGenericTags(Activity activity, IEnumerable bootstrapServers) { activity?.SetTag(Conventions.AttributeMessagingSystem, MessagingSystemId); activity?.SetTag(Conventions.AttributePeerService, string.Join(",", bootstrapServers ?? Enumerable.Empty())); diff --git a/src/KafkaFlow.OpenTelemetry/ExtensionMethods.cs b/src/KafkaFlow.OpenTelemetry/ExtensionMethods.cs index 9b169c949..ef72ef941 100644 --- a/src/KafkaFlow.OpenTelemetry/ExtensionMethods.cs +++ b/src/KafkaFlow.OpenTelemetry/ExtensionMethods.cs @@ -1,7 +1,7 @@ -namespace KafkaFlow.Configuration -{ - using KafkaFlow.OpenTelemetry; +using KafkaFlow.OpenTelemetry; +namespace KafkaFlow.Configuration +{ /// /// Adds OpenTelemetry instrumentation /// diff --git a/src/KafkaFlow.OpenTelemetry/OpenTelemetryConsumerEventsHandler.cs b/src/KafkaFlow.OpenTelemetry/OpenTelemetryConsumerEventsHandler.cs index f884f8540..6faa42e61 100644 --- a/src/KafkaFlow.OpenTelemetry/OpenTelemetryConsumerEventsHandler.cs +++ b/src/KafkaFlow.OpenTelemetry/OpenTelemetryConsumerEventsHandler.cs @@ -1,21 +1,21 @@ -namespace KafkaFlow.OpenTelemetry +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; +using System.Threading.Tasks; +using global::OpenTelemetry; +using global::OpenTelemetry.Context.Propagation; +using global::OpenTelemetry.Trace; + +namespace KafkaFlow.OpenTelemetry { - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.Text; - using System.Threading.Tasks; - using global::OpenTelemetry; - using global::OpenTelemetry.Context.Propagation; - using global::OpenTelemetry.Trace; - internal static class OpenTelemetryConsumerEventsHandler { private const string ProcessString = "process"; private const string AttributeMessagingSourceName = "messaging.source.name"; private const string AttributeMessagingKafkaConsumerGroup = "messaging.kafka.consumer.group"; private const string AttributeMessagingKafkaSourcePartition = "messaging.kafka.source.partition"; - private static readonly TextMapPropagator Propagator = Propagators.DefaultTextMapPropagator; + private static readonly TextMapPropagator s_propagator = Propagators.DefaultTextMapPropagator; public static Task OnConsumeStarted(IMessageContext context) { @@ -24,13 +24,13 @@ public static Task OnConsumeStarted(IMessageContext context) var activityName = !string.IsNullOrEmpty(context?.ConsumerContext.Topic) ? $"{context?.ConsumerContext.Topic} {ProcessString}" : ProcessString; // Extract the PropagationContext of the upstream parent from the message headers. - var parentContext = Propagator.Extract(new PropagationContext(default, Baggage.Current), context, ExtractTraceContextIntoBasicProperties); + var parentContext = s_propagator.Extract(new PropagationContext(default, Baggage.Current), context, ExtractTraceContextIntoBasicProperties); Baggage.Current = parentContext.Baggage; // Start an activity with a name following the semantic convention of the OpenTelemetry messaging specification. // The convention also defines a set of attributes (in .NET they are mapped as `tags`) to be populated in the activity. // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/messaging.md - var activity = ActivitySourceAccessor.ActivitySource.StartActivity(activityName, ActivityKind.Consumer, parentContext.ActivityContext); + var activity = ActivitySourceAccessor.s_activitySource.StartActivity(activityName, ActivityKind.Consumer, parentContext.ActivityContext); foreach (var item in Baggage.Current) { @@ -94,4 +94,4 @@ private static void SetConsumerTags(IMessageContext context, Activity activity) activity.SetTag(AttributeMessagingKafkaSourcePartition, context.ConsumerContext.Partition); } } -} +} \ No newline at end of file diff --git a/src/KafkaFlow.OpenTelemetry/OpenTelemetryProducerEventsHandler.cs b/src/KafkaFlow.OpenTelemetry/OpenTelemetryProducerEventsHandler.cs index 09275f938..8b2db5fef 100644 --- a/src/KafkaFlow.OpenTelemetry/OpenTelemetryProducerEventsHandler.cs +++ b/src/KafkaFlow.OpenTelemetry/OpenTelemetryProducerEventsHandler.cs @@ -1,20 +1,20 @@ -namespace KafkaFlow.OpenTelemetry +using System; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using global::OpenTelemetry; +using global::OpenTelemetry.Context.Propagation; +using global::OpenTelemetry.Trace; + +namespace KafkaFlow.OpenTelemetry { - using System; - using System.Diagnostics; - using System.Linq; - using System.Text; - using System.Threading.Tasks; - using global::OpenTelemetry; - using global::OpenTelemetry.Context.Propagation; - using global::OpenTelemetry.Trace; - internal static class OpenTelemetryProducerEventsHandler { private const string PublishString = "publish"; private const string AttributeMessagingDestinationName = "messaging.destination.name"; private const string AttributeMessagingKafkaDestinationPartition = "messaging.kafka.destination.partition"; - private static readonly TextMapPropagator Propagator = Propagators.DefaultTextMapPropagator; + private static readonly TextMapPropagator s_propagator = Propagators.DefaultTextMapPropagator; public static Task OnProducerStarted(IMessageContext context) { @@ -25,7 +25,7 @@ public static Task OnProducerStarted(IMessageContext context) // Start an activity with a name following the semantic convention of the OpenTelemetry messaging specification. // The convention also defines a set of attributes (in .NET they are mapped as `tags`) to be populated in the activity. // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/messaging.md - var activity = ActivitySourceAccessor.ActivitySource.StartActivity(activityName, ActivityKind.Producer); + var activity = ActivitySourceAccessor.s_activitySource.StartActivity(activityName, ActivityKind.Producer); // Depending on Sampling (and whether a listener is registered or not), the // activity above may not be created. @@ -47,7 +47,7 @@ public static Task OnProducerStarted(IMessageContext context) Baggage.Current = Baggage.Create(activity?.Baggage.ToDictionary(item => item.Key, item => item.Value)); // Inject the ActivityContext into the message headers to propagate trace context to the receiving service. - Propagator.Inject(new PropagationContext(contextToInject, Baggage.Current), context, InjectTraceContextIntoBasicProperties); + s_propagator.Inject(new PropagationContext(contextToInject, Baggage.Current), context, InjectTraceContextIntoBasicProperties); ActivitySourceAccessor.SetGenericTags(activity, context?.Brokers); @@ -104,4 +104,4 @@ private static void SetProducerTags(IMessageContext context, Activity activity) activity.SetTag(ActivitySourceAccessor.AttributeMessagingKafkaMessageOffset, context?.ProducerContext.Offset); } } -} +} \ No newline at end of file diff --git a/src/KafkaFlow.SchemaRegistry/ClusterConfigurationBuilderExtensions.cs b/src/KafkaFlow.SchemaRegistry/ClusterConfigurationBuilderExtensions.cs index 83c4123a8..95abcaec0 100644 --- a/src/KafkaFlow.SchemaRegistry/ClusterConfigurationBuilderExtensions.cs +++ b/src/KafkaFlow.SchemaRegistry/ClusterConfigurationBuilderExtensions.cs @@ -1,9 +1,9 @@ +using System; +using Confluent.SchemaRegistry; +using KafkaFlow.Configuration; + namespace KafkaFlow { - using System; - using Confluent.SchemaRegistry; - using KafkaFlow.Configuration; - /// /// No needed /// diff --git a/src/KafkaFlow.SchemaRegistry/ConfluentDeserializerWrapper.cs b/src/KafkaFlow.SchemaRegistry/ConfluentDeserializerWrapper.cs index ace5aa9c5..c908eb5ea 100644 --- a/src/KafkaFlow.SchemaRegistry/ConfluentDeserializerWrapper.cs +++ b/src/KafkaFlow.SchemaRegistry/ConfluentDeserializerWrapper.cs @@ -1,20 +1,20 @@ +using System; +using System.Collections.Concurrent; +using System.IO; +using System.Threading.Tasks; +using Confluent.Kafka; +using Microsoft.IO; + namespace KafkaFlow { - using System; - using System.Collections.Concurrent; - using System.IO; - using System.Threading.Tasks; - using Confluent.Kafka; - using Microsoft.IO; - /// /// A wrapper to call the typed Confluent deserializers /// public abstract class ConfluentDeserializerWrapper { - private static readonly RecyclableMemoryStreamManager MemoryStreamManager = new(); + private static readonly RecyclableMemoryStreamManager s_memoryStreamManager = new(); - private static readonly ConcurrentDictionary Deserializers = new(); + private static readonly ConcurrentDictionary s_deserializers = new(); /// /// Get the deserializer based on the target message type @@ -26,9 +26,9 @@ public static ConfluentDeserializerWrapper GetOrCreateDeserializer( Type messageType, Func deserializerFactory) { - return Deserializers.SafeGetOrAdd( + return s_deserializers.SafeGetOrAdd( messageType, - _ => (ConfluentDeserializerWrapper) Activator.CreateInstance( + _ => (ConfluentDeserializerWrapper)Activator.CreateInstance( typeof(InnerConfluentDeserializerWrapper<>).MakeGenericType(messageType), deserializerFactory)); } @@ -43,22 +43,22 @@ public static ConfluentDeserializerWrapper GetOrCreateDeserializer( private class InnerConfluentDeserializerWrapper : ConfluentDeserializerWrapper { - private readonly IAsyncDeserializer deserializer; + private readonly IAsyncDeserializer _deserializer; public InnerConfluentDeserializerWrapper(Func deserializerFactory) { - this.deserializer = (IAsyncDeserializer) deserializerFactory(); + _deserializer = (IAsyncDeserializer)deserializerFactory(); } public override async Task DeserializeAsync(Stream input, ISerializerContext context) { - using var buffer = MemoryStreamManager.GetStream(); + using var buffer = s_memoryStreamManager.GetStream(); await input.CopyToAsync(buffer).ConfigureAwait(false); - return await this.deserializer + return await _deserializer .DeserializeAsync( - new ReadOnlyMemory(buffer.GetBuffer(), 0, (int) buffer.Length), + new ReadOnlyMemory(buffer.GetBuffer(), 0, (int)buffer.Length), false, new SerializationContext(MessageComponentType.Value, context.Topic)) .ConfigureAwait(false); diff --git a/src/KafkaFlow.SchemaRegistry/ConfluentSerializerWrapper.cs b/src/KafkaFlow.SchemaRegistry/ConfluentSerializerWrapper.cs index d705cdfda..6d506f0a8 100644 --- a/src/KafkaFlow.SchemaRegistry/ConfluentSerializerWrapper.cs +++ b/src/KafkaFlow.SchemaRegistry/ConfluentSerializerWrapper.cs @@ -1,17 +1,17 @@ +using System; +using System.Collections.Concurrent; +using System.IO; +using System.Threading.Tasks; +using Confluent.Kafka; + namespace KafkaFlow { - using System; - using System.Collections.Concurrent; - using System.IO; - using System.Threading.Tasks; - using Confluent.Kafka; - /// /// A wrapper to call the typed Confluent serializers and deserializers /// public abstract class ConfluentSerializerWrapper { - private static readonly ConcurrentDictionary Serializers = new(); + private static readonly ConcurrentDictionary s_serializers = new(); /// /// Get the serializer based on the target message type @@ -23,9 +23,9 @@ public static ConfluentSerializerWrapper GetOrCreateSerializer( Type messageType, Func serializerFactory) { - return Serializers.SafeGetOrAdd( + return s_serializers.SafeGetOrAdd( messageType, - _ => (ConfluentSerializerWrapper) Activator.CreateInstance( + _ => (ConfluentSerializerWrapper)Activator.CreateInstance( typeof(InnerConfluentSerializerWrapper<>).MakeGenericType(messageType), serializerFactory)); } @@ -41,17 +41,17 @@ public static ConfluentSerializerWrapper GetOrCreateSerializer( private class InnerConfluentSerializerWrapper : ConfluentSerializerWrapper { - private readonly IAsyncSerializer serializer; + private readonly IAsyncSerializer _serializer; public InnerConfluentSerializerWrapper(Func serializerFactory) { - this.serializer = (IAsyncSerializer) serializerFactory(); + _serializer = (IAsyncSerializer)serializerFactory(); } public override async Task SerializeAsync(object message, Stream output, ISerializerContext context) { - var data = await this.serializer - .SerializeAsync((T) message, new SerializationContext(MessageComponentType.Value, context.Topic)) + var data = await _serializer + .SerializeAsync((T)message, new SerializationContext(MessageComponentType.Value, context.Topic)) .ConfigureAwait(false); await output diff --git a/src/KafkaFlow.SchemaRegistry/ISchemaRegistryTypeNameResolver.cs b/src/KafkaFlow.SchemaRegistry/ISchemaRegistryTypeNameResolver.cs index 17cc95c82..eda8ed04f 100644 --- a/src/KafkaFlow.SchemaRegistry/ISchemaRegistryTypeNameResolver.cs +++ b/src/KafkaFlow.SchemaRegistry/ISchemaRegistryTypeNameResolver.cs @@ -1,7 +1,7 @@ +using System.Threading.Tasks; + namespace KafkaFlow { - using System.Threading.Tasks; - /// /// An interface to implement a type name resolver to messages serialized with schema registry serializers /// diff --git a/src/KafkaFlow.SchemaRegistry/SchemaRegistryTypeResolver.cs b/src/KafkaFlow.SchemaRegistry/SchemaRegistryTypeResolver.cs index 3861d1ef6..803f4199b 100644 --- a/src/KafkaFlow.SchemaRegistry/SchemaRegistryTypeResolver.cs +++ b/src/KafkaFlow.SchemaRegistry/SchemaRegistryTypeResolver.cs @@ -1,23 +1,23 @@ +using System; +using System.Buffers.Binary; +using System.Collections.Concurrent; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using KafkaFlow.Middlewares.Serializer.Resolvers; + namespace KafkaFlow { - using System; - using System.Buffers.Binary; - using System.Collections.Concurrent; - using System.Linq; - using System.Threading; - using System.Threading.Tasks; - using KafkaFlow.Middlewares.Serializer.Resolvers; - /// /// The message type resolver to be used with schema registry serializers /// public class SchemaRegistryTypeResolver : IMessageTypeResolver { - private static readonly ConcurrentDictionary Types = new(); + private static readonly ConcurrentDictionary s_types = new(); - private static readonly SemaphoreSlim Semaphore = new(1, 1); + private static readonly SemaphoreSlim s_semaphore = new(1, 1); - private readonly ISchemaRegistryTypeNameResolver typeNameResolver; + private readonly ISchemaRegistryTypeNameResolver _typeNameResolver; /// /// Initializes a new instance of the class. @@ -25,39 +25,39 @@ public class SchemaRegistryTypeResolver : IMessageTypeResolver /// A instance of the interface. public SchemaRegistryTypeResolver(ISchemaRegistryTypeNameResolver typeNameResolver) { - this.typeNameResolver = typeNameResolver; + _typeNameResolver = typeNameResolver; } /// public async ValueTask OnConsumeAsync(IMessageContext context) { var schemaId = BinaryPrimitives.ReadInt32BigEndian( - ((byte[]) context.Message.Value).AsSpan().Slice(1, 4)); + ((byte[])context.Message.Value).AsSpan().Slice(1, 4)); - if (Types.TryGetValue(schemaId, out var type)) + if (s_types.TryGetValue(schemaId, out var type)) { return type; } - await Semaphore.WaitAsync(); + await s_semaphore.WaitAsync(); try { - if (Types.TryGetValue(schemaId, out type)) + if (s_types.TryGetValue(schemaId, out type)) { return type; } - var typeName = await this.typeNameResolver.ResolveAsync(schemaId); + var typeName = await _typeNameResolver.ResolveAsync(schemaId); - return Types[schemaId] = AppDomain.CurrentDomain + return s_types[schemaId] = AppDomain.CurrentDomain .GetAssemblies() .Select(a => a.GetType(typeName)) .FirstOrDefault(x => x != null); } finally { - Semaphore.Release(); + s_semaphore.Release(); } } diff --git a/src/KafkaFlow.Serializer.JsonCore/JsonCoreDeserializer.cs b/src/KafkaFlow.Serializer.JsonCore/JsonCoreDeserializer.cs index 521b3be16..6a9a18d30 100644 --- a/src/KafkaFlow.Serializer.JsonCore/JsonCoreDeserializer.cs +++ b/src/KafkaFlow.Serializer.JsonCore/JsonCoreDeserializer.cs @@ -1,16 +1,16 @@ -namespace KafkaFlow.Serializer -{ - using System; - using System.IO; - using System.Text.Json; - using System.Threading.Tasks; +using System; +using System.IO; +using System.Text.Json; +using System.Threading.Tasks; +namespace KafkaFlow.Serializer +{ /// /// A message deserializer using System.Text.Json library /// public class JsonCoreDeserializer : IDeserializer { - private readonly JsonSerializerOptions serializerOptions; + private readonly JsonSerializerOptions _serializerOptions; /// /// Initializes a new instance of the class. @@ -18,7 +18,7 @@ public class JsonCoreDeserializer : IDeserializer /// Json serializer options public JsonCoreDeserializer(JsonSerializerOptions options) { - this.serializerOptions = options; + _serializerOptions = options; } /// @@ -33,7 +33,7 @@ public JsonCoreDeserializer() public async Task DeserializeAsync(Stream input, Type type, ISerializerContext context) { return await JsonSerializer - .DeserializeAsync(input, type, this.serializerOptions) + .DeserializeAsync(input, type, _serializerOptions) .ConfigureAwait(false); } } diff --git a/src/KafkaFlow.Serializer.JsonCore/JsonCoreSerializer.cs b/src/KafkaFlow.Serializer.JsonCore/JsonCoreSerializer.cs index e0069dd7e..22eb2b4e8 100644 --- a/src/KafkaFlow.Serializer.JsonCore/JsonCoreSerializer.cs +++ b/src/KafkaFlow.Serializer.JsonCore/JsonCoreSerializer.cs @@ -1,16 +1,16 @@ -namespace KafkaFlow.Serializer -{ - using System.IO; - using System.Text.Json; - using System.Threading.Tasks; +using System.IO; +using System.Text.Json; +using System.Threading.Tasks; +namespace KafkaFlow.Serializer +{ /// /// A message serializer using System.Text.Json library /// public class JsonCoreSerializer : ISerializer { - private readonly JsonSerializerOptions serializerOptions; - private readonly JsonWriterOptions writerOptions; + private readonly JsonSerializerOptions _serializerOptions; + private readonly JsonWriterOptions _writerOptions; /// /// Initializes a new instance of the class. @@ -18,7 +18,7 @@ public class JsonCoreSerializer : ISerializer /// Json serializer options public JsonCoreSerializer(JsonSerializerOptions options) { - this.serializerOptions = options; + _serializerOptions = options; } /// @@ -27,7 +27,7 @@ public JsonCoreSerializer(JsonSerializerOptions options) /// Json writer options public JsonCoreSerializer(JsonWriterOptions writerOptions) { - this.writerOptions = writerOptions; + _writerOptions = writerOptions; } /// @@ -37,8 +37,8 @@ public JsonCoreSerializer(JsonWriterOptions writerOptions) /// Json writer options public JsonCoreSerializer(JsonSerializerOptions serializerOptions, JsonWriterOptions writerOptions) { - this.serializerOptions = serializerOptions; - this.writerOptions = writerOptions; + _serializerOptions = serializerOptions; + _writerOptions = writerOptions; } /// @@ -52,9 +52,9 @@ public JsonCoreSerializer() /// public Task SerializeAsync(object message, Stream output, ISerializerContext context) { - using var writer = new Utf8JsonWriter(output, this.writerOptions); + using var writer = new Utf8JsonWriter(output, _writerOptions); - JsonSerializer.Serialize(writer, message, this.serializerOptions); + JsonSerializer.Serialize(writer, message, _serializerOptions); return Task.CompletedTask; } diff --git a/src/KafkaFlow.Serializer.NewtonsoftJson/NewtonsoftJsonDeserializer.cs b/src/KafkaFlow.Serializer.NewtonsoftJson/NewtonsoftJsonDeserializer.cs index f0b05dcff..170a87259 100644 --- a/src/KafkaFlow.Serializer.NewtonsoftJson/NewtonsoftJsonDeserializer.cs +++ b/src/KafkaFlow.Serializer.NewtonsoftJson/NewtonsoftJsonDeserializer.cs @@ -1,11 +1,11 @@ -namespace KafkaFlow.Serializer -{ - using System; - using System.IO; - using System.Text; - using System.Threading.Tasks; - using Newtonsoft.Json; +using System; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; +namespace KafkaFlow.Serializer +{ /// /// A message deserializer using NewtonsoftJson library /// @@ -13,8 +13,9 @@ public class NewtonsoftJsonDeserializer : IDeserializer { private const int DefaultBufferSize = 1024; - private static readonly UTF8Encoding UTF8NoBom = new (false); - private readonly JsonSerializerSettings settings; + private static readonly UTF8Encoding s_uTF8NoBom = new(false); + + private readonly JsonSerializerSettings _settings; /// /// Initializes a new instance of the class. @@ -22,7 +23,7 @@ public class NewtonsoftJsonDeserializer : IDeserializer /// Json serializer settings public NewtonsoftJsonDeserializer(JsonSerializerSettings settings) { - this.settings = settings; + _settings = settings; } /// @@ -38,12 +39,12 @@ public Task DeserializeAsync(Stream input, Type type, ISerializerContext { using var sr = new StreamReader( input, - UTF8NoBom, + s_uTF8NoBom, true, DefaultBufferSize, true); - var serializer = JsonSerializer.CreateDefault(this.settings); + var serializer = JsonSerializer.CreateDefault(_settings); return Task.FromResult(serializer.Deserialize(sr, type)); } diff --git a/src/KafkaFlow.Serializer.NewtonsoftJson/NewtonsoftJsonSerializer.cs b/src/KafkaFlow.Serializer.NewtonsoftJson/NewtonsoftJsonSerializer.cs index 8ca731d2c..2a312ca4f 100644 --- a/src/KafkaFlow.Serializer.NewtonsoftJson/NewtonsoftJsonSerializer.cs +++ b/src/KafkaFlow.Serializer.NewtonsoftJson/NewtonsoftJsonSerializer.cs @@ -1,10 +1,10 @@ -namespace KafkaFlow.Serializer -{ - using System.IO; - using System.Text; - using System.Threading.Tasks; - using Newtonsoft.Json; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; +namespace KafkaFlow.Serializer +{ /// /// A message serializer using NewtonsoftJson library /// @@ -12,8 +12,9 @@ public class NewtonsoftJsonSerializer : ISerializer { private const int DefaultBufferSize = 1024; - private static readonly UTF8Encoding UTF8NoBom = new (false); - private readonly JsonSerializerSettings settings; + private static readonly UTF8Encoding s_uTF8NoBom = new(false); + + private readonly JsonSerializerSettings _settings; /// /// Initializes a new instance of the class. @@ -21,7 +22,7 @@ public class NewtonsoftJsonSerializer : ISerializer /// Json serializer settings public NewtonsoftJsonSerializer(JsonSerializerSettings settings) { - this.settings = settings; + _settings = settings; } /// @@ -35,8 +36,8 @@ public NewtonsoftJsonSerializer() /// public Task SerializeAsync(object message, Stream output, ISerializerContext context) { - using var sw = new StreamWriter(output, UTF8NoBom, DefaultBufferSize, true); - var serializer = JsonSerializer.CreateDefault(this.settings); + using var sw = new StreamWriter(output, s_uTF8NoBom, DefaultBufferSize, true); + var serializer = JsonSerializer.CreateDefault(_settings); serializer.Serialize(sw, message); diff --git a/src/KafkaFlow.Serializer.ProtobufNet/ProtobufNetDeserializer.cs b/src/KafkaFlow.Serializer.ProtobufNet/ProtobufNetDeserializer.cs index c4838c35a..e2f6822a1 100644 --- a/src/KafkaFlow.Serializer.ProtobufNet/ProtobufNetDeserializer.cs +++ b/src/KafkaFlow.Serializer.ProtobufNet/ProtobufNetDeserializer.cs @@ -1,10 +1,9 @@ -namespace KafkaFlow.Serializer -{ - using System; - using System.IO; - using System.Threading.Tasks; - using ProtoBuf; +using System; +using System.IO; +using System.Threading.Tasks; +namespace KafkaFlow.Serializer +{ /// /// A message deserializer using protobuf-net library /// @@ -13,7 +12,7 @@ public class ProtobufNetDeserializer : IDeserializer /// public Task DeserializeAsync(Stream input, Type type, ISerializerContext context) { - return Task.FromResult(Serializer.Deserialize(type, input)); + return Task.FromResult(ProtoBuf.Serializer.Deserialize(type, input)); } } } diff --git a/src/KafkaFlow.Serializer.ProtobufNet/ProtobufNetSerializer.cs b/src/KafkaFlow.Serializer.ProtobufNet/ProtobufNetSerializer.cs index 12d8a706d..9aa879163 100644 --- a/src/KafkaFlow.Serializer.ProtobufNet/ProtobufNetSerializer.cs +++ b/src/KafkaFlow.Serializer.ProtobufNet/ProtobufNetSerializer.cs @@ -1,9 +1,8 @@ -namespace KafkaFlow.Serializer -{ - using System.IO; - using System.Threading.Tasks; - using ProtoBuf; +using System.IO; +using System.Threading.Tasks; +namespace KafkaFlow.Serializer +{ /// /// A message serializer using protobuf-net library /// @@ -12,7 +11,7 @@ public class ProtobufNetSerializer : ISerializer /// public Task SerializeAsync(object message, Stream output, ISerializerContext context) { - Serializer.Serialize(output, message); + ProtoBuf.Serializer.Serialize(output, message); return Task.CompletedTask; } diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConfluentAvroDeserializer.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConfluentAvroDeserializer.cs index 3f29adc7d..b59bdd5b8 100644 --- a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConfluentAvroDeserializer.cs +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConfluentAvroDeserializer.cs @@ -1,17 +1,17 @@ -namespace KafkaFlow.Serializer.SchemaRegistry -{ - using System; - using System.IO; - using System.Threading.Tasks; - using Confluent.SchemaRegistry; - using Confluent.SchemaRegistry.Serdes; +using System; +using System.IO; +using System.Threading.Tasks; +using Confluent.SchemaRegistry; +using Confluent.SchemaRegistry.Serdes; +namespace KafkaFlow.Serializer.SchemaRegistry +{ /// /// A message serializer using Apache.Avro library /// public class ConfluentAvroDeserializer : IDeserializer { - private readonly ISchemaRegistryClient schemaRegistryClient; + private readonly ISchemaRegistryClient _schemaRegistryClient; /// /// Initializes a new instance of the class. @@ -19,7 +19,7 @@ public class ConfluentAvroDeserializer : IDeserializer /// The to be used by the framework public ConfluentAvroDeserializer(IDependencyResolver resolver) { - this.schemaRegistryClient = + _schemaRegistryClient = resolver.Resolve() ?? throw new InvalidOperationException( $"No schema registry configuration was found. Set it using {nameof(ClusterConfigurationBuilderExtensions.WithSchemaRegistry)} on cluster configuration"); @@ -34,7 +34,7 @@ public Task DeserializeAsync(Stream input, Type type, ISerializerContext () => Activator .CreateInstance( typeof(AvroDeserializer<>).MakeGenericType(type), - this.schemaRegistryClient, + _schemaRegistryClient, null)) .DeserializeAsync(input, context); } diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConfluentAvroSerializer.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConfluentAvroSerializer.cs index e0e2eb49e..6118f5932 100644 --- a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConfluentAvroSerializer.cs +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConfluentAvroSerializer.cs @@ -1,18 +1,18 @@ -namespace KafkaFlow.Serializer.SchemaRegistry -{ - using System; - using System.IO; - using System.Threading.Tasks; - using Confluent.SchemaRegistry; - using Confluent.SchemaRegistry.Serdes; +using System; +using System.IO; +using System.Threading.Tasks; +using Confluent.SchemaRegistry; +using Confluent.SchemaRegistry.Serdes; +namespace KafkaFlow.Serializer.SchemaRegistry +{ /// /// A message serializer using Apache.Avro library /// public class ConfluentAvroSerializer : ISerializer { - private readonly ISchemaRegistryClient schemaRegistryClient; - private readonly AvroSerializerConfig serializerConfig; + private readonly ISchemaRegistryClient _schemaRegistryClient; + private readonly AvroSerializerConfig _serializerConfig; /// /// Initializes a new instance of the class. @@ -23,12 +23,12 @@ public ConfluentAvroSerializer( IDependencyResolver resolver, AvroSerializerConfig serializerConfig = null) { - this.schemaRegistryClient = + _schemaRegistryClient = resolver.Resolve() ?? throw new InvalidOperationException( $"No schema registry configuration was found. Set it using {nameof(ClusterConfigurationBuilderExtensions.WithSchemaRegistry)} on cluster configuration"); - this.serializerConfig = serializerConfig; + _serializerConfig = serializerConfig; } /// @@ -39,8 +39,8 @@ public Task SerializeAsync(object message, Stream output, ISerializerContext con message.GetType(), () => Activator.CreateInstance( typeof(AvroSerializer<>).MakeGenericType(message.GetType()), - this.schemaRegistryClient, - this.serializerConfig)) + _schemaRegistryClient, + _serializerConfig)) .SerializeAsync(message, output, context); } } diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConfluentAvroTypeNameResolver.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConfluentAvroTypeNameResolver.cs index c0fc1c9a2..79be740ff 100644 --- a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConfluentAvroTypeNameResolver.cs +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConfluentAvroTypeNameResolver.cs @@ -1,21 +1,21 @@ +using System.Threading.Tasks; +using Confluent.SchemaRegistry; +using Newtonsoft.Json; + namespace KafkaFlow.Serializer.SchemaRegistry { - using System.Threading.Tasks; - using Confluent.SchemaRegistry; - using Newtonsoft.Json; - internal class ConfluentAvroTypeNameResolver : ISchemaRegistryTypeNameResolver { - private readonly ISchemaRegistryClient client; + private readonly ISchemaRegistryClient _client; public ConfluentAvroTypeNameResolver(ISchemaRegistryClient client) { - this.client = client; + _client = client; } public async Task ResolveAsync(int id) { - var schema = await this.client.GetSchemaAsync(id); + var schema = await _client.GetSchemaAsync(id); var avroFields = JsonConvert.DeserializeObject(schema.SchemaString); return $"{avroFields.Namespace}.{avroFields.Name}"; diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConsumerConfigurationBuilderExtensions.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConsumerConfigurationBuilderExtensions.cs index 859e852f5..e0e44fda5 100644 --- a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConsumerConfigurationBuilderExtensions.cs +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ConsumerConfigurationBuilderExtensions.cs @@ -1,10 +1,10 @@ -namespace KafkaFlow -{ - using Confluent.SchemaRegistry; - using KafkaFlow.Configuration; - using KafkaFlow.Middlewares.Serializer; - using KafkaFlow.Serializer.SchemaRegistry; +using Confluent.SchemaRegistry; +using KafkaFlow.Configuration; +using KafkaFlow.Middlewares.Serializer; +using KafkaFlow.Serializer.SchemaRegistry; +namespace KafkaFlow +{ /// /// No needed /// diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ProducerConfigurationBuilderExtensions.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ProducerConfigurationBuilderExtensions.cs index 54bf6bac7..5c4e98536 100644 --- a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ProducerConfigurationBuilderExtensions.cs +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/ProducerConfigurationBuilderExtensions.cs @@ -1,11 +1,11 @@ -namespace KafkaFlow -{ - using Confluent.SchemaRegistry; - using Confluent.SchemaRegistry.Serdes; - using KafkaFlow.Configuration; - using KafkaFlow.Middlewares.Serializer; - using KafkaFlow.Serializer.SchemaRegistry; +using Confluent.SchemaRegistry; +using Confluent.SchemaRegistry.Serdes; +using KafkaFlow.Configuration; +using KafkaFlow.Middlewares.Serializer; +using KafkaFlow.Serializer.SchemaRegistry; +namespace KafkaFlow +{ /// /// No needed /// diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ConfluentJsonDeserializer.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ConfluentJsonDeserializer.cs index 0ec931348..f86e20238 100644 --- a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ConfluentJsonDeserializer.cs +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ConfluentJsonDeserializer.cs @@ -1,17 +1,17 @@ -namespace KafkaFlow.Serializer.SchemaRegistry -{ - using System; - using System.IO; - using System.Threading.Tasks; - using Confluent.SchemaRegistry.Serdes; - using NJsonSchema.Generation; +using System; +using System.IO; +using System.Threading.Tasks; +using Confluent.SchemaRegistry.Serdes; +using NJsonSchema.Generation; +namespace KafkaFlow.Serializer.SchemaRegistry +{ /// /// A json message serializer integrated with the confluent schema registry /// public class ConfluentJsonDeserializer : IDeserializer { - private readonly JsonSchemaGeneratorSettings schemaGeneratorSettings; + private readonly JsonSchemaGeneratorSettings _schemaGeneratorSettings; /// /// Initializes a new instance of the class. @@ -19,7 +19,7 @@ public class ConfluentJsonDeserializer : IDeserializer /// An instance of public ConfluentJsonDeserializer(JsonSchemaGeneratorSettings schemaGeneratorSettings = null) { - this.schemaGeneratorSettings = schemaGeneratorSettings; + _schemaGeneratorSettings = schemaGeneratorSettings; } /// @@ -32,7 +32,7 @@ public Task DeserializeAsync(Stream input, Type type, ISerializerContext .CreateInstance( typeof(JsonDeserializer<>).MakeGenericType(type), null, - this.schemaGeneratorSettings)) + _schemaGeneratorSettings)) .DeserializeAsync(input, context); } } diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ConfluentJsonSerializer.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ConfluentJsonSerializer.cs index fa2763903..2da3b3d01 100644 --- a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ConfluentJsonSerializer.cs +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ConfluentJsonSerializer.cs @@ -1,20 +1,20 @@ -namespace KafkaFlow.Serializer.SchemaRegistry -{ - using System; - using System.IO; - using System.Threading.Tasks; - using Confluent.SchemaRegistry; - using Confluent.SchemaRegistry.Serdes; - using NJsonSchema.Generation; +using System; +using System.IO; +using System.Threading.Tasks; +using Confluent.SchemaRegistry; +using Confluent.SchemaRegistry.Serdes; +using NJsonSchema.Generation; +namespace KafkaFlow.Serializer.SchemaRegistry +{ /// /// A json message serializer integrated with the confluent schema registry /// public class ConfluentJsonSerializer : ISerializer { - private readonly ISchemaRegistryClient schemaRegistryClient; - private readonly JsonSerializerConfig serializerConfig; - private readonly JsonSchemaGeneratorSettings schemaGeneratorSettings; + private readonly ISchemaRegistryClient _schemaRegistryClient; + private readonly JsonSerializerConfig _serializerConfig; + private readonly JsonSchemaGeneratorSettings _schemaGeneratorSettings; /// /// Initializes a new instance of the class. @@ -40,13 +40,13 @@ public ConfluentJsonSerializer( JsonSerializerConfig serializerConfig, JsonSchemaGeneratorSettings schemaGeneratorSettings = null) { - this.schemaRegistryClient = + _schemaRegistryClient = resolver.Resolve() ?? throw new InvalidOperationException( $"No schema registry configuration was found. Set it using {nameof(ClusterConfigurationBuilderExtensions.WithSchemaRegistry)} on cluster configuration"); - this.serializerConfig = serializerConfig; - this.schemaGeneratorSettings = schemaGeneratorSettings; + _serializerConfig = serializerConfig; + _schemaGeneratorSettings = schemaGeneratorSettings; } /// @@ -57,9 +57,9 @@ public Task SerializeAsync(object message, Stream output, ISerializerContext con message.GetType(), () => Activator.CreateInstance( typeof(JsonSerializer<>).MakeGenericType(message.GetType()), - this.schemaRegistryClient, - this.serializerConfig, - this.schemaGeneratorSettings)) + _schemaRegistryClient, + _serializerConfig, + _schemaGeneratorSettings)) .SerializeAsync(message, output, context); } } diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ConsumerConfigurationBuilderExtensions.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ConsumerConfigurationBuilderExtensions.cs index 4700b797b..c73033f03 100644 --- a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ConsumerConfigurationBuilderExtensions.cs +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ConsumerConfigurationBuilderExtensions.cs @@ -1,9 +1,9 @@ -namespace KafkaFlow -{ - using KafkaFlow.Configuration; - using KafkaFlow.Middlewares.Serializer.Resolvers; - using KafkaFlow.Serializer.SchemaRegistry; +using KafkaFlow.Configuration; +using KafkaFlow.Middlewares.Serializer.Resolvers; +using KafkaFlow.Serializer.SchemaRegistry; +namespace KafkaFlow +{ /// /// No needed /// diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ProducerConfigurationBuilderExtensions.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ProducerConfigurationBuilderExtensions.cs index 208595450..e8ec141cb 100644 --- a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ProducerConfigurationBuilderExtensions.cs +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/ProducerConfigurationBuilderExtensions.cs @@ -1,10 +1,10 @@ -namespace KafkaFlow -{ - using Confluent.SchemaRegistry.Serdes; - using KafkaFlow.Configuration; - using KafkaFlow.Middlewares.Serializer.Resolvers; - using KafkaFlow.Serializer.SchemaRegistry; +using Confluent.SchemaRegistry.Serdes; +using KafkaFlow.Configuration; +using KafkaFlow.Middlewares.Serializer.Resolvers; +using KafkaFlow.Serializer.SchemaRegistry; +namespace KafkaFlow +{ /// /// No needed /// diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConfluentProtobufDeserializer.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConfluentProtobufDeserializer.cs index 3722dc35d..9e18232a1 100644 --- a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConfluentProtobufDeserializer.cs +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConfluentProtobufDeserializer.cs @@ -1,11 +1,11 @@ -namespace KafkaFlow.Serializer.SchemaRegistry -{ - using System; - using System.Collections.Generic; - using System.IO; - using System.Threading.Tasks; - using Confluent.SchemaRegistry.Serdes; +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using Confluent.SchemaRegistry.Serdes; +namespace KafkaFlow.Serializer.SchemaRegistry +{ /// /// A protobuf message serializer integrated with the confluent schema registry /// diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConfluentProtobufSerializer.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConfluentProtobufSerializer.cs index d29699d71..3f5dc5c4b 100644 --- a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConfluentProtobufSerializer.cs +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConfluentProtobufSerializer.cs @@ -1,18 +1,18 @@ -namespace KafkaFlow.Serializer.SchemaRegistry -{ - using System; - using System.IO; - using System.Threading.Tasks; - using Confluent.SchemaRegistry; - using Confluent.SchemaRegistry.Serdes; +using System; +using System.IO; +using System.Threading.Tasks; +using Confluent.SchemaRegistry; +using Confluent.SchemaRegistry.Serdes; +namespace KafkaFlow.Serializer.SchemaRegistry +{ /// /// A protobuf message serializer integrated with the confluent schema registry /// public class ConfluentProtobufSerializer : ISerializer { - private readonly ISchemaRegistryClient schemaRegistryClient; - private readonly ProtobufSerializerConfig serializerConfig; + private readonly ISchemaRegistryClient _schemaRegistryClient; + private readonly ProtobufSerializerConfig _serializerConfig; /// /// Initializes a new instance of the class. @@ -21,12 +21,12 @@ public class ConfluentProtobufSerializer : ISerializer /// An instance of public ConfluentProtobufSerializer(IDependencyResolver resolver, ProtobufSerializerConfig serializerConfig = null) { - this.schemaRegistryClient = + _schemaRegistryClient = resolver.Resolve() ?? throw new InvalidOperationException( $"No schema registry configuration was found. Set it using {nameof(ClusterConfigurationBuilderExtensions.WithSchemaRegistry)} on cluster configuration"); - this.serializerConfig = serializerConfig; + _serializerConfig = serializerConfig; } /// @@ -37,8 +37,8 @@ public Task SerializeAsync(object message, Stream output, ISerializerContext con message.GetType(), () => Activator.CreateInstance( typeof(ProtobufSerializer<>).MakeGenericType(message.GetType()), - this.schemaRegistryClient, - this.serializerConfig)) + _schemaRegistryClient, + _serializerConfig)) .SerializeAsync(message, output, context); } } diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConfluentProtobufTypeNameResolver.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConfluentProtobufTypeNameResolver.cs index 8ae17ee63..ff754b45a 100644 --- a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConfluentProtobufTypeNameResolver.cs +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConfluentProtobufTypeNameResolver.cs @@ -1,23 +1,23 @@ +using System.Linq; +using System.Threading.Tasks; +using Confluent.SchemaRegistry; +using Google.Protobuf; +using Google.Protobuf.Reflection; + namespace KafkaFlow { - using System.Linq; - using System.Threading.Tasks; - using Confluent.SchemaRegistry; - using Google.Protobuf; - using Google.Protobuf.Reflection; - internal class ConfluentProtobufTypeNameResolver : ISchemaRegistryTypeNameResolver { - private readonly ISchemaRegistryClient client; + private readonly ISchemaRegistryClient _client; public ConfluentProtobufTypeNameResolver(ISchemaRegistryClient client) { - this.client = client; + _client = client; } public async Task ResolveAsync(int id) { - var schemaString = (await this.client.GetSchemaAsync(id, "serialized")).SchemaString; + var schemaString = (await _client.GetSchemaAsync(id, "serialized")).SchemaString; var protoFields = FileDescriptorProto.Parser.ParseFrom(ByteString.FromBase64(schemaString)); diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConsumerConfigurationBuilderExtensions.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConsumerConfigurationBuilderExtensions.cs index 59012f3d8..558eb8056 100644 --- a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConsumerConfigurationBuilderExtensions.cs +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ConsumerConfigurationBuilderExtensions.cs @@ -1,10 +1,10 @@ -namespace KafkaFlow -{ - using Confluent.SchemaRegistry; - using KafkaFlow.Configuration; - using KafkaFlow.Middlewares.Serializer; - using KafkaFlow.Serializer.SchemaRegistry; +using Confluent.SchemaRegistry; +using KafkaFlow.Configuration; +using KafkaFlow.Middlewares.Serializer; +using KafkaFlow.Serializer.SchemaRegistry; +namespace KafkaFlow +{ /// /// No needed /// diff --git a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ProducerConfigurationBuilderExtensions.cs b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ProducerConfigurationBuilderExtensions.cs index af83cd19d..180073f59 100644 --- a/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ProducerConfigurationBuilderExtensions.cs +++ b/src/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/ProducerConfigurationBuilderExtensions.cs @@ -1,11 +1,11 @@ -namespace KafkaFlow -{ - using Confluent.SchemaRegistry; - using Confluent.SchemaRegistry.Serdes; - using KafkaFlow.Configuration; - using KafkaFlow.Middlewares.Serializer; - using KafkaFlow.Serializer.SchemaRegistry; +using Confluent.SchemaRegistry; +using Confluent.SchemaRegistry.Serdes; +using KafkaFlow.Configuration; +using KafkaFlow.Middlewares.Serializer; +using KafkaFlow.Serializer.SchemaRegistry; +namespace KafkaFlow +{ /// /// No needed /// diff --git a/src/KafkaFlow.UnitTests/Consumer/ConsumerManagerTests.cs b/src/KafkaFlow.UnitTests/Consumer/ConsumerManagerTests.cs deleted file mode 100644 index d8492f775..000000000 --- a/src/KafkaFlow.UnitTests/Consumer/ConsumerManagerTests.cs +++ /dev/null @@ -1,167 +0,0 @@ -namespace KafkaFlow.UnitTests.Consumer -{ - using System; - using System.Collections.Generic; - using System.Threading.Tasks; - using AutoFixture; - using Confluent.Kafka; - using FluentAssertions; - using KafkaFlow.Configuration; - using KafkaFlow.Consumers; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; - - [TestClass] - public class ConsumerManagerTests - { - private readonly Fixture fixture = new(); - - private ConsumerManager target; - - private Mock consumerMock; - private Mock workerPoolMock; - private Mock feederMock; - private Mock logHandlerMock; - private Mock dependencyResolver; - - private Action, List> onPartitionAssignedHandler; - private Action, List> onPartitionRevokedHandler; - - [TestInitialize] - public void Setup() - { - this.consumerMock = new Mock(); - this.workerPoolMock = new Mock(); - this.feederMock = new Mock(); - this.logHandlerMock = new Mock(); - this.dependencyResolver = new Mock(); - - this.consumerMock - .Setup( - x => x.OnPartitionsAssigned(It.IsAny, List>>())) - .Callback( - (Action, List> value) => - this.onPartitionAssignedHandler = value); - - this.consumerMock - .Setup( - x => x.OnPartitionsRevoked( - It.IsAny, List>>())) - .Callback( - (Action, List> value) => - this.onPartitionRevokedHandler = value); - - var configurationMock = new Mock(); - - configurationMock - .SetupGet(x => x.WorkersCountCalculator) - .Returns((_, _) => Task.FromResult(10)); - - configurationMock - .SetupGet(x => x.WorkersCountEvaluationInterval) - .Returns(TimeSpan.FromMinutes(5)); - - this.consumerMock - .SetupGet(x => x.Configuration) - .Returns(configurationMock.Object); - - this.target = new ConsumerManager( - this.consumerMock.Object, - this.workerPoolMock.Object, - this.feederMock.Object, - this.dependencyResolver.Object, - this.logHandlerMock.Object); - } - - [TestMethod] - public void ConstructorCalled_InitializeProperties() - { - // Assert - this.target.Consumer.Should().Be(this.consumerMock.Object); - this.target.WorkerPool.Should().Be(this.workerPoolMock.Object); - this.target.Feeder.Should().Be(this.feederMock.Object); - } - - [TestMethod] - public async Task StartAsync_StartDependencies() - { - // Arrange - this.feederMock - .Setup(x => x.Start()); - - // Act - await this.target.StartAsync(); - - // Assert - this.feederMock.VerifyAll(); - } - - [TestMethod] - public async Task StopAsync_StopDependencies() - { - // Arrange - this.feederMock - .Setup(x => x.StopAsync()) - .Returns(Task.CompletedTask); - - this.workerPoolMock - .Setup(x => x.StopAsync()) - .Returns(Task.CompletedTask); - - // Act - await this.target.StopAsync(); - - // Assert - this.feederMock.VerifyAll(); - this.workerPoolMock.VerifyAll(); - this.consumerMock.Verify(x => x.Dispose(), Times.Once()); - } - - [TestMethod] - public void OnPartitionsAssigned_StartWorkerPool() - { - // Arrange - var partitions = this.fixture.Create>(); - - this.workerPoolMock - .Setup(x => x.StartAsync(partitions, It.IsAny())) - .Returns(Task.CompletedTask); - - this.logHandlerMock - .Setup(x => x.Info(It.IsAny(), It.IsAny())); - - // Act - this.onPartitionAssignedHandler(this.dependencyResolver.Object, Mock.Of>(), partitions); - - // Assert - this.workerPoolMock.VerifyAll(); - this.logHandlerMock.VerifyAll(); - } - - [TestMethod] - public void OnPartitionsRevoked_StopWorkerPool() - { - // Arrange - IConsumer consumer = null; - var partitions = this.fixture.Create>(); - - this.workerPoolMock - .Setup(x => x.StopAsync()) - .Returns(Task.CompletedTask); - - this.consumerMock - .SetupGet(x => x.Configuration) - .Returns(new Mock().Object); - - this.logHandlerMock - .Setup(x => x.Warning(It.IsAny(), It.IsAny())); - - // Act - this.onPartitionRevokedHandler(this.dependencyResolver.Object, consumer, partitions); - - // Assert - this.workerPoolMock.VerifyAll(); - this.logHandlerMock.VerifyAll(); - } - } -} diff --git a/src/KafkaFlow.UnitTests/Middlewares/Serialization/SchemaRegistryTypeResolverTests.cs b/src/KafkaFlow.UnitTests/Middlewares/Serialization/SchemaRegistryTypeResolverTests.cs deleted file mode 100644 index 38f720526..000000000 --- a/src/KafkaFlow.UnitTests/Middlewares/Serialization/SchemaRegistryTypeResolverTests.cs +++ /dev/null @@ -1,47 +0,0 @@ -namespace KafkaFlow.UnitTests.Middlewares.Serialization -{ - using System; - using System.Buffers.Binary; - using System.Threading.Tasks; - using FluentAssertions; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; - - [TestClass] - public class SchemaRegistryTypeResolverTests - { - private readonly Mock messageContextMock; - private readonly Mock schemaRegistryTypeNameResolverMock; - private readonly SchemaRegistryTypeResolver schemaRegistryTypeResolver; - private readonly byte[] messageKey = new byte[] { 0x18, 0x19 }; - private readonly byte[] messageValue = new byte[] { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25 }; - - public SchemaRegistryTypeResolverTests() - { - this.messageContextMock = new Mock(); - this.messageContextMock.Setup(context => context.Message).Returns(new Message(messageKey, messageValue)); - this.schemaRegistryTypeNameResolverMock = new Mock(); - this.schemaRegistryTypeResolver = new SchemaRegistryTypeResolver(this.schemaRegistryTypeNameResolverMock.Object); - } - - [TestMethod] - public async Task OnConsumeAsync_WhenCalledTwice_TypeIsResolvedOnceThenTypeIsLoadedFromCache() - { - // Arrange - var expectedSchemaId = BinaryPrimitives.ReadInt32BigEndian( - this.messageValue.AsSpan().Slice(1, 4)); - - this.schemaRegistryTypeNameResolverMock.Setup( - resolver => resolver.ResolveAsync(expectedSchemaId)).ReturnsAsync(typeof(SchemaRegistryTypeResolverTests).FullName); - - // Act - await this.schemaRegistryTypeResolver.OnConsumeAsync(messageContextMock.Object); - var type = await this.schemaRegistryTypeResolver.OnConsumeAsync(messageContextMock.Object); - - // Assert - this.schemaRegistryTypeNameResolverMock.Verify(resolver => resolver.ResolveAsync(expectedSchemaId), Times.Once); - var expectedObject = (SchemaRegistryTypeResolverTests)Activator.CreateInstance(type); - expectedObject.Should().NotBeNull(); - } - } -} diff --git a/src/KafkaFlow.UnitTests/OffsetManagerTests.cs b/src/KafkaFlow.UnitTests/OffsetManagerTests.cs deleted file mode 100644 index 631de1336..000000000 --- a/src/KafkaFlow.UnitTests/OffsetManagerTests.cs +++ /dev/null @@ -1,88 +0,0 @@ -namespace KafkaFlow.UnitTests -{ - using System; - using System.Collections.Generic; - using Confluent.Kafka; - using FluentAssertions; - using KafkaFlow.Consumers; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; - using TopicPartitionOffset = KafkaFlow.TopicPartitionOffset; - - [TestClass] - public class OffsetManagerTests - { - private Mock committerMock; - private OffsetManager target; - private TopicPartition topicPartition; - - [TestInitialize] - public void Setup() - { - this.committerMock = new Mock(); - this.topicPartition = new TopicPartition("topic-A", new Partition(1)); - - this.target = new OffsetManager( - this.committerMock.Object, - new List { this.topicPartition }); - } - - [TestMethod] - public void MarkAsProcessed_WithNotQueuedContext_ShouldThrowInvalidOperation() - { - // Act - Action act = () => this.target.MarkAsProcessed(this.MockConsumerContext(1)); - - // Assert - act.Should().Throw(); - } - - [TestMethod] - public void MarkAsProcessed_WithGaps_ShouldStoreOffsetJustOnce() - { - // Arrange - this.target.Enqueue(this.MockConsumerContext(1)); - this.target.Enqueue(this.MockConsumerContext(2)); - this.target.Enqueue(this.MockConsumerContext(3)); - - // Act - this.target.MarkAsProcessed(this.MockConsumerContext(3)); - this.target.MarkAsProcessed(this.MockConsumerContext(2)); - this.target.MarkAsProcessed(this.MockConsumerContext(1)); - - // Assert - this.committerMock.Verify( - c => - c.MarkAsProcessed( - It.Is( - p => - p.Partition == this.topicPartition.Partition && - p.Offset == 3)), - Times.Once); - } - - private IConsumerContext MockConsumerContext(int offset) - { - var mock = new Mock(); - var tpo = new TopicPartitionOffset(this.topicPartition.Topic, this.topicPartition.Partition, offset); - - mock - .SetupGet(x => x.Offset) - .Returns(tpo.Offset); - - mock - .SetupGet(x => x.Partition) - .Returns(tpo.Partition); - - mock - .SetupGet(x => x.Topic) - .Returns(tpo.Topic); - - mock - .SetupGet(x => x.TopicPartitionOffset) - .Returns(tpo); - - return mock.Object; - } - } -} diff --git a/src/KafkaFlow.Unity/UnityDependencyConfigurator.cs b/src/KafkaFlow.Unity/UnityDependencyConfigurator.cs index 8273095bf..452e0d19e 100644 --- a/src/KafkaFlow.Unity/UnityDependencyConfigurator.cs +++ b/src/KafkaFlow.Unity/UnityDependencyConfigurator.cs @@ -1,17 +1,16 @@ -namespace KafkaFlow.Unity -{ - using System; - using System.Linq; - using global::Unity; - using global::Unity.Lifetime; - using InstanceLifetime = KafkaFlow.InstanceLifetime; +using System; +using System.Linq; +using global::Unity; +using global::Unity.Lifetime; +namespace KafkaFlow.Unity +{ /// /// The Unity implementation of /// public class UnityDependencyConfigurator : IDependencyConfigurator { - private readonly IUnityContainer container; + private readonly IUnityContainer _container; /// /// Initializes a new instance of the class. @@ -19,7 +18,7 @@ public class UnityDependencyConfigurator : IDependencyConfigurator /// The Unity container instance public UnityDependencyConfigurator(IUnityContainer container) { - this.container = container; + _container = container; } /// @@ -28,7 +27,7 @@ public IDependencyConfigurator Add( Type implementationType, InstanceLifetime lifetime) { - this.container.RegisterType( + _container.RegisterType( serviceType, implementationType, (ITypeLifetimeManager)ParseLifetime(lifetime)); @@ -40,7 +39,7 @@ public IDependencyConfigurator Add(InstanceLifetime l where TService : class where TImplementation : class, TService { - this.container.RegisterType((ITypeLifetimeManager)ParseLifetime(lifetime)); + _container.RegisterType((ITypeLifetimeManager)ParseLifetime(lifetime)); return this; } @@ -48,7 +47,7 @@ public IDependencyConfigurator Add(InstanceLifetime l public IDependencyConfigurator Add(InstanceLifetime lifetime) where TService : class { - this.container.RegisterType((ITypeLifetimeManager)ParseLifetime(lifetime)); + _container.RegisterType((ITypeLifetimeManager)ParseLifetime(lifetime)); return this; } @@ -56,7 +55,7 @@ public IDependencyConfigurator Add(InstanceLifetime lifetime) public IDependencyConfigurator Add(TImplementation service) where TImplementation : class { - this.container.RegisterInstance(service); + _container.RegisterInstance(service); return this; } @@ -73,7 +72,7 @@ public IDependencyConfigurator Add( name = Guid.NewGuid().ToString(); } - this.container.RegisterFactory( + _container.RegisterFactory( serviceType, name, c => factory(new UnityDependencyResolver(c)), @@ -82,11 +81,6 @@ public IDependencyConfigurator Add( return this; } - private bool AlreadyRegistered(Type registeredType) - { - return this.container.Registrations.Any(x => x.RegisteredType == registeredType); - } - private static object ParseLifetime(InstanceLifetime lifetime) => lifetime switch { @@ -95,5 +89,10 @@ private static object ParseLifetime(InstanceLifetime lifetime) => InstanceLifetime.Transient => new TransientLifetimeManager(), _ => throw new InvalidCastException($"There is not mapping defined to {lifetime}") }; + + private bool AlreadyRegistered(Type registeredType) + { + return _container.Registrations.Any(x => x.RegisteredType == registeredType); + } } } diff --git a/src/KafkaFlow.Unity/UnityDependencyResolver.cs b/src/KafkaFlow.Unity/UnityDependencyResolver.cs index 35b06c43f..b98099735 100644 --- a/src/KafkaFlow.Unity/UnityDependencyResolver.cs +++ b/src/KafkaFlow.Unity/UnityDependencyResolver.cs @@ -1,35 +1,35 @@ +using System; +using System.Collections.Generic; +using global::Unity; + namespace KafkaFlow.Unity { - using System; - using System.Collections.Generic; - using global::Unity; - /// /// Unity implementation of /// public class UnityDependencyResolver : IDependencyResolver { - private readonly IUnityContainer container; + private readonly IUnityContainer _container; /// /// Initializes a new instance of the class. /// /// A Unity container instance - public UnityDependencyResolver(IUnityContainer container) => this.container = container; + public UnityDependencyResolver(IUnityContainer container) => _container = container; /// public IDependencyResolverScope CreateScope() => - new UnityDependencyResolverScope(this.container.CreateChildContainer()); + new UnityDependencyResolverScope(_container.CreateChildContainer()); /// - public object Resolve(Type type) => this.container.Resolve(type); + public object Resolve(Type type) => _container.Resolve(type); /// public IEnumerable ResolveAll(Type type) { - yield return this.container.Resolve(type); + yield return _container.Resolve(type); - foreach (var instance in this.container.ResolveAll(type)) + foreach (var instance in _container.ResolveAll(type)) { yield return instance; } diff --git a/src/KafkaFlow.Unity/UnityDependencyResolverScope.cs b/src/KafkaFlow.Unity/UnityDependencyResolverScope.cs index 5a5bf27ba..c0aa31e8b 100644 --- a/src/KafkaFlow.Unity/UnityDependencyResolverScope.cs +++ b/src/KafkaFlow.Unity/UnityDependencyResolverScope.cs @@ -1,19 +1,19 @@ +using global::Unity; + namespace KafkaFlow.Unity { - using global::Unity; - internal class UnityDependencyResolverScope : IDependencyResolverScope { - private readonly IUnityContainer container; + private readonly IUnityContainer _container; public UnityDependencyResolverScope(IUnityContainer container) { - this.container = container; + _container = container; this.Resolver = new UnityDependencyResolver(container); } public IDependencyResolver Resolver { get; } - public void Dispose() => this.container.Dispose(); + public void Dispose() => _container.Dispose(); } } diff --git a/src/KafkaFlow.sln b/src/KafkaFlow.sln deleted file mode 100644 index b78e82c70..000000000 --- a/src/KafkaFlow.sln +++ /dev/null @@ -1,259 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.7.34031.279 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow", "KafkaFlow\KafkaFlow.csproj", "{E1055352-9F5B-4980-80A3-50C335B79A16}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Compressor.Gzip", "KafkaFlow.Compressor.Gzip\KafkaFlow.Compressor.Gzip.csproj", "{B668ACDA-5E45-4985-9D33-6EDFF9059D9A}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Serializer.JsonCore", "KafkaFlow.Serializer.JsonCore\KafkaFlow.Serializer.JsonCore.csproj", "{42CFFA0D-3BF2-42F0-A1B0-BDCD30CBB470}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Serializer.ProtobufNet", "KafkaFlow.Serializer.ProtobufNet\KafkaFlow.Serializer.ProtobufNet.csproj", "{8917E0B9-A943-46FB-8E91-6E9B91F976F6}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.UnitTests", "KafkaFlow.UnitTests\KafkaFlow.UnitTests.csproj", "{CE82B50F-6C03-4875-ADF5-63FD5B7F1AF8}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Framework", "Framework", "{068CB250-2804-4C7E-9490-17F432B9CE21}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{7A9B997B-DAAC-4004-94F3-32F6B88E0068}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{303AE78F-6C96-4DF4-AC89-5C4FD53AFF0B}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Serialization", "Serialization", "{ADAAA63C-E17C-4F1B-A062-3CCA071D75C2}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Compression", "Compression", "{0A782A83-B66D-4B99-9BE2-2B18AAD2E03C}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Abstractions", "KafkaFlow.Abstractions\KafkaFlow.Abstractions.csproj", "{88808771-56BE-422B-94DC-7AB070F64E98}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.IntegrationTests", "KafkaFlow.IntegrationTests\KafkaFlow.IntegrationTests.csproj", "{36F459F4-8323-472A-A8C5-8C9D89F92012}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Serializer.NewtonsoftJson", "KafkaFlow.Serializer.NewtonsoftJson\KafkaFlow.Serializer.NewtonsoftJson.csproj", "{FC622AB0-6481-4249-8D83-27BC39912103}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DependencyResolvers", "DependencyResolvers", "{292BCEDD-55B4-49BB-B8B2-24CD834FF2AA}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Microsoft.DependencyInjection", "KafkaFlow.Microsoft.DependencyInjection\KafkaFlow.Microsoft.DependencyInjection.csproj", "{B86A51E3-7AC9-4EF8-BD2A-1ACC9EF0F5AE}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Unity", "KafkaFlow.Unity\KafkaFlow.Unity.csproj", "{22DB5734-E792-4309-B565-77F02D27D88C}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Sample", "..\samples\KafkaFlow.Sample\KafkaFlow.Sample.csproj", "{E59C13AF-41E7-4DFA-B118-A65EA87F0605}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "LogHandlers", "LogHandlers", "{EF626895-FDAE-4B28-9110-BA85671CBBF2}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.LogHandler.Console", "KafkaFlow.LogHandler.Console\KafkaFlow.LogHandler.Console.csproj", "{6E9F7CDC-E935-4A51-9358-2E6DBB901A34}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Admin", "Admin", "{58483813-0D7C-423E-8E7D-8FBF3E6CDB6D}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Admin", "KafkaFlow.Admin\KafkaFlow.Admin.csproj", "{46B6F104-D46E-4DC2-ADC2-18E76F5BBCD9}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Admin.WebApi", "KafkaFlow.Admin.WebApi\KafkaFlow.Admin.WebApi.csproj", "{827620D3-2258-410E-A79E-E782ED42284C}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Sample.WebApi", "..\samples\KafkaFlow.Sample.WebApi\KafkaFlow.Sample.WebApi.csproj", "{15C12D0C-FE8A-41F9-BBCF-5A963F05D5C7}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro", "KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro\KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro.csproj", "{2E63A019-F8AD-4EC3-A80A-F560DEC7C5B4}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Middlewares", "Middlewares", "{ED24B548-6F37-4283-A35B-F6015BFB7A34}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Sample.BatchOperations", "..\samples\KafkaFlow.Sample.BatchOperations\KafkaFlow.Sample.BatchOperations.csproj", "{DE8A8871-B19E-489D-8292-386A06A4CDFA}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Extensions.Hosting", "KafkaFlow.Extensions.Hosting\KafkaFlow.Extensions.Hosting.csproj", "{7913342E-80FD-4094-B892-18DAA2E6948F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.SchemaRegistry", "KafkaFlow.SchemaRegistry\KafkaFlow.SchemaRegistry.csproj", "{98C9826C-76F6-4C21-8A32-D55C2647905B}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Serializer.SchemaRegistry.ConfluentJson", "KafkaFlow.Serializer.SchemaRegistry.ConfluentJson\KafkaFlow.Serializer.SchemaRegistry.ConfluentJson.csproj", "{582D0B0C-F331-45A0-B4D8-CE9DC24F5389}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf", "KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf\KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf.csproj", "{F212D09B-9AD6-428F-9008-38BF1F470B3A}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Admin.Dashboard", "KafkaFlow.Admin.Dashboard\KafkaFlow.Admin.Dashboard.csproj", "{4072F646-9393-4BF3-A479-0550AC1BB6C4}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Sample.Dashboard", "..\samples\KafkaFlow.Sample.Dashboard\KafkaFlow.Sample.Dashboard.csproj", "{F32DC7DA-36EA-4199-91F5-81960FD9C650}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Sample.SchemaRegistry", "..\samples\KafkaFlow.Sample.SchemaRegistry\KafkaFlow.Sample.SchemaRegistry.csproj", "{2BD49C06-7A88-4B98-91B0-659282D2A45E}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Sample.FlowControl", "..\samples\KafkaFlow.Sample.FlowControl\KafkaFlow.Sample.FlowControl.csproj", "{7B61C99E-3AEB-4497-8A38-F780CB309130}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Deploy", "Deploy", "{4A6A390C-A63A-4371-86BB-28481AD6D4C0}" - ProjectSection(SolutionItems) = preProject - ..\.github\workflows\build.yml = ..\.github\workflows\build.yml - ..\.github\workflows\publish.yml = ..\.github\workflows\publish.yml - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.LogHandler.Microsoft", "KafkaFlow.LogHandler.Microsoft\KafkaFlow.LogHandler.Microsoft.csproj", "{8EAF0D96-F760-4FEF-9237-92779F66482D}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Sample.PauseConsumerOnError", "..\samples\KafkaFlow.Sample.PauseConsumerOnError\KafkaFlow.Sample.PauseConsumerOnError.csproj", "{B4A9E7CE-7A37-411E-967E-D9B5FD1A3992}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.Sample.ConsumerThrottling", "..\samples\KafkaFlow.Sample.ConsumerThrottling\KafkaFlow.Sample.ConsumerThrottling.csproj", "{4A16F519-FAF8-432C-AD0A-CC44F7BD392D}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Telemetry", "Telemetry", "{96F5D441-B8DE-4ABC-BEF2-F758D1B2BA39}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KafkaFlow.OpenTelemetry", "KafkaFlow.OpenTelemetry\KafkaFlow.OpenTelemetry.csproj", "{1557B135-4925-4FA2-80DA-8AD13155F3BD}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KafkaFlow.Sample.WildcardConsumer", "..\samples\KafkaFlow.Sample.WildcardConsumer\KafkaFlow.Sample.WildcardConsumer.csproj", "{E3A02BB4-6881-4568-B92F-CC0878BD8175}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E1055352-9F5B-4980-80A3-50C335B79A16}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E1055352-9F5B-4980-80A3-50C335B79A16}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E1055352-9F5B-4980-80A3-50C335B79A16}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E1055352-9F5B-4980-80A3-50C335B79A16}.Release|Any CPU.Build.0 = Release|Any CPU - {B668ACDA-5E45-4985-9D33-6EDFF9059D9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B668ACDA-5E45-4985-9D33-6EDFF9059D9A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B668ACDA-5E45-4985-9D33-6EDFF9059D9A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B668ACDA-5E45-4985-9D33-6EDFF9059D9A}.Release|Any CPU.Build.0 = Release|Any CPU - {42CFFA0D-3BF2-42F0-A1B0-BDCD30CBB470}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {42CFFA0D-3BF2-42F0-A1B0-BDCD30CBB470}.Debug|Any CPU.Build.0 = Debug|Any CPU - {42CFFA0D-3BF2-42F0-A1B0-BDCD30CBB470}.Release|Any CPU.ActiveCfg = Release|Any CPU - {42CFFA0D-3BF2-42F0-A1B0-BDCD30CBB470}.Release|Any CPU.Build.0 = Release|Any CPU - {8917E0B9-A943-46FB-8E91-6E9B91F976F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8917E0B9-A943-46FB-8E91-6E9B91F976F6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8917E0B9-A943-46FB-8E91-6E9B91F976F6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8917E0B9-A943-46FB-8E91-6E9B91F976F6}.Release|Any CPU.Build.0 = Release|Any CPU - {CE82B50F-6C03-4875-ADF5-63FD5B7F1AF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CE82B50F-6C03-4875-ADF5-63FD5B7F1AF8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CE82B50F-6C03-4875-ADF5-63FD5B7F1AF8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CE82B50F-6C03-4875-ADF5-63FD5B7F1AF8}.Release|Any CPU.Build.0 = Release|Any CPU - {88808771-56BE-422B-94DC-7AB070F64E98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {88808771-56BE-422B-94DC-7AB070F64E98}.Debug|Any CPU.Build.0 = Debug|Any CPU - {88808771-56BE-422B-94DC-7AB070F64E98}.Release|Any CPU.ActiveCfg = Release|Any CPU - {88808771-56BE-422B-94DC-7AB070F64E98}.Release|Any CPU.Build.0 = Release|Any CPU - {36F459F4-8323-472A-A8C5-8C9D89F92012}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {36F459F4-8323-472A-A8C5-8C9D89F92012}.Debug|Any CPU.Build.0 = Debug|Any CPU - {36F459F4-8323-472A-A8C5-8C9D89F92012}.Release|Any CPU.ActiveCfg = Release|Any CPU - {36F459F4-8323-472A-A8C5-8C9D89F92012}.Release|Any CPU.Build.0 = Release|Any CPU - {FC622AB0-6481-4249-8D83-27BC39912103}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FC622AB0-6481-4249-8D83-27BC39912103}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FC622AB0-6481-4249-8D83-27BC39912103}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FC622AB0-6481-4249-8D83-27BC39912103}.Release|Any CPU.Build.0 = Release|Any CPU - {B86A51E3-7AC9-4EF8-BD2A-1ACC9EF0F5AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B86A51E3-7AC9-4EF8-BD2A-1ACC9EF0F5AE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B86A51E3-7AC9-4EF8-BD2A-1ACC9EF0F5AE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B86A51E3-7AC9-4EF8-BD2A-1ACC9EF0F5AE}.Release|Any CPU.Build.0 = Release|Any CPU - {22DB5734-E792-4309-B565-77F02D27D88C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {22DB5734-E792-4309-B565-77F02D27D88C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {22DB5734-E792-4309-B565-77F02D27D88C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {22DB5734-E792-4309-B565-77F02D27D88C}.Release|Any CPU.Build.0 = Release|Any CPU - {E59C13AF-41E7-4DFA-B118-A65EA87F0605}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E59C13AF-41E7-4DFA-B118-A65EA87F0605}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E59C13AF-41E7-4DFA-B118-A65EA87F0605}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E59C13AF-41E7-4DFA-B118-A65EA87F0605}.Release|Any CPU.Build.0 = Release|Any CPU - {6E9F7CDC-E935-4A51-9358-2E6DBB901A34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6E9F7CDC-E935-4A51-9358-2E6DBB901A34}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6E9F7CDC-E935-4A51-9358-2E6DBB901A34}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6E9F7CDC-E935-4A51-9358-2E6DBB901A34}.Release|Any CPU.Build.0 = Release|Any CPU - {46B6F104-D46E-4DC2-ADC2-18E76F5BBCD9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {46B6F104-D46E-4DC2-ADC2-18E76F5BBCD9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {46B6F104-D46E-4DC2-ADC2-18E76F5BBCD9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {46B6F104-D46E-4DC2-ADC2-18E76F5BBCD9}.Release|Any CPU.Build.0 = Release|Any CPU - {827620D3-2258-410E-A79E-E782ED42284C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {827620D3-2258-410E-A79E-E782ED42284C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {827620D3-2258-410E-A79E-E782ED42284C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {827620D3-2258-410E-A79E-E782ED42284C}.Release|Any CPU.Build.0 = Release|Any CPU - {15C12D0C-FE8A-41F9-BBCF-5A963F05D5C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {15C12D0C-FE8A-41F9-BBCF-5A963F05D5C7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {15C12D0C-FE8A-41F9-BBCF-5A963F05D5C7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {15C12D0C-FE8A-41F9-BBCF-5A963F05D5C7}.Release|Any CPU.Build.0 = Release|Any CPU - {2E63A019-F8AD-4EC3-A80A-F560DEC7C5B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2E63A019-F8AD-4EC3-A80A-F560DEC7C5B4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2E63A019-F8AD-4EC3-A80A-F560DEC7C5B4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2E63A019-F8AD-4EC3-A80A-F560DEC7C5B4}.Release|Any CPU.Build.0 = Release|Any CPU - {DE8A8871-B19E-489D-8292-386A06A4CDFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DE8A8871-B19E-489D-8292-386A06A4CDFA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DE8A8871-B19E-489D-8292-386A06A4CDFA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DE8A8871-B19E-489D-8292-386A06A4CDFA}.Release|Any CPU.Build.0 = Release|Any CPU - {7913342E-80FD-4094-B892-18DAA2E6948F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7913342E-80FD-4094-B892-18DAA2E6948F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7913342E-80FD-4094-B892-18DAA2E6948F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7913342E-80FD-4094-B892-18DAA2E6948F}.Release|Any CPU.Build.0 = Release|Any CPU - {98C9826C-76F6-4C21-8A32-D55C2647905B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {98C9826C-76F6-4C21-8A32-D55C2647905B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {98C9826C-76F6-4C21-8A32-D55C2647905B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {98C9826C-76F6-4C21-8A32-D55C2647905B}.Release|Any CPU.Build.0 = Release|Any CPU - {582D0B0C-F331-45A0-B4D8-CE9DC24F5389}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {582D0B0C-F331-45A0-B4D8-CE9DC24F5389}.Debug|Any CPU.Build.0 = Debug|Any CPU - {582D0B0C-F331-45A0-B4D8-CE9DC24F5389}.Release|Any CPU.ActiveCfg = Release|Any CPU - {582D0B0C-F331-45A0-B4D8-CE9DC24F5389}.Release|Any CPU.Build.0 = Release|Any CPU - {F212D09B-9AD6-428F-9008-38BF1F470B3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F212D09B-9AD6-428F-9008-38BF1F470B3A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F212D09B-9AD6-428F-9008-38BF1F470B3A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F212D09B-9AD6-428F-9008-38BF1F470B3A}.Release|Any CPU.Build.0 = Release|Any CPU - {4072F646-9393-4BF3-A479-0550AC1BB6C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4072F646-9393-4BF3-A479-0550AC1BB6C4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4072F646-9393-4BF3-A479-0550AC1BB6C4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4072F646-9393-4BF3-A479-0550AC1BB6C4}.Release|Any CPU.Build.0 = Release|Any CPU - {F32DC7DA-36EA-4199-91F5-81960FD9C650}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F32DC7DA-36EA-4199-91F5-81960FD9C650}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F32DC7DA-36EA-4199-91F5-81960FD9C650}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F32DC7DA-36EA-4199-91F5-81960FD9C650}.Release|Any CPU.Build.0 = Release|Any CPU - {2BD49C06-7A88-4B98-91B0-659282D2A45E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2BD49C06-7A88-4B98-91B0-659282D2A45E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2BD49C06-7A88-4B98-91B0-659282D2A45E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2BD49C06-7A88-4B98-91B0-659282D2A45E}.Release|Any CPU.Build.0 = Release|Any CPU - {7B61C99E-3AEB-4497-8A38-F780CB309130}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7B61C99E-3AEB-4497-8A38-F780CB309130}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7B61C99E-3AEB-4497-8A38-F780CB309130}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7B61C99E-3AEB-4497-8A38-F780CB309130}.Release|Any CPU.Build.0 = Release|Any CPU - {8EAF0D96-F760-4FEF-9237-92779F66482D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8EAF0D96-F760-4FEF-9237-92779F66482D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8EAF0D96-F760-4FEF-9237-92779F66482D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8EAF0D96-F760-4FEF-9237-92779F66482D}.Release|Any CPU.Build.0 = Release|Any CPU - {B4A9E7CE-7A37-411E-967E-D9B5FD1A3992}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B4A9E7CE-7A37-411E-967E-D9B5FD1A3992}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B4A9E7CE-7A37-411E-967E-D9B5FD1A3992}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B4A9E7CE-7A37-411E-967E-D9B5FD1A3992}.Release|Any CPU.Build.0 = Release|Any CPU - {4A16F519-FAF8-432C-AD0A-CC44F7BD392D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4A16F519-FAF8-432C-AD0A-CC44F7BD392D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4A16F519-FAF8-432C-AD0A-CC44F7BD392D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4A16F519-FAF8-432C-AD0A-CC44F7BD392D}.Release|Any CPU.Build.0 = Release|Any CPU - {1557B135-4925-4FA2-80DA-8AD13155F3BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1557B135-4925-4FA2-80DA-8AD13155F3BD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1557B135-4925-4FA2-80DA-8AD13155F3BD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1557B135-4925-4FA2-80DA-8AD13155F3BD}.Release|Any CPU.Build.0 = Release|Any CPU - {E3A02BB4-6881-4568-B92F-CC0878BD8175}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E3A02BB4-6881-4568-B92F-CC0878BD8175}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E3A02BB4-6881-4568-B92F-CC0878BD8175}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E3A02BB4-6881-4568-B92F-CC0878BD8175}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {E1055352-9F5B-4980-80A3-50C335B79A16} = {068CB250-2804-4C7E-9490-17F432B9CE21} - {B668ACDA-5E45-4985-9D33-6EDFF9059D9A} = {0A782A83-B66D-4B99-9BE2-2B18AAD2E03C} - {42CFFA0D-3BF2-42F0-A1B0-BDCD30CBB470} = {ADAAA63C-E17C-4F1B-A062-3CCA071D75C2} - {8917E0B9-A943-46FB-8E91-6E9B91F976F6} = {ADAAA63C-E17C-4F1B-A062-3CCA071D75C2} - {CE82B50F-6C03-4875-ADF5-63FD5B7F1AF8} = {7A9B997B-DAAC-4004-94F3-32F6B88E0068} - {ADAAA63C-E17C-4F1B-A062-3CCA071D75C2} = {ED24B548-6F37-4283-A35B-F6015BFB7A34} - {0A782A83-B66D-4B99-9BE2-2B18AAD2E03C} = {ED24B548-6F37-4283-A35B-F6015BFB7A34} - {88808771-56BE-422B-94DC-7AB070F64E98} = {068CB250-2804-4C7E-9490-17F432B9CE21} - {36F459F4-8323-472A-A8C5-8C9D89F92012} = {7A9B997B-DAAC-4004-94F3-32F6B88E0068} - {FC622AB0-6481-4249-8D83-27BC39912103} = {ADAAA63C-E17C-4F1B-A062-3CCA071D75C2} - {B86A51E3-7AC9-4EF8-BD2A-1ACC9EF0F5AE} = {292BCEDD-55B4-49BB-B8B2-24CD834FF2AA} - {22DB5734-E792-4309-B565-77F02D27D88C} = {292BCEDD-55B4-49BB-B8B2-24CD834FF2AA} - {E59C13AF-41E7-4DFA-B118-A65EA87F0605} = {303AE78F-6C96-4DF4-AC89-5C4FD53AFF0B} - {6E9F7CDC-E935-4A51-9358-2E6DBB901A34} = {EF626895-FDAE-4B28-9110-BA85671CBBF2} - {46B6F104-D46E-4DC2-ADC2-18E76F5BBCD9} = {58483813-0D7C-423E-8E7D-8FBF3E6CDB6D} - {827620D3-2258-410E-A79E-E782ED42284C} = {58483813-0D7C-423E-8E7D-8FBF3E6CDB6D} - {15C12D0C-FE8A-41F9-BBCF-5A963F05D5C7} = {303AE78F-6C96-4DF4-AC89-5C4FD53AFF0B} - {2E63A019-F8AD-4EC3-A80A-F560DEC7C5B4} = {ADAAA63C-E17C-4F1B-A062-3CCA071D75C2} - {DE8A8871-B19E-489D-8292-386A06A4CDFA} = {303AE78F-6C96-4DF4-AC89-5C4FD53AFF0B} - {7913342E-80FD-4094-B892-18DAA2E6948F} = {068CB250-2804-4C7E-9490-17F432B9CE21} - {98C9826C-76F6-4C21-8A32-D55C2647905B} = {ADAAA63C-E17C-4F1B-A062-3CCA071D75C2} - {582D0B0C-F331-45A0-B4D8-CE9DC24F5389} = {ADAAA63C-E17C-4F1B-A062-3CCA071D75C2} - {F212D09B-9AD6-428F-9008-38BF1F470B3A} = {ADAAA63C-E17C-4F1B-A062-3CCA071D75C2} - {4072F646-9393-4BF3-A479-0550AC1BB6C4} = {58483813-0D7C-423E-8E7D-8FBF3E6CDB6D} - {F32DC7DA-36EA-4199-91F5-81960FD9C650} = {303AE78F-6C96-4DF4-AC89-5C4FD53AFF0B} - {2BD49C06-7A88-4B98-91B0-659282D2A45E} = {303AE78F-6C96-4DF4-AC89-5C4FD53AFF0B} - {7B61C99E-3AEB-4497-8A38-F780CB309130} = {303AE78F-6C96-4DF4-AC89-5C4FD53AFF0B} - {8EAF0D96-F760-4FEF-9237-92779F66482D} = {EF626895-FDAE-4B28-9110-BA85671CBBF2} - {B4A9E7CE-7A37-411E-967E-D9B5FD1A3992} = {303AE78F-6C96-4DF4-AC89-5C4FD53AFF0B} - {4A16F519-FAF8-432C-AD0A-CC44F7BD392D} = {303AE78F-6C96-4DF4-AC89-5C4FD53AFF0B} - {1557B135-4925-4FA2-80DA-8AD13155F3BD} = {96F5D441-B8DE-4ABC-BEF2-F758D1B2BA39} - {E3A02BB4-6881-4568-B92F-CC0878BD8175} = {303AE78F-6C96-4DF4-AC89-5C4FD53AFF0B} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {6AE955B5-16B0-41CF-9F12-66D15B3DD1AB} - EndGlobalSection -EndGlobal diff --git a/src/KafkaFlow/Batching/BatchConsumeMessageContext.cs b/src/KafkaFlow/Batching/BatchConsumeMessageContext.cs index b398876ae..8fdbf72e3 100644 --- a/src/KafkaFlow/Batching/BatchConsumeMessageContext.cs +++ b/src/KafkaFlow/Batching/BatchConsumeMessageContext.cs @@ -1,11 +1,11 @@ +using System; +using System.Collections.Generic; + namespace KafkaFlow.Batching { - using System; - using System.Collections.Generic; - internal class BatchConsumeMessageContext : IMessageContext, IDisposable { - private readonly IDependencyResolverScope batchDependencyScope; + private readonly IDependencyResolverScope _batchDependencyScope; public BatchConsumeMessageContext( IConsumerContext consumer, @@ -14,7 +14,7 @@ public BatchConsumeMessageContext( { this.ConsumerContext = consumer; this.Message = new Message(null, batchMessage); - this.batchDependencyScope = consumer.WorkerDependencyResolver.CreateScope(); + _batchDependencyScope = consumer.WorkerDependencyResolver.CreateScope(); this.Items = new Dictionary(); this.Brokers = brokers; } @@ -27,7 +27,7 @@ public BatchConsumeMessageContext( public IProducerContext ProducerContext => null; - public IDependencyResolver DependencyResolver => this.batchDependencyScope.Resolver; + public IDependencyResolver DependencyResolver => _batchDependencyScope.Resolver; public IDictionary Items { get; } @@ -36,6 +36,6 @@ public BatchConsumeMessageContext( public IMessageContext SetMessage(object key, object value) => throw new NotSupportedException($"{nameof(BatchConsumeMessageContext)} does not allow to change the message"); - public void Dispose() => this.batchDependencyScope.Dispose(); + public void Dispose() => _batchDependencyScope.Dispose(); } } diff --git a/src/KafkaFlow/Batching/BatchConsumeMiddleware.cs b/src/KafkaFlow/Batching/BatchConsumeMiddleware.cs index c371bb80f..b4819de79 100644 --- a/src/KafkaFlow/Batching/BatchConsumeMiddleware.cs +++ b/src/KafkaFlow/Batching/BatchConsumeMiddleware.cs @@ -1,25 +1,25 @@ -namespace KafkaFlow.Batching +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using KafkaFlow.Configuration; +using KafkaFlow.Consumers; + +namespace KafkaFlow.Batching { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Threading; - using System.Threading.Tasks; - using KafkaFlow.Configuration; - using KafkaFlow.Consumers; - internal class BatchConsumeMiddleware : IMessageMiddleware, IDisposable { - private readonly SemaphoreSlim dispatchSemaphore = new(1, 1); + private readonly SemaphoreSlim _dispatchSemaphore = new(1, 1); - private readonly int batchSize; - private readonly TimeSpan batchTimeout; - private readonly ILogHandler logHandler; - private readonly IConsumerConfiguration consumerConfiguration; + private readonly int _batchSize; + private readonly TimeSpan _batchTimeout; + private readonly ILogHandler _logHandler; + private readonly IConsumerConfiguration _consumerConfiguration; - private readonly List batch; - private CancellationTokenSource dispatchTokenSource; - private Task dispatchTask; + private readonly List _batch; + private CancellationTokenSource _dispatchTokenSource; + private Task _dispatchTask; public BatchConsumeMiddleware( IConsumerMiddlewareContext middlewareContext, @@ -27,26 +27,26 @@ public BatchConsumeMiddleware( TimeSpan batchTimeout, ILogHandler logHandler) { - this.batchSize = batchSize; - this.batchTimeout = batchTimeout; - this.logHandler = logHandler; - this.batch = new(batchSize); - this.consumerConfiguration = middlewareContext.Consumer.Configuration; + _batchSize = batchSize; + _batchTimeout = batchTimeout; + _logHandler = logHandler; + _batch = new(batchSize); + _consumerConfiguration = middlewareContext.Consumer.Configuration; middlewareContext.Worker.WorkerStopped.Subscribe(() => this.TriggerDispatchAndWaitAsync()); } public async Task Invoke(IMessageContext context, MiddlewareDelegate next) { - await this.dispatchSemaphore.WaitAsync(); + await _dispatchSemaphore.WaitAsync(); try { context.ConsumerContext.AutoMessageCompletion = false; - this.batch.Add(context); + _batch.Add(context); - if (this.batch.Count == 1) + if (_batch.Count == 1) { this.ScheduleExecution(context, next); return; @@ -54,10 +54,10 @@ public async Task Invoke(IMessageContext context, MiddlewareDelegate next) } finally { - this.dispatchSemaphore.Release(); + _dispatchSemaphore.Release(); } - if (this.batch.Count >= this.batchSize) + if (_batch.Count >= _batchSize) { await this.TriggerDispatchAndWaitAsync(); } @@ -65,26 +65,26 @@ public async Task Invoke(IMessageContext context, MiddlewareDelegate next) public void Dispose() { - this.dispatchTask?.Dispose(); - this.dispatchTokenSource?.Dispose(); - this.dispatchSemaphore.Dispose(); + _dispatchTask?.Dispose(); + _dispatchTokenSource?.Dispose(); + _dispatchSemaphore.Dispose(); } private async Task TriggerDispatchAndWaitAsync() { - await this.dispatchSemaphore.WaitAsync(); - this.dispatchTokenSource?.Cancel(); - this.dispatchSemaphore.Release(); + await _dispatchSemaphore.WaitAsync(); + _dispatchTokenSource?.Cancel(); + _dispatchSemaphore.Release(); - await (this.dispatchTask ?? Task.CompletedTask); + await (_dispatchTask ?? Task.CompletedTask); } private void ScheduleExecution(IMessageContext context, MiddlewareDelegate next) { - this.dispatchTokenSource = CancellationTokenSource.CreateLinkedTokenSource(context.ConsumerContext.WorkerStopped); + _dispatchTokenSource = CancellationTokenSource.CreateLinkedTokenSource(context.ConsumerContext.WorkerStopped); - this.dispatchTask = Task - .Delay(this.batchTimeout, this.dispatchTokenSource.Token) + _dispatchTask = Task + .Delay(_batchTimeout, _dispatchTokenSource.Token) .ContinueWith( _ => this.DispatchAsync(context, next), CancellationToken.None); @@ -92,12 +92,12 @@ private void ScheduleExecution(IMessageContext context, MiddlewareDelegate next) private async Task DispatchAsync(IMessageContext context, MiddlewareDelegate next) { - await this.dispatchSemaphore.WaitAsync(); + await _dispatchSemaphore.WaitAsync(); - this.dispatchTokenSource.Dispose(); - this.dispatchTokenSource = null; + _dispatchTokenSource.Dispose(); + _dispatchTokenSource = null; - var localBatch = this.batch.ToList(); + var localBatch = _batch.ToList(); try { @@ -106,7 +106,7 @@ private async Task DispatchAsync(IMessageContext context, MiddlewareDelegate nex return; } - var batchContext = new BatchConsumeMessageContext(context.ConsumerContext, localBatch, this.consumerConfiguration.ClusterConfiguration.Brokers); + var batchContext = new BatchConsumeMessageContext(context.ConsumerContext, localBatch, _consumerConfiguration.ClusterConfiguration.Brokers); await next(batchContext).ConfigureAwait(false); } @@ -119,7 +119,7 @@ private async Task DispatchAsync(IMessageContext context, MiddlewareDelegate nex } catch (Exception ex) { - this.logHandler.Error( + _logHandler.Error( "Error executing a message batch", ex, new @@ -131,10 +131,10 @@ private async Task DispatchAsync(IMessageContext context, MiddlewareDelegate nex } finally { - this.batch.Clear(); - this.dispatchSemaphore.Release(); + _batch.Clear(); + _dispatchSemaphore.Release(); - if (this.consumerConfiguration.AutoMessageCompletion) + if (_consumerConfiguration.AutoMessageCompletion) { foreach (var messageContext in localBatch) { diff --git a/src/KafkaFlow/Batching/BatchingExtensions.cs b/src/KafkaFlow/Batching/BatchingExtensions.cs index 00b100aa4..d79253dc7 100644 --- a/src/KafkaFlow/Batching/BatchingExtensions.cs +++ b/src/KafkaFlow/Batching/BatchingExtensions.cs @@ -1,11 +1,11 @@ +using System; +using System.Collections.Generic; +using KafkaFlow.Batching; +using KafkaFlow.Configuration; +using KafkaFlow.Consumers; + namespace KafkaFlow { - using System; - using System.Collections.Generic; - using KafkaFlow.Batching; - using KafkaFlow.Configuration; - using KafkaFlow.Consumers; - /// /// no needed /// diff --git a/src/KafkaFlow/Clusters/ClusterManager.cs b/src/KafkaFlow/Clusters/ClusterManager.cs index aeca278af..5b6f3d1c2 100644 --- a/src/KafkaFlow/Clusters/ClusterManager.cs +++ b/src/KafkaFlow/Clusters/ClusterManager.cs @@ -1,30 +1,28 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Confluent.Kafka; +using Confluent.Kafka.Admin; +using KafkaFlow.Configuration; + namespace KafkaFlow.Clusters { - using System; - using System.Collections.Concurrent; - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - using Confluent.Kafka; - using Confluent.Kafka.Admin; - using KafkaFlow.Configuration; - using TopicMetadata = KafkaFlow.TopicMetadata; - using TopicPartitionOffset = KafkaFlow.TopicPartitionOffset; - internal class ClusterManager : IClusterManager, IDisposable { - private readonly ILogHandler logHandler; - private readonly Lazy lazyAdminClient; - private readonly ClusterConfiguration configuration; + private readonly ILogHandler _logHandler; + private readonly Lazy _lazyAdminClient; + private readonly ClusterConfiguration _configuration; - private readonly ConcurrentDictionary topicMetadataCache = new(); + private readonly ConcurrentDictionary _topicMetadataCache = new(); public ClusterManager(ILogHandler logHandler, ClusterConfiguration configuration) { - this.logHandler = logHandler; - this.configuration = configuration; + _logHandler = logHandler; + _configuration = configuration; - this.lazyAdminClient = new Lazy( + _lazyAdminClient = new Lazy( () => { var config = new AdminClientConfig @@ -39,16 +37,16 @@ public ClusterManager(ILogHandler logHandler, ClusterConfiguration configuration }); } - public string ClusterName => this.configuration.Name; + public string ClusterName => _configuration.Name; public ValueTask GetTopicMetadataAsync(string topicName) { return new ValueTask( - this.topicMetadataCache.GetOrAdd( + _topicMetadataCache.GetOrAdd( topicName, _ => { - var metadata = this.lazyAdminClient.Value.GetMetadata(topicName, TimeSpan.FromSeconds(30)); + var metadata = _lazyAdminClient.Value.GetMetadata(topicName, TimeSpan.FromSeconds(30)); if (!metadata.Topics.Any()) { @@ -84,7 +82,7 @@ public async Task> GetConsumerGroupOffsetsAsyn new Partition(partition.Id)))) .ToList(); - var result = await this.lazyAdminClient.Value.ListConsumerGroupOffsetsAsync( + var result = await _lazyAdminClient.Value.ListConsumerGroupOffsetsAsync( new[] { new ConsumerGroupTopicPartitions(consumerGroup, topics) }); if (!result.Any()) @@ -112,7 +110,7 @@ public async Task CreateIfNotExistsAsync(IEnumerable configu }) .ToArray(); - await this.lazyAdminClient.Value.CreateTopicsAsync(topics); + await _lazyAdminClient.Value.CreateTopicsAsync(topics); } catch (CreateTopicsException exception) { @@ -121,7 +119,7 @@ public async Task CreateIfNotExistsAsync(IEnumerable configu { if (exceptionResult.Error.Code == ErrorCode.TopicAlreadyExists) { - this.logHandler.Warning( + _logHandler.Warning( "An error occurred creating topic {Topic}: {Reason}", new { @@ -136,12 +134,12 @@ public async Task CreateIfNotExistsAsync(IEnumerable configu if (hasNonExpectedErrors) { - this.logHandler.Error( + _logHandler.Error( "An error occurred creating topics", exception, new { - Servers = this.configuration.Brokers, + Servers = _configuration.Brokers, }); throw; } @@ -150,9 +148,9 @@ public async Task CreateIfNotExistsAsync(IEnumerable configu public void Dispose() { - if (this.lazyAdminClient.IsValueCreated) + if (_lazyAdminClient.IsValueCreated) { - this.lazyAdminClient.Value.Dispose(); + _lazyAdminClient.Value.Dispose(); } } } diff --git a/src/KafkaFlow/Clusters/ClusterManagerAccessor.cs b/src/KafkaFlow/Clusters/ClusterManagerAccessor.cs index 89abe2751..8e61d681a 100644 --- a/src/KafkaFlow/Clusters/ClusterManagerAccessor.cs +++ b/src/KafkaFlow/Clusters/ClusterManagerAccessor.cs @@ -1,22 +1,22 @@ +using System.Collections.Generic; +using System.Linq; + namespace KafkaFlow.Clusters { - using System.Collections.Generic; - using System.Linq; - internal class ClusterManagerAccessor : IClusterManagerAccessor { - private readonly Dictionary managers; + private readonly Dictionary _managers; public ClusterManagerAccessor(IEnumerable managers) { - this.managers = managers.ToDictionary(manager => manager.ClusterName); + _managers = managers.ToDictionary(manager => manager.ClusterName); } - public IEnumerable All => this.managers.Values; + public IEnumerable All => _managers.Values; public IClusterManager this[string name] => this.GetManager(name); public IClusterManager GetManager(string name) => - this.managers.TryGetValue(name, out var manager) ? manager : null; + _managers.TryGetValue(name, out var manager) ? manager : null; } } diff --git a/src/KafkaFlow/Clusters/IClusterManager.cs b/src/KafkaFlow/Clusters/IClusterManager.cs index 6d2f149b4..d34c2365a 100644 --- a/src/KafkaFlow/Clusters/IClusterManager.cs +++ b/src/KafkaFlow/Clusters/IClusterManager.cs @@ -1,9 +1,9 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using KafkaFlow.Configuration; + namespace KafkaFlow.Clusters { - using System.Collections.Generic; - using System.Threading.Tasks; - using KafkaFlow.Configuration; - /// /// Provides access to Cluster administration /// diff --git a/src/KafkaFlow/Clusters/IClusterManagerAccessor.cs b/src/KafkaFlow/Clusters/IClusterManagerAccessor.cs index 854ccc3e1..509091631 100644 --- a/src/KafkaFlow/Clusters/IClusterManagerAccessor.cs +++ b/src/KafkaFlow/Clusters/IClusterManagerAccessor.cs @@ -1,7 +1,7 @@ +using System.Collections.Generic; + namespace KafkaFlow.Clusters { - using System.Collections.Generic; - /// /// Provides access to the configured cluster manager /// diff --git a/src/KafkaFlow/Configuration/ClusterConfiguration.cs b/src/KafkaFlow/Configuration/ClusterConfiguration.cs index e6299e5da..de20ad6fa 100644 --- a/src/KafkaFlow/Configuration/ClusterConfiguration.cs +++ b/src/KafkaFlow/Configuration/ClusterConfiguration.cs @@ -1,19 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; + namespace KafkaFlow.Configuration { - using System; - using System.Collections.Generic; - using System.Collections.ObjectModel; - using System.Linq; - /// /// Represents the cluster configuration values /// public class ClusterConfiguration { - private readonly Func securityInformationHandler; - private readonly List producers = new(); - private readonly List consumers = new(); - private readonly ReadOnlyCollection topicsToCreateIfNotExist; + private readonly Func _securityInformationHandler; + private readonly List _producers = new(); + private readonly List _consumers = new(); + private readonly ReadOnlyCollection _topicsToCreateIfNotExist; /// /// Initializes a new instance of the class. @@ -34,13 +34,13 @@ public ClusterConfiguration( Action onStoppingHandler, IEnumerable topicsToCreateIfNotExist = null) { - this.securityInformationHandler = securityInformationHandler; - this.Name = name ?? Guid.NewGuid().ToString(); - this.Kafka = kafka; - this.Brokers = brokers.ToList(); - this.OnStoppingHandler = onStoppingHandler; - this.OnStartedHandler = onStartedHandler; - this.topicsToCreateIfNotExist = topicsToCreateIfNotExist?.ToList().AsReadOnly() ?? + _securityInformationHandler = securityInformationHandler; + Name = name ?? Guid.NewGuid().ToString(); + Kafka = kafka; + Brokers = brokers.ToList(); + OnStoppingHandler = onStoppingHandler; + OnStartedHandler = onStartedHandler; + _topicsToCreateIfNotExist = topicsToCreateIfNotExist?.ToList().AsReadOnly() ?? new List().AsReadOnly(); } @@ -62,18 +62,18 @@ public ClusterConfiguration( /// /// Gets the list of producers /// - public IReadOnlyCollection Producers => this.producers.AsReadOnly(); + public IReadOnlyCollection Producers => _producers.AsReadOnly(); /// /// Gets the list of consumers /// - public IReadOnlyCollection Consumers => this.consumers.AsReadOnly(); + public IReadOnlyCollection Consumers => _consumers.AsReadOnly(); /// /// Gets the list of topics to create if they do not exist /// public IReadOnlyCollection TopicsToCreateIfNotExist => - this.topicsToCreateIfNotExist; + _topicsToCreateIfNotExist; /// /// Gets the handler to be executed when the cluster started @@ -90,19 +90,19 @@ public ClusterConfiguration( /// /// A list of consumer configurations public void AddConsumers(IEnumerable configurations) => - this.consumers.AddRange(configurations); + _consumers.AddRange(configurations); /// /// Adds a list of producer configurations /// /// A list of producer configurations public void AddProducers(IEnumerable configurations) => - this.producers.AddRange(configurations); + _producers.AddRange(configurations); /// /// Gets the kafka security information /// /// - public SecurityInformation GetSecurityInformation() => this.securityInformationHandler?.Invoke(); + public SecurityInformation GetSecurityInformation() => _securityInformationHandler?.Invoke(); } } diff --git a/src/KafkaFlow/Configuration/ClusterConfigurationBuilder.cs b/src/KafkaFlow/Configuration/ClusterConfigurationBuilder.cs index ac8c34585..d4c15607a 100644 --- a/src/KafkaFlow/Configuration/ClusterConfigurationBuilder.cs +++ b/src/KafkaFlow/Configuration/ClusterConfigurationBuilder.cs @@ -1,20 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using KafkaFlow.Producers; + namespace KafkaFlow.Configuration { - using System; - using System.Collections.Generic; - using System.Linq; - using KafkaFlow.Producers; - internal class ClusterConfigurationBuilder : IClusterConfigurationBuilder { - private readonly List producers = new(); - private readonly List consumers = new(); - private readonly List topicsToCreateIfNotExist = new(); - private Action onStartedHandler = _ => { }; - private Action onStoppingHandler = _ => { }; - private IEnumerable brokers; - private string name; - private Func securityInformationHandler; + private readonly List _producers = new(); + private readonly List _consumers = new(); + private readonly List _topicsToCreateIfNotExist = new(); + private Action _onStartedHandler = _ => { }; + private Action _onStoppingHandler = _ => { }; + private IEnumerable _brokers; + private string _name; + private Func _securityInformationHandler; public ClusterConfigurationBuilder(IDependencyConfigurator dependencyConfigurator) { @@ -27,35 +27,35 @@ public ClusterConfiguration Build(KafkaConfiguration kafkaConfiguration) { var configuration = new ClusterConfiguration( kafkaConfiguration, - this.name, - this.brokers.ToList(), - this.securityInformationHandler, - this.onStartedHandler, - this.onStoppingHandler, - this.topicsToCreateIfNotExist); + _name, + _brokers.ToList(), + _securityInformationHandler, + _onStartedHandler, + _onStoppingHandler, + _topicsToCreateIfNotExist); - configuration.AddProducers(this.producers.Select(x => x.Build(configuration))); - configuration.AddConsumers(this.consumers.Select(x => x.Build(configuration))); + configuration.AddProducers(_producers.Select(x => x.Build(configuration))); + configuration.AddConsumers(_consumers.Select(x => x.Build(configuration))); return configuration; } public IClusterConfigurationBuilder WithBrokers(IEnumerable brokers) { - this.brokers = brokers; + _brokers = brokers; return this; } public IClusterConfigurationBuilder WithName(string name) { - this.name = name; + _name = name; return this; } public IClusterConfigurationBuilder WithSecurityInformation(Action handler) { // Uses a handler to avoid in-memory stored passwords for long periods - this.securityInformationHandler = () => + _securityInformationHandler = () => { var config = new SecurityInformation(); handler(config); @@ -80,7 +80,7 @@ public IClusterConfigurationBuilder AddProducer(string name, Action handler) { - this.onStoppingHandler = handler; + _onStoppingHandler = handler; return this; } public IClusterConfigurationBuilder OnStarted(Action handler) { - this.onStartedHandler = handler; + _onStartedHandler = handler; return this; } @@ -113,7 +113,7 @@ public IClusterConfigurationBuilder CreateTopicIfNotExists( int numberOfPartitions, short replicationFactor) { - this.topicsToCreateIfNotExist.Add(new TopicConfiguration(topicName, numberOfPartitions, replicationFactor)); + _topicsToCreateIfNotExist.Add(new TopicConfiguration(topicName, numberOfPartitions, replicationFactor)); return this; } } diff --git a/src/KafkaFlow/Configuration/ConsumerConfiguration.cs b/src/KafkaFlow/Configuration/ConsumerConfiguration.cs index 01eca3090..7b59709e4 100644 --- a/src/KafkaFlow/Configuration/ConsumerConfiguration.cs +++ b/src/KafkaFlow/Configuration/ConsumerConfiguration.cs @@ -1,16 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + namespace KafkaFlow.Configuration { - using System; - using System.Collections.Generic; - using System.Threading.Tasks; - using Confluent.Kafka; - internal class ConsumerConfiguration : IConsumerConfiguration { - private readonly ConsumerConfig consumerConfig; + private readonly Confluent.Kafka.ConsumerConfig _consumerConfig; public ConsumerConfiguration( - ConsumerConfig consumerConfig, + Confluent.Kafka.ConsumerConfig consumerConfig, IReadOnlyList topics, IReadOnlyList manualAssignPartitions, string consumerName, @@ -27,14 +26,14 @@ public ConsumerConfiguration( ConsumerInitialState initialState, TimeSpan autoCommitInterval, IReadOnlyList> statisticsHandlers, - IReadOnlyList>> partitionsAssignedHandlers, - IReadOnlyList>> partitionsRevokedHandlers, + IReadOnlyList>> partitionsAssignedHandlers, + IReadOnlyList>> partitionsRevokedHandlers, IReadOnlyList pendingOffsetsStatisticsHandlers, ConsumerCustomFactory customFactory) { - this.consumerConfig = consumerConfig ?? throw new ArgumentNullException(nameof(consumerConfig)); + _consumerConfig = consumerConfig ?? throw new ArgumentNullException(nameof(consumerConfig)); - if (string.IsNullOrEmpty(this.consumerConfig.GroupId)) + if (string.IsNullOrEmpty(_consumerConfig.GroupId)) { throw new ArgumentNullException(nameof(consumerConfig.GroupId)); } @@ -87,7 +86,7 @@ public ConsumerConfiguration( public TimeSpan WorkersCountEvaluationInterval { get; } - public string GroupId => this.consumerConfig.GroupId; + public string GroupId => _consumerConfig.GroupId; public int BufferSize { get; } @@ -103,17 +102,17 @@ public ConsumerConfiguration( public IReadOnlyList> StatisticsHandlers { get; } - public IReadOnlyList>> PartitionsAssignedHandlers { get; } + public IReadOnlyList>> PartitionsAssignedHandlers { get; } - public IReadOnlyList>> PartitionsRevokedHandlers { get; } + public IReadOnlyList>> PartitionsRevokedHandlers { get; } public IReadOnlyList PendingOffsetsStatisticsHandlers { get; } public ConsumerCustomFactory CustomFactory { get; } - public ConsumerConfig GetKafkaConfig() + public Confluent.Kafka.ConsumerConfig GetKafkaConfig() { - return this.consumerConfig; + return _consumerConfig; } } } diff --git a/src/KafkaFlow/Configuration/ConsumerConfigurationBuilder.cs b/src/KafkaFlow/Configuration/ConsumerConfigurationBuilder.cs index b0544080b..ba952b983 100644 --- a/src/KafkaFlow/Configuration/ConsumerConfigurationBuilder.cs +++ b/src/KafkaFlow/Configuration/ConsumerConfigurationBuilder.cs @@ -1,75 +1,74 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Threading.Tasks; +using KafkaFlow.Consumers.DistributionStrategies; + namespace KafkaFlow.Configuration { - using System; - using System.Collections.Generic; - using System.ComponentModel; - using System.Linq; - using System.Threading.Tasks; - using Confluent.Kafka; - using KafkaFlow.Consumers.DistributionStrategies; - internal sealed class ConsumerConfigurationBuilder : IConsumerConfigurationBuilder { - private readonly List topics = new(); - private readonly List topicsPartitions = new(); - private readonly List> statisticsHandlers = new(); + private readonly List _topics = new(); + private readonly List _topicsPartitions = new(); + private readonly List> _statisticsHandlers = new(); - private readonly List pendingOffsetsStatisticsHandlers = new(); + private readonly List _pendingOffsetsStatisticsHandlers = new(); - private readonly List>> partitionAssignedHandlers = new(); - private readonly List>> partitionRevokedHandlers = new(); - private readonly ConsumerMiddlewareConfigurationBuilder middlewareConfigurationBuilder; + private readonly List>> _partitionAssignedHandlers = new(); + private readonly List>> _partitionRevokedHandlers = new(); + private readonly ConsumerMiddlewareConfigurationBuilder _middlewareConfigurationBuilder; - private ConsumerConfig consumerConfig; + private Confluent.Kafka.ConsumerConfig _consumerConfig; - private string name; - private bool disableManagement; - private string groupId = string.Empty; - private AutoOffsetReset? autoOffsetReset; - private int? maxPollIntervalMs; - private Func> workersCountCalculator; - private TimeSpan workersCountEvaluationInterval = TimeSpan.FromMinutes(5); - private int bufferSize; - private TimeSpan workerStopTimeout = TimeSpan.FromSeconds(30); - private bool autoMessageCompletion = true; - private bool noStoreOffsets; - private ConsumerInitialState initialState = ConsumerInitialState.Running; - private int statisticsInterval; + private string _name; + private bool _disableManagement; + private string _groupId = string.Empty; + private Confluent.Kafka.AutoOffsetReset? _autoOffsetReset; + private int? _maxPollIntervalMs; + private Func> _workersCountCalculator; + private TimeSpan _workersCountEvaluationInterval = TimeSpan.FromMinutes(5); + private int _bufferSize; + private TimeSpan _workerStopTimeout = TimeSpan.FromSeconds(30); + private bool _autoMessageCompletion = true; + private bool _noStoreOffsets; + private ConsumerInitialState _initialState = ConsumerInitialState.Running; + private int _statisticsInterval; - private Factory distributionStrategyFactory = _ => new BytesSumDistributionStrategy(); - private TimeSpan autoCommitInterval = TimeSpan.FromSeconds(5); + private Factory _distributionStrategyFactory = _ => new BytesSumDistributionStrategy(); + private TimeSpan _autoCommitInterval = TimeSpan.FromSeconds(5); - private ConsumerCustomFactory customFactory = (consumer, _) => consumer; + private ConsumerCustomFactory _customFactory = (consumer, _) => consumer; public ConsumerConfigurationBuilder(IDependencyConfigurator dependencyConfigurator) { this.DependencyConfigurator = dependencyConfigurator; - this.middlewareConfigurationBuilder = new ConsumerMiddlewareConfigurationBuilder(dependencyConfigurator); + _middlewareConfigurationBuilder = new ConsumerMiddlewareConfigurationBuilder(dependencyConfigurator); } public IDependencyConfigurator DependencyConfigurator { get; } public IConsumerConfigurationBuilder Topic(string topicName) { - this.topics.Add(topicName); + _topics.Add(topicName); return this; } public IConsumerConfigurationBuilder ManualAssignPartitions(string topicName, IEnumerable partitions) { - this.topicsPartitions.Add(new TopicPartitions(topicName, partitions)); + _topicsPartitions.Add(new TopicPartitions(topicName, partitions)); return this; } - public IConsumerConfigurationBuilder WithConsumerConfig(ConsumerConfig config) + public IConsumerConfigurationBuilder WithConsumerConfig(Confluent.Kafka.ConsumerConfig config) { - this.consumerConfig = config; + _consumerConfig = config; return this; } public IConsumerConfigurationBuilder Topics(IEnumerable topicNames) { - this.topics.AddRange(topicNames); + _topics.AddRange(topicNames); return this; } @@ -77,28 +76,28 @@ public IConsumerConfigurationBuilder Topics(IEnumerable topicNames) public IConsumerConfigurationBuilder WithName(string name) { - this.name = name; + _name = name; return this; } public IConsumerConfigurationBuilder DisableManagement() { - this.disableManagement = true; + _disableManagement = true; return this; } public IConsumerConfigurationBuilder WithGroupId(string groupId) { - this.groupId = groupId; + _groupId = groupId; return this; } public IConsumerConfigurationBuilder WithAutoOffsetReset(KafkaFlow.AutoOffsetReset autoOffsetReset) { - this.autoOffsetReset = autoOffsetReset switch + _autoOffsetReset = autoOffsetReset switch { - KafkaFlow.AutoOffsetReset.Earliest => AutoOffsetReset.Earliest, - KafkaFlow.AutoOffsetReset.Latest => AutoOffsetReset.Latest, + KafkaFlow.AutoOffsetReset.Earliest => Confluent.Kafka.AutoOffsetReset.Earliest, + KafkaFlow.AutoOffsetReset.Latest => Confluent.Kafka.AutoOffsetReset.Latest, _ => throw new InvalidEnumArgumentException( nameof(autoOffsetReset), (int)autoOffsetReset, @@ -110,13 +109,13 @@ public IConsumerConfigurationBuilder WithAutoOffsetReset(KafkaFlow.AutoOffsetRes public IConsumerConfigurationBuilder WithAutoCommitIntervalMs(int autoCommitIntervalMs) { - this.autoCommitInterval = TimeSpan.FromMilliseconds(autoCommitIntervalMs); + _autoCommitInterval = TimeSpan.FromMilliseconds(autoCommitIntervalMs); return this; } public IConsumerConfigurationBuilder WithMaxPollIntervalMs(int maxPollIntervalMs) { - this.maxPollIntervalMs = maxPollIntervalMs; + _maxPollIntervalMs = maxPollIntervalMs; return this; } @@ -124,8 +123,8 @@ public IConsumerConfigurationBuilder WithWorkersCount( Func> calculator, TimeSpan evaluationInterval) { - this.workersCountCalculator = calculator; - this.workersCountEvaluationInterval = evaluationInterval; + _workersCountCalculator = calculator; + _workersCountEvaluationInterval = evaluationInterval; return this; } @@ -141,26 +140,26 @@ public IConsumerConfigurationBuilder WithWorkersCount(int workersCount) public IConsumerConfigurationBuilder WithBufferSize(int size) { - this.bufferSize = size; + _bufferSize = size; return this; } public IConsumerConfigurationBuilder WithWorkerStopTimeout(int seconds) { - this.workerStopTimeout = TimeSpan.FromSeconds(seconds); + _workerStopTimeout = TimeSpan.FromSeconds(seconds); return this; } public IConsumerConfigurationBuilder WithWorkerStopTimeout(TimeSpan timeout) { - this.workerStopTimeout = timeout; + _workerStopTimeout = timeout; return this; } public IConsumerConfigurationBuilder WithWorkerDistributionStrategy(Factory factory) where T : class, IWorkerDistributionStrategy { - this.distributionStrategyFactory = factory; + _distributionStrategyFactory = factory; return this; } @@ -168,88 +167,88 @@ public IConsumerConfigurationBuilder WithWorkerDistributionStrategy() where T : class, IWorkerDistributionStrategy { this.DependencyConfigurator.AddTransient(); - this.distributionStrategyFactory = resolver => resolver.Resolve(); + _distributionStrategyFactory = resolver => resolver.Resolve(); return this; } public IConsumerConfigurationBuilder WithManualMessageCompletion() { - this.autoMessageCompletion = false; + _autoMessageCompletion = false; return this; } public IConsumerConfigurationBuilder WithoutStoringOffsets() { - this.noStoreOffsets = true; + _noStoreOffsets = true; return this; } public IConsumerConfigurationBuilder WithInitialState(ConsumerInitialState state) { - this.initialState = state; + _initialState = state; return this; } public IConsumerConfigurationBuilder AddMiddlewares(Action middlewares) { - middlewares(this.middlewareConfigurationBuilder); + middlewares(_middlewareConfigurationBuilder); return this; } public IConsumerConfigurationBuilder WithPartitionsAssignedHandler( - Action> partitionsAssignedHandler) + Action> partitionsAssignedHandler) { - this.partitionAssignedHandlers.Add(partitionsAssignedHandler); + _partitionAssignedHandlers.Add(partitionsAssignedHandler); return this; } public IConsumerConfigurationBuilder WithPartitionsRevokedHandler( - Action> partitionsRevokedHandler) + Action> partitionsRevokedHandler) { - this.partitionRevokedHandlers.Add(partitionsRevokedHandler); + _partitionRevokedHandlers.Add(partitionsRevokedHandler); return this; } public IConsumerConfigurationBuilder WithStatisticsHandler(Action statisticsHandler) { - this.statisticsHandlers.Add(statisticsHandler); + _statisticsHandlers.Add(statisticsHandler); return this; } public IConsumerConfigurationBuilder WithStatisticsIntervalMs(int statisticsIntervalMs) { - this.statisticsInterval = statisticsIntervalMs; + _statisticsInterval = statisticsIntervalMs; return this; } public IConsumerConfigurationBuilder WithPendingOffsetsStatisticsHandler( - Action> pendingOffsetsHandler, + Action> pendingOffsetsHandler, TimeSpan interval) { - this.pendingOffsetsStatisticsHandlers.Add(new(pendingOffsetsHandler, interval)); + _pendingOffsetsStatisticsHandlers.Add(new(pendingOffsetsHandler, interval)); return this; } public IConsumerConfigurationBuilder WithCustomFactory(ConsumerCustomFactory customFactory) { - this.customFactory = customFactory; + _customFactory = customFactory; return this; } public IConsumerConfiguration Build(ClusterConfiguration clusterConfiguration) { - var middlewareConfiguration = this.middlewareConfigurationBuilder.Build(); + var middlewareConfiguration = _middlewareConfigurationBuilder.Build(); - this.consumerConfig ??= new ConsumerConfig(); + _consumerConfig ??= new Confluent.Kafka.ConsumerConfig(); - var consumerConfigCopy = new ConsumerConfig(this.consumerConfig.ToDictionary(x => x.Key, x => x.Value)); + var consumerConfigCopy = new Confluent.Kafka.ConsumerConfig(_consumerConfig.ToDictionary(x => x.Key, x => x.Value)); - consumerConfigCopy.BootstrapServers = this.consumerConfig.BootstrapServers ?? string.Join(",", clusterConfiguration.Brokers); - consumerConfigCopy.GroupId = this.consumerConfig.GroupId ?? this.groupId; - consumerConfigCopy.AutoOffsetReset = this.consumerConfig.AutoOffsetReset ?? this.autoOffsetReset; - consumerConfigCopy.MaxPollIntervalMs = this.consumerConfig.MaxPollIntervalMs ?? this.maxPollIntervalMs; - consumerConfigCopy.StatisticsIntervalMs = this.consumerConfig.StatisticsIntervalMs ?? this.statisticsInterval; + consumerConfigCopy.BootstrapServers = _consumerConfig.BootstrapServers ?? string.Join(",", clusterConfiguration.Brokers); + consumerConfigCopy.GroupId = _consumerConfig.GroupId ?? _groupId; + consumerConfigCopy.AutoOffsetReset = _consumerConfig.AutoOffsetReset ?? _autoOffsetReset; + consumerConfigCopy.MaxPollIntervalMs = _consumerConfig.MaxPollIntervalMs ?? _maxPollIntervalMs; + consumerConfigCopy.StatisticsIntervalMs = _consumerConfig.StatisticsIntervalMs ?? _statisticsInterval; consumerConfigCopy.EnableAutoOffsetStore = false; consumerConfigCopy.EnableAutoCommit = false; @@ -258,26 +257,26 @@ public IConsumerConfiguration Build(ClusterConfiguration clusterConfiguration) return new ConsumerConfiguration( consumerConfigCopy, - this.topics, - this.topicsPartitions, - this.name, + _topics, + _topicsPartitions, + _name, clusterConfiguration, - this.disableManagement, - this.workersCountCalculator, - this.workersCountEvaluationInterval, - this.bufferSize, - this.workerStopTimeout, - this.distributionStrategyFactory, + _disableManagement, + _workersCountCalculator, + _workersCountEvaluationInterval, + _bufferSize, + _workerStopTimeout, + _distributionStrategyFactory, middlewareConfiguration, - this.autoMessageCompletion, - this.noStoreOffsets, - this.initialState, - this.autoCommitInterval, - this.statisticsHandlers, - this.partitionAssignedHandlers, - this.partitionRevokedHandlers, - this.pendingOffsetsStatisticsHandlers, - this.customFactory); + _autoMessageCompletion, + _noStoreOffsets, + _initialState, + _autoCommitInterval, + _statisticsHandlers, + _partitionAssignedHandlers, + _partitionRevokedHandlers, + _pendingOffsetsStatisticsHandlers, + _customFactory); } } } diff --git a/src/KafkaFlow/Configuration/IConsumerConfiguration.cs b/src/KafkaFlow/Configuration/IConsumerConfiguration.cs index 21f5b6896..980fa5e0e 100644 --- a/src/KafkaFlow/Configuration/IConsumerConfiguration.cs +++ b/src/KafkaFlow/Configuration/IConsumerConfiguration.cs @@ -1,10 +1,9 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + namespace KafkaFlow.Configuration { - using System; - using System.Collections.Generic; - using System.Threading.Tasks; - using Confluent.Kafka; - /// /// Represents the Consumer configuration values /// @@ -77,7 +76,7 @@ public interface IConsumerConfiguration bool AutoMessageCompletion { get; } /// - /// Gets a value indicating that no offsets will be stored on Kafka + /// Gets a value indicating whether gets a value indicating that no offsets will be stored on Kafka /// bool NoStoreOffsets { get; } @@ -94,12 +93,12 @@ public interface IConsumerConfiguration /// /// Gets the handlers that will be called when the partitions are assigned /// - IReadOnlyList>> PartitionsAssignedHandlers { get; } + IReadOnlyList>> PartitionsAssignedHandlers { get; } /// /// Gets the handlers that will be called when the partitions are revoked /// - IReadOnlyList>> PartitionsRevokedHandlers { get; } + IReadOnlyList>> PartitionsRevokedHandlers { get; } /// /// Gets the handlers that will be called when there are pending offsets @@ -120,6 +119,6 @@ public interface IConsumerConfiguration /// Parses KafkaFlow configuration to Confluent configuration /// /// - ConsumerConfig GetKafkaConfig(); + Confluent.Kafka.ConsumerConfig GetKafkaConfig(); } } diff --git a/src/KafkaFlow/Configuration/IMiddlewareInstanceContainer.cs b/src/KafkaFlow/Configuration/IMiddlewareInstanceContainer.cs index 81152c04e..fcf45c976 100644 --- a/src/KafkaFlow/Configuration/IMiddlewareInstanceContainer.cs +++ b/src/KafkaFlow/Configuration/IMiddlewareInstanceContainer.cs @@ -1,7 +1,7 @@ +using System; + namespace KafkaFlow.Configuration { - using System; - internal interface IMiddlewareInstanceContainer { Guid Id { get; } diff --git a/src/KafkaFlow/Configuration/IProducerConfiguration.cs b/src/KafkaFlow/Configuration/IProducerConfiguration.cs index 6481698f2..536331387 100644 --- a/src/KafkaFlow/Configuration/IProducerConfiguration.cs +++ b/src/KafkaFlow/Configuration/IProducerConfiguration.cs @@ -1,10 +1,9 @@ +using System; +using System.Collections.Generic; +using Confluent.Kafka; + namespace KafkaFlow.Configuration { - using System; - using System.Collections.Generic; - using Confluent.Kafka; - using Acks = KafkaFlow.Acks; - /// /// Represents the producer configuration values /// diff --git a/src/KafkaFlow/Configuration/KafkaConfiguration.cs b/src/KafkaFlow/Configuration/KafkaConfiguration.cs index 3b7adf3d4..6b636d87e 100644 --- a/src/KafkaFlow/Configuration/KafkaConfiguration.cs +++ b/src/KafkaFlow/Configuration/KafkaConfiguration.cs @@ -1,24 +1,24 @@ +using System.Collections.Generic; + namespace KafkaFlow.Configuration { - using System.Collections.Generic; - /// /// Represents the kafka configuration values /// public class KafkaConfiguration { - private readonly List clusters = new(); + private readonly List _clusters = new(); /// /// Gets the cluster configuration list /// - public IReadOnlyCollection Clusters => this.clusters; + public IReadOnlyCollection Clusters => _clusters; /// /// Adds a list of cluster configurations /// /// A list of cluster configurations public void AddClusters(IEnumerable configurations) => - this.clusters.AddRange(configurations); + _clusters.AddRange(configurations); } } diff --git a/src/KafkaFlow/Configuration/KafkaConfigurationBuilder.cs b/src/KafkaFlow/Configuration/KafkaConfigurationBuilder.cs index c194cc501..8953a2935 100644 --- a/src/KafkaFlow/Configuration/KafkaConfigurationBuilder.cs +++ b/src/KafkaFlow/Configuration/KafkaConfigurationBuilder.cs @@ -1,31 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using KafkaFlow.Clusters; +using KafkaFlow.Consumers; +using KafkaFlow.Producers; + namespace KafkaFlow.Configuration { - using System; - using System.Collections.Generic; - using System.Linq; - using KafkaFlow.Clusters; - using KafkaFlow.Consumers; - using KafkaFlow.Producers; - internal class KafkaConfigurationBuilder : IKafkaConfigurationBuilder { - private readonly IDependencyConfigurator dependencyConfigurator; - private readonly List clusters = new(); - private readonly IList> globalEventsConfigurators = new List>(); - private Type logHandlerType = typeof(NullLogHandler); + private readonly IDependencyConfigurator _dependencyConfigurator; + private readonly List _clusters = new(); + private readonly IList> _globalEventsConfigurators = new List>(); + private Type _logHandlerType = typeof(NullLogHandler); public KafkaConfigurationBuilder(IDependencyConfigurator dependencyConfigurator) { - this.dependencyConfigurator = dependencyConfigurator; + _dependencyConfigurator = dependencyConfigurator; } public KafkaConfiguration Build() { var configuration = new KafkaConfiguration(); - configuration.AddClusters(this.clusters.Select(x => x.Build(configuration))); + configuration.AddClusters(_clusters.Select(x => x.Build(configuration))); - this.dependencyConfigurator.AddSingleton( + _dependencyConfigurator.AddSingleton( resolver => new ProducerAccessor( configuration.Clusters .SelectMany(x => x.Producers) @@ -36,13 +36,13 @@ public KafkaConfiguration Build() foreach (var cluster in configuration.Clusters) { - this.dependencyConfigurator.AddSingleton( + _dependencyConfigurator.AddSingleton( resolver => new ClusterManager(resolver.Resolve(), cluster)); } - this.dependencyConfigurator - .AddTransient(typeof(ILogHandler), this.logHandlerType) + _dependencyConfigurator + .AddTransient(typeof(ILogHandler), _logHandlerType) .AddSingleton() .AddSingleton(new ConsumerAccessor()) .AddSingleton(new ConsumerManagerFactory()) @@ -57,7 +57,7 @@ public KafkaConfiguration Build() var globalEvents = new GlobalEvents(logHandler); - foreach (var del in this.globalEventsConfigurators) + foreach (var del in _globalEventsConfigurators) { del.Invoke(globalEvents); } @@ -70,11 +70,11 @@ public KafkaConfiguration Build() public IKafkaConfigurationBuilder AddCluster(Action cluster) { - var builder = new ClusterConfigurationBuilder(this.dependencyConfigurator); + var builder = new ClusterConfigurationBuilder(_dependencyConfigurator); cluster(builder); - this.clusters.Add(builder); + _clusters.Add(builder); return this; } @@ -82,13 +82,13 @@ public IKafkaConfigurationBuilder AddCluster(Action() where TLogHandler : ILogHandler { - this.logHandlerType = typeof(TLogHandler); + _logHandlerType = typeof(TLogHandler); return this; } public IKafkaConfigurationBuilder SubscribeGlobalEvents(Action observers) { - this.globalEventsConfigurators.Add(observers); + _globalEventsConfigurators.Add(observers); return this; } diff --git a/src/KafkaFlow/Configuration/KafkaFlowConfigurator.cs b/src/KafkaFlow/Configuration/KafkaFlowConfigurator.cs index 25d503461..099c5d22c 100644 --- a/src/KafkaFlow/Configuration/KafkaFlowConfigurator.cs +++ b/src/KafkaFlow/Configuration/KafkaFlowConfigurator.cs @@ -1,16 +1,16 @@ +using System; +using KafkaFlow.Clusters; +using KafkaFlow.Consumers; +using KafkaFlow.Producers; + namespace KafkaFlow.Configuration { - using System; - using KafkaFlow.Clusters; - using KafkaFlow.Consumers; - using KafkaFlow.Producers; - /// /// A class to configure KafkaFlow /// public class KafkaFlowConfigurator { - private readonly KafkaConfiguration configuration; + private readonly KafkaConfiguration _configuration; /// /// Initializes a new instance of the class. @@ -25,7 +25,7 @@ public KafkaFlowConfigurator( kafka(builder); - this.configuration = builder.Build(); + _configuration = builder.Build(); } /// @@ -39,7 +39,7 @@ public IKafkaBus CreateBus(IDependencyResolver resolver) return new KafkaBus( scope.Resolver, - this.configuration, + _configuration, scope.Resolver.Resolve(), scope.Resolver.Resolve(), scope.Resolver.Resolve(), diff --git a/src/KafkaFlow/Configuration/MiddlewareConfiguration.cs b/src/KafkaFlow/Configuration/MiddlewareConfiguration.cs index 4eea54b91..32aa4832a 100644 --- a/src/KafkaFlow/Configuration/MiddlewareConfiguration.cs +++ b/src/KafkaFlow/Configuration/MiddlewareConfiguration.cs @@ -1,7 +1,7 @@ +using System; + namespace KafkaFlow.Configuration { - using System; - /// /// Represents a middleware configuration /// diff --git a/src/KafkaFlow/Configuration/MiddlewareConfigurationBuilder.cs b/src/KafkaFlow/Configuration/MiddlewareConfigurationBuilder.cs index 95cf0a893..5213b2d4f 100644 --- a/src/KafkaFlow/Configuration/MiddlewareConfigurationBuilder.cs +++ b/src/KafkaFlow/Configuration/MiddlewareConfigurationBuilder.cs @@ -1,13 +1,13 @@ +using System; +using System.Collections.Generic; + namespace KafkaFlow.Configuration { - using System; - using System.Collections.Generic; - internal class MiddlewareConfigurationBuilder : IMiddlewareConfigurationBuilder where TBuilder : class, IMiddlewareConfigurationBuilder { - private readonly List middlewaresConfigurations = new(); + private readonly List _middlewaresConfigurations = new(); protected MiddlewareConfigurationBuilder(IDependencyConfigurator dependencyConfigurator) { @@ -21,7 +21,7 @@ public TBuilder Add( MiddlewareLifetime lifetime = MiddlewareLifetime.ConsumerOrProducer) where T : class, IMessageMiddleware { - return this.AddAt(this.middlewaresConfigurations.Count, factory, lifetime); + return this.AddAt(_middlewaresConfigurations.Count, factory, lifetime); } public TBuilder AddAtBeginning( @@ -35,7 +35,7 @@ public TBuilder AddAtBeginning( public TBuilder Add(MiddlewareLifetime lifetime = MiddlewareLifetime.ConsumerOrProducer) where T : class, IMessageMiddleware { - return this.AddAt(this.middlewaresConfigurations.Count, lifetime); + return this.AddAt(_middlewaresConfigurations.Count, lifetime); } public TBuilder AddAtBeginning(MiddlewareLifetime lifetime = MiddlewareLifetime.ConsumerOrProducer) @@ -44,7 +44,7 @@ public TBuilder AddAtBeginning(MiddlewareLifetime lifetime = MiddlewareLifeti return this.AddAt(0, lifetime); } - public IReadOnlyList Build() => this.middlewaresConfigurations; + public IReadOnlyList Build() => _middlewaresConfigurations; private static InstanceLifetime ParseLifetime(MiddlewareLifetime lifetime) { @@ -72,7 +72,7 @@ private TBuilder AddAt( _ => new MiddlewareInstanceContainer(containerId, factory), ParseLifetime(lifetime)); - this.middlewaresConfigurations.Insert( + _middlewaresConfigurations.Insert( position, new MiddlewareConfiguration(typeof(T), lifetime, containerId)); @@ -86,7 +86,7 @@ private TBuilder AddAt( { this.DependencyConfigurator.Add(ParseLifetime(lifetime)); - this.middlewaresConfigurations.Insert( + _middlewaresConfigurations.Insert( position, new MiddlewareConfiguration(typeof(T), lifetime)); diff --git a/src/KafkaFlow/Configuration/MiddlewareInstanceContainer.cs b/src/KafkaFlow/Configuration/MiddlewareInstanceContainer.cs index a81d2b9e6..5a06c8bce 100644 --- a/src/KafkaFlow/Configuration/MiddlewareInstanceContainer.cs +++ b/src/KafkaFlow/Configuration/MiddlewareInstanceContainer.cs @@ -1,40 +1,40 @@ +using System; + namespace KafkaFlow.Configuration { - using System; - internal class MiddlewareInstanceContainer : IMiddlewareInstanceContainer { - private readonly object sync = new(); - private readonly Factory factory; + private readonly object _sync = new(); + private readonly Factory _factory; - private IMessageMiddleware instance; + private IMessageMiddleware _instance; public MiddlewareInstanceContainer(Guid id, Factory factory) { this.Id = id; - this.factory = factory; + _factory = factory; } public Guid Id { get; } public IMessageMiddleware GetInstance(IDependencyResolver resolver) { - if (this.instance is not null) + if (_instance is not null) { - return this.instance; + return _instance; } - lock (this.sync) + lock (_sync) { - if (this.instance is not null) + if (_instance is not null) { - return this.instance; + return _instance; } - this.instance = this.factory(resolver); + _instance = _factory(resolver); } - return this.instance; + return _instance; } } } diff --git a/src/KafkaFlow/Configuration/PendingOffsetsStatisticsHandler.cs b/src/KafkaFlow/Configuration/PendingOffsetsStatisticsHandler.cs index 6df2d96dc..04d0ddf11 100644 --- a/src/KafkaFlow/Configuration/PendingOffsetsStatisticsHandler.cs +++ b/src/KafkaFlow/Configuration/PendingOffsetsStatisticsHandler.cs @@ -1,9 +1,8 @@ +using System; +using System.Collections.Generic; + namespace KafkaFlow.Configuration { - using System; - using System.Collections.Generic; - using Confluent.Kafka; - /// /// Represents a handler for pending offsets statistics. /// @@ -14,7 +13,7 @@ public class PendingOffsetsStatisticsHandler /// /// The action to handle pending offsets statistics. /// The interval at which the handler should be executed. - public PendingOffsetsStatisticsHandler(Action> handler, TimeSpan interval) + public PendingOffsetsStatisticsHandler(Action> handler, TimeSpan interval) { this.Handler = handler; this.Interval = interval; @@ -23,7 +22,7 @@ public PendingOffsetsStatisticsHandler(Action /// Gets the action that handles pending offsets statistics. /// - public Action> Handler { get; } + public Action> Handler { get; } /// /// Gets the interval at which the handler should be executed. diff --git a/src/KafkaFlow/Configuration/ProducerConfiguration.cs b/src/KafkaFlow/Configuration/ProducerConfiguration.cs index 124931791..98c27943f 100644 --- a/src/KafkaFlow/Configuration/ProducerConfiguration.cs +++ b/src/KafkaFlow/Configuration/ProducerConfiguration.cs @@ -1,10 +1,9 @@ +using System; +using System.Collections.Generic; +using Confluent.Kafka; + namespace KafkaFlow.Configuration { - using System; - using System.Collections.Generic; - using Confluent.Kafka; - using Acks = KafkaFlow.Acks; - internal class ProducerConfiguration : IProducerConfiguration { public ProducerConfiguration( diff --git a/src/KafkaFlow/Configuration/ProducerConfigurationBuilder.cs b/src/KafkaFlow/Configuration/ProducerConfigurationBuilder.cs index a02a4c827..930750809 100644 --- a/src/KafkaFlow/Configuration/ProducerConfigurationBuilder.cs +++ b/src/KafkaFlow/Configuration/ProducerConfigurationBuilder.cs @@ -1,106 +1,105 @@ +using System; +using System.Collections.Generic; +using Confluent.Kafka; + namespace KafkaFlow.Configuration { - using System; - using System.Collections.Generic; - using Confluent.Kafka; - using Acks = KafkaFlow.Acks; - internal class ProducerConfigurationBuilder : IProducerConfigurationBuilder { - private readonly string name; - private readonly ProducerMiddlewareConfigurationBuilder middlewareConfigurationBuilder; - private readonly List> statisticsHandlers = new(); + private readonly string _name; + private readonly ProducerMiddlewareConfigurationBuilder _middlewareConfigurationBuilder; + private readonly List> _statisticsHandlers = new(); - private string topic; - private ProducerConfig producerConfig; - private Acks? acks; - private int statisticsInterval; - private double? lingerMs; - private ProducerCustomFactory customFactory = (producer, _) => producer; + private string _topic; + private ProducerConfig _producerConfig; + private Acks? _acks; + private int _statisticsInterval; + private double? _lingerMs; + private ProducerCustomFactory _customFactory = (producer, _) => producer; public ProducerConfigurationBuilder(IDependencyConfigurator dependencyConfigurator, string name) { - this.name = name; + _name = name; this.DependencyConfigurator = dependencyConfigurator; - this.middlewareConfigurationBuilder = new ProducerMiddlewareConfigurationBuilder(dependencyConfigurator); + _middlewareConfigurationBuilder = new ProducerMiddlewareConfigurationBuilder(dependencyConfigurator); } public IDependencyConfigurator DependencyConfigurator { get; } public IProducerConfigurationBuilder AddMiddlewares(Action middlewares) { - middlewares(this.middlewareConfigurationBuilder); + middlewares(_middlewareConfigurationBuilder); return this; } public IProducerConfigurationBuilder DefaultTopic(string topic) { - this.topic = topic; + _topic = topic; return this; } public IProducerConfigurationBuilder WithProducerConfig(ProducerConfig config) { - this.producerConfig = config; + _producerConfig = config; return this; } public IProducerConfigurationBuilder WithCompression(CompressionType compressionType, int? compressionLevel) { - this.producerConfig ??= new ProducerConfig(); - this.producerConfig.CompressionType = compressionType; - this.producerConfig.CompressionLevel = compressionLevel; + _producerConfig ??= new ProducerConfig(); + _producerConfig.CompressionType = compressionType; + _producerConfig.CompressionLevel = compressionLevel; return this; } public IProducerConfigurationBuilder WithAcks(Acks acks) { - this.acks = acks; + _acks = acks; return this; } public IProducerConfigurationBuilder WithLingerMs(double lingerMs) { - this.lingerMs = lingerMs; + _lingerMs = lingerMs; return this; } public IProducerConfigurationBuilder WithStatisticsHandler(Action statisticsHandler) { - this.statisticsHandlers.Add(statisticsHandler); + _statisticsHandlers.Add(statisticsHandler); return this; } public IProducerConfigurationBuilder WithStatisticsIntervalMs(int statisticsIntervalMs) { - this.statisticsInterval = statisticsIntervalMs; + _statisticsInterval = statisticsIntervalMs; return this; } public IProducerConfigurationBuilder WithCustomFactory(ProducerCustomFactory customFactory) { - this.customFactory = customFactory; + _customFactory = customFactory; return this; } public IProducerConfiguration Build(ClusterConfiguration clusterConfiguration) { - this.producerConfig ??= new ProducerConfig(); + _producerConfig ??= new ProducerConfig(); - this.producerConfig.StatisticsIntervalMs = this.statisticsInterval; - this.producerConfig.LingerMs = this.lingerMs; + _producerConfig.StatisticsIntervalMs = _statisticsInterval; + _producerConfig.LingerMs = _lingerMs; - this.producerConfig.ReadSecurityInformationFrom(clusterConfiguration); + _producerConfig.ReadSecurityInformationFrom(clusterConfiguration); var configuration = new ProducerConfiguration( clusterConfiguration, - this.name, - this.topic, - this.acks, - this.middlewareConfigurationBuilder.Build(), - this.producerConfig, - this.statisticsHandlers, - this.customFactory); + _name, + _topic, + _acks, + _middlewareConfigurationBuilder.Build(), + _producerConfig, + _statisticsHandlers, + _customFactory); return configuration; } diff --git a/src/KafkaFlow/ConsumerManagerFactory.cs b/src/KafkaFlow/ConsumerManagerFactory.cs index 33bce7adb..c8856b833 100644 --- a/src/KafkaFlow/ConsumerManagerFactory.cs +++ b/src/KafkaFlow/ConsumerManagerFactory.cs @@ -1,8 +1,8 @@ +using KafkaFlow.Configuration; +using KafkaFlow.Consumers; + namespace KafkaFlow { - using KafkaFlow.Configuration; - using KafkaFlow.Consumers; - internal class ConsumerManagerFactory : IConsumerManagerFactory { public IConsumerManager Create(IConsumerConfiguration configuration, IDependencyResolver consumerDependencyResolver) diff --git a/src/KafkaFlow/Consumers/Consumer.cs b/src/KafkaFlow/Consumers/Consumer.cs index e19583156..5682cecf1 100644 --- a/src/KafkaFlow/Consumers/Consumer.cs +++ b/src/KafkaFlow/Consumers/Consumer.cs @@ -1,43 +1,42 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using KafkaFlow.Configuration; + namespace KafkaFlow.Consumers { - using System; - using System.Collections.Concurrent; - using System.Collections.Generic; - using System.Linq; - using System.Threading; - using System.Threading.Tasks; - using Confluent.Kafka; - using KafkaFlow.Configuration; - internal class Consumer : IConsumer { - private readonly IDependencyResolver dependencyResolver; - private readonly ILogHandler logHandler; + private readonly IDependencyResolver _dependencyResolver; + private readonly ILogHandler _logHandler; - private readonly List, List>> - partitionsAssignedHandlers = new(); + private readonly List, List>> + _partitionsAssignedHandlers = new(); - private readonly List, List>> - partitionsRevokedHandlers = new(); + private readonly List, List>> + _partitionsRevokedHandlers = new(); - private readonly List, Error>> errorsHandlers = new(); - private readonly List, string>> statisticsHandlers = new(); - private readonly ConcurrentDictionary currentPartitionsOffsets = new(); - private readonly ConsumerFlowManager flowManager; + private readonly List, Confluent.Kafka.Error>> _errorsHandlers = new(); + private readonly List, string>> _statisticsHandlers = new(); + private readonly ConcurrentDictionary _currentPartitionsOffsets = new(); + private readonly ConsumerFlowManager _flowManager; - private IConsumer consumer; + private Confluent.Kafka.IConsumer _consumer; public Consumer( IConsumerConfiguration configuration, IDependencyResolver dependencyResolver, ILogHandler logHandler) { - this.dependencyResolver = dependencyResolver; - this.logHandler = logHandler; + _dependencyResolver = dependencyResolver; + _logHandler = logHandler; this.Configuration = configuration; - this.flowManager = new ConsumerFlowManager( + _flowManager = new ConsumerFlowManager( this, - this.logHandler); + _logHandler); foreach (var handler in this.Configuration.StatisticsHandlers) { @@ -54,7 +53,7 @@ public Consumer( this.OnPartitionsRevoked((resolver, _, topicPartitions) => handler(resolver, topicPartitions)); } - var middlewareContext = this.dependencyResolver.Resolve(); + var middlewareContext = _dependencyResolver.Resolve(); middlewareContext.Worker = null; middlewareContext.Consumer = this; @@ -66,13 +65,13 @@ public Consumer( public IReadOnlyList Subscription { get; private set; } = new List(); - public IReadOnlyList Assignment { get; private set; } = new List(); + public IReadOnlyList Assignment { get; private set; } = new List(); - public IConsumerFlowManager FlowManager => this.flowManager; + public IConsumerFlowManager FlowManager => _flowManager; - public string MemberId => this.consumer?.MemberId; + public string MemberId => _consumer?.MemberId; - public string ClientInstanceName => this.consumer?.Name; + public string ClientInstanceName => _consumer?.Name; public ConsumerStatus Status { @@ -94,45 +93,45 @@ public ConsumerStatus Status } } - public void OnPartitionsAssigned(Action, List> handler) => - this.partitionsAssignedHandlers.Add(handler); + public void OnPartitionsAssigned(Action, List> handler) => + _partitionsAssignedHandlers.Add(handler); - public void OnPartitionsRevoked(Action, List> handler) => - this.partitionsRevokedHandlers.Add(handler); + public void OnPartitionsRevoked(Action, List> handler) => + _partitionsRevokedHandlers.Add(handler); - public void OnError(Action, Error> handler) => - this.errorsHandlers.Add(handler); + public void OnError(Action, Confluent.Kafka.Error> handler) => + _errorsHandlers.Add(handler); - public void OnStatistics(Action, string> handler) => - this.statisticsHandlers.Add(handler); + public void OnStatistics(Action, string> handler) => + _statisticsHandlers.Add(handler); - public Offset GetPosition(TopicPartition topicPartition) => - this.consumer.Position(topicPartition); + public Confluent.Kafka.Offset GetPosition(Confluent.Kafka.TopicPartition topicPartition) => + _consumer.Position(topicPartition); - public WatermarkOffsets GetWatermarkOffsets(TopicPartition topicPartition) => - this.consumer.GetWatermarkOffsets(topicPartition); + public Confluent.Kafka.WatermarkOffsets GetWatermarkOffsets(Confluent.Kafka.TopicPartition topicPartition) => + _consumer.GetWatermarkOffsets(topicPartition); - public WatermarkOffsets QueryWatermarkOffsets(TopicPartition topicPartition, TimeSpan timeout) => - this.consumer.QueryWatermarkOffsets(topicPartition, timeout); + public Confluent.Kafka.WatermarkOffsets QueryWatermarkOffsets(Confluent.Kafka.TopicPartition topicPartition, TimeSpan timeout) => + _consumer.QueryWatermarkOffsets(topicPartition, timeout); - public List OffsetsForTimes( - IEnumerable topicPartitions, + public List OffsetsForTimes( + IEnumerable topicPartitions, TimeSpan timeout) => - this.consumer.OffsetsForTimes(topicPartitions, timeout); + _consumer.OffsetsForTimes(topicPartitions, timeout); public IEnumerable GetTopicPartitionsLag() { return this.Assignment.Select( tp => { - var offset = Math.Max(0, this.currentPartitionsOffsets.GetOrAdd(tp, _ => this.GetPosition(tp))); + var offset = Math.Max(0, _currentPartitionsOffsets.GetOrAdd(tp, _ => this.GetPosition(tp))); var offsetEnd = Math.Max(0, this.GetWatermarkOffsets(tp).High.Value); return new TopicPartitionLag(tp.Topic, tp.Partition.Value, offset == 0 ? 0 : offsetEnd - offset); }); } - public void Commit(IReadOnlyCollection offsets) + public void Commit(IReadOnlyCollection offsets) { var validOffsets = offsets .Where(x => x.Offset.Value >= 0) @@ -143,31 +142,31 @@ public void Commit(IReadOnlyCollection offsets) return; } - this.consumer.Commit(validOffsets); + _consumer.Commit(validOffsets); foreach (var offset in validOffsets) { - this.currentPartitionsOffsets[offset.TopicPartition] = offset.Offset.Value; + _currentPartitionsOffsets[offset.TopicPartition] = offset.Offset.Value; } } - public async ValueTask> ConsumeAsync(CancellationToken cancellationToken) + public async ValueTask> ConsumeAsync(CancellationToken cancellationToken) { while (true) { try { this.EnsureConsumer(); - await this.flowManager.BlockHeartbeat(cancellationToken); - return this.consumer.Consume(cancellationToken); + await _flowManager.BlockHeartbeat(cancellationToken); + return _consumer.Consume(cancellationToken); } catch (OperationCanceledException) { throw; } - catch (KafkaException ex) when (ex.Error.IsFatal) + catch (Confluent.Kafka.KafkaException ex) when (ex.Error.IsFatal) { - this.logHandler.Error( + _logHandler.Error( "Kafka Consumer fatal error occurred. Recreating consumer in 5 seconds", ex, null); @@ -178,11 +177,11 @@ public async ValueTask> ConsumeAsync(CancellationT } catch (Exception ex) { - this.logHandler.Error("Kafka Consumer Error", ex, null); + _logHandler.Error("Kafka Consumer Error", ex, null); } finally { - this.flowManager.ReleaseHeartbeat(); + _flowManager.ReleaseHeartbeat(); } } } @@ -205,47 +204,47 @@ private void RegisterLogErrorHandler() if (error.IsFatal) { - this.logHandler.Error("Kafka Consumer Internal Error", null, errorData); + _logHandler.Error("Kafka Consumer Internal Error", null, errorData); } else { - this.logHandler.Warning("Kafka Consumer Internal Warning", errorData); + _logHandler.Warning("Kafka Consumer Internal Warning", errorData); } }); } private void EnsureConsumer() { - if (this.consumer != null) + if (_consumer != null) { return; } var kafkaConfig = this.Configuration.GetKafkaConfig(); - var consumerBuilder = new ConsumerBuilder(kafkaConfig); + var consumerBuilder = new Confluent.Kafka.ConsumerBuilder(kafkaConfig); - this.consumer = + _consumer = consumerBuilder .SetPartitionsAssignedHandler( (consumer, partitions) => this.FirePartitionsAssignedHandlers(consumer, partitions)) .SetPartitionsRevokedHandler( (consumer, partitions) => { - this.Assignment = new List(); + this.Assignment = new List(); this.Subscription = new List(); - this.currentPartitionsOffsets.Clear(); - this.flowManager.Stop(); + _currentPartitionsOffsets.Clear(); + _flowManager.Stop(); - this.partitionsRevokedHandlers.ForEach(handler => handler(this.dependencyResolver, consumer, partitions)); + _partitionsRevokedHandlers.ForEach(handler => handler(_dependencyResolver, consumer, partitions)); }) - .SetErrorHandler((consumer, error) => this.errorsHandlers.ForEach(x => x(consumer, error))) - .SetStatisticsHandler((consumer, statistics) => this.statisticsHandlers.ForEach(x => x(consumer, statistics))) + .SetErrorHandler((consumer, error) => _errorsHandlers.ForEach(x => x(consumer, error))) + .SetStatisticsHandler((consumer, statistics) => _statisticsHandlers.ForEach(x => x(consumer, statistics))) .Build(); if (this.Configuration.Topics.Any()) { - this.consumer.Subscribe(this.Configuration.Topics); + _consumer.Subscribe(this.Configuration.Topics); } if (this.Configuration.ManualAssignPartitions.Any()) @@ -257,26 +256,26 @@ private void EnsureConsumer() private void ManualAssign(IEnumerable topics) { var partitions = topics - .SelectMany(topic => topic.Partitions.Select(partition => new TopicPartition(topic.Name, new Partition(partition)))) + .SelectMany(topic => topic.Partitions.Select(partition => new Confluent.Kafka.TopicPartition(topic.Name, new Confluent.Kafka.Partition(partition)))) .ToList(); - this.consumer.Assign(partitions); - this.FirePartitionsAssignedHandlers(this.consumer, partitions); + _consumer.Assign(partitions); + this.FirePartitionsAssignedHandlers(_consumer, partitions); } - private void FirePartitionsAssignedHandlers(IConsumer consumer, List partitions) + private void FirePartitionsAssignedHandlers(Confluent.Kafka.IConsumer consumer, List partitions) { this.Assignment = partitions; this.Subscription = consumer.Subscription; - this.flowManager.Start(consumer); + _flowManager.Start(consumer); - this.partitionsAssignedHandlers.ForEach(handler => handler(this.dependencyResolver, consumer, partitions)); + _partitionsAssignedHandlers.ForEach(handler => handler(_dependencyResolver, consumer, partitions)); } private void InvalidateConsumer() { - this.consumer?.Close(); - this.consumer = null; + _consumer?.Close(); + _consumer = null; } } } diff --git a/src/KafkaFlow/Consumers/ConsumerAccessor.cs b/src/KafkaFlow/Consumers/ConsumerAccessor.cs index 727d3ed9f..c627c4e92 100644 --- a/src/KafkaFlow/Consumers/ConsumerAccessor.cs +++ b/src/KafkaFlow/Consumers/ConsumerAccessor.cs @@ -1,18 +1,18 @@ +using System.Collections.Generic; + namespace KafkaFlow.Consumers { - using System.Collections.Generic; - internal class ConsumerAccessor : IConsumerAccessor { - private readonly IDictionary consumers = new Dictionary(); + private readonly IDictionary _consumers = new Dictionary(); - public IEnumerable All => this.consumers.Values; + public IEnumerable All => _consumers.Values; public IMessageConsumer this[string name] => this.GetConsumer(name); public IMessageConsumer GetConsumer(string name) => - this.consumers.TryGetValue(name, out var consumer) ? consumer : null; + _consumers.TryGetValue(name, out var consumer) ? consumer : null; - void IConsumerAccessor.Add(IMessageConsumer consumer) => this.consumers.Add(consumer.ConsumerName, consumer); + void IConsumerAccessor.Add(IMessageConsumer consumer) => _consumers.Add(consumer.ConsumerName, consumer); } } diff --git a/src/KafkaFlow/Consumers/ConsumerContext.cs b/src/KafkaFlow/Consumers/ConsumerContext.cs index 794dd7031..77fccbd2d 100644 --- a/src/KafkaFlow/Consumers/ConsumerContext.cs +++ b/src/KafkaFlow/Consumers/ConsumerContext.cs @@ -1,18 +1,17 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Confluent.Kafka; + namespace KafkaFlow.Consumers { - using System; - using System.Threading; - using System.Threading.Tasks; - using Confluent.Kafka; - using TopicPartitionOffset = KafkaFlow.TopicPartitionOffset; - internal class ConsumerContext : IConsumerContext { - private readonly TaskCompletionSource completionSource = new(); - private readonly IConsumer consumer; - private readonly IOffsetManager offsetManager; - private readonly IConsumerWorker worker; - private readonly IDependencyResolverScope messageDependencyScope; + private readonly TaskCompletionSource _completionSource = new(); + private readonly IConsumer _consumer; + private readonly IOffsetManager _offsetManager; + private readonly IConsumerWorker _worker; + private readonly IDependencyResolverScope _messageDependencyScope; public ConsumerContext( IConsumer consumer, @@ -23,11 +22,11 @@ public ConsumerContext( IDependencyResolver consumerDependencyResolver) { this.ConsumerDependencyResolver = consumerDependencyResolver; - this.consumer = consumer; - this.offsetManager = offsetManager; - this.worker = worker; - this.messageDependencyScope = messageDependencyScope; - this.AutoMessageCompletion = this.consumer.Configuration.AutoMessageCompletion; + _consumer = consumer; + _offsetManager = offsetManager; + _worker = worker; + _messageDependencyScope = messageDependencyScope; + this.AutoMessageCompletion = _consumer.Configuration.AutoMessageCompletion; this.TopicPartitionOffset = new TopicPartitionOffset( kafkaResult.Topic, kafkaResult.Partition.Value, @@ -35,13 +34,13 @@ public ConsumerContext( this.MessageTimestamp = kafkaResult.Message.Timestamp.UtcDateTime; } - public string ConsumerName => this.consumer.Configuration.ConsumerName; + public string ConsumerName => _consumer.Configuration.ConsumerName; - public CancellationToken WorkerStopped => this.worker.StopCancellationToken; + public CancellationToken WorkerStopped => _worker.StopCancellationToken; - public int WorkerId => this.worker.Id; + public int WorkerId => _worker.Id; - public IDependencyResolver WorkerDependencyResolver => this.worker.WorkerDependencyResolver; + public IDependencyResolver WorkerDependencyResolver => _worker.WorkerDependencyResolver; public IDependencyResolver ConsumerDependencyResolver { get; } @@ -53,7 +52,7 @@ public ConsumerContext( public TopicPartitionOffset TopicPartitionOffset { get; } - public string GroupId => this.consumer.Configuration.GroupId; + public string GroupId => _consumer.Configuration.GroupId; public bool AutoMessageCompletion { get; set; } @@ -61,28 +60,28 @@ public ConsumerContext( public DateTime MessageTimestamp { get; } - public Task Completion => this.completionSource.Task; + public Task Completion => _completionSource.Task; public void Complete() { if (this.ShouldStoreOffset) { - this.offsetManager.MarkAsProcessed(this); + _offsetManager.MarkAsProcessed(this); } - this.messageDependencyScope.Dispose(); - this.completionSource.TrySetResult(this.TopicPartitionOffset); + _messageDependencyScope.Dispose(); + _completionSource.TrySetResult(this.TopicPartitionOffset); } public IOffsetsWatermark GetOffsetsWatermark() => new OffsetsWatermark( - this.consumer.GetWatermarkOffsets( + _consumer.GetWatermarkOffsets( new TopicPartition( this.TopicPartitionOffset.Topic, this.TopicPartitionOffset.Partition))); - public void Pause() => this.consumer.FlowManager.Pause(this.consumer.Assignment); + public void Pause() => _consumer.FlowManager.Pause(_consumer.Assignment); - public void Resume() => this.consumer.FlowManager.Resume(this.consumer.Assignment); + public void Resume() => _consumer.FlowManager.Resume(_consumer.Assignment); } } diff --git a/src/KafkaFlow/Consumers/ConsumerFlowManager.cs b/src/KafkaFlow/Consumers/ConsumerFlowManager.cs index 9e6c3cc50..9acba77a2 100644 --- a/src/KafkaFlow/Consumers/ConsumerFlowManager.cs +++ b/src/KafkaFlow/Consumers/ConsumerFlowManager.cs @@ -1,48 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Confluent.Kafka; + namespace KafkaFlow.Consumers { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Threading; - using System.Threading.Tasks; - using Confluent.Kafka; - internal class ConsumerFlowManager : IConsumerFlowManager { - private readonly IConsumer consumer; - private readonly ILogHandler logHandler; - private readonly List pausedPartitions = new(); - private readonly SemaphoreSlim consumerSemaphore = new(1, 1); + private readonly IConsumer _consumer; + private readonly ILogHandler _logHandler; + private readonly List _pausedPartitions = new(); + private readonly SemaphoreSlim _consumerSemaphore = new(1, 1); - private IConsumer clientConsumer; - private CancellationTokenSource heartbeatTokenSource; - private Task heartbeatTask; + private IConsumer _clientConsumer; + private CancellationTokenSource _heartbeatTokenSource; + private Task _heartbeatTask; public ConsumerFlowManager( IConsumer consumer, ILogHandler logHandler) { - this.consumer = consumer; - this.logHandler = logHandler; + _consumer = consumer; + _logHandler = logHandler; } - public IReadOnlyList PausedPartitions => this.pausedPartitions.AsReadOnly(); + public IReadOnlyList PausedPartitions => _pausedPartitions.AsReadOnly(); public void Pause(IReadOnlyCollection topicPartitions) { - lock (this.pausedPartitions) + lock (_pausedPartitions) { - topicPartitions = topicPartitions.Except(this.pausedPartitions).ToList(); + topicPartitions = topicPartitions.Except(_pausedPartitions).ToList(); if (!topicPartitions.Any()) { return; } - this.clientConsumer.Pause(topicPartitions); - this.pausedPartitions.AddRange(topicPartitions); + _clientConsumer.Pause(topicPartitions); + _pausedPartitions.AddRange(topicPartitions); - if (this.consumer.Status != ConsumerStatus.Paused) + if (_consumer.Status != ConsumerStatus.Paused) { return; } @@ -53,20 +53,20 @@ public void Pause(IReadOnlyCollection topicPartitions) public Task BlockHeartbeat(CancellationToken cancellationToken) { - return this.consumerSemaphore.WaitAsync(cancellationToken); + return _consumerSemaphore.WaitAsync(cancellationToken); } public void ReleaseHeartbeat() { - if (this.consumerSemaphore.CurrentCount != 1) + if (_consumerSemaphore.CurrentCount != 1) { - this.consumerSemaphore.Release(); + _consumerSemaphore.Release(); } } public void Resume(IReadOnlyCollection topicPartitions) { - lock (this.pausedPartitions) + lock (_pausedPartitions) { if (!topicPartitions.Any()) { @@ -75,51 +75,51 @@ public void Resume(IReadOnlyCollection topicPartitions) foreach (var topicPartition in topicPartitions) { - this.pausedPartitions.Remove(topicPartition); + _pausedPartitions.Remove(topicPartition); } - if (this.consumer.Status == ConsumerStatus.Paused) + if (_consumer.Status == ConsumerStatus.Paused) { return; } this.StopHeartbeat(); - this.clientConsumer.Resume(topicPartitions); + _clientConsumer.Resume(topicPartitions); } } public void Start(IConsumer clientConsumer) { - this.clientConsumer = clientConsumer; + _clientConsumer = clientConsumer; } public void Stop() { - this.pausedPartitions.Clear(); + _pausedPartitions.Clear(); this.StopHeartbeat(); } private void StartHeartbeat() { - this.heartbeatTokenSource = new CancellationTokenSource(); + _heartbeatTokenSource = new CancellationTokenSource(); - this.heartbeatTask = Task.Run( + _heartbeatTask = Task.Run( () => { - if (this.consumerSemaphore.Wait(0)) + if (_consumerSemaphore.Wait(0)) { try { const int consumeTimeoutCall = 1000; - while (!this.heartbeatTokenSource.IsCancellationRequested) + while (!_heartbeatTokenSource.IsCancellationRequested) { - var result = this.clientConsumer.Consume(consumeTimeoutCall); + var result = _clientConsumer.Consume(consumeTimeoutCall); if (result != null) { - this.logHandler.Warning( + _logHandler.Warning( "Paused consumer heartbeat process wrongly read a message, please report this issue", null); } @@ -127,7 +127,7 @@ private void StartHeartbeat() } catch (Exception ex) { - this.logHandler.Error( + _logHandler.Error( "Error executing paused consumer background heartbeat", ex, null); @@ -142,9 +142,9 @@ private void StartHeartbeat() private void StopHeartbeat() { - this.heartbeatTokenSource?.Cancel(); - this.heartbeatTask?.GetAwaiter().GetResult(); - this.heartbeatTask?.Dispose(); + _heartbeatTokenSource?.Cancel(); + _heartbeatTask?.GetAwaiter().GetResult(); + _heartbeatTask?.Dispose(); } } } diff --git a/src/KafkaFlow/Consumers/ConsumerManager.cs b/src/KafkaFlow/Consumers/ConsumerManager.cs index a8c34bea3..26d28b59f 100644 --- a/src/KafkaFlow/Consumers/ConsumerManager.cs +++ b/src/KafkaFlow/Consumers/ConsumerManager.cs @@ -1,19 +1,18 @@ -namespace KafkaFlow.Consumers +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using KafkaFlow.Configuration; + +namespace KafkaFlow.Consumers { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Threading; - using System.Threading.Tasks; - using Confluent.Kafka; - using KafkaFlow.Configuration; - internal class ConsumerManager : IConsumerManager { - private readonly IDependencyResolver dependencyResolver; - private readonly ILogHandler logHandler; + private readonly IDependencyResolver _dependencyResolver; + private readonly ILogHandler _logHandler; - private Timer evaluateWorkersCountTimer; + private Timer _evaluateWorkersCountTimer; public ConsumerManager( IConsumer consumer, @@ -22,8 +21,8 @@ public ConsumerManager( IDependencyResolver dependencyResolver, ILogHandler logHandler) { - this.dependencyResolver = dependencyResolver; - this.logHandler = logHandler; + _dependencyResolver = dependencyResolver; + _logHandler = logHandler; this.Consumer = consumer; this.WorkerPool = consumerWorkerPool; this.Feeder = feeder; @@ -42,7 +41,7 @@ public Task StartAsync() { this.Feeder.Start(); - this.evaluateWorkersCountTimer = new Timer( + _evaluateWorkersCountTimer = new Timer( state => _ = this.EvaluateWorkersCountAsync(), null, this.Consumer.Configuration.WorkersCountEvaluationInterval, @@ -58,14 +57,14 @@ public async Task StopAsync() await this.Feeder.StopAsync().ConfigureAwait(false); await this.WorkerPool.StopAsync().ConfigureAwait(false); - this.evaluateWorkersCountTimer?.Dispose(); - this.evaluateWorkersCountTimer = null; + _evaluateWorkersCountTimer?.Dispose(); + _evaluateWorkersCountTimer = null; this.Consumer.Dispose(); } - private void StopEvaluateWorkerCountTimer() => this.evaluateWorkersCountTimer?.Change(Timeout.Infinite, Timeout.Infinite); + private void StopEvaluateWorkerCountTimer() => _evaluateWorkersCountTimer?.Change(Timeout.Infinite, Timeout.Infinite); - private void StartEvaluateWorkerCountTimer() => this.evaluateWorkersCountTimer?.Change( + private void StartEvaluateWorkerCountTimer() => _evaluateWorkersCountTimer?.Change( this.Consumer.Configuration.WorkersCountEvaluationInterval, this.Consumer.Configuration.WorkersCountEvaluationInterval); @@ -97,22 +96,22 @@ private async Task ChangeWorkersCountAsync(int workersCount) } catch (Exception e) { - this.logHandler.Error("Error changing workers count", e, null); + _logHandler.Error("Error changing workers count", e, null); } } - private void OnPartitionRevoked(IEnumerable topicPartitions) + private void OnPartitionRevoked(IEnumerable topicPartitions) { - this.logHandler.Warning( + _logHandler.Warning( "Partitions revoked", this.GetConsumerLogInfo(topicPartitions.Select(x => x.TopicPartition))); this.WorkerPool.StopAsync().GetAwaiter().GetResult(); } - private void OnPartitionAssigned(IReadOnlyCollection partitions) + private void OnPartitionAssigned(IReadOnlyCollection partitions) { - this.logHandler.Info( + _logHandler.Info( "Partitions assigned", this.GetConsumerLogInfo(partitions)); @@ -124,7 +123,7 @@ private void OnPartitionAssigned(IReadOnlyCollection partitions) .GetResult(); } - private object GetConsumerLogInfo(IEnumerable partitions) => new + private object GetConsumerLogInfo(IEnumerable partitions) => new { this.Consumer.Configuration.GroupId, this.Consumer.Configuration.ConsumerName, @@ -139,7 +138,7 @@ private void OnPartitionAssigned(IReadOnlyCollection partitions) }), }; - private async Task CalculateWorkersCount(IEnumerable partitions) + private async Task CalculateWorkersCount(IEnumerable partitions) { try { @@ -156,11 +155,11 @@ private async Task CalculateWorkersCount(IEnumerable partit .Select(x => x.Partition.Value) .ToList())) .ToList()), - this.dependencyResolver); + _dependencyResolver); } catch (Exception e) { - this.logHandler.Error("Error calculating new workers count, using one worker as fallback", e, null); + _logHandler.Error("Error calculating new workers count, using one worker as fallback", e, null); return 1; } diff --git a/src/KafkaFlow/Consumers/ConsumerWorker.cs b/src/KafkaFlow/Consumers/ConsumerWorker.cs index a40f2143a..a4c1fcbc9 100644 --- a/src/KafkaFlow/Consumers/ConsumerWorker.cs +++ b/src/KafkaFlow/Consumers/ConsumerWorker.cs @@ -1,26 +1,26 @@ +using System; +using System.Threading; +using System.Threading.Channels; +using System.Threading.Tasks; + namespace KafkaFlow.Consumers { - using System; - using System.Threading; - using System.Threading.Channels; - using System.Threading.Tasks; - internal class ConsumerWorker : IConsumerWorker { - private readonly IConsumer consumer; - private readonly IDependencyResolverScope workerDependencyResolverScope; - private readonly IMiddlewareExecutor middlewareExecutor; - private readonly ILogHandler logHandler; - private readonly GlobalEvents globalEvents; + private readonly IConsumer _consumer; + private readonly IDependencyResolverScope _workerDependencyResolverScope; + private readonly IMiddlewareExecutor _middlewareExecutor; + private readonly ILogHandler _logHandler; + private readonly GlobalEvents _globalEvents; - private readonly Channel messagesBuffer; + private readonly Channel _messagesBuffer; - private readonly Event workerStoppingEvent; - private readonly Event workerStoppedEvent; - private readonly Event workerProcessingEnded; + private readonly Event _workerStoppingEvent; + private readonly Event _workerStoppedEvent; + private readonly Event _workerProcessingEnded; - private CancellationTokenSource stopCancellationTokenSource; - private Task backgroundTask; + private CancellationTokenSource _stopCancellationTokenSource; + private Task _backgroundTask; public ConsumerWorker( IConsumer consumer, @@ -30,18 +30,18 @@ public ConsumerWorker( ILogHandler logHandler) { this.Id = workerId; - this.consumer = consumer; - this.workerDependencyResolverScope = consumerDependencyResolver.CreateScope(); - this.middlewareExecutor = middlewareExecutor; - this.logHandler = logHandler; - this.messagesBuffer = Channel.CreateBounded(consumer.Configuration.BufferSize); - this.globalEvents = consumerDependencyResolver.Resolve(); + _consumer = consumer; + _workerDependencyResolverScope = consumerDependencyResolver.CreateScope(); + _middlewareExecutor = middlewareExecutor; + _logHandler = logHandler; + _messagesBuffer = Channel.CreateBounded(consumer.Configuration.BufferSize); + _globalEvents = consumerDependencyResolver.Resolve(); - this.workerStoppingEvent = new(logHandler); - this.workerStoppedEvent = new(logHandler); - this.workerProcessingEnded = new Event(logHandler); + _workerStoppingEvent = new(logHandler); + _workerStoppedEvent = new(logHandler); + _workerProcessingEnded = new Event(logHandler); - var middlewareContext = this.workerDependencyResolverScope.Resolver.Resolve(); + var middlewareContext = _workerDependencyResolverScope.Resolver.Resolve(); middlewareContext.Worker = this; middlewareContext.Consumer = consumer; @@ -49,39 +49,39 @@ public ConsumerWorker( public int Id { get; } - public CancellationToken StopCancellationToken => this.stopCancellationTokenSource?.Token ?? default; + public CancellationToken StopCancellationToken => _stopCancellationTokenSource?.Token ?? default; - public IDependencyResolver WorkerDependencyResolver => this.workerDependencyResolverScope.Resolver; + public IDependencyResolver WorkerDependencyResolver => _workerDependencyResolverScope.Resolver; - public IEvent WorkerStopping => this.workerStoppingEvent; + public IEvent WorkerStopping => _workerStoppingEvent; - public IEvent WorkerStopped => this.workerStoppedEvent; + public IEvent WorkerStopped => _workerStoppedEvent; - public IEvent WorkerProcessingEnded => this.workerProcessingEnded; + public IEvent WorkerProcessingEnded => _workerProcessingEnded; public ValueTask EnqueueAsync( IMessageContext context, CancellationToken stopCancellationToken) { - return this.messagesBuffer.Writer.WriteAsync(context, stopCancellationToken); + return _messagesBuffer.Writer.WriteAsync(context, stopCancellationToken); } public Task StartAsync() { - this.stopCancellationTokenSource = new CancellationTokenSource(); + _stopCancellationTokenSource = new CancellationTokenSource(); - this.backgroundTask = Task.Run( + _backgroundTask = Task.Run( async () => { try { try { - while (await this.messagesBuffer.Reader.WaitToReadAsync(CancellationToken.None).ConfigureAwait(false)) + while (await _messagesBuffer.Reader.WaitToReadAsync(CancellationToken.None).ConfigureAwait(false)) { - while (this.messagesBuffer.Reader.TryRead(out var message)) + while (_messagesBuffer.Reader.TryRead(out var message)) { - await this.ProcessMessageAsync(message, this.stopCancellationTokenSource.Token).ConfigureAwait(false); + await this.ProcessMessageAsync(message, _stopCancellationTokenSource.Token).ConfigureAwait(false); } } } @@ -92,7 +92,7 @@ public Task StartAsync() } catch (Exception ex) { - this.logHandler.Error("KafkaFlow consumer worker fatal error", ex, null); + _logHandler.Error("KafkaFlow consumer worker fatal error", ex, null); } }, CancellationToken.None); @@ -102,25 +102,25 @@ public Task StartAsync() public async Task StopAsync() { - await this.workerStoppingEvent.FireAsync(); + await _workerStoppingEvent.FireAsync(); - this.messagesBuffer.Writer.TryComplete(); + _messagesBuffer.Writer.TryComplete(); - if (this.stopCancellationTokenSource.Token.CanBeCanceled) + if (_stopCancellationTokenSource.Token.CanBeCanceled) { - this.stopCancellationTokenSource.CancelAfter(this.consumer.Configuration.WorkerStopTimeout); + _stopCancellationTokenSource.CancelAfter(_consumer.Configuration.WorkerStopTimeout); } - await this.backgroundTask.ConfigureAwait(false); + await _backgroundTask.ConfigureAwait(false); - await this.workerStoppedEvent.FireAsync(); + await _workerStoppedEvent.FireAsync(); } public void Dispose() { - this.backgroundTask.Dispose(); - this.workerDependencyResolverScope.Dispose(); - this.stopCancellationTokenSource.Dispose(); + _backgroundTask.Dispose(); + _workerDependencyResolverScope.Dispose(); + _stopCancellationTokenSource.Dispose(); } private async Task ProcessMessageAsync(IMessageContext context, CancellationToken cancellationToken) @@ -129,20 +129,20 @@ private async Task ProcessMessageAsync(IMessageContext context, CancellationToke { try { - await this.globalEvents.FireMessageConsumeStartedAsync(new MessageEventContext(context)); + await _globalEvents.FireMessageConsumeStartedAsync(new MessageEventContext(context)); - _= context.ConsumerContext.Completion.ContinueWith( + _ = context.ConsumerContext.Completion.ContinueWith( async task => { if (task.IsFaulted) { - await this.globalEvents.FireMessageConsumeErrorAsync(new MessageErrorEventContext(context, task.Exception)); + await _globalEvents.FireMessageConsumeErrorAsync(new MessageErrorEventContext(context, task.Exception)); } - await this.globalEvents.FireMessageConsumeCompletedAsync(new MessageEventContext(context)); + await _globalEvents.FireMessageConsumeCompletedAsync(new MessageEventContext(context)); }); - await this.middlewareExecutor + await _middlewareExecutor .Execute(context, _ => Task.CompletedTask) .ConfigureAwait(false); } @@ -152,9 +152,9 @@ await this.middlewareExecutor } catch (Exception ex) { - await this.globalEvents.FireMessageConsumeErrorAsync(new MessageErrorEventContext(context, ex)); + await _globalEvents.FireMessageConsumeErrorAsync(new MessageErrorEventContext(context, ex)); - this.logHandler.Error( + _logHandler.Error( "Error processing message", ex, new @@ -172,12 +172,12 @@ await this.middlewareExecutor context.ConsumerContext.Complete(); } - await this.workerProcessingEnded.FireAsync(context); + await _workerProcessingEnded.FireAsync(context); } } catch (Exception ex) { - this.logHandler.Error("KafkaFlow internal message error", ex, null); + _logHandler.Error("KafkaFlow internal message error", ex, null); } } } diff --git a/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs b/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs index 2c45bc2fe..59846df75 100644 --- a/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs +++ b/src/KafkaFlow/Consumers/ConsumerWorkerPool.cs @@ -1,29 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Confluent.Kafka; +using KafkaFlow.Configuration; + namespace KafkaFlow.Consumers { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Threading; - using System.Threading.Tasks; - using Confluent.Kafka; - using KafkaFlow.Configuration; - internal class ConsumerWorkerPool : IConsumerWorkerPool { - private readonly IConsumer consumer; - private readonly IDependencyResolver consumerDependencyResolver; - private readonly IMiddlewareExecutor middlewareExecutor; - private readonly ILogHandler logHandler; - private readonly Factory distributionStrategyFactory; - private readonly IOffsetCommitter offsetCommitter; + private readonly IConsumer _consumer; + private readonly IDependencyResolver _consumerDependencyResolver; + private readonly IMiddlewareExecutor _middlewareExecutor; + private readonly ILogHandler _logHandler; + private readonly Factory _distributionStrategyFactory; + private readonly IOffsetCommitter _offsetCommitter; - private readonly Event workerPoolStoppedSubject; + private readonly Event _workerPoolStoppedSubject; - private TaskCompletionSource startedTaskSource = new(); - private List workers = new(); + private TaskCompletionSource _startedTaskSource = new(); + private List _workers = new(); - private IWorkerDistributionStrategy distributionStrategy; - private IOffsetManager offsetManager; + private IWorkerDistributionStrategy _distributionStrategy; + private IOffsetManager _offsetManager; public ConsumerWorkerPool( IConsumer consumer, @@ -32,36 +32,36 @@ public ConsumerWorkerPool( IConsumerConfiguration consumerConfiguration, ILogHandler logHandler) { - this.consumer = consumer; - this.consumerDependencyResolver = consumerDependencyResolver; - this.middlewareExecutor = middlewareExecutor; - this.logHandler = logHandler; - this.distributionStrategyFactory = consumerConfiguration.DistributionStrategyFactory; - this.workerPoolStoppedSubject = new Event(logHandler); - - this.offsetCommitter = consumer.Configuration.NoStoreOffsets ? + _consumer = consumer; + _consumerDependencyResolver = consumerDependencyResolver; + _middlewareExecutor = middlewareExecutor; + _logHandler = logHandler; + _distributionStrategyFactory = consumerConfiguration.DistributionStrategyFactory; + _workerPoolStoppedSubject = new Event(logHandler); + + _offsetCommitter = consumer.Configuration.NoStoreOffsets ? new NullOffsetCommitter() : new OffsetCommitter( consumer, consumerDependencyResolver, logHandler); - this.offsetCommitter.PendingOffsetsStatisticsHandlers.AddRange(consumer.Configuration.PendingOffsetsStatisticsHandlers); + _offsetCommitter.PendingOffsetsStatisticsHandlers.AddRange(consumer.Configuration.PendingOffsetsStatisticsHandlers); } public int CurrentWorkersCount { get; private set; } - public IEvent WorkerPoolStopped => this.workerPoolStoppedSubject; + public IEvent WorkerPoolStopped => _workerPoolStoppedSubject; public async Task StartAsync(IReadOnlyCollection partitions, int workersCount) { try { - this.offsetManager = this.consumer.Configuration.NoStoreOffsets ? + _offsetManager = _consumer.Configuration.NoStoreOffsets ? new NullOffsetManager() : - new OffsetManager(this.offsetCommitter, partitions); + new OffsetManager(_offsetCommitter, partitions); - await this.offsetCommitter.StartAsync(); + await _offsetCommitter.StartAsync(); this.CurrentWorkersCount = workersCount; @@ -72,67 +72,67 @@ await Task.WhenAll( workerId => { var worker = new ConsumerWorker( - this.consumer, - this.consumerDependencyResolver, + _consumer, + _consumerDependencyResolver, workerId, - this.middlewareExecutor, - this.logHandler); + _middlewareExecutor, + _logHandler); - this.workers.Add(worker); + _workers.Add(worker); return worker.StartAsync(); })) .ConfigureAwait(false); - this.distributionStrategy = this.distributionStrategyFactory(this.consumerDependencyResolver); - this.distributionStrategy.Initialize(this.workers.AsReadOnly()); + _distributionStrategy = _distributionStrategyFactory(_consumerDependencyResolver); + _distributionStrategy.Initialize(_workers.AsReadOnly()); - this.startedTaskSource.TrySetResult(null); + _startedTaskSource.TrySetResult(null); } catch (Exception e) { - this.logHandler.Error( + _logHandler.Error( "Error starting WorkerPool", e, new { - this.consumer.Configuration.ConsumerName, + _consumer.Configuration.ConsumerName, }); } } public async Task StopAsync() { - if (this.workers.Count == 0) + if (_workers.Count == 0) { return; } - var currentWorkers = this.workers; - this.workers = new List(); - this.startedTaskSource = new(); + var currentWorkers = _workers; + _workers = new List(); + _startedTaskSource = new(); await Task.WhenAll(currentWorkers.Select(x => x.StopAsync())).ConfigureAwait(false); - await this.offsetManager.WaitContextsCompletionAsync(); + await _offsetManager.WaitContextsCompletionAsync(); currentWorkers.ForEach(worker => worker.Dispose()); - this.offsetManager = null; + _offsetManager = null; - await this.workerPoolStoppedSubject.FireAsync(); + await _workerPoolStoppedSubject.FireAsync(); - await this.offsetCommitter.StopAsync(); + await _offsetCommitter.StopAsync(); } public async Task EnqueueAsync(ConsumeResult message, CancellationToken stopCancellationToken) { - await this.startedTaskSource.Task.ConfigureAwait(false); + await _startedTaskSource.Task.ConfigureAwait(false); - var worker = (IConsumerWorker)await this.distributionStrategy + var worker = (IConsumerWorker)await _distributionStrategy .GetWorkerAsync( new WorkerDistributionContext( - this.consumer.Configuration.ConsumerName, + _consumer.Configuration.ConsumerName, message.Topic, message.Partition.Value, message.Message.Key, @@ -150,27 +150,27 @@ await worker .EnqueueAsync(context, stopCancellationToken) .ConfigureAwait(false); - this.offsetManager.Enqueue(context.ConsumerContext); + _offsetManager.Enqueue(context.ConsumerContext); } private MessageContext CreateMessageContext(ConsumeResult message, IConsumerWorker worker) { - var messageDependencyScope = this.consumerDependencyResolver.CreateScope(); + var messageDependencyScope = _consumerDependencyResolver.CreateScope(); var context = new MessageContext( new Message(message.Message.Key, message.Message.Value), new MessageHeaders(message.Message.Headers), messageDependencyScope.Resolver, new ConsumerContext( - this.consumer, - this.offsetManager, + _consumer, + _offsetManager, message, worker, messageDependencyScope, - this.consumerDependencyResolver), + _consumerDependencyResolver), null, - this.consumer.Configuration.ClusterConfiguration.Brokers); + _consumer.Configuration.ClusterConfiguration.Brokers); return context; } } -} \ No newline at end of file +} diff --git a/src/KafkaFlow/Consumers/DistributionStrategies/BytesSumDistributionStrategy.cs b/src/KafkaFlow/Consumers/DistributionStrategies/BytesSumDistributionStrategy.cs index 6581cbb6d..095dbd7c1 100644 --- a/src/KafkaFlow/Consumers/DistributionStrategies/BytesSumDistributionStrategy.cs +++ b/src/KafkaFlow/Consumers/DistributionStrategies/BytesSumDistributionStrategy.cs @@ -1,9 +1,9 @@ -namespace KafkaFlow.Consumers.DistributionStrategies; - using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +namespace KafkaFlow.Consumers.DistributionStrategies; + /// /// This strategy sums all bytes in the partition key and apply a mod operator with the total number of workers, the resulting number is the worker ID to be chosen /// This algorithm is fast and creates a good work balance. Messages with the same partition key are always delivered in the same worker, so, message order is guaranteed @@ -11,20 +11,20 @@ namespace KafkaFlow.Consumers.DistributionStrategies; /// public class BytesSumDistributionStrategy : IWorkerDistributionStrategy { - private IReadOnlyList workers; + private IReadOnlyList _workers; /// public void Initialize(IReadOnlyList workers) { - this.workers = workers; + _workers = workers; } /// public ValueTask GetWorkerAsync(WorkerDistributionContext context) { - if (context.RawMessageKey is null || this.workers.Count == 1) + if (context.RawMessageKey is null || _workers.Count == 1) { - return new ValueTask(this.workers[0]); + return new ValueTask(_workers[0]); } var bytesSum = 0; @@ -37,6 +37,6 @@ public ValueTask GetWorkerAsync(WorkerDistributionContext context) return new ValueTask( context.ConsumerStoppedCancellationToken.IsCancellationRequested ? null - : this.workers.ElementAtOrDefault(bytesSum % this.workers.Count)); + : _workers.ElementAtOrDefault(bytesSum % _workers.Count)); } } diff --git a/src/KafkaFlow/Consumers/DistributionStrategies/FreeWorkerDistributionStrategy.cs b/src/KafkaFlow/Consumers/DistributionStrategies/FreeWorkerDistributionStrategy.cs index 9511a868a..3037917c7 100644 --- a/src/KafkaFlow/Consumers/DistributionStrategies/FreeWorkerDistributionStrategy.cs +++ b/src/KafkaFlow/Consumers/DistributionStrategies/FreeWorkerDistributionStrategy.cs @@ -1,30 +1,30 @@ -namespace KafkaFlow.Consumers.DistributionStrategies; - using System.Collections.Generic; using System.Threading.Channels; using System.Threading.Tasks; +namespace KafkaFlow.Consumers.DistributionStrategies; + /// /// This strategy chooses the first free worker to process the message. When a worker finishes the processing, it notifies the worker pool that it is free to get a new message /// This is the fastest and resource-friendly strategy (the message buffer is not used) but messages with the same partition key can be delivered in different workers, so, no message order guarantee /// public class FreeWorkerDistributionStrategy : IWorkerDistributionStrategy { - private readonly Channel freeWorkers = Channel.CreateUnbounded(); + private readonly Channel _freeWorkers = Channel.CreateUnbounded(); /// public void Initialize(IReadOnlyList workers) { foreach (var worker in workers) { - worker.WorkerProcessingEnded.Subscribe(_ => Task.FromResult(this.freeWorkers.Writer.WriteAsync(worker))); - this.freeWorkers.Writer.TryWrite(worker); + worker.WorkerProcessingEnded.Subscribe(_ => Task.FromResult(_freeWorkers.Writer.WriteAsync(worker))); + _freeWorkers.Writer.TryWrite(worker); } } /// public ValueTask GetWorkerAsync(WorkerDistributionContext context) { - return this.freeWorkers.Reader.ReadAsync(context.ConsumerStoppedCancellationToken); + return _freeWorkers.Reader.ReadAsync(context.ConsumerStoppedCancellationToken); } -} \ No newline at end of file +} diff --git a/src/KafkaFlow/Consumers/IConsumer.cs b/src/KafkaFlow/Consumers/IConsumer.cs index 4774289c7..3516aa609 100644 --- a/src/KafkaFlow/Consumers/IConsumer.cs +++ b/src/KafkaFlow/Consumers/IConsumer.cs @@ -1,12 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using KafkaFlow.Configuration; + namespace KafkaFlow.Consumers { - using System; - using System.Collections.Generic; - using System.Threading; - using System.Threading.Tasks; - using Confluent.Kafka; - using KafkaFlow.Configuration; - /// /// Represents a KafkaFlow consumer /// @@ -17,21 +16,21 @@ public interface IConsumer : IDisposable /// IConsumerConfiguration Configuration { get; } - /// + /// IReadOnlyList Subscription { get; } - /// - IReadOnlyList Assignment { get; } + /// + IReadOnlyList Assignment { get; } /// /// Gets the consumer /// IConsumerFlowManager FlowManager { get; } - /// + /// string MemberId { get; } - /// + /// string ClientInstanceName { get; } /// @@ -49,44 +48,44 @@ public interface IConsumer : IDisposable /// Register a handler to be executed when the partitions are assigned /// /// The handler that will be executed - void OnPartitionsAssigned(Action, List> handler); + void OnPartitionsAssigned(Action, List> handler); /// /// Register a handler to be executed when the partitions are revoked /// /// The handler that will be executed - void OnPartitionsRevoked(Action, List> handler); + void OnPartitionsRevoked(Action, List> handler); /// /// Register a handler to be executed when an error occurs /// /// The handler that will be executed - void OnError(Action, Error> handler); + void OnError(Action, Confluent.Kafka.Error> handler); /// /// Register a handler to be executed to receive statistics information /// /// The handler that will be executed - void OnStatistics(Action, string> handler); + void OnStatistics(Action, string> handler); - /// - Offset GetPosition(TopicPartition topicPartition); + /// + Confluent.Kafka.Offset GetPosition(Confluent.Kafka.TopicPartition topicPartition); - /// - WatermarkOffsets GetWatermarkOffsets(TopicPartition topicPartition); + /// + Confluent.Kafka.WatermarkOffsets GetWatermarkOffsets(Confluent.Kafka.TopicPartition topicPartition); - /// - WatermarkOffsets QueryWatermarkOffsets(TopicPartition topicPartition, TimeSpan timeout); + /// + Confluent.Kafka.WatermarkOffsets QueryWatermarkOffsets(Confluent.Kafka.TopicPartition topicPartition, TimeSpan timeout); - /// - List OffsetsForTimes( - IEnumerable topicPartitions, + /// + List OffsetsForTimes( + IEnumerable topicPartitions, TimeSpan timeout); - /// - void Commit(IReadOnlyCollection offsetsValues); + /// + void Commit(IReadOnlyCollection offsetsValues); - /// - ValueTask> ConsumeAsync(CancellationToken cancellationToken); + /// + ValueTask> ConsumeAsync(CancellationToken cancellationToken); } } diff --git a/src/KafkaFlow/Consumers/IConsumerAccessor.cs b/src/KafkaFlow/Consumers/IConsumerAccessor.cs index 48033804b..f3db89fa2 100644 --- a/src/KafkaFlow/Consumers/IConsumerAccessor.cs +++ b/src/KafkaFlow/Consumers/IConsumerAccessor.cs @@ -1,7 +1,7 @@ +using System.Collections.Generic; + namespace KafkaFlow.Consumers { - using System.Collections.Generic; - /// /// Provides access to the configured consumers /// diff --git a/src/KafkaFlow/Consumers/IConsumerFlowManager.cs b/src/KafkaFlow/Consumers/IConsumerFlowManager.cs index 3102da03a..5dcf19ade 100644 --- a/src/KafkaFlow/Consumers/IConsumerFlowManager.cs +++ b/src/KafkaFlow/Consumers/IConsumerFlowManager.cs @@ -1,8 +1,8 @@ +using System.Collections.Generic; +using Confluent.Kafka; + namespace KafkaFlow.Consumers { - using System.Collections.Generic; - using Confluent.Kafka; - /// /// The consumer flow manager /// diff --git a/src/KafkaFlow/Consumers/IConsumerManager.cs b/src/KafkaFlow/Consumers/IConsumerManager.cs index a96d1fc84..fef29e6ce 100644 --- a/src/KafkaFlow/Consumers/IConsumerManager.cs +++ b/src/KafkaFlow/Consumers/IConsumerManager.cs @@ -1,7 +1,7 @@ +using System.Threading.Tasks; + namespace KafkaFlow.Consumers { - using System.Threading.Tasks; - internal interface IConsumerManager { IWorkerPoolFeeder Feeder { get; } diff --git a/src/KafkaFlow/Consumers/IConsumerWorker.cs b/src/KafkaFlow/Consumers/IConsumerWorker.cs index bf997816a..11c544d0a 100644 --- a/src/KafkaFlow/Consumers/IConsumerWorker.cs +++ b/src/KafkaFlow/Consumers/IConsumerWorker.cs @@ -1,9 +1,9 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + namespace KafkaFlow.Consumers { - using System; - using System.Threading; - using System.Threading.Tasks; - internal interface IConsumerWorker : IWorker, IDisposable { CancellationToken StopCancellationToken { get; } diff --git a/src/KafkaFlow/Consumers/IConsumerWorkerPool.cs b/src/KafkaFlow/Consumers/IConsumerWorkerPool.cs index 32f0c51f1..3824faa1a 100644 --- a/src/KafkaFlow/Consumers/IConsumerWorkerPool.cs +++ b/src/KafkaFlow/Consumers/IConsumerWorkerPool.cs @@ -1,10 +1,10 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Confluent.Kafka; + namespace KafkaFlow.Consumers { - using System.Collections.Generic; - using System.Threading; - using System.Threading.Tasks; - using Confluent.Kafka; - internal interface IConsumerWorkerPool { int CurrentWorkersCount { get; } diff --git a/src/KafkaFlow/Consumers/IMessageConsumer.cs b/src/KafkaFlow/Consumers/IMessageConsumer.cs index 70041a49f..78e7271ef 100644 --- a/src/KafkaFlow/Consumers/IMessageConsumer.cs +++ b/src/KafkaFlow/Consumers/IMessageConsumer.cs @@ -1,10 +1,9 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + namespace KafkaFlow.Consumers { - using System; - using System.Collections.Generic; - using System.Threading.Tasks; - using Confluent.Kafka; - /// /// Provides access to the kafka message consumer /// @@ -48,7 +47,7 @@ public interface IMessageConsumer /// /// Gets the current partition assignment /// - IReadOnlyList Assignment { get; } + IReadOnlyList Assignment { get; } /// /// Gets the (dynamic) group member id of this consumer (as set by the broker). @@ -77,12 +76,12 @@ public interface IMessageConsumer /// /// Gets the consumer's paused partitions /// - IReadOnlyList PausedPartitions { get; } + IReadOnlyList PausedPartitions { get; } /// /// Gets the consumer's running partitions /// - IEnumerable RunningPartitions { get; } + IEnumerable RunningPartitions { get; } /// /// Gets the lag of each topic/partitions assigned @@ -94,7 +93,7 @@ public interface IMessageConsumer /// Overrides the offsets of the given partitions and restart the consumer /// /// The offset values - Task OverrideOffsetsAndRestartAsync(IReadOnlyCollection offsets); + Task OverrideOffsetsAndRestartAsync(IReadOnlyCollection offsets); /// /// Restart the current consumer with the new worker count @@ -134,7 +133,7 @@ public interface IMessageConsumer /// /// Per partition success or error. /// - void Pause(IReadOnlyCollection partitions); + void Pause(IReadOnlyCollection partitions); /// /// Resume consumption for the provided list of partitions. @@ -148,7 +147,7 @@ public interface IMessageConsumer /// /// Per partition success or error. /// - void Resume(IReadOnlyCollection partitions); + void Resume(IReadOnlyCollection partitions); /// /// Gets the current position (offset) for the @@ -162,7 +161,7 @@ public interface IMessageConsumer /// /// Thrown if the request failed. /// - Offset GetPosition(TopicPartition topicPartition); + Confluent.Kafka.Offset GetPosition(Confluent.Kafka.TopicPartition topicPartition); /// /// Get the last cached low (oldest available / @@ -185,7 +184,7 @@ public interface IMessageConsumer /// The requested WatermarkOffsets /// (see that class for additional documentation). /// - WatermarkOffsets GetWatermarkOffsets(TopicPartition topicPartition); + Confluent.Kafka.WatermarkOffsets GetWatermarkOffsets(Confluent.Kafka.TopicPartition topicPartition); /// /// Query the Kafka cluster for low (oldest @@ -205,7 +204,7 @@ public interface IMessageConsumer /// The requested WatermarkOffsets (see /// that class for additional documentation). /// - WatermarkOffsets QueryWatermarkOffsets(TopicPartition topicPartition, TimeSpan timeout); + Confluent.Kafka.WatermarkOffsets QueryWatermarkOffsets(Confluent.Kafka.TopicPartition topicPartition, TimeSpan timeout); /// /// Look up the offsets for the given partitions @@ -244,8 +243,8 @@ public interface IMessageConsumer /// /// property of the exception. /// - List GetOffsets( - IEnumerable timestampsToSearch, + List GetOffsets( + IEnumerable timestampsToSearch, TimeSpan timeout); } } diff --git a/src/KafkaFlow/Consumers/IOffsetCommitter.cs b/src/KafkaFlow/Consumers/IOffsetCommitter.cs index 2986b610e..3fe5227af 100644 --- a/src/KafkaFlow/Consumers/IOffsetCommitter.cs +++ b/src/KafkaFlow/Consumers/IOffsetCommitter.cs @@ -1,9 +1,9 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using KafkaFlow.Configuration; + namespace KafkaFlow.Consumers { - using System.Collections.Generic; - using System.Threading.Tasks; - using KafkaFlow.Configuration; - internal interface IOffsetCommitter { List PendingOffsetsStatisticsHandlers { get; } diff --git a/src/KafkaFlow/Consumers/IOffsetManager.cs b/src/KafkaFlow/Consumers/IOffsetManager.cs index aff5e27ab..feba67859 100644 --- a/src/KafkaFlow/Consumers/IOffsetManager.cs +++ b/src/KafkaFlow/Consumers/IOffsetManager.cs @@ -1,7 +1,7 @@ +using System.Threading.Tasks; + namespace KafkaFlow.Consumers { - using System.Threading.Tasks; - internal interface IOffsetManager { void Enqueue(IConsumerContext context); diff --git a/src/KafkaFlow/Consumers/IWorkerPoolFeeder.cs b/src/KafkaFlow/Consumers/IWorkerPoolFeeder.cs index 0ae7f6aad..3f36a8be5 100644 --- a/src/KafkaFlow/Consumers/IWorkerPoolFeeder.cs +++ b/src/KafkaFlow/Consumers/IWorkerPoolFeeder.cs @@ -1,7 +1,7 @@ +using System.Threading.Tasks; + namespace KafkaFlow.Consumers { - using System.Threading.Tasks; - internal interface IWorkerPoolFeeder { void Start(); diff --git a/src/KafkaFlow/Consumers/MessageConsumer.cs b/src/KafkaFlow/Consumers/MessageConsumer.cs index 262854764..acbcc82f7 100644 --- a/src/KafkaFlow/Consumers/MessageConsumer.cs +++ b/src/KafkaFlow/Consumers/MessageConsumer.cs @@ -1,117 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + namespace KafkaFlow.Consumers { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - using Confluent.Kafka; - internal class MessageConsumer : IMessageConsumer { - private static readonly IReadOnlyList EmptyTopicPartition = new List().AsReadOnly(); + private static readonly IReadOnlyList s_emptyTopicPartition = new List().AsReadOnly(); - private readonly IConsumerManager consumerManager; - private readonly ILogHandler logHandler; + private readonly IConsumerManager _consumerManager; + private readonly ILogHandler _logHandler; public MessageConsumer( IConsumerManager consumerManager, ILogHandler logHandler) { - this.consumerManager = consumerManager; - this.logHandler = logHandler; + _consumerManager = consumerManager; + _logHandler = logHandler; } - public string ConsumerName => this.consumerManager.Consumer.Configuration.ConsumerName; + public string ConsumerName => _consumerManager.Consumer.Configuration.ConsumerName; - public string ClusterName => this.consumerManager.Consumer.Configuration.ClusterConfiguration.Name; + public string ClusterName => _consumerManager.Consumer.Configuration.ClusterConfiguration.Name; - public bool ManagementDisabled => this.consumerManager.Consumer.Configuration.ManagementDisabled; + public bool ManagementDisabled => _consumerManager.Consumer.Configuration.ManagementDisabled; - public string GroupId => this.consumerManager.Consumer.Configuration.GroupId; + public string GroupId => _consumerManager.Consumer.Configuration.GroupId; - public IReadOnlyList Topics => this.consumerManager.Consumer.Configuration.Topics; + public IReadOnlyList Topics => _consumerManager.Consumer.Configuration.Topics; - public IReadOnlyList Subscription => this.consumerManager.Consumer.Subscription; + public IReadOnlyList Subscription => _consumerManager.Consumer.Subscription; - public IReadOnlyList Assignment => this.consumerManager.Consumer.Assignment ?? EmptyTopicPartition; + public IReadOnlyList Assignment => _consumerManager.Consumer.Assignment ?? s_emptyTopicPartition; - public ConsumerStatus Status => this.consumerManager.Consumer.Status; + public ConsumerStatus Status => _consumerManager.Consumer.Status; - public string MemberId => this.consumerManager.Consumer.MemberId; + public string MemberId => _consumerManager.Consumer.MemberId; - public string ClientInstanceName => this.consumerManager.Consumer.ClientInstanceName; + public string ClientInstanceName => _consumerManager.Consumer.ClientInstanceName; - public int WorkersCount => this.consumerManager.WorkerPool.CurrentWorkersCount; + public int WorkersCount => _consumerManager.WorkerPool.CurrentWorkersCount; - public IReadOnlyList PausedPartitions => - this.consumerManager.Consumer.FlowManager?.PausedPartitions ?? - EmptyTopicPartition; + public IReadOnlyList PausedPartitions => + _consumerManager.Consumer.FlowManager?.PausedPartitions ?? + s_emptyTopicPartition; - public IEnumerable RunningPartitions => this.Assignment.Except(this.PausedPartitions); + public IEnumerable RunningPartitions => this.Assignment.Except(this.PausedPartitions); public async Task StartAsync() { - await this.consumerManager.StartAsync().ConfigureAwait(false); - this.logHandler.Info($"Kafka consumer '{this.ConsumerName}' was manually started", null); + await _consumerManager.StartAsync().ConfigureAwait(false); + _logHandler.Info($"Kafka consumer '{this.ConsumerName}' was manually started", null); } public async Task StopAsync() { - await this.consumerManager.StopAsync().ConfigureAwait(false); - this.logHandler.Info($"Kafka consumer '{this.ConsumerName}' was manually stopped", null); + await _consumerManager.StopAsync().ConfigureAwait(false); + _logHandler.Info($"Kafka consumer '{this.ConsumerName}' was manually stopped", null); } public async Task RestartAsync() { await this.InternalRestart().ConfigureAwait(false); - this.logHandler.Info($"Kafka consumer '{this.ConsumerName}' was manually restarted", null); + _logHandler.Info($"Kafka consumer '{this.ConsumerName}' was manually restarted", null); } - public void Pause(IReadOnlyCollection topicPartitions) + public void Pause(IReadOnlyCollection topicPartitions) { - this.consumerManager.Consumer.FlowManager.Pause(topicPartitions); - this.logHandler.Info($"Kafka consumer '{this.ConsumerName}' was paused", topicPartitions); + _consumerManager.Consumer.FlowManager.Pause(topicPartitions); + _logHandler.Info($"Kafka consumer '{this.ConsumerName}' was paused", topicPartitions); } - public void Resume(IReadOnlyCollection topicPartitions) + public void Resume(IReadOnlyCollection topicPartitions) { - this.consumerManager.Consumer.FlowManager.Resume(topicPartitions); - this.logHandler.Info($"Kafka consumer '{this.ConsumerName}' was resumed", topicPartitions); + _consumerManager.Consumer.FlowManager.Resume(topicPartitions); + _logHandler.Info($"Kafka consumer '{this.ConsumerName}' was resumed", topicPartitions); } - public Offset GetPosition(TopicPartition topicPartition) => - this.consumerManager.Consumer.GetPosition(topicPartition); + public Confluent.Kafka.Offset GetPosition(Confluent.Kafka.TopicPartition topicPartition) => + _consumerManager.Consumer.GetPosition(topicPartition); - public WatermarkOffsets GetWatermarkOffsets(TopicPartition topicPartition) => - this.consumerManager.Consumer.GetWatermarkOffsets(topicPartition); + public Confluent.Kafka.WatermarkOffsets GetWatermarkOffsets(Confluent.Kafka.TopicPartition topicPartition) => + _consumerManager.Consumer.GetWatermarkOffsets(topicPartition); - public WatermarkOffsets QueryWatermarkOffsets(TopicPartition topicPartition, TimeSpan timeout) => - this.consumerManager.Consumer.QueryWatermarkOffsets(topicPartition, timeout); + public Confluent.Kafka.WatermarkOffsets QueryWatermarkOffsets(Confluent.Kafka.TopicPartition topicPartition, TimeSpan timeout) => + _consumerManager.Consumer.QueryWatermarkOffsets(topicPartition, timeout); - public List GetOffsets( - IEnumerable topicPartitions, + public List GetOffsets( + IEnumerable topicPartitions, TimeSpan timeout) => - this.consumerManager.Consumer.OffsetsForTimes(topicPartitions, timeout); + _consumerManager.Consumer.OffsetsForTimes(topicPartitions, timeout); public IEnumerable GetTopicPartitionsLag() => - this.consumerManager.Consumer.GetTopicPartitionsLag(); + _consumerManager.Consumer.GetTopicPartitionsLag(); - public async Task OverrideOffsetsAndRestartAsync(IReadOnlyCollection offsets) + public async Task OverrideOffsetsAndRestartAsync(IReadOnlyCollection offsets) { try { - await this.consumerManager.Feeder.StopAsync().ConfigureAwait(false); - await this.consumerManager.WorkerPool.StopAsync().ConfigureAwait(false); + await _consumerManager.Feeder.StopAsync().ConfigureAwait(false); + await _consumerManager.WorkerPool.StopAsync().ConfigureAwait(false); - this.consumerManager.Consumer.Commit(offsets); + _consumerManager.Consumer.Commit(offsets); await this.InternalRestart().ConfigureAwait(false); - this.logHandler.Info($"Offsets of Kafka consumer '{this.ConsumerName}' were overridden ", GetOffsetsLogData(offsets)); + _logHandler.Info($"Offsets of Kafka consumer '{this.ConsumerName}' were overridden ", GetOffsetsLogData(offsets)); } catch (Exception e) { - this.logHandler.Error( + _logHandler.Error( "Error overriding offsets", e, GetOffsetsLogData(offsets)); @@ -121,16 +120,16 @@ public async Task OverrideOffsetsAndRestartAsync(IReadOnlyCollection Task.FromResult(workersCount); + _consumerManager.Consumer.Configuration.WorkersCountCalculator = (_, _) => Task.FromResult(workersCount); await this.InternalRestart().ConfigureAwait(false); - this.logHandler.Info( + _logHandler.Info( $"Total of workers in KafkaFlow consumer '{this.ConsumerName}' were updated", new { workersCount }); } - private static object GetOffsetsLogData(IEnumerable offsets) => offsets + private static object GetOffsetsLogData(IEnumerable offsets) => offsets .GroupBy(x => x.Topic) .Select( x => new @@ -146,9 +145,9 @@ private static object GetOffsetsLogData(IEnumerable offset private async Task InternalRestart() { - await this.consumerManager.StopAsync().ConfigureAwait(false); + await _consumerManager.StopAsync().ConfigureAwait(false); await Task.Delay(5000).ConfigureAwait(false); - await this.consumerManager.StartAsync().ConfigureAwait(false); + await _consumerManager.StartAsync().ConfigureAwait(false); } } } diff --git a/src/KafkaFlow/Consumers/NullOffsetCommitter.cs b/src/KafkaFlow/Consumers/NullOffsetCommitter.cs index 27228989c..7de25bc93 100644 --- a/src/KafkaFlow/Consumers/NullOffsetCommitter.cs +++ b/src/KafkaFlow/Consumers/NullOffsetCommitter.cs @@ -1,10 +1,9 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using KafkaFlow.Configuration; + namespace KafkaFlow.Consumers { - using System.Collections.Generic; - using System.Threading.Tasks; - using KafkaFlow; - using KafkaFlow.Configuration; - internal class NullOffsetCommitter : IOffsetCommitter { public List PendingOffsetsStatisticsHandlers { get; } = new(); diff --git a/src/KafkaFlow/Consumers/NullOffsetManager.cs b/src/KafkaFlow/Consumers/NullOffsetManager.cs index a9c4df3d3..8faaa3f74 100644 --- a/src/KafkaFlow/Consumers/NullOffsetManager.cs +++ b/src/KafkaFlow/Consumers/NullOffsetManager.cs @@ -1,7 +1,7 @@ +using System.Threading.Tasks; + namespace KafkaFlow.Consumers { - using System.Threading.Tasks; - internal class NullOffsetManager : IOffsetManager { public void Enqueue(IConsumerContext context) diff --git a/src/KafkaFlow/Consumers/OffsetCommitter.cs b/src/KafkaFlow/Consumers/OffsetCommitter.cs index f93e6ac99..b51aca2ec 100644 --- a/src/KafkaFlow/Consumers/OffsetCommitter.cs +++ b/src/KafkaFlow/Consumers/OffsetCommitter.cs @@ -1,42 +1,42 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using KafkaFlow.Configuration; + namespace KafkaFlow.Consumers { - using System; - using System.Collections.Concurrent; - using System.Collections.Generic; - using System.Linq; - using System.Threading; - using System.Threading.Tasks; - using KafkaFlow.Configuration; - internal class OffsetCommitter : IOffsetCommitter { - private readonly IConsumer consumer; - private readonly IDependencyResolver resolver; + private readonly IConsumer _consumer; + private readonly IDependencyResolver _resolver; - private readonly ILogHandler logHandler; + private readonly ILogHandler _logHandler; - private readonly object commitSyncRoot = new(); + private readonly object _commitSyncRoot = new(); - private Timer commitTimer; - private IReadOnlyList statisticsTimers; + private Timer _commitTimer; + private IReadOnlyList _statisticsTimers; - private ConcurrentDictionary<(string, int), TopicPartitionOffset> offsetsToCommit = new(); + private ConcurrentDictionary<(string, int), TopicPartitionOffset> _offsetsToCommit = new(); public OffsetCommitter( IConsumer consumer, IDependencyResolver resolver, ILogHandler logHandler) { - this.consumer = consumer; - this.resolver = resolver; - this.logHandler = logHandler; + _consumer = consumer; + _resolver = resolver; + _logHandler = logHandler; } public List PendingOffsetsStatisticsHandlers { get; } = new(); public void MarkAsProcessed(TopicPartitionOffset tpo) { - this.offsetsToCommit.AddOrUpdate( + _offsetsToCommit.AddOrUpdate( (tpo.Topic, tpo.Partition), tpo, (_, _) => tpo); @@ -44,13 +44,13 @@ public void MarkAsProcessed(TopicPartitionOffset tpo) public Task StartAsync() { - this.commitTimer = new Timer( + _commitTimer = new Timer( _ => this.CommitHandler(), null, - this.consumer.Configuration.AutoCommitInterval, - this.consumer.Configuration.AutoCommitInterval); + _consumer.Configuration.AutoCommitInterval, + _consumer.Configuration.AutoCommitInterval); - this.statisticsTimers = this.PendingOffsetsStatisticsHandlers + _statisticsTimers = this.PendingOffsetsStatisticsHandlers .Select( handler => new Timer( _ => this.PendingOffsetsHandler(handler), @@ -64,10 +64,10 @@ public Task StartAsync() public Task StopAsync() { - this.commitTimer.Dispose(); + _commitTimer.Dispose(); this.CommitHandler(); - foreach (var timer in this.statisticsTimers) + foreach (var timer in _statisticsTimers) { timer.Dispose(); } @@ -77,11 +77,11 @@ public Task StopAsync() private void PendingOffsetsHandler(PendingOffsetsStatisticsHandler handler) { - if (!this.offsetsToCommit.IsEmpty) + if (!_offsetsToCommit.IsEmpty) { handler.Handler( - this.resolver, - this.offsetsToCommit.Values.Select( + _resolver, + _offsetsToCommit.Values.Select( x => new Confluent.Kafka.TopicPartitionOffset(x.Topic, x.Partition, x.Offset))); } @@ -89,34 +89,34 @@ private void PendingOffsetsHandler(PendingOffsetsStatisticsHandler handler) private void CommitHandler() { - lock (this.commitSyncRoot) + lock (_commitSyncRoot) { ConcurrentDictionary<(string, int), TopicPartitionOffset> offsets = null; try { - if (!this.offsetsToCommit.Any()) + if (!_offsetsToCommit.Any()) { return; } offsets = Interlocked.Exchange( - ref this.offsetsToCommit, + ref _offsetsToCommit, new ConcurrentDictionary<(string, int), TopicPartitionOffset>()); - this.consumer.Commit( + _consumer.Commit( offsets.Values .Select(x => new Confluent.Kafka.TopicPartitionOffset(x.Topic, x.Partition, x.Offset + 1)) .ToList()); - if (!this.consumer.Configuration.ManagementDisabled) + if (!_consumer.Configuration.ManagementDisabled) { this.LogOffsetsCommitted(offsets.Values); } } catch (Exception e) { - this.logHandler.Warning( + _logHandler.Warning( "Error Commiting Offsets", new { ErrorMessage = e.Message }); @@ -130,7 +130,7 @@ private void CommitHandler() private void LogOffsetsCommitted(IEnumerable offsets) { - this.logHandler.Verbose( + _logHandler.Verbose( "Offsets committed", new { @@ -153,7 +153,7 @@ private void RequeueFailedOffsets(IEnumerable offsets) { foreach (var tpo in offsets) { - this.offsetsToCommit.TryAdd((tpo.Topic, tpo.Partition), tpo); + _offsetsToCommit.TryAdd((tpo.Topic, tpo.Partition), tpo); } } } diff --git a/src/KafkaFlow/Consumers/OffsetManager.cs b/src/KafkaFlow/Consumers/OffsetManager.cs index 657091486..883c5e317 100644 --- a/src/KafkaFlow/Consumers/OffsetManager.cs +++ b/src/KafkaFlow/Consumers/OffsetManager.cs @@ -1,28 +1,28 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Confluent.Kafka; + namespace KafkaFlow.Consumers { - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - using Confluent.Kafka; - internal class OffsetManager : IOffsetManager { - private readonly IOffsetCommitter committer; - private readonly Dictionary<(string, int), PartitionOffsets> partitionsOffsets; + private readonly IOffsetCommitter _committer; + private readonly Dictionary<(string, int), PartitionOffsets> _partitionsOffsets; public OffsetManager( IOffsetCommitter committer, IEnumerable partitions) { - this.committer = committer; - this.partitionsOffsets = partitions.ToDictionary( + _committer = committer; + _partitionsOffsets = partitions.ToDictionary( partition => (partition.Topic, partition.Partition.Value), _ => new PartitionOffsets()); } public void MarkAsProcessed(IConsumerContext context) { - if (!this.partitionsOffsets.TryGetValue((context.Topic, context.Partition), out var offsets)) + if (!_partitionsOffsets.TryGetValue((context.Topic, context.Partition), out var offsets)) { return; } @@ -31,14 +31,14 @@ public void MarkAsProcessed(IConsumerContext context) { if (offsets.TryDequeue(context)) { - this.committer.MarkAsProcessed(offsets.DequeuedContext.TopicPartitionOffset); + _committer.MarkAsProcessed(offsets.DequeuedContext.TopicPartitionOffset); } } } public void Enqueue(IConsumerContext context) { - if (this.partitionsOffsets.TryGetValue( + if (_partitionsOffsets.TryGetValue( (context.Topic, context.Partition), out var offsets)) { @@ -48,7 +48,7 @@ public void Enqueue(IConsumerContext context) public Task WaitContextsCompletionAsync() => Task.WhenAll( - this.partitionsOffsets + _partitionsOffsets .Select(x => x.Value.WaitContextsCompletionAsync()) .ToList()); } diff --git a/src/KafkaFlow/Consumers/OffsetsWatermark.cs b/src/KafkaFlow/Consumers/OffsetsWatermark.cs index 184e08a35..d24b55890 100644 --- a/src/KafkaFlow/Consumers/OffsetsWatermark.cs +++ b/src/KafkaFlow/Consumers/OffsetsWatermark.cs @@ -1,24 +1,24 @@ +using System; +using Confluent.Kafka; + namespace KafkaFlow.Consumers { - using System; - using Confluent.Kafka; - internal readonly struct OffsetsWatermark : IOffsetsWatermark, IEquatable { - private readonly WatermarkOffsets watermark; + private readonly WatermarkOffsets _watermark; public OffsetsWatermark(WatermarkOffsets watermark) { - this.watermark = watermark; + _watermark = watermark; } - public long High => this.watermark.High.Value; + public long High => _watermark.High.Value; - public long Low => this.watermark.Low.Value; + public long Low => _watermark.Low.Value; public bool Equals(OffsetsWatermark other) { - return Equals(this.watermark, other.watermark); + return Equals(_watermark, other._watermark); } public override bool Equals(object obj) @@ -28,7 +28,7 @@ public override bool Equals(object obj) public override int GetHashCode() { - return this.watermark != null ? this.watermark.GetHashCode() : 0; + return _watermark != null ? _watermark.GetHashCode() : 0; } } } diff --git a/src/KafkaFlow/Consumers/PartitionOffsets.cs b/src/KafkaFlow/Consumers/PartitionOffsets.cs index 36fa60314..9a4eada09 100644 --- a/src/KafkaFlow/Consumers/PartitionOffsets.cs +++ b/src/KafkaFlow/Consumers/PartitionOffsets.cs @@ -1,22 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + namespace KafkaFlow.Consumers { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - internal class PartitionOffsets { - private readonly SortedDictionary processedContexts = new(); - private readonly LinkedList receivedContexts = new(); + private readonly SortedDictionary _processedContexts = new(); + private readonly LinkedList _receivedContexts = new(); public IConsumerContext DequeuedContext { get; private set; } public void Enqueue(IConsumerContext context) { - lock (this.receivedContexts) + lock (_receivedContexts) { - this.receivedContexts.AddLast(context); + _receivedContexts.AddLast(context); } } @@ -24,32 +24,33 @@ public bool TryDequeue(IConsumerContext context) { this.DequeuedContext = null; - lock (this.receivedContexts) + lock (_receivedContexts) { - if (!this.receivedContexts.Any()) + if (!_receivedContexts.Any()) { throw new InvalidOperationException( $"There is no offsets in the received queue. Call {nameof(this.Enqueue)} first"); } - if (context.Offset != this.receivedContexts.First.Value.Offset) + if (context.Offset != _receivedContexts.First.Value.Offset) { - this.processedContexts.Add(context.Offset, context); + _processedContexts.Add(context.Offset, context); return false; } do { - this.DequeuedContext = this.receivedContexts.First.Value; - this.receivedContexts.RemoveFirst(); - } while (this.receivedContexts.Count > 0 && this.processedContexts.Remove(this.receivedContexts.First.Value.Offset)); + this.DequeuedContext = _receivedContexts.First.Value; + _receivedContexts.RemoveFirst(); + } + while (_receivedContexts.Count > 0 && _processedContexts.Remove(_receivedContexts.First.Value.Offset)); } return true; } public Task WaitContextsCompletionAsync() => Task.WhenAll( - this.receivedContexts + _receivedContexts .Select(x => x.Completion) .ToList()); } diff --git a/src/KafkaFlow/Consumers/WorkerPoolFeeder.cs b/src/KafkaFlow/Consumers/WorkerPoolFeeder.cs index 79f3cf8b6..d56625a0d 100644 --- a/src/KafkaFlow/Consumers/WorkerPoolFeeder.cs +++ b/src/KafkaFlow/Consumers/WorkerPoolFeeder.cs @@ -1,41 +1,41 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + namespace KafkaFlow.Consumers { - using System; - using System.Threading; - using System.Threading.Tasks; - internal class WorkerPoolFeeder : IWorkerPoolFeeder { - private readonly IConsumer consumer; - private readonly IConsumerWorkerPool workerPool; - private readonly ILogHandler logHandler; + private readonly IConsumer _consumer; + private readonly IConsumerWorkerPool _workerPool; + private readonly ILogHandler _logHandler; - private CancellationTokenSource stopTokenSource; - private Task feederTask; + private CancellationTokenSource _stopTokenSource; + private Task _feederTask; public WorkerPoolFeeder( IConsumer consumer, IConsumerWorkerPool workerPool, ILogHandler logHandler) { - this.consumer = consumer; - this.workerPool = workerPool; - this.logHandler = logHandler; + _consumer = consumer; + _workerPool = workerPool; + _logHandler = logHandler; } public void Start() { - this.stopTokenSource = new CancellationTokenSource(); - var token = this.stopTokenSource.Token; + _stopTokenSource = new CancellationTokenSource(); + var token = _stopTokenSource.Token; - this.feederTask = Task.Run( + _feederTask = Task.Run( async () => { while (!token.IsCancellationRequested) { try { - var message = await this.consumer + var message = await _consumer .ConsumeAsync(token) .ConfigureAwait(false); @@ -44,7 +44,7 @@ public void Start() continue; } - await this.workerPool + await _workerPool .EnqueueAsync(message, token) .ConfigureAwait(false); } @@ -54,7 +54,7 @@ await this.workerPool } catch (Exception ex) { - this.logHandler.Error( + _logHandler.Error( "Error consuming message from Kafka", ex, null); @@ -66,13 +66,13 @@ await this.workerPool public async Task StopAsync() { - if (this.stopTokenSource is { IsCancellationRequested: false }) + if (_stopTokenSource is { IsCancellationRequested: false }) { - this.stopTokenSource.Cancel(); - this.stopTokenSource.Dispose(); + _stopTokenSource.Cancel(); + _stopTokenSource.Dispose(); } - await (this.feederTask ?? Task.CompletedTask); + await (_feederTask ?? Task.CompletedTask); } } } diff --git a/src/KafkaFlow/Consumers/WorkersBalancers/ConsumerLagWorkerBalancer.cs b/src/KafkaFlow/Consumers/WorkersBalancers/ConsumerLagWorkerBalancer.cs index 911d4fb7a..59d0d068b 100644 --- a/src/KafkaFlow/Consumers/WorkersBalancers/ConsumerLagWorkerBalancer.cs +++ b/src/KafkaFlow/Consumers/WorkersBalancers/ConsumerLagWorkerBalancer.cs @@ -1,12 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using KafkaFlow.Clusters; +using KafkaFlow.Configuration; + namespace KafkaFlow.Consumers.WorkersBalancers { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - using KafkaFlow.Clusters; - using KafkaFlow.Configuration; - /// /// Represents a balancer that dynamically calculates the number of workers for a consumer based on the current lag. /// The calculation employs a simple rule of three considering the total lag across all application instances, @@ -16,12 +16,12 @@ internal class ConsumerLagWorkerBalancer { private const int DefaultWorkersCount = 1; - private readonly IClusterManager clusterManager; - private readonly IConsumerAccessor consumerAccessor; - private readonly ILogHandler logHandler; - private readonly int totalConsumerWorkers; - private readonly int minInstanceWorkers; - private readonly int maxInstanceWorkers; + private readonly IClusterManager _clusterManager; + private readonly IConsumerAccessor _consumerAccessor; + private readonly ILogHandler _logHandler; + private readonly int _totalConsumerWorkers; + private readonly int _minInstanceWorkers; + private readonly int _maxInstanceWorkers; public ConsumerLagWorkerBalancer( IClusterManager clusterManager, @@ -31,19 +31,19 @@ public ConsumerLagWorkerBalancer( int minInstanceWorkers, int maxInstanceWorkers) { - this.clusterManager = clusterManager; - this.consumerAccessor = consumerAccessor; - this.logHandler = logHandler; - this.totalConsumerWorkers = totalConsumerWorkers; - this.minInstanceWorkers = minInstanceWorkers; - this.maxInstanceWorkers = maxInstanceWorkers; + _clusterManager = clusterManager; + _consumerAccessor = consumerAccessor; + _logHandler = logHandler; + _totalConsumerWorkers = totalConsumerWorkers; + _minInstanceWorkers = minInstanceWorkers; + _maxInstanceWorkers = maxInstanceWorkers; } public async Task GetWorkersCountAsync(WorkersCountContext context) { var workers = await this.CalculateAsync(context); - this.logHandler.Info( + _logHandler.Info( "New workers count calculated", new { @@ -101,7 +101,7 @@ private async Task CalculateAsync(WorkersCountContext context) var lastOffsets = this.GetPartitionsLastOffset(context.ConsumerName, topicsMetadata); - var partitionsOffset = await this.clusterManager.GetConsumerGroupOffsetsAsync( + var partitionsOffset = await _clusterManager.GetConsumerGroupOffsetsAsync( context.ConsumerGroupId, context.AssignedTopicsPartitions.Select(t => t.Name)); @@ -112,16 +112,16 @@ private async Task CalculateAsync(WorkersCountContext context) var ratio = instanceLag / Math.Max(1, totalConsumerLag); - var workers = (int)Math.Round(this.totalConsumerWorkers * ratio); + var workers = (int)Math.Round(_totalConsumerWorkers * ratio); - workers = Math.Min(workers, this.maxInstanceWorkers); - workers = Math.Max(workers, this.minInstanceWorkers); + workers = Math.Min(workers, _maxInstanceWorkers); + workers = Math.Max(workers, _minInstanceWorkers); return workers; } catch (Exception e) { - this.logHandler.Error( + _logHandler.Error( "Error calculating new workers count, using 1 as fallback", e, new @@ -137,7 +137,7 @@ private async Task CalculateAsync(WorkersCountContext context) string consumerName, IEnumerable<(string Name, TopicMetadata Metadata)> topicsMetadata) { - var consumer = this.consumerAccessor[consumerName]; + var consumer = _consumerAccessor[consumerName]; return topicsMetadata.SelectMany( topic => topic.Metadata.Partitions.Select( @@ -156,7 +156,7 @@ private async Task CalculateAsync(WorkersCountContext context) foreach (var topic in context.AssignedTopicsPartitions) { - topicsMetadata.Add((topic.Name, await this.clusterManager.GetTopicMetadataAsync(topic.Name))); + topicsMetadata.Add((topic.Name, await _clusterManager.GetTopicMetadataAsync(topic.Name))); } return topicsMetadata; diff --git a/src/KafkaFlow/DateTimeProvider.cs b/src/KafkaFlow/DateTimeProvider.cs index a5570242b..6f641fa9e 100644 --- a/src/KafkaFlow/DateTimeProvider.cs +++ b/src/KafkaFlow/DateTimeProvider.cs @@ -1,7 +1,7 @@ +using System; + namespace KafkaFlow { - using System; - internal class DateTimeProvider : IDateTimeProvider { public DateTime UtcNow => DateTime.UtcNow; diff --git a/src/KafkaFlow/Delegates.cs b/src/KafkaFlow/Delegates.cs index d448eb58f..3f2fec26b 100644 --- a/src/KafkaFlow/Delegates.cs +++ b/src/KafkaFlow/Delegates.cs @@ -1,8 +1,8 @@ +using Confluent.Kafka; +using KafkaFlow.Consumers; + namespace KafkaFlow { - using Confluent.Kafka; - using KafkaFlow.Consumers; - /// /// A factory to decorates the consumer created by KafkaFlow /// diff --git a/src/KafkaFlow/Event.cs b/src/KafkaFlow/Event.cs index 39432d58e..ab2a51a07 100644 --- a/src/KafkaFlow/Event.cs +++ b/src/KafkaFlow/Event.cs @@ -1,19 +1,19 @@ -namespace KafkaFlow -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +namespace KafkaFlow +{ internal class Event : IEvent { - private readonly ILogHandler logHandler; + private readonly ILogHandler _logHandler; - private readonly List> handlers = new(); + private readonly List> _handlers = new(); public Event(ILogHandler logHandler) { - this.logHandler = logHandler; + _logHandler = logHandler; } public IEventSubscription Subscribe(Func handler) @@ -23,17 +23,17 @@ public IEventSubscription Subscribe(Func handler) throw new ArgumentNullException("Handler cannot be null"); } - if (!this.handlers.Contains(handler)) + if (!_handlers.Contains(handler)) { - this.handlers.Add(handler); + _handlers.Add(handler); } - return new EventSubscription(() => this.handlers.Remove(handler)); + return new EventSubscription(() => _handlers.Remove(handler)); } internal Task FireAsync(TArg arg) { - var tasks = this.handlers + var tasks = _handlers .Select(handler => this.ProcessHandler(handler, arg)); return Task.WhenAll(tasks); @@ -60,21 +60,21 @@ private Task ProcessHandler(Func handler, TArg arg) private void LogHandlerOnError(Exception ex) { - this.logHandler.Error("Error firing event", ex, new { Event = this.GetType().Name }); + _logHandler.Error("Error firing event", ex, new { Event = this.GetType().Name }); } } internal class Event : IEvent { - private readonly Event evt; + private readonly Event _evt; public Event(ILogHandler logHandler) { - this.evt = new Event(logHandler); + _evt = new Event(logHandler); } - public IEventSubscription Subscribe(Func handler) => this.evt.Subscribe(_ => handler.Invoke()); + public IEventSubscription Subscribe(Func handler) => _evt.Subscribe(_ => handler.Invoke()); - internal Task FireAsync() => this.evt.FireAsync(null); + internal Task FireAsync() => _evt.FireAsync(null); } } \ No newline at end of file diff --git a/src/KafkaFlow/EventSubscription.cs b/src/KafkaFlow/EventSubscription.cs index 36d725083..ff528ef3e 100644 --- a/src/KafkaFlow/EventSubscription.cs +++ b/src/KafkaFlow/EventSubscription.cs @@ -1,19 +1,19 @@ -namespace KafkaFlow -{ - using System; +using System; +namespace KafkaFlow +{ internal class EventSubscription : IEventSubscription { - private readonly Action cancelDelegate; + private readonly Action _cancelDelegate; public EventSubscription(Action cancelDelegate) { - this.cancelDelegate = cancelDelegate; + _cancelDelegate = cancelDelegate; } public void Cancel() { - this.cancelDelegate.Invoke(); + _cancelDelegate.Invoke(); } } } diff --git a/src/KafkaFlow/Extensions/ConfigurationBuilderExtensions.cs b/src/KafkaFlow/Extensions/ConfigurationBuilderExtensions.cs index 8189c22b5..920496454 100644 --- a/src/KafkaFlow/Extensions/ConfigurationBuilderExtensions.cs +++ b/src/KafkaFlow/Extensions/ConfigurationBuilderExtensions.cs @@ -1,15 +1,15 @@ +using System; +using System.Collections.Generic; +using Confluent.Kafka; +using KafkaFlow.Clusters; +using KafkaFlow.Configuration; +using KafkaFlow.Consumers; +using KafkaFlow.Consumers.WorkersBalancers; +using KafkaFlow.Middlewares.Compressor; +using KafkaFlow.Middlewares.TypedHandler; + namespace KafkaFlow { - using System; - using System.Collections.Generic; - using Confluent.Kafka; - using KafkaFlow.Clusters; - using KafkaFlow.Configuration; - using KafkaFlow.Consumers; - using KafkaFlow.Consumers.WorkersBalancers; - using KafkaFlow.Middlewares.Compressor; - using KafkaFlow.Middlewares.TypedHandler; - /// /// Provides extension methods over and /// @@ -206,7 +206,6 @@ public static IConsumerMiddlewareConfigurationBuilder AddTypedHandlers( /// The middleware configuration builder /// The compressor type /// - [Obsolete("Compressors should only be used in backward compatibility scenarios, in the vast majority of cases native compression (producer.WithCompression()) should be used instead")] public static IConsumerMiddlewareConfigurationBuilder AddDecompressor(this IConsumerMiddlewareConfigurationBuilder middlewares) where T : class, IDecompressor { @@ -221,7 +220,6 @@ public static IConsumerMiddlewareConfigurationBuilder AddDecompressor(this IC /// The decompressor type that implements /// A factory to create the instance /// - [Obsolete("Compressors should only be used in backward compatibility scenarios, in the vast majority of cases native compression (producer.WithCompression()) should be used instead")] public static IConsumerMiddlewareConfigurationBuilder AddDecompressor( this IConsumerMiddlewareConfigurationBuilder middlewares, Factory factory) @@ -237,7 +235,6 @@ public static IConsumerMiddlewareConfigurationBuilder AddDecompressor( /// The middleware configuration builder /// The compressor type that implements /// - [Obsolete("Compressors should only be used in backward compatibility scenarios, in the vast majority of cases native compression (producer.WithCompression()) should be used instead")] public static IProducerMiddlewareConfigurationBuilder AddCompressor(this IProducerMiddlewareConfigurationBuilder middlewares) where T : class, ICompressor { @@ -253,7 +250,6 @@ public static IProducerMiddlewareConfigurationBuilder AddCompressor(this IPro /// The compressor type that implements /// A factory to create the instance /// - [Obsolete("Compressors should only be used in backward compatibility scenarios, in the vast majority of cases native compression (producer.WithCompression()) should be used instead")] public static IProducerMiddlewareConfigurationBuilder AddCompressor( this IProducerMiddlewareConfigurationBuilder middlewares, Factory factory) diff --git a/src/KafkaFlow/Extensions/ConfigurationExtensions.cs b/src/KafkaFlow/Extensions/ConfigurationExtensions.cs index eb1741167..6057d30c1 100644 --- a/src/KafkaFlow/Extensions/ConfigurationExtensions.cs +++ b/src/KafkaFlow/Extensions/ConfigurationExtensions.cs @@ -1,12 +1,12 @@ +using System; +using Confluent.Kafka; +using KafkaFlow.Configuration; +using SaslMechanism = KafkaFlow.Configuration.SaslMechanism; +using SecurityProtocol = KafkaFlow.Configuration.SecurityProtocol; +using SslEndpointIdentificationAlgorithm = KafkaFlow.Configuration.SslEndpointIdentificationAlgorithm; + namespace KafkaFlow { - using System; - using Confluent.Kafka; - using KafkaFlow.Configuration; - using SaslMechanism = KafkaFlow.Configuration.SaslMechanism; - using SecurityProtocol = KafkaFlow.Configuration.SecurityProtocol; - using SslEndpointIdentificationAlgorithm = KafkaFlow.Configuration.SslEndpointIdentificationAlgorithm; - internal static class ConfigurationExtensions { public static Confluent.Kafka.SaslMechanism ToConfluent(this SaslMechanism mechanism) => mechanism switch diff --git a/src/KafkaFlow/GlobalEvents.cs b/src/KafkaFlow/GlobalEvents.cs index c4e4212a3..4c012f47b 100644 --- a/src/KafkaFlow/GlobalEvents.cs +++ b/src/KafkaFlow/GlobalEvents.cs @@ -1,56 +1,55 @@ -namespace KafkaFlow -{ - using System.Threading.Tasks; - using KafkaFlow.Configuration; +using System.Threading.Tasks; +using KafkaFlow.Configuration; +namespace KafkaFlow +{ internal class GlobalEvents : IGlobalEvents { - private readonly Event messageConsumeCompleted; - private readonly Event messageConsumeError; - private readonly Event messageConsumeStarted; - private readonly Event messageProduceCompleted; - private readonly Event messageProduceError; - private readonly Event messageProduceStarted; + private readonly Event _messageConsumeCompleted; + private readonly Event _messageConsumeError; + private readonly Event _messageConsumeStarted; + private readonly Event _messageProduceCompleted; + private readonly Event _messageProduceError; + private readonly Event _messageProduceStarted; public GlobalEvents(ILogHandler log) { - this.messageConsumeCompleted = new(log); - this.messageConsumeError = new(log); - this.messageConsumeStarted = new(log); - this.messageProduceCompleted = new(log); - this.messageProduceError = new(log); - this.messageProduceStarted = new(log); + _messageConsumeCompleted = new(log); + _messageConsumeError = new(log); + _messageConsumeStarted = new(log); + _messageProduceCompleted = new(log); + _messageProduceError = new(log); + _messageProduceStarted = new(log); } - public IEvent MessageConsumeCompleted => this.messageConsumeCompleted; + public IEvent MessageConsumeCompleted => _messageConsumeCompleted; - public IEvent MessageConsumeError => this.messageConsumeError; + public IEvent MessageConsumeError => _messageConsumeError; - public IEvent MessageConsumeStarted => this.messageConsumeStarted; + public IEvent MessageConsumeStarted => _messageConsumeStarted; - public IEvent MessageProduceCompleted => this.messageProduceCompleted; + public IEvent MessageProduceCompleted => _messageProduceCompleted; - public IEvent MessageProduceError => this.messageProduceError; + public IEvent MessageProduceError => _messageProduceError; - public IEvent MessageProduceStarted => this.messageProduceStarted; + public IEvent MessageProduceStarted => _messageProduceStarted; public Task FireMessageConsumeStartedAsync(MessageEventContext context) - => this.messageConsumeStarted.FireAsync(context); + => _messageConsumeStarted.FireAsync(context); public Task FireMessageConsumeErrorAsync(MessageErrorEventContext context) - => this.messageConsumeError.FireAsync(context); + => _messageConsumeError.FireAsync(context); public Task FireMessageConsumeCompletedAsync(MessageEventContext context) - => this.messageConsumeCompleted.FireAsync(context); + => _messageConsumeCompleted.FireAsync(context); public Task FireMessageProduceStartedAsync(MessageEventContext context) - => this.messageProduceStarted.FireAsync(context); + => _messageProduceStarted.FireAsync(context); public Task FireMessageProduceErrorAsync(MessageErrorEventContext context) - => this.messageProduceError.FireAsync(context); + => _messageProduceError.FireAsync(context); public Task FireMessageProduceCompletedAsync(MessageEventContext context) - => this.messageProduceCompleted.FireAsync(context); - + => _messageProduceCompleted.FireAsync(context); } } diff --git a/src/KafkaFlow/IConsumerManagerFactory.cs b/src/KafkaFlow/IConsumerManagerFactory.cs index 5e95b3b94..430228060 100644 --- a/src/KafkaFlow/IConsumerManagerFactory.cs +++ b/src/KafkaFlow/IConsumerManagerFactory.cs @@ -1,8 +1,8 @@ +using KafkaFlow.Configuration; +using KafkaFlow.Consumers; + namespace KafkaFlow { - using KafkaFlow.Configuration; - using KafkaFlow.Consumers; - internal interface IConsumerManagerFactory { IConsumerManager Create(IConsumerConfiguration configuration, IDependencyResolver resolver); diff --git a/src/KafkaFlow/IKafkaBus.cs b/src/KafkaFlow/IKafkaBus.cs index 1a1751044..1b5f91b98 100644 --- a/src/KafkaFlow/IKafkaBus.cs +++ b/src/KafkaFlow/IKafkaBus.cs @@ -1,10 +1,10 @@ +using System.Threading; +using System.Threading.Tasks; +using KafkaFlow.Consumers; +using KafkaFlow.Producers; + namespace KafkaFlow { - using System.Threading; - using System.Threading.Tasks; - using KafkaFlow.Consumers; - using KafkaFlow.Producers; - /// /// Provides access to the kafka bus operations /// diff --git a/src/KafkaFlow/IMiddlewareExecutor.cs b/src/KafkaFlow/IMiddlewareExecutor.cs index 7f7580c04..6ff6f309f 100644 --- a/src/KafkaFlow/IMiddlewareExecutor.cs +++ b/src/KafkaFlow/IMiddlewareExecutor.cs @@ -1,8 +1,8 @@ +using System; +using System.Threading.Tasks; + namespace KafkaFlow { - using System; - using System.Threading.Tasks; - internal interface IMiddlewareExecutor { Task Execute(IMessageContext context, Func nextOperation); diff --git a/src/KafkaFlow/KafkaBus.cs b/src/KafkaFlow/KafkaBus.cs index 8ac7a699c..c6ce0e7d7 100644 --- a/src/KafkaFlow/KafkaBus.cs +++ b/src/KafkaFlow/KafkaBus.cs @@ -1,22 +1,22 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using KafkaFlow.Clusters; +using KafkaFlow.Configuration; +using KafkaFlow.Consumers; +using KafkaFlow.Producers; + namespace KafkaFlow { - using System.Collections.Generic; - using System.Linq; - using System.Threading; - using System.Threading.Tasks; - using KafkaFlow.Clusters; - using KafkaFlow.Configuration; - using KafkaFlow.Consumers; - using KafkaFlow.Producers; - internal class KafkaBus : IKafkaBus { - private readonly IDependencyResolver dependencyResolver; - private readonly KafkaConfiguration configuration; - private readonly IConsumerManagerFactory consumerManagerFactory; - private readonly IClusterManagerAccessor clusterManagerAccessor; + private readonly IDependencyResolver _dependencyResolver; + private readonly KafkaConfiguration _configuration; + private readonly IConsumerManagerFactory _consumerManagerFactory; + private readonly IClusterManagerAccessor _clusterManagerAccessor; - private readonly List consumerManagers = new(); + private readonly List _consumerManagers = new(); public KafkaBus( IDependencyResolver dependencyResolver, @@ -26,10 +26,10 @@ public KafkaBus( IProducerAccessor producers, IClusterManagerAccessor clusterManagerAccessor) { - this.dependencyResolver = dependencyResolver; - this.configuration = configuration; - this.consumerManagerFactory = consumerManagerFactory; - this.clusterManagerAccessor = clusterManagerAccessor; + _dependencyResolver = dependencyResolver; + _configuration = configuration; + _consumerManagerFactory = consumerManagerFactory; + _clusterManagerAccessor = clusterManagerAccessor; this.Consumers = consumers; this.Producers = producers; } @@ -44,18 +44,18 @@ public async Task StartAsync(CancellationToken stopCancellationToken = default) stopTokenSource.Token.Register(() => this.StopAsync().GetAwaiter().GetResult()); - foreach (var cluster in this.configuration.Clusters) + foreach (var cluster in _configuration.Clusters) { await this.CreateMissingClusterTopics(cluster); foreach (var consumerConfiguration in cluster.Consumers) { - var consumerDependencyScope = this.dependencyResolver.CreateScope(); + var consumerDependencyScope = _dependencyResolver.CreateScope(); var consumerManager = - this.consumerManagerFactory.Create(consumerConfiguration, consumerDependencyScope.Resolver); + _consumerManagerFactory.Create(consumerConfiguration, consumerDependencyScope.Resolver); - this.consumerManagers.Add(consumerManager); + _consumerManagers.Add(consumerManager); this.Consumers.Add( new MessageConsumer( consumerManager, @@ -67,18 +67,18 @@ public async Task StartAsync(CancellationToken stopCancellationToken = default) } } - cluster.OnStartedHandler(this.dependencyResolver); + cluster.OnStartedHandler(_dependencyResolver); } } public Task StopAsync() { - foreach (var cluster in this.configuration.Clusters) + foreach (var cluster in _configuration.Clusters) { - cluster.OnStoppingHandler(this.dependencyResolver); + cluster.OnStoppingHandler(_dependencyResolver); } - return Task.WhenAll(this.consumerManagers.Select(x => x.StopAsync())); + return Task.WhenAll(_consumerManagers.Select(x => x.StopAsync())); } private async Task CreateMissingClusterTopics(ClusterConfiguration cluster) @@ -88,7 +88,7 @@ private async Task CreateMissingClusterTopics(ClusterConfiguration cluster) return; } - await this.clusterManagerAccessor[cluster.Name].CreateIfNotExistsAsync( + await _clusterManagerAccessor[cluster.Name].CreateIfNotExistsAsync( cluster.TopicsToCreateIfNotExist); } } diff --git a/src/KafkaFlow/MessageContext.cs b/src/KafkaFlow/MessageContext.cs index e59f50bb4..cbbf708cc 100644 --- a/src/KafkaFlow/MessageContext.cs +++ b/src/KafkaFlow/MessageContext.cs @@ -1,7 +1,7 @@ +using System.Collections.Generic; + namespace KafkaFlow { - using System.Collections.Generic; - internal class MessageContext : IMessageContext { public MessageContext( diff --git a/src/KafkaFlow/MessageHeaders.cs b/src/KafkaFlow/MessageHeaders.cs index 54287586b..5d7cde588 100644 --- a/src/KafkaFlow/MessageHeaders.cs +++ b/src/KafkaFlow/MessageHeaders.cs @@ -1,15 +1,15 @@ +using System.Collections; +using System.Collections.Generic; +using Confluent.Kafka; + namespace KafkaFlow { - using System.Collections; - using System.Collections.Generic; - using Confluent.Kafka; - /// /// Collection of message headers /// public class MessageHeaders : IMessageHeaders { - private readonly Headers headers; + private readonly Headers _headers; /// /// Initializes a new instance of the class. @@ -17,7 +17,7 @@ public class MessageHeaders : IMessageHeaders /// The Confluent headers public MessageHeaders(Headers headers) { - this.headers = headers; + _headers = headers; } /// @@ -34,11 +34,11 @@ public MessageHeaders() /// The zero-based index of the element to get public byte[] this[string key] { - get => this.headers.TryGetLastBytes(key, out var value) ? value : null; + get => _headers.TryGetLastBytes(key, out var value) ? value : null; set { - this.headers.Remove(key); - this.headers.Add(key, value); + _headers.Remove(key); + _headers.Add(key, value); } } @@ -49,14 +49,14 @@ public byte[] this[string key] /// The header value (possibly null) public void Add(string key, byte[] value) { - this.headers.Add(key, value); + _headers.Add(key, value); } /// /// Gets all the kafka headers /// /// - public Headers GetKafkaHeaders() => this.headers; + public Headers GetKafkaHeaders() => _headers; /// /// Gets an enumerator that iterates through @@ -64,7 +64,7 @@ public void Add(string key, byte[] value) /// public IEnumerator> GetEnumerator() { - foreach (var header in this.headers) + foreach (var header in _headers) { yield return new KeyValuePair(header.Key, header.GetValueBytes()); } diff --git a/src/KafkaFlow/MiddlewareExecutor.cs b/src/KafkaFlow/MiddlewareExecutor.cs index b2710ff9d..6513b1bb5 100644 --- a/src/KafkaFlow/MiddlewareExecutor.cs +++ b/src/KafkaFlow/MiddlewareExecutor.cs @@ -1,21 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using KafkaFlow.Configuration; + namespace KafkaFlow { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - using KafkaFlow.Configuration; - internal class MiddlewareExecutor : IMiddlewareExecutor { - private readonly IReadOnlyList configurations; + private readonly IReadOnlyList _configurations; - private readonly Dictionary consumerOrProducerMiddlewares = new(); - private readonly Dictionary<(int, int), IMessageMiddleware> workersMiddlewares = new(); + private readonly Dictionary _consumerOrProducerMiddlewares = new(); + private readonly Dictionary<(int, int), IMessageMiddleware> _workersMiddlewares = new(); public MiddlewareExecutor(IReadOnlyList configurations) { - this.configurations = configurations; + _configurations = configurations; } public Task Execute(IMessageContext context, Func nextOperation) @@ -25,7 +25,7 @@ public Task Execute(IMessageContext context, Func nextOpe internal Task OnWorkerPoolStopped() { - this.workersMiddlewares.Clear(); + _workersMiddlewares.Clear(); return Task.CompletedTask; } @@ -56,12 +56,12 @@ private static IMessageMiddleware CreateInstance( private Task ExecuteDefinition(int index, IMessageContext context, Func nextOperation) { - if (this.configurations.Count == index) + if (_configurations.Count == index) { return nextOperation(context); } - var configuration = this.configurations[index]; + var configuration = _configurations[index]; return this .ResolveInstance(index, context, configuration) @@ -91,7 +91,7 @@ private IMessageMiddleware GetConsumerOrProducerInstance( int index, MiddlewareConfiguration configuration) { - return this.consumerOrProducerMiddlewares.SafeGetOrAdd( + return _consumerOrProducerMiddlewares.SafeGetOrAdd( index, _ => CreateInstance(dependencyResolver, configuration)); } @@ -101,7 +101,7 @@ private IMessageMiddleware GetWorkerInstance( IMessageContext context, MiddlewareConfiguration configuration) { - return this.workersMiddlewares.SafeGetOrAdd( + return _workersMiddlewares.SafeGetOrAdd( (index, context.ConsumerContext?.WorkerId ?? 0), _ => CreateInstance(context.ConsumerContext.WorkerDependencyResolver, configuration)); } diff --git a/src/KafkaFlow/Middlewares/Compressor/CompressorProducerMiddleware.cs b/src/KafkaFlow/Middlewares/Compressor/CompressorProducerMiddleware.cs index ed3ca3d42..3373ed1af 100644 --- a/src/KafkaFlow/Middlewares/Compressor/CompressorProducerMiddleware.cs +++ b/src/KafkaFlow/Middlewares/Compressor/CompressorProducerMiddleware.cs @@ -1,14 +1,14 @@ -namespace KafkaFlow.Middlewares.Compressor -{ - using System; - using System.Threading.Tasks; +using System; +using System.Threading.Tasks; +namespace KafkaFlow.Middlewares.Compressor +{ /// /// Middleware to compress the messages when producing /// public class CompressorProducerMiddleware : IMessageMiddleware { - private readonly ICompressor compressor; + private readonly ICompressor _compressor; /// /// Initializes a new instance of the class. @@ -16,7 +16,7 @@ public class CompressorProducerMiddleware : IMessageMiddleware /// Instance of public CompressorProducerMiddleware(ICompressor compressor) { - this.compressor = compressor; + _compressor = compressor; } /// @@ -28,7 +28,7 @@ public Task Invoke(IMessageContext context, MiddlewareDelegate next) $"{nameof(context.Message.Value)} must be a byte array to be compressed and it is '{context.Message.Value.GetType().FullName}'"); } - var data = this.compressor.Compress(rawData); + var data = _compressor.Compress(rawData); return next(context.SetMessage(context.Message.Key, data)); } diff --git a/src/KafkaFlow/Middlewares/Compressor/DecompressorConsumerMiddleware.cs b/src/KafkaFlow/Middlewares/Compressor/DecompressorConsumerMiddleware.cs index d52ae8360..ba4f218f2 100644 --- a/src/KafkaFlow/Middlewares/Compressor/DecompressorConsumerMiddleware.cs +++ b/src/KafkaFlow/Middlewares/Compressor/DecompressorConsumerMiddleware.cs @@ -1,14 +1,14 @@ -namespace KafkaFlow.Middlewares.Compressor -{ - using System; - using System.Threading.Tasks; +using System; +using System.Threading.Tasks; +namespace KafkaFlow.Middlewares.Compressor +{ /// /// Middleware to decompress the messages when consuming /// public class DecompressorConsumerMiddleware : IMessageMiddleware { - private readonly IDecompressor decompressor; + private readonly IDecompressor _decompressor; /// /// Initializes a new instance of the class. @@ -16,7 +16,7 @@ public class DecompressorConsumerMiddleware : IMessageMiddleware /// Instance of public DecompressorConsumerMiddleware(IDecompressor decompressor) { - this.decompressor = decompressor; + _decompressor = decompressor; } /// @@ -28,7 +28,7 @@ public Task Invoke(IMessageContext context, MiddlewareDelegate next) $"{nameof(context.Message.Value)} must be a byte array to be decompressed and it is '{context.Message.Value.GetType().FullName}'"); } - var data = this.decompressor.Decompress(rawData); + var data = _decompressor.Decompress(rawData); return next(context.SetMessage(context.Message.Key, data)); } diff --git a/src/KafkaFlow/Middlewares/ConsumerThrottling/Configuration/ConsumerThrottlingActionConfigurationBuilder.cs b/src/KafkaFlow/Middlewares/ConsumerThrottling/Configuration/ConsumerThrottlingActionConfigurationBuilder.cs index e0c02903f..9794cfca2 100644 --- a/src/KafkaFlow/Middlewares/ConsumerThrottling/Configuration/ConsumerThrottlingActionConfigurationBuilder.cs +++ b/src/KafkaFlow/Middlewares/ConsumerThrottling/Configuration/ConsumerThrottlingActionConfigurationBuilder.cs @@ -1,7 +1,7 @@ +using System; + namespace KafkaFlow.Middlewares.ConsumerThrottling.Configuration { - using System; - internal class ConsumerThrottlingActionConfigurationBuilder : IConsumerThrottlingActionConfigurationBuilder, IConsumerThrottlingThresholdActionConfigurationBuilder diff --git a/src/KafkaFlow/Middlewares/ConsumerThrottling/Configuration/ConsumerThrottlingConfiguration.cs b/src/KafkaFlow/Middlewares/ConsumerThrottling/Configuration/ConsumerThrottlingConfiguration.cs index def130389..6185d4b37 100644 --- a/src/KafkaFlow/Middlewares/ConsumerThrottling/Configuration/ConsumerThrottlingConfiguration.cs +++ b/src/KafkaFlow/Middlewares/ConsumerThrottling/Configuration/ConsumerThrottlingConfiguration.cs @@ -1,8 +1,8 @@ +using System; +using System.Collections.Generic; + namespace KafkaFlow.Middlewares.ConsumerThrottling.Configuration { - using System; - using System.Collections.Generic; - internal class ConsumerThrottlingConfiguration { public ConsumerThrottlingConfiguration( diff --git a/src/KafkaFlow/Middlewares/ConsumerThrottling/Configuration/ConsumerThrottlingConfigurationBuilder.cs b/src/KafkaFlow/Middlewares/ConsumerThrottling/Configuration/ConsumerThrottlingConfigurationBuilder.cs index f1792b344..bacb06222 100644 --- a/src/KafkaFlow/Middlewares/ConsumerThrottling/Configuration/ConsumerThrottlingConfigurationBuilder.cs +++ b/src/KafkaFlow/Middlewares/ConsumerThrottling/Configuration/ConsumerThrottlingConfigurationBuilder.cs @@ -1,26 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; + namespace KafkaFlow.Middlewares.ConsumerThrottling.Configuration { - using System; - using System.Collections.Generic; - using System.Linq; - internal class ConsumerThrottlingConfigurationBuilder : IConsumerThrottlingMetricConfigurationBuilder, IConsumerThrottlingActionsConfigurationBuilder { - private readonly List> metrics = new(); - private readonly List actions = new(); - private TimeSpan interval = TimeSpan.FromSeconds(5); + private readonly List> _metrics = new(); + private readonly List _actions = new(); + private TimeSpan _interval = TimeSpan.FromSeconds(5); public IConsumerThrottlingActionsConfigurationBuilder WithInterval(TimeSpan interval) { - this.interval = interval; + _interval = interval; return this; } public IConsumerThrottlingMetricConfigurationBuilder AddMetric(Func factory) { - this.metrics.Add(factory); + _metrics.Add(factory); return this; } @@ -30,18 +30,18 @@ public IConsumerThrottlingActionsConfigurationBuilder AddAction(Action x(resolver)) .ToList(), - this.actions + _actions .Select(x => new ConsumerThrottlingThreshold(x.Threshold, x.Factory(resolver))) .ToList()); } diff --git a/src/KafkaFlow/Middlewares/ConsumerThrottling/Configuration/ConsumerThrottlingConfigurationBuilderExtensions.cs b/src/KafkaFlow/Middlewares/ConsumerThrottling/Configuration/ConsumerThrottlingConfigurationBuilderExtensions.cs index c9eefdd80..9621a0d1d 100644 --- a/src/KafkaFlow/Middlewares/ConsumerThrottling/Configuration/ConsumerThrottlingConfigurationBuilderExtensions.cs +++ b/src/KafkaFlow/Middlewares/ConsumerThrottling/Configuration/ConsumerThrottlingConfigurationBuilderExtensions.cs @@ -1,12 +1,12 @@ +using System; +using System.Collections.Generic; +using KafkaFlow.Configuration; +using KafkaFlow.Consumers; +using KafkaFlow.Middlewares.ConsumerThrottling; +using KafkaFlow.Middlewares.ConsumerThrottling.Configuration; + namespace KafkaFlow { - using System; - using System.Collections.Generic; - using KafkaFlow.Configuration; - using KafkaFlow.Consumers; - using KafkaFlow.Middlewares.ConsumerThrottling; - using KafkaFlow.Middlewares.ConsumerThrottling.Configuration; - /// /// Provides extension methods for configuring consumer throttling in KafkaFlow. /// diff --git a/src/KafkaFlow/Middlewares/ConsumerThrottling/Configuration/IConsumerThrottlingActionsConfigurationBuilder.cs b/src/KafkaFlow/Middlewares/ConsumerThrottling/Configuration/IConsumerThrottlingActionsConfigurationBuilder.cs index 0c44bd3d4..c5b1e7e49 100644 --- a/src/KafkaFlow/Middlewares/ConsumerThrottling/Configuration/IConsumerThrottlingActionsConfigurationBuilder.cs +++ b/src/KafkaFlow/Middlewares/ConsumerThrottling/Configuration/IConsumerThrottlingActionsConfigurationBuilder.cs @@ -1,7 +1,7 @@ +using System; + namespace KafkaFlow.Middlewares.ConsumerThrottling.Configuration { - using System; - /// /// Provides methods to configure throttling actions for KafkaFlow consumers. /// diff --git a/src/KafkaFlow/Middlewares/ConsumerThrottling/Configuration/IConsumerThrottlingMetricConfigurationBuilder.cs b/src/KafkaFlow/Middlewares/ConsumerThrottling/Configuration/IConsumerThrottlingMetricConfigurationBuilder.cs index ecf613255..f926107fb 100644 --- a/src/KafkaFlow/Middlewares/ConsumerThrottling/Configuration/IConsumerThrottlingMetricConfigurationBuilder.cs +++ b/src/KafkaFlow/Middlewares/ConsumerThrottling/Configuration/IConsumerThrottlingMetricConfigurationBuilder.cs @@ -1,7 +1,7 @@ +using System; + namespace KafkaFlow.Middlewares.ConsumerThrottling.Configuration { - using System; - /// /// An interface to configure the throttling metrics for KafkaFlow consumers. /// diff --git a/src/KafkaFlow/Middlewares/ConsumerThrottling/Configuration/IConsumerThrottlingThresholdActionConfigurationBuilder.cs b/src/KafkaFlow/Middlewares/ConsumerThrottling/Configuration/IConsumerThrottlingThresholdActionConfigurationBuilder.cs index 1a1f4b58e..91c5dc8ae 100644 --- a/src/KafkaFlow/Middlewares/ConsumerThrottling/Configuration/IConsumerThrottlingThresholdActionConfigurationBuilder.cs +++ b/src/KafkaFlow/Middlewares/ConsumerThrottling/Configuration/IConsumerThrottlingThresholdActionConfigurationBuilder.cs @@ -1,7 +1,7 @@ +using System; + namespace KafkaFlow.Middlewares.ConsumerThrottling.Configuration { - using System; - /// /// An interface to configure the actions applied when a throttling threshold is met. /// diff --git a/src/KafkaFlow/Middlewares/ConsumerThrottling/ConsumerThrottlingDelayAction.cs b/src/KafkaFlow/Middlewares/ConsumerThrottling/ConsumerThrottlingDelayAction.cs index d0116d422..2c410bef7 100644 --- a/src/KafkaFlow/Middlewares/ConsumerThrottling/ConsumerThrottlingDelayAction.cs +++ b/src/KafkaFlow/Middlewares/ConsumerThrottling/ConsumerThrottlingDelayAction.cs @@ -1,20 +1,20 @@ +using System; +using System.Threading.Tasks; + namespace KafkaFlow.Middlewares.ConsumerThrottling { - using System; - using System.Threading.Tasks; - internal class ConsumerThrottlingDelayAction : IConsumerThrottlingAction { - private readonly TimeSpan delay; + private readonly TimeSpan _delay; public ConsumerThrottlingDelayAction(TimeSpan delay) { - this.delay = delay; + _delay = delay; } public Task ExecuteAsync() { - return Task.Delay(this.delay); + return Task.Delay(_delay); } } } diff --git a/src/KafkaFlow/Middlewares/ConsumerThrottling/ConsumerThrottlingKafkaLagMetric.cs b/src/KafkaFlow/Middlewares/ConsumerThrottling/ConsumerThrottlingKafkaLagMetric.cs index 8611084ef..578ad16c4 100644 --- a/src/KafkaFlow/Middlewares/ConsumerThrottling/ConsumerThrottlingKafkaLagMetric.cs +++ b/src/KafkaFlow/Middlewares/ConsumerThrottling/ConsumerThrottlingKafkaLagMetric.cs @@ -1,17 +1,17 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using KafkaFlow.Consumers; + namespace KafkaFlow.Middlewares.ConsumerThrottling { - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - using KafkaFlow.Consumers; - internal class ConsumerThrottlingKafkaLagMetric : IConsumerThrottlingMetric { - private readonly IReadOnlyList consumers; + private readonly IReadOnlyList _consumers; public ConsumerThrottlingKafkaLagMetric(IConsumerAccessor consumerAccessor, IEnumerable consumersNames) { - this.consumers = consumerAccessor.All + _consumers = consumerAccessor.All .Where(consumer => consumersNames.Contains(consumer.ConsumerName)) .ToList() .AsReadOnly(); @@ -19,7 +19,7 @@ public ConsumerThrottlingKafkaLagMetric(IConsumerAccessor consumerAccessor, IEnu public Task GetValueAsync() { - var lag = this.consumers + var lag = _consumers .SelectMany(x => x.GetTopicPartitionsLag()) .Select(x => x.Lag) .Sum(); diff --git a/src/KafkaFlow/Middlewares/ConsumerThrottling/ConsumerThrottlingMiddleware.cs b/src/KafkaFlow/Middlewares/ConsumerThrottling/ConsumerThrottlingMiddleware.cs index 91019140d..1add86f0b 100644 --- a/src/KafkaFlow/Middlewares/ConsumerThrottling/ConsumerThrottlingMiddleware.cs +++ b/src/KafkaFlow/Middlewares/ConsumerThrottling/ConsumerThrottlingMiddleware.cs @@ -1,29 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using KafkaFlow.Middlewares.ConsumerThrottling.Configuration; + namespace KafkaFlow.Middlewares.ConsumerThrottling { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Threading; - using System.Threading.Tasks; - using KafkaFlow.Middlewares.ConsumerThrottling.Configuration; - internal class ConsumerThrottlingMiddleware : IMessageMiddleware, IDisposable { - private readonly ConsumerThrottlingConfiguration configuration; - private readonly IReadOnlyList thresholds; + private readonly ConsumerThrottlingConfiguration _configuration; + private readonly IReadOnlyList _thresholds; - private readonly Timer timer; + private readonly Timer _timer; - private long metricValue; + private long _metricValue; public ConsumerThrottlingMiddleware(ConsumerThrottlingConfiguration configuration) { - this.configuration = configuration; - this.thresholds = configuration.Thresholds + _configuration = configuration; + _thresholds = configuration.Thresholds .OrderByDescending(x => x.ThresholdValue) .ToList(); - this.timer = new Timer( + _timer = new Timer( state => _ = this.UpdateMetricValueAsync(), null, configuration.EvaluationInterval, @@ -32,9 +32,9 @@ public ConsumerThrottlingMiddleware(ConsumerThrottlingConfiguration configuratio public async Task Invoke(IMessageContext context, MiddlewareDelegate next) { - foreach (var threshold in this.thresholds) + foreach (var threshold in _thresholds) { - if (await threshold.TryExecuteActionAsync(this.metricValue).ConfigureAwait(false)) + if (await threshold.TryExecuteActionAsync(_metricValue).ConfigureAwait(false)) { break; } @@ -45,19 +45,19 @@ public async Task Invoke(IMessageContext context, MiddlewareDelegate next) public void Dispose() { - this.timer?.Dispose(); + _timer?.Dispose(); } private async Task UpdateMetricValueAsync() { long total = 0; - foreach (var metric in this.configuration.Metrics) + foreach (var metric in _configuration.Metrics) { total += await metric.GetValueAsync().ConfigureAwait(false); } - this.metricValue = total; + _metricValue = total; } } } diff --git a/src/KafkaFlow/Middlewares/ConsumerThrottling/ConsumerThrottlingThreshold.cs b/src/KafkaFlow/Middlewares/ConsumerThrottling/ConsumerThrottlingThreshold.cs index 89ef0ede9..b2a281d73 100644 --- a/src/KafkaFlow/Middlewares/ConsumerThrottling/ConsumerThrottlingThreshold.cs +++ b/src/KafkaFlow/Middlewares/ConsumerThrottling/ConsumerThrottlingThreshold.cs @@ -1,14 +1,14 @@ +using System.Threading.Tasks; + namespace KafkaFlow.Middlewares.ConsumerThrottling { - using System.Threading.Tasks; - internal class ConsumerThrottlingThreshold : IConsumerThrottlingThreshold { - private readonly IConsumerThrottlingAction action; + private readonly IConsumerThrottlingAction _action; public ConsumerThrottlingThreshold(long thresholdValue, IConsumerThrottlingAction action) { - this.action = action; + _action = action; this.ThresholdValue = thresholdValue; } @@ -21,7 +21,7 @@ public async Task TryExecuteActionAsync(long metricValue) return false; } - await this.action.ExecuteAsync(); + await _action.ExecuteAsync(); return true; } diff --git a/src/KafkaFlow/Middlewares/ConsumerThrottling/IConsumerThrottlingAction.cs b/src/KafkaFlow/Middlewares/ConsumerThrottling/IConsumerThrottlingAction.cs index a7f0c8f56..07cab0b53 100644 --- a/src/KafkaFlow/Middlewares/ConsumerThrottling/IConsumerThrottlingAction.cs +++ b/src/KafkaFlow/Middlewares/ConsumerThrottling/IConsumerThrottlingAction.cs @@ -1,7 +1,7 @@ +using System.Threading.Tasks; + namespace KafkaFlow.Middlewares.ConsumerThrottling { - using System.Threading.Tasks; - /// /// Defines a throttling action that can be executed by a KafkaFlow consumer. /// diff --git a/src/KafkaFlow/Middlewares/ConsumerThrottling/IConsumerThrottlingMetric.cs b/src/KafkaFlow/Middlewares/ConsumerThrottling/IConsumerThrottlingMetric.cs index 3fd4ce475..bf34851d6 100644 --- a/src/KafkaFlow/Middlewares/ConsumerThrottling/IConsumerThrottlingMetric.cs +++ b/src/KafkaFlow/Middlewares/ConsumerThrottling/IConsumerThrottlingMetric.cs @@ -1,7 +1,7 @@ +using System.Threading.Tasks; + namespace KafkaFlow.Middlewares.ConsumerThrottling { - using System.Threading.Tasks; - /// /// Defines a metric that is used by the KafkaFlow consumer throttling feature. /// diff --git a/src/KafkaFlow/Middlewares/ConsumerThrottling/IConsumerThrottlingThreshold.cs b/src/KafkaFlow/Middlewares/ConsumerThrottling/IConsumerThrottlingThreshold.cs index b13e8f312..d0780c4ce 100644 --- a/src/KafkaFlow/Middlewares/ConsumerThrottling/IConsumerThrottlingThreshold.cs +++ b/src/KafkaFlow/Middlewares/ConsumerThrottling/IConsumerThrottlingThreshold.cs @@ -1,7 +1,7 @@ +using System.Threading.Tasks; + namespace KafkaFlow.Middlewares.ConsumerThrottling { - using System.Threading.Tasks; - internal interface IConsumerThrottlingThreshold { long ThresholdValue { get; } diff --git a/src/KafkaFlow/Middlewares/Serializer/Configuration/ConsumerMiddlewareConfigurationBuilder.cs b/src/KafkaFlow/Middlewares/Serializer/Configuration/ConsumerMiddlewareConfigurationBuilder.cs index bae8b29c6..58105ca3b 100644 --- a/src/KafkaFlow/Middlewares/Serializer/Configuration/ConsumerMiddlewareConfigurationBuilder.cs +++ b/src/KafkaFlow/Middlewares/Serializer/Configuration/ConsumerMiddlewareConfigurationBuilder.cs @@ -1,10 +1,10 @@ -namespace KafkaFlow -{ - using System; - using KafkaFlow.Configuration; - using KafkaFlow.Middlewares.Serializer; - using KafkaFlow.Middlewares.Serializer.Resolvers; +using System; +using KafkaFlow.Configuration; +using KafkaFlow.Middlewares.Serializer; +using KafkaFlow.Middlewares.Serializer.Resolvers; +namespace KafkaFlow +{ /// /// No needed /// diff --git a/src/KafkaFlow/Middlewares/Serializer/Configuration/ProducerMiddlewareConfigurationBuilder.cs b/src/KafkaFlow/Middlewares/Serializer/Configuration/ProducerMiddlewareConfigurationBuilder.cs index 83b667532..43327258f 100644 --- a/src/KafkaFlow/Middlewares/Serializer/Configuration/ProducerMiddlewareConfigurationBuilder.cs +++ b/src/KafkaFlow/Middlewares/Serializer/Configuration/ProducerMiddlewareConfigurationBuilder.cs @@ -1,10 +1,10 @@ -namespace KafkaFlow -{ - using System; - using KafkaFlow.Configuration; - using KafkaFlow.Middlewares.Serializer; - using KafkaFlow.Middlewares.Serializer.Resolvers; +using System; +using KafkaFlow.Configuration; +using KafkaFlow.Middlewares.Serializer; +using KafkaFlow.Middlewares.Serializer.Resolvers; +namespace KafkaFlow +{ /// /// No needed /// diff --git a/src/KafkaFlow/Middlewares/Serializer/DeserializerConsumerMiddleware.cs b/src/KafkaFlow/Middlewares/Serializer/DeserializerConsumerMiddleware.cs index 191ae420a..fe929b05f 100644 --- a/src/KafkaFlow/Middlewares/Serializer/DeserializerConsumerMiddleware.cs +++ b/src/KafkaFlow/Middlewares/Serializer/DeserializerConsumerMiddleware.cs @@ -1,17 +1,17 @@ -namespace KafkaFlow.Middlewares.Serializer -{ - using System; - using System.IO; - using System.Threading.Tasks; - using KafkaFlow.Middlewares.Serializer.Resolvers; +using System; +using System.IO; +using System.Threading.Tasks; +using KafkaFlow.Middlewares.Serializer.Resolvers; +namespace KafkaFlow.Middlewares.Serializer +{ /// /// Middleware to deserialize messages when consuming /// public class DeserializerConsumerMiddleware : IMessageMiddleware { - private readonly IDeserializer deserializer; - private readonly IMessageTypeResolver typeResolver; + private readonly IDeserializer _deserializer; + private readonly IMessageTypeResolver _typeResolver; /// /// Initializes a new instance of the class. @@ -22,8 +22,8 @@ public DeserializerConsumerMiddleware( IDeserializer deserializer, IMessageTypeResolver typeResolver) { - this.deserializer = deserializer; - this.typeResolver = typeResolver; + _deserializer = deserializer; + _typeResolver = typeResolver; } /// @@ -53,7 +53,7 @@ public async Task Invoke(IMessageContext context, MiddlewareDelegate next) return; } - var messageType = await this.typeResolver.OnConsumeAsync(context); + var messageType = await _typeResolver.OnConsumeAsync(context); if (messageType is null) { @@ -62,7 +62,7 @@ public async Task Invoke(IMessageContext context, MiddlewareDelegate next) using var stream = new MemoryStream(rawData); - var data = await this.deserializer + var data = await _deserializer .DeserializeAsync( stream, messageType, diff --git a/src/KafkaFlow/Middlewares/Serializer/Resolvers/DefaultTypeResolver.cs b/src/KafkaFlow/Middlewares/Serializer/Resolvers/DefaultTypeResolver.cs index b1bf40385..368b6a80c 100644 --- a/src/KafkaFlow/Middlewares/Serializer/Resolvers/DefaultTypeResolver.cs +++ b/src/KafkaFlow/Middlewares/Serializer/Resolvers/DefaultTypeResolver.cs @@ -1,8 +1,8 @@ +using System; +using System.Threading.Tasks; + namespace KafkaFlow.Middlewares.Serializer.Resolvers { - using System; - using System.Threading.Tasks; - internal class DefaultTypeResolver : IMessageTypeResolver { private const string MessageType = "Message-Type"; @@ -12,7 +12,7 @@ public ValueTask OnConsumeAsync(IMessageContext context) var typeName = context.Headers.GetString(MessageType); return typeName is null ? - new ValueTask((Type) null) : + new ValueTask((Type)null) : new ValueTask(Type.GetType(typeName)); } diff --git a/src/KafkaFlow/Middlewares/Serializer/Resolvers/IMessageTypeResolver.cs b/src/KafkaFlow/Middlewares/Serializer/Resolvers/IMessageTypeResolver.cs index 44aba2ebf..23b9d2748 100644 --- a/src/KafkaFlow/Middlewares/Serializer/Resolvers/IMessageTypeResolver.cs +++ b/src/KafkaFlow/Middlewares/Serializer/Resolvers/IMessageTypeResolver.cs @@ -1,8 +1,8 @@ -namespace KafkaFlow.Middlewares.Serializer.Resolvers -{ - using System; - using System.Threading.Tasks; +using System; +using System.Threading.Tasks; +namespace KafkaFlow.Middlewares.Serializer.Resolvers +{ /// /// Used by the serializer middleware to resolve the type when consuming and store it when producing /// diff --git a/src/KafkaFlow/Middlewares/Serializer/Resolvers/SingleMessageTypeResolver.cs b/src/KafkaFlow/Middlewares/Serializer/Resolvers/SingleMessageTypeResolver.cs index bc75f6144..e19ae5bad 100644 --- a/src/KafkaFlow/Middlewares/Serializer/Resolvers/SingleMessageTypeResolver.cs +++ b/src/KafkaFlow/Middlewares/Serializer/Resolvers/SingleMessageTypeResolver.cs @@ -1,14 +1,14 @@ +using System; +using System.Threading.Tasks; + namespace KafkaFlow.Middlewares.Serializer.Resolvers { - using System; - using System.Threading.Tasks; - /// /// The message type resolver to be used when all messages are the same type /// public class SingleMessageTypeResolver : IMessageTypeResolver { - private readonly Type messageType; + private readonly Type _messageType; /// /// Initializes a new instance of the class. @@ -16,11 +16,11 @@ public class SingleMessageTypeResolver : IMessageTypeResolver /// The message type to be returned when consuming public SingleMessageTypeResolver(Type messageType) { - this.messageType = messageType; + _messageType = messageType; } /// - public ValueTask OnConsumeAsync(IMessageContext context) => new ValueTask(this.messageType); + public ValueTask OnConsumeAsync(IMessageContext context) => new ValueTask(_messageType); /// public ValueTask OnProduceAsync(IMessageContext context) diff --git a/src/KafkaFlow/Middlewares/Serializer/SerializerProducerMiddleware.cs b/src/KafkaFlow/Middlewares/Serializer/SerializerProducerMiddleware.cs index b91f6fcb3..cc544cc8d 100644 --- a/src/KafkaFlow/Middlewares/Serializer/SerializerProducerMiddleware.cs +++ b/src/KafkaFlow/Middlewares/Serializer/SerializerProducerMiddleware.cs @@ -1,19 +1,19 @@ -namespace KafkaFlow.Middlewares.Serializer -{ - using System.Threading.Tasks; - using KafkaFlow.Middlewares.Serializer.Resolvers; - using Microsoft.IO; +using System.Threading.Tasks; +using KafkaFlow.Middlewares.Serializer.Resolvers; +using Microsoft.IO; +namespace KafkaFlow.Middlewares.Serializer +{ /// /// Middleware to serialize messages when producing /// public class SerializerProducerMiddleware : IMessageMiddleware { - private static readonly RecyclableMemoryStreamManager MemoryStreamManager = new(); + private static readonly RecyclableMemoryStreamManager s_memoryStreamManager = new(); - private readonly ISerializer serializer; + private readonly ISerializer _serializer; - private readonly IMessageTypeResolver typeResolver; + private readonly IMessageTypeResolver _typeResolver; /// /// Initializes a new instance of the class. @@ -24,8 +24,8 @@ public SerializerProducerMiddleware( ISerializer serializer, IMessageTypeResolver typeResolver) { - this.serializer = serializer; - this.typeResolver = typeResolver; + _serializer = serializer; + _typeResolver = typeResolver; } /// @@ -36,13 +36,13 @@ public SerializerProducerMiddleware( /// public async Task Invoke(IMessageContext context, MiddlewareDelegate next) { - await this.typeResolver.OnProduceAsync(context); + await _typeResolver.OnProduceAsync(context); byte[] messageValue; - using (var buffer = MemoryStreamManager.GetStream()) + using (var buffer = s_memoryStreamManager.GetStream()) { - await this.serializer + await _serializer .SerializeAsync( context.Message.Value, buffer, diff --git a/src/KafkaFlow/Middlewares/TypedHandler/Configuration/TypedHandlerConfiguration.cs b/src/KafkaFlow/Middlewares/TypedHandler/Configuration/TypedHandlerConfiguration.cs index 22d5407e2..5df72bd20 100644 --- a/src/KafkaFlow/Middlewares/TypedHandler/Configuration/TypedHandlerConfiguration.cs +++ b/src/KafkaFlow/Middlewares/TypedHandler/Configuration/TypedHandlerConfiguration.cs @@ -1,7 +1,7 @@ +using System; + namespace KafkaFlow.Middlewares.TypedHandler.Configuration { - using System; - internal class TypedHandlerConfiguration { public HandlerTypeMapping HandlerMapping { get; } = new(); diff --git a/src/KafkaFlow/Middlewares/TypedHandler/Configuration/TypedHandlerConfigurationBuilder.cs b/src/KafkaFlow/Middlewares/TypedHandler/Configuration/TypedHandlerConfigurationBuilder.cs index acea49420..d4bd655d3 100644 --- a/src/KafkaFlow/Middlewares/TypedHandler/Configuration/TypedHandlerConfigurationBuilder.cs +++ b/src/KafkaFlow/Middlewares/TypedHandler/Configuration/TypedHandlerConfigurationBuilder.cs @@ -1,22 +1,22 @@ -namespace KafkaFlow -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Reflection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; - using KafkaFlow.Middlewares.TypedHandler.Configuration; +using KafkaFlow.Middlewares.TypedHandler.Configuration; +namespace KafkaFlow +{ /// /// Builder class for typed handler configuration /// public class TypedHandlerConfigurationBuilder { - private readonly IDependencyConfigurator dependencyConfigurator; - private readonly List handlers = new(); + private readonly IDependencyConfigurator _dependencyConfigurator; + private readonly List _handlers = new(); - private Action onNoHandlerFound = (_) => { }; - private InstanceLifetime serviceLifetime = InstanceLifetime.Singleton; + private Action _onNoHandlerFound = (_) => { }; + private InstanceLifetime _serviceLifetime = InstanceLifetime.Singleton; /// /// Initializes a new instance of the class. @@ -24,7 +24,7 @@ public class TypedHandlerConfigurationBuilder /// Dependency injection configurator public TypedHandlerConfigurationBuilder(IDependencyConfigurator dependencyConfigurator) { - this.dependencyConfigurator = dependencyConfigurator; + _dependencyConfigurator = dependencyConfigurator; } /// @@ -47,7 +47,7 @@ public TypedHandlerConfigurationBuilder AddHandlersFromAssemblyOf(params Type[] .Where(x => x.IsClass && !x.IsAbstract && typeof(IMessageHandler).IsAssignableFrom(x)) .Distinct(); - this.handlers.AddRange(handlerTypes); + _handlers.AddRange(handlerTypes); return this; } @@ -58,7 +58,7 @@ public TypedHandlerConfigurationBuilder AddHandlersFromAssemblyOf(params Type[] /// public TypedHandlerConfigurationBuilder AddHandlers(IEnumerable handlers) { - this.handlers.AddRange(handlers); + _handlers.AddRange(handlers); return this; } @@ -70,7 +70,7 @@ public TypedHandlerConfigurationBuilder AddHandlers(IEnumerable handlers) public TypedHandlerConfigurationBuilder AddHandler() where T : class, IMessageHandler { - this.handlers.Add(typeof(T)); + _handlers.Add(typeof(T)); return this; } @@ -81,7 +81,7 @@ public TypedHandlerConfigurationBuilder AddHandler() /// public TypedHandlerConfigurationBuilder WhenNoHandlerFound(Action handler) { - this.onNoHandlerFound = handler; + _onNoHandlerFound = handler; return this; } @@ -92,7 +92,7 @@ public TypedHandlerConfigurationBuilder WhenNoHandlerFound(Action public TypedHandlerConfigurationBuilder WithHandlerLifetime(InstanceLifetime lifetime) { - this.serviceLifetime = lifetime; + _serviceLifetime = lifetime; return this; } @@ -100,15 +100,15 @@ internal TypedHandlerConfiguration Build() { var configuration = new TypedHandlerConfiguration { - OnNoHandlerFound = this.onNoHandlerFound, + OnNoHandlerFound = _onNoHandlerFound, }; - foreach (var handlerType in this.handlers) + foreach (var handlerType in _handlers) { - this.dependencyConfigurator.Add( + _dependencyConfigurator.Add( handlerType, handlerType, - this.serviceLifetime); + _serviceLifetime); var messageTypes = handlerType .GetInterfaces() diff --git a/src/KafkaFlow/Middlewares/TypedHandler/HandlerExecutor.cs b/src/KafkaFlow/Middlewares/TypedHandler/HandlerExecutor.cs index 0af39ecd0..2753d4079 100644 --- a/src/KafkaFlow/Middlewares/TypedHandler/HandlerExecutor.cs +++ b/src/KafkaFlow/Middlewares/TypedHandler/HandlerExecutor.cs @@ -1,18 +1,18 @@ +using System; +using System.Collections.Concurrent; +using System.Threading.Tasks; + namespace KafkaFlow.Middlewares.TypedHandler { - using System; - using System.Collections.Concurrent; - using System.Threading.Tasks; - internal abstract class HandlerExecutor { - private static readonly ConcurrentDictionary Executors = new(); + private static readonly ConcurrentDictionary s_executors = new(); public static HandlerExecutor GetExecutor(Type messageType) { - return Executors.SafeGetOrAdd( + return s_executors.SafeGetOrAdd( messageType, - _ => (HandlerExecutor) Activator.CreateInstance(typeof(InnerHandlerExecutor<>).MakeGenericType(messageType))); + _ => (HandlerExecutor)Activator.CreateInstance(typeof(InnerHandlerExecutor<>).MakeGenericType(messageType))); } public abstract Task Execute(object handler, IMessageContext context, object message); @@ -21,9 +21,9 @@ private class InnerHandlerExecutor : HandlerExecutor { public override Task Execute(object handler, IMessageContext context, object message) { - var h = (IMessageHandler) handler; + var h = (IMessageHandler)handler; - return h.Handle(context, (T) message); + return h.Handle(context, (T)message); } } } diff --git a/src/KafkaFlow/Middlewares/TypedHandler/HandlerTypeMapping.cs b/src/KafkaFlow/Middlewares/TypedHandler/HandlerTypeMapping.cs index 986ee1c2a..766eb6b04 100644 --- a/src/KafkaFlow/Middlewares/TypedHandler/HandlerTypeMapping.cs +++ b/src/KafkaFlow/Middlewares/TypedHandler/HandlerTypeMapping.cs @@ -1,20 +1,20 @@ +using System; +using System.Collections.Generic; + namespace KafkaFlow.Middlewares.TypedHandler { - using System; - using System.Collections.Generic; - internal class HandlerTypeMapping { - private static readonly IReadOnlyList EmptyList = new List().AsReadOnly(); + private static readonly IReadOnlyList s_emptyList = new List().AsReadOnly(); - private readonly Dictionary> mapping = new(); + private readonly Dictionary> _mapping = new(); public void AddMapping(Type messageType, Type handlerType) { - if (!this.mapping.TryGetValue(messageType, out var handlers)) + if (!_mapping.TryGetValue(messageType, out var handlers)) { handlers = new List(); - this.mapping.Add(messageType, handlers); + _mapping.Add(messageType, handlers); } handlers.Add(handlerType); @@ -24,12 +24,12 @@ public IReadOnlyList GetHandlersTypes(Type messageType) { if (messageType is null) { - return EmptyList; + return s_emptyList; } - return this.mapping.TryGetValue(messageType, out var handlerType) ? + return _mapping.TryGetValue(messageType, out var handlerType) ? handlerType : - EmptyList; + s_emptyList; } } } diff --git a/src/KafkaFlow/Middlewares/TypedHandler/TypedHandlerMiddleware.cs b/src/KafkaFlow/Middlewares/TypedHandler/TypedHandlerMiddleware.cs index 37d308491..8de550dbd 100644 --- a/src/KafkaFlow/Middlewares/TypedHandler/TypedHandlerMiddleware.cs +++ b/src/KafkaFlow/Middlewares/TypedHandler/TypedHandlerMiddleware.cs @@ -1,31 +1,31 @@ +using System.Linq; +using System.Threading.Tasks; +using KafkaFlow.Middlewares.TypedHandler.Configuration; + namespace KafkaFlow.Middlewares.TypedHandler { - using System.Linq; - using System.Threading.Tasks; - using KafkaFlow.Middlewares.TypedHandler.Configuration; - internal class TypedHandlerMiddleware : IMessageMiddleware { - private readonly IDependencyResolver dependencyResolver; - private readonly TypedHandlerConfiguration configuration; + private readonly IDependencyResolver _dependencyResolver; + private readonly TypedHandlerConfiguration _configuration; public TypedHandlerMiddleware( IDependencyResolver dependencyResolver, TypedHandlerConfiguration configuration) { - this.dependencyResolver = dependencyResolver; - this.configuration = configuration; + _dependencyResolver = dependencyResolver; + _configuration = configuration; } public async Task Invoke(IMessageContext context, MiddlewareDelegate next) { - var handlers = this.configuration + var handlers = _configuration .HandlerMapping .GetHandlersTypes(context.Message.Value?.GetType()); if (!handlers.Any()) { - this.configuration.OnNoHandlerFound(context); + _configuration.OnNoHandlerFound(context); } else { @@ -36,7 +36,7 @@ await Task.WhenAll( HandlerExecutor .GetExecutor(context.Message.Value.GetType()) .Execute( - this.dependencyResolver.Resolve(handler), + _dependencyResolver.Resolve(handler), context, context.Message.Value))) .ConfigureAwait(false); diff --git a/src/KafkaFlow/Producers/BatchProduceException.cs b/src/KafkaFlow/Producers/BatchProduceException.cs index 23294f9d9..733f704fe 100644 --- a/src/KafkaFlow/Producers/BatchProduceException.cs +++ b/src/KafkaFlow/Producers/BatchProduceException.cs @@ -1,8 +1,8 @@ +using System; +using System.Collections.Generic; + namespace KafkaFlow.Producers { - using System; - using System.Collections.Generic; - /// /// Exception thrown by /// diff --git a/src/KafkaFlow/Producers/BatchProduceExtension.cs b/src/KafkaFlow/Producers/BatchProduceExtension.cs index 0cf70a929..69bbb1c38 100644 --- a/src/KafkaFlow/Producers/BatchProduceExtension.cs +++ b/src/KafkaFlow/Producers/BatchProduceExtension.cs @@ -1,9 +1,9 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + namespace KafkaFlow.Producers { - using System.Collections.Generic; - using System.Threading; - using System.Threading.Tasks; - /// /// No needed /// diff --git a/src/KafkaFlow/Producers/BatchProduceItem.cs b/src/KafkaFlow/Producers/BatchProduceItem.cs index e23cfd28d..08073e8f5 100644 --- a/src/KafkaFlow/Producers/BatchProduceItem.cs +++ b/src/KafkaFlow/Producers/BatchProduceItem.cs @@ -1,7 +1,7 @@ +using Confluent.Kafka; + namespace KafkaFlow.Producers { - using Confluent.Kafka; - /// /// Represents a message to be produced in batch /// diff --git a/src/KafkaFlow/Producers/IMessageProducer.cs b/src/KafkaFlow/Producers/IMessageProducer.cs index 5eaa83eca..d06ae0f76 100644 --- a/src/KafkaFlow/Producers/IMessageProducer.cs +++ b/src/KafkaFlow/Producers/IMessageProducer.cs @@ -1,9 +1,9 @@ +using System; +using System.Threading.Tasks; +using Confluent.Kafka; + namespace KafkaFlow { - using System; - using System.Threading.Tasks; - using Confluent.Kafka; - /// /// Provides access to the kafka message producer /// diff --git a/src/KafkaFlow/Producers/IProducerAccessor.cs b/src/KafkaFlow/Producers/IProducerAccessor.cs index 629b44665..75b478a0a 100644 --- a/src/KafkaFlow/Producers/IProducerAccessor.cs +++ b/src/KafkaFlow/Producers/IProducerAccessor.cs @@ -1,7 +1,7 @@ +using System.Collections.Generic; + namespace KafkaFlow.Producers { - using System.Collections.Generic; - /// /// Provides access to the configured producers /// diff --git a/src/KafkaFlow/Producers/MessageProducer.cs b/src/KafkaFlow/Producers/MessageProducer.cs index ab12773d3..76b6e7a5c 100644 --- a/src/KafkaFlow/Producers/MessageProducer.cs +++ b/src/KafkaFlow/Producers/MessageProducer.cs @@ -1,35 +1,35 @@ +using System; +using System.Text; +using System.Threading.Tasks; +using Confluent.Kafka; +using KafkaFlow.Configuration; + namespace KafkaFlow.Producers { - using System; - using System.Text; - using System.Threading.Tasks; - using Confluent.Kafka; - using KafkaFlow.Configuration; - internal class MessageProducer : IMessageProducer, IDisposable { - private readonly IDependencyResolverScope producerDependencyScope; - private readonly ILogHandler logHandler; - private readonly IProducerConfiguration configuration; - private readonly MiddlewareExecutor middlewareExecutor; - private readonly GlobalEvents globalEvents; + private readonly IDependencyResolverScope _producerDependencyScope; + private readonly ILogHandler _logHandler; + private readonly IProducerConfiguration _configuration; + private readonly MiddlewareExecutor _middlewareExecutor; + private readonly GlobalEvents _globalEvents; - private readonly object producerCreationSync = new(); + private readonly object _producerCreationSync = new(); - private volatile IProducer producer; + private volatile IProducer _producer; public MessageProducer( IDependencyResolver dependencyResolver, IProducerConfiguration configuration) { - this.producerDependencyScope = dependencyResolver.CreateScope(); - this.logHandler = dependencyResolver.Resolve(); - this.configuration = configuration; - this.middlewareExecutor = new MiddlewareExecutor(configuration.MiddlewaresConfigurations); - this.globalEvents = dependencyResolver.Resolve(); + _producerDependencyScope = dependencyResolver.CreateScope(); + _logHandler = dependencyResolver.Resolve(); + _configuration = configuration; + _middlewareExecutor = new MiddlewareExecutor(configuration.MiddlewaresConfigurations); + _globalEvents = dependencyResolver.Resolve(); } - public string ProducerName => this.configuration.Name; + public string ProducerName => _configuration.Name; public async Task> ProduceAsync( string topic, @@ -40,7 +40,7 @@ public async Task> ProduceAsync( { DeliveryResult report = null; - using var messageScope = this.producerDependencyScope.Resolver.CreateScope(); + using var messageScope = _producerDependencyScope.Resolver.CreateScope(); var messageContext = this.CreateMessageContext( topic, @@ -49,11 +49,11 @@ public async Task> ProduceAsync( headers, messageScope.Resolver); - await this.globalEvents.FireMessageProduceStartedAsync(new MessageEventContext(messageContext)); + await _globalEvents.FireMessageProduceStartedAsync(new MessageEventContext(messageContext)); try { - await this.middlewareExecutor + await _middlewareExecutor .Execute( messageContext, async context => @@ -64,11 +64,11 @@ await this.middlewareExecutor }) .ConfigureAwait(false); - await this.globalEvents.FireMessageProduceCompletedAsync(new MessageEventContext(messageContext)); + await _globalEvents.FireMessageProduceCompletedAsync(new MessageEventContext(messageContext)); } catch (Exception e) { - await this.globalEvents.FireMessageProduceErrorAsync(new MessageErrorEventContext(messageContext, e)); + await _globalEvents.FireMessageProduceErrorAsync(new MessageErrorEventContext(messageContext, e)); throw; } @@ -81,14 +81,14 @@ public Task> ProduceAsync( IMessageHeaders headers = null, int? partition = null) { - if (string.IsNullOrWhiteSpace(this.configuration.DefaultTopic)) + if (string.IsNullOrWhiteSpace(_configuration.DefaultTopic)) { throw new InvalidOperationException( $"There is no default topic defined for producer {this.ProducerName}"); } return this.ProduceAsync( - this.configuration.DefaultTopic, + _configuration.DefaultTopic, messageKey, messageValue, headers, @@ -103,7 +103,7 @@ public void Produce( Action> deliveryHandler = null, int? partition = null) { - var messageScope = this.producerDependencyScope.Resolver.CreateScope(); + var messageScope = _producerDependencyScope.Resolver.CreateScope(); var messageContext = this.CreateMessageContext( topic, @@ -112,9 +112,9 @@ public void Produce( headers, messageScope.Resolver); - this.globalEvents.FireMessageProduceStartedAsync(new MessageEventContext(messageContext)); + _globalEvents.FireMessageProduceStartedAsync(new MessageEventContext(messageContext)); - this.middlewareExecutor + _middlewareExecutor .Execute( messageContext, context => @@ -157,7 +157,7 @@ public void Produce( messageScope.Dispose(); }); - this.globalEvents.FireMessageProduceCompletedAsync(new MessageEventContext(messageContext)); + _globalEvents.FireMessageProduceCompletedAsync(new MessageEventContext(messageContext)); } public void Produce( @@ -167,14 +167,14 @@ public void Produce( Action> deliveryHandler = null, int? partition = null) { - if (string.IsNullOrWhiteSpace(this.configuration.DefaultTopic)) + if (string.IsNullOrWhiteSpace(_configuration.DefaultTopic)) { throw new InvalidOperationException( $"There is no default topic defined for producer {this.ProducerName}"); } this.Produce( - this.configuration.DefaultTopic, + _configuration.DefaultTopic, messageKey, messageValue, headers, @@ -184,7 +184,7 @@ public void Produce( public void Dispose() { - this.producer?.Dispose(); + _producer?.Dispose(); } private static void FillContextWithResultMetadata(IMessageContext context, DeliveryResult result) @@ -227,19 +227,19 @@ private static Message CreateMessage(IMessageContext context) private IProducer EnsureProducer() { - if (this.producer != null) + if (_producer != null) { - return this.producer; + return _producer; } - lock (this.producerCreationSync) + lock (_producerCreationSync) { - if (this.producer != null) + if (_producer != null) { - return this.producer; + return _producer; } - var producerBuilder = new ProducerBuilder(this.configuration.GetKafkaConfig()) + var producerBuilder = new ProducerBuilder(_configuration.GetKafkaConfig()) .SetErrorHandler( (_, error) => { @@ -249,32 +249,32 @@ private IProducer EnsureProducer() } else { - this.logHandler.Warning("Kafka Producer Error", new { Error = error }); + _logHandler.Warning("Kafka Producer Error", new { Error = error }); } }) .SetStatisticsHandler( (_, statistics) => { - foreach (var handler in this.configuration.StatisticsHandlers) + foreach (var handler in _configuration.StatisticsHandlers) { handler.Invoke(statistics); } }); - return this.producer = this.configuration.CustomFactory( + return _producer = _configuration.CustomFactory( producerBuilder.Build(), - this.producerDependencyScope.Resolver); + _producerDependencyScope.Resolver); } } private void InvalidateProducer(Error error, DeliveryResult result) { - lock (this.producerCreationSync) + lock (_producerCreationSync) { - this.producer = null; + _producer = null; } - this.logHandler.Error( + _logHandler.Error( "Kafka produce fatal error occurred. The producer will be recreated", result is null ? new KafkaException(error) : new ProduceException(error, result), new { Error = error }); @@ -297,7 +297,7 @@ private async Task> InternalProduceAsync(IMessage } catch (ProduceException e) { - await this.globalEvents.FireMessageProduceErrorAsync(new MessageErrorEventContext(context, e)); + await _globalEvents.FireMessageProduceErrorAsync(new MessageErrorEventContext(context, e)); if (e.Error.IsFatal) { @@ -360,8 +360,8 @@ private MessageContext CreateMessageContext( headers, messageScopedResolver, null, - new ProducerContext(topic, this.producerDependencyScope.Resolver), - this.configuration.Cluster.Brokers); + new ProducerContext(topic, _producerDependencyScope.Resolver), + _configuration.Cluster.Brokers); } } } diff --git a/src/KafkaFlow/Producers/MessageProducerWrapper.cs b/src/KafkaFlow/Producers/MessageProducerWrapper.cs index 78268f1d9..8115a3411 100644 --- a/src/KafkaFlow/Producers/MessageProducerWrapper.cs +++ b/src/KafkaFlow/Producers/MessageProducerWrapper.cs @@ -1,19 +1,19 @@ +using System; +using System.Threading.Tasks; +using Confluent.Kafka; + namespace KafkaFlow.Producers { - using System; - using System.Threading.Tasks; - using Confluent.Kafka; - internal class MessageProducerWrapper : IMessageProducer { - private readonly IMessageProducer producer; + private readonly IMessageProducer _producer; public MessageProducerWrapper(IMessageProducer producer) { - this.producer = producer; + _producer = producer; } - public string ProducerName => this.producer.ProducerName; + public string ProducerName => _producer.ProducerName; public Task> ProduceAsync( string topic, @@ -22,7 +22,7 @@ public Task> ProduceAsync( IMessageHeaders headers = null, int? partition = null) { - return this.producer.ProduceAsync( + return _producer.ProduceAsync( topic, messageKey, message, @@ -36,7 +36,7 @@ public Task> ProduceAsync( IMessageHeaders headers = null, int? partition = null) { - return this.producer.ProduceAsync( + return _producer.ProduceAsync( messageKey, message, headers, @@ -51,7 +51,7 @@ public void Produce( Action> deliveryHandler = null, int? partition = null) { - this.producer.Produce( + _producer.Produce( topic, messageKey, message, @@ -67,7 +67,7 @@ public void Produce( Action> deliveryHandler = null, int? partition = null) { - this.producer.Produce( + _producer.Produce( messageKey, message, headers, diff --git a/src/KafkaFlow/Producers/ProducerAccessor.cs b/src/KafkaFlow/Producers/ProducerAccessor.cs index 0bdecc0f2..cd844c620 100644 --- a/src/KafkaFlow/Producers/ProducerAccessor.cs +++ b/src/KafkaFlow/Producers/ProducerAccessor.cs @@ -1,25 +1,25 @@ +using System.Collections.Generic; +using System.Linq; + namespace KafkaFlow.Producers { - using System.Collections.Generic; - using System.Linq; - internal class ProducerAccessor : IProducerAccessor { - private readonly Dictionary producers; + private readonly Dictionary _producers; public ProducerAccessor(IEnumerable producers) { - this.producers = producers.ToDictionary(x => x.ProducerName); + _producers = producers.ToDictionary(x => x.ProducerName); } - public IEnumerable All => this.producers.Values; + public IEnumerable All => _producers.Values; public IMessageProducer this[string name] => this.GetProducer(name); public IMessageProducer GetProducer(string name) => - this.producers.TryGetValue(name, out var consumer) ? consumer : null; + _producers.TryGetValue(name, out var consumer) ? consumer : null; public IMessageProducer GetProducer() => - this.producers.TryGetValue(typeof(TProducer).FullName!, out var consumer) ? consumer : null; + _producers.TryGetValue(typeof(TProducer).FullName!, out var consumer) ? consumer : null; } } diff --git a/src/KafkaFlow/TopicMetadata.cs b/src/KafkaFlow/TopicMetadata.cs index cf3397cdf..1097b3fbc 100644 --- a/src/KafkaFlow/TopicMetadata.cs +++ b/src/KafkaFlow/TopicMetadata.cs @@ -1,7 +1,7 @@ +using System.Collections.Generic; + namespace KafkaFlow { - using System.Collections.Generic; - public record TopicMetadata { public TopicMetadata(string name, IReadOnlyCollection partitions) diff --git a/src/KafkaFlow/TopicPartitionMetadata.cs b/src/KafkaFlow/TopicPartitionMetadata.cs index 37ecd4a8e..c32462886 100644 --- a/src/KafkaFlow/TopicPartitionMetadata.cs +++ b/src/KafkaFlow/TopicPartitionMetadata.cs @@ -2,9 +2,9 @@ namespace KafkaFlow { public class TopicPartitionMetadata { - public TopicPartitionMetadata(int Id) + public TopicPartitionMetadata(int id) { - this.Id = Id; + this.Id = id; } public int Id { get; } diff --git a/src/StyleCopAnalyzersDefault.ruleset b/src/StyleCopAnalyzersDefault.ruleset index 841a79a7a..233fb45e0 100644 --- a/src/StyleCopAnalyzersDefault.ruleset +++ b/src/StyleCopAnalyzersDefault.ruleset @@ -5,16 +5,16 @@ - + - + - + @@ -38,7 +38,7 @@ - + @@ -103,14 +103,14 @@ - + - - - + + + - + diff --git a/src/stylecop.json b/src/stylecop.json index 1fb82d1e8..0ac797437 100644 --- a/src/stylecop.json +++ b/src/stylecop.json @@ -11,6 +11,10 @@ }, "layoutRules": { "newlineAtEndOfFile": "require" + }, + "orderingRules": { + "systemUsingDirectivesFirst": true, + "usingDirectivesPlacement": "outsideNamespace" } } } diff --git a/src/KafkaFlow.IntegrationTests/CompressionSerializationTest.cs b/tests/KafkaFlow.IntegrationTests/CompressionSerializationTest.cs similarity index 52% rename from src/KafkaFlow.IntegrationTests/CompressionSerializationTest.cs rename to tests/KafkaFlow.IntegrationTests/CompressionSerializationTest.cs index 02be99616..a3b3a8d31 100644 --- a/src/KafkaFlow.IntegrationTests/CompressionSerializationTest.cs +++ b/tests/KafkaFlow.IntegrationTests/CompressionSerializationTest.cs @@ -1,27 +1,27 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using AutoFixture; +using global::Microsoft.Extensions.DependencyInjection; +using global::Microsoft.VisualStudio.TestTools.UnitTesting; +using KafkaFlow.IntegrationTests.Core; +using KafkaFlow.IntegrationTests.Core.Handlers; +using KafkaFlow.IntegrationTests.Core.Messages; +using KafkaFlow.IntegrationTests.Core.Producers; + namespace KafkaFlow.IntegrationTests { - using System; - using System.Linq; - using System.Threading.Tasks; - using AutoFixture; - using global::Microsoft.Extensions.DependencyInjection; - using global::Microsoft.VisualStudio.TestTools.UnitTesting; - using KafkaFlow.IntegrationTests.Core; - using KafkaFlow.IntegrationTests.Core.Handlers; - using KafkaFlow.IntegrationTests.Core.Messages; - using KafkaFlow.IntegrationTests.Core.Producers; - [TestClass] public class CompressionSerializationTest { - private readonly Fixture fixture = new(); + private readonly Fixture _fixture = new(); - private IServiceProvider provider; + private IServiceProvider _provider; [TestInitialize] public void Setup() { - this.provider = Bootstrapper.GetServiceProvider(); + _provider = Bootstrapper.GetServiceProvider(); MessageStorage.Clear(); } @@ -29,8 +29,8 @@ public void Setup() public async Task JsonGzipMessageTest() { // Arrange - var producer = this.provider.GetRequiredService>(); - var messages = this.fixture.CreateMany(10).ToList(); + var producer = _provider.GetRequiredService>(); + var messages = _fixture.CreateMany(10).ToList(); // Act await Task.WhenAll(messages.Select(m => producer.ProduceAsync(m.Id.ToString(), m))); @@ -46,8 +46,8 @@ public async Task JsonGzipMessageTest() public async Task ProtoBufGzipMessageTest() { // Arrange - var producer = this.provider.GetRequiredService>(); - var messages = this.fixture.CreateMany(10).ToList(); + var producer = _provider.GetRequiredService>(); + var messages = _fixture.CreateMany(10).ToList(); // Act await Task.WhenAll(messages.Select(m => producer.ProduceAsync(m.Id.ToString(), m))); diff --git a/tests/KafkaFlow.IntegrationTests/CompressionTest.cs b/tests/KafkaFlow.IntegrationTests/CompressionTest.cs new file mode 100644 index 000000000..d445d627d --- /dev/null +++ b/tests/KafkaFlow.IntegrationTests/CompressionTest.cs @@ -0,0 +1,44 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using AutoFixture; +using global::Microsoft.Extensions.DependencyInjection; +using global::Microsoft.VisualStudio.TestTools.UnitTesting; +using KafkaFlow.IntegrationTests.Core; +using KafkaFlow.IntegrationTests.Core.Handlers; +using KafkaFlow.IntegrationTests.Core.Producers; + +namespace KafkaFlow.IntegrationTests +{ + [TestClass] + public class CompressionTest + { + private readonly Fixture _fixture = new(); + + private IServiceProvider _provider; + + [TestInitialize] + public void Setup() + { + _provider = Bootstrapper.GetServiceProvider(); + MessageStorage.Clear(); + } + + [TestMethod] + public async Task GzipTest() + { + // Arrange + var producer = _provider.GetRequiredService>(); + var messages = _fixture.CreateMany(10).ToList(); + + // Act + await Task.WhenAll(messages.Select(m => producer.ProduceAsync(Guid.NewGuid().ToString(), m))); + + // Assert + foreach (var message in messages) + { + await MessageStorage.AssertMessageAsync(message); + } + } + } +} diff --git a/src/KafkaFlow.IntegrationTests/ConsumerTest.cs b/tests/KafkaFlow.IntegrationTests/ConsumerTest.cs similarity index 70% rename from src/KafkaFlow.IntegrationTests/ConsumerTest.cs rename to tests/KafkaFlow.IntegrationTests/ConsumerTest.cs index d80752cf3..2268cf8ff 100644 --- a/src/KafkaFlow.IntegrationTests/ConsumerTest.cs +++ b/tests/KafkaFlow.IntegrationTests/ConsumerTest.cs @@ -1,28 +1,28 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using AutoFixture; +using global::Microsoft.Extensions.DependencyInjection; +using global::Microsoft.VisualStudio.TestTools.UnitTesting; +using KafkaFlow.Consumers; +using KafkaFlow.IntegrationTests.Core; +using KafkaFlow.IntegrationTests.Core.Handlers; +using KafkaFlow.IntegrationTests.Core.Messages; +using KafkaFlow.IntegrationTests.Core.Producers; + namespace KafkaFlow.IntegrationTests { - using System; - using System.Linq; - using System.Threading.Tasks; - using AutoFixture; - using global::Microsoft.Extensions.DependencyInjection; - using global::Microsoft.VisualStudio.TestTools.UnitTesting; - using KafkaFlow.Consumers; - using KafkaFlow.IntegrationTests.Core; - using KafkaFlow.IntegrationTests.Core.Handlers; - using KafkaFlow.IntegrationTests.Core.Messages; - using KafkaFlow.IntegrationTests.Core.Producers; - [TestClass] public class ConsumerTest { - private readonly Fixture fixture = new(); + private readonly Fixture _fixture = new(); - private IServiceProvider provider; + private IServiceProvider _provider; [TestInitialize] public void Setup() { - this.provider = Bootstrapper.GetServiceProvider(); + _provider = Bootstrapper.GetServiceProvider(); MessageStorage.Clear(); } @@ -30,9 +30,9 @@ public void Setup() public async Task MultipleMessagesMultipleHandlersSingleTopicTest() { // Arrange - var producer = this.provider.GetRequiredService>(); - var messages1 = this.fixture.CreateMany(5).ToList(); - var messages2 = this.fixture.CreateMany(5).ToList(); + var producer = _provider.GetRequiredService>(); + var messages1 = _fixture.CreateMany(5).ToList(); + var messages2 = _fixture.CreateMany(5).ToList(); // Act await Task.WhenAll(messages1.Select(m => producer.ProduceAsync(m.Id.ToString(), m))); @@ -54,9 +54,9 @@ public async Task MultipleMessagesMultipleHandlersSingleTopicTest() public async Task MultipleTopicsSingleConsumerTest() { // Arrange - var producer1 = this.provider.GetRequiredService>(); - var producer2 = this.provider.GetRequiredService>(); - var messages = this.fixture.CreateMany(1).ToList(); + var producer1 = _provider.GetRequiredService>(); + var producer2 = _provider.GetRequiredService>(); + var messages = _fixture.CreateMany(1).ToList(); // Act messages.ForEach(m => producer1.Produce(m.Id.ToString(), m)); @@ -73,8 +73,8 @@ public async Task MultipleTopicsSingleConsumerTest() public async Task MultipleHandlersSingleTypeConsumerTest() { // Arrange - var producer = this.provider.GetRequiredService>(); - var messages = this.fixture.CreateMany(5).ToList(); + var producer = _provider.GetRequiredService>(); + var messages = _fixture.CreateMany(5).ToList(); // Act messages.ForEach(m => producer.Produce(m.Id.ToString(), m)); @@ -92,8 +92,8 @@ public async Task MessageOrderingTest() // Arrange var version = 1; var partitionKey = Guid.NewGuid(); - var producer = this.provider.GetRequiredService>(); - var messages = this.fixture + var producer = _provider.GetRequiredService>(); + var messages = _fixture .Build() .Without(t => t.Version) .Do(t => t.Version = version++) @@ -122,8 +122,8 @@ public async Task MessageOrderingTest() public async Task PauseResumeHeartbeatTest() { // Arrange - var producer = this.provider.GetRequiredService>(); - var messages = this.fixture.CreateMany(5).ToList(); + var producer = _provider.GetRequiredService>(); + var messages = _fixture.CreateMany(5).ToList(); // Act await Task.WhenAll( @@ -146,7 +146,7 @@ await Task.WhenAll( public void AddConsumer_WithSharedConsumerConfig_ConsumersAreConfiguratedIndependently() { // Act - var consumers = this.provider.GetRequiredService().All; + var consumers = _provider.GetRequiredService().All; // Assert Assert.IsNotNull(consumers.FirstOrDefault(x => x.GroupId.Equals(Bootstrapper.AvroGroupId))); diff --git a/src/KafkaFlow.IntegrationTests/Core/Bootstrapper.cs b/tests/KafkaFlow.IntegrationTests/Core/Bootstrapper.cs similarity index 95% rename from src/KafkaFlow.IntegrationTests/Core/Bootstrapper.cs rename to tests/KafkaFlow.IntegrationTests/Core/Bootstrapper.cs index 23edee91c..c8de5991f 100644 --- a/src/KafkaFlow.IntegrationTests/Core/Bootstrapper.cs +++ b/tests/KafkaFlow.IntegrationTests/Core/Bootstrapper.cs @@ -1,23 +1,22 @@ +using System; +using System.IO; +using System.Threading; +using Confluent.Kafka; +using Confluent.SchemaRegistry; +using Confluent.SchemaRegistry.Serdes; +using global::Microsoft.Extensions.Configuration; +using global::Microsoft.Extensions.DependencyInjection; +using global::Microsoft.Extensions.Hosting; +using KafkaFlow.Compressor.Gzip; +using KafkaFlow.IntegrationTests.Core.Handlers; +using KafkaFlow.IntegrationTests.Core.Messages; +using KafkaFlow.IntegrationTests.Core.Middlewares; +using KafkaFlow.IntegrationTests.Core.Producers; +using KafkaFlow.Serializer; +using KafkaFlow.Serializer.SchemaRegistry; + namespace KafkaFlow.IntegrationTests.Core { - using System; - using System.IO; - using System.Threading; - using Confluent.Kafka; - using Confluent.SchemaRegistry; - using Confluent.SchemaRegistry.Serdes; - using global::Microsoft.Extensions.Configuration; - using global::Microsoft.Extensions.DependencyInjection; - using global::Microsoft.Extensions.Hosting; - using KafkaFlow.Compressor.Gzip; - using KafkaFlow.IntegrationTests.Core.Handlers; - using KafkaFlow.IntegrationTests.Core.Messages; - using KafkaFlow.IntegrationTests.Core.Middlewares; - using KafkaFlow.IntegrationTests.Core.Producers; - using KafkaFlow.Serializer; - using KafkaFlow.Serializer.SchemaRegistry; - using AutoOffsetReset = KafkaFlow.AutoOffsetReset; - internal static class Bootstrapper { public const string PauseResumeTopicName = "test-pause-resume"; @@ -41,9 +40,9 @@ internal static class Bootstrapper private const string ProtobufGzipTopicName2 = "test-protobuf-gzip-2"; private const string AvroTopicName = "test-avro"; - private static readonly Lazy LazyProvider = new(SetupProvider); + private static readonly Lazy s_lazyProvider = new(SetupProvider); - public static IServiceProvider GetServiceProvider() => LazyProvider.Value; + public static IServiceProvider GetServiceProvider() => s_lazyProvider.Value; private static IServiceProvider SetupProvider() { diff --git a/src/KafkaFlow.IntegrationTests/Core/Exceptions/ErrorExecutingMiddlewareException.cs b/tests/KafkaFlow.IntegrationTests/Core/Exceptions/ErrorExecutingMiddlewareException.cs similarity index 76% rename from src/KafkaFlow.IntegrationTests/Core/Exceptions/ErrorExecutingMiddlewareException.cs rename to tests/KafkaFlow.IntegrationTests/Core/Exceptions/ErrorExecutingMiddlewareException.cs index a582da1e5..90a717237 100644 --- a/src/KafkaFlow.IntegrationTests/Core/Exceptions/ErrorExecutingMiddlewareException.cs +++ b/tests/KafkaFlow.IntegrationTests/Core/Exceptions/ErrorExecutingMiddlewareException.cs @@ -1,7 +1,7 @@ -namespace KafkaFlow.IntegrationTests.Core.Exceptions -{ - using System; +using System; +namespace KafkaFlow.IntegrationTests.Core.Exceptions +{ public class ErrorExecutingMiddlewareException : Exception { public ErrorExecutingMiddlewareException(string middlewareName) diff --git a/src/KafkaFlow.IntegrationTests/Core/Exceptions/PartitionAssignmentException.cs b/tests/KafkaFlow.IntegrationTests/Core/Exceptions/PartitionAssignmentException.cs similarity index 78% rename from src/KafkaFlow.IntegrationTests/Core/Exceptions/PartitionAssignmentException.cs rename to tests/KafkaFlow.IntegrationTests/Core/Exceptions/PartitionAssignmentException.cs index 6f11c60da..61a0ce102 100644 --- a/src/KafkaFlow.IntegrationTests/Core/Exceptions/PartitionAssignmentException.cs +++ b/tests/KafkaFlow.IntegrationTests/Core/Exceptions/PartitionAssignmentException.cs @@ -1,7 +1,7 @@ -namespace KafkaFlow.IntegrationTests.Core.Exceptions -{ - using System; +using System; +namespace KafkaFlow.IntegrationTests.Core.Exceptions +{ public class PartitionAssignmentException : Exception { private const string ExceptionMessage = "Partition assignment hasn't occurred yet."; diff --git a/src/KafkaFlow.IntegrationTests/Core/Handlers/AvroMessageHandler.cs b/tests/KafkaFlow.IntegrationTests/Core/Handlers/AvroMessageHandler.cs similarity index 75% rename from src/KafkaFlow.IntegrationTests/Core/Handlers/AvroMessageHandler.cs rename to tests/KafkaFlow.IntegrationTests/Core/Handlers/AvroMessageHandler.cs index feb76b1f8..56bfe79c8 100644 --- a/src/KafkaFlow.IntegrationTests/Core/Handlers/AvroMessageHandler.cs +++ b/tests/KafkaFlow.IntegrationTests/Core/Handlers/AvroMessageHandler.cs @@ -1,9 +1,8 @@ +using System.Threading.Tasks; +using MessageTypes; + namespace KafkaFlow.IntegrationTests.Core.Handlers { - using System.Threading.Tasks; - using KafkaFlow.Middlewares.TypedHandler; - using MessageTypes; - internal class AvroMessageHandler : IMessageHandler { public Task Handle(IMessageContext context, LogMessages2 message) diff --git a/src/KafkaFlow.IntegrationTests/Core/Handlers/ConfluentJsonMessageHandler.cs b/tests/KafkaFlow.IntegrationTests/Core/Handlers/ConfluentJsonMessageHandler.cs similarity index 70% rename from src/KafkaFlow.IntegrationTests/Core/Handlers/ConfluentJsonMessageHandler.cs rename to tests/KafkaFlow.IntegrationTests/Core/Handlers/ConfluentJsonMessageHandler.cs index 22e12e1cc..11c8dbaba 100644 --- a/src/KafkaFlow.IntegrationTests/Core/Handlers/ConfluentJsonMessageHandler.cs +++ b/tests/KafkaFlow.IntegrationTests/Core/Handlers/ConfluentJsonMessageHandler.cs @@ -1,9 +1,8 @@ +using System.Threading.Tasks; +using KafkaFlow.IntegrationTests.Core.Messages; + namespace KafkaFlow.IntegrationTests.Core.Handlers { - using System.Threading.Tasks; - using KafkaFlow.IntegrationTests.Core.Messages; - using KafkaFlow.Middlewares.TypedHandler; - internal class ConfluentJsonMessageHandler : IMessageHandler { public Task Handle(IMessageContext context, TestMessage3 message) diff --git a/src/KafkaFlow.IntegrationTests/Core/Handlers/ConfluentProtobufMessageHandler.cs b/tests/KafkaFlow.IntegrationTests/Core/Handlers/ConfluentProtobufMessageHandler.cs similarity index 71% rename from src/KafkaFlow.IntegrationTests/Core/Handlers/ConfluentProtobufMessageHandler.cs rename to tests/KafkaFlow.IntegrationTests/Core/Handlers/ConfluentProtobufMessageHandler.cs index 697efca9f..c95e81db8 100644 --- a/src/KafkaFlow.IntegrationTests/Core/Handlers/ConfluentProtobufMessageHandler.cs +++ b/tests/KafkaFlow.IntegrationTests/Core/Handlers/ConfluentProtobufMessageHandler.cs @@ -1,9 +1,8 @@ +using System.Threading.Tasks; +using KafkaFlow.IntegrationTests.Core.Messages; + namespace KafkaFlow.IntegrationTests.Core.Handlers { - using System.Threading.Tasks; - using KafkaFlow.IntegrationTests.Core.Messages; - using KafkaFlow.Middlewares.TypedHandler; - internal class ConfluentProtobufMessageHandler : IMessageHandler { public Task Handle(IMessageContext context, TestProtoMessage message) diff --git a/src/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler.cs b/tests/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler.cs similarity index 70% rename from src/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler.cs rename to tests/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler.cs index f2d1bb484..e53cd4642 100644 --- a/src/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler.cs +++ b/tests/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler.cs @@ -1,9 +1,8 @@ +using System.Threading.Tasks; +using KafkaFlow.IntegrationTests.Core.Messages; + namespace KafkaFlow.IntegrationTests.Core.Handlers { - using System.Threading.Tasks; - using KafkaFlow.IntegrationTests.Core.Messages; - using KafkaFlow.Middlewares.TypedHandler; - internal class MessageHandler : IMessageHandler { public Task Handle(IMessageContext context, TestMessage1 message) diff --git a/src/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler1.cs b/tests/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler1.cs similarity index 70% rename from src/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler1.cs rename to tests/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler1.cs index 1b01e1ea0..fa550c173 100644 --- a/src/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler1.cs +++ b/tests/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler1.cs @@ -1,9 +1,8 @@ +using System.Threading.Tasks; +using KafkaFlow.IntegrationTests.Core.Messages; + namespace KafkaFlow.IntegrationTests.Core.Handlers { - using System.Threading.Tasks; - using KafkaFlow.IntegrationTests.Core.Messages; - using KafkaFlow.Middlewares.TypedHandler; - internal class MessageHandler1 : IMessageHandler { public Task Handle(IMessageContext context, TestMessage1 message) diff --git a/src/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler2.cs b/tests/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler2.cs similarity index 70% rename from src/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler2.cs rename to tests/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler2.cs index f47f02638..a257e65da 100644 --- a/src/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler2.cs +++ b/tests/KafkaFlow.IntegrationTests/Core/Handlers/MessageHandler2.cs @@ -1,10 +1,9 @@ +using System; +using System.Threading.Tasks; +using KafkaFlow.IntegrationTests.Core.Messages; + namespace KafkaFlow.IntegrationTests.Core.Handlers { - using System; - using System.Threading.Tasks; - using KafkaFlow.IntegrationTests.Core.Messages; - using KafkaFlow.Middlewares.TypedHandler; - internal class MessageHandler2 : IMessageHandler { public async Task Handle(IMessageContext context, TestMessage2 message) diff --git a/src/KafkaFlow.IntegrationTests/Core/Handlers/MessageStorage.cs b/tests/KafkaFlow.IntegrationTests/Core/Handlers/MessageStorage.cs similarity index 64% rename from src/KafkaFlow.IntegrationTests/Core/Handlers/MessageStorage.cs rename to tests/KafkaFlow.IntegrationTests/Core/Handlers/MessageStorage.cs index 9b117f8ed..5ab66f0ed 100644 --- a/src/KafkaFlow.IntegrationTests/Core/Handlers/MessageStorage.cs +++ b/tests/KafkaFlow.IntegrationTests/Core/Handlers/MessageStorage.cs @@ -1,49 +1,49 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using global::Microsoft.VisualStudio.TestTools.UnitTesting; +using KafkaFlow.IntegrationTests.Core.Messages; +using MessageTypes; + namespace KafkaFlow.IntegrationTests.Core.Handlers { - using System; - using System.Collections.Concurrent; - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - using global::Microsoft.VisualStudio.TestTools.UnitTesting; - using KafkaFlow.IntegrationTests.Core.Messages; - using MessageTypes; - internal static class MessageStorage { private const int TimeoutSec = 8; - private static readonly ConcurrentBag TestMessages = new(); - private static readonly ConcurrentBag AvroMessages = new(); - private static readonly ConcurrentBag ProtoMessages = new(); - private static readonly ConcurrentBag<(long, int)> Versions = new(); - private static readonly ConcurrentBag ByteMessages = new(); + private static readonly ConcurrentBag s_testMessages = new(); + private static readonly ConcurrentBag s_avroMessages = new(); + private static readonly ConcurrentBag s_protoMessages = new(); + private static readonly ConcurrentBag<(long, int)> s_versions = new(); + private static readonly ConcurrentBag s_byteMessages = new(); public static void Add(ITestMessage message) { - Versions.Add((DateTime.Now.Ticks, message.Version)); - TestMessages.Add(message); + s_versions.Add((DateTime.Now.Ticks, message.Version)); + s_testMessages.Add(message); } public static void Add(LogMessages2 message) { - AvroMessages.Add(message); + s_avroMessages.Add(message); } public static void Add(TestProtoMessage message) { - ProtoMessages.Add(message); + s_protoMessages.Add(message); } public static void Add(byte[] message) { - ByteMessages.Add(message); + s_byteMessages.Add(message); } public static async Task AssertCountMessageAsync(ITestMessage message, int count) { var start = DateTime.Now; - while (TestMessages.Count(x => x.Id == message.Id && x.Value == message.Value) != count) + while (s_testMessages.Count(x => x.Id == message.Id && x.Value == message.Value) != count) { if (DateTime.Now.Subtract(start).Seconds > TimeoutSec) { @@ -59,7 +59,7 @@ public static async Task AssertMessageAsync(ITestMessage message) { var start = DateTime.Now; - while (!TestMessages.Any(x => x.Id == message.Id && x.Value == message.Value)) + while (!s_testMessages.Any(x => x.Id == message.Id && x.Value == message.Value)) { if (DateTime.Now.Subtract(start).Seconds > TimeoutSec) { @@ -75,7 +75,7 @@ public static async Task AssertMessageAsync(LogMessages2 message) { var start = DateTime.Now; - while (!AvroMessages.Any(x => x.Message == message.Message && x.Schema.Fullname == message.Schema.Fullname)) + while (!s_avroMessages.Any(x => x.Message == message.Message && x.Schema.Fullname == message.Schema.Fullname)) { if (DateTime.Now.Subtract(start).Seconds > TimeoutSec) { @@ -91,7 +91,7 @@ public static async Task AssertMessageAsync(TestProtoMessage message) { var start = DateTime.Now; - while (!ProtoMessages.Any(x => x.Id == message.Id && x.Value == message.Value && x.Version == message.Version)) + while (!s_protoMessages.Any(x => x.Id == message.Id && x.Value == message.Value && x.Version == message.Version)) { if (DateTime.Now.Subtract(start).Seconds > TimeoutSec) { @@ -107,7 +107,7 @@ public static async Task AssertMessageAsync(byte[] message) { var start = DateTime.Now; - while (!ByteMessages.Any(x => x.SequenceEqual(message))) + while (!s_byteMessages.Any(x => x.SequenceEqual(message))) { if (DateTime.Now.Subtract(start).Seconds > TimeoutSec) { @@ -121,15 +121,15 @@ public static async Task AssertMessageAsync(byte[] message) public static List<(long ticks, int version)> GetVersions() { - return Versions.ToList(); + return s_versions.ToList(); } public static void Clear() { - Versions.Clear(); - TestMessages.Clear(); - ByteMessages.Clear(); - ProtoMessages.Clear(); + s_versions.Clear(); + s_testMessages.Clear(); + s_byteMessages.Clear(); + s_protoMessages.Clear(); } } } diff --git a/src/KafkaFlow.IntegrationTests/Core/Handlers/PauseResumeHandler.cs b/tests/KafkaFlow.IntegrationTests/Core/Handlers/PauseResumeHandler.cs similarity index 77% rename from src/KafkaFlow.IntegrationTests/Core/Handlers/PauseResumeHandler.cs rename to tests/KafkaFlow.IntegrationTests/Core/Handlers/PauseResumeHandler.cs index 05ccf1350..9d4a00419 100644 --- a/src/KafkaFlow.IntegrationTests/Core/Handlers/PauseResumeHandler.cs +++ b/tests/KafkaFlow.IntegrationTests/Core/Handlers/PauseResumeHandler.cs @@ -1,9 +1,8 @@ +using System.Threading.Tasks; +using KafkaFlow.IntegrationTests.Core.Messages; + namespace KafkaFlow.IntegrationTests.Core.Handlers { - using System.Threading.Tasks; - using KafkaFlow.IntegrationTests.Core.Messages; - using KafkaFlow.Middlewares.TypedHandler; - internal class PauseResumeHandler : IMessageHandler { public async Task Handle(IMessageContext context, PauseResumeMessage message) diff --git a/src/KafkaFlow.IntegrationTests/Core/Messages/ITestMessage.cs b/tests/KafkaFlow.IntegrationTests/Core/Messages/ITestMessage.cs similarity index 68% rename from src/KafkaFlow.IntegrationTests/Core/Messages/ITestMessage.cs rename to tests/KafkaFlow.IntegrationTests/Core/Messages/ITestMessage.cs index 36f762119..43b4371ae 100644 --- a/src/KafkaFlow.IntegrationTests/Core/Messages/ITestMessage.cs +++ b/tests/KafkaFlow.IntegrationTests/Core/Messages/ITestMessage.cs @@ -1,7 +1,7 @@ -namespace KafkaFlow.IntegrationTests.Core.Messages -{ - using System; +using System; +namespace KafkaFlow.IntegrationTests.Core.Messages +{ internal interface ITestMessage { Guid Id { get; set; } diff --git a/src/KafkaFlow.IntegrationTests/Core/Messages/LogMessages2.cs b/tests/KafkaFlow.IntegrationTests/Core/Messages/LogMessages2.cs similarity index 94% rename from src/KafkaFlow.IntegrationTests/Core/Messages/LogMessages2.cs rename to tests/KafkaFlow.IntegrationTests/Core/Messages/LogMessages2.cs index 6e393f689..baba54966 100644 --- a/src/KafkaFlow.IntegrationTests/Core/Messages/LogMessages2.cs +++ b/tests/KafkaFlow.IntegrationTests/Core/Messages/LogMessages2.cs @@ -20,7 +20,7 @@ internal partial class LogMessages2 : ISpecificRecord { public static Schema _SCHEMA = Avro.Schema.Parse("{\"type\":\"record\",\"name\":\"LogMessages2\",\"namespace\":\"MessageTypes\",\"fields\":[{\"nam" + "e\":\"Message\",\"type\":\"string\"}]}"); - private string _Message; + private string _message; public virtual Schema Schema { get @@ -32,11 +32,11 @@ public string Message { get { - return this._Message; + return _message; } set { - this._Message = value; + _message = value; } } public virtual object Get(int fieldPos) diff --git a/src/KafkaFlow.IntegrationTests/Core/Messages/PauseResumeMessage.cs b/tests/KafkaFlow.IntegrationTests/Core/Messages/PauseResumeMessage.cs similarity index 73% rename from src/KafkaFlow.IntegrationTests/Core/Messages/PauseResumeMessage.cs rename to tests/KafkaFlow.IntegrationTests/Core/Messages/PauseResumeMessage.cs index 540116376..e168e937e 100644 --- a/src/KafkaFlow.IntegrationTests/Core/Messages/PauseResumeMessage.cs +++ b/tests/KafkaFlow.IntegrationTests/Core/Messages/PauseResumeMessage.cs @@ -1,8 +1,8 @@ -namespace KafkaFlow.IntegrationTests.Core.Messages -{ - using System; - using System.Runtime.Serialization; +using System; +using System.Runtime.Serialization; +namespace KafkaFlow.IntegrationTests.Core.Messages +{ [DataContract] internal class PauseResumeMessage : ITestMessage { diff --git a/src/KafkaFlow.IntegrationTests/Core/Messages/TestMessage1.cs b/tests/KafkaFlow.IntegrationTests/Core/Messages/TestMessage1.cs similarity index 72% rename from src/KafkaFlow.IntegrationTests/Core/Messages/TestMessage1.cs rename to tests/KafkaFlow.IntegrationTests/Core/Messages/TestMessage1.cs index 044f99b65..aee78844b 100644 --- a/src/KafkaFlow.IntegrationTests/Core/Messages/TestMessage1.cs +++ b/tests/KafkaFlow.IntegrationTests/Core/Messages/TestMessage1.cs @@ -1,8 +1,8 @@ -namespace KafkaFlow.IntegrationTests.Core.Messages -{ - using System; - using System.Runtime.Serialization; +using System; +using System.Runtime.Serialization; +namespace KafkaFlow.IntegrationTests.Core.Messages +{ [DataContract] internal class TestMessage1 : ITestMessage { diff --git a/src/KafkaFlow.IntegrationTests/Core/Messages/TestMessage2.cs b/tests/KafkaFlow.IntegrationTests/Core/Messages/TestMessage2.cs similarity index 72% rename from src/KafkaFlow.IntegrationTests/Core/Messages/TestMessage2.cs rename to tests/KafkaFlow.IntegrationTests/Core/Messages/TestMessage2.cs index d1a4c6183..431f5f0fd 100644 --- a/src/KafkaFlow.IntegrationTests/Core/Messages/TestMessage2.cs +++ b/tests/KafkaFlow.IntegrationTests/Core/Messages/TestMessage2.cs @@ -1,8 +1,8 @@ -namespace KafkaFlow.IntegrationTests.Core.Messages -{ - using System; - using System.Runtime.Serialization; +using System; +using System.Runtime.Serialization; +namespace KafkaFlow.IntegrationTests.Core.Messages +{ [DataContract] internal class TestMessage2 : ITestMessage { diff --git a/src/KafkaFlow.IntegrationTests/Core/Messages/TestMessage3.cs b/tests/KafkaFlow.IntegrationTests/Core/Messages/TestMessage3.cs similarity index 72% rename from src/KafkaFlow.IntegrationTests/Core/Messages/TestMessage3.cs rename to tests/KafkaFlow.IntegrationTests/Core/Messages/TestMessage3.cs index e54bb4262..f6beafd59 100644 --- a/src/KafkaFlow.IntegrationTests/Core/Messages/TestMessage3.cs +++ b/tests/KafkaFlow.IntegrationTests/Core/Messages/TestMessage3.cs @@ -1,7 +1,7 @@ -namespace KafkaFlow.IntegrationTests.Core.Messages -{ - using System; +using System; +namespace KafkaFlow.IntegrationTests.Core.Messages +{ internal class TestMessage3 : ITestMessage { public Guid Id { get; set; } diff --git a/src/KafkaFlow.IntegrationTests/Core/Messages/TestProtoMessage.cs b/tests/KafkaFlow.IntegrationTests/Core/Messages/TestProtoMessage.cs similarity index 100% rename from src/KafkaFlow.IntegrationTests/Core/Messages/TestProtoMessage.cs rename to tests/KafkaFlow.IntegrationTests/Core/Messages/TestProtoMessage.cs diff --git a/src/KafkaFlow.IntegrationTests/Core/Messages/logmessages2.avsc b/tests/KafkaFlow.IntegrationTests/Core/Messages/logmessages2.avsc similarity index 100% rename from src/KafkaFlow.IntegrationTests/Core/Messages/logmessages2.avsc rename to tests/KafkaFlow.IntegrationTests/Core/Messages/logmessages2.avsc diff --git a/src/KafkaFlow.IntegrationTests/Core/Middlewares/GzipMiddleware.cs b/tests/KafkaFlow.IntegrationTests/Core/Middlewares/GzipMiddleware.cs similarity index 76% rename from src/KafkaFlow.IntegrationTests/Core/Middlewares/GzipMiddleware.cs rename to tests/KafkaFlow.IntegrationTests/Core/Middlewares/GzipMiddleware.cs index 69bc10b42..027f64359 100644 --- a/src/KafkaFlow.IntegrationTests/Core/Middlewares/GzipMiddleware.cs +++ b/tests/KafkaFlow.IntegrationTests/Core/Middlewares/GzipMiddleware.cs @@ -1,10 +1,10 @@ +using System.Diagnostics; +using System.Threading.Tasks; +using KafkaFlow.IntegrationTests.Core.Handlers; +using KafkaFlow.OpenTelemetry; + namespace KafkaFlow.IntegrationTests.Core.Middlewares { - using System.Diagnostics; - using System.Threading.Tasks; - using KafkaFlow.IntegrationTests.Core.Handlers; - using KafkaFlow.OpenTelemetry; - internal class GzipMiddleware : IMessageMiddleware { public async Task Invoke(IMessageContext context, MiddlewareDelegate next) @@ -16,4 +16,4 @@ public async Task Invoke(IMessageContext context, MiddlewareDelegate next) await next(context); } } -} +} \ No newline at end of file diff --git a/src/KafkaFlow.IntegrationTests/Core/Producers/AvroProducer.cs b/tests/KafkaFlow.IntegrationTests/Core/Producers/AvroProducer.cs similarity index 100% rename from src/KafkaFlow.IntegrationTests/Core/Producers/AvroProducer.cs rename to tests/KafkaFlow.IntegrationTests/Core/Producers/AvroProducer.cs diff --git a/src/KafkaFlow.IntegrationTests/Core/Producers/ConfluentJsonProducer.cs b/tests/KafkaFlow.IntegrationTests/Core/Producers/ConfluentJsonProducer.cs similarity index 100% rename from src/KafkaFlow.IntegrationTests/Core/Producers/ConfluentJsonProducer.cs rename to tests/KafkaFlow.IntegrationTests/Core/Producers/ConfluentJsonProducer.cs diff --git a/src/KafkaFlow.IntegrationTests/Core/Producers/ConfluentProtobufProducer.cs b/tests/KafkaFlow.IntegrationTests/Core/Producers/ConfluentProtobufProducer.cs similarity index 100% rename from src/KafkaFlow.IntegrationTests/Core/Producers/ConfluentProtobufProducer.cs rename to tests/KafkaFlow.IntegrationTests/Core/Producers/ConfluentProtobufProducer.cs diff --git a/src/KafkaFlow.IntegrationTests/Core/Producers/GzipProducer.cs b/tests/KafkaFlow.IntegrationTests/Core/Producers/GzipProducer.cs similarity index 100% rename from src/KafkaFlow.IntegrationTests/Core/Producers/GzipProducer.cs rename to tests/KafkaFlow.IntegrationTests/Core/Producers/GzipProducer.cs diff --git a/src/KafkaFlow.IntegrationTests/Core/Producers/JsonGzipProducer.cs b/tests/KafkaFlow.IntegrationTests/Core/Producers/JsonGzipProducer.cs similarity index 100% rename from src/KafkaFlow.IntegrationTests/Core/Producers/JsonGzipProducer.cs rename to tests/KafkaFlow.IntegrationTests/Core/Producers/JsonGzipProducer.cs diff --git a/src/KafkaFlow.IntegrationTests/Core/Producers/JsonProducer.cs b/tests/KafkaFlow.IntegrationTests/Core/Producers/JsonProducer.cs similarity index 100% rename from src/KafkaFlow.IntegrationTests/Core/Producers/JsonProducer.cs rename to tests/KafkaFlow.IntegrationTests/Core/Producers/JsonProducer.cs diff --git a/src/KafkaFlow.IntegrationTests/Core/Producers/JsonProducer2.cs b/tests/KafkaFlow.IntegrationTests/Core/Producers/JsonProducer2.cs similarity index 100% rename from src/KafkaFlow.IntegrationTests/Core/Producers/JsonProducer2.cs rename to tests/KafkaFlow.IntegrationTests/Core/Producers/JsonProducer2.cs diff --git a/src/KafkaFlow.IntegrationTests/Core/Producers/ProtobufGzipProducer.cs b/tests/KafkaFlow.IntegrationTests/Core/Producers/ProtobufGzipProducer.cs similarity index 100% rename from src/KafkaFlow.IntegrationTests/Core/Producers/ProtobufGzipProducer.cs rename to tests/KafkaFlow.IntegrationTests/Core/Producers/ProtobufGzipProducer.cs diff --git a/src/KafkaFlow.IntegrationTests/Core/Producers/ProtobufGzipProducer2.cs b/tests/KafkaFlow.IntegrationTests/Core/Producers/ProtobufGzipProducer2.cs similarity index 100% rename from src/KafkaFlow.IntegrationTests/Core/Producers/ProtobufGzipProducer2.cs rename to tests/KafkaFlow.IntegrationTests/Core/Producers/ProtobufGzipProducer2.cs diff --git a/src/KafkaFlow.IntegrationTests/Core/Producers/ProtobufProducer.cs b/tests/KafkaFlow.IntegrationTests/Core/Producers/ProtobufProducer.cs similarity index 100% rename from src/KafkaFlow.IntegrationTests/Core/Producers/ProtobufProducer.cs rename to tests/KafkaFlow.IntegrationTests/Core/Producers/ProtobufProducer.cs diff --git a/src/KafkaFlow.IntegrationTests/Core/TraceLogHandler.cs b/tests/KafkaFlow.IntegrationTests/Core/TraceLogHandler.cs similarity index 94% rename from src/KafkaFlow.IntegrationTests/Core/TraceLogHandler.cs rename to tests/KafkaFlow.IntegrationTests/Core/TraceLogHandler.cs index 86f07fd3c..9b4eabca9 100644 --- a/src/KafkaFlow.IntegrationTests/Core/TraceLogHandler.cs +++ b/tests/KafkaFlow.IntegrationTests/Core/TraceLogHandler.cs @@ -1,9 +1,9 @@ +using System; +using System.Diagnostics; +using System.Text.Json; + namespace KafkaFlow.IntegrationTests.Core { - using System; - using System.Diagnostics; - using System.Text.Json; - internal class TraceLogHandler : ILogHandler { public void Error(string message, Exception ex, object data) diff --git a/src/KafkaFlow.IntegrationTests/GlobalEventsTest.cs b/tests/KafkaFlow.IntegrationTests/GlobalEventsTest.cs similarity index 87% rename from src/KafkaFlow.IntegrationTests/GlobalEventsTest.cs rename to tests/KafkaFlow.IntegrationTests/GlobalEventsTest.cs index c1452a340..7b5025d08 100644 --- a/src/KafkaFlow.IntegrationTests/GlobalEventsTest.cs +++ b/tests/KafkaFlow.IntegrationTests/GlobalEventsTest.cs @@ -1,36 +1,36 @@ -namespace KafkaFlow.IntegrationTests +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using AutoFixture; +using Confluent.Kafka; +using KafkaFlow.Configuration; +using KafkaFlow.IntegrationTests.Core; +using KafkaFlow.IntegrationTests.Core.Exceptions; +using KafkaFlow.IntegrationTests.Core.Handlers; +using KafkaFlow.IntegrationTests.Core.Messages; +using KafkaFlow.IntegrationTests.Core.Middlewares; +using KafkaFlow.IntegrationTests.Core.Producers; +using KafkaFlow.Serializer; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Polly; + +namespace KafkaFlow.IntegrationTests { - using System; - using System.IO; - using System.Linq; - using System.Threading.Tasks; - using AutoFixture; - using Confluent.Kafka; - using KafkaFlow.Configuration; - using KafkaFlow.IntegrationTests.Core; - using KafkaFlow.IntegrationTests.Core.Exceptions; - using KafkaFlow.IntegrationTests.Core.Handlers; - using KafkaFlow.IntegrationTests.Core.Messages; - using KafkaFlow.IntegrationTests.Core.Middlewares; - using KafkaFlow.IntegrationTests.Core.Producers; - using KafkaFlow.Serializer; - using Microsoft.Extensions.Configuration; - using Microsoft.Extensions.DependencyInjection; - using Microsoft.Extensions.Hosting; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Polly; - [TestClass] public class GlobalEventsTest { - private readonly Fixture fixture = new(); - private string topic; - private bool isPartitionAssigned; + private readonly Fixture _fixture = new(); + private string _topic; + private bool _isPartitionAssigned; [TestInitialize] public void Setup() { - this.topic = $"GlobalEventsTestTopic_{Guid.NewGuid()}"; + _topic = $"GlobalEventsTestTopic_{Guid.NewGuid()}"; MessageStorage.Clear(); } @@ -69,7 +69,7 @@ void ConfigureGlobalEvents(IGlobalEvents observers) MessageStorage.Clear(); var producer = provider.GetRequiredService>(); - var message = this.fixture.Create(); + var message = _fixture.Create(); // Act await producer.ProduceAsync(null, message); @@ -105,7 +105,7 @@ void ConfigureGlobalEvents(IGlobalEvents observers) MessageStorage.Clear(); var producer = provider.GetRequiredService>(); - var message = this.fixture.Create(); + var message = _fixture.Create(); // Act producer.Produce(message.Id.ToString(), message); @@ -150,7 +150,7 @@ void ConfigureGlobalEvents(IGlobalEvents observers) MessageStorage.Clear(); var producer = provider.GetRequiredService>(); - var message = this.fixture.Create(); + var message = _fixture.Create(); // Act await producer.ProduceAsync(null, message); @@ -191,7 +191,7 @@ void ConfigureGlobalEvents(IGlobalEvents observers) MessageStorage.Clear(); var producer = provider.GetRequiredService>(); - var message = this.fixture.Create(); + var message = _fixture.Create(); var errorOccured = false; // Act @@ -215,8 +215,8 @@ private void ConfigureConsumer(IConsumerConfigurationBuilder consumerConfigur where T : class, IMessageMiddleware { consumerConfigurationBuilder - .Topic(this.topic) - .WithGroupId(this.topic) + .Topic(_topic) + .WithGroupId(_topic) .WithBufferSize(100) .WithWorkersCount(10) .WithAutoOffsetReset(KafkaFlow.AutoOffsetReset.Earliest) @@ -226,7 +226,7 @@ private void ConfigureConsumer(IConsumerConfigurationBuilder consumerConfigur .Add()) .WithPartitionsAssignedHandler((_, _) => { - this.isPartitionAssigned = true; + _isPartitionAssigned = true; }); } @@ -234,7 +234,7 @@ private void ConfigureProducer(IProducerConfigurationBuilder producerConfigur where T : class, ISerializer { producerConfigurationBuilder - .DefaultTopic(this.topic) + .DefaultTopic(_topic) .AddMiddlewares(middlewares => middlewares.AddSerializer()); } @@ -243,7 +243,7 @@ private async Task GetServiceProviderAsync( Action consumerConfiguration, Action producerConfiguration) { - this.isPartitionAssigned = false; + _isPartitionAssigned = false; var builder = Host .CreateDefaultBuilder() @@ -265,7 +265,7 @@ private async Task GetServiceProviderAsync( .AddCluster( cluster => cluster .WithBrokers(context.Configuration.GetValue("Kafka:Brokers").Split(';')) - .CreateTopicIfNotExists(this.topic, 1, 1) + .CreateTopicIfNotExists(_topic, 1, 1) .AddProducer(producerConfiguration) .AddConsumer(consumerConfiguration)) .SubscribeGlobalEvents(configureGlobalEvents))) @@ -290,7 +290,7 @@ private async Task WaitForPartitionAssignmentAsync() await Policy .HandleResult(isAvailable => !isAvailable) .WaitAndRetryAsync(Enumerable.Range(0, 6).Select(i => TimeSpan.FromSeconds(Math.Pow(i, 2)))) - .ExecuteAsync(() => Task.FromResult(this.isPartitionAssigned)); + .ExecuteAsync(() => Task.FromResult(_isPartitionAssigned)); } private class TriggerErrorMessageMiddleware : IMessageMiddleware @@ -313,7 +313,7 @@ public Task SerializeAsync(object _, Stream output, ISerializerContext context) public Task DeserializeAsync(Stream _, Type type, ISerializerContext context) { var error = new Error(ErrorCode.BrokerNotAvailable); - throw new ProduceException(error,null); + throw new ProduceException(error, null); } } } diff --git a/src/KafkaFlow.IntegrationTests/KafkaFlow.IntegrationTests.csproj b/tests/KafkaFlow.IntegrationTests/KafkaFlow.IntegrationTests.csproj similarity index 57% rename from src/KafkaFlow.IntegrationTests/KafkaFlow.IntegrationTests.csproj rename to tests/KafkaFlow.IntegrationTests/KafkaFlow.IntegrationTests.csproj index f58a8a198..ff36e19ee 100644 --- a/src/KafkaFlow.IntegrationTests/KafkaFlow.IntegrationTests.csproj +++ b/tests/KafkaFlow.IntegrationTests/KafkaFlow.IntegrationTests.csproj @@ -30,16 +30,16 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/src/KafkaFlow.IntegrationTests/OpenTelemetryTests.cs b/tests/KafkaFlow.IntegrationTests/OpenTelemetryTests.cs similarity index 80% rename from src/KafkaFlow.IntegrationTests/OpenTelemetryTests.cs rename to tests/KafkaFlow.IntegrationTests/OpenTelemetryTests.cs index a0df1c528..54a84ff14 100644 --- a/src/KafkaFlow.IntegrationTests/OpenTelemetryTests.cs +++ b/tests/KafkaFlow.IntegrationTests/OpenTelemetryTests.cs @@ -1,41 +1,40 @@ -namespace KafkaFlow.IntegrationTests +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using AutoFixture; +using global::OpenTelemetry; +using global::OpenTelemetry.Trace; +using KafkaFlow.Compressor.Gzip; +using KafkaFlow.Configuration; +using KafkaFlow.IntegrationTests.Core; +using KafkaFlow.IntegrationTests.Core.Handlers; +using KafkaFlow.IntegrationTests.Core.Middlewares; +using KafkaFlow.IntegrationTests.Core.Producers; +using KafkaFlow.OpenTelemetry; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Polly; + +namespace KafkaFlow.IntegrationTests { - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.IO; - using System.Linq; - using System.Threading.Tasks; - using AutoFixture; - using global::OpenTelemetry; - using global::OpenTelemetry.Trace; - using KafkaFlow.Compressor; - using KafkaFlow.Compressor.Gzip; - using KafkaFlow.Configuration; - using KafkaFlow.IntegrationTests.Core; - using KafkaFlow.IntegrationTests.Core.Handlers; - using KafkaFlow.IntegrationTests.Core.Middlewares; - using KafkaFlow.IntegrationTests.Core.Producers; - using KafkaFlow.OpenTelemetry; - using Microsoft.Extensions.Configuration; - using Microsoft.Extensions.DependencyInjection; - using Microsoft.Extensions.Hosting; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Polly; - [TestClass] public class OpenTelemetryTests { - private readonly Fixture fixture = new(); + private readonly Fixture _fixture = new(); - private List exportedItems; + private List _exportedItems; - private bool isPartitionAssigned; + private bool _isPartitionAssigned; [TestInitialize] public void Setup() { - this.exportedItems = new List(); + _exportedItems = new List(); } [TestMethod] @@ -47,11 +46,11 @@ public async Task AddOpenTelemetry_ProducingAndConsumingOneMessage_TraceAndSpans using var tracerProvider = Sdk.CreateTracerProviderBuilder() .AddSource(KafkaFlowInstrumentation.ActivitySourceName) - .AddInMemoryExporter(this.exportedItems) + .AddInMemoryExporter(_exportedItems) .Build(); var producer = provider.GetRequiredService>(); - var message = this.fixture.Create(); + var message = _fixture.Create(); // Act await producer.ProduceAsync(null, message); @@ -59,7 +58,7 @@ public async Task AddOpenTelemetry_ProducingAndConsumingOneMessage_TraceAndSpans // Assert var (producerSpan, consumerSpan, internalSpan) = await this.WaitForSpansAsync(); - Assert.IsNotNull(this.exportedItems); + Assert.IsNotNull(_exportedItems); Assert.IsNull(producerSpan.ParentId); Assert.AreEqual(producerSpan.TraceId, consumerSpan.TraceId); Assert.AreEqual(consumerSpan.ParentSpanId, producerSpan.SpanId); @@ -74,11 +73,11 @@ public async Task AddOpenTelemetry_CreateActivityOnConsumingMessage_TraceIsPropa using var tracerProvider = Sdk.CreateTracerProviderBuilder() .AddSource("KafkaFlow.OpenTelemetry") - .AddInMemoryExporter(this.exportedItems) + .AddInMemoryExporter(_exportedItems) .Build(); var producer = provider.GetRequiredService>(); - var message = this.fixture.Create(); + var message = _fixture.Create(); // Act await producer.ProduceAsync(null, message); @@ -86,7 +85,7 @@ public async Task AddOpenTelemetry_CreateActivityOnConsumingMessage_TraceIsPropa // Assert var (producerSpan, consumerSpan, internalSpan) = await this.WaitForSpansAsync(); - Assert.IsNotNull(this.exportedItems); + Assert.IsNotNull(_exportedItems); Assert.IsNull(producerSpan.ParentId); Assert.AreEqual(producerSpan.TraceId, consumerSpan.TraceId); Assert.AreEqual(consumerSpan.ParentSpanId, producerSpan.SpanId); @@ -110,11 +109,11 @@ public async Task AddOpenTelemetry_ProducingAndConsumingOneMessage_BaggageIsProp using var tracerProvider = Sdk.CreateTracerProviderBuilder() .AddSource(KafkaFlowInstrumentation.ActivitySourceName) .AddSource(kafkaFlowTestString) - .AddInMemoryExporter(this.exportedItems) + .AddInMemoryExporter(_exportedItems) .Build(); var producer = provider.GetRequiredService>(); - var message = this.fixture.Create(); + var message = _fixture.Create(); // Act ActivitySource activitySource = new(kafkaFlowTestString); @@ -129,7 +128,7 @@ public async Task AddOpenTelemetry_ProducingAndConsumingOneMessage_BaggageIsProp // Assert var (producerSpan, consumerSpan, internalSpan) = await this.WaitForSpansAsync(); - Assert.IsNotNull(this.exportedItems); + Assert.IsNotNull(_exportedItems); Assert.AreEqual(producerSpan.TraceId, consumerSpan.TraceId); Assert.AreEqual(consumerSpan.ParentSpanId, producerSpan.SpanId); Assert.AreEqual(producerSpan.GetBaggageItem(baggageName1), baggageValue1); @@ -142,7 +141,7 @@ private async Task GetServiceProvider() { var topicName = $"OpenTelemetryTestTopic_{Guid.NewGuid()}"; - this.isPartitionAssigned = false; + _isPartitionAssigned = false; var builder = Host .CreateDefaultBuilder() @@ -184,7 +183,7 @@ private async Task GetServiceProvider() .Add()) .WithPartitionsAssignedHandler((_, _) => { - this.isPartitionAssigned = true; + _isPartitionAssigned = true; }))) .AddOpenTelemetryInstrumentation())) .UseDefaultServiceProvider( @@ -208,7 +207,7 @@ private async Task WaitForPartitionAssignmentAsync() await Policy .HandleResult(isAvailable => !isAvailable) .WaitAndRetryAsync(Enumerable.Range(0, 6).Select(i => TimeSpan.FromSeconds(Math.Pow(i, 2)))) - .ExecuteAsync(() => Task.FromResult(this.isPartitionAssigned)); + .ExecuteAsync(() => Task.FromResult(_isPartitionAssigned)); } private async Task<(Activity producerSpan, Activity consumerSpan, Activity internalSpan)> WaitForSpansAsync() @@ -220,9 +219,9 @@ await Policy .WaitAndRetryAsync(Enumerable.Range(0, 6).Select(i => TimeSpan.FromSeconds(Math.Pow(i, 2)))) .ExecuteAsync(() => { - producerSpan = this.exportedItems.Find(x => x.Kind == ActivityKind.Producer); - consumerSpan = this.exportedItems.Find(x => x.Kind == ActivityKind.Consumer); - internalSpan = this.exportedItems.Find(x => x.Kind == ActivityKind.Internal); + producerSpan = _exportedItems.Find(x => x.Kind == ActivityKind.Producer); + consumerSpan = _exportedItems.Find(x => x.Kind == ActivityKind.Consumer); + internalSpan = _exportedItems.Find(x => x.Kind == ActivityKind.Internal); return Task.FromResult(producerSpan != null && consumerSpan != null); }); @@ -230,4 +229,4 @@ await Policy return (producerSpan, consumerSpan, internalSpan); } } -} +} \ No newline at end of file diff --git a/tests/KafkaFlow.IntegrationTests/ProducerTest.cs b/tests/KafkaFlow.IntegrationTests/ProducerTest.cs new file mode 100644 index 000000000..c32e01213 --- /dev/null +++ b/tests/KafkaFlow.IntegrationTests/ProducerTest.cs @@ -0,0 +1,40 @@ +using System; +using System.Threading.Tasks; +using AutoFixture; +using KafkaFlow.IntegrationTests.Core; +using KafkaFlow.IntegrationTests.Core.Handlers; +using KafkaFlow.IntegrationTests.Core.Producers; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace KafkaFlow.IntegrationTests +{ + [TestClass] + public class ProducerTest + { + private readonly Fixture _fixture = new(); + + private IServiceProvider _provider; + + [TestInitialize] + public void Setup() + { + _provider = Bootstrapper.GetServiceProvider(); + MessageStorage.Clear(); + } + + [TestMethod] + public async Task ProduceNullKeyTest() + { + // Arrange + var producer = _provider.GetRequiredService>(); + var message = _fixture.Create(); + + // Act + await producer.ProduceAsync(null, message); + + // Assert + await MessageStorage.AssertMessageAsync(message); + } + } +} diff --git a/src/KafkaFlow.IntegrationTests/SerializationTest.cs b/tests/KafkaFlow.IntegrationTests/SerializationTest.cs similarity index 59% rename from src/KafkaFlow.IntegrationTests/SerializationTest.cs rename to tests/KafkaFlow.IntegrationTests/SerializationTest.cs index 39765da95..bd43d478f 100644 --- a/src/KafkaFlow.IntegrationTests/SerializationTest.cs +++ b/tests/KafkaFlow.IntegrationTests/SerializationTest.cs @@ -1,28 +1,28 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using AutoFixture; +using global::Microsoft.Extensions.DependencyInjection; +using global::Microsoft.VisualStudio.TestTools.UnitTesting; +using KafkaFlow.IntegrationTests.Core; +using KafkaFlow.IntegrationTests.Core.Handlers; +using KafkaFlow.IntegrationTests.Core.Messages; +using KafkaFlow.IntegrationTests.Core.Producers; +using MessageTypes; + namespace KafkaFlow.IntegrationTests { - using System; - using System.Linq; - using System.Threading.Tasks; - using AutoFixture; - using global::Microsoft.Extensions.DependencyInjection; - using global::Microsoft.VisualStudio.TestTools.UnitTesting; - using KafkaFlow.IntegrationTests.Core; - using KafkaFlow.IntegrationTests.Core.Handlers; - using KafkaFlow.IntegrationTests.Core.Messages; - using KafkaFlow.IntegrationTests.Core.Producers; - using MessageTypes; - [TestClass] public class SerializationTest { - private readonly Fixture fixture = new(); + private readonly Fixture _fixture = new(); - private IServiceProvider provider; + private IServiceProvider _provider; [TestInitialize] public void Setup() { - this.provider = Bootstrapper.GetServiceProvider(); + _provider = Bootstrapper.GetServiceProvider(); MessageStorage.Clear(); } @@ -30,8 +30,8 @@ public void Setup() public async Task JsonMessageTest() { // Arrange - var producer = this.provider.GetRequiredService>(); - var messages = this.fixture.CreateMany(10).ToList(); + var producer = _provider.GetRequiredService>(); + var messages = _fixture.CreateMany(10).ToList(); // Act await Task.WhenAll(messages.Select(m => producer.ProduceAsync(m.Id.ToString(), m))); @@ -47,8 +47,8 @@ public async Task JsonMessageTest() public async Task ProtobufMessageTest() { // Arrange - var producer = this.provider.GetRequiredService>(); - var messages = this.fixture.CreateMany(10).ToList(); + var producer = _provider.GetRequiredService>(); + var messages = _fixture.CreateMany(10).ToList(); // Act await Task.WhenAll(messages.Select(m => producer.ProduceAsync(m.Id.ToString(), m))); @@ -64,8 +64,8 @@ public async Task ProtobufMessageTest() public async Task AvroMessageTest() { // Arrange - var producer = this.provider.GetRequiredService>(); - var messages = this.fixture.CreateMany(10).ToList(); + var producer = _provider.GetRequiredService>(); + var messages = _fixture.CreateMany(10).ToList(); // Act await Task.WhenAll(messages.Select(m => producer.ProduceAsync(Guid.NewGuid().ToString(), m))); @@ -81,8 +81,8 @@ public async Task AvroMessageTest() public async Task ProtobufSchemaRegistryMessageTest() { // Arrange - var producer = this.provider.GetRequiredService>(); - var messages = this.fixture.CreateMany(10).ToList(); + var producer = _provider.GetRequiredService>(); + var messages = _fixture.CreateMany(10).ToList(); // Act await Task.WhenAll(messages.Select(m => producer.ProduceAsync(m.Id, m))); @@ -98,8 +98,8 @@ public async Task ProtobufSchemaRegistryMessageTest() public async Task JsonSchemaRegistryMessageTest() { // Arrange - var producer = this.provider.GetRequiredService>(); - var messages = this.fixture.CreateMany(10).ToList(); + var producer = _provider.GetRequiredService>(); + var messages = _fixture.CreateMany(10).ToList(); // Act await Task.WhenAll(messages.Select(m => producer.ProduceAsync(m.Id.ToString(), m))); diff --git a/src/KafkaFlow.IntegrationTests/conf/appsettings.json b/tests/KafkaFlow.IntegrationTests/conf/appsettings.json similarity index 100% rename from src/KafkaFlow.IntegrationTests/conf/appsettings.json rename to tests/KafkaFlow.IntegrationTests/conf/appsettings.json diff --git a/src/KafkaFlow.UnitTests/Admin.WebApi/Controllers/ConsumersControllerTests.cs b/tests/KafkaFlow.UnitTests/Admin.WebApi/Controllers/ConsumersControllerTests.cs similarity index 67% rename from src/KafkaFlow.UnitTests/Admin.WebApi/Controllers/ConsumersControllerTests.cs rename to tests/KafkaFlow.UnitTests/Admin.WebApi/Controllers/ConsumersControllerTests.cs index 25d018991..4b4bcf972 100644 --- a/src/KafkaFlow.UnitTests/Admin.WebApi/Controllers/ConsumersControllerTests.cs +++ b/tests/KafkaFlow.UnitTests/Admin.WebApi/Controllers/ConsumersControllerTests.cs @@ -1,33 +1,33 @@ -namespace KafkaFlow.UnitTests.Admin.WebApi.Controllers +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using AutoFixture; +using FluentAssertions; +using KafkaFlow.Admin; +using KafkaFlow.Admin.WebApi.Contracts; +using KafkaFlow.Admin.WebApi.Controllers; +using KafkaFlow.Consumers; +using Microsoft.AspNetCore.Mvc; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + +namespace KafkaFlow.UnitTests.Admin.WebApi.Controllers { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - using AutoFixture; - using FluentAssertions; - using KafkaFlow.Admin; - using KafkaFlow.Admin.WebApi.Contracts; - using KafkaFlow.Admin.WebApi.Controllers; - using KafkaFlow.Consumers; - using Microsoft.AspNetCore.Mvc; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; - [TestClass] public class ConsumersControllerTests { - private readonly Fixture fixture = new(); - private ConsumersController target; - private Mock mockConsumerAccessor; - private Mock mockConsumerAdmin; + private readonly Fixture _fixture = new(); + private ConsumersController _target; + private Mock _mockConsumerAccessor; + private Mock _mockConsumerAdmin; [TestInitialize] public void TestSetup() { - this.mockConsumerAccessor = this.fixture.Freeze>(); - this.mockConsumerAdmin = this.fixture.Freeze>(); - this.target = new ConsumersController(this.mockConsumerAccessor.Object, this.mockConsumerAdmin.Object); + _mockConsumerAccessor = _fixture.Freeze>(); + _mockConsumerAdmin = _fixture.Freeze>(); + _target = new ConsumersController(_mockConsumerAccessor.Object, _mockConsumerAdmin.Object); } [TestMethod] @@ -42,10 +42,10 @@ public void GetConsumersByGroupId_ValidGroupId_ReturnsOkResultWithConsumersRespo Mock.Of(c => c.GroupId == "group1" && c.ConsumerName == "consumer2"), }; - this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + _mockConsumerAccessor.Setup(x => x.All).Returns(consumers); // Act - var result = this.target.GetConsumersByGroupId(groupId) as ObjectResult; + var result = _target.GetConsumersByGroupId(groupId) as ObjectResult; // Assert result.Should().NotBeNull(); @@ -69,10 +69,10 @@ public void GetConsumerByGroupIdName_ValidGroupIdAndExistingConsumer_ReturnsOkRe Mock.Of(c => c.GroupId == "group1" && c.ConsumerName == "consumer2"), }; - this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers.AsQueryable()); + _mockConsumerAccessor.Setup(x => x.All).Returns(consumers.AsQueryable()); // Act - var result = this.target.GetConsumerByGroupIdName(groupId, consumerName) as ObjectResult; + var result = _target.GetConsumerByGroupIdName(groupId, consumerName) as ObjectResult; // Assert result.Should().NotBeNull(); @@ -91,7 +91,7 @@ public void GetConsumerByGroupIdName_ValidGroupIdAndNonExistingConsumer_ReturnsN var consumerName = "nonExistingConsumer"; // Act - var result = this.target.GetConsumerByGroupIdName(groupId, consumerName) as NotFoundResult; + var result = _target.GetConsumerByGroupIdName(groupId, consumerName) as NotFoundResult; // Assert result.Should().NotBeNull(); @@ -111,16 +111,16 @@ public async Task PauseConsumer_ValidGroupIdAndExistingConsumer_ReturnsAcceptedR Mock.Of(c => c.GroupId == groupId && c.ConsumerName == consumerName), }; - this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + _mockConsumerAccessor.Setup(x => x.All).Returns(consumers); // Act - var result = await this.target.PauseConsumer(groupId, consumerName, topics) as AcceptedResult; + var result = await _target.PauseConsumer(groupId, consumerName, topics) as AcceptedResult; // Assert result.Should().NotBeNull(); result.StatusCode.Should().Be(202); - this.mockConsumerAdmin.Verify(x => x.PauseConsumerAsync(consumerName, topics), Times.Once); + _mockConsumerAdmin.Verify(x => x.PauseConsumerAsync(consumerName, topics), Times.Once); } [TestMethod] @@ -136,10 +136,10 @@ public async Task PauseConsumer_ValidGroupIdAndNonExistingConsumer_ReturnsNotFou Mock.Of(c => c.GroupId == groupId && c.ConsumerName == "consumer2"), }; - this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + _mockConsumerAccessor.Setup(x => x.All).Returns(consumers); // Act - var result = await this.target.PauseConsumer(groupId, consumerName, topics) as NotFoundResult; + var result = await _target.PauseConsumer(groupId, consumerName, topics) as NotFoundResult; // Assert result.Should().NotBeNull(); @@ -159,16 +159,16 @@ public async Task ResumeConsumer_ValidGroupIdAndNonExistingConsumer_ReturnsNotFo Mock.Of(c => c.GroupId == groupId && c.ConsumerName == "existingConsumer"), }; - this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + _mockConsumerAccessor.Setup(x => x.All).Returns(consumers); // Act - var result = await this.target.ResumeConsumer(groupId, consumerName, topics) as NotFoundResult; + var result = await _target.ResumeConsumer(groupId, consumerName, topics) as NotFoundResult; // Assert result.Should().NotBeNull(); result.StatusCode.Should().Be(404); - this.mockConsumerAdmin.Verify(x => x.ResumeConsumerAsync(consumerName, topics), Times.Never); + _mockConsumerAdmin.Verify(x => x.ResumeConsumerAsync(consumerName, topics), Times.Never); } [TestMethod] @@ -183,16 +183,16 @@ public async Task StartConsumer_ValidGroupIdAndExistingConsumer_ReturnsAcceptedR Mock.Of(c => c.GroupId == groupId && c.ConsumerName == consumerName), }; - this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + _mockConsumerAccessor.Setup(x => x.All).Returns(consumers); // Act - var result = await this.target.StartConsumer(groupId, consumerName) as AcceptedResult; + var result = await _target.StartConsumer(groupId, consumerName) as AcceptedResult; // Assert result.Should().NotBeNull(); result.StatusCode.Should().Be(202); - this.mockConsumerAdmin.Verify(x => x.StartConsumerAsync(consumerName), Times.Once); + _mockConsumerAdmin.Verify(x => x.StartConsumerAsync(consumerName), Times.Once); } [TestMethod] @@ -207,16 +207,16 @@ public async Task StartConsumer_ValidGroupIdAndNonExistingConsumer_ReturnsNotFou Mock.Of(c => c.GroupId == groupId && c.ConsumerName == "consumer1"), }; - this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + _mockConsumerAccessor.Setup(x => x.All).Returns(consumers); // Act - var result = await this.target.StartConsumer(groupId, consumerName) as NotFoundResult; + var result = await _target.StartConsumer(groupId, consumerName) as NotFoundResult; // Assert result.Should().NotBeNull(); result.StatusCode.Should().Be(404); - this.mockConsumerAdmin.Verify(x => x.StartConsumerAsync(consumerName), Times.Never); + _mockConsumerAdmin.Verify(x => x.StartConsumerAsync(consumerName), Times.Never); } [TestMethod] @@ -231,16 +231,16 @@ public async Task StopConsumer_ValidGroupIdAndExistingConsumer_ReturnsAcceptedRe Mock.Of(c => c.GroupId == groupId && c.ConsumerName == consumerName), }; - this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + _mockConsumerAccessor.Setup(x => x.All).Returns(consumers); // Act - var result = await this.target.StopConsumer(groupId, consumerName) as AcceptedResult; + var result = await _target.StopConsumer(groupId, consumerName) as AcceptedResult; // Assert result.Should().NotBeNull(); result.StatusCode.Should().Be(202); - this.mockConsumerAdmin.Verify(x => x.StopConsumerAsync(consumerName), Times.Once); + _mockConsumerAdmin.Verify(x => x.StopConsumerAsync(consumerName), Times.Once); } [TestMethod] @@ -255,16 +255,16 @@ public async Task StopConsumer_ValidGroupIdAndNonExistingConsumer_ReturnsNotFoun Mock.Of(c => c.GroupId == groupId && c.ConsumerName == "consumer1"), }; - this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + _mockConsumerAccessor.Setup(x => x.All).Returns(consumers); // Act - var result = await this.target.StopConsumer(groupId, consumerName) as NotFoundResult; + var result = await _target.StopConsumer(groupId, consumerName) as NotFoundResult; // Assert result.Should().NotBeNull(); result.StatusCode.Should().Be(404); - this.mockConsumerAdmin.Verify(x => x.StopConsumerAsync(consumerName), Times.Never); + _mockConsumerAdmin.Verify(x => x.StopConsumerAsync(consumerName), Times.Never); } [TestMethod] @@ -279,16 +279,16 @@ public async Task RestartConsumer_ValidGroupIdAndExistingConsumer_ReturnsAccepte Mock.Of(c => c.GroupId == groupId && c.ConsumerName == consumerName), }; - this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + _mockConsumerAccessor.Setup(x => x.All).Returns(consumers); // Act - var result = await this.target.RestartConsumer(groupId, consumerName) as AcceptedResult; + var result = await _target.RestartConsumer(groupId, consumerName) as AcceptedResult; // Assert result.Should().NotBeNull(); result.StatusCode.Should().Be(202); - this.mockConsumerAdmin.Verify(x => x.RestartConsumerAsync(consumerName), Times.Once); + _mockConsumerAdmin.Verify(x => x.RestartConsumerAsync(consumerName), Times.Once); } [TestMethod] @@ -303,16 +303,16 @@ public async Task RestartConsumer_ValidGroupIdAndNonExistingConsumer_ReturnsNotF Mock.Of(c => c.GroupId == groupId && c.ConsumerName == "consumer1"), }; - this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + _mockConsumerAccessor.Setup(x => x.All).Returns(consumers); // Act - var result = await this.target.RestartConsumer(groupId, consumerName) as NotFoundResult; + var result = await _target.RestartConsumer(groupId, consumerName) as NotFoundResult; // Assert result.Should().NotBeNull(); result.StatusCode.Should().Be(404); - this.mockConsumerAdmin.Verify(x => x.StopConsumerAsync(consumerName), Times.Never); + _mockConsumerAdmin.Verify(x => x.StopConsumerAsync(consumerName), Times.Never); } [TestMethod] @@ -329,16 +329,16 @@ public async Task ResetOffsets_ValidRequest_ReturnsAcceptedResult() Mock.Of(c => c.GroupId == groupId && c.ConsumerName == consumerName), }; - this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + _mockConsumerAccessor.Setup(x => x.All).Returns(consumers); // Act - var result = await this.target.ResetOffsets(groupId, consumerName, topics, request) as AcceptedResult; + var result = await _target.ResetOffsets(groupId, consumerName, topics, request) as AcceptedResult; // Assert result.Should().NotBeNull(); result.StatusCode.Should().Be(202); - this.mockConsumerAdmin.Verify(x => x.ResetOffsetsAsync(consumerName, topics), Times.Once); + _mockConsumerAdmin.Verify(x => x.ResetOffsetsAsync(consumerName, topics), Times.Once); } [TestMethod] @@ -355,16 +355,16 @@ public async Task ResetOffsets_InvalidConfirmValue_ReturnsBadRequestResult() Mock.Of(c => c.GroupId == groupId && c.ConsumerName == consumerName), }; - this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + _mockConsumerAccessor.Setup(x => x.All).Returns(consumers); // Act - var result = await this.target.ResetOffsets(groupId, consumerName, topics, request) as BadRequestResult; + var result = await _target.ResetOffsets(groupId, consumerName, topics, request) as BadRequestResult; // Assert result.Should().NotBeNull(); result.StatusCode.Should().Be(400); - this.mockConsumerAdmin.Verify(x => x.ResetOffsetsAsync(consumerName, topics), Times.Never); + _mockConsumerAdmin.Verify(x => x.ResetOffsetsAsync(consumerName, topics), Times.Never); } [TestMethod] @@ -374,23 +374,23 @@ public async Task RewindOffsets_ValidGroupIdAndNonExistingConsumer_ReturnsNotFou var groupId = "group1"; var consumerName = "nonExistingConsumer"; var topics = new List { "topic1", "topic2" }; - var request = new RewindOffsetsToDateRequest { Date = this.fixture.Create() }; + var request = new RewindOffsetsToDateRequest { Date = _fixture.Create() }; var consumers = new List { Mock.Of(c => c.GroupId == groupId && c.ConsumerName == "consumer1"), }; - this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + _mockConsumerAccessor.Setup(x => x.All).Returns(consumers); // Act - var result = await this.target.RewindOffsets(groupId, consumerName, topics, request) as NotFoundResult; + var result = await _target.RewindOffsets(groupId, consumerName, topics, request) as NotFoundResult; // Assert result.Should().NotBeNull(); result.StatusCode.Should().Be(404); - this.mockConsumerAdmin.Verify(x => x.RewindOffsetsAsync(consumerName, request.Date, topics), Times.Never); + _mockConsumerAdmin.Verify(x => x.RewindOffsetsAsync(consumerName, request.Date, topics), Times.Never); } [TestMethod] @@ -400,23 +400,23 @@ public async Task RewindOffsets_ValidRequest_ReturnsAcceptedResult() var groupId = "group1"; var consumerName = "consumer1"; var topics = new List { "topic1", "topic2" }; - var request = new RewindOffsetsToDateRequest { Date = this.fixture.Create() }; + var request = new RewindOffsetsToDateRequest { Date = _fixture.Create() }; var consumers = new List { Mock.Of(c => c.GroupId == groupId && c.ConsumerName == consumerName), }; - this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + _mockConsumerAccessor.Setup(x => x.All).Returns(consumers); // Act - var result = await this.target.RewindOffsets(groupId, consumerName, topics, request) as AcceptedResult; + var result = await _target.RewindOffsets(groupId, consumerName, topics, request) as AcceptedResult; // Assert result.Should().NotBeNull(); result.StatusCode.Should().Be(202); - this.mockConsumerAdmin.Verify(x => x.RewindOffsetsAsync(consumerName, request.Date, topics), Times.Once); + _mockConsumerAdmin.Verify(x => x.RewindOffsetsAsync(consumerName, request.Date, topics), Times.Once); } [TestMethod] @@ -429,13 +429,13 @@ public async Task RewindOffsets_InvalidRequest_ReturnsBadRequestResult() RewindOffsetsToDateRequest request = null; // Act - var result = await this.target.RewindOffsets(groupId, consumerName, topics, request) as BadRequestResult; + var result = await _target.RewindOffsets(groupId, consumerName, topics, request) as BadRequestResult; // Assert result.Should().NotBeNull(); result.StatusCode.Should().Be(400); - this.mockConsumerAdmin.Verify(x => x.RewindOffsetsAsync(consumerName, It.IsAny(), topics), Times.Never); + _mockConsumerAdmin.Verify(x => x.RewindOffsetsAsync(consumerName, It.IsAny(), topics), Times.Never); } [TestMethod] @@ -445,23 +445,23 @@ public async Task ChangeWorkersCount_ValidRequest_ReturnsAcceptedResult() var groupId = "group1"; var consumerName = "consumer1"; var topics = new List { "topic1", "topic2" }; - var request = new RewindOffsetsToDateRequest { Date = this.fixture.Create() }; + var request = new RewindOffsetsToDateRequest { Date = _fixture.Create() }; var consumers = new List { Mock.Of(c => c.GroupId == groupId && c.ConsumerName == consumerName), }; - this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + _mockConsumerAccessor.Setup(x => x.All).Returns(consumers); // Act - var result = await this.target.RewindOffsets(groupId, consumerName, topics, request) as AcceptedResult; + var result = await _target.RewindOffsets(groupId, consumerName, topics, request) as AcceptedResult; // Assert result.Should().NotBeNull(); result.StatusCode.Should().Be(202); - this.mockConsumerAdmin.Verify(x => x.RewindOffsetsAsync(consumerName, request.Date, topics), Times.Once); + _mockConsumerAdmin.Verify(x => x.RewindOffsetsAsync(consumerName, request.Date, topics), Times.Once); } [TestMethod] @@ -473,13 +473,13 @@ public async Task ChangeWorkersCount_NullRequest_ReturnsBadRequestResult() ChangeWorkersCountRequest request = null; // Act - var result = await this.target.ChangeWorkersCount(groupId, consumerName, request) as BadRequestResult; + var result = await _target.ChangeWorkersCount(groupId, consumerName, request) as BadRequestResult; // Assert result.Should().NotBeNull(); result.StatusCode.Should().Be(400); - this.mockConsumerAdmin.Verify(x => x.ChangeWorkersCountAsync(consumerName, It.IsAny()), Times.Never); + _mockConsumerAdmin.Verify(x => x.ChangeWorkersCountAsync(consumerName, It.IsAny()), Times.Never); } [DataRow(0)] @@ -494,13 +494,13 @@ public async Task ChangeWorkersCount_InvalidWorkerCount_ReturnsBadRequestResult( ChangeWorkersCountRequest request = new ChangeWorkersCountRequest { WorkersCount = workerCount }; // Act - var result = await this.target.ChangeWorkersCount(groupId, consumerName, request) as BadRequestResult; + var result = await _target.ChangeWorkersCount(groupId, consumerName, request) as BadRequestResult; // Assert result.Should().NotBeNull(); result.StatusCode.Should().Be(400); - this.mockConsumerAdmin.Verify(x => x.ChangeWorkersCountAsync(consumerName, It.IsAny()), Times.Never); + _mockConsumerAdmin.Verify(x => x.ChangeWorkersCountAsync(consumerName, It.IsAny()), Times.Never); } } } diff --git a/src/KafkaFlow.UnitTests/Admin.WebApi/Controllers/GroupsControllerTests.cs b/tests/KafkaFlow.UnitTests/Admin.WebApi/Controllers/GroupsControllerTests.cs similarity index 51% rename from src/KafkaFlow.UnitTests/Admin.WebApi/Controllers/GroupsControllerTests.cs rename to tests/KafkaFlow.UnitTests/Admin.WebApi/Controllers/GroupsControllerTests.cs index 91bbcdf18..75e2bd940 100644 --- a/src/KafkaFlow.UnitTests/Admin.WebApi/Controllers/GroupsControllerTests.cs +++ b/tests/KafkaFlow.UnitTests/Admin.WebApi/Controllers/GroupsControllerTests.cs @@ -1,32 +1,32 @@ -namespace KafkaFlow.UnitTests.Admin.WebApi.Controllers -{ - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - using AutoFixture; - using FluentAssertions; - using KafkaFlow.Admin; - using KafkaFlow.Admin.WebApi.Contracts; - using KafkaFlow.Admin.WebApi.Controllers; - using KafkaFlow.Consumers; - using Microsoft.AspNetCore.Mvc; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using AutoFixture; +using FluentAssertions; +using KafkaFlow.Admin; +using KafkaFlow.Admin.WebApi.Contracts; +using KafkaFlow.Admin.WebApi.Controllers; +using KafkaFlow.Consumers; +using Microsoft.AspNetCore.Mvc; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +namespace KafkaFlow.UnitTests.Admin.WebApi.Controllers +{ [TestClass] public class GroupsControllerTests { - private readonly Fixture fixture = new(); - private GroupsController target; - private Mock mockConsumerAccessor; - private Mock mockConsumerAdmin; + private readonly Fixture _fixture = new(); + private GroupsController _target; + private Mock _mockConsumerAccessor; + private Mock _mockConsumerAdmin; [TestInitialize] public void TestSetup() { - this.mockConsumerAccessor = this.fixture.Freeze>(); - this.mockConsumerAdmin = this.fixture.Freeze>(); - this.target = new GroupsController(this.mockConsumerAccessor.Object, this.mockConsumerAdmin.Object); + _mockConsumerAccessor = _fixture.Freeze>(); + _mockConsumerAdmin = _fixture.Freeze>(); + _target = new GroupsController(_mockConsumerAccessor.Object, _mockConsumerAdmin.Object); } [TestMethod] @@ -40,10 +40,10 @@ public void GetAllGroups_ReturnsOkResultWithGroupsResponse() Mock.Of(), }; - this.mockConsumerAccessor.Setup(x => x.All).Returns(consumers); + _mockConsumerAccessor.Setup(x => x.All).Returns(consumers); // Act - var result = this.target.GetAllGroups() as ObjectResult; + var result = _target.GetAllGroups() as ObjectResult; // Assert result.Should().NotBeNull(); @@ -62,13 +62,13 @@ public async Task PauseGroup_ValidGroupId_ReturnsAcceptedResult() var topics = new List { "topic1", "topic2" }; // Act - var result = await this.target.PauseGroup(groupId, topics) as AcceptedResult; + var result = await _target.PauseGroup(groupId, topics) as AcceptedResult; // Assert result.Should().NotBeNull(); result.StatusCode.Should().Be(202); - this.mockConsumerAdmin.Verify(x => x.PauseConsumerGroupAsync(groupId, topics), Times.Once); + _mockConsumerAdmin.Verify(x => x.PauseConsumerGroupAsync(groupId, topics), Times.Once); } [TestMethod] @@ -79,13 +79,13 @@ public async Task ResumeGroup_ValidGroupId_ReturnsAcceptedResult() var topics = new List { "topic1", "topic2" }; // Act - var result = await this.target.ResumeGroup(groupId, topics) as AcceptedResult; + var result = await _target.ResumeGroup(groupId, topics) as AcceptedResult; // Assert result.Should().NotBeNull(); result.StatusCode.Should().Be(202); - this.mockConsumerAdmin.Verify(x => x.ResumeConsumerGroupAsync(groupId, topics), Times.Once); + _mockConsumerAdmin.Verify(x => x.ResumeConsumerGroupAsync(groupId, topics), Times.Once); } } } diff --git a/src/KafkaFlow.UnitTests/Admin.WebApi/Controllers/TelemetryControllerTests.cs b/tests/KafkaFlow.UnitTests/Admin.WebApi/Controllers/TelemetryControllerTests.cs similarity index 83% rename from src/KafkaFlow.UnitTests/Admin.WebApi/Controllers/TelemetryControllerTests.cs rename to tests/KafkaFlow.UnitTests/Admin.WebApi/Controllers/TelemetryControllerTests.cs index 0a9d2bd0c..f801c6325 100644 --- a/src/KafkaFlow.UnitTests/Admin.WebApi/Controllers/TelemetryControllerTests.cs +++ b/tests/KafkaFlow.UnitTests/Admin.WebApi/Controllers/TelemetryControllerTests.cs @@ -1,35 +1,35 @@ -namespace KafkaFlow.UnitTests.Admin.WebApi.Controllers -{ - using System; - using System.Collections.Generic; - using System.Linq; - using FluentAssertions; - using KafkaFlow.Admin; - using KafkaFlow.Admin.Messages; - using KafkaFlow.Admin.WebApi.Contracts; - using KafkaFlow.Admin.WebApi.Controllers; - using KafkaFlow.Consumers; - using Microsoft.AspNetCore.Mvc; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; +using System; +using System.Collections.Generic; +using System.Linq; +using FluentAssertions; +using KafkaFlow.Admin; +using KafkaFlow.Admin.Messages; +using KafkaFlow.Admin.WebApi.Contracts; +using KafkaFlow.Admin.WebApi.Controllers; +using KafkaFlow.Consumers; +using Microsoft.AspNetCore.Mvc; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +namespace KafkaFlow.UnitTests.Admin.WebApi.Controllers +{ [TestClass] public class TelemetryControllerTests { - private Mock mockTelemetryStorage; - private TelemetryController target; + private Mock _mockTelemetryStorage; + private TelemetryController _target; [TestInitialize] public void TestInitialize() { - this.mockTelemetryStorage = new Mock(); - this.target = new TelemetryController(this.mockTelemetryStorage.Object); + _mockTelemetryStorage = new Mock(); + _target = new TelemetryController(_mockTelemetryStorage.Object); } [TestMethod] public void GetTelemetry_ReturnsOkResultWithTelemetryResponse() { - // Arrange + // Arrange var metrics = new List { new ConsumerTelemetryMetric @@ -73,10 +73,10 @@ public void GetTelemetry_ReturnsOkResultWithTelemetryResponse() }, }; - this.mockTelemetryStorage.Setup(x => x.Get()).Returns(metrics); + _mockTelemetryStorage.Setup(x => x.Get()).Returns(metrics); // Act - var result = this.target.GetTelemetry() as ObjectResult; + var result = _target.GetTelemetry() as ObjectResult; // Assert result.Should().NotBeNull(); diff --git a/src/KafkaFlow.UnitTests/BatchConsume/BatchConsumeMiddlewareTests.cs b/tests/KafkaFlow.UnitTests/BatchConsume/BatchConsumeMiddlewareTests.cs similarity index 64% rename from src/KafkaFlow.UnitTests/BatchConsume/BatchConsumeMiddlewareTests.cs rename to tests/KafkaFlow.UnitTests/BatchConsume/BatchConsumeMiddlewareTests.cs index 0f8b27be7..acca249c9 100644 --- a/src/KafkaFlow.UnitTests/BatchConsume/BatchConsumeMiddlewareTests.cs +++ b/tests/KafkaFlow.UnitTests/BatchConsume/BatchConsumeMiddlewareTests.cs @@ -1,46 +1,45 @@ +using System; +using System.Threading.Tasks; +using AutoFixture; +using FluentAssertions; +using KafkaFlow.Batching; +using KafkaFlow.Configuration; +using KafkaFlow.Consumers; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + namespace KafkaFlow.UnitTests.BatchConsume { - using System; - using System.Collections.Generic; - using System.Threading.Tasks; - using AutoFixture; - using FluentAssertions; - using KafkaFlow.Batching; - using KafkaFlow.Configuration; - using KafkaFlow.Consumers; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; - [TestClass] public class BatchConsumeMiddlewareTests { private const int BatchSize = 3; - private readonly TimeSpan batchTimeout = TimeSpan.FromMilliseconds(1000); - private readonly TimeSpan waitForTaskExecution = TimeSpan.FromMilliseconds(100); - private readonly Fixture fixture = new(); + private readonly TimeSpan _batchTimeout = TimeSpan.FromMilliseconds(1000); + private readonly TimeSpan _waitForTaskExecution = TimeSpan.FromMilliseconds(100); + private readonly Fixture _fixture = new(); - private Mock logHandlerMock; + private Mock _logHandlerMock; - private IMessageContext nextContext; - private int timesNextWasCalled; + private IMessageContext _nextContext; + private int _timesNextWasCalled; - private BatchConsumeMiddleware target; + private BatchConsumeMiddleware _target; [TestInitialize] public void Setup() { - this.nextContext = null; - this.timesNextWasCalled = 0; + _nextContext = null; + _timesNextWasCalled = 0; - this.logHandlerMock = new Mock(); + _logHandlerMock = new Mock(); var middlewareContextMock = new Mock(); var workerMock = new Mock(); var consumerMock = new Mock(); var consumerConfigurationMock = new Mock(); - var clusterConfig = this.fixture.Create(); + var clusterConfig = _fixture.Create(); consumerConfigurationMock.SetupGet(x => x.ClusterConfiguration).Returns(clusterConfig); @@ -58,17 +57,17 @@ public void Setup() workerMock .SetupGet(x => x.WorkerStopped) - .Returns(new Event(this.logHandlerMock.Object)); + .Returns(new Event(_logHandlerMock.Object)); consumerConfigurationMock .SetupGet(x => x.AutoMessageCompletion) .Returns(true); - this.target = new BatchConsumeMiddleware( + _target = new BatchConsumeMiddleware( middlewareContextMock.Object, BatchSize, - this.batchTimeout, - this.logHandlerMock.Object); + _batchTimeout, + _logHandlerMock.Object); } [TestMethod] @@ -87,12 +86,12 @@ public async Task AddAsync_LessThanBatchSize_CallNextOnTimeout() .Returns(consumerContext.Object); // Act - await this.target.Invoke(context.Object, this.NextCallback); + await _target.Invoke(context.Object, this.NextCallback); // Assert - this.timesNextWasCalled.Should().Be(0); + _timesNextWasCalled.Should().Be(0); await this.WaitBatchTimeoutAsync(); - this.timesNextWasCalled.Should().Be(1); + _timesNextWasCalled.Should().Be(1); consumerContext.Verify(x => x.Complete(), Times.Once); } @@ -114,14 +113,14 @@ public async Task AddAsync_ExactlyBatchSize_CallNextInstantly() // Act for (var i = 0; i < BatchSize; i++) { - await this.target.Invoke(contextMock.Object, this.NextCallback); + await _target.Invoke(contextMock.Object, this.NextCallback); } - await Task.Delay(this.waitForTaskExecution); + await Task.Delay(_waitForTaskExecution); // Assert - this.timesNextWasCalled.Should().Be(1); - this.nextContext.GetMessagesBatch().Should().HaveCount(BatchSize); + _timesNextWasCalled.Should().Be(1); + _nextContext.GetMessagesBatch().Should().HaveCount(BatchSize); consumerContext.Verify(x => x.Complete(), Times.Exactly(BatchSize)); } @@ -143,18 +142,18 @@ public async Task AddAsync_MoreThanBatchSize_CallNextInstantlyThenCallWhenTimeou // Act for (var i = 0; i < BatchSize + 1; i++) { - await this.target.Invoke(contextMock.Object, this.NextCallback); + await _target.Invoke(contextMock.Object, this.NextCallback); } - await Task.Delay(this.waitForTaskExecution); + await Task.Delay(_waitForTaskExecution); // Assert - this.timesNextWasCalled.Should().Be(1); - this.nextContext.GetMessagesBatch().Should().HaveCount(BatchSize); + _timesNextWasCalled.Should().Be(1); + _nextContext.GetMessagesBatch().Should().HaveCount(BatchSize); consumerContext.Verify(x => x.Complete(), Times.Exactly(BatchSize)); await this.WaitBatchTimeoutAsync(); - this.timesNextWasCalled.Should().Be(2); + _timesNextWasCalled.Should().Be(2); consumerContext.Verify(x => x.Complete(), Times.Exactly(BatchSize + 1)); } @@ -170,19 +169,19 @@ public async Task AddAsync_NextThrowException_LogError() .Returns(consumerContext.Object); // Act - await this.target.Invoke(contextMock.Object, _ => throw new Exception()); + await _target.Invoke(contextMock.Object, _ => throw new Exception()); // Assert await this.WaitBatchTimeoutAsync(); - this.logHandlerMock.Verify(x => x.Error(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + _logHandlerMock.Verify(x => x.Error(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); } - private Task WaitBatchTimeoutAsync() => Task.Delay(this.batchTimeout + this.waitForTaskExecution); + private Task WaitBatchTimeoutAsync() => Task.Delay(_batchTimeout + _waitForTaskExecution); private Task NextCallback(IMessageContext ctx) { - this.nextContext = ctx; - this.timesNextWasCalled++; + _nextContext = ctx; + _timesNextWasCalled++; return Task.CompletedTask; } } diff --git a/src/KafkaFlow.UnitTests/Compressors/CompressorConsumerMiddlewareTests.cs b/tests/KafkaFlow.UnitTests/Compressors/CompressorConsumerMiddlewareTests.cs similarity index 54% rename from src/KafkaFlow.UnitTests/Compressors/CompressorConsumerMiddlewareTests.cs rename to tests/KafkaFlow.UnitTests/Compressors/CompressorConsumerMiddlewareTests.cs index 57ced96cb..1e79dd6db 100644 --- a/src/KafkaFlow.UnitTests/Compressors/CompressorConsumerMiddlewareTests.cs +++ b/tests/KafkaFlow.UnitTests/Compressors/CompressorConsumerMiddlewareTests.cs @@ -1,46 +1,46 @@ -namespace KafkaFlow.UnitTests.Compressors -{ - using System; - using System.Threading.Tasks; - using FluentAssertions; +using System; +using System.Threading.Tasks; +using FluentAssertions; - using KafkaFlow.Middlewares.Compressor; +using KafkaFlow.Middlewares.Compressor; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +namespace KafkaFlow.UnitTests.Compressors +{ [TestClass] public class CompressorConsumerMiddlewareTests { - private Mock contextMock; - private Mock decompressorMock; - private bool nextCalled; - private DecompressorConsumerMiddleware target; + private Mock _contextMock; + private Mock _decompressorMock; + private bool _nextCalled; + private DecompressorConsumerMiddleware _target; [TestInitialize] public void Setup() { - this.contextMock = new Mock(); - this.decompressorMock = new Mock(); - this.target = new DecompressorConsumerMiddleware(this.decompressorMock.Object); + _contextMock = new Mock(); + _decompressorMock = new Mock(); + _target = new DecompressorConsumerMiddleware(_decompressorMock.Object); } [TestMethod] public void Invoke_NotByteArrayMessage_ThrowsInvalidOperationException() { // Arrange - this.contextMock + _contextMock .SetupGet(x => x.Message) .Returns(new Message(new object(), new object())); // Act - Func act = () => this.target.Invoke(this.contextMock.Object, _ => this.SetNextCalled()); + Func act = () => _target.Invoke(_contextMock.Object, _ => this.SetNextCalled()); // Assert act.Should().Throw(); - this.nextCalled.Should().BeFalse(); - this.contextMock.Verify(x => x.SetMessage(It.IsAny(), It.IsAny()), Times.Never); - this.decompressorMock.Verify(x => x.Decompress(It.IsAny()), Times.Never); + _nextCalled.Should().BeFalse(); + _contextMock.Verify(x => x.SetMessage(It.IsAny(), It.IsAny()), Times.Never); + _decompressorMock.Verify(x => x.Decompress(It.IsAny()), Times.Never); } [TestMethod] @@ -53,21 +53,21 @@ public async Task Invoke_ValidMessage_CallNext() var transformedContextMock = new Mock(); IMessageContext resultContext = null; - this.contextMock + _contextMock .SetupGet(x => x.Message) .Returns(compressedMessage); - this.decompressorMock - .Setup(x => x.Decompress((byte[]) compressedMessage.Value)) + _decompressorMock + .Setup(x => x.Decompress((byte[])compressedMessage.Value)) .Returns(uncompressedValue); - this.contextMock + _contextMock .Setup(x => x.SetMessage(compressedMessage.Key, uncompressedValue)) .Returns(transformedContextMock.Object); // Act - await this.target.Invoke( - this.contextMock.Object, + await _target.Invoke( + _contextMock.Object, ctx => { resultContext = ctx; @@ -77,13 +77,13 @@ await this.target.Invoke( // Assert resultContext.Should().NotBeNull(); resultContext.Should().Be(transformedContextMock.Object); - this.contextMock.VerifyAll(); - this.decompressorMock.VerifyAll(); + _contextMock.VerifyAll(); + _decompressorMock.VerifyAll(); } private Task SetNextCalled() { - this.nextCalled = true; + _nextCalled = true; return Task.CompletedTask; } } diff --git a/src/KafkaFlow.UnitTests/Compressors/CompressorProducerMiddlewareTests.cs b/tests/KafkaFlow.UnitTests/Compressors/CompressorProducerMiddlewareTests.cs similarity index 62% rename from src/KafkaFlow.UnitTests/Compressors/CompressorProducerMiddlewareTests.cs rename to tests/KafkaFlow.UnitTests/Compressors/CompressorProducerMiddlewareTests.cs index 24c41eed2..448a6a7e9 100644 --- a/src/KafkaFlow.UnitTests/Compressors/CompressorProducerMiddlewareTests.cs +++ b/tests/KafkaFlow.UnitTests/Compressors/CompressorProducerMiddlewareTests.cs @@ -1,29 +1,29 @@ -namespace KafkaFlow.UnitTests.Compressors -{ - using System; - using System.Threading.Tasks; - using FluentAssertions; +using System; +using System.Threading.Tasks; +using FluentAssertions; - using KafkaFlow.Middlewares.Compressor; +using KafkaFlow.Middlewares.Compressor; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +namespace KafkaFlow.UnitTests.Compressors +{ [TestClass] public class CompressorProducerMiddlewareTests { - private Mock contextMock; - private Mock compressorMock; + private Mock _contextMock; + private Mock _compressorMock; - private CompressorProducerMiddleware target; + private CompressorProducerMiddleware _target; [TestInitialize] public void Setup() { - this.contextMock = new Mock(); - this.compressorMock = new Mock(); + _contextMock = new Mock(); + _compressorMock = new Mock(); - this.target = new CompressorProducerMiddleware(this.compressorMock.Object); + _target = new CompressorProducerMiddleware(_compressorMock.Object); } [TestMethod] @@ -33,13 +33,13 @@ public async Task Invoke_InvalidMessage_Throws() var uncompressedMessage = new Message(new byte[1], new object()); IMessageContext resultContext = null; - this.contextMock + _contextMock .SetupGet(x => x.Message) .Returns(uncompressedMessage); // Act - Func act = () => this.target.Invoke( - this.contextMock.Object, + Func act = () => _target.Invoke( + _contextMock.Object, ctx => { resultContext = ctx; @@ -49,8 +49,8 @@ public async Task Invoke_InvalidMessage_Throws() // Assert await act.Should().ThrowAsync(); resultContext.Should().BeNull(); - this.contextMock.Verify(x => x.SetMessage(It.IsAny(), It.IsAny()), Times.Never); - this.compressorMock.Verify(x => x.Compress(It.IsAny()), Times.Never); + _contextMock.Verify(x => x.SetMessage(It.IsAny(), It.IsAny()), Times.Never); + _compressorMock.Verify(x => x.Compress(It.IsAny()), Times.Never); } [TestMethod] @@ -64,21 +64,21 @@ public async Task Invoke_ValidMessage_Compress() var transformedContextMock = new Mock(); IMessageContext resultContext = null; - this.contextMock + _contextMock .SetupGet(x => x.Message) .Returns(uncompressedMessage); - this.compressorMock + _compressorMock .Setup(x => x.Compress(uncompressedValue)) .Returns(compressedValue); - this.contextMock + _contextMock .Setup(x => x.SetMessage(uncompressedMessage.Key, compressedValue)) .Returns(transformedContextMock.Object); // Act - await this.target.Invoke( - this.contextMock.Object, + await _target.Invoke( + _contextMock.Object, ctx => { resultContext = ctx; @@ -88,8 +88,8 @@ await this.target.Invoke( // Assert resultContext.Should().NotBeNull(); resultContext.Should().Be(transformedContextMock.Object); - this.contextMock.VerifyAll(); - this.compressorMock.VerifyAll(); + _contextMock.VerifyAll(); + _compressorMock.VerifyAll(); } } } diff --git a/src/KafkaFlow.UnitTests/ConfigurationBuilders/ConsumerConfigurationBuilderTests.cs b/tests/KafkaFlow.UnitTests/ConfigurationBuilders/ConsumerConfigurationBuilderTests.cs similarity index 72% rename from src/KafkaFlow.UnitTests/ConfigurationBuilders/ConsumerConfigurationBuilderTests.cs rename to tests/KafkaFlow.UnitTests/ConfigurationBuilders/ConsumerConfigurationBuilderTests.cs index 88efc9d1f..fe60be91d 100644 --- a/src/KafkaFlow.UnitTests/ConfigurationBuilders/ConsumerConfigurationBuilderTests.cs +++ b/tests/KafkaFlow.UnitTests/ConfigurationBuilders/ConsumerConfigurationBuilderTests.cs @@ -1,57 +1,55 @@ +using System; +using System.Collections.Generic; +using AutoFixture; +using FluentAssertions; +using KafkaFlow.Configuration; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + namespace KafkaFlow.UnitTests.ConfigurationBuilders { - using System; - using System.Collections.Generic; - using AutoFixture; - using Confluent.Kafka; - using FluentAssertions; - using KafkaFlow.Configuration; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; - using AutoOffsetReset = KafkaFlow.AutoOffsetReset; - [TestClass] public class ConsumerConfigurationBuilderTests { - private readonly Fixture fixture = new(); + private readonly Fixture _fixture = new(); - private Mock dependencyConfiguratorMock; + private Mock _dependencyConfiguratorMock; - private ConsumerConfigurationBuilder target; + private ConsumerConfigurationBuilder _target; [TestInitialize] public void Setup() { - this.dependencyConfiguratorMock = new Mock(); + _dependencyConfiguratorMock = new Mock(); - this.target = new ConsumerConfigurationBuilder(this.dependencyConfiguratorMock.Object); + _target = new ConsumerConfigurationBuilder(_dependencyConfiguratorMock.Object); } [TestMethod] public void DependencyConfigurator_SetProperty_ReturnPassedInstance() { // Assert - this.target.DependencyConfigurator.Should().Be(this.dependencyConfiguratorMock.Object); + _target.DependencyConfigurator.Should().Be(_dependencyConfiguratorMock.Object); } [TestMethod] public void Build_RequiredCalls_ReturnDefaultValues() { // Arrange - var clusterConfiguration = this.fixture.Create(); - var topic1 = this.fixture.Create(); + var clusterConfiguration = _fixture.Create(); + var topic1 = _fixture.Create(); const int bufferSize = 100; const int workers = 10; - var groupId = this.fixture.Create(); + var groupId = _fixture.Create(); - this.target + _target .Topics(topic1) .WithBufferSize(bufferSize) .WithWorkersCount(workers) .WithGroupId(groupId); // Act - var configuration = this.target.Build(clusterConfiguration); + var configuration = _target.Build(clusterConfiguration); // Assert configuration.Topics.Should().BeEquivalentTo(topic1); @@ -73,27 +71,27 @@ public void Build_RequiredCalls_ReturnDefaultValues() public void Build_AllCalls_ReturnPassedValues() { // Arrange - var clusterConfiguration = this.fixture.Create(); - var topic1 = this.fixture.Create(); - var topic2 = this.fixture.Create(); - var name = this.fixture.Create(); + var clusterConfiguration = _fixture.Create(); + var topic1 = _fixture.Create(); + var topic2 = _fixture.Create(); + var name = _fixture.Create(); const int bufferSize = 100; const int workers = 10; const AutoOffsetReset offsetReset = AutoOffsetReset.Earliest; - var groupId = this.fixture.Create(); + var groupId = _fixture.Create(); const int autoCommitInterval = 10000; const int maxPollIntervalMs = 500000; ConsumerCustomFactory customFactory = (producer, _) => producer; Action statisticsHandler = _ => { }; - Action> partitionsAssignedHandler = (_, _) => { }; - Action> partitionsRevokedHandler = (_, _) => { }; + Action> partitionsAssignedHandler = (_, _) => { }; + Action> partitionsRevokedHandler = (_, _) => { }; const int statisticsIntervalMs = 100; - var consumerConfig = new ConsumerConfig + var consumerConfig = new Confluent.Kafka.ConsumerConfig { - ClientId = "testeclient" + ClientId = "testeclient", }; - this.target + _target .Topics(topic1) .Topic(topic2) .WithName(name) @@ -113,7 +111,7 @@ public void Build_AllCalls_ReturnPassedValues() .AddMiddlewares(m => m.Add()); // Act - var configuration = this.target.Build(clusterConfiguration); + var configuration = _target.Build(clusterConfiguration); // Assert configuration.Topics.Should().BeEquivalentTo(topic1, topic2); diff --git a/src/KafkaFlow.UnitTests/ConfigurationBuilders/KafkaConfigurationBuilderTests.cs b/tests/KafkaFlow.UnitTests/ConfigurationBuilders/KafkaConfigurationBuilderTests.cs similarity index 75% rename from src/KafkaFlow.UnitTests/ConfigurationBuilders/KafkaConfigurationBuilderTests.cs rename to tests/KafkaFlow.UnitTests/ConfigurationBuilders/KafkaConfigurationBuilderTests.cs index bccb9329a..89cb49317 100644 --- a/src/KafkaFlow.UnitTests/ConfigurationBuilders/KafkaConfigurationBuilderTests.cs +++ b/tests/KafkaFlow.UnitTests/ConfigurationBuilders/KafkaConfigurationBuilderTests.cs @@ -1,9 +1,9 @@ -namespace KafkaFlow.UnitTests.ConfigurationBuilders -{ - using KafkaFlow.Configuration; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; +using KafkaFlow.Configuration; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +namespace KafkaFlow.UnitTests.ConfigurationBuilders +{ [TestClass] public class KafkaConfigurationBuilderTests { diff --git a/src/KafkaFlow.UnitTests/ConfigurationBuilders/ProducerConfigurationBuilderTests.cs b/tests/KafkaFlow.UnitTests/ConfigurationBuilders/ProducerConfigurationBuilderTests.cs similarity index 66% rename from src/KafkaFlow.UnitTests/ConfigurationBuilders/ProducerConfigurationBuilderTests.cs rename to tests/KafkaFlow.UnitTests/ConfigurationBuilders/ProducerConfigurationBuilderTests.cs index 938b16d9a..63557aa25 100644 --- a/src/KafkaFlow.UnitTests/ConfigurationBuilders/ProducerConfigurationBuilderTests.cs +++ b/tests/KafkaFlow.UnitTests/ConfigurationBuilders/ProducerConfigurationBuilderTests.cs @@ -1,54 +1,54 @@ +using System; +using AutoFixture; +using Confluent.Kafka; +using FluentAssertions; +using KafkaFlow.Configuration; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + namespace KafkaFlow.UnitTests.ConfigurationBuilders { - using System; - using AutoFixture; - using Confluent.Kafka; - using FluentAssertions; - using KafkaFlow.Configuration; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; - [TestClass] public class ProducerConfigurationBuilderTests { - private readonly Fixture fixture = new(); + private readonly Fixture _fixture = new(); - private Mock dependencyConfiguratorMock; + private Mock _dependencyConfiguratorMock; - private string name; + private string _name; - private ProducerConfigurationBuilder target; + private ProducerConfigurationBuilder _target; [TestInitialize] public void Setup() { - this.dependencyConfiguratorMock = new Mock(); - this.name = this.fixture.Create(); + _dependencyConfiguratorMock = new Mock(); + _name = _fixture.Create(); - this.target = new ProducerConfigurationBuilder( - this.dependencyConfiguratorMock.Object, - this.name); + _target = new ProducerConfigurationBuilder( + _dependencyConfiguratorMock.Object, + _name); } [TestMethod] public void DependencyConfigurator_SetProperty_ReturnPassedInstance() { // Assert - this.target.DependencyConfigurator.Should().Be(this.dependencyConfiguratorMock.Object); + _target.DependencyConfigurator.Should().Be(_dependencyConfiguratorMock.Object); } [TestMethod] public void Build_RequiredCalls_ReturnDefaultValues() { // Arrange - var clusterConfiguration = this.fixture.Create(); + var clusterConfiguration = _fixture.Create(); // Act - var configuration = this.target.Build(clusterConfiguration); + var configuration = _target.Build(clusterConfiguration); // Assert configuration.Cluster.Should().Be(clusterConfiguration); - configuration.Name.Should().Be(this.name); + configuration.Name.Should().Be(_name); configuration.DefaultTopic.Should().BeNull(); configuration.Acks.Should().BeNull(); configuration.StatisticsHandlers.Should().BeEmpty(); @@ -59,10 +59,10 @@ public void Build_RequiredCalls_ReturnDefaultValues() public void Build_AllCalls_ReturnPassedValues() { // Arrange - var clusterConfiguration = this.fixture.Create(); + var clusterConfiguration = _fixture.Create(); - var defaultTopic = this.fixture.Create(); - var acks = this.fixture.Create(); + var defaultTopic = _fixture.Create(); + var acks = _fixture.Create(); const int lingerMs = 50; ProducerCustomFactory customFactory = (producer, _) => producer; Action statisticsHandler = _ => { }; @@ -71,7 +71,7 @@ public void Build_AllCalls_ReturnPassedValues() var compressionType = CompressionType.Lz4; var compressionLevel = 5; - this.target + _target .DefaultTopic(defaultTopic) .WithAcks(acks) .WithLingerMs(lingerMs) @@ -83,11 +83,11 @@ public void Build_AllCalls_ReturnPassedValues() .AddMiddlewares(m => m.Add()); // Act - var configuration = this.target.Build(clusterConfiguration); + var configuration = _target.Build(clusterConfiguration); // Assert configuration.Cluster.Should().Be(clusterConfiguration); - configuration.Name.Should().Be(this.name); + configuration.Name.Should().Be(_name); configuration.DefaultTopic.Should().Be(defaultTopic); configuration.Acks.Should().Be(acks); configuration.BaseProducerConfig.LingerMs.Should().Be(lingerMs); @@ -103,19 +103,19 @@ public void Build_AllCalls_ReturnPassedValues() public void Build_UseCompressionWithoutCompressionLevel_ReturnDefaultValues() { // Arrange - var clusterConfiguration = this.fixture.Create(); + var clusterConfiguration = _fixture.Create(); var compressionType = CompressionType.Gzip; - this.target + _target .WithCompression(compressionType); // Act - var configuration = this.target.Build(clusterConfiguration); + var configuration = _target.Build(clusterConfiguration); // Assert configuration.Cluster.Should().Be(clusterConfiguration); - configuration.Name.Should().Be(this.name); + configuration.Name.Should().Be(_name); configuration.BaseProducerConfig.CompressionType.Should().Be(compressionType); configuration.BaseProducerConfig.CompressionLevel.Should().Be(-1); } diff --git a/tests/KafkaFlow.UnitTests/Consumer/ConsumerManagerTests.cs b/tests/KafkaFlow.UnitTests/Consumer/ConsumerManagerTests.cs new file mode 100644 index 000000000..28d3d9574 --- /dev/null +++ b/tests/KafkaFlow.UnitTests/Consumer/ConsumerManagerTests.cs @@ -0,0 +1,166 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using AutoFixture; +using FluentAssertions; +using KafkaFlow.Configuration; +using KafkaFlow.Consumers; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + +namespace KafkaFlow.UnitTests.Consumer +{ + [TestClass] + public class ConsumerManagerTests + { + private readonly Fixture _fixture = new(); + + private ConsumerManager _target; + + private Mock _consumerMock; + private Mock _workerPoolMock; + private Mock _feederMock; + private Mock _logHandlerMock; + private Mock _dependencyResolver; + + private Action, List> _onPartitionAssignedHandler; + private Action, List> _onPartitionRevokedHandler; + + [TestInitialize] + public void Setup() + { + _consumerMock = new Mock(); + _workerPoolMock = new Mock(); + _feederMock = new Mock(); + _logHandlerMock = new Mock(); + _dependencyResolver = new Mock(); + + _consumerMock + .Setup( + x => x.OnPartitionsAssigned(It.IsAny, List>>())) + .Callback( + (Action, List> value) => + _onPartitionAssignedHandler = value); + + _consumerMock + .Setup( + x => x.OnPartitionsRevoked( + It.IsAny, List>>())) + .Callback( + (Action, List> value) => + _onPartitionRevokedHandler = value); + + var configurationMock = new Mock(); + + configurationMock + .SetupGet(x => x.WorkersCountCalculator) + .Returns((_, _) => Task.FromResult(10)); + + configurationMock + .SetupGet(x => x.WorkersCountEvaluationInterval) + .Returns(TimeSpan.FromMinutes(5)); + + _consumerMock + .SetupGet(x => x.Configuration) + .Returns(configurationMock.Object); + + _target = new ConsumerManager( + _consumerMock.Object, + _workerPoolMock.Object, + _feederMock.Object, + _dependencyResolver.Object, + _logHandlerMock.Object); + } + + [TestMethod] + public void ConstructorCalled_InitializeProperties() + { + // Assert + _target.Consumer.Should().Be(_consumerMock.Object); + _target.WorkerPool.Should().Be(_workerPoolMock.Object); + _target.Feeder.Should().Be(_feederMock.Object); + } + + [TestMethod] + public async Task StartAsync_StartDependencies() + { + // Arrange + _feederMock + .Setup(x => x.Start()); + + // Act + await _target.StartAsync(); + + // Assert + _feederMock.VerifyAll(); + } + + [TestMethod] + public async Task StopAsync_StopDependencies() + { + // Arrange + _feederMock + .Setup(x => x.StopAsync()) + .Returns(Task.CompletedTask); + + _workerPoolMock + .Setup(x => x.StopAsync()) + .Returns(Task.CompletedTask); + + // Act + await _target.StopAsync(); + + // Assert + _feederMock.VerifyAll(); + _workerPoolMock.VerifyAll(); + _consumerMock.Verify(x => x.Dispose(), Times.Once()); + } + + [TestMethod] + public void OnPartitionsAssigned_StartWorkerPool() + { + // Arrange + var partitions = _fixture.Create>(); + + _workerPoolMock + .Setup(x => x.StartAsync(partitions, It.IsAny())) + .Returns(Task.CompletedTask); + + _logHandlerMock + .Setup(x => x.Info(It.IsAny(), It.IsAny())); + + // Act + _onPartitionAssignedHandler(_dependencyResolver.Object, Mock.Of>(), partitions); + + // Assert + _workerPoolMock.VerifyAll(); + _logHandlerMock.VerifyAll(); + } + + [TestMethod] + public void OnPartitionsRevoked_StopWorkerPool() + { + // Arrange + Confluent.Kafka.IConsumer consumer = null; + var partitions = _fixture.Create>(); + + _workerPoolMock + .Setup(x => x.StopAsync()) + .Returns(Task.CompletedTask); + + _consumerMock + .SetupGet(x => x.Configuration) + .Returns(new Mock().Object); + + _logHandlerMock + .Setup(x => x.Warning(It.IsAny(), It.IsAny())); + + // Act + _onPartitionRevokedHandler(_dependencyResolver.Object, consumer, partitions); + + // Assert + _workerPoolMock.VerifyAll(); + _logHandlerMock.VerifyAll(); + } + } +} diff --git a/src/KafkaFlow.UnitTests/Consumer/WorkerPoolFeederTests.cs b/tests/KafkaFlow.UnitTests/Consumer/WorkerPoolFeederTests.cs similarity index 67% rename from src/KafkaFlow.UnitTests/Consumer/WorkerPoolFeederTests.cs rename to tests/KafkaFlow.UnitTests/Consumer/WorkerPoolFeederTests.cs index a1930c73e..282064004 100644 --- a/src/KafkaFlow.UnitTests/Consumer/WorkerPoolFeederTests.cs +++ b/tests/KafkaFlow.UnitTests/Consumer/WorkerPoolFeederTests.cs @@ -1,33 +1,33 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Confluent.Kafka; +using KafkaFlow.Consumers; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + namespace KafkaFlow.UnitTests.Consumer { - using System; - using System.Threading; - using System.Threading.Tasks; - using Confluent.Kafka; - using KafkaFlow.Consumers; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; - [TestClass] public class WorkerPoolFeederTests { - private WorkerPoolFeeder target; + private WorkerPoolFeeder _target; - private Mock consumerMock; - private Mock workerPoolMock; - private Mock logHandlerMock; + private Mock _consumerMock; + private Mock _workerPoolMock; + private Mock _logHandlerMock; [TestInitialize] public void Setup() { - this.consumerMock = new Mock(MockBehavior.Strict); - this.workerPoolMock = new Mock(MockBehavior.Strict); - this.logHandlerMock = new Mock(MockBehavior.Strict); - - this.target = new WorkerPoolFeeder( - this.consumerMock.Object, - this.workerPoolMock.Object, - this.logHandlerMock.Object); + _consumerMock = new Mock(MockBehavior.Strict); + _workerPoolMock = new Mock(MockBehavior.Strict); + _logHandlerMock = new Mock(MockBehavior.Strict); + + _target = new WorkerPoolFeeder( + _consumerMock.Object, + _workerPoolMock.Object, + _logHandlerMock.Object); } [TestMethod] @@ -35,7 +35,7 @@ public void Setup() public async Task StopAsync_WithoutStarting_Return() { // Act - await this.target.StopAsync(); + await _target.StopAsync(); } [TestMethod] @@ -45,7 +45,7 @@ public async Task StopAsync_WaitingOnConsumeWithCancellation_MustStop() // Arrange var ready = new ManualResetEvent(false); - this.consumerMock + _consumerMock .Setup(x => x.ConsumeAsync(It.IsAny())) .Returns( async (CancellationToken ct) => @@ -56,12 +56,12 @@ public async Task StopAsync_WaitingOnConsumeWithCancellation_MustStop() }); // Act - this.target.Start(); + _target.Start(); ready.WaitOne(); - await this.target.StopAsync(); + await _target.StopAsync(); // Assert - this.consumerMock.Verify(x => x.ConsumeAsync(It.IsAny()), Times.Once); + _consumerMock.Verify(x => x.ConsumeAsync(It.IsAny()), Times.Once); } [TestMethod] @@ -72,11 +72,11 @@ public async Task StopAsync_WaitingOnQueuingWithCancellation_MustStop() var consumeResult = new ConsumeResult(); var ready = new ManualResetEvent(false); - this.consumerMock + _consumerMock .Setup(x => x.ConsumeAsync(It.IsAny())) .ReturnsAsync(consumeResult); - this.workerPoolMock + _workerPoolMock .Setup(x => x.EnqueueAsync(consumeResult, It.IsAny())) .Returns((ConsumeResult _, CancellationToken ct) => { @@ -85,13 +85,13 @@ public async Task StopAsync_WaitingOnQueuingWithCancellation_MustStop() }); // Act - this.target.Start(); + _target.Start(); ready.WaitOne(); - await this.target.StopAsync(); + await _target.StopAsync(); // Assert - this.consumerMock.VerifyAll(); - this.workerPoolMock.VerifyAll(); + _consumerMock.VerifyAll(); + _workerPoolMock.VerifyAll(); } [TestMethod] @@ -103,12 +103,12 @@ public async Task ConsumeAsyncThrows_LogAndCallConsumeAsyncAgain() var exception = new Exception(); var ready = new ManualResetEvent(false); - this.consumerMock + _consumerMock .SetupSequence(x => x.ConsumeAsync(It.IsAny())) .Throws(exception) .ReturnsAsync(consumeResult); - this.workerPoolMock + _workerPoolMock .Setup(x => x.EnqueueAsync(consumeResult, It.IsAny())) .Returns((ConsumeResult _, CancellationToken ct) => { @@ -116,18 +116,18 @@ public async Task ConsumeAsyncThrows_LogAndCallConsumeAsyncAgain() return Task.Delay(Timeout.Infinite, ct); }); - this.logHandlerMock + _logHandlerMock .Setup(x => x.Error(It.IsAny(), exception, It.IsAny())); // Act - this.target.Start(); + _target.Start(); ready.WaitOne(); - await this.target.StopAsync(); + await _target.StopAsync(); // Assert - this.consumerMock.VerifyAll(); - this.workerPoolMock.VerifyAll(); - this.logHandlerMock.VerifyAll(); + _consumerMock.VerifyAll(); + _workerPoolMock.VerifyAll(); + _logHandlerMock.VerifyAll(); } [TestMethod] @@ -139,12 +139,12 @@ public async Task EnqueueAsyncThrows_LogAndCallConsumeAsyncAgain() var exception = new Exception(); var ready = new ManualResetEvent(false); - this.consumerMock + _consumerMock .Setup(x => x.ConsumeAsync(It.IsAny())) .ReturnsAsync(consumeResult); var hasThrown = false; - this.workerPoolMock + _workerPoolMock .Setup(x => x.EnqueueAsync(consumeResult, It.IsAny())) .Returns((ConsumeResult _, CancellationToken ct) => { @@ -159,18 +159,18 @@ public async Task EnqueueAsyncThrows_LogAndCallConsumeAsyncAgain() return Task.Delay(Timeout.Infinite, ct); }); - this.logHandlerMock + _logHandlerMock .Setup(x => x.Error(It.IsAny(), exception, It.IsAny())); // Act - this.target.Start(); + _target.Start(); ready.WaitOne(); - await this.target.StopAsync(); + await _target.StopAsync(); // Assert - this.consumerMock.VerifyAll(); - this.workerPoolMock.VerifyAll(); - this.logHandlerMock.VerifyAll(); + _consumerMock.VerifyAll(); + _workerPoolMock.VerifyAll(); + _logHandlerMock.VerifyAll(); } } } diff --git a/src/KafkaFlow.UnitTests/DummyObjects/DummyProtobufObject.cs b/tests/KafkaFlow.UnitTests/DummyObjects/DummyProtobufObject.cs similarity index 100% rename from src/KafkaFlow.UnitTests/DummyObjects/DummyProtobufObject.cs rename to tests/KafkaFlow.UnitTests/DummyObjects/DummyProtobufObject.cs diff --git a/src/KafkaFlow.UnitTests/DummyObjects/DummyProtobufObject.proto b/tests/KafkaFlow.UnitTests/DummyObjects/DummyProtobufObject.proto similarity index 100% rename from src/KafkaFlow.UnitTests/DummyObjects/DummyProtobufObject.proto rename to tests/KafkaFlow.UnitTests/DummyObjects/DummyProtobufObject.proto diff --git a/src/KafkaFlow.UnitTests/EventTests.cs b/tests/KafkaFlow.UnitTests/EventTests.cs similarity index 73% rename from src/KafkaFlow.UnitTests/EventTests.cs rename to tests/KafkaFlow.UnitTests/EventTests.cs index 53aabdee0..8ac80c800 100644 --- a/src/KafkaFlow.UnitTests/EventTests.cs +++ b/tests/KafkaFlow.UnitTests/EventTests.cs @@ -1,23 +1,23 @@ -namespace KafkaFlow.UnitTests +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + +namespace KafkaFlow.UnitTests { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; - [TestClass] public class EventTests { - private readonly Event target; - private readonly Event typedTarget; + private readonly Event _target; + private readonly Event _typedTarget; public EventTests() { var log = new Mock(); - this.target = new Event(log.Object); - this.typedTarget = new Event(log.Object); + _target = new Event(log.Object); + _typedTarget = new Event(log.Object); } [TestMethod] @@ -26,14 +26,14 @@ public async Task FireAsync_EventSubscribed_CallDelegateWithSuccess() // Arrange var numberOfCalls = 0; - this.target.Subscribe(() => + _target.Subscribe(() => { numberOfCalls++; return Task.CompletedTask; }); // Act - await this.target.FireAsync(); + await _target.FireAsync(); // Assert Assert.AreEqual(1, numberOfCalls); @@ -45,20 +45,20 @@ public async Task FireAsync_EventWithMultipleObservers_CallAllDelegatesWithSucce // Arrange var numberOfCalls = 0; - this.target.Subscribe(() => + _target.Subscribe(() => { numberOfCalls++; return Task.CompletedTask; }); - this.target.Subscribe(() => + _target.Subscribe(() => { numberOfCalls++; return Task.CompletedTask; }); // Act - await this.target.FireAsync(); + await _target.FireAsync(); // Assert Assert.AreEqual(2, numberOfCalls); @@ -70,16 +70,16 @@ public async Task FireAsync_EventWithMultipleObserversAndErrors_CallAllDelegates // Arrange var numberOfCalls = 0; - this.target.Subscribe(() => throw new NotImplementedException()); + _target.Subscribe(() => throw new NotImplementedException()); - this.target.Subscribe(() => + _target.Subscribe(() => { numberOfCalls++; return Task.CompletedTask; }); // Act - await this.target.FireAsync(); + await _target.FireAsync(); // Assert Assert.AreEqual(1, numberOfCalls); @@ -92,14 +92,14 @@ public async Task FireAsync_EventSubscribedWithArgument_CallDelegateWithSuccess( var expectedArgument = Guid.NewGuid().ToString(); var receivedArgument = string.Empty; - this.typedTarget.Subscribe(arg => + _typedTarget.Subscribe(arg => { receivedArgument = arg; return Task.CompletedTask; }); // Act - await this.typedTarget.FireAsync(expectedArgument); + await _typedTarget.FireAsync(expectedArgument); // Assert Assert.AreEqual(expectedArgument, receivedArgument); @@ -112,20 +112,20 @@ public async Task FireAsync_EventWithMultipleObserversAndArgument_CallAllDelegat var expectedArgument = Guid.NewGuid().ToString(); var receivedArguments = new List(); - this.typedTarget.Subscribe(arg => + _typedTarget.Subscribe(arg => { receivedArguments.Add(arg); return Task.CompletedTask; }); - this.typedTarget.Subscribe(arg => + _typedTarget.Subscribe(arg => { receivedArguments.Add(arg); return Task.CompletedTask; }); // Act - await this.typedTarget.FireAsync(expectedArgument); + await _typedTarget.FireAsync(expectedArgument); // Assert Assert.AreEqual(2, receivedArguments.Count); @@ -138,16 +138,16 @@ public async Task FireAsync_TypedEventWithMultipleObserversAndErrors_CallAllDele // Arrange var numberOfCalls = 0; - this.typedTarget.Subscribe(_ => throw new NotImplementedException()); + _typedTarget.Subscribe(_ => throw new NotImplementedException()); - this.typedTarget.Subscribe(_ => + _typedTarget.Subscribe(_ => { numberOfCalls++; return Task.CompletedTask; }); // Act - await this.typedTarget.FireAsync(Guid.NewGuid().ToString()); + await _typedTarget.FireAsync(Guid.NewGuid().ToString()); // Assert Assert.AreEqual(1, numberOfCalls); @@ -166,11 +166,11 @@ public async Task FireAsync_DuplicatedEventHandler_CallHandlerOnce() return Task.CompletedTask; }; - this.typedTarget.Subscribe(handler); - this.typedTarget.Subscribe(handler); + _typedTarget.Subscribe(handler); + _typedTarget.Subscribe(handler); // Act - await this.typedTarget.FireAsync(expectedArgument); + await _typedTarget.FireAsync(expectedArgument); // Assert Assert.AreEqual(1, receivedArguments.Count); @@ -190,12 +190,12 @@ public async Task FireAsync_UnsubscribeEventHandler_DoesNotCallHandler() return Task.CompletedTask; }; - var subscription = this.typedTarget.Subscribe(handler); + var subscription = _typedTarget.Subscribe(handler); subscription.Cancel(); // Act - await this.typedTarget.FireAsync(expectedArgument); + await _typedTarget.FireAsync(expectedArgument); // Assert Assert.AreEqual(0, receivedArguments.Count); diff --git a/src/KafkaFlow.UnitTests/ExtensionHelpers.cs b/tests/KafkaFlow.UnitTests/ExtensionHelpers.cs similarity index 88% rename from src/KafkaFlow.UnitTests/ExtensionHelpers.cs rename to tests/KafkaFlow.UnitTests/ExtensionHelpers.cs index 50c81f1e2..f072e393f 100644 --- a/src/KafkaFlow.UnitTests/ExtensionHelpers.cs +++ b/tests/KafkaFlow.UnitTests/ExtensionHelpers.cs @@ -1,8 +1,8 @@ +using System; +using System.Threading.Tasks; + namespace KafkaFlow.UnitTests { - using System; - using System.Threading.Tasks; - public static class ExtensionHelpers { public static TaskCompletionSource WithTimeout(this TaskCompletionSource taskCompletionSource, int milliseconds) diff --git a/src/KafkaFlow.UnitTests/KafkaFlow.UnitTests.csproj b/tests/KafkaFlow.UnitTests/KafkaFlow.UnitTests.csproj similarity index 55% rename from src/KafkaFlow.UnitTests/KafkaFlow.UnitTests.csproj rename to tests/KafkaFlow.UnitTests/KafkaFlow.UnitTests.csproj index 681188711..4819c54ce 100644 --- a/src/KafkaFlow.UnitTests/KafkaFlow.UnitTests.csproj +++ b/tests/KafkaFlow.UnitTests/KafkaFlow.UnitTests.csproj @@ -29,15 +29,15 @@ - - - - - - - - - + + + + + + + + + diff --git a/src/KafkaFlow.UnitTests/LogHandlers/MicrosoftLogHandlerTests.cs b/tests/KafkaFlow.UnitTests/LogHandlers/MicrosoftLogHandlerTests.cs similarity index 79% rename from src/KafkaFlow.UnitTests/LogHandlers/MicrosoftLogHandlerTests.cs rename to tests/KafkaFlow.UnitTests/LogHandlers/MicrosoftLogHandlerTests.cs index 9f06cb861..d8978d771 100644 --- a/src/KafkaFlow.UnitTests/LogHandlers/MicrosoftLogHandlerTests.cs +++ b/tests/KafkaFlow.UnitTests/LogHandlers/MicrosoftLogHandlerTests.cs @@ -1,9 +1,9 @@ -namespace KafkaFlow.UnitTests.LogHandlers -{ - using Microsoft.Extensions.Logging; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; +using Microsoft.Extensions.Logging; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +namespace KafkaFlow.UnitTests.LogHandlers +{ [TestClass] public class MicrosoftLogHandlerTests { diff --git a/src/KafkaFlow.UnitTests/MemoryTelemetryStorageTests.cs b/tests/KafkaFlow.UnitTests/MemoryTelemetryStorageTests.cs similarity index 71% rename from src/KafkaFlow.UnitTests/MemoryTelemetryStorageTests.cs rename to tests/KafkaFlow.UnitTests/MemoryTelemetryStorageTests.cs index bb7bf0f66..1d19ab2bc 100644 --- a/src/KafkaFlow.UnitTests/MemoryTelemetryStorageTests.cs +++ b/tests/KafkaFlow.UnitTests/MemoryTelemetryStorageTests.cs @@ -1,40 +1,40 @@ +using System; +using System.Linq; +using FluentAssertions; +using KafkaFlow.Admin; +using KafkaFlow.Admin.Messages; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + namespace KafkaFlow.UnitTests { - using System; - using System.Linq; - using FluentAssertions; - using KafkaFlow.Admin; - using KafkaFlow.Admin.Messages; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; - [TestClass] public class MemoryTelemetryStorageTests { - private Mock dateTimeProviderMock; + private Mock _dateTimeProviderMock; - private MemoryTelemetryStorage target; + private MemoryTelemetryStorage _target; [TestInitialize] public void Setup() { - this.dateTimeProviderMock = new(); + _dateTimeProviderMock = new(); - this.dateTimeProviderMock + _dateTimeProviderMock .SetupGet(x => x.MinValue) .Returns(DateTime.MinValue); - this.target = new( + _target = new( TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1), - this.dateTimeProviderMock.Object); + _dateTimeProviderMock.Object); } [TestMethod] public void Get_NoItems_ReturnsEmpty() { // Act - var metrics = this.target.Get(); + var metrics = _target.Get(); // Assert metrics.Should().BeEmpty(); @@ -46,15 +46,15 @@ public void Put_OneItem_ReturnsOneItem() // Arrange var now = DateTime.Now; - this.dateTimeProviderMock + _dateTimeProviderMock .SetupGet(x => x.UtcNow) .Returns(now); // Act - this.target.Put(new ConsumerTelemetryMetric { SentAt = now }); + _target.Put(new ConsumerTelemetryMetric { SentAt = now }); // Assert - this.target.Get().Should().HaveCount(1); + _target.Get().Should().HaveCount(1); } [TestMethod] @@ -63,7 +63,7 @@ public void PutTwoItems_SameInstanceGroupConsumer_ReplaceOlder() // Arrange var now = DateTime.Now; - this.dateTimeProviderMock + _dateTimeProviderMock .SetupGet(x => x.UtcNow) .Returns(now); @@ -84,12 +84,12 @@ public void PutTwoItems_SameInstanceGroupConsumer_ReplaceOlder() }; // Act - this.target.Put(metric1); - this.target.Put(metric2); + _target.Put(metric1); + _target.Put(metric2); // Assert - this.target.Get().Should().HaveCount(1); - this.target.Get().First().Should().Be(metric2); + _target.Get().Should().HaveCount(1); + _target.Get().First().Should().Be(metric2); } [TestMethod] @@ -98,7 +98,7 @@ public void PutTwoItems_DifferentInstanceGroupConsumer_ReturnsTwo() // Arrange var now = DateTime.Now; - this.dateTimeProviderMock + _dateTimeProviderMock .SetupGet(x => x.UtcNow) .Returns(now); @@ -119,11 +119,11 @@ public void PutTwoItems_DifferentInstanceGroupConsumer_ReturnsTwo() }; // Act - this.target.Put(metric1); - this.target.Put(metric2); + _target.Put(metric1); + _target.Put(metric2); // Assert - this.target.Get().Should().HaveCount(2); + _target.Get().Should().HaveCount(2); } [TestMethod] @@ -132,7 +132,7 @@ public void PutTwoItems_ExpiryOne_ReturnsOne() // Arrange var now = new DateTime(2000, 01, 01); - this.dateTimeProviderMock + _dateTimeProviderMock .SetupGet(x => x.UtcNow) .Returns(now); @@ -144,7 +144,7 @@ public void PutTwoItems_ExpiryOne_ReturnsOne() SentAt = now, }; - this.target.Put(metric1); + _target.Put(metric1); var metric2 = new ConsumerTelemetryMetric { @@ -154,16 +154,16 @@ public void PutTwoItems_ExpiryOne_ReturnsOne() SentAt = now.AddSeconds(5), }; - this.dateTimeProviderMock + _dateTimeProviderMock .SetupGet(x => x.UtcNow) .Returns(now.AddSeconds(2)); // Act - this.target.Put(metric2); + _target.Put(metric2); // Assert - this.target.Get().Should().HaveCount(1); - this.target.Get().First().Should().Be(metric2); + _target.Get().Should().HaveCount(1); + _target.Get().First().Should().Be(metric2); } } } diff --git a/src/KafkaFlow.UnitTests/MessageHeadersTests.cs b/tests/KafkaFlow.UnitTests/MessageHeadersTests.cs similarity index 74% rename from src/KafkaFlow.UnitTests/MessageHeadersTests.cs rename to tests/KafkaFlow.UnitTests/MessageHeadersTests.cs index ed89bddbd..be00d053a 100644 --- a/src/KafkaFlow.UnitTests/MessageHeadersTests.cs +++ b/tests/KafkaFlow.UnitTests/MessageHeadersTests.cs @@ -1,16 +1,16 @@ +using System.Text; +using Confluent.Kafka; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + namespace KafkaFlow.UnitTests { - using System.Text; - using Confluent.Kafka; - using FluentAssertions; - using Microsoft.VisualStudio.TestTools.UnitTesting; - [TestClass] public class MessageHeadersTests { private const string Key = "abc"; private const string StrValue = "123"; - private readonly byte[] value = Encoding.UTF8.GetBytes("123"); + private readonly byte[] _value = Encoding.UTF8.GetBytes("123"); [TestMethod] public void Add_WithKeyNotNull_ShouldAddValueCorrectly() @@ -19,17 +19,17 @@ public void Add_WithKeyNotNull_ShouldAddValueCorrectly() var header = new MessageHeaders(); // Act - header.Add(Key, this.value); + header.Add(Key, _value); // Assert - header[Key].Should().BeEquivalentTo(this.value); + header[Key].Should().BeEquivalentTo(_value); } [TestMethod] public void GetKafkaHeader_ShouldReturnKafkaHeaders() { // Arrange - var kafkaHeaders = new Headers { { Key, this.value } }; + var kafkaHeaders = new Headers { { Key, _value } }; var messageHeaders = new MessageHeaders(kafkaHeaders); // Act diff --git a/src/KafkaFlow.UnitTests/Middlewares/Serialization/ConfluentAvroTypeNameResolverTests.cs b/tests/KafkaFlow.UnitTests/Middlewares/Serialization/ConfluentAvroTypeNameResolverTests.cs similarity index 52% rename from src/KafkaFlow.UnitTests/Middlewares/Serialization/ConfluentAvroTypeNameResolverTests.cs rename to tests/KafkaFlow.UnitTests/Middlewares/Serialization/ConfluentAvroTypeNameResolverTests.cs index 5fdeb0921..b67801108 100644 --- a/src/KafkaFlow.UnitTests/Middlewares/Serialization/ConfluentAvroTypeNameResolverTests.cs +++ b/tests/KafkaFlow.UnitTests/Middlewares/Serialization/ConfluentAvroTypeNameResolverTests.cs @@ -1,23 +1,23 @@ +using System.Threading.Tasks; +using Confluent.SchemaRegistry; +using FluentAssertions; +using KafkaFlow.Serializer.SchemaRegistry; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Newtonsoft.Json; + namespace KafkaFlow.UnitTests.Middlewares.Serialization { - using System.Threading.Tasks; - using Confluent.SchemaRegistry; - using FluentAssertions; - using KafkaFlow.Serializer.SchemaRegistry; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; - using Newtonsoft.Json; - [TestClass] public class ConfluentAvroTypeNameResolverTests { - private readonly Mock schemaRegistryClient; - private readonly ConfluentAvroTypeNameResolver schemaRegistryTypeResolver; + private readonly Mock _schemaRegistryClient; + private readonly ConfluentAvroTypeNameResolver _schemaRegistryTypeResolver; public ConfluentAvroTypeNameResolverTests() { - this.schemaRegistryClient = new Mock(); - this.schemaRegistryTypeResolver = new ConfluentAvroTypeNameResolver(this.schemaRegistryClient.Object); + _schemaRegistryClient = new Mock(); + _schemaRegistryTypeResolver = new ConfluentAvroTypeNameResolver(_schemaRegistryClient.Object); } [TestMethod] @@ -34,11 +34,11 @@ public async Task ResolveAsync_ValidSchemaObject_ReturnsAvroFieldsInCorrectForma var schema = new Schema(JsonConvert.SerializeObject(schemaObj), SchemaType.Avro); - this.schemaRegistryClient.Setup(client => client.GetSchemaAsync(schemaId, null)) + _schemaRegistryClient.Setup(client => client.GetSchemaAsync(schemaId, null)) .ReturnsAsync(schema); // Act - var avroFields = await this.schemaRegistryTypeResolver.ResolveAsync(schemaId); + var avroFields = await _schemaRegistryTypeResolver.ResolveAsync(schemaId); // Assert avroFields.Should().Be($"{schemaObj.NameSpace}.{schemaObj.Name}"); diff --git a/src/KafkaFlow.UnitTests/Middlewares/Serialization/ConfluentProtobufTypeNameResolverTests.cs b/tests/KafkaFlow.UnitTests/Middlewares/Serialization/ConfluentProtobufTypeNameResolverTests.cs similarity index 50% rename from src/KafkaFlow.UnitTests/Middlewares/Serialization/ConfluentProtobufTypeNameResolverTests.cs rename to tests/KafkaFlow.UnitTests/Middlewares/Serialization/ConfluentProtobufTypeNameResolverTests.cs index cd6ec854f..4185222eb 100644 --- a/src/KafkaFlow.UnitTests/Middlewares/Serialization/ConfluentProtobufTypeNameResolverTests.cs +++ b/tests/KafkaFlow.UnitTests/Middlewares/Serialization/ConfluentProtobufTypeNameResolverTests.cs @@ -1,26 +1,25 @@ -namespace KafkaFlow.UnitTests.Middlewares.Serialization -{ - using System; - using System.Threading.Tasks; - using Confluent.SchemaRegistry; +using System; +using System.Threading.Tasks; +using Confluent.SchemaRegistry; - using FluentAssertions; +using FluentAssertions; - using Google.Protobuf; - using KafkaFlow.Serializer.SchemaRegistry; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; +using Google.Protobuf; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +namespace KafkaFlow.UnitTests.Middlewares.Serialization +{ [TestClass] public class ConfluentProtobufTypeNameResolverTests { - private readonly Mock schemaRegistryClient; - private readonly ConfluentProtobufTypeNameResolver schemaRegistryTypeResolver; + private readonly Mock _schemaRegistryClient; + private readonly ConfluentProtobufTypeNameResolver _schemaRegistryTypeResolver; public ConfluentProtobufTypeNameResolverTests() { - this.schemaRegistryClient = new Mock(); - this.schemaRegistryTypeResolver = new ConfluentProtobufTypeNameResolver(this.schemaRegistryClient.Object); + _schemaRegistryClient = new Mock(); + _schemaRegistryTypeResolver = new ConfluentProtobufTypeNameResolver(_schemaRegistryClient.Object); } [TestMethod] @@ -36,11 +35,11 @@ public async Task ResolveAsync_ValidProtobufObject_ReturnsProtoFields() }; var base64Encoded = Convert.ToBase64String(dummyProtobufObj.ToByteArray()); - this.schemaRegistryClient.Setup(client => client.GetSchemaAsync(schemaId, "serialized")) + _schemaRegistryClient.Setup(client => client.GetSchemaAsync(schemaId, "serialized")) .ReturnsAsync(new Schema(base64Encoded, SchemaType.Protobuf)); // Act - var protoFields = await this.schemaRegistryTypeResolver.ResolveAsync(schemaId); + var protoFields = await _schemaRegistryTypeResolver.ResolveAsync(schemaId); // Assert protoFields.Should().NotBeNull(); diff --git a/tests/KafkaFlow.UnitTests/Middlewares/Serialization/SchemaRegistryTypeResolverTests.cs b/tests/KafkaFlow.UnitTests/Middlewares/Serialization/SchemaRegistryTypeResolverTests.cs new file mode 100644 index 000000000..066944415 --- /dev/null +++ b/tests/KafkaFlow.UnitTests/Middlewares/Serialization/SchemaRegistryTypeResolverTests.cs @@ -0,0 +1,47 @@ +using System; +using System.Buffers.Binary; +using System.Threading.Tasks; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + +namespace KafkaFlow.UnitTests.Middlewares.Serialization +{ + [TestClass] + public class SchemaRegistryTypeResolverTests + { + private readonly Mock _messageContextMock; + private readonly Mock _schemaRegistryTypeNameResolverMock; + private readonly SchemaRegistryTypeResolver _schemaRegistryTypeResolver; + private readonly byte[] _messageKey = new byte[] { 0x18, 0x19 }; + private readonly byte[] _messageValue = new byte[] { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25 }; + + public SchemaRegistryTypeResolverTests() + { + _messageContextMock = new Mock(); + _messageContextMock.Setup(context => context.Message).Returns(new Message(_messageKey, _messageValue)); + _schemaRegistryTypeNameResolverMock = new Mock(); + _schemaRegistryTypeResolver = new SchemaRegistryTypeResolver(_schemaRegistryTypeNameResolverMock.Object); + } + + [TestMethod] + public async Task OnConsumeAsync_WhenCalledTwice_TypeIsResolvedOnceThenTypeIsLoadedFromCache() + { + // Arrange + var expectedSchemaId = BinaryPrimitives.ReadInt32BigEndian( + _messageValue.AsSpan().Slice(1, 4)); + + _schemaRegistryTypeNameResolverMock.Setup( + resolver => resolver.ResolveAsync(expectedSchemaId)).ReturnsAsync(typeof(SchemaRegistryTypeResolverTests).FullName); + + // Act + await _schemaRegistryTypeResolver.OnConsumeAsync(_messageContextMock.Object); + var type = await _schemaRegistryTypeResolver.OnConsumeAsync(_messageContextMock.Object); + + // Assert + _schemaRegistryTypeNameResolverMock.Verify(resolver => resolver.ResolveAsync(expectedSchemaId), Times.Once); + var expectedObject = (SchemaRegistryTypeResolverTests)Activator.CreateInstance(type); + expectedObject.Should().NotBeNull(); + } + } +} diff --git a/src/KafkaFlow.UnitTests/OffsetCommitterTests.cs b/tests/KafkaFlow.UnitTests/OffsetCommitterTests.cs similarity index 53% rename from src/KafkaFlow.UnitTests/OffsetCommitterTests.cs rename to tests/KafkaFlow.UnitTests/OffsetCommitterTests.cs index 1df3b351c..5c2a2b090 100644 --- a/src/KafkaFlow.UnitTests/OffsetCommitterTests.cs +++ b/tests/KafkaFlow.UnitTests/OffsetCommitterTests.cs @@ -1,72 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using KafkaFlow.Consumers; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + namespace KafkaFlow.UnitTests { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Threading.Tasks; - using Confluent.Kafka; - using KafkaFlow.Consumers; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; - [TestClass] public class OffsetCommitterTests { private const int TestTimeout = 5000; - private Mock consumerMock; + private Mock _consumerMock; - private TopicPartition topicPartition; + private Confluent.Kafka.TopicPartition _topicPartition; - private OffsetCommitter offsetCommitter; + private OffsetCommitter _offsetCommitter; [TestInitialize] public async Task Setup() { - this.consumerMock = new Mock(); - this.topicPartition = new TopicPartition("topic-A", new Partition(1)); + _consumerMock = new Mock(); + _topicPartition = new Confluent.Kafka.TopicPartition("topic-A", new Confluent.Kafka.Partition(1)); - this.consumerMock + _consumerMock .Setup(c => c.Configuration.AutoCommitInterval) .Returns(TimeSpan.FromMilliseconds(1000)); - this.offsetCommitter = new OffsetCommitter( - this.consumerMock.Object, + _offsetCommitter = new OffsetCommitter( + _consumerMock.Object, Mock.Of(), Mock.Of()); - await this.offsetCommitter.StartAsync(); + await _offsetCommitter.StartAsync(); } [TestCleanup] public async Task Cleanup() { - await this.offsetCommitter.StopAsync(); + await _offsetCommitter.StopAsync(); } [TestMethod] public async Task MarkAsProcessed_ShouldCommit() { // Arrange - var expectedOffsets = new[] { new TopicPartitionOffset(this.topicPartition, new Offset(2)) }; + var expectedOffsets = new[] { new Confluent.Kafka.TopicPartitionOffset(_topicPartition, new Confluent.Kafka.Offset(2)) }; var ready = new TaskCompletionSource().WithTimeout(TestTimeout); - this.consumerMock - .Setup(c => c.Commit(It.Is>(l => l.SequenceEqual(expectedOffsets)))) - .Callback((IEnumerable _) => ready.SetResult()); + _consumerMock + .Setup(c => c.Commit(It.Is>(l => l.SequenceEqual(expectedOffsets)))) + .Callback((IEnumerable _) => ready.SetResult()); // Act - this.offsetCommitter.MarkAsProcessed( + _offsetCommitter.MarkAsProcessed( new KafkaFlow.TopicPartitionOffset( - this.topicPartition.Topic, - this.topicPartition.Partition, + _topicPartition.Topic, + _topicPartition.Partition, 1)); await ready.Task; // Assert - this.consumerMock.VerifyAll(); + _consumerMock.VerifyAll(); } [TestMethod] @@ -76,7 +75,7 @@ public async Task PendingOffsetsState_ShouldExecuteHandlers() var ready = new TaskCompletionSource().WithTimeout(TestTimeout); var committer = new OffsetCommitter( - this.consumerMock.Object, + _consumerMock.Object, Mock.Of(), Mock.Of()); @@ -87,8 +86,8 @@ public async Task PendingOffsetsState_ShouldExecuteHandlers() // Act committer.MarkAsProcessed( new KafkaFlow.TopicPartitionOffset( - this.topicPartition.Topic, - this.topicPartition.Partition, + _topicPartition.Topic, + _topicPartition.Partition, 1)); // Assert @@ -102,15 +101,15 @@ public async Task PendingOffsetsState_ShouldExecuteHandlers() public async Task MarkAsProcessed_WithFailure_ShouldRequeueFailedOffsetAndCommit() { // Arrange - var expectedOffsets = new[] { new TopicPartitionOffset(this.topicPartition, new Offset(2)) }; + var expectedOffsets = new[] { new Confluent.Kafka.TopicPartitionOffset(_topicPartition, new Confluent.Kafka.Offset(2)) }; var ready = new TaskCompletionSource().WithTimeout(TestTimeout); var hasThrown = false; - this.consumerMock - .Setup(c => c.Commit(It.Is>(l => l.SequenceEqual(expectedOffsets)))) + _consumerMock + .Setup(c => c.Commit(It.Is>(l => l.SequenceEqual(expectedOffsets)))) .Callback( - (IEnumerable _) => + (IEnumerable _) => { if (!hasThrown) { @@ -122,17 +121,17 @@ public async Task MarkAsProcessed_WithFailure_ShouldRequeueFailedOffsetAndCommit }); // Act - this.offsetCommitter.MarkAsProcessed( + _offsetCommitter.MarkAsProcessed( new KafkaFlow.TopicPartitionOffset( - this.topicPartition.Topic, - this.topicPartition.Partition, + _topicPartition.Topic, + _topicPartition.Partition, 1)); await ready.Task; // Assert - this.consumerMock.Verify( - c => c.Commit(It.Is>(l => l.SequenceEqual(expectedOffsets))), + _consumerMock.Verify( + c => c.Commit(It.Is>(l => l.SequenceEqual(expectedOffsets))), Times.Exactly(2)); } } diff --git a/tests/KafkaFlow.UnitTests/OffsetManagerTests.cs b/tests/KafkaFlow.UnitTests/OffsetManagerTests.cs new file mode 100644 index 000000000..0f2a7221a --- /dev/null +++ b/tests/KafkaFlow.UnitTests/OffsetManagerTests.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using Confluent.Kafka; +using FluentAssertions; +using KafkaFlow.Consumers; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + +namespace KafkaFlow.UnitTests +{ + [TestClass] + public class OffsetManagerTests + { + private Mock _committerMock; + private OffsetManager _target; + private TopicPartition _topicPartition; + + [TestInitialize] + public void Setup() + { + _committerMock = new Mock(); + _topicPartition = new TopicPartition("topic-A", new Partition(1)); + + _target = new OffsetManager( + _committerMock.Object, + new List { _topicPartition }); + } + + [TestMethod] + public void MarkAsProcessed_WithNotQueuedContext_ShouldThrowInvalidOperation() + { + // Act + Action act = () => _target.MarkAsProcessed(this.MockConsumerContext(1)); + + // Assert + act.Should().Throw(); + } + + [TestMethod] + public void MarkAsProcessed_WithGaps_ShouldStoreOffsetJustOnce() + { + // Arrange + _target.Enqueue(this.MockConsumerContext(1)); + _target.Enqueue(this.MockConsumerContext(2)); + _target.Enqueue(this.MockConsumerContext(3)); + + // Act + _target.MarkAsProcessed(this.MockConsumerContext(3)); + _target.MarkAsProcessed(this.MockConsumerContext(2)); + _target.MarkAsProcessed(this.MockConsumerContext(1)); + + // Assert + _committerMock.Verify( + c => + c.MarkAsProcessed( + It.Is( + p => + p.Partition == _topicPartition.Partition && + p.Offset == 3)), + Times.Once); + } + + private IConsumerContext MockConsumerContext(int offset) + { + var mock = new Mock(); + var tpo = new TopicPartitionOffset(_topicPartition.Topic, _topicPartition.Partition, offset); + + mock + .SetupGet(x => x.Offset) + .Returns(tpo.Offset); + + mock + .SetupGet(x => x.Partition) + .Returns(tpo.Partition); + + mock + .SetupGet(x => x.Topic) + .Returns(tpo.Topic); + + mock + .SetupGet(x => x.TopicPartitionOffset) + .Returns(tpo); + + return mock.Object; + } + } +} diff --git a/src/KafkaFlow.UnitTests/PartitionOffsetsTests.cs b/tests/KafkaFlow.UnitTests/PartitionOffsetsTests.cs similarity index 95% rename from src/KafkaFlow.UnitTests/PartitionOffsetsTests.cs rename to tests/KafkaFlow.UnitTests/PartitionOffsetsTests.cs index e3a4b168c..0379e9c88 100644 --- a/src/KafkaFlow.UnitTests/PartitionOffsetsTests.cs +++ b/tests/KafkaFlow.UnitTests/PartitionOffsetsTests.cs @@ -1,13 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using FluentAssertions; +using KafkaFlow.Consumers; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + namespace KafkaFlow.UnitTests { - using System; - using System.Collections.Generic; - using System.Threading.Tasks; - using FluentAssertions; - using KafkaFlow.Consumers; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; - [TestClass] public class PartitionOffsetsTests { diff --git a/src/KafkaFlow.UnitTests/Serializers/JsonCoreSerializerTests.cs b/tests/KafkaFlow.UnitTests/Serializers/JsonCoreSerializerTests.cs similarity index 69% rename from src/KafkaFlow.UnitTests/Serializers/JsonCoreSerializerTests.cs rename to tests/KafkaFlow.UnitTests/Serializers/JsonCoreSerializerTests.cs index eb17adf0c..25aa6dda7 100644 --- a/src/KafkaFlow.UnitTests/Serializers/JsonCoreSerializerTests.cs +++ b/tests/KafkaFlow.UnitTests/Serializers/JsonCoreSerializerTests.cs @@ -1,18 +1,18 @@ -namespace KafkaFlow.UnitTests.Serializers +using System.IO; +using System.Text.Encodings.Web; +using System.Text.Json; +using System.Threading.Tasks; +using FluentAssertions; +using KafkaFlow.Serializer; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + +namespace KafkaFlow.UnitTests.Serializers { - using System.IO; - using System.Text.Encodings.Web; - using System.Text.Json; - using System.Threading.Tasks; - using FluentAssertions; - using KafkaFlow.Serializer; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; - [TestClass] public class JsonCoreSerializerTests { - private readonly Mock contextMock = new(); + private readonly Mock _contextMock = new(); [TestMethod] public async Task SerializeAsync_PreventEscapeOfAccentedCharacter_SerializedObjectDoesNotHaveAccentedCharacterEscaped() @@ -26,7 +26,7 @@ public async Task SerializeAsync_PreventEscapeOfAccentedCharacter_SerializedObje var target = new JsonCoreSerializer(writerOptions); // Act - await target.SerializeAsync(message, output, this.contextMock.Object); + await target.SerializeAsync(message, output, _contextMock.Object); // Assert var result = GetStreamText(output); @@ -45,4 +45,4 @@ private class TestMessage public string Text { get; set; } } } -} \ No newline at end of file +} diff --git a/src/KafkaFlow.UnitTests/Serializers/NewtonsoftJsonDeserializerTests.cs b/tests/KafkaFlow.UnitTests/Serializers/NewtonsoftJsonDeserializerTests.cs similarity index 54% rename from src/KafkaFlow.UnitTests/Serializers/NewtonsoftJsonDeserializerTests.cs rename to tests/KafkaFlow.UnitTests/Serializers/NewtonsoftJsonDeserializerTests.cs index 88fa963e8..374b698d8 100644 --- a/src/KafkaFlow.UnitTests/Serializers/NewtonsoftJsonDeserializerTests.cs +++ b/tests/KafkaFlow.UnitTests/Serializers/NewtonsoftJsonDeserializerTests.cs @@ -1,33 +1,33 @@ +using System; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using AutoFixture; +using FluentAssertions; +using KafkaFlow.Serializer; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Newtonsoft.Json; + namespace KafkaFlow.UnitTests.Serializers { - using System; - using System.IO; - using System.Text; - using System.Threading.Tasks; - using AutoFixture; - using FluentAssertions; - using KafkaFlow.Serializer; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; - using Newtonsoft.Json; - [TestClass] public class NewtonsoftJsonDeserializerTests { - private readonly Mock contextMock = new (); - private readonly NewtonsoftJsonDeserializer deserializer = new (); + private readonly Mock _contextMock = new(); + private readonly NewtonsoftJsonDeserializer _deserializer = new(); - private readonly Fixture fixture = new(); + private readonly Fixture _fixture = new(); [TestMethod] public async Task DeserializeAsync_ValidPayload_ObjectGenerated() { // Arrange - var message = this.fixture.Create(); + var message = _fixture.Create(); using var input = new MemoryStream(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(message))); // Act - var result = await this.deserializer.DeserializeAsync(input, typeof(TestMessage), this.contextMock.Object); + var result = await _deserializer.DeserializeAsync(input, typeof(TestMessage), _contextMock.Object); // Assert result.Should().NotBeNull(); diff --git a/src/KafkaFlow.UnitTests/Serializers/NewtonsoftJsonSerializerTests.cs b/tests/KafkaFlow.UnitTests/Serializers/NewtonsoftJsonSerializerTests.cs similarity index 56% rename from src/KafkaFlow.UnitTests/Serializers/NewtonsoftJsonSerializerTests.cs rename to tests/KafkaFlow.UnitTests/Serializers/NewtonsoftJsonSerializerTests.cs index 93673ed05..89956c1aa 100644 --- a/src/KafkaFlow.UnitTests/Serializers/NewtonsoftJsonSerializerTests.cs +++ b/tests/KafkaFlow.UnitTests/Serializers/NewtonsoftJsonSerializerTests.cs @@ -1,31 +1,31 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using AutoFixture; +using FluentAssertions; +using KafkaFlow.Serializer; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + namespace KafkaFlow.UnitTests.Serializers { - using System; - using System.IO; - using System.Threading.Tasks; - using AutoFixture; - using FluentAssertions; - using KafkaFlow.Serializer; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; - [TestClass] public class NewtonsoftJsonSerializerTests { - private readonly Mock contextMock = new (); - private readonly NewtonsoftJsonSerializer serializer = new (); + private readonly Mock _contextMock = new(); + private readonly NewtonsoftJsonSerializer _serializer = new(); - private readonly Fixture fixture = new(); + private readonly Fixture _fixture = new(); [TestMethod] public async Task SerializeAsync_ValidPayload_JsonByteArrayGenerated() { // Arrange - var message = this.fixture.Create(); + var message = _fixture.Create(); using var output = new MemoryStream(); // Act - await this.serializer.SerializeAsync(message, output, this.contextMock.Object); + await _serializer.SerializeAsync(message, output, _contextMock.Object); // Assert output.Length.Should().BeGreaterThan(0); diff --git a/src/KafkaFlow.UnitTests/Serializers/SerializerConsumerMiddlewareTests.cs b/tests/KafkaFlow.UnitTests/Serializers/SerializerConsumerMiddlewareTests.cs similarity index 55% rename from src/KafkaFlow.UnitTests/Serializers/SerializerConsumerMiddlewareTests.cs rename to tests/KafkaFlow.UnitTests/Serializers/SerializerConsumerMiddlewareTests.cs index 6c05b0201..6c9f857ca 100644 --- a/src/KafkaFlow.UnitTests/Serializers/SerializerConsumerMiddlewareTests.cs +++ b/tests/KafkaFlow.UnitTests/Serializers/SerializerConsumerMiddlewareTests.cs @@ -1,57 +1,57 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using FluentAssertions; +using KafkaFlow.Middlewares.Serializer; +using KafkaFlow.Middlewares.Serializer.Resolvers; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + namespace KafkaFlow.UnitTests.Serializers { - using System; - using System.IO; - using System.Threading.Tasks; - using FluentAssertions; - using KafkaFlow.Middlewares.Serializer; - using KafkaFlow.Middlewares.Serializer.Resolvers; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; - [TestClass] public class SerializerConsumerMiddlewareTests { - private Mock contextMock; - private Mock deserializerMock; - private Mock typeResolverMock; + private Mock _contextMock; + private Mock _deserializerMock; + private Mock _typeResolverMock; - private bool nextCalled; + private bool _nextCalled; - private DeserializerConsumerMiddleware target; + private DeserializerConsumerMiddleware _target; [TestInitialize] public void Setup() { - this.contextMock = new Mock(); - this.deserializerMock = new Mock(); - this.typeResolverMock = new Mock(); + _contextMock = new Mock(); + _deserializerMock = new Mock(); + _typeResolverMock = new Mock(); - this.target = new DeserializerConsumerMiddleware( - this.deserializerMock.Object, - this.typeResolverMock.Object); + _target = new DeserializerConsumerMiddleware( + _deserializerMock.Object, + _typeResolverMock.Object); } [TestMethod] public async Task Invoke_NullMessageType_ReturnWithoutCallingNext() { // Arrange - this.contextMock + _contextMock .SetupGet(x => x.Message) .Returns(new Message(new byte[1], new byte[1])); - this.typeResolverMock - .Setup(x => x.OnConsumeAsync(this.contextMock.Object)) + _typeResolverMock + .Setup(x => x.OnConsumeAsync(_contextMock.Object)) .ReturnsAsync((Type)null); // Act - await this.target.Invoke(this.contextMock.Object, _ => this.SetNextCalled()); + await _target.Invoke(_contextMock.Object, _ => this.SetNextCalled()); // Assert - this.nextCalled.Should().BeFalse(); - this.typeResolverMock.VerifyAll(); - this.contextMock.Verify(x => x.SetMessage(It.IsAny(), It.IsAny()), Times.Never); - this.deserializerMock.Verify( + _nextCalled.Should().BeFalse(); + _typeResolverMock.VerifyAll(); + _contextMock.Verify(x => x.SetMessage(It.IsAny(), It.IsAny()), Times.Never); + _deserializerMock.Verify( x => x.DeserializeAsync(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); } @@ -60,40 +60,40 @@ public async Task Invoke_NullMessageType_ReturnWithoutCallingNext() public async Task Invoke_NullMessage_CallNext() { // Arrange - this.contextMock + _contextMock .SetupGet(x => x.Message) .Returns(new Message(null, null)); // Act - await this.target.Invoke(this.contextMock.Object, _ => this.SetNextCalled()); + await _target.Invoke(_contextMock.Object, _ => this.SetNextCalled()); // Assert - this.nextCalled.Should().BeTrue(); - this.deserializerMock.Verify( + _nextCalled.Should().BeTrue(); + _deserializerMock.Verify( x => x.DeserializeAsync(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); - this.typeResolverMock.Verify(x => x.OnConsumeAsync(It.IsAny()), Times.Never); + _typeResolverMock.Verify(x => x.OnConsumeAsync(It.IsAny()), Times.Never); } [TestMethod] public void Invoke_NotByteArrayMessage_ThrowsInvalidOperationException() { // Arrange - this.contextMock + _contextMock .SetupGet(x => x.Message) .Returns(new Message(null, new TestMessage())); // Act - Func act = () => this.target.Invoke(this.contextMock.Object, _ => this.SetNextCalled()); + Func act = () => _target.Invoke(_contextMock.Object, _ => this.SetNextCalled()); // Assert act.Should().Throw(); - this.nextCalled.Should().BeFalse(); - this.contextMock.Verify(x => x.SetMessage(It.IsAny(), It.IsAny()), Times.Never); - this.deserializerMock.Verify( + _nextCalled.Should().BeFalse(); + _contextMock.Verify(x => x.SetMessage(It.IsAny(), It.IsAny()), Times.Never); + _deserializerMock.Verify( x => x.DeserializeAsync(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); - this.typeResolverMock.Verify(x => x.OnConsumeAsync(It.IsAny()), Times.Never); + _typeResolverMock.Verify(x => x.OnConsumeAsync(It.IsAny()), Times.Never); } [TestMethod] @@ -112,29 +112,29 @@ public async Task Invoke_ValidMessage_Deserialize() var transformedContextMock = new Mock(); IMessageContext resultContext = null; - this.contextMock + _contextMock .SetupGet(x => x.Message) .Returns(rawMessage); - this.contextMock + _contextMock .Setup(x => x.SetMessage(rawKey, deserializedMessage)) .Returns(transformedContextMock.Object); - this.typeResolverMock - .Setup(x => x.OnConsumeAsync(this.contextMock.Object)) + _typeResolverMock + .Setup(x => x.OnConsumeAsync(_contextMock.Object)) .ReturnsAsync(messageType); - this.deserializerMock + _deserializerMock .Setup(x => x.DeserializeAsync(It.IsAny(), messageType, It.IsAny())) .ReturnsAsync(deserializedMessage); - this.contextMock + _contextMock .SetupGet(x => x.ConsumerContext) .Returns(consumerContext.Object); // Act - await this.target.Invoke( - this.contextMock.Object, + await _target.Invoke( + _contextMock.Object, ctx => { resultContext = ctx; @@ -144,14 +144,14 @@ await this.target.Invoke( // Assert resultContext.Should().NotBeNull(); resultContext.Should().Be(transformedContextMock.Object); - this.contextMock.VerifyAll(); - this.deserializerMock.VerifyAll(); - this.typeResolverMock.VerifyAll(); + _contextMock.VerifyAll(); + _deserializerMock.VerifyAll(); + _typeResolverMock.VerifyAll(); } private Task SetNextCalled() { - this.nextCalled = true; + _nextCalled = true; return Task.CompletedTask; } diff --git a/src/KafkaFlow.UnitTests/Serializers/SerializerProducerMiddlewareTests.cs b/tests/KafkaFlow.UnitTests/Serializers/SerializerProducerMiddlewareTests.cs similarity index 53% rename from src/KafkaFlow.UnitTests/Serializers/SerializerProducerMiddlewareTests.cs rename to tests/KafkaFlow.UnitTests/Serializers/SerializerProducerMiddlewareTests.cs index c828b4504..061dccb9c 100644 --- a/src/KafkaFlow.UnitTests/Serializers/SerializerProducerMiddlewareTests.cs +++ b/tests/KafkaFlow.UnitTests/Serializers/SerializerProducerMiddlewareTests.cs @@ -1,58 +1,58 @@ +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using AutoFixture; +using FluentAssertions; +using KafkaFlow.Middlewares.Serializer; +using KafkaFlow.Middlewares.Serializer.Resolvers; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + namespace KafkaFlow.UnitTests.Serializers { - using System.IO; - using System.Linq; - using System.Threading.Tasks; - using AutoFixture; - using FluentAssertions; - using KafkaFlow.Middlewares.Serializer; - using KafkaFlow.Middlewares.Serializer.Resolvers; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using Moq; - [TestClass] public class SerializerProducerMiddlewareTests { - private readonly Fixture fixture = new(); + private readonly Fixture _fixture = new(); - private Mock contextMock; - private Mock serializerMock; - private Mock typeResolverMock; + private Mock _contextMock; + private Mock _serializerMock; + private Mock _typeResolverMock; - private SerializerProducerMiddleware target; + private SerializerProducerMiddleware _target; [TestInitialize] public void Setup() { - this.contextMock = new Mock(); - this.serializerMock = new Mock(); - this.typeResolverMock = new Mock(); + _contextMock = new Mock(); + _serializerMock = new Mock(); + _typeResolverMock = new Mock(); - this.target = new SerializerProducerMiddleware( - this.serializerMock.Object, - this.typeResolverMock.Object); + _target = new SerializerProducerMiddleware( + _serializerMock.Object, + _typeResolverMock.Object); } [TestMethod] public async Task Invoke_ValidMessage_Serialize() { // Arrange - var rawMessage = this.fixture.Create(); + var rawMessage = _fixture.Create(); var key = new object(); var deserializedMessage = new Message(key, new TestMessage()); IMessageContext resultContext = null; var producerContext = new Mock(); - producerContext.SetupGet(x=>x.Topic).Returns("test-topic"); + producerContext.SetupGet(x => x.Topic).Returns("test-topic"); var transformedContextMock = new Mock(); - this.contextMock + _contextMock .SetupGet(x => x.Message) .Returns(deserializedMessage); - this.typeResolverMock.Setup(x => x.OnProduceAsync(this.contextMock.Object)); + _typeResolverMock.Setup(x => x.OnProduceAsync(_contextMock.Object)); - this.serializerMock + _serializerMock .Setup( x => x.SerializeAsync( deserializedMessage.Value, @@ -60,17 +60,17 @@ public async Task Invoke_ValidMessage_Serialize() It.IsAny())) .Callback((object _, Stream stream, ISerializerContext _) => stream.WriteAsync(rawMessage)); - this.contextMock + _contextMock .Setup(x => x.SetMessage(key, It.Is(value => value.SequenceEqual(rawMessage)))) .Returns(transformedContextMock.Object); - this.contextMock + _contextMock .SetupGet(x => x.ProducerContext) .Returns(producerContext.Object); // Act - await this.target.Invoke( - this.contextMock.Object, + await _target.Invoke( + _contextMock.Object, ctx => { resultContext = ctx; @@ -80,9 +80,9 @@ await this.target.Invoke( // Assert resultContext.Should().NotBeNull(); resultContext.Should().Be(transformedContextMock.Object); - this.contextMock.VerifyAll(); - this.serializerMock.VerifyAll(); - this.typeResolverMock.VerifyAll(); + _contextMock.VerifyAll(); + _serializerMock.VerifyAll(); + _typeResolverMock.VerifyAll(); } private class TestMessage diff --git a/src/KafkaFlow.UnitTests/TypedHandler/HandlerTypeMappingTests.cs b/tests/KafkaFlow.UnitTests/TypedHandler/HandlerTypeMappingTests.cs similarity index 52% rename from src/KafkaFlow.UnitTests/TypedHandler/HandlerTypeMappingTests.cs rename to tests/KafkaFlow.UnitTests/TypedHandler/HandlerTypeMappingTests.cs index 90856c544..d5e34af58 100644 --- a/src/KafkaFlow.UnitTests/TypedHandler/HandlerTypeMappingTests.cs +++ b/tests/KafkaFlow.UnitTests/TypedHandler/HandlerTypeMappingTests.cs @@ -1,30 +1,30 @@ +using FluentAssertions; +using KafkaFlow.Middlewares.TypedHandler; +using Microsoft.VisualStudio.TestTools.UnitTesting; + namespace KafkaFlow.UnitTests.TypedHandler { - using FluentAssertions; - using KafkaFlow.Middlewares.TypedHandler; - using Microsoft.VisualStudio.TestTools.UnitTesting; - [TestClass] public class HandlerTypeMappingTests { - private HandlerTypeMapping target; + private HandlerTypeMapping _target; [TestInitialize] public void Setup() { - this.target = new HandlerTypeMapping(); + _target = new HandlerTypeMapping(); } [TestMethod] public void AddSeveralMappings_GetHandlersTypesReturnsListOfHandlers() { // Act - this.target.AddMapping(typeof(int), typeof(string)); - this.target.AddMapping(typeof(int), typeof(double)); - this.target.AddMapping(typeof(int), typeof(bool)); + _target.AddMapping(typeof(int), typeof(string)); + _target.AddMapping(typeof(int), typeof(double)); + _target.AddMapping(typeof(int), typeof(bool)); // Assert - this.target.GetHandlersTypes(typeof(int)) + _target.GetHandlersTypes(typeof(int)) .Should() .BeEquivalentTo( typeof(string), From f89ac3dabac6b0036092d73cabd36053b1f23c0e Mon Sep 17 00:00:00 2001 From: Joel Oliveira Date: Thu, 23 Nov 2023 15:06:27 +0000 Subject: [PATCH 18/20] docs: add v2 documentation to website docs --- website/docs/getting-started/installation.md | 1 + website/docs/guides/compression.md | 1 + website/docusaurus.config.js | 17 +- .../getting-started/_category_.json | 7 + .../create-your-first-application.md | 245 +++++++++++++++++ .../getting-started/installation.md | 91 ++++++ .../version-2.x/getting-started/packages.md | 56 ++++ .../version-2.x/getting-started/samples.md | 55 ++++ .../version-2.x/guides/_category_.json | 7 + .../version-2.x/guides/admin/_category_.json | 7 + .../version-2.x/guides/admin/admin.md | 15 + .../version-2.x/guides/admin/dashboard.md | 67 +++++ .../version-2.x/guides/admin/web-api.md | 259 ++++++++++++++++++ .../version-2.x/guides/authentication.md | 29 ++ .../version-2.x/guides/compression.md | 48 ++++ .../version-2.x/guides/configuration.md | 179 ++++++++++++ .../guides/consumers/_category_.json | 7 + .../guides/consumers/add-consumers.md | 150 ++++++++++ .../version-2.x/guides/consumers/consumers.md | 74 +++++ .../guides/dependency-injection.md | 22 ++ .../version-2.x/guides/global-events.md | 115 ++++++++ .../version-2.x/guides/logging.md | 52 ++++ .../guides/middlewares/_category_.json | 7 + .../middlewares/batch-consume-middleware.md | 67 +++++ .../middlewares/compressor-middleware.md | 47 ++++ .../consumer-throttling-middleware.md | 60 ++++ .../guides/middlewares/middlewares.md | 207 ++++++++++++++ .../middlewares/serializer-middleware.md | 132 +++++++++ .../middlewares/typed-handler-middleware.md | 116 ++++++++ .../version-2.x/guides/open-telemetry.md | 23 ++ .../version-2.x/guides/producers.md | 170 ++++++++++++ .../version-2.x/introduction.md | 52 ++++ .../reference/KafkaFlow.Admin/_category_.json | 7 + .../KafkaFlow.BatchConsume/_category_.json | 7 + .../KafkaFlow.Compressor/_category_.json | 7 + .../_category_.json | 7 + .../_category_.json | 7 + .../_category_.json | 7 + .../_category_.json | 7 + .../KafkaFlow.SchemaRegistry/_category_.json | 7 + .../_category_.json | 7 + .../_category_.json | 7 + .../_category_.json | 7 + .../_category_.json | 7 + .../_category_.json | 7 + .../_category_.json | 7 + .../KafkaFlow.Serializer/_category_.json | 7 + .../KafkaFlow.TypedHandler/_category_.json | 7 + .../reference/KafkaFlow.Unity/_category_.json | 7 + .../reference/KafkaFlow/_category_.json | 7 + .../version-2.x/reference/_category_.json | 7 + .../version-2.x-sidebars.json | 144 ++++++++++ website/versions.json | 3 + 53 files changed, 2661 insertions(+), 4 deletions(-) create mode 100644 website/versioned_docs/version-2.x/getting-started/_category_.json create mode 100644 website/versioned_docs/version-2.x/getting-started/create-your-first-application.md create mode 100644 website/versioned_docs/version-2.x/getting-started/installation.md create mode 100644 website/versioned_docs/version-2.x/getting-started/packages.md create mode 100644 website/versioned_docs/version-2.x/getting-started/samples.md create mode 100644 website/versioned_docs/version-2.x/guides/_category_.json create mode 100644 website/versioned_docs/version-2.x/guides/admin/_category_.json create mode 100644 website/versioned_docs/version-2.x/guides/admin/admin.md create mode 100644 website/versioned_docs/version-2.x/guides/admin/dashboard.md create mode 100644 website/versioned_docs/version-2.x/guides/admin/web-api.md create mode 100644 website/versioned_docs/version-2.x/guides/authentication.md create mode 100644 website/versioned_docs/version-2.x/guides/compression.md create mode 100644 website/versioned_docs/version-2.x/guides/configuration.md create mode 100644 website/versioned_docs/version-2.x/guides/consumers/_category_.json create mode 100644 website/versioned_docs/version-2.x/guides/consumers/add-consumers.md create mode 100644 website/versioned_docs/version-2.x/guides/consumers/consumers.md create mode 100644 website/versioned_docs/version-2.x/guides/dependency-injection.md create mode 100644 website/versioned_docs/version-2.x/guides/global-events.md create mode 100644 website/versioned_docs/version-2.x/guides/logging.md create mode 100644 website/versioned_docs/version-2.x/guides/middlewares/_category_.json create mode 100644 website/versioned_docs/version-2.x/guides/middlewares/batch-consume-middleware.md create mode 100644 website/versioned_docs/version-2.x/guides/middlewares/compressor-middleware.md create mode 100644 website/versioned_docs/version-2.x/guides/middlewares/consumer-throttling-middleware.md create mode 100644 website/versioned_docs/version-2.x/guides/middlewares/middlewares.md create mode 100644 website/versioned_docs/version-2.x/guides/middlewares/serializer-middleware.md create mode 100644 website/versioned_docs/version-2.x/guides/middlewares/typed-handler-middleware.md create mode 100644 website/versioned_docs/version-2.x/guides/open-telemetry.md create mode 100644 website/versioned_docs/version-2.x/guides/producers.md create mode 100644 website/versioned_docs/version-2.x/introduction.md create mode 100644 website/versioned_docs/version-2.x/reference/KafkaFlow.Admin/_category_.json create mode 100644 website/versioned_docs/version-2.x/reference/KafkaFlow.BatchConsume/_category_.json create mode 100644 website/versioned_docs/version-2.x/reference/KafkaFlow.Compressor/_category_.json create mode 100644 website/versioned_docs/version-2.x/reference/KafkaFlow.Extensions.Hosting/_category_.json create mode 100644 website/versioned_docs/version-2.x/reference/KafkaFlow.LogHandler.Console/_category_.json create mode 100644 website/versioned_docs/version-2.x/reference/KafkaFlow.LogHandler.Microsoft/_category_.json create mode 100644 website/versioned_docs/version-2.x/reference/KafkaFlow.Microsoft.DependencyInjection/_category_.json create mode 100644 website/versioned_docs/version-2.x/reference/KafkaFlow.SchemaRegistry/_category_.json create mode 100644 website/versioned_docs/version-2.x/reference/KafkaFlow.Serializer.JsonCore/_category_.json create mode 100644 website/versioned_docs/version-2.x/reference/KafkaFlow.Serializer.NewtonsoftJson/_category_.json create mode 100644 website/versioned_docs/version-2.x/reference/KafkaFlow.Serializer.ProtobufNet/_category_.json create mode 100644 website/versioned_docs/version-2.x/reference/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/_category_.json create mode 100644 website/versioned_docs/version-2.x/reference/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/_category_.json create mode 100644 website/versioned_docs/version-2.x/reference/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/_category_.json create mode 100644 website/versioned_docs/version-2.x/reference/KafkaFlow.Serializer/_category_.json create mode 100644 website/versioned_docs/version-2.x/reference/KafkaFlow.TypedHandler/_category_.json create mode 100644 website/versioned_docs/version-2.x/reference/KafkaFlow.Unity/_category_.json create mode 100644 website/versioned_docs/version-2.x/reference/KafkaFlow/_category_.json create mode 100644 website/versioned_docs/version-2.x/reference/_category_.json create mode 100644 website/versioned_sidebars/version-2.x-sidebars.json create mode 100644 website/versions.json diff --git a/website/docs/getting-started/installation.md b/website/docs/getting-started/installation.md index 08b40a7f7..4c491f7d9 100644 --- a/website/docs/getting-started/installation.md +++ b/website/docs/getting-started/installation.md @@ -25,6 +25,7 @@ Required Packages: - [KafkaFlow.LogHandler.Console](https://www.nuget.org/packages/KafkaFlow.LogHandler.Console/) You can quickly install them using .NET CLI 👇 + ```shell dotnet add package KafkaFlow dotnet add package KafkaFlow.Microsoft.DependencyInjection diff --git a/website/docs/guides/compression.md b/website/docs/guides/compression.md index 032e68b3a..b641990c4 100644 --- a/website/docs/guides/compression.md +++ b/website/docs/guides/compression.md @@ -9,6 +9,7 @@ In this section, we will learn how to configure Producer Compression in KafkaFlo KafkaFlow relies on the native message compression provided by the [Confluent Kafka client](https://github.com/confluentinc/confluent-kafka-dotnet). The following compression types are supported: + * Gzip * Snappy * Lz4 diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index 1cf75a8be..ad7f928be 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -34,10 +34,14 @@ const config = { ({ docs: { sidebarPath: require.resolve('./sidebars.js'), - // Please change this to your repo. - // Remove this to remove the "edit this page" links. - editUrl: - 'https://github.com/farfetch/kafkaflow/tree/master/website/', + editUrl: 'https://github.com/farfetch/kafkaflow/tree/master/website/', + lastVersion: 'current', + versions: { + current: { + label: '3.x', + path: '/', + }, + }, }, theme: { customCss: require.resolve('./src/css/custom.css'), @@ -63,6 +67,11 @@ const config = { height: 32, }, items: [ + { + type: 'docsVersionDropdown', + position: 'right', + dropdownActiveClassDisabled: false, + }, { type: 'doc', docId: 'introduction', diff --git a/website/versioned_docs/version-2.x/getting-started/_category_.json b/website/versioned_docs/version-2.x/getting-started/_category_.json new file mode 100644 index 000000000..20d34deee --- /dev/null +++ b/website/versioned_docs/version-2.x/getting-started/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "Getting Started", + "position": 2, + "link": { + "type": "generated-index" + } +} diff --git a/website/versioned_docs/version-2.x/getting-started/create-your-first-application.md b/website/versioned_docs/version-2.x/getting-started/create-your-first-application.md new file mode 100644 index 000000000..e8b1e295c --- /dev/null +++ b/website/versioned_docs/version-2.x/getting-started/create-your-first-application.md @@ -0,0 +1,245 @@ +--- +sidebar_position: 2 +sidebar_label: Quickstart +--- + + +# Quickstart: Create your first application with KafkaFlow + +In this article, you use C# and the .NET CLI to create two applications that will produce and consume events from Apache Kafka. + +By the end of the article, you will know how to use KafkaFlow to either Produce or Consume events from Apache Kafka. + + +## Prerequisites + + - [.NET 6.0 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) + - [Docker Desktop](https://www.docker.com/products/docker-desktop/) + +## Overview + +You will create two applications: + + 1. **Consumer:** Will be running waiting for incoming messages and will write them to the console. + 2. **Producer:** Will send a message every time you run the application. + +To connect them, you will be running an Apache Kafka cluster using Docker. + +## Steps + +### 1. Create a folder for your applications + +Create a new folder with the name _KafkaFlowQuickstart_. + +### 2. Setup Apache Kafka + +Inside the folder from step 1, create a `docker-compose.yml` file. You can download it from [here](../../../docker-compose.yml). + +### 3. Start the cluster + +Using your terminal of choice, start the cluster. + +```bash +docker-compose up -d +``` + +### 4. Create Producer Project + +Run the following command to create a Console Project named _Producer_. +```bash +dotnet new console --name Producer +``` + +### 5. Install KafkaFlow packages + +Inside the _Producer_ project directory, run the following commands to install the required packages. + +```bash +dotnet add package KafkaFlow +dotnet add package KafkaFlow.Microsoft.DependencyInjection +dotnet add package KafkaFlow.LogHandler.Console +dotnet add package KafkaFlow.TypedHandler +dotnet add package KafkaFlow.Serializer +dotnet add package KafkaFlow.Serializer.JsonCore +dotnet add package Microsoft.Extensions.DependencyInjection +``` + +### 6. Create the Message contract + +Add a new class file named _HelloMessage.cs_ and add the following example: + +```csharp +namespace Producer; + +public class HelloMessage +{ + public string Text { get; set; } = default!; +} +``` + +### 7. Create message sender + +Replace the content of the _Program.cs_ with the following example: + +```csharp +using Microsoft.Extensions.DependencyInjection; +using KafkaFlow.Producers; +using KafkaFlow.Serializer; +using KafkaFlow; +using Producer; + +var services = new ServiceCollection(); + +const string topicName = "sample-topic"; +const string producerName = "say-hello"; + +services.AddKafka( + kafka => kafka + .UseConsoleLog() + .AddCluster( + cluster => cluster + .WithBrokers(new[] { "localhost:9092" }) + .CreateTopicIfNotExists(topicName, 1, 1) + .AddProducer( + producerName, + producer => producer + .DefaultTopic(topicName) + .AddMiddlewares(m => + m.AddSerializer() + ) + ) + ) +); + +var serviceProvider = services.BuildServiceProvider(); + +var producer = serviceProvider + .GetRequiredService() + .GetProducer(producerName); + +await producer.ProduceAsync( + topicName, + Guid.NewGuid().ToString(), + new HelloMessage { Text = "Hello!" }); + + +Console.WriteLine("Message sent!"); + +``` + + +### 8. Create Consumer Project + +Run the following command to create a Console Project named _Consumer_. +```bash +dotnet new console --name Consumer +``` + +### 9. Add a reference to the Producer + +In order to access the message contract, add a reference to the Producer Project. + +Inside the _Consumer_ project directory, run the following commands to add the reference. + +```bash +dotnet add reference ../Producer +``` + +### 10. Install KafkaFlow packages + +Inside the _Consumer_ project directory, run the following commands to install the required packages. + +```bash +dotnet add package KafkaFlow +dotnet add package KafkaFlow.Microsoft.DependencyInjection +dotnet add package KafkaFlow.LogHandler.Console +dotnet add package KafkaFlow.TypedHandler +dotnet add package KafkaFlow.Serializer +dotnet add package KafkaFlow.Serializer.JsonCore +dotnet add package Microsoft.Extensions.DependencyInjection +``` + +### 11. Create a Message Handler + +Create a new class file named _HelloMessageHandler.cs_ and add the following example. + +```csharp +using KafkaFlow; +using KafkaFlow.TypedHandler; +using Producer; + +namespace Consumer; + +public class HelloMessageHandler : IMessageHandler +{ + public Task Handle(IMessageContext context, HelloMessage message) + { + Console.WriteLine( + "Partition: {0} | Offset: {1} | Message: {2}", + context.ConsumerContext.Partition, + context.ConsumerContext.Offset, + message.Text); + + return Task.CompletedTask; + } +} +``` + +### 12. Create the Message Consumer + +Replace the content of the _Program.cs_ with the following example. + +```csharp +using KafkaFlow; +using KafkaFlow.Serializer; +using Microsoft.Extensions.DependencyInjection; +using KafkaFlow.TypedHandler; +using Consumer; + +const string topicName = "sample-topic"; +var services = new ServiceCollection(); + +services.AddKafka(kafka => kafka + .UseConsoleLog() + .AddCluster(cluster => cluster + .WithBrokers(new[] { "localhost:9092" }) + .CreateTopicIfNotExists(topicName, 1, 1) + .AddConsumer(consumer => consumer + .Topic(topicName) + .WithGroupId("sample-group") + .WithBufferSize(100) + .WithWorkersCount(10) + .AddMiddlewares(middlewares => middlewares + .AddSerializer() + .AddTypedHandlers(h => h.AddHandler()) + ) + ) + ) +); + +var serviceProvider = services.BuildServiceProvider(); + +var bus = serviceProvider.CreateKafkaBus(); + +await bus.StartAsync(); + +Console.ReadKey(); + +await bus.StopAsync(); +``` + +### 13. Run! + +From the `KafkaFlowQuickstart` directory: + + 1. Run the Consumer: + +```bash +dotnet run --project Consumer/Consumer.csproj +``` + + 2. From another terminal, run the Producer: + +```bash +dotnet run --project Producer/Producer.csproj +``` \ No newline at end of file diff --git a/website/versioned_docs/version-2.x/getting-started/installation.md b/website/versioned_docs/version-2.x/getting-started/installation.md new file mode 100644 index 000000000..ef6b0cee0 --- /dev/null +++ b/website/versioned_docs/version-2.x/getting-started/installation.md @@ -0,0 +1,91 @@ +--- +sidebar_position: 1 +--- + + +# Installation + +KafkaFlow is a set of nuget packages. + +## Prerequisites + + - One of the following .NET versions + - .NET Core 2.1 or above. + - .NET Framework 4.6.1 or above. + + +## Installing + + +Install KafkaFlow using NuGet package management. + +Required Packages: + - [KafkaFlow](https://www.nuget.org/packages/KafkaFlow/) + - [KafkaFlow.Microsoft.DependencyInjection](https://www.nuget.org/packages/KafkaFlow.Microsoft.DependencyInjection/) + - [KafkaFlow.LogHandler.Console](https://www.nuget.org/packages/KafkaFlow.LogHandler.Console/) + +You can quickly install them using .NET CLI 👇 + +```shell +dotnet add package KafkaFlow +dotnet add package KafkaFlow.Microsoft.DependencyInjection +dotnet add package KafkaFlow.LogHandler.Console +``` + +You can find a complete list of the available packages [here](packages.md). + + +## Setup + +Types are in the `KafkaFlow` namespace. + +```csharp +using KafkaFlow; +using KafkaFlow.Producers; +using KafkaFlow.Serializer; +``` + +The host is configured using Dependency Injection. This is typically done once at application `Startup.cs` shown bellow, but you can find an example on how to do it with an [Hosted Service here](create-your-first-application.md). + +```csharp +public void ConfigureServices(IServiceCollection services) +{ + services.AddKafka(kafka => kafka + .UseConsoleLog() + .AddCluster(cluster => cluster + .WithBrokers(new[] { "localhost:9092" }) + .AddConsumer(consumer => consumer + .Topic("sample-topic") + .WithGroupId("sample-group") + .WithBufferSize(100) + .WithWorkersCount(10) + .AddMiddlewares(middlewares => middlewares + .AddSerializer() + .AddTypedHandlers(handlers => handlers + .AddHandler()) + ) + ) + .AddProducer("producer-name", producer => producer + .DefaultTopic("sample-topic") + .AddMiddlewares(middlewares => middlewares + .AddSerializer() + ) + ) + ) + ); +} + +public void Configure( + IApplicationBuilder app, + IWebHostEnvironment env, + IHostApplicationLifetime lifetime) +{ + var kafkaBus = app.ApplicationServices.CreateKafkaBus(); + + lifetime.ApplicationStarted.Register(() => kafkaBus.StartAsync(lifetime.ApplicationStopped)); +} +``` + +Now you can create Message Handlers or access Producers and start exchanging events trouh Kafka. + + diff --git a/website/versioned_docs/version-2.x/getting-started/packages.md b/website/versioned_docs/version-2.x/getting-started/packages.md new file mode 100644 index 000000000..198e8595e --- /dev/null +++ b/website/versioned_docs/version-2.x/getting-started/packages.md @@ -0,0 +1,56 @@ +--- +sidebar_position: 4 +--- + +# Packages + +## Core + +| Package | NuGet Stable | Downloads | +| ------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [KafkaFlow](https://www.nuget.org/packages/KafkaFlow/) | [![KafkaFlow](https://img.shields.io/nuget/v/KafkaFlow.svg)](https://www.nuget.org/packages/KafkaFlow/) | [![KafkaFlow](https://img.shields.io/nuget/dt/KafkaFlow.svg)](https://www.nuget.org/packages/KafkaFlow/) | +| [KafkaFlow.Abstractions](https://www.nuget.org/packages/KafkaFlow.Abstractions/) | [![KafkaFlow.Abstractions](https://img.shields.io/nuget/v/KafkaFlow.Abstractions.svg)](https://www.nuget.org/packages/KafkaFlow.Abstractions/) | [![KafkaFlow](https://img.shields.io/nuget/dt/KafkaFlow.Abstractions.svg)](https://www.nuget.org/packages/KafkaFlow.Abstractions/) | +| [KafkaFlow.Extensions.Hosting](https://www.nuget.org/packages/KafkaFlow.Extensions.Hosting/) | [![KafkaFlow.Extensions.Hosting](https://img.shields.io/nuget/v/KafkaFlow.Extensions.Hosting.svg)](https://www.nuget.org/packages/KafkaFlow.Extensions.Hosting/) | [![KafkaFlow](https://img.shields.io/nuget/dt/KafkaFlow.Extensions.Hosting.svg)](https://www.nuget.org/packages/KafkaFlow.Extensions.Hosting/) | +| [KafkaFlow.LogHandler.Console](https://www.nuget.org/packages/KafkaFlow.LogHandler.Console/) | [![KafkaFlow.LogHandler.Console](https://img.shields.io/nuget/v/KafkaFlow.LogHandler.Console.svg)](https://www.nuget.org/packages/KafkaFlow.LogHandler.Console/) | [![KafkaFlow.LogHandler.Console](https://img.shields.io/nuget/dt/KafkaFlow.LogHandler.Console.svg)](https://www.nuget.org/packages/KafkaFlow.LogHandler.Console/) | + +## Serialization + +| Package | NuGet Stable | Downloads | +| ---------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [KafkaFlow.Serializer](https://www.nuget.org/packages/KafkaFlow.Serializer/) | [![KafkaFlow.Serializer](https://img.shields.io/nuget/v/KafkaFlow.Serializer.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer/) | [![KafkaFlow.Serializer](https://img.shields.io/nuget/dt/KafkaFlow.Serializer.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer/) | +| [KafkaFlow.SchemaRegistry](https://www.nuget.org/packages/KafkaFlow.SchemaRegistry/) | [![KafkaFlow.SchemaRegistry](https://img.shields.io/nuget/v/KafkaFlow.SchemaRegistry.svg)](https://www.nuget.org/packages/KafkaFlow.SchemaRegistry/) | [![KafkaFlow.SchemaRegistry](https://img.shields.io/nuget/dt/KafkaFlow.SchemaRegistry.svg)](https://www.nuget.org/packages/KafkaFlow.SchemaRegistry/) | +| [KafkaFlow.Serializer.ProtobufNet](https://www.nuget.org/packages/KafkaFlow.Serializer.ProtobufNet/) | [![KafkaFlow.Serializer.ProtobufNet](https://img.shields.io/nuget/v/KafkaFlow.Serializer.ProtobufNet.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.ProtobufNet/) | [![KafkaFlow.Serializer.ProtobufNet](https://img.shields.io/nuget/dt/KafkaFlow.Serializer.ProtobufNet.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.ProtobufNet/) | +| [KafkaFlow.Serializer.JsonCore](https://www.nuget.org/packages/KafkaFlow.Serializer.JsonCore/) | [![KafkaFlow.Serializer.JsonCore](https://img.shields.io/nuget/v/KafkaFlow.Serializer.JsonCore.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.JsonCore/) | [![KafkaFlow.Serializer.JsonCore](https://img.shields.io/nuget/dt/KafkaFlow.Serializer.JsonCore.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.JsonCore/) | +| [KafkaFlow.Serializer.NewtonsoftJson](https://www.nuget.org/packages/KafkaFlow.Serializer.NewtonsoftJson/) | [![KafkaFlow.Serializer.NewtonsoftJson](https://img.shields.io/nuget/v/KafkaFlow.Serializer.NewtonsoftJson.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.NewtonsoftJson/) | [![KafkaFlow.Serializer.NewtonsoftJson](https://img.shields.io/nuget/dt/KafkaFlow.Serializer.NewtonsoftJson.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.NewtonsoftJson/) | +| [KafkaFlow.Serializer.SchemaRegistry.ConfluentJson](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/) | [![KafkaFlow.Serializer.SchemaRegistry.ConfluentJson](https://img.shields.io/nuget/v/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/) | [![KafkaFlow.Serializer.SchemaRegistry.ConfluentJson](https://img.shields.io/nuget/dt/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/) | +| [KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/) | [![KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro](https://img.shields.io/nuget/v/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/) | [![KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro](https://img.shields.io/nuget/dt/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/) | +| [KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/) | [![KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf](https://img.shields.io/nuget/v/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/) | [![KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf](https://img.shields.io/nuget/dt/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf.svg)](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/) | + +## Compression + +| Package | NuGet Stable | Downloads | +| ------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [KafkaFlow.Compressor](https://www.nuget.org/packages/KafkaFlow.Compressor/) | [![KafkaFlow.Compressor](https://img.shields.io/nuget/v/KafkaFlow.Compressor.svg)](https://www.nuget.org/packages/KafkaFlow.Compressor/) | [![KafkaFlow.Compressor](https://img.shields.io/nuget/dt/KafkaFlow.Compressor.svg)](https://www.nuget.org/packages/KafkaFlow.Compressor/) | +| [KafkaFlow.Compressor.Gzip](https://www.nuget.org/packages/KafkaFlow.Compressor.Gzip/) | [![KafkaFlow.Compressor.Gzip](https://img.shields.io/nuget/v/KafkaFlow.Compressor.Gzip.svg)](https://www.nuget.org/packages/KafkaFlow.Compressor.Gzip/) | [![KafkaFlow.Compressor.Gzip](https://img.shields.io/nuget/dt/KafkaFlow.Compressor.Gzip.svg)](https://www.nuget.org/packages/KafkaFlow.Compressor.Gzip/) | + +## Middlewares + +| Package | NuGet Stable | Downloads | +| ------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [KafkaFlow.TypedHandler](https://www.nuget.org/packages/KafkaFlow.TypedHandler/) | [![KafkaFlow.TypedHandler](https://img.shields.io/nuget/v/KafkaFlow.TypedHandler.svg)](https://www.nuget.org/packages/KafkaFlow.TypedHandler/) | [![KafkaFlow.TypedHandler](https://img.shields.io/nuget/dt/KafkaFlow.TypedHandler.svg)](https://www.nuget.org/packages/KafkaFlow.TypedHandler/) | +| [KafkaFlow.BatchConsume](https://www.nuget.org/packages/KafkaFlow.BatchConsume/) | [![KafkaFlow.BatchConsume](https://img.shields.io/nuget/v/KafkaFlow.BatchConsume.svg)](https://www.nuget.org/packages/KafkaFlow.BatchConsume/) | [![KafkaFlow.BatchConsume](https://img.shields.io/nuget/dt/KafkaFlow.BatchConsume.svg)](https://www.nuget.org/packages/KafkaFlow.BatchConsume/) | + +## Dependency Injection + +| Package | NuGet Stable | Downloads | +| ------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [KafkaFlow.Microsoft.DependencyInjection](https://www.nuget.org/packages/KafkaFlow.Microsoft.DependencyInjection/) | [![KafkaFlow.Microsoft.DependencyInjection](https://img.shields.io/nuget/v/KafkaFlow.Microsoft.DependencyInjection.svg)](https://www.nuget.org/packages/KafkaFlow.Microsoft.DependencyInjection/) | [![KafkaFlow.Microsoft.DependencyInjection](https://img.shields.io/nuget/dt/KafkaFlow.Microsoft.DependencyInjection.svg)](https://www.nuget.org/packages/KafkaFlow.Microsoft.DependencyInjection/) | +| [KafkaFlow.Unity](https://www.nuget.org/packages/KafkaFlow.Unity/) | [![KafkaFlow.Unity](https://img.shields.io/nuget/v/KafkaFlow.Unity.svg)](https://www.nuget.org/packages/KafkaFlow.Unity/) | [![KafkaFlow.Unity](https://img.shields.io/nuget/dt/KafkaFlow.Unity.svg)](https://www.nuget.org/packages/KafkaFlow.Unity/) | + +## Administration + +| Package | NuGet Stable | Downloads | +| ------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [KafkaFlow.Admin](https://www.nuget.org/packages/KafkaFlow.Admin/) | [![KafkaFlow.Admin](https://img.shields.io/nuget/v/KafkaFlow.Admin.svg)](https://www.nuget.org/packages/KafkaFlow.Admin/) | [![KafkaFlow.Admin](https://img.shields.io/nuget/dt/KafkaFlow.Admin.svg)](https://www.nuget.org/packages/KafkaFlow.Admin/) | +| [KafkaFlow.Admin.WebApi](https://www.nuget.org/packages/KafkaFlow.Admin.WebApi/) | [![KafkaFlow.Admin.WebApi](https://img.shields.io/nuget/v/KafkaFlow.Admin.WebApi.svg)](https://www.nuget.org/packages/KafkaFlow.Admin.WebApi/) | [![KafkaFlow.Admin.WebApi](https://img.shields.io/nuget/dt/KafkaFlow.Admin.WebApi.svg)](https://www.nuget.org/packages/KafkaFlow.Admin.WebApi/) | +| [KafkaFlow.Admin.Dashboard](https://www.nuget.org/packages/KafkaFlow.Admin.Dashboard/) | [![KafkaFlow.Admin.Dashboard](https://img.shields.io/nuget/v/KafkaFlow.Admin.Dashboard.svg)](https://www.nuget.org/packages/KafkaFlow.Admin.Dashboard/) | [![KafkaFlow.Admin.Dashboard](https://img.shields.io/nuget/dt/KafkaFlow.Admin.Dashboard.svg)](https://www.nuget.org/packages/KafkaFlow.Admin.Dashboard/) | \ No newline at end of file diff --git a/website/versioned_docs/version-2.x/getting-started/samples.md b/website/versioned_docs/version-2.x/getting-started/samples.md new file mode 100644 index 000000000..aba90fd4a --- /dev/null +++ b/website/versioned_docs/version-2.x/getting-started/samples.md @@ -0,0 +1,55 @@ +--- +sidebar_position: 5 +--- + +# Samples + +We know that working code is a valuable learning tool for many, so here you can find a list of samples built to demonstrate KafkaFlow capabilities. + +## Basic + +This is a simple sample that shows how to produce and consume messages. + +You can find the code here: [/samples/KafkaFlow.Sample](https://github.com/Farfetch/kafkaflow/tree/master/samples/KafkaFlow.Sample) + +## Batching + +This is a sample that shows batch processing using KafkaFlow. + +You can find the code here: [/samples/KafkaFlow.Sample.BatchOperations](https://github.com/Farfetch/kafkaflow/tree/master/samples/KafkaFlow.Sample.BatchOperations) + +## Schema Registry + +This is a sample that shows how to use Schema Registry with KafkaFlow. + +You can find the code here: [/samples/KafkaFlow.Sample](https://github.com/Farfetch/kafkaflow/tree/master/samples/KafkaFlow.Sample.SchemaRegistry) + +## Web API + +This sample shows how to host an administration Web API for administrative operations. + +You can find the code here: [/samples/KafkaFlow.Sample](https://github.com/Farfetch/kafkaflow/tree/master/samples/KafkaFlow.Sample.WebApi) + +## Dashboard + +This sample shows how to use KafkaFlow to expose an administration Dashboard. + +You can find the code here: [/samples/KafkaFlow.Sample](https://github.com/Farfetch/kafkaflow/tree/master/samples/KafkaFlow.Sample.Dashboard) + +## Flow of Control + +This is a sample that shows how to control the state of a consumer (Starting, Pausing, Stopping, etc.) programmatically. + +You can find the code here: [/samples/KafkaFlow.Sample.FlowControl](https://github.com/Farfetch/kafkaflow/tree/master/samples/KafkaFlow.Sample.FlowControl) + +## Pause Consumer on Error + +This is a sample that shows how to stop the consumer when an exception is raised. + +You can find the code here: [/samples/KafkaFlow.Sample.PauseConsumerOnError](https://github.com/Farfetch/kafkaflow/tree/master/samples/KafkaFlow.Sample.PauseConsumerOnError) + +## Consumer Throttling + +This is a sample that shows how to throttle a consumer based on others consumers lag + +You can find the code here: [/samples/KafkaFlow.Sample.ConsumerThrottling](https://github.com/Farfetch/kafkaflow/tree/master/samples/KafkaFlow.Sample.ConsumerThrottling) diff --git a/website/versioned_docs/version-2.x/guides/_category_.json b/website/versioned_docs/version-2.x/guides/_category_.json new file mode 100644 index 000000000..f389501a2 --- /dev/null +++ b/website/versioned_docs/version-2.x/guides/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "Guides", + "position": 3, + "link": { + "type": "generated-index" + } +} diff --git a/website/versioned_docs/version-2.x/guides/admin/_category_.json b/website/versioned_docs/version-2.x/guides/admin/_category_.json new file mode 100644 index 000000000..c4631cb9f --- /dev/null +++ b/website/versioned_docs/version-2.x/guides/admin/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "Administration", + "position": 8, + "link": { + "type": "generated-index" + } + } \ No newline at end of file diff --git a/website/versioned_docs/version-2.x/guides/admin/admin.md b/website/versioned_docs/version-2.x/guides/admin/admin.md new file mode 100644 index 000000000..8f99a8ab0 --- /dev/null +++ b/website/versioned_docs/version-2.x/guides/admin/admin.md @@ -0,0 +1,15 @@ +--- +sidebar_position: 1 +--- + +# Administration + +In this section, we will learn about KafkaFlow administration features. + +KafkaFlow provides an administrative infrastructure that you can use to get details about KafkaFlow consumers and perform administration tasks over them. + +There are two methods you can use: + - The [Administration Web API](web-api). + - The [Dashboard](dashboard). + + diff --git a/website/versioned_docs/version-2.x/guides/admin/dashboard.md b/website/versioned_docs/version-2.x/guides/admin/dashboard.md new file mode 100644 index 000000000..ddad1bd90 --- /dev/null +++ b/website/versioned_docs/version-2.x/guides/admin/dashboard.md @@ -0,0 +1,67 @@ +--- +sidebar_position: 3 +--- + +# Dashboard + +In this section, we will learn how to configure the Dashboard. + +KafkaFlow provides a Dashboard where you can visualize information related to your consumers and use all operations available on [KafkaFlow.Admin.WebApi](web-api). + +:::caution +It is important to note that the Dashboard runs, shows information, and manages the consumers on all application instances. This means that if you have 10 machines running your application, the Dashboard will run in every instance. **Any operation will affect the consumer in all the machines**. +:::caution + +## Adding the Dashboard + +Install the following packages: +* [KafkaFlow.Admin](https://www.nuget.org/packages/KafkaFlow.Admin/) +* [KafkaFlow.Admin.WebApi](https://www.nuget.org/packages/KafkaFlow.Admin.WebApi/) +* [KafkaFlow.Admin.Dashboard](https://www.nuget.org/packages/KafkaFlow.Admin.Dashboard/) + +```bash +dotnet add package KafkaFlow.Microsoft.DependencyInjection +dotnet add package KafkaFlow.Admin +dotnet add package KafkaFlow.Admin.WebApi +dotnet add package KafkaFlow.Admin.Dashboard +``` + + +You can configure the Dashboard during the [configuration](../configuration), as shown in the following example (*built using .NET 6*). + +```csharp +using KafkaFlow; +using KafkaFlow.Admin.Dashboard; + +var builder = WebApplication.CreateBuilder(args); + +builder.Services + .AddKafka(kafka => kafka + .AddCluster(cluster => cluster + .WithBrokers(new[] { "localhost:9092" }) + .AddConsumer(consumer => consumer + .Topic("mytopic") + .WithGroupId("g1") + .WithWorkersCount(1) + .WithBufferSize(10) + ) + .EnableAdminMessages("kafka-flow.admin") + .EnableTelemetry("kafka-flow.admin") // you can use the same topic used in EnableAdminMessages, if need it + )) + .AddControllers(); + +var app = builder.Build(); + +app.MapControllers(); +app.UseKafkaFlowDashboard(); + +var kafkaBus = app.Services.CreateKafkaBus(); +await kafkaBus.StartAsync(); + +await app.RunAsync(); +``` + +The dashboard UI will be available at `/kafka-flow` and is refreshed every 5 seconds with telemetry data available at the endpoint `/kafka-flow/telemetry`. + +![image](https://user-images.githubusercontent.com/233064/124478023-1d773680-dd7b-11eb-89e4-41a1f4f36a6f.png) + diff --git a/website/versioned_docs/version-2.x/guides/admin/web-api.md b/website/versioned_docs/version-2.x/guides/admin/web-api.md new file mode 100644 index 000000000..bc10878fe --- /dev/null +++ b/website/versioned_docs/version-2.x/guides/admin/web-api.md @@ -0,0 +1,259 @@ +--- +sidebar_position: 2 +sidebar_label: Web API +--- + +# Administration Web API + +In this section, we will learn how to configure the Administration Web API. + +You can configure KafkaFlow to expose an API for administrative operations. + +The API can be used either manually (for example, you can install and use [Swagger](#swagger)) or by any other application using the available endpoints. + +Furthermore, you can execute the operations publishing commands directly to the KafkaFlow admin topics using the class `AdminProducer`. + + +:::caution +It is important to note that these operations will be executed on all application instances. If you have 10 machines running your application, **one single POST** to pause a specific consumer will pause it in **all** the machines. +::: + + +## Adding the Admin API + +Install the following packages: +* [KafkaFlow.Admin](https://www.nuget.org/packages/KafkaFlow.Admin/) +* [KafkaFlow.Admin.WebApi](https://www.nuget.org/packages/KafkaFlow.Admin.WebApi/) + +```bash +dotnet add package KafkaFlow.Microsoft.DependencyInjection +dotnet add package KafkaFlow.Admin +dotnet add package KafkaFlow.Admin.WebApi +``` + +You can configure the API during the [configuration](../configuration) by enabling Admin Messages on the Cluster configuration, as shown in the following example (*built using .NET 6*). + +```csharp +using KafkaFlow; + +var builder = WebApplication.CreateBuilder(args); + +builder.Services + .AddKafka(kafka => kafka + .AddCluster(cluster => cluster + .WithBrokers(new[] { "localhost:9092" }) + .AddConsumer(consumer => consumer + .Topic("mytopic") + .WithGroupId("g1") + .WithWorkersCount(1) + .WithBufferSize(10) + ) + .EnableAdminMessages( + "kafka-flow.admin" // the admin topic + ) + )) + .AddControllers(); + +var app = builder.Build(); + +app.MapControllers(); + +var kafkaBus = app.Services.CreateKafkaBus(); +await kafkaBus.StartAsync(); + +await app.RunAsync(); +``` + +The API will be accessed on `/kafka-flow/`. + +## Adding Swagger to Admin API {#swagger} + +It's possible to generate a [Swagger](https://swagger.io/) interface for documentation and as UI to explore and test operations. + +:::info +This is not a KafkaFlow feature. This guide works as a starting guide on how to configure it using [Swashbuckle](https://github.com/domaindrivendev/Swashbuckle.AspNetCore). +For advanced information on it, go to Swashbuckle documentation. +::: + +Install Swashbuckle package. + +```bash +dotnet add package Swashbuckle.AspNetCore +``` + +Register the Swagger Generator on the services configuration. + +```csharp +using Microsoft.OpenApi.Models; + +builder.Services + .AddSwaggerGen( + c => + { + c.SwaggerDoc( + "kafka-flow", + new OpenApiInfo + { + Title = "KafkaFlow Admin", + Version = "kafka-flow", + }); + }); +``` + +Expose the generated documentation. + +```bash +app.UseSwagger(); +app.UseSwaggerUI(c => +{ + c.SwaggerEndpoint("/swagger/kafka-flow/swagger.json", "KafkaFlow Admin"); +}); +``` + +Swagger UI will be accessed on `/swagger/`. + + +## API Endpoints + +![admin-swagger-1](https://user-images.githubusercontent.com/233064/98698756-5129ca00-236e-11eb-9a70-e0f997050cd6.jpg) + +### Consumers + +#### Start +Start a consumer based on his name. + +Command +```csharp +var consumerAdmin = provider.GetService(); +await consumerAdmin.StartConsumerAsync(consumerName); +``` + +#### Stop +Stop a consumer based on his name. + +Command +```csharp +var consumerAdmin = provider.GetService(); +await consumerAdmin.StopConsumerAsync(consumerName); +``` + +#### Pause +Pause all Kafka consumers based on their name and groupId. + +Endpoint + +`POST /kafka-flow/groups/{groupId}/consumers/{consumerName}/pause` + +Command +```csharp +var consumerAdmin = provider.GetService(); +await consumerAdmin.PauseConsumerAsync(consumerName, new []{ topicName }); +``` + +#### Resume +Resume all Kafka consumers based on their name and groupId. + +Endpoint + +`POST /kafka-flow/groups/{groupId}/consumers/{consumerName}/resume` + +Command +```csharp +var consumerAdmin = provider.GetService(); +await consumerAdmin.ResumeConsumerAsync(consumerName, new []{ topicName }); +``` + +#### Restart +Restart all Kafka consumers based on their. This operation will not change any offsets, it's a simple restart. The internal Confluent Consumer will be recreated. This operation causes a partition rebalanced between the consumers. + +Endpoint + +`POST /kafka-flow/groups/{groupId}/consumers/{consumerName}/restart` + +Command +```csharp +var consumerAdmin = provider.GetService(); +await consumerAdmin.RestartConsumerAsync(consumerName); +``` + +#### Reset Offsets +Reset the offset of all topics listening by the Kafka consumers with the name and groupId informed. To achieve this, KafkaFlow needs to stop the consumers, search for the lowest offset value in each topic/partition, commit these offsets, and restart the consumers. This operation causes a rebalance between the consumers. ** All topic messages will be reprocessed ** + +Endpoint + +`POST /kafka-flow/groups/{groupId}/consumers/{consumerName}/reset-offsets` + +Command +```csharp +var consumerAdmin = provider.GetService(); +await consumerAdmin.ResetOffsetsAsync(consumerName, new []{ topicName }); +``` + +#### Rewind Offsets +Rewind the offset of all topics listening by a Kafka consumer with its name and groupId. To achieve this, KafkaFlow needs to stop the consumers, search for the first offset before the DateTime informed, commit the new offsets, and restart the consumers. This operation causes a rebalance between the consumers. + +Endpoint + +``` +POST /kafka-flow/groups/{groupId}/consumers/{consumerName}/rewind-offsets-to-date + +BODY +{ + "date": "2000-11-09T17:52:54.547Z" +} + +``` + +Command +```csharp +var consumerAdmin = provider.GetService(); +await consumerAdmin.RewindOffsetsAsync(consumerName, DateTime.Today.AddDays(-1), new []{ topicName }); +``` +#### Change the Number of Workers​ +Change the numbers of workers (degree of parallelism) for the KafkaFlow consumer with the name and groupId informed. This operation causes a rebalance between the consumers. + +Endpoint + +``` +POST /kafka-flow/groups/{groupId}/consumers/{consumerName}/change-worker-count + +BODY +{ + "workerCount": 0 +} + +``` + +Command +```csharp +var consumerAdmin = provider.GetService(); +await consumerAdmin.ChangeWorkersCountAsync(consumerName, 100); +``` + +### Consumer Group + +#### Pause +Pause all Kafka consumers based on their groupId. + +Endpoint + +`POST /kafka-flow/groups/{groupId}/pause` + +Command +```csharp +var consumerAdmin = provider.GetService(); +await consumerAdmin.PauseConsumerGroupAsync(groupId, new []{ topicName }); +``` + +#### Resume +Resume all Kafka consumers based on groupId. + +Endpoint + +`POST /kafka-flow/groups/{groupId}/resume` + +Command +```csharp +var consumerAdmin = provider.GetService(); +await consumerAdmin.ResumeConsumerGroupAsync(groupId, new []{ topicName }); +``` diff --git a/website/versioned_docs/version-2.x/guides/authentication.md b/website/versioned_docs/version-2.x/guides/authentication.md new file mode 100644 index 000000000..7decd8f87 --- /dev/null +++ b/website/versioned_docs/version-2.x/guides/authentication.md @@ -0,0 +1,29 @@ +--- +sidebar_position: 8 +--- + +# Authentication + +To produce and consume messages to/from authenticated brokers you have to configure the cluster with security information in the application setup. + +KafkaFlow sends all the security information to [Confluent Kafka Client](https://github.com/confluentinc/confluent-kafka-dotnet) so more information about it can be found [here](https://github.com/edenhill/librdkafka/blob/master/CONFIGURATION.md). + +```csharp + services.AddKafka( + kafka => kafka + .AddCluster( + cluster => cluster + .WithBrokers(new[] {"localhost:9092"}) + .WithSchemaRegistry(config => config.Url = "localhost:8081") + .WithSecurityInformation(information => + { + information.SaslMechanism = SaslMechanism.Plain; + information.SaslPassword = "pwd"; + information.SaslUsername = "user"; + information.SecurityProtocol = SecurityProtocol.SaslPlaintext; + information.EnableSslCertificateVerification = true; + ... + }) + ... + ... +``` diff --git a/website/versioned_docs/version-2.x/guides/compression.md b/website/versioned_docs/version-2.x/guides/compression.md new file mode 100644 index 000000000..b641990c4 --- /dev/null +++ b/website/versioned_docs/version-2.x/guides/compression.md @@ -0,0 +1,48 @@ +--- +sidebar_position: 5 +--- + +# Compression + +In this section, we will learn how to configure Producer Compression in KafkaFlow. + +KafkaFlow relies on the native message compression provided by the [Confluent Kafka client](https://github.com/confluentinc/confluent-kafka-dotnet). + +The following compression types are supported: + +* Gzip +* Snappy +* Lz4 +* Zstd + +```csharp +.WithCompression(CompressionType.Gzip) +``` + +:::info +If you want to use a different compression type, visit the [Compressor Middleware guide](middlewares/compressor-middleware). +::: + +Optionally, it's possible to specify the compression level, providing it as the second argument. +You can find the possible values [here](https://docs.confluent.io/platform/current/clients/confluent-kafka-dotnet/_site/api/Confluent.Kafka.ProducerConfig.html#Confluent_Kafka_ProducerConfig_CompressionLevel). + +```csharp +.WithCompression(CompressionType.Gzip, 5) +``` + +:::info +The configuration must be done only by the producers. The consumers will identify compressed messages and decompress them automatically. +::: + +```csharp +services.AddKafka(kafka => kafka + .AddCluster(cluster => cluster + .WithBrokers(new[] { "localhost:9092" }) + .AddProducer(producer => producer + .WithCompression(CompressionType.Gzip) + ... + ) + ) + ) +); +``` diff --git a/website/versioned_docs/version-2.x/guides/configuration.md b/website/versioned_docs/version-2.x/guides/configuration.md new file mode 100644 index 000000000..c40118981 --- /dev/null +++ b/website/versioned_docs/version-2.x/guides/configuration.md @@ -0,0 +1,179 @@ +--- +sidebar_position: 0 +--- + +# Configuration + +In this section, we will introduce how configuration is done in KafkaFlow. + +KafkaFlow is a highly configured framework. You can customize it through a Fluent Builder. + +Using the builder, you can configure [Logging](../guides/logging.md), [Global Events](../guides/global-events.md), Clusters, Producers, Consumers and others. + +There are a few options to configure KafkaFlow: + - [Using a Hosted Service](#hosted-service) + - [Using ASP.NET Core Startup](#aspnet-core-startup) + - [Using Startup.cs](#startup-class) + - [Using other DI Container (Unity or other)](#other-di-container) + + +## Using a Hosted Service {#hosted-service} + +The Hosted Service model can be used as a hosting model on applications like Console apps. + +Add the required package references: + +```bash +dotnet add package KafkaFlow +dotnet add package KafkaFlow.Extensions.Hosting +dotnet add package KafkaFlow.Microsoft.DependencyInjection +dotnet add package Microsoft.Extensions.Hosting +``` + +Register KafkaFlow Hosted Service: + +```csharp +using KafkaFlow; +using Microsoft.Extensions.Hosting; + +public static class Program +{ + private static async Task Main(string[] args) + { + await Host + .CreateDefaultBuilder(args) + .ConfigureServices((hostContext, services) => + { + services.AddKafkaFlowHostedService(kafka => kafka + .AddCluster(cluster => cluster + .WithBrokers(new[] { "localhost:9092" }) + ... + ) + ); + }) + .Build() + .RunAsync(); + } +} +``` + + +## Using ASP.NET Core Startup {#aspnet-core-startup} + +After .NET 6 the `Startup.cs` class is not required. + +Add the required package references: + +```bash +dotnet add package KafkaFlow +dotnet add package KafkaFlow.Microsoft.DependencyInjection +``` + +To configure KafkaFlow, use the builder to register KafkaFlow dependencies and start the Kafka Bus before the application run. + +```csharp +using KafkaFlow; + +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddKafka(kafka => kafka + .AddCluster(cluster => cluster + .WithBrokers(new[] { "localhost:9092" }) + ... + ) +); + +var app = builder.Build(); + +app.MapGet("/", () => "Hello World!"); + +var kafkaBus = app.Services.CreateKafkaBus(); +await kafkaBus.StartAsync(); + +app.Run(); +``` + + +## Using Startup.cs {#startup-class} + +Add the required package references: + +```bash +dotnet add package KafkaFlow +dotnet add package KafkaFlow.Microsoft.DependencyInjection +``` + +To configure KafkaFlow, use the `ConfigureServices` method to register KafkaFlow dependencies, and on the `Configure` method register an event to start the Kafka Bus on application start. + +```csharp +public void ConfigureServices(IServiceCollection services) +{ + services.AddKafka(kafka => kafka + .UseConsoleLog() + .AddCluster(cluster => cluster + .WithBrokers(new[] { "localhost:9092" }) + ... + ) + ); +} + +public void Configure( + IApplicationBuilder app, + IWebHostEnvironment env, + IHostApplicationLifetime lifetime) +{ + var kafkaBus = app.ApplicationServices.CreateKafkaBus(); + + lifetime.ApplicationStarted.Register(() => kafkaBus.StartAsync(lifetime.ApplicationStopped)); +} +``` + + +## Using other DI Container (Unity or other) {#other-di-container} + +:::info + +If you want to use a DI container other than Unity, check [how to implement](dependency-injection.md) it first. + +::: + +Add the required package references: + +```bash +dotnet add package KafkaFlow +dotnet add package KafkaFlow.Unity +``` + +Use `KafkaFlowConfigurator` to specify the desired Dependency Injection container: + +```csharp +using KafkaFlow.Configuration; +using KafkaFlow.Unity; +using Unity; + + +static class Program +{ + public static async Task Main(string[] args) + { + var container = new UnityContainer(); + + var configurator = new KafkaFlowConfigurator( + new UnityDependencyConfigurator(container), + kafka => kafka + .AddCluster(cluster => cluster + .WithBrokers(new[] { "localhost:9092" }) + ... + ) + ); + + var bus = configurator.CreateBus(new UnityDependencyResolver(container)); + + // Call when your app starts + await bus.StartAsync(); + + // Call when your app stops + await bus.StopAsync(); + } +} +``` \ No newline at end of file diff --git a/website/versioned_docs/version-2.x/guides/consumers/_category_.json b/website/versioned_docs/version-2.x/guides/consumers/_category_.json new file mode 100644 index 000000000..b675e87f6 --- /dev/null +++ b/website/versioned_docs/version-2.x/guides/consumers/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "Consumers", + "position": 3, + "link": { + "type": "generated-index" + } + } \ No newline at end of file diff --git a/website/versioned_docs/version-2.x/guides/consumers/add-consumers.md b/website/versioned_docs/version-2.x/guides/consumers/add-consumers.md new file mode 100644 index 000000000..0d2ae78bd --- /dev/null +++ b/website/versioned_docs/version-2.x/guides/consumers/add-consumers.md @@ -0,0 +1,150 @@ +--- +sidebar_position: 2 +--- + +# Add Consumers + +In this section, we will learn how to add and configure a Consumer on KafkaFlow. + +To add a consumer, you need to configure the Topic that the consumer will be listening to and the Consumer Group that will be part of. You can find an example below. + + +```csharp +using KafkaFlow; +using Microsoft.Extensions.DependencyInjection; + +services.AddKafka(kafka => kafka + .AddCluster(cluster => cluster + .WithBrokers(new[] { "localhost:9092" }) + .AddConsumer(consumer => consumer + .Topic("topic-name") + .WithGroupId("sample-group") + .WithBufferSize(100) + .WithWorkersCount(10) + .AddMiddlewares(middlewares => middlewares + ... + ) + ) + ) +); +``` + +On a Consumer, you can configure the Middlewares that will be invoked. You can find more information on how to configure Middlewares [here](../middlewares). + +## Automatic Partitions Assignment + +Using the `Topic()` or `Topics()` methods, the consumer will trigger the automatic partition assignment that will distribute the topic partitions across the application instances. + + +```csharp +using KafkaFlow; +using KafkaFlow.Serializer; +using Microsoft.Extensions.DependencyInjection; +using KafkaFlow.TypedHandler; + +services.AddKafka(kafka => kafka + .AddCluster(cluster => cluster + .WithBrokers(new[] { "localhost:9092" }) + .AddConsumer(consumer => consumer + .Topic("topic-name") + .WithGroupId("sample-group") + ... + ) + ) +); +``` + +## Manual Partitions Assignment + +The client application can specify the topic partitions manually using the `ManualAssignPartitions()` method instead of using the `Topic()` or `Topics()` methods. + + +```csharp +using KafkaFlow; +using KafkaFlow.Serializer; +using Microsoft.Extensions.DependencyInjection; +using KafkaFlow.TypedHandler; + +services.AddKafka(kafka => kafka + .AddCluster(cluster => cluster + .WithBrokers(new[] { "localhost:9092" }) + .AddConsumer(consumer => consumer + .ManualAssignPartitions("topic-name", new[] { 1, 2, 3 }) + ... + ) + ) +); +``` + +## Offset Strategy + +You can configure the Offset Strategy for a consumer group in case the Consumer Group has no offset stored in Kafka. +There are two options: + - Earliest: Reads from the beginning of the Topic. + - Latest: Only reads new messages. + +```csharp +using KafkaFlow; +using Microsoft.Extensions.DependencyInjection; + +services.AddKafka(kafka => kafka + .AddCluster(cluster => cluster + .WithBrokers(new[] { "localhost:9092" }) + .AddConsumer(consumer => consumer + .Topic("topic-name") + .WithGroupId("sample-group") + .WithAutoOffsetReset(AutoOffsetReset.Earliest) + ... + ) + ) +); +``` + +## Store Offsets Manually + +By default, offsets are stored after the handler and middleware execution automatically. +This is the equivalent to configure the consumer as `WithAutoStoreOffsets()`. + +To control Offset storing, it's possible to configure using `WithManualStoreOffsets()` as the following example: + + +```csharp +using KafkaFlow; +using Microsoft.Extensions.DependencyInjection; + +services.AddKafka(kafka => kafka + .AddCluster(cluster => cluster + .WithBrokers(new[] { "localhost:9092" }) + .AddConsumer(consumer => consumer + .Topic("topic-name") + .WithGroupId("sample-group") + .WithManualStoreOffsets() + ... + ) + ) +); +``` + +## Disable Store Offsets + +In a scenario where storing offsets it's not needed, you can disable it by calling the `WithoutStoringOffsets()` method in the consumer setup. + + +```csharp +using KafkaFlow; +using KafkaFlow.Serializer; +using Microsoft.Extensions.DependencyInjection; +using KafkaFlow.TypedHandler; + +services.AddKafka(kafka => kafka + .AddCluster(cluster => cluster + .WithBrokers(new[] { "localhost:9092" }) + .AddConsumer(consumer => consumer + .Topic("topic-name") + .WithGroupId("sample-group") + .WithoutStoringOffsets() + ... + ) + ) +); +``` diff --git a/website/versioned_docs/version-2.x/guides/consumers/consumers.md b/website/versioned_docs/version-2.x/guides/consumers/consumers.md new file mode 100644 index 000000000..6eb75edeb --- /dev/null +++ b/website/versioned_docs/version-2.x/guides/consumers/consumers.md @@ -0,0 +1,74 @@ +--- +sidebar_position: 1 +--- + +# Consumers + +In this section, we will learn all about Consumers on KafkaFlow. + +Here is where KafkaFlow shines. Using KafkaFlow, you have control over how to consume the messages. Every consumer has its own [Workers](#workers) and [Middlewares](#middlewares) configuration. You can have multiple consumers consuming the same Topic with different consumer groups or one consumer with multiple Topics. + + +## Message Flow + +Every KafkaFlow consumer is composed of a group of components: [Kafka Consumer](#kafka-consumer), [Consumer Worker Pool](#consumer-worker-pool), [Distribution Strategy](#distribution-strategy), [Workers](#workers), [Middlewares](#middlewares), and [Offset Manager](#offset-manager). + +The following diagram demonstrates the flow of a message through those components. + +![Message Flow](https://user-images.githubusercontent.com/233064/98690729-24bd8000-2365-11eb-8bd0-19e6aeeaebda.jpg) + + +### Kafka Consumer + +It’s where the Confluent Client runs. It has a background task that fetches the messages from any topics/partitions assigned for that consumer and delivers them to the [Consumer Worker Pool](#consumer-worker-pool). If the Confluent Consumer stops working for any reason (if a fatal exception occurs), the consumer will be recreated. + +### Consumer Worker Pool + +It orchestrates the Workers creation and destruction when the application starts, stops, and when partitions are assigned or revoked. It receives the message from [Kafka Consumer](#kafka-consumer) and uses the [Distribution Strategy](#distribution-strategy) to choose a [Worker](#workers) to enqueue the messages. + +### Distribution Strategy + +It’s an algorithm to choose a [Worker](#workers) to process the message. The Framework has two: **BytesSum** and **FreeWorker**. + + - The **BytesSum** maintains the message order with some performance and resource penalties, **it is the default strategy**. + - The **FreeWorker** is faster, but the message order is lost. A custom strategy can be implemented using the `IDistibutionStrategy` interface. + +You can configure the consumer strategy on the [configuration](../configuration) with the method `WithWorkDistributionStrategy`. + +### Workers + +Workers are responsible for processing messages when consuming. You define how many workers a consumer will have. + +The workers process the messages in parallel. By default (using the ByteSum distribution strategy), all messages with the same partition key are processed by the same Worker so that the message order is respected for the same partition key. + +Every worker has a buffer to avoid idling when many messages arrive with the same partition key for any other worker. + +The buffer size should be dimensioned depending on how many messages arrive with the same partition key, on average. When the bus is requested to stop, every worker receives the stop command, and it only releases the stop call when it ends the current message and stores it in the [Offset Manager](#offset-manager). + +### Middlewares + +It’s a customizable collection of middlewares. This collection is configurable per consumer. Middlewares can be created by implementing the `IMessageMiddleware` interface. Each consumer has its own instances of middlewares, so they are not shared between consumers but shared between [Workers](#workers) instead. You can see more information about middlewares [here](../middlewares). + +### Offset Manager + +It is a component that receives all the offsets from the workers and orchestrates them before storing them in Kafka; this avoids an offset override when many messages are processed concurrently. + +Even when you choose to use the manual offset store option, you will store the offset in the OffsetManager and then store the offsets in Kafka when possible. + +:::warning +When the application stops, there is a big chance to have processed messages already stored in OffsetManager but not stored in Kafka. In this scenario, when the application starts again, these messages will be processed again. Your application must be prepared to deal with it. +::: + +### Max Poll Intervals + +This is the value that Kafka uses to determine the maximum amount of time allowed between calls to the consumers' poll method before the process is considered as failed. By default, this has a value of 300 seconds, but it may be adjusted with the `WithMaxPollInterval` configuration. + +If the maximum time is exceeded, the consumer will go offline, but the workers will continue to run in the background, leading to an increasing read lag until the application goes down. + +Further information can be found in the official [documentation](https://docs.confluent.io/platform/current/clients/consumer.html#message-handling). + +## How it works + +The following animation shows a consumer listening to one topic with two [Workers](#workers) having a buffer size of 2 using the **BytesSum** distribution strategy. + +![consumer-animation](https://user-images.githubusercontent.com/233064/98690723-22f3bc80-2365-11eb-8453-04349abb103c.gif) diff --git a/website/versioned_docs/version-2.x/guides/dependency-injection.md b/website/versioned_docs/version-2.x/guides/dependency-injection.md new file mode 100644 index 000000000..fd6c0cb9f --- /dev/null +++ b/website/versioned_docs/version-2.x/guides/dependency-injection.md @@ -0,0 +1,22 @@ +--- +sidebar_position: 20 +--- + +# Dependency Injection + +KafkaFlow Dependency Injection framework support is extensible. + +[Microsoft .NET DI](https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection/) and [Unity 5](http://unitycontainer.org/articles/quickstart.html) are natively supported. You can see [here](configuration) how to use them. + +## Add support for a new Dependency Injection container + +Other DI frameworks can be supported by implementing a set of interfaces: + +- `IDependencyConfigurator` +- `IDependencyResolver` +- `IDependencyResolverScope` + + +You can find an example [here](https://github.com/Farfetch/kafkaflow/tree/master/src/KafkaFlow.Unity). + +Once the interfaces are implemented, use them the same way you use Unity ([see here](configuration)). \ No newline at end of file diff --git a/website/versioned_docs/version-2.x/guides/global-events.md b/website/versioned_docs/version-2.x/guides/global-events.md new file mode 100644 index 000000000..87803b12d --- /dev/null +++ b/website/versioned_docs/version-2.x/guides/global-events.md @@ -0,0 +1,115 @@ +--- +sidebar_position: 9 +--- + +# Global Events + +In this section, we will delve into the concept of Global Events in KafkaFlow, which provides a mechanism to subscribe to various events that are triggered during the message production and consumption processes. + +KafkaFlow offers a range of Global Events that can be subscribed to. These events can be used to monitor and react to different stages of message handling. Below is a list of available events: + - [Message Produce Started Event](#message-produce-started-event) + - [Message Produce Completed Event](#message-produce-completed-event) + - [Message Produce Error Event](#message-produce-error-event) + - [Message Consume Started Event](#message-consume-started-event) + - [Message Consume Completed Event](#message-consume-completed-event) + - [Message Consume Error Event](#message-consume-error-event) + +## Message Produce Started Event {#message-produce-started-event} + +The Message Produce Started Event is triggered when the message production process begins. It provides an opportunity to perform tasks or gather information before middlewares execution. + +```csharp +services.AddKafka( + kafka => kafka + .SubscribeGlobalEvents(observers => + { + observers.MessageProduceStarted.Subscribe(eventContext => + { + // Add your logic here + }); + }) +``` + +## Message Produce Completed Event {#message-produce-completed-event} + +The Message Produce Completed Event is triggered when a message is successfully produced or when error messages occur during the production process. Subscribing to this event enables you to track the successful completion of message production. + +```csharp +services.AddKafka( + kafka => kafka + .SubscribeGlobalEvents(observers => + { + observers.MessageProduceCompleted.Subscribe(eventContext => + { + // Add your logic here + }); + }) +``` + +## Message Produce Error Event {#message-produce-error-event} + +In case an error occurs during message production, the Message Produce Error Event is triggered. By subscribing to this event, you will be able to catch any exceptions that may occur while producing a message. + +```csharp +services.AddKafka( + kafka => kafka + .SubscribeGlobalEvents(observers => + { + observers.MessageProduceError.Subscribe(eventContext => + { + // Add your logic here + }); + }) +``` + +## Message Consume Started Event {#message-consume-started-event} + +The Message Consume Started Event is raised at the beginning of the message consumption process. It offers an opportunity to execute specific tasks or set up resources before message processing begins. + +```csharp +services.AddKafka( + kafka => kafka + .SubscribeGlobalEvents(observers => + { + observers.MessageConsumeStarted.Subscribe(eventContext => + { + // Add your logic here + }); + }) +``` + +## Message Consume Completed Event {#message-consume-completed-event} + +The Message Consume Completed Event signals the successful completion of message consumption. By subscribing to this event, you can track when messages have been successfully processed. + +:::info +Please note that the current event is not compatible with Batch Consume in the current version (v2). However, this limitation is expected to be addressed in future releases (v3+). +:::info + +```csharp +services.AddKafka( + kafka => kafka + .SubscribeGlobalEvents(observers => + { + observers.MessageProduceCompleted.Subscribe(eventContext => + { + // Add your logic here + }); + }) +``` + +## Message Consume Error Event {#message-consume-error-event} + +If an error occurs during message consumption, the Message Consume Error Event is triggered. Subscribing to this event allows you to manage and respond to consumption errors. + +```csharp +services.AddKafka( + kafka => kafka + .SubscribeGlobalEvents(observers => + { + observers.MessageConsumeError.Subscribe(eventContext => + { + // Add your logic here + }); + }) +``` \ No newline at end of file diff --git a/website/versioned_docs/version-2.x/guides/logging.md b/website/versioned_docs/version-2.x/guides/logging.md new file mode 100644 index 000000000..98ca1ce93 --- /dev/null +++ b/website/versioned_docs/version-2.x/guides/logging.md @@ -0,0 +1,52 @@ +--- +sidebar_position: 6 +--- +# Logging + +In this section, we will learn how to configure Logging in KafkaFlow. + + +There are a few options you can use to add logging to KafkaFlow: + - [Using Console Logger](#console-logger) + - [Using Microsoft Logging Framework](#microsoft-logging-framework) + - [Using your own Logger](#custom-logger) + +:::info + +By default, KafkaFlow logs are ignored. +The default implementation is the `NullLogHandler`. + +::: + +## Using Console Logger {#console-logger} + +The package [KafkaFlow.LogHandler.Console](https://www.nuget.org/packages/KafkaFlow.LogHandler.Console/) can be installed to log the framework messages to the console output after the installation, use the method `UseConsoleLog` in the [configuration](configuration). + +```csharp +services.AddKafka( + kafka => kafka + .UseConsoleLog() + ... +``` + +## Using Microsoft Logging Framework {#microsoft-logging-framework} + +The package [KafkaFlow.LogHandler.Microsoft](https://www.nuget.org/packages/KafkaFlow.LogHandler.Microsoft/) can be installed to log the framework messages to the console output after the installation, use the method `UseMicrosoftLog` in the [configuration](configuration). + +```csharp +services.AddKafka( + kafka => kafka + .UseMicrosoftLog() + ... +``` + +## Using your own Logger {#custom-logger} + +The framework has the `ILogHandler` interface that can be implemented to log the framework's messages. The log handler can be configured in the [configuration](configuration) process using the method `UseLogHandler`: + +```csharp +services.AddKafka( + kafka => kafka + .UseLogHandler() + ... +``` diff --git a/website/versioned_docs/version-2.x/guides/middlewares/_category_.json b/website/versioned_docs/version-2.x/guides/middlewares/_category_.json new file mode 100644 index 000000000..0f8c5ffb5 --- /dev/null +++ b/website/versioned_docs/version-2.x/guides/middlewares/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "Middlewares", + "position": 4, + "link": { + "type": "generated-index" + } +} diff --git a/website/versioned_docs/version-2.x/guides/middlewares/batch-consume-middleware.md b/website/versioned_docs/version-2.x/guides/middlewares/batch-consume-middleware.md new file mode 100644 index 000000000..6fcbeb2d7 --- /dev/null +++ b/website/versioned_docs/version-2.x/guides/middlewares/batch-consume-middleware.md @@ -0,0 +1,67 @@ +--- +sidebar_position: 5 +--- + +# Batch Consume Middleware + +In this section, we will learn how to use the Batch Consume Middleware. + +The Batch Consume Middleware is used to accumulate a number of messages or wait some time to build a collection of messages and deliver them to the next middleware to be processed, as it was just one message. + +## How to use it + +Install the [KafkaFlow.BatchConsume](https://www.nuget.org/packages/KafkaFlow.BatchConsume) package. + +```bash +dotnet add package KafkaFlow.BatchConsume +``` + +On the configuration, use the `BatchConsume` extension method to add the middleware to your consumer middlewares. + +The `BatchConsume` method has two arguments: + - The first one must define the maximum batch size. + - The second one defines the `TimeSpan` that the Middleware waits for new messages to be part of the batch. + + +```csharp +services.AddKafka(kafka => kafka + .AddCluster(cluster => cluster + .WithBrokers(new[] { "localhost:9092" }) + .AddConsumer( + consumerBuilder => consumerBuilder + ... + .AddMiddlewares( + middlewares => middlewares + ... + .BatchConsume(100, TimeSpan.FromSeconds(10)) // Configuration of the BatchConsumeMiddleware + .Add() // Middleware to process the batch + ) + ) + ) +); +``` + +To access the batch from the next middleware, use the `GetMessagesBatch` method accessible through the `context` argument. + +:::warning +When using the `Batch Consume` middleware, the `IServiceScopeFactory` should be used to create scopes instead of the `IServiceProvider`, as the latter may dispose the scope. +::: + +```csharp +using KafkaFlow.BatchConsume; + +internal class HandlingMiddleware : IMessageMiddleware +{ + public Task Invoke(IMessageContext context, MiddlewareDelegate next) + { + var batch = context.GetMessagesBatch(); + + (...) + + return Task.CompletedTask; + } +} +``` +:::tip +You can find a sample on batch processing [here](https://github.com/Farfetch/kafkaflow/tree/master/samples/KafkaFlow.Sample.BatchOperations). +::: \ No newline at end of file diff --git a/website/versioned_docs/version-2.x/guides/middlewares/compressor-middleware.md b/website/versioned_docs/version-2.x/guides/middlewares/compressor-middleware.md new file mode 100644 index 000000000..819b70127 --- /dev/null +++ b/website/versioned_docs/version-2.x/guides/middlewares/compressor-middleware.md @@ -0,0 +1,47 @@ +--- +sidebar_position: 4 +--- + +# Compressor Middleware + +In this section, we will learn how to build a custom Compressor Middleware. + +:::warning +It's recommended to use the producer's native compression instead of the compressor middleware. See [here](../compression) how to use it. +::: + +If you want to build your own way of compress and decompress messages, you can find in this section the needed instructions. + +## Add a Compressor Middleware + +Install the [KafkaFlow.Compressor](https://www.nuget.org/packages/KafkaFlow.Compressor/) package and add the `AddCompressor` extension method to your producer/consumer middlewares to use it. + +The method receives a class that implements the `IMessageCompressor` interface as a generic argument. This class will be used in the compress/decompress process. + +A class instance can be provided as an argument through a factory method too. + +Install the [KafkaFlow.Compressor.Gzip](https://www.nuget.org/packages/KafkaFlow.Compressor.Gzip/) package to use the `GzipMessageCompressor` that uses the GZIP algorithm. + +```csharp +public class Startup +{ + public void ConfigureServices(IServiceCollection services) + { + services.AddKafka(kafka => kafka + .AddCluster(cluster => cluster + .WithBrokers(new[] { "localhost:9092" }) + .AddProducer(producer => producer + ... + .AddMiddlewares(middlewares => middlewares + ... + .AddCompressor() + // or + .AddCompressor(resolver => new GzipMessageCompressor(...)) + ... + ) + ) + ) + ); + } +} +``` diff --git a/website/versioned_docs/version-2.x/guides/middlewares/consumer-throttling-middleware.md b/website/versioned_docs/version-2.x/guides/middlewares/consumer-throttling-middleware.md new file mode 100644 index 000000000..2c4014b62 --- /dev/null +++ b/website/versioned_docs/version-2.x/guides/middlewares/consumer-throttling-middleware.md @@ -0,0 +1,60 @@ +--- +sidebar_position: 6 +--- + +# Consumer Throttling + +In this section, we will learn how Consumer Throttling works and how to configure it. Consumer Throttling is a feature in KafkaFlow that allows you to dynamically manage the rate at which your application consumes messages from Kafka topics. It provides a mechanism to slow down or pause the consumption of messages based on specified metrics. This can be particularly useful in scenarios where you want to prioritize certain types of messages over others, or when there is a need to control the rate of processing during high-load periods or when dealing with backlogs. + +This functionality is highly extensible, allowing for the use of custom metrics and actions by implementing the `IConsumerThrottlingMetric` and `IConsumerThrottlingAction` interfaces respectively. Although KafkaFlow comes with built-in implementations like Consumer Lag for metrics and Delay for actions, you can create your own based on your specific needs. + +## Use Case Example + +One example of how Consumer Throttling can be utilized effectively is when you want to segregate single and bulk actions into different consumers and topics. For instance, you may want to prioritize the processing of single actions and slow down the processing of bulk actions. This can be achieved by monitoring the consumer lag of the consumer responsible for single actions and applying throttling to the consumer handling the bulk actions based on this metric. + +## How to Configure Consumer Throttling + +Configuring Consumer Throttling is straightforward with the fluent interface provided by KafkaFlow. Here's a simple example: + +```csharp +.AddConsumer( + consumer => consumer + .Topic("bulk-topic") + .WithName("bulkConsumer") + .AddMiddlewares( + middlewares => middlewares + .ThrottleConsumer( + t => t + .ByOtherConsumersLag("singleConsumer") + .WithInterval(TimeSpan.FromSeconds(5)) + .AddAction(a => a.AboveThreshold(10).ApplyDelay(100)) + .AddAction(a => a.AboveThreshold(100).ApplyDelay(1_000)) + .AddAction(a => a.AboveThreshold(1_000).ApplyDelay(10_000))) + .AddSerializer() + ) +) +``` + +## Consumer Throttling Methods + +Here's a brief overview of the methods used to configure Consumer Throttling: + +- `ThrottleConsumer`: This method enables the Throttling feature for the consumer. + +- `ByOtherConsumersLag`: This extension method of `AddMetric` sets which consumers' lag should be monitored. The throttling will be applied based on these consumers' lag. + +- `WithInterval`: This method specifies the interval at which the metrics will be checked and the throttling actions applied. + +- `AddAction`: This method allows you to define actions that will be taken when certain metric thresholds are met. Actions can include applying a delay or pausing the consumer. + +- `AboveThreshold`: This method sets the metric threshold at which the action will be applied. + +- `ApplyDelay`: This extension method of `Apply` sets a delay to the consumer when the specified threshold is met. + +These extension methods, `ByOtherConsumersLag` and `ApplyDelay`, are convenient ways to set up commonly used metrics and actions. But as stated earlier, KafkaFlow allows you to implement your own custom metrics and actions via the `IConsumerThrottlingMetric` and `IConsumerThrottlingAction` interfaces respectively. + +In summary, Consumer Throttling is a powerful tool for managing message consumption in KafkaFlow. It brings flexibility and control to your message processing workflows and allows for effective prioritization and rate control. Whether you're using built-in metrics and actions or implementing your own, you can fine-tune your consumers to perform optimally under various conditions. + +:::tip +You can find a sample on batch processing [here](https://github.com/Farfetch/kafkaflow/tree/master/samples/KafkaFlow.Sample.ConsumerThrottling). +::: diff --git a/website/versioned_docs/version-2.x/guides/middlewares/middlewares.md b/website/versioned_docs/version-2.x/guides/middlewares/middlewares.md new file mode 100644 index 000000000..db9696b6f --- /dev/null +++ b/website/versioned_docs/version-2.x/guides/middlewares/middlewares.md @@ -0,0 +1,207 @@ +--- +sidebar_position: 1 +--- + +# Middleware Introduction + +In this section, we will learn what Middlewares are and how to create them. + +KafkaFlow is middleware-oriented. Messages are delivered to a middleware and then forwarded to another middleware, and so on. It's a middleware pipeline that will be invoked in sequence. + +:::info + +Middlewares are executed in the same order they are defined in the configuration. +Every product/consumer has its own Middlewares instances, so the instances are not shared between different consumers/producers, but when consuming, the instances are shared between the workers of the same consumer. + +::: + +Middlewares are instantiated by the configured dependency injection container, so every dependency configured by your container can be delivered in the middleware constructor. + +## Use Cases + +Middlewares can perform several jobs. As an example, Middlewares can be used to: + +- Transform the messages, allowing them to apply serialization and compression. +- Log the messages +- Handle exceptions +- Apply retry policies (take a look into [KafkaFlow Retry Extensions](https://github.com/Farfetch/kafkaflow-retry-extensions)) +- Collect metrics +- etc. + +## Built-in middlewares + +KafkaFlow provides the following middlewares out of the box: + +- [Serializer](serializer-middleware) +- [Compressor](compressor-middleware) +- [Typed Handler](typed-handler-middleware) +- [Batch Consume](batch-consume-middleware) +- [Consumer Throttling](consumer-throttling-middleware) + +## When Consuming​ + +The message will be delivered as a byte array to the first middleware; you will choose the middlewares to process the messages (you will probably create a middleware to do it or use the [Typed Handler](typed-handler-middleware)). The next message will only be processed after all configured middlewares execute for that consumer. + +## When Producing + +The middlewares are called when the `Produce` or `PoduceAsync` of the `IMessageProducer` is called. After all the middlewares execute, the message will be published to Kafka. + +## Creating a middleware + +You can create your own middlewares by implementing the `IMessageMiddleware` interface. You must implement the `Invoke` method, which receives two parameters: the `IMessageContext` and the `MiddlewareDelegate`. The `IMessageContext` is an object that has the message, message metadata, and consumer/producer information. The `MiddlewareDelegate` is an `async` method that calls the next middleware, it receives an `IMessageContext` parameter which is the context that will be passed to the next middleware. + +### Some middleware samples + +#### Log messages and processing time + +```csharp +public class LoggingMiddleware : IMessageMiddleware +{ + private readonly ILogger log; + + public LoggingMiddleware(ILogger log) + { + this.log = log ?? throw new ArgumentNullException(nameof(log)); + } + + public async Task Invoke(IMessageContext context, MiddlewareDelegate next) + { + this.log.Info("Kafka Message Received"); + + var sw = Stopwatch.StartNew(); + + await next(context).ConfigureAwait(false); + + sw.Stop(); + + this.log.Info( + "Kafka Message processed", + () => new + { + MessageType = context.Message?.GetType().FullName, + ProcessingTime = sw.ElapsedMilliseconds + }); + } +} +``` + +#### Log any exception + +```csharp +public class ErrorHandlingMiddleware : IMessageMiddleware +{ + private readonly ILogger log; + + public ErrorHandlingMiddleware(ILogger log) + { + this.log = log ?? throw new ArgumentNullException(nameof(log)); + } + + public async Task Invoke(IMessageContext context, MiddlewareDelegate next) + { + try + { + await next(context).ConfigureAwait(false); + } + catch(Exception ex) + { + this.log.Error("Error processing message", ex); + } + } +} +``` + +#### Ignore messages + +```csharp +public class IgnoreMessageMiddleware : IMessageMiddleware +{ + public Task Invoke(IMessageContext context, MiddlewareDelegate next) + { + return UnwantedMessage(context) ? + Task.CompletedTask : + next(context); + } + + private bool UnwantedMessage(IMessageContext context) + { + ... + } +} +``` + +#### Transform messages + +:::info + +This is only a sample, use the [Serializer Middleware](serializer-middleware) instead. + +::: + +```csharp +public class JsonDeserializeMiddleware : IMessageMiddleware +{ + public Task Invoke(IMessageContext context, MiddlewareDelegate next) + { + if(!(context.Message is byte[] rawMessage)) + throw new InvalidoperationException(); + + var type = Type.GetType(context.Headers.GetString("Message-Type")); + + var jsonMessage = Encoding.UTF8.GetString(rawMessage); + + context.TransformMessage(JsonConvert.Deserialize(jsonMessage, MessageType)); + + return next(context); + } +} +``` + +#### Pause Consumer when an exception is raised + +Add the following middleware to the beginning of your Consumer middleware pipeline. + +:::info +This middleware is part of a sample you can find [here](https://github.com/Farfetch/kafkaflow/tree/master/samples/KafkaFlow.Sample.PauseConsumerOnError). +::: + +```csharp +using KafkaFlow.Consumers; + +public class PauseConsumerOnExceptionMiddleware : IMessageMiddleware +{ + private readonly IConsumerAccessor consumerAccessor; + private readonly ILogHandler logHandler; + + public PauseConsumerOnExceptionMiddleware(IConsumerAccessor consumerAccessor, ILogHandler logHandler) + { + this.consumerAccessor = consumerAccessor; + this.logHandler = logHandler; + } + + public async Task Invoke(IMessageContext context, MiddlewareDelegate next) + { + try + { + await next(context); + } + catch (Exception exception) + { + context.ConsumerContext.ShouldStoreOffset = false; + this.logHandler.Error("Error handling message", exception, + new + { + context.Message, + context.ConsumerContext.Topic, + MessageKey = context.Message.Key, + context.ConsumerContext.ConsumerName, + }); + + var consumer = this.consumerAccessor[context.ConsumerContext.ConsumerName]; + consumer.Pause(consumer.Assignment); + + this.logHandler.Warning("Consumer stopped", context.ConsumerContext.ConsumerName); + } + } +} +``` diff --git a/website/versioned_docs/version-2.x/guides/middlewares/serializer-middleware.md b/website/versioned_docs/version-2.x/guides/middlewares/serializer-middleware.md new file mode 100644 index 000000000..674d92294 --- /dev/null +++ b/website/versioned_docs/version-2.x/guides/middlewares/serializer-middleware.md @@ -0,0 +1,132 @@ +--- +sidebar_position: 3 +--- + +# Serializer Middleware + +In this section, we will learn how to use the Serializer Middleware. + +The Serializer Middleware is used to serialize and deserialize messages. + +You can use one of the following common serializers or build your own: +- [KafkaFlow.Serializer.ProtoBufNet](https://www.nuget.org/packages/KafkaFlow.Serializer.ProtobufNet/) +- [KafkaFlow.Serializer.JsonCore](https://www.nuget.org/packages/KafkaFlow.Serializer.JsonCore/) +- [KafkaFlow.Serializer.NewtonsoftJson](https://www.nuget.org/packages/KafkaFlow.Serializer.NewtonsoftJson/) + +## How to use it + +Install the [KafkaFlow.Serializer](https://www.nuget.org/packages/KafkaFlow.Serializer) package. + +```bash +dotnet add package KafkaFlow.Serializer +``` + +On the configuration, add the `AddSerializer` extension method to your producer/consumer middlewares to use it. + +The `AddSerializer` method has two arguments: + - The first one must implement the `IMessageSerializer` interface. + - The second one is optional and must implement the `IMessageTypeResolver` interface. If the parameter is not provided, then the `DefaultTypeResolver` will be used. +Both classes can be provided as an argument through a factory method too. + +:::tip +For topics that have just one message type, use the `AddSingleTypeSerializer` method. +:::tip + + +```csharp +services.AddKafka(kafka => kafka + .AddCluster(cluster => cluster + .WithBrokers(new[] { "localhost:9092" }) + .AddProducer(producer => producer + ... + .AddMiddlewares(middlewares => middleware + ... + .AddSerializer() // Using the DefaultMessageTypeResolver + // or + .AddSerializer() + // or + .AddSerializer( + resolver => new JsonMessageSerializer(...), + resolver => new YourTypeResolver(...)) + // or + .AddSingleTypeSerializer() + // or + .AddSingleTypeSerializer(resolver => new JsonMessageSerializer(...)) + ... + ) + ) + ) +); + +``` + +## Adding Schema Registry support +Serializer middlewares can be used along with schema registry allowing the evolution of schemas according to the configured compatibility setting. + +Install the [KafkaFlow.SchemaRegistry](https://www.nuget.org/packages/KafkaFlow.SchemaRegistry/) package, configure the schema registry broker, and use one of the following packages to use all the schema registry integration features. + +- [KafkaFlow.Serializer.SchemaRegistry.ConfluentJson](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/) +- [KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/) +- [KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf](https://www.nuget.org/packages/KafkaFlow.Serializer.ConfluentProtobuf/) + +```csharp +public class Startup +{ + public void ConfigureServices(IServiceCollection services) + { + services.AddKafka( + kafka => kafka + .AddCluster( + cluster => cluster + .WithBrokers(new[] { "localhost:9092" }) + .WithSchemaRegistry(config => config.Url = "localhost:8081") + .AddProducer( + ... + .AddMiddlewares(middlewares => + middlewares.AddSchemaRegistryAvroSerializer(new AvroSerializerConfig{ SubjectNameStrategy = SubjectNameStrategy.TopicRecord }) + ) + .AddConsumer( + ... + .AddMiddlewares(middlewares => middlewares.AddSchemaRegistryAvroSerializer() + ) + ) + ); + } +} +``` +:::info +[ConfluentAvro](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/) and [ConfluentProtobuf](https://www.nuget.org/packages/KafkaFlow.Serializer.ConfluentProtobuf/) type resolvers can support multiple types per topic however, due to the JSON serialization format used by [confluent-kafka-dotnet](https://docs.confluent.io/platform/current/clients/confluent-kafka-dotnet/_site/api/Confluent.SchemaRegistry.Serdes.JsonSerializer-1.html), [ConfluentJson](https://www.nuget.org/packages/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/) type resolver can only resolve a single type of message per topic. +::: + +:::info +To be able to publish multiple type messages per topic, `SubjectNameStrategy.Record` or `SubjectNameStrategy.TopicRecord` must be used. +You can see a detailed explanation [here](https://docs.confluent.io/platform/current/schema-registry/serdes-develop/index.html#subject-name-strategy). +::: + + +## Creating a Message Type Resolver + +A type resolver is needed to instruct the middleware where to find the destination message type in the message metadata when consuming and where to store it when producing. + +The framework has the `DefaultTypeResolver` that will be used omitting the second type parameter in the `AddSerializer` method. You can create your own implementation of `IMessageTypeResolver` to allow communication with other frameworks. + +```csharp +public class SampleMessageTypeResolver : IMessageTypeResolver +{ + private const string MessageType = "MessageType"; + + public Type OnConsume(IMessageContext context) + { + var typeName = context.Headers.GetString(MessageType); + + return Type.GetType(typeName); + } + + public void OnProduce(IMessageContext context) + { + context.Headers.SetString( + MessageType, + $"{context.Message.GetType().FullName}, {context.Message.GetType().Assembly.GetName().Name}"); + } +} +``` diff --git a/website/versioned_docs/version-2.x/guides/middlewares/typed-handler-middleware.md b/website/versioned_docs/version-2.x/guides/middlewares/typed-handler-middleware.md new file mode 100644 index 000000000..e0144299e --- /dev/null +++ b/website/versioned_docs/version-2.x/guides/middlewares/typed-handler-middleware.md @@ -0,0 +1,116 @@ +--- +sidebar_position: 2 +--- + +# Typed Handler Middleware + +In this section, we will learn how to use the Typed Handler middleware. + +The Typed Handler Middleware allows you to execute different handlers depending on the message type. + +:::tip +Use it when the topic has different message types. +::: + +When a message with a given type arrives, the middleware will call the appropriate message handler for that message type. + +### How Message Type is discovered + +The Message Type discovery may vary depending on the implementation. + +#### With Schema Registry +When using a Schema Registry, the schema is read from it, and the first 5 bytes of the message represent the `SchemaId` registered on the Schema Registry. + +#### Without Schema Registry +Using other serializers with no Schema Registry, the `DefaultTypeResolver` is used by default. The `DefaultTypeResolver` uses the header `Message-Type` to identify the message type based on the Type fully qualified name. + +It's also possible to write your own `TypeResolver` implementing the `IMessageTypeResolver` interface and using it in the `AddSerializer` method in the consumer/producer middleware. + +## Configure Typed Handler + +There are three ways to add handlers to a consumer: +- **`AddHandler()`:** adds one handler per call. +- **`AddHandlers(IEnumerable handlers)`:** adds many handlers per call. +- **`AddHandlersFromAssemblyOf()`:** adds all classes on the given assembly type that implement the `IMessageHandler` interface. + +```csharp +services.AddKafka(kafka => kafka + .AddCluster(cluster => cluster + .WithBrokers(new[] { "localhost:9092" }) + .AddConsumer(consumer => consumer + ... + .AddMiddlewares(middlewares => middlewares + ... + .AddTypedHandlers(handlers => handlers + .WithHandlerLifetime(InstanceLifetime.Singleton) + .AddHandler() + // or + .AddHandlers( ... ) + // or + .AddHandlersFromAssemblyOf() + ) + ) + ) + ) +); +``` + +## Create a Message Handler + +A message handler can be created by implementing the `IMessageHandler` interface. + +The handler's instance is created by the configured dependency injection container, any handler dependency will be injected through the constructor, and the instance lifetime can be configured in the configuration. + +:::warning +If there's no handler defined for the arriving message, it will be ignored. +::: + +```csharp +public class ProductCreatedHandler : IMessageHandler +{ + public Task Handle(IMessageContext context, ProductCreatedEvent message) + { + ... + } +} +``` + +## Configuring Handler Lifetime + +The Handler lifetime can be configured to one of the following modes: + - **Singleton:** A single class instance will be created for the entire application. + - **Scoped:** A new class instance will be created for each scope. + - **Transient:** A new class instance will be created every time it is requested. + +:::info +By default, the handler lifetime is Singleton. +::: + +## Handling No Handler Found event + +If there's no handler defined for the arriving message, it will be ignored. + +It is possible to handle those events. As an example, the following code writes to the console when a message can't be handled. + + +```csharp +services.AddKafka(kafka => kafka + .AddCluster(cluster => cluster + .WithBrokers(new[] { "localhost:9092" }) + .AddConsumer(consumer => consumer + ... + .AddMiddlewares(middlewares => middlewares + ... + .AddTypedHandlers(handlers => handlers + .AddHandler() + .WhenNoHandlerFound(context => + Console.WriteLine("Message not handled > Partition: {0} | Offset: {1}", + context.ConsumerContext.Partition, + context.ConsumerContext.Offset) + ) + ) + ) + ) + ) +); +``` \ No newline at end of file diff --git a/website/versioned_docs/version-2.x/guides/open-telemetry.md b/website/versioned_docs/version-2.x/guides/open-telemetry.md new file mode 100644 index 000000000..bf2f6af15 --- /dev/null +++ b/website/versioned_docs/version-2.x/guides/open-telemetry.md @@ -0,0 +1,23 @@ +--- +sidebar_position: 10 +--- + +# OpenTelemetry instrumentation + +KafkaFlow includes support for [Traces](https://opentelemetry.io/docs/concepts/signals/traces/) and [Baggage](https://opentelemetry.io/docs/concepts/signals/baggage/) signals using [OpenTelemetry instrumentation](https://opentelemetry.io/docs/instrumentation/net/). + +## Including OpenTelemetry instrumentation in your code + +Add the package [KafkaFlow.OpenTelemetry](https://www.nuget.org/packages/KafkaFlow.OpenTelemetry/) to the project and add the extension method `AddOpenTelemetryInstrumentation` in your Startup: + +```csharp +services.AddKafka( + kafka => kafka + .AddCluster(...) + .AddOpenTelemetryInstrumentation() +); +``` + +## Using KafkaFlow instrumentation with .NET Automatic Instrumentation + +When using [.NET automatic instrumentation](https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation), the KafkaFlow activity can be captured by including the ActivitySource name `KafkaFlow.OpenTelemetry` as a parameter to the variable `OTEL_DOTNET_AUTO_TRACES_ADDITIONAL_SOURCES`. diff --git a/website/versioned_docs/version-2.x/guides/producers.md b/website/versioned_docs/version-2.x/guides/producers.md new file mode 100644 index 000000000..4e329df93 --- /dev/null +++ b/website/versioned_docs/version-2.x/guides/producers.md @@ -0,0 +1,170 @@ +--- +sidebar_position: 2 +--- + +# Producers + +In this section, we will learn how to add and configure a Producer on KafkaFlow. + +To produce messages using KafkaFlow, Producers need to be configured in the application [configuration](configuration). + +The producers also support [Middlewares](middlewares). + +You have two ways to configure the producers: + - [Name-based producer](#named-producers) + - [Type-based producer](#type-based-producers) + +:::tip +It's highly recommended to read [Confluent Producer documentation](https://github.com/confluentinc/confluent-kafka-dotnet/wiki/Producer) for better practices when producing messages. +::: + +## Name-based producers + +Uses a name to bind the configuration to the producer instance. +Use the name as a key to access the Producer when you want to produce a message. + +```csharp +using KafkaFlow; +using KafkaFlow.Producers; +using Microsoft.Extensions.DependencyInjection; + +services.AddKafka(kafka => kafka + .AddCluster(cluster => cluster + .WithBrokers(new[] { "localhost:9092" }) + .AddProducer( + "product-events", //the producer name + producer => + producer + ) + ) +); + +public class ProductService : IProductService +{ + private readonly IProducerAccessor _producers; + + public ProductService(IProducerAccessor producers) + { + _producers = producers; + } + + public async Task CreateProduct(Product product) => + await _producers["product-events"] + .ProduceAsync(product.Id.ToString(), product); +} +``` + +## Type-based producers + +Uses a class to bind the configuration to the producer instance, this is commonly used when you create a producer class to decouple the framework from your service classes. + +For example, if you have a `ProductEventsProducer` in your app, you can use this class when configuring the producer to bind the configuration with the instance of `IMessageProducer`. + +```csharp +using KafkaFlow; +using KafkaFlow.Producers; +using Microsoft.Extensions.DependencyInjection; + +var services = new ServiceCollection(); + +services.AddKafka(kafka => kafka + .AddCluster(cluster => cluster + .WithBrokers(new[] { "localhost:9092" }) + .AddProducer( + producer => + producer + ... + ) + ) +); + +public class ProductEventsProducer : IProductEventsProducer +{ + private readonly IMessageProducer _producer; + + public ProductEventsProducer(IMessageProducer producer) + { + _producer = producer; + } + + public Task ProduceAsync(Product product) => + _producer + .ProduceAsync(product.Id.ToString(), product); +} +``` + +## How to produce a message to a given topic + +There are two ways to specify the destination Topic of a message. + +You can specify it as the first argument when the Produce method is invoked, as shown in the following example: + +```csharp +await _producers["product-events"] + .ProduceAsync("products-topic", product.Id.ToString(), product); +``` + +You can also set the Default Topic that a Producer should produce to. +You can do that, on the producer configuration. + +```csharp +using KafkaFlow; +using KafkaFlow.Producers; +using Microsoft.Extensions.DependencyInjection; + +services.AddKafka(kafka => kafka + .AddCluster(cluster => cluster + .WithBrokers(new[] { "localhost:9092" }) + .AddProducer( + "product-events", + producer => + producer + .DefaultTopic("products-topic") + ) + ) +); +``` + +## How to produce a message without Message Key + +You can send the message key argument as `null` when the Produce method is invoked, as shown in the following example: + +```csharp +await producer.ProduceAsync(null, product); +``` + +## How to configure ACKS when publishing a message + +An Ack is an acknowledgment that the producer receives from the broker to ensure that the message has been successfully committed. + +The following table establishes the mapping between KafkaFlow and Kafka. You can find [here](https://docs.confluent.io/platform/current/installation/configuration/producer-configs.html#producerconfigs_acks) the meaning of each of those values. + +| KafkaFlow | Kafka | +| -- | -- | +| Acks.None | `acks=0` | +| Acks.Leader | `acks=1` | +| Acks.All | `acks=all` | + + +```csharp +using KafkaFlow; +using KafkaFlow.Producers; +using Microsoft.Extensions.DependencyInjection; + +services.AddKafka(kafka => kafka + .AddCluster(cluster => cluster + .WithBrokers(new[] { "localhost:9092" }) + .AddProducer( + "product-events", + producer => + producer + .WithAcks(Acks.Leader) + ) + ) +); +``` + +## How to customize compression + +You can find more information in the [Compression guide](compression). + diff --git a/website/versioned_docs/version-2.x/introduction.md b/website/versioned_docs/version-2.x/introduction.md new file mode 100644 index 000000000..e7b17b25e --- /dev/null +++ b/website/versioned_docs/version-2.x/introduction.md @@ -0,0 +1,52 @@ +--- +sidebar_position: 1 +description: KafkaFlow is a .NET framework to create Kafka-based applications, simple to use and extend. +sidebar_label: Introduction +slug: / +--- + +# Introduction to KafkaFlow + +⚡️ KafkaFlow was designed to build .NET applications on top of Apache Kafka **in a simple and maintainable way**. + +🏗 Built on top of [Confluent Kafka Client](https://github.com/confluentinc/confluent-kafka-dotnet). + +🔌 Extensible by design. + +Get started building by installing [KafkaFlow](getting-started/installation.md) or following our [Quickstart](getting-started/create-your-first-application.md). + +## Features {#features} + +Our goal is to empower you to build event-driven applications on top of Apache Kafka. +To do that, KafkaFlow gives you access to features like: + +- Multi-threaded consumer with message order guarantee. +- [Middlewares](guides/middlewares/) support for producing and consuming messages. +- Support topics with different message types. +- Consumers with many topics. +- [Serializer middleware](guides/middlewares/serializer-middleware.md) with **ApacheAvro**, **ProtoBuf** and **Json** algorithms. +- [Schema Registry](guides/middlewares/serializer-middleware.md#adding-schema-registry-support) support. +- [Compression](guides/compression.md) using native Confluent Kafka client compression or compressor middleware. +- [Global Events Subcription](guides/global-events.md) for message production and consumption. +- [Open Telemetry Instrumentation](guides/open-telemetry.md) for traces and baggage signals. +- Graceful shutdown (wait to finish processing to shutdown). +- Store offset when processing ends, avoiding message loss. +- Supports .NET Core and .NET Framework. +- Can be used with any dependency injection framework (see [here](guides/dependency-injection.md)). +- Fluent configuration. +- [Admin Web API](guides/admin/web-api.md) that allows pause, resume and restart consumers, change workers count, and rewind offsets, **all at runtime**. +- [Dashboard UI](guides/admin/dashboard.md) that allows to visualize of relevant information about all consumers and managing them. + +## Join the community {#join-the-community} + +- [GitHub](https://github.com/farfetch/kafkaflow): For new feature requests, bug reporting or contributing with your own pull request. +- [Slack](https://join.slack.com/t/kafkaflow/shared_invite/zt-puihrtcl-NnnylPZloAiVlQfsw~RD6Q): The place to be if you want to ask questions or share ideas. +- [Stack Overflow](https://stackoverflow.com/questions/tagged/kafkaflow): The best place to start if you have a question. + +## Something missing here? {#something-missing} + +If you have suggestions to improve the documentation, please send us a new [issue](https://github.com/farfetch/kafkaflow/issues). + +## License + +KafkaFlow is a free and open source project, released under the permissible [MIT license](https://github.com/Farfetch/kafkaflow/blob/master/LICENSE). diff --git a/website/versioned_docs/version-2.x/reference/KafkaFlow.Admin/_category_.json b/website/versioned_docs/version-2.x/reference/KafkaFlow.Admin/_category_.json new file mode 100644 index 000000000..5d71067d7 --- /dev/null +++ b/website/versioned_docs/version-2.x/reference/KafkaFlow.Admin/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "KafkaFlow.Admin", + "position": 2, + "link": { + "type": "generated-index" + } +} diff --git a/website/versioned_docs/version-2.x/reference/KafkaFlow.BatchConsume/_category_.json b/website/versioned_docs/version-2.x/reference/KafkaFlow.BatchConsume/_category_.json new file mode 100644 index 000000000..7cc5dcaf6 --- /dev/null +++ b/website/versioned_docs/version-2.x/reference/KafkaFlow.BatchConsume/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "KafkaFlow.BatchConsume", + "position": 3, + "link": { + "type": "generated-index" + } +} diff --git a/website/versioned_docs/version-2.x/reference/KafkaFlow.Compressor/_category_.json b/website/versioned_docs/version-2.x/reference/KafkaFlow.Compressor/_category_.json new file mode 100644 index 000000000..e7bf262a0 --- /dev/null +++ b/website/versioned_docs/version-2.x/reference/KafkaFlow.Compressor/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "KafkaFlow.Compressor", + "position": 4, + "link": { + "type": "generated-index" + } +} diff --git a/website/versioned_docs/version-2.x/reference/KafkaFlow.Extensions.Hosting/_category_.json b/website/versioned_docs/version-2.x/reference/KafkaFlow.Extensions.Hosting/_category_.json new file mode 100644 index 000000000..a60915f75 --- /dev/null +++ b/website/versioned_docs/version-2.x/reference/KafkaFlow.Extensions.Hosting/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "KafkaFlow.Extensions.Hosting", + "position": 6, + "link": { + "type": "generated-index" + } +} diff --git a/website/versioned_docs/version-2.x/reference/KafkaFlow.LogHandler.Console/_category_.json b/website/versioned_docs/version-2.x/reference/KafkaFlow.LogHandler.Console/_category_.json new file mode 100644 index 000000000..700ecc050 --- /dev/null +++ b/website/versioned_docs/version-2.x/reference/KafkaFlow.LogHandler.Console/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "KafkaFlow.LogHandler.Console", + "position": 7, + "link": { + "type": "generated-index" + } +} diff --git a/website/versioned_docs/version-2.x/reference/KafkaFlow.LogHandler.Microsoft/_category_.json b/website/versioned_docs/version-2.x/reference/KafkaFlow.LogHandler.Microsoft/_category_.json new file mode 100644 index 000000000..6dda1bec8 --- /dev/null +++ b/website/versioned_docs/version-2.x/reference/KafkaFlow.LogHandler.Microsoft/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "KafkaFlow.LogHandler.Microsoft", + "position": 8, + "link": { + "type": "generated-index" + } +} diff --git a/website/versioned_docs/version-2.x/reference/KafkaFlow.Microsoft.DependencyInjection/_category_.json b/website/versioned_docs/version-2.x/reference/KafkaFlow.Microsoft.DependencyInjection/_category_.json new file mode 100644 index 000000000..486db03f9 --- /dev/null +++ b/website/versioned_docs/version-2.x/reference/KafkaFlow.Microsoft.DependencyInjection/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "KafkaFlow.Microsoft.DependencyInjection", + "position": 9, + "link": { + "type": "generated-index" + } +} diff --git a/website/versioned_docs/version-2.x/reference/KafkaFlow.SchemaRegistry/_category_.json b/website/versioned_docs/version-2.x/reference/KafkaFlow.SchemaRegistry/_category_.json new file mode 100644 index 000000000..13965578e --- /dev/null +++ b/website/versioned_docs/version-2.x/reference/KafkaFlow.SchemaRegistry/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "KafkaFlow.SchemaRegistry", + "position": 10, + "link": { + "type": "generated-index" + } +} diff --git a/website/versioned_docs/version-2.x/reference/KafkaFlow.Serializer.JsonCore/_category_.json b/website/versioned_docs/version-2.x/reference/KafkaFlow.Serializer.JsonCore/_category_.json new file mode 100644 index 000000000..e7f202562 --- /dev/null +++ b/website/versioned_docs/version-2.x/reference/KafkaFlow.Serializer.JsonCore/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "KafkaFlow.Serializer.JsonCore", + "position": 12, + "link": { + "type": "generated-index" + } +} diff --git a/website/versioned_docs/version-2.x/reference/KafkaFlow.Serializer.NewtonsoftJson/_category_.json b/website/versioned_docs/version-2.x/reference/KafkaFlow.Serializer.NewtonsoftJson/_category_.json new file mode 100644 index 000000000..c9d228580 --- /dev/null +++ b/website/versioned_docs/version-2.x/reference/KafkaFlow.Serializer.NewtonsoftJson/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "KafkaFlow.Serializer.NewtonsoftJson", + "position": 13, + "link": { + "type": "generated-index" + } +} diff --git a/website/versioned_docs/version-2.x/reference/KafkaFlow.Serializer.ProtobufNet/_category_.json b/website/versioned_docs/version-2.x/reference/KafkaFlow.Serializer.ProtobufNet/_category_.json new file mode 100644 index 000000000..e043382be --- /dev/null +++ b/website/versioned_docs/version-2.x/reference/KafkaFlow.Serializer.ProtobufNet/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "KafkaFlow.Serializer.ProtobufNet", + "position": 14, + "link": { + "type": "generated-index" + } +} diff --git a/website/versioned_docs/version-2.x/reference/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/_category_.json b/website/versioned_docs/version-2.x/reference/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/_category_.json new file mode 100644 index 000000000..abc81a69f --- /dev/null +++ b/website/versioned_docs/version-2.x/reference/KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "KafkaFlow.Serializer.SchemaRegistry.ConfluentAvro", + "position": 15, + "link": { + "type": "generated-index" + } +} diff --git a/website/versioned_docs/version-2.x/reference/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/_category_.json b/website/versioned_docs/version-2.x/reference/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/_category_.json new file mode 100644 index 000000000..89a4155e5 --- /dev/null +++ b/website/versioned_docs/version-2.x/reference/KafkaFlow.Serializer.SchemaRegistry.ConfluentJson/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "KafkaFlow.Serializer.SchemaRegistry.ConfluentJson", + "position": 16, + "link": { + "type": "generated-index" + } +} diff --git a/website/versioned_docs/version-2.x/reference/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/_category_.json b/website/versioned_docs/version-2.x/reference/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/_category_.json new file mode 100644 index 000000000..b3383f2b9 --- /dev/null +++ b/website/versioned_docs/version-2.x/reference/KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "KafkaFlow.Serializer.SchemaRegistry.ConfluentProtobuf", + "position": 17, + "link": { + "type": "generated-index" + } +} diff --git a/website/versioned_docs/version-2.x/reference/KafkaFlow.Serializer/_category_.json b/website/versioned_docs/version-2.x/reference/KafkaFlow.Serializer/_category_.json new file mode 100644 index 000000000..73405a081 --- /dev/null +++ b/website/versioned_docs/version-2.x/reference/KafkaFlow.Serializer/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "KafkaFlow.Serializer", + "position": 11, + "link": { + "type": "generated-index" + } +} diff --git a/website/versioned_docs/version-2.x/reference/KafkaFlow.TypedHandler/_category_.json b/website/versioned_docs/version-2.x/reference/KafkaFlow.TypedHandler/_category_.json new file mode 100644 index 000000000..6b7f92787 --- /dev/null +++ b/website/versioned_docs/version-2.x/reference/KafkaFlow.TypedHandler/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "KafkaFlow.TypedHandler", + "position": 18, + "link": { + "type": "generated-index" + } +} diff --git a/website/versioned_docs/version-2.x/reference/KafkaFlow.Unity/_category_.json b/website/versioned_docs/version-2.x/reference/KafkaFlow.Unity/_category_.json new file mode 100644 index 000000000..5db5426cf --- /dev/null +++ b/website/versioned_docs/version-2.x/reference/KafkaFlow.Unity/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "KafkaFlow.Unity", + "position": 19, + "link": { + "type": "generated-index" + } +} diff --git a/website/versioned_docs/version-2.x/reference/KafkaFlow/_category_.json b/website/versioned_docs/version-2.x/reference/KafkaFlow/_category_.json new file mode 100644 index 000000000..3bb255c0e --- /dev/null +++ b/website/versioned_docs/version-2.x/reference/KafkaFlow/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "KafkaFlow", + "position": 1, + "link": { + "type": "generated-index" + } +} diff --git a/website/versioned_docs/version-2.x/reference/_category_.json b/website/versioned_docs/version-2.x/reference/_category_.json new file mode 100644 index 000000000..22e0368dd --- /dev/null +++ b/website/versioned_docs/version-2.x/reference/_category_.json @@ -0,0 +1,7 @@ +{ + "label": "Reference", + "position": 4, + "link": { + "type": "generated-index" + } +} diff --git a/website/versioned_sidebars/version-2.x-sidebars.json b/website/versioned_sidebars/version-2.x-sidebars.json new file mode 100644 index 000000000..1ffa17dce --- /dev/null +++ b/website/versioned_sidebars/version-2.x-sidebars.json @@ -0,0 +1,144 @@ +{ + "tutorialSidebar": [ + "introduction", + { + "type": "category", + "label": "Getting Started", + "items": [ + { + "type": "doc", + "id": "getting-started/installation" + }, + { + "type": "doc", + "id": "getting-started/create-your-first-application", + "label": "Quickstart" + }, + { + "type": "doc", + "id": "getting-started/packages" + }, + { + "type": "doc", + "id": "getting-started/samples" + } + ], + "link": { + "type": "generated-index" + } + }, + { + "type": "category", + "label": "Guides", + "items": [ + { + "type": "doc", + "id": "guides/configuration" + }, + { + "type": "doc", + "id": "guides/producers" + }, + { + "type": "category", + "label": "Consumers", + "items": [ + { + "type": "doc", + "id": "guides/consumers/consumers" + }, + { + "type": "doc", + "id": "guides/consumers/add-consumers" + } + ], + "link": { + "type": "generated-index" + } + }, + { + "type": "category", + "label": "Middlewares", + "items": [ + { + "type": "doc", + "id": "guides/middlewares/middlewares" + }, + { + "type": "doc", + "id": "guides/middlewares/typed-handler-middleware" + }, + { + "type": "doc", + "id": "guides/middlewares/serializer-middleware" + }, + { + "type": "doc", + "id": "guides/middlewares/compressor-middleware" + }, + { + "type": "doc", + "id": "guides/middlewares/batch-consume-middleware" + }, + { + "type": "doc", + "id": "guides/middlewares/consumer-throttling-middleware" + } + ], + "link": { + "type": "generated-index" + } + }, + { + "type": "doc", + "id": "guides/compression" + }, + { + "type": "doc", + "id": "guides/logging" + }, + { + "type": "category", + "label": "Administration", + "items": [ + { + "type": "doc", + "id": "guides/admin/admin" + }, + { + "type": "doc", + "id": "guides/admin/web-api", + "label": "Web API" + }, + { + "type": "doc", + "id": "guides/admin/dashboard" + } + ], + "link": { + "type": "generated-index" + } + }, + { + "type": "doc", + "id": "guides/authentication" + }, + { + "type": "doc", + "id": "guides/global-events" + }, + { + "type": "doc", + "id": "guides/open-telemetry" + }, + { + "type": "doc", + "id": "guides/dependency-injection" + } + ], + "link": { + "type": "generated-index" + } + } + ] +} \ No newline at end of file diff --git a/website/versions.json b/website/versions.json new file mode 100644 index 000000000..353308aea --- /dev/null +++ b/website/versions.json @@ -0,0 +1,3 @@ +[ + "2.x" +] \ No newline at end of file From 3bee56dceac27a64bddf2f762a119252415928d3 Mon Sep 17 00:00:00 2001 From: Guilherme Ferreira Date: Mon, 27 Nov 2023 12:25:40 +0000 Subject: [PATCH 19/20] docs: fix versioned docs routing --- website/docs/getting-started/create-your-first-application.md | 2 +- website/docusaurus.config.js | 1 - .../getting-started/create-your-first-application.md | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/website/docs/getting-started/create-your-first-application.md b/website/docs/getting-started/create-your-first-application.md index b1a0e671a..1e1efe071 100644 --- a/website/docs/getting-started/create-your-first-application.md +++ b/website/docs/getting-started/create-your-first-application.md @@ -33,7 +33,7 @@ Create a new folder with the name _KafkaFlowQuickstart_. ### 2. Setup Apache Kafka -Inside the folder from step 1, create a `docker-compose.yml` file. You can download it from [here](../../../docker-compose.yml). +Inside the folder from step 1, create a `docker-compose.yml` file. You can download it from [here](https://github.com/Farfetch/kafkaflow/blob/master/docker-compose.yml). ### 3. Start the cluster diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index ad7f928be..2b41b511a 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -39,7 +39,6 @@ const config = { versions: { current: { label: '3.x', - path: '/', }, }, }, diff --git a/website/versioned_docs/version-2.x/getting-started/create-your-first-application.md b/website/versioned_docs/version-2.x/getting-started/create-your-first-application.md index e8b1e295c..941faefe2 100644 --- a/website/versioned_docs/version-2.x/getting-started/create-your-first-application.md +++ b/website/versioned_docs/version-2.x/getting-started/create-your-first-application.md @@ -33,7 +33,7 @@ Create a new folder with the name _KafkaFlowQuickstart_. ### 2. Setup Apache Kafka -Inside the folder from step 1, create a `docker-compose.yml` file. You can download it from [here](../../../docker-compose.yml). +Inside the folder from step 1, create a `docker-compose.yml` file. You can download it from [here](https://github.com/Farfetch/kafkaflow/blob/master/docker-compose.yml). ### 3. Start the cluster From c5417f92d489209256ae3b1f46d8e830ca800e15 Mon Sep 17 00:00:00 2001 From: Joel Oliveira Date: Mon, 27 Nov 2023 16:21:50 +0000 Subject: [PATCH 20/20] docs: update v2 documentation --- .../versioned_docs/version-2.x/getting-started/samples.md | 6 ++++++ .../version-2.x/guides/consumers/add-consumers.md | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/website/versioned_docs/version-2.x/getting-started/samples.md b/website/versioned_docs/version-2.x/getting-started/samples.md index aba90fd4a..b3766d631 100644 --- a/website/versioned_docs/version-2.x/getting-started/samples.md +++ b/website/versioned_docs/version-2.x/getting-started/samples.md @@ -53,3 +53,9 @@ You can find the code here: [/samples/KafkaFlow.Sample.PauseConsumerOnError](htt This is a sample that shows how to throttle a consumer based on others consumers lag You can find the code here: [/samples/KafkaFlow.Sample.ConsumerThrottling](https://github.com/Farfetch/kafkaflow/tree/master/samples/KafkaFlow.Sample.ConsumerThrottling) + +## Wildcard Consumers + +This sample shows how to use a consumer to handle all the topics according to a naming convention. This is not a feature of KafkaFlow, but a demonstration of how to use the pattern conventions exposed by [librdkafka](https://github.com/confluentinc/librdkafka/tree/95a542c87c61d2c45b445f91c73dd5442eb04f3c) ([here](https://github.com/confluentinc/librdkafka/blob/95a542c87c61d2c45b445f91c73dd5442eb04f3c/src-cpp/rdkafkacpp.h#L2681)). + +You can find the code here: [/samples/KafkaFlow.Sample.WildcardConsumer](https://github.com/Farfetch/kafkaflow/tree/master/samples/KafkaFlow.Sample.WildcardConsumer) \ No newline at end of file diff --git a/website/versioned_docs/version-2.x/guides/consumers/add-consumers.md b/website/versioned_docs/version-2.x/guides/consumers/add-consumers.md index 0d2ae78bd..50f1aadf1 100644 --- a/website/versioned_docs/version-2.x/guides/consumers/add-consumers.md +++ b/website/versioned_docs/version-2.x/guides/consumers/add-consumers.md @@ -31,6 +31,11 @@ services.AddKafka(kafka => kafka On a Consumer, you can configure the Middlewares that will be invoked. You can find more information on how to configure Middlewares [here](../middlewares). +:::tip +You can use a naming pattern such as a wildcard to connect to any topic that matches a naming convention. +You can find a sample on [here](https://github.com/Farfetch/kafkaflow/tree/master/samples/KafkaFlow.Sample.WildcardConsumer). +::: + ## Automatic Partitions Assignment Using the `Topic()` or `Topics()` methods, the consumer will trigger the automatic partition assignment that will distribute the topic partitions across the application instances.