session-expiration-alert
Version:
An Angular module to time session expiration. When user session idle time reaches a threshold, then pop up a modal dialog to let user choose to continue session or log out the system. When user session is expired, timer will stop and user will be logged o
1 lines • 18.3 kB
Source Map (JSON)
{"version":3,"file":"session-expiration-alert.mjs","sources":["../../../projects/session-expiration-alert/src/lib/services/session-interrupt.service.ts","../../../projects/session-expiration-alert/src/lib/models/session-expiration-config.ts","../../../projects/session-expiration-alert/src/lib/services/session-timer.service.ts","../../../projects/session-expiration-alert/src/lib/components/session-expiration-alert/session-expiration-alert.component.ts","../../../projects/session-expiration-alert/src/lib/components/session-expiration-alert/session-expiration-alert.component.html","../../../projects/session-expiration-alert/src/lib/services/session-timer-http-interceptor.ts","../../../projects/session-expiration-alert/src/lib/session-expiration-alert.module.ts","../../../projects/session-expiration-alert/src/public-api.ts","../../../projects/session-expiration-alert/src/session-expiration-alert.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\r\n\r\n@Injectable()\r\nexport class SessionInterruptService {\r\n constructor() {}\r\n\r\n /**\r\n * Method to refresh session cookie. Normally, this method issue a quick API call to server.\r\n *\r\n * @memberof SessionInterruptService\r\n */\r\n continueSession() {\r\n console.log('You clicked continue session.');\r\n }\r\n\r\n /**\r\n * Method to remove session cookie. Normally, this method redirect to website logout endpoint.\r\n *\r\n * @memberof SessionInterruptService\r\n */\r\n stopSession() {\r\n console.log('You clicked logout.');\r\n }\r\n\r\n /**\r\n * Method to handle expiration event. Can be empty.\r\n */\r\n onExpire() {\r\n console.log('Session expired.');\r\n }\r\n}\r\n","import { InjectionToken } from '@angular/core';\r\n\r\nexport interface SessionExpirationConfig {\r\n totalMinutes: number;\r\n}\r\n\r\nexport const ConfigToken = new InjectionToken<SessionExpirationConfig>(\r\n 'config'\r\n);\r\n","import { Inject, Injectable } from '@angular/core';\r\nimport { interval, Observable, Subject, Subscription } from 'rxjs';\r\nimport {\r\n ConfigToken,\r\n SessionExpirationConfig,\r\n} from '../models/session-expiration-config';\r\n\r\n@Injectable()\r\nexport class SessionTimerService {\r\n private readonly _timeoutSeconds: number;\r\n private _count: number = 0;\r\n private timerSubscription!: Subscription;\r\n private timer: Observable<number> = interval(1000);\r\n private _remainSeconds = new Subject<number>();\r\n /**\r\n * Observable to get session remaining time (in seconds).\r\n *\r\n * Subscribers need to unsubscribe to it before hosting element is destroyed.\r\n *\r\n * @memberof SessionTimerService\r\n */\r\n remainSeconds$ = this._remainSeconds.asObservable();\r\n\r\n constructor(@Inject(ConfigToken) readonly config: SessionExpirationConfig) {\r\n this._timeoutSeconds = config.totalMinutes * 60;\r\n }\r\n\r\n startTimer() {\r\n this.stopTimer();\r\n this._count = this._timeoutSeconds;\r\n this.timerSubscription = this.timer.subscribe((n) => {\r\n if (this._count > 0) {\r\n this._count--;\r\n this._remainSeconds.next(this._count);\r\n }\r\n });\r\n }\r\n\r\n stopTimer() {\r\n if (this.timerSubscription) {\r\n this.timerSubscription.unsubscribe();\r\n }\r\n }\r\n\r\n resetTimer() {\r\n this.startTimer();\r\n }\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ElementRef,\r\n HostListener,\r\n Input,\r\n OnChanges,\r\n OnDestroy,\r\n OnInit,\r\n SimpleChanges,\r\n} from '@angular/core';\r\nimport { Subscription } from 'rxjs';\r\nimport { SessionInterruptService } from '../../services/session-interrupt.service';\r\nimport { SessionTimerService } from '../../services/session-timer.service';\r\n\r\n@Component({\r\n selector: 'session-expiration-alert',\r\n templateUrl: './session-expiration-alert.component.html',\r\n styleUrls: ['./session-expiration-alert.component.css', './btn.css'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n standalone: false,\r\n})\r\nexport class SessionExpirationAlertComponent\r\n implements OnInit, OnChanges, OnDestroy\r\n{\r\n /**\r\n * Should start the timer or not. Usually, you can set it to true if a user is authenticated.\r\n */\r\n @Input() startTimer? = true;\r\n\r\n /**\r\n * Count down seconds.\r\n */\r\n @Input() alertAt? = 60;\r\n\r\n showModal = false;\r\n expired = false;\r\n private sessionTimerSubscription!: Subscription;\r\n\r\n constructor(\r\n private el: ElementRef,\r\n private sessionInterrupter: SessionInterruptService,\r\n public sessionTimer: SessionTimerService\r\n ) {}\r\n\r\n ngOnInit() {\r\n if (!this.sessionTimerSubscription && this.startTimer) {\r\n this.trackSessionTime();\r\n }\r\n // move element to bottom of page (just before </body>)\r\n // so it can be displayed above everything else\r\n document.body.appendChild(this.el.nativeElement);\r\n }\r\n ngOnChanges(changes: SimpleChanges): void {\r\n if (changes['startTimer']) {\r\n this.cleanUp();\r\n if (changes['startTimer'].currentValue) {\r\n this.trackSessionTime();\r\n }\r\n }\r\n }\r\n\r\n private trackSessionTime() {\r\n this.sessionTimer.startTimer();\r\n this.expired = false;\r\n this.sessionTimerSubscription = this.sessionTimer.remainSeconds$.subscribe(\r\n (t) => {\r\n if (t === this.alertAt) {\r\n this.open();\r\n }\r\n if (t === 0) {\r\n this.expired = true;\r\n this.cleanUp();\r\n this.sessionInterrupter.onExpire();\r\n }\r\n }\r\n );\r\n }\r\n continue() {\r\n this.sessionInterrupter.continueSession();\r\n this.sessionTimer.resetTimer();\r\n this.close();\r\n }\r\n logout() {\r\n this.sessionTimer.stopTimer();\r\n this.close();\r\n this.sessionInterrupter.stopSession();\r\n }\r\n\r\n open(): void {\r\n this.showModal = true;\r\n document.body.classList.add('sea-modal-open');\r\n }\r\n\r\n close(): void {\r\n this.showModal = false;\r\n document.body.classList.remove('sea-modal-open');\r\n }\r\n\r\n cleanUp() {\r\n this.sessionTimer.stopTimer();\r\n if (this.sessionTimerSubscription) {\r\n this.sessionTimerSubscription.unsubscribe();\r\n }\r\n }\r\n reload() {\r\n this.close();\r\n location.reload();\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this.el.nativeElement.remove();\r\n this.cleanUp();\r\n }\r\n\r\n @HostListener('document:keydown.tab', ['$event'])\r\n handleTabKey(e: KeyboardEvent) {\r\n const modal = document.querySelector('#session-expiration-alert');\r\n if (modal) {\r\n const btn1 = modal.querySelector<HTMLButtonElement>('button.btn-primary');\r\n const btn2 = modal.querySelector<HTMLButtonElement>(\r\n 'button.btn-secondary'\r\n );\r\n if (document.activeElement === btn1) {\r\n btn2?.focus();\r\n e.preventDefault();\r\n }\r\n }\r\n }\r\n @HostListener('document:keydown.shift.tab', ['$event'])\r\n handleShiftTabKey(e: KeyboardEvent) {\r\n const modal = document.querySelector('#session-expiration-alert');\r\n if (modal) {\r\n const btn1 = modal.querySelector<HTMLButtonElement>('button.btn-primary');\r\n const btn2 = modal.querySelector<HTMLButtonElement>(\r\n 'button.btn-secondary'\r\n );\r\n if (document.activeElement === btn2) {\r\n btn1?.focus();\r\n e.preventDefault();\r\n }\r\n }\r\n }\r\n}\r\n","<div\r\n class=\"sea-modal\"\r\n id=\"session-expiration-alert\"\r\n role=\"dialog\"\r\n tabindex=\"-1\"\r\n aria-modal=\"true\"\r\n aria-label=\"session-expiration-alert\"\r\n [hidden]=\"!showModal\"\r\n>\r\n <div role=\"document\" class=\"sea-modal-content\" id=\"expiring\" *ngIf=\"!expired\">\r\n <div class=\"sea-modal-header\">Session is about to expire</div>\r\n <div class=\"sea-modal-body\">\r\n <p>\r\n Your session will expire in\r\n {{ sessionTimer.remainSeconds$ | async }} seconds.\r\n </p>\r\n </div>\r\n <div class=\"sea-modal-footer\">\r\n <button type=\"button\" class=\"btn btn-secondary\" (click)=\"logout()\">\r\n Logout\r\n </button>\r\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"continue()\">\r\n Continue Session\r\n </button>\r\n </div>\r\n </div>\r\n <div role=\"document\" class=\"sea-modal-content\" id=\"expired\" *ngIf=\"expired\">\r\n <div class=\"sea-modal-header\">Session expired</div>\r\n <div class=\"sea-modal-body\">\r\n <p>\r\n The current page is idle due to lack of activity. You can try to reload\r\n this page or log out of the website.\r\n </p>\r\n </div>\r\n <div class=\"sea-modal-footer\">\r\n <button type=\"button\" class=\"btn btn-secondary\" (click)=\"logout()\">\r\n Logout\r\n </button>\r\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"reload()\">\r\n Reload Page\r\n </button>\r\n </div>\r\n </div>\r\n</div>\r\n<div class=\"sea-modal-background\" [hidden]=\"!showModal\"></div>\r\n","import { HttpEvent, HttpHandlerFn, HttpRequest } from '@angular/common/http';\r\nimport { inject } from '@angular/core';\r\nimport { Observable } from 'rxjs';\r\nimport { SessionTimerService } from '../services/session-timer.service';\r\n\r\nexport function sessionTimerHttpInterceptor(\r\n req: HttpRequest<unknown>,\r\n next: HttpHandlerFn\r\n): Observable<HttpEvent<unknown>> {\r\n const timerService = inject(SessionTimerService);\r\n timerService.resetTimer();\r\n return next(req);\r\n}\r\n","import { CommonModule } from '@angular/common';\r\nimport { provideHttpClient, withInterceptors } from '@angular/common/http';\r\nimport { ModuleWithProviders, NgModule } from '@angular/core';\r\n\r\nimport { SessionExpirationAlertComponent } from './components/session-expiration-alert/session-expiration-alert.component';\r\nimport {\r\n ConfigToken,\r\n SessionExpirationConfig,\r\n} from './models/session-expiration-config';\r\nimport { SessionInterruptService } from './services/session-interrupt.service';\r\nimport { sessionTimerHttpInterceptor } from './services/session-timer-http-interceptor';\r\nimport { SessionTimerService } from './services/session-timer.service';\r\n\r\n@NgModule({\r\n imports: [CommonModule],\r\n declarations: [SessionExpirationAlertComponent],\r\n providers: [\r\n SessionTimerService,\r\n provideHttpClient(withInterceptors([sessionTimerHttpInterceptor])),\r\n SessionInterruptService,\r\n ],\r\n exports: [SessionExpirationAlertComponent],\r\n})\r\nexport class SessionExpirationAlert {\r\n /**\r\n *\r\n * @param config SessionExpirationConfig, default value: { totalMinutes: 20 }\r\n *\r\n */\r\n static forRoot(\r\n config: SessionExpirationConfig = {\r\n totalMinutes: 20,\r\n }\r\n ): ModuleWithProviders<SessionExpirationAlert> {\r\n return {\r\n ngModule: SessionExpirationAlert,\r\n providers: [\r\n {\r\n provide: ConfigToken,\r\n useValue: config,\r\n },\r\n ],\r\n };\r\n }\r\n}\r\n","/*\r\n * Public API Surface of session-expiration-alert\r\n */\r\n\r\nexport * from './lib/session-expiration-alert.module';\r\nexport * from './lib/models/session-expiration-config';\r\nexport * from './lib/services/session-interrupt.service';\r\nexport * from './lib/services/session-timer-http-interceptor';\r\nexport * from './lib/services/session-timer.service';\r\nexport * from './lib/components/session-expiration-alert/session-expiration-alert.component';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.SessionInterruptService","i2.SessionTimerService"],"mappings":";;;;;;;MAGa,uBAAuB,CAAA;AAClC,IAAA,WAAA,GAAA;AAEA;;;;AAIG;IACH,eAAe,GAAA;AACb,QAAA,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC;;AAG9C;;;;AAIG;IACH,WAAW,GAAA;AACT,QAAA,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC;;AAGpC;;AAEG;IACH,QAAQ,GAAA;AACN,QAAA,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;;uGAzBtB,uBAAuB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;2GAAvB,uBAAuB,EAAA,CAAA;;2FAAvB,uBAAuB,EAAA,UAAA,EAAA,CAAA;kBADnC;;;MCIY,WAAW,GAAG,IAAI,cAAc,CAC3C,QAAQ;;MCCG,mBAAmB,CAAA;AAeY,IAAA,MAAA;AAdzB,IAAA,eAAe;IACxB,MAAM,GAAW,CAAC;AAClB,IAAA,iBAAiB;AACjB,IAAA,KAAK,GAAuB,QAAQ,CAAC,IAAI,CAAC;AAC1C,IAAA,cAAc,GAAG,IAAI,OAAO,EAAU;AAC9C;;;;;;AAMG;AACH,IAAA,cAAc,GAAG,IAAI,CAAC,cAAc,CAAC,YAAY,EAAE;AAEnD,IAAA,WAAA,CAA0C,MAA+B,EAAA;QAA/B,IAAM,CAAA,MAAA,GAAN,MAAM;QAC9C,IAAI,CAAC,eAAe,GAAG,MAAM,CAAC,YAAY,GAAG,EAAE;;IAGjD,UAAU,GAAA;QACR,IAAI,CAAC,SAAS,EAAE;AAChB,QAAA,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,eAAe;AAClC,QAAA,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,KAAI;AAClD,YAAA,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;gBACnB,IAAI,CAAC,MAAM,EAAE;gBACb,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;;AAEzC,SAAC,CAAC;;IAGJ,SAAS,GAAA;AACP,QAAA,IAAI,IAAI,CAAC,iBAAiB,EAAE;AAC1B,YAAA,IAAI,CAAC,iBAAiB,CAAC,WAAW,EAAE;;;IAIxC,UAAU,GAAA;QACR,IAAI,CAAC,UAAU,EAAE;;AArCR,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,kBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,mBAAmB,kBAeV,WAAW,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;2GAfpB,mBAAmB,EAAA,CAAA;;2FAAnB,mBAAmB,EAAA,UAAA,EAAA,CAAA;kBAD/B;;0BAgBc,MAAM;2BAAC,WAAW;;;MCDpB,+BAA+B,CAAA;AAkBhC,IAAA,EAAA;AACA,IAAA,kBAAA;AACD,IAAA,YAAA;AAjBT;;AAEG;IACM,UAAU,GAAI,IAAI;AAE3B;;AAEG;IACM,OAAO,GAAI,EAAE;IAEtB,SAAS,GAAG,KAAK;IACjB,OAAO,GAAG,KAAK;AACP,IAAA,wBAAwB;AAEhC,IAAA,WAAA,CACU,EAAc,EACd,kBAA2C,EAC5C,YAAiC,EAAA;QAFhC,IAAE,CAAA,EAAA,GAAF,EAAE;QACF,IAAkB,CAAA,kBAAA,GAAlB,kBAAkB;QACnB,IAAY,CAAA,YAAA,GAAZ,YAAY;;IAGrB,QAAQ,GAAA;QACN,IAAI,CAAC,IAAI,CAAC,wBAAwB,IAAI,IAAI,CAAC,UAAU,EAAE;YACrD,IAAI,CAAC,gBAAgB,EAAE;;;;QAIzB,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC;;AAElD,IAAA,WAAW,CAAC,OAAsB,EAAA;AAChC,QAAA,IAAI,OAAO,CAAC,YAAY,CAAC,EAAE;YACzB,IAAI,CAAC,OAAO,EAAE;AACd,YAAA,IAAI,OAAO,CAAC,YAAY,CAAC,CAAC,YAAY,EAAE;gBACtC,IAAI,CAAC,gBAAgB,EAAE;;;;IAKrB,gBAAgB,GAAA;AACtB,QAAA,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE;AAC9B,QAAA,IAAI,CAAC,OAAO,GAAG,KAAK;AACpB,QAAA,IAAI,CAAC,wBAAwB,GAAG,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,SAAS,CACxE,CAAC,CAAC,KAAI;AACJ,YAAA,IAAI,CAAC,KAAK,IAAI,CAAC,OAAO,EAAE;gBACtB,IAAI,CAAC,IAAI,EAAE;;AAEb,YAAA,IAAI,CAAC,KAAK,CAAC,EAAE;AACX,gBAAA,IAAI,CAAC,OAAO,GAAG,IAAI;gBACnB,IAAI,CAAC,OAAO,EAAE;AACd,gBAAA,IAAI,CAAC,kBAAkB,CAAC,QAAQ,EAAE;;AAEtC,SAAC,CACF;;IAEH,QAAQ,GAAA;AACN,QAAA,IAAI,CAAC,kBAAkB,CAAC,eAAe,EAAE;AACzC,QAAA,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE;QAC9B,IAAI,CAAC,KAAK,EAAE;;IAEd,MAAM,GAAA;AACJ,QAAA,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE;QAC7B,IAAI,CAAC,KAAK,EAAE;AACZ,QAAA,IAAI,CAAC,kBAAkB,CAAC,WAAW,EAAE;;IAGvC,IAAI,GAAA;AACF,QAAA,IAAI,CAAC,SAAS,GAAG,IAAI;QACrB,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,gBAAgB,CAAC;;IAG/C,KAAK,GAAA;AACH,QAAA,IAAI,CAAC,SAAS,GAAG,KAAK;QACtB,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,gBAAgB,CAAC;;IAGlD,OAAO,GAAA;AACL,QAAA,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE;AAC7B,QAAA,IAAI,IAAI,CAAC,wBAAwB,EAAE;AACjC,YAAA,IAAI,CAAC,wBAAwB,CAAC,WAAW,EAAE;;;IAG/C,MAAM,GAAA;QACJ,IAAI,CAAC,KAAK,EAAE;QACZ,QAAQ,CAAC,MAAM,EAAE;;IAGnB,WAAW,GAAA;AACT,QAAA,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,MAAM,EAAE;QAC9B,IAAI,CAAC,OAAO,EAAE;;AAIhB,IAAA,YAAY,CAAC,CAAgB,EAAA;QAC3B,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,2BAA2B,CAAC;QACjE,IAAI,KAAK,EAAE;YACT,MAAM,IAAI,GAAG,KAAK,CAAC,aAAa,CAAoB,oBAAoB,CAAC;YACzE,MAAM,IAAI,GAAG,KAAK,CAAC,aAAa,CAC9B,sBAAsB,CACvB;AACD,YAAA,IAAI,QAAQ,CAAC,aAAa,KAAK,IAAI,EAAE;gBACnC,IAAI,EAAE,KAAK,EAAE;gBACb,CAAC,CAAC,cAAc,EAAE;;;;AAKxB,IAAA,iBAAiB,CAAC,CAAgB,EAAA;QAChC,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,2BAA2B,CAAC;QACjE,IAAI,KAAK,EAAE;YACT,MAAM,IAAI,GAAG,KAAK,CAAC,aAAa,CAAoB,oBAAoB,CAAC;YACzE,MAAM,IAAI,GAAG,KAAK,CAAC,aAAa,CAC9B,sBAAsB,CACvB;AACD,YAAA,IAAI,QAAQ,CAAC,aAAa,KAAK,IAAI,EAAE;gBACnC,IAAI,EAAE,KAAK,EAAE;gBACb,CAAC,CAAC,cAAc,EAAE;;;;uGArHb,+BAA+B,EAAA,IAAA,EAAA,CAAA,EAAA,KAAA,EAAA,EAAA,CAAA,UAAA,EAAA,EAAA,EAAA,KAAA,EAAAA,uBAAA,EAAA,EAAA,EAAA,KAAA,EAAAC,mBAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAA/B,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,+BAA+B,wSCtB5C,4lDA6CA,EAAA,MAAA,EAAA,CAAA,qsCAAA,EAAA,22BAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,IAAA,EAAA,QAAA,EAAA,QAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,UAAA,EAAA,UAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAA,EAAA,CAAA,SAAA,EAAA,IAAA,EAAA,OAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FDvBa,+BAA+B,EAAA,UAAA,EAAA,CAAA;kBAP3C,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,0BAA0B,EAGnB,eAAA,EAAA,uBAAuB,CAAC,MAAM,cACnC,KAAK,EAAA,QAAA,EAAA,4lDAAA,EAAA,MAAA,EAAA,CAAA,qsCAAA,EAAA,22BAAA,CAAA,EAAA;iJAQR,UAAU,EAAA,CAAA;sBAAlB;gBAKQ,OAAO,EAAA,CAAA;sBAAf;gBAmFD,YAAY,EAAA,CAAA;sBADX,YAAY;uBAAC,sBAAsB,EAAE,CAAC,QAAQ,CAAC;gBAehD,iBAAiB,EAAA,CAAA;sBADhB,YAAY;uBAAC,4BAA4B,EAAE,CAAC,QAAQ,CAAC;;;AE5HxC,SAAA,2BAA2B,CACzC,GAAyB,EACzB,IAAmB,EAAA;AAEnB,IAAA,MAAM,YAAY,GAAG,MAAM,CAAC,mBAAmB,CAAC;IAChD,YAAY,CAAC,UAAU,EAAE;AACzB,IAAA,OAAO,IAAI,CAAC,GAAG,CAAC;AAClB;;MCWa,sBAAsB,CAAA;AACjC;;;;AAIG;IACH,OAAO,OAAO,CACZ,MAAkC,GAAA;AAChC,QAAA,YAAY,EAAE,EAAE;AACjB,KAAA,EAAA;QAED,OAAO;AACL,YAAA,QAAQ,EAAE,sBAAsB;AAChC,YAAA,SAAS,EAAE;AACT,gBAAA;AACE,oBAAA,OAAO,EAAE,WAAW;AACpB,oBAAA,QAAQ,EAAE,MAAM;AACjB,iBAAA;AACF,aAAA;SACF;;uGAnBQ,sBAAsB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,QAAA,EAAA,CAAA;AAAtB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,mBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,sBAAsB,EARlB,YAAA,EAAA,CAAA,+BAA+B,CADpC,EAAA,OAAA,EAAA,CAAA,YAAY,aAOZ,+BAA+B,CAAA,EAAA,CAAA;AAE9B,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,mBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,sBAAsB,EAPtB,SAAA,EAAA;YACT,mBAAmB;AACnB,YAAA,iBAAiB,CAAC,gBAAgB,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC;YAClE,uBAAuB;AACxB,SAAA,EAAA,OAAA,EAAA,CANS,YAAY,CAAA,EAAA,CAAA;;2FASX,sBAAsB,EAAA,UAAA,EAAA,CAAA;kBAVlC,QAAQ;AAAC,YAAA,IAAA,EAAA,CAAA;oBACR,OAAO,EAAE,CAAC,YAAY,CAAC;oBACvB,YAAY,EAAE,CAAC,+BAA+B,CAAC;AAC/C,oBAAA,SAAS,EAAE;wBACT,mBAAmB;AACnB,wBAAA,iBAAiB,CAAC,gBAAgB,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC;wBAClE,uBAAuB;AACxB,qBAAA;oBACD,OAAO,EAAE,CAAC,+BAA+B,CAAC;AAC3C,iBAAA;;;ACtBD;;AAEG;;ACFH;;AAEG;;;;"}