@cleavelandprice/ngx-lib 4.7.14 → 4.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/cleavelandprice-ngx-lib-active-directory-kendo.mjs +619 -0
- package/fesm2022/cleavelandprice-ngx-lib-active-directory-kendo.mjs.map +1 -0
- package/fesm2022/cleavelandprice-ngx-lib-authentication-sso.mjs +18 -6
- package/fesm2022/cleavelandprice-ngx-lib-authentication-sso.mjs.map +1 -1
- package/fesm2022/cleavelandprice-ngx-lib-table.mjs +9 -11
- package/fesm2022/cleavelandprice-ngx-lib-table.mjs.map +1 -1
- package/package.json +5 -1
- package/types/cleavelandprice-ngx-lib-active-directory-kendo.d.ts +188 -0
- package/types/cleavelandprice-ngx-lib-table.d.ts +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cleavelandprice-ngx-lib-active-directory-kendo.mjs","sources":["../../../../projects/cleavelandprice/ngx-lib/active-directory/kendo/src/model/user-chooser-default-settings.ts","../../../../projects/cleavelandprice/ngx-lib/active-directory/kendo/src/components/user-chooser-list/user-chooser-list.ts","../../../../projects/cleavelandprice/ngx-lib/active-directory/kendo/src/components/user-chooser-list/user-chooser-list.html","../../../../projects/cleavelandprice/ngx-lib/active-directory/kendo/src/components/user-chooser-dialog/user-chooser-dialog.ts","../../../../projects/cleavelandprice/ngx-lib/active-directory/kendo/src/components/user-chooser-dialog/user-chooser-dialog.html","../../../../projects/cleavelandprice/ngx-lib/active-directory/kendo/src/components/user-field/user-field.ts","../../../../projects/cleavelandprice/ngx-lib/active-directory/kendo/src/components/user-field/user-field.html","../../../../projects/cleavelandprice/ngx-lib/active-directory/kendo/src/kendo-active-directory.module.ts","../../../../projects/cleavelandprice/ngx-lib/active-directory/kendo/src/cleavelandprice-ngx-lib-active-directory-kendo.ts"],"sourcesContent":["import { IUserChooserColumn } from \"./user-chooser-column-interface\";\r\nimport { IUserChooserSettings } from \"./user-chooser-settings-interface\";\r\nimport { SelectableSettings } from \"@progress/kendo-angular-grid\";\r\n\r\nexport const USER_CHOOSER_DEFAULT_SETTINGS = {\r\n usersTitle: 'Select User(s)',\r\n groupsTitle: 'Select Group(s)',\r\n displayMultiSelectInstructions: true,\r\n displayHideUnselectedToggle: true,\r\n displaySelectedCount: true,\r\n filterMode: 'Global' as 'Column' | 'Global' | 'Both' | 'None',\r\n groupable: true,\r\n sortable: true,\r\n pageable: false,\r\n pageSize: 150,\r\n height: 600,\r\n additionalWidth: 500,\r\n displayPhotos: true,\r\n photoColumnWidth: 40,\r\n returnType: 'AccountName' as 'AccountName' | 'Object',\r\n cancelReturnValue: 'cancel',\r\n okButtonText: 'Ok',\r\n cancelButtonText: 'Cancel',\r\n unselectButtonText: 'Unselect All',\r\n emptyDataPullMode: 'Users' as 'All' | 'Users' | 'Groups',\r\n selectionSettings: {\r\n checkboxOnly: false,\r\n mode: 'multiple' as 'single' | 'multiple',\r\n enabled: true,\r\n drag: true,\r\n cell: false,\r\n metaKeyMultiSelect: false\r\n } as SelectableSettings,\r\n userColumns: [\r\n { field: 'employeeNumber', title: 'Emp #', width: 120, columnFilterable: true, globalFilterable: true, sortable: true, groupable: true, hidden: true },\r\n { field: 'displayName', title: 'Display Name', width: 200, columnFilterable: true, globalFilterable: true, sortable: true, groupable: false },\r\n { field: 'department', title: 'Department', width: 200, columnFilterable: true, globalFilterable: true, sortable: true, groupable: true },\r\n { field: 'title', title: 'Title', width: 200, columnFilterable: true, globalFilterable: true, sortable: true, groupable: true },\r\n { field: 'telephoneNumber', title: 'Phone', width: 120, columnFilterable: true, globalFilterable: false, sortable: true, groupable: false },\r\n { field: 'sAMAccountName', title: 'Username', width: 200, columnFilterable: true, globalFilterable: true, sortable: true, groupable: false, hidden: true }\r\n ] as IUserChooserColumn[],\r\n groupColumns: [\r\n { field: 'name', title: 'Name', width: 200, columnFilterable: true, globalFilterable: true, sortable: true, groupable: false },\r\n { field: 'sAMAccountName', title: 'Username', width: 200, columnFilterable: true, globalFilterable: true, sortable: true, groupable: false, hidden: false }\r\n ]\r\n} as IUserChooserSettings","import { ChangeDetectorRef, Component, afterNextRender, computed, debounced, effect, inject, input, model, OnDestroy, signal, viewChild, ViewEncapsulation } from '@angular/core';\r\nimport { NgClass } from '@angular/common';\r\nimport { toObservable, toSignal } from '@angular/core/rxjs-interop';\r\n\r\nimport { of, Subscription, switchMap } from 'rxjs';\r\n\r\nimport { CleavelandPriceUser, Group } from '@cleavelandprice/ngx-lib/active-directory';\r\nimport { PhotoItem, SharePointService } from '@cleavelandprice/ngx-lib/sharepoint';\r\n\r\nimport { KENDO_GRID, GridComponent, RowArgs, RowClassArgs } from \"@progress/kendo-angular-grid\";\r\nimport { process } from '@progress/kendo-data-query';\r\n\r\nimport { IUserChooserSettings } from '../../model/user-chooser-settings-interface';\r\nimport { USER_CHOOSER_DEFAULT_SETTINGS } from '../../model/user-chooser-default-settings';\r\n\r\n@Component({\r\n selector: 'user-chooser-list',\r\n imports: [\r\n NgClass,\r\n KENDO_GRID\r\n ],\r\n templateUrl: './user-chooser-list.html',\r\n styleUrl: './user-chooser-list.scss',\r\n encapsulation: ViewEncapsulation.None // Required for rowClassCallback\r\n})\r\nexport class UserChooserList implements OnDestroy {\r\n #sp = inject(SharePointService);\r\n grid = viewChild<GridComponent>(GridComponent);\r\n settings = input<IUserChooserSettings>({\r\n ...USER_CHOOSER_DEFAULT_SETTINGS\r\n });\r\n\r\n data = input<(CleavelandPriceUser | Group)[]>([]);\r\n photoClass = input<string>('user-chooser-photo');\r\n selectedAccountNames = model<string[]>([]);\r\n filter = input<string>('');\r\n #debouncedFilter = debounced(() => this.filter(), 300);\r\n #filteredData = signal<(CleavelandPriceUser | Group)[]>([]);\r\n hideUnselected = input(false);\r\n mode = computed(() => this.data().at(0)?.hasOwnProperty('givenName') ? 'users' : 'groups');\r\n\r\n //#region Either passed in or pulled from the service\r\n photos = input<PhotoItem[] | undefined>();\r\n #photosFromService$ = toObservable(this.photos)\r\n .pipe(switchMap(photos => {\r\n if (photos) {\r\n return of(photos);\r\n }\r\n\r\n return (this.data().at(0)?.hasOwnProperty('givenName'))\r\n ? this.#sp.getPhotos()\r\n : of([]);\r\n }));\r\n #resolvedPhotos = toSignal(this.#photosFromService$, { initialValue: [] });\r\n //#endregion Either passed in or pulled from the service\r\n\r\n selectedCount = signal<number>(0);\r\n \r\n gridData = computed(() =>\r\n this.#debouncedFilter.value() ?\r\n this.#filteredData() :\r\n this.data()\r\n .filter(data =>\r\n !this.hideUnselected() ||\r\n this.selectedAccountNames()\r\n .some(item => item.toLowerCase() === data.sAMAccountName!.toLowerCase())\r\n )\r\n );\r\n\r\n #cdr = inject(ChangeDetectorRef);\r\n\r\n selectionChangeSubscription?: Subscription;\r\n\r\n constructor() {\r\n effect(() => {\r\n const filterableFields = this.settings().userColumns!\r\n .filter(c => c.globalFilterable ?? true)\r\n .map(c => c.field)\r\n ?? [];\r\n\r\n const filters = filterableFields.map(field => ({\r\n field: field,\r\n operator: 'contains',\r\n value: this.#debouncedFilter.value()\r\n }));\r\n\r\n this.#filteredData.set(\r\n process(\r\n //this.users(),\r\n this.data(),\r\n {\r\n filter: filters.length > 0 ? { logic: 'or', filters: filters } : undefined\r\n })\r\n .data\r\n .filter(data => !this.hideUnselected() || this.selectedAccountNames().some(s => s.toLowerCase() === data.sAMAccountName!.toLowerCase()))\r\n );\r\n });\r\n\r\n afterNextRender(() => {\r\n this.selectedCount.set(this.grid()?.selectionService.selected?.length ?? 0);\r\n\r\n this.selectionChangeSubscription = this.grid()?.selectionService.changes.subscribe((event) => {\r\n this.selectedCount.set(this.grid()?.selectionService.selected?.length ?? 0);\r\n });\r\n });\r\n }\r\n\r\n ngOnDestroy() {\r\n this.selectionChangeSubscription?.unsubscribe();\r\n }\r\n \r\n photo(user: CleavelandPriceUser): PhotoItem | null {\r\n return this.#resolvedPhotos()\r\n .find(p => p.accountName?.toLowerCase() === user.sAMAccountName!.toLowerCase())\r\n ?? null;\r\n }\r\n\r\n // Function to generate a case-insensitive key\r\n caseInsensitiveSelectBy = (context: RowArgs): string => {\r\n // Convert to string and then to lowercase to ensure consistency.\r\n return String(context.dataItem.sAMAccountName).toLowerCase();\r\n };\r\n\r\n unselectAll() {\r\n this.selectedAccountNames.set([]);\r\n this.#cdr.detectChanges();\r\n this.grid()?.selectionService.changes.emit({selectedRows: [], deselectedRows: [], shiftKey: false, ctrlKey: false});\r\n }\r\n\r\n rowClassCallback(context: RowClassArgs): any {\r\n if (this.mode() === 'groups') {\r\n return {\r\n 'disabled': false\r\n };\r\n } \r\n\r\n // Return an object with the class name as key and a condition as value\r\n return {\r\n 'disabled': !(context.dataItem as CleavelandPriceUser).enabled\r\n };\r\n }\r\n}","<kendo-grid #grid [kendoGridBinding]=\"gridData()\"\r\n [rowClass]=\"rowClassCallback.bind(this)\"\r\n [filterable]=\"settings().filterMode === 'Column' || settings().filterMode === 'Both'\"\r\n [groupable]=\"settings().groupable!\"\r\n [sortable]=\"settings().sortable!\"\r\n [pageSize]=\"settings().pageable! ? settings().pageSize! : 0\"\r\n [pageable]=\"settings().pageable!\"\r\n [height]=\"settings().height!\"\r\n [selectable]=\"settings().selectionSettings!\"\r\n [kendoGridSelectBy]=\"caseInsensitiveSelectBy\"\r\n [(selectedKeys)]=\"selectedAccountNames\">\r\n \r\n <!-- Checkbox is we are in checkbox selection mode -->\r\n @if (settings().selectionSettings?.checkboxOnly ?? false) {\r\n <kendo-grid-column [width]=\"30\">\r\n <ng-template kendoGridCellTemplate let-rowIndex=\"rowIndex\">\r\n <kendo-checkbox [kendoGridSelectionCheckbox]=\"rowIndex\"></kendo-checkbox>\r\n </ng-template>\r\n </kendo-grid-column>\r\n }\r\n\r\n @if (mode() === 'users') {\r\n <!-- Optional user photo -->\r\n @if (settings().displayPhotos ?? false) {\r\n <kendo-grid-column [width]=\"settings().photoColumnWidth ?? 40\">\r\n <ng-template kendoGridCellTemplate let-dataItem>\r\n @if (photo(dataItem)) {\r\n <img [src]=\"photo(dataItem)!.encodedAbsUrl\" [ngClass]=\"photoClass()\" />\r\n }\r\n </ng-template>\r\n </kendo-grid-column>\r\n }\r\n \r\n <!-- Columns -->\r\n @for (column of settings().userColumns!; track column.field) {\r\n <kendo-grid-column [field]=\"column.field\" [title]=\"column.title\"\r\n [width]=\"column.width ?? 0\"\r\n [hidden]=\"column.hidden ?? false\"\r\n [filterable]=\"column.columnFilterable ?? true\"\r\n [sortable]=\"column.sortable ?? true\"\r\n [groupable]=\"column.groupable ?? true\" />\r\n }\r\n } @else if (mode() === 'groups') {\r\n <!-- Columns -->\r\n @for (column of settings().groupColumns!; track column.field) {\r\n <kendo-grid-column [field]=\"column.field\" [title]=\"column.title\"\r\n [width]=\"column.width ?? 0\"\r\n [hidden]=\"column.hidden ?? false\"\r\n [filterable]=\"column.columnFilterable ?? true\"\r\n [sortable]=\"column.sortable ?? true\"\r\n [groupable]=\"column.groupable ?? true\" />\r\n }\r\n }\r\n</kendo-grid>","import { Component, input, output, signal, computed, model, viewChild, inject } from '@angular/core';\r\nimport { toObservable, toSignal } from '@angular/core/rxjs-interop';\r\nimport { of, switchMap } from 'rxjs';\r\n\r\nimport { ActiveDirectoryService, CleavelandPriceUser, Group } from '@cleavelandprice/ngx-lib/active-directory';\r\nimport { PhotoItem, SharePointService } from '@cleavelandprice/ngx-lib/sharepoint';\r\n\r\nimport { KENDO_BUTTONS } from '@progress/kendo-angular-buttons';\r\nimport { KENDO_DIALOGS } from \"@progress/kendo-angular-dialog\";\r\nimport { KENDO_INPUTS } from '@progress/kendo-angular-inputs';\r\nimport { KENDO_LABELS } from '@progress/kendo-angular-label';\r\nimport { KENDO_TABSTRIP, SelectEvent } from '@progress/kendo-angular-layout';\r\nimport { KENDO_ICONS } from '@progress/kendo-angular-icons';\r\nimport { filterClearIcon } from '@progress/kendo-svg-icons';\r\n\r\nimport { IUserChooserSettings } from '../../model/user-chooser-settings-interface';\r\nimport { USER_CHOOSER_DEFAULT_SETTINGS } from '../../model/user-chooser-default-settings';\r\nimport { UserChooserList } from '../user-chooser-list/user-chooser-list';\r\n\r\n@Component({\r\n selector: 'user-chooser-dialog',\r\n imports: [\r\n KENDO_DIALOGS,\r\n KENDO_BUTTONS,\r\n KENDO_INPUTS,\r\n KENDO_LABELS,\r\n KENDO_TABSTRIP,\r\n KENDO_ICONS,\r\n UserChooserList\r\n ],\r\n templateUrl: './user-chooser-dialog.html',\r\n styleUrl: './user-chooser-dialog.scss',\r\n})\r\nexport class UserChooserDialogComponent {\r\n #services = {\r\n ad: inject(ActiveDirectoryService),\r\n sp: inject(SharePointService)\r\n };\r\n \r\n userChooserList = viewChild<UserChooserList>('userChooserList');\r\n groupChooserList = viewChild<UserChooserList>('groupChooserList');\r\n\r\n settings = input<IUserChooserSettings>({\r\n ...USER_CHOOSER_DEFAULT_SETTINGS\r\n });\r\n\r\n //#region Either passed in or pulled from the service\r\n users = input<CleavelandPriceUser[] | undefined>();\r\n #usersFromService$ = toObservable(this.users)\r\n .pipe(switchMap(users => {\r\n if (users) {\r\n return of(users);\r\n }\r\n\r\n return (this.settings().emptyDataPullMode === 'All' || this.settings().emptyDataPullMode === 'Users')\r\n ? this.#services.ad.getUsers('NgxLibUserChooser')\r\n : of([]);\r\n }));\r\n resolvedUsers = toSignal(this.#usersFromService$, { initialValue: [] });\r\n\r\n groups = input<Group[] | undefined>();\r\n #groupsFromService$ = toObservable(this.groups)\r\n .pipe(switchMap(groups => {\r\n if (groups) {\r\n return of(groups);\r\n }\r\n\r\n return (this.settings().emptyDataPullMode === 'All' || this.settings().emptyDataPullMode === 'Groups')\r\n ? this.#services.ad.getGroups('NgxLibUserChooser')\r\n : of([]);\r\n }));\r\n resolvedGroups = toSignal(this.#groupsFromService$, { initialValue: [] });\r\n\r\n photos = input<PhotoItem[] | undefined>();\r\n #photosFromService$ = toObservable(this.photos)\r\n .pipe(switchMap(photos => {\r\n if (photos) {\r\n return of(photos);\r\n }\r\n\r\n return (this.settings().emptyDataPullMode === 'All' || this.settings().emptyDataPullMode === 'Users')\r\n ? this.#services.sp.getPhotos()\r\n : of([]);\r\n }));\r\n resolvedPhotos = toSignal(this.#photosFromService$, { initialValue: [] });\r\n //#endregion Either passed in or pulled from the service\r\n\r\n photoClass = input<string>('user-chooser-photo');\r\n\r\n selectedUsers = model<string[]>([]);\r\n selectedGroups = model<string[]>([]);\r\n\r\n hideUnselected = signal(false);\r\n \r\n returnValue = computed<UserChooserReturnValue>(() => {\r\n const users = \r\n this.settings().returnType === 'Object' ?\r\n // User objects\r\n this.resolvedUsers().filter(u => this.selectedUsers().some(s => s.toLowerCase() === u.sAMAccountName.toLowerCase())) :\r\n // Account names - reject any invalid account names that may have been passed in\r\n this.resolvedUsers().filter(u => this.selectedUsers().some(s => s.toLowerCase() === u.sAMAccountName.toLowerCase())).map(u => u.sAMAccountName.toLowerCase());\r\n\r\n const groups = \r\n this.settings().returnType === 'Object' ?\r\n // Group objects\r\n this.resolvedGroups().filter(u => this.selectedGroups().some(s => s.toLowerCase() === u.sAMAccountName.toLowerCase())) :\r\n // Account names - reject any invalid account names that may have been passed in\r\n this.resolvedGroups().filter(u => this.selectedGroups().some(s => s.toLowerCase() === u.sAMAccountName.toLowerCase())).map(u => u.sAMAccountName.toLowerCase());\r\n\r\n const validUsers = [\r\n ...(\r\n this.settings().returnType === 'Object' ?\r\n (users as CleavelandPriceUser[]).map(u => u.sAMAccountName.toLowerCase()) :\r\n (users as string[])\r\n )\r\n ];\r\n const invalidUsers = this.selectedUsers().filter(s => !validUsers.some(u => u.toLowerCase() === s.toLowerCase()));\r\n\r\n const validGroups = [\r\n ...(\r\n this.settings().returnType === 'Object' ?\r\n (groups as Group[]).map(u => u.sAMAccountName.toLowerCase()) :\r\n (groups as string[])\r\n )\r\n ];\r\n const invalidGroups = this.selectedGroups().filter(s => !validGroups.some(u => u.toLowerCase() === s.toLowerCase()));\r\n\r\n return { users, groups, invalidUsers, invalidGroups };\r\n });\r\n\r\n multiSelectInstructions = computed(() => {\r\n if (!this.settings().displayMultiSelectInstructions) {\r\n return '';\r\n }\r\n\r\n const instructions: string[] = [];\r\n\r\n if (this.settings().selectionSettings?.mode === 'multiple' && this.settings().selectionSettings?.metaKeyMultiSelect) {\r\n instructions.push('<span class=\"bold\">[CTRL/SHIFT + Click]</span>');\r\n }\r\n\r\n if (this.settings().selectionSettings?.drag) {\r\n instructions.push('<span class=\"bold\">[Click and drag]</span>');\r\n }\r\n\r\n if (instructions.length === 0) {\r\n return '';\r\n }\r\n\r\n return `${instructions.join(' or ')} to select multiple`;\r\n });\r\n \r\n close = output<any>();\r\n filter = signal<string>('');\r\n\r\n filterClearIcon = filterClearIcon;\r\n\r\n dialogWidth = computed(() =>\r\n this.settings().userColumns!\r\n .filter(c => !c.hidden)\r\n .reduce((total, column) => total + (column.width ?? 0), 0)\r\n + (this.settings().additionalWidth ?? 0)\r\n );\r\n\r\n selectedTabIndex = signal(0);\r\n mode = computed(() => this.resolvedUsers().length > 0 && this.resolvedGroups().length > 0 ? 'tabs' : 'standalone');\r\n\r\n title = computed(() => {\r\n return (\r\n (this.mode() === 'tabs' && this.selectedTabIndex() === 0) ||\r\n (this.mode() === 'standalone' && this.resolvedUsers().length > 0)\r\n ) ?\r\n this.settings().usersTitle ?? 'Select User(s)' :\r\n this.settings().groupsTitle ?? 'Select Group(s)';\r\n });\r\n\r\n unselectAll() {\r\n const list = this.selectedTabIndex() === 0 ?\r\n this.userChooserList :\r\n this.groupChooserList;\r\n\r\n list()?.unselectAll();\r\n }\r\n\r\n onTabSelect(e: SelectEvent) {\r\n this.selectedTabIndex.set(e.index);\r\n }\r\n}\r\n\r\nexport type UserChooserReturnValue = {\r\n users: CleavelandPriceUser[] | string[];\r\n groups: Group[] | string[];\r\n invalidUsers: string[];\r\n invalidGroups: string[];\r\n};","<kendo-dialog [width]=\"dialogWidth()\" (close)=\"close.emit('cancel')\">\r\n <!-- Title -->\r\n <kendo-dialog-titlebar>\r\n <div id=\"title\" class=\"bold\">\r\n {{ title() }}\r\n </div>\r\n @if (multiSelectInstructions()) {\r\n <div id=\"multi-select-instructions\" [innerHTML]=\"multiSelectInstructions()\">\r\n </div>\r\n }\r\n </kendo-dialog-titlebar>\r\n\r\n <!-- Global filter -->\r\n @if (settings().filterMode === 'Global' || settings().filterMode === 'Both') {\r\n <kendo-textbox id=\"filter\" [(value)]=\"filter\" placeholder=\"Type here to filter employee list...\">\r\n @if (filter()) {\r\n <ng-template kendoTextBoxSuffixTemplate>\r\n <kendo-svgicon [icon]=\"filterClearIcon\" class=\"clear-filter\" (click)=\"filter.set('')\" />\r\n </ng-template>\r\n }\r\n </kendo-textbox>\r\n }\r\n\r\n @if (resolvedUsers().length > 0 && resolvedGroups().length > 0) {\r\n <!-- Groups AND Users, so we need tabs -->\r\n <kendo-tabstrip [keepTabContent]=\"true\" (tabSelect)=\"onTabSelect($event)\">\r\n <!-- Users tab -->\r\n <kendo-tabstrip-tab title=\"Users\" [selected]=\"true\" #usersTab>\r\n <ng-template kendoTabContent>\r\n <user-chooser-list #userChooserList [data]=\"resolvedUsers()\" [photos]=\"resolvedPhotos()\" [settings]=\"settings()\"\r\n [photoClass]=\"photoClass()\"\r\n [(selectedAccountNames)]=\"selectedUsers\"\r\n [hideUnselected]=\"hideUnselected()\"\r\n [filter]=\"filter()\" />\r\n </ng-template>\r\n </kendo-tabstrip-tab>\r\n\r\n <!-- Groups tab -->\r\n <kendo-tabstrip-tab title=\"Groups\" #groupsTab>\r\n <ng-template kendoTabContent>\r\n <user-chooser-list #groupChooserList [data]=\"resolvedGroups()\" [settings]=\"settings()\"\r\n [photoClass]=\"photoClass()\"\r\n [(selectedAccountNames)]=\"selectedGroups\"\r\n [hideUnselected]=\"hideUnselected()\"\r\n [filter]=\"filter()\" />\r\n </ng-template>\r\n </kendo-tabstrip-tab>\r\n </kendo-tabstrip>\r\n }\r\n @else if (resolvedUsers().length > 0) {\r\n <!-- Users only -->\r\n <user-chooser-list #userChooserList [data]=\"resolvedUsers()\" [photos]=\"resolvedPhotos()\" [settings]=\"settings()\"\r\n [photoClass]=\"photoClass()\"\r\n [(selectedAccountNames)]=\"selectedUsers\"\r\n [hideUnselected]=\"hideUnselected()\"\r\n [filter]=\"filter()\"\r\n /> <!-- (selectedCountChange)=\"selectedUsersCount.set($event)\" -->\r\n }\r\n @else if (resolvedGroups().length > 0) {\r\n <!-- Groups only -->\r\n <user-chooser-list #groupChooserList [data]=\"resolvedGroups()\" [settings]=\"settings()\"\r\n [photoClass]=\"photoClass()\"\r\n [(selectedAccountNames)]=\"selectedGroups\"\r\n [hideUnselected]=\"hideUnselected()\"\r\n [filter]=\"filter()\"\r\n /> <!-- (selectedCountChange)=\"selectedGroupsCount.set($event)\" -->\r\n }\r\n\r\n <kendo-dialog-actions>\r\n <!-- Hide unselected toggle -->\r\n <div id=\"hide-toggle\">\r\n @if (\r\n settings().displayHideUnselectedToggle &&\r\n (selectedUsers().length > 0 || selectedGroups().length > 0))\r\n {\r\n <kendo-label [for]=\"hideunselected\">Hide Unselected </kendo-label>\r\n <kendo-switch #hideunselected (valueChange)=\"hideUnselected.set($event)\" onLabel=\"'Yes'\" offLabel=\"'No'\" />\r\n }\r\n </div>\r\n\r\n <!-- Selected user count -->\r\n <div id=\"selected-count\">\r\n @if (settings().displaySelectedCount) {\r\n @if (resolvedUsers().length > 0 && resolvedGroups().length > 0) {\r\n {{ userChooserList()?.selectedCount() }} user(s), {{ groupChooserList()?.selectedCount() }} group(s) selected\r\n\r\n }\r\n @else if (resolvedUsers().length > 0) {\r\n {{ userChooserList()?.selectedCount() }} user(s) selected\r\n }\r\n @else if (resolvedGroups().length > 0) {\r\n {{ groupChooserList()?.selectedCount() }} group(s) selected\r\n }\r\n }\r\n </div>\r\n\r\n <div id=\"buttons\">\r\n <!-- Unselect All button -->\r\n @if (\r\n (selectedTabIndex() === 0 && selectedUsers().length > 0) ||\r\n (selectedTabIndex() === 1 && selectedGroups().length > 0))\r\n {\r\n <button kendoButton (click)=\"unselectAll()\">\r\n {{ settings().unselectButtonText ?? 'Unselect All' }}\r\n </button>\r\n }\r\n \r\n <!-- Cancel button -->\r\n <button kendoButton\r\n (click)=\"close.emit(settings().cancelReturnValue)\">\r\n\r\n {{ settings().cancelButtonText ?? 'Cancel' }}\r\n </button>\r\n\r\n <!-- Ok button -->\r\n <button kendoButton themeColor=\"primary\"\r\n [disabled]=\"selectedUsers().length === 0 && selectedGroups().length === 0\"\r\n (click)=\"close.emit(returnValue())\">\r\n\r\n {{ settings().okButtonText ?? 'Ok' }}\r\n </button>\r\n </div>\r\n </kendo-dialog-actions>\r\n</kendo-dialog>","import { Component, inject, input, computed, signal, Signal, model, output } from '@angular/core';\r\nimport { NgClass } from '@angular/common';\r\nimport { toObservable, toSignal } from '@angular/core/rxjs-interop';\r\nimport { of, switchMap } from 'rxjs';\r\n\r\nimport { ActiveDirectoryService, CleavelandPriceUser, Group } from '@cleavelandprice/ngx-lib/active-directory';\r\nimport { SharePointService, PhotoItem } from '@cleavelandprice/ngx-lib/sharepoint';\r\n\r\nimport { userIcon, usersIcon, questionCircleIcon } from '@progress/kendo-svg-icons';\r\nimport { KENDO_ICONS } from '@progress/kendo-angular-icons';\r\n\r\nimport { UserFieldDisplayType } from '../../model/user-field-display-type';\r\nimport { IUserChooserSettings } from '../../model/user-chooser-settings-interface';\r\nimport { USER_CHOOSER_DEFAULT_SETTINGS } from '../../model/user-chooser-default-settings';\r\nimport { UserChooserDialogComponent, UserChooserReturnValue } from '../user-chooser-dialog/user-chooser-dialog';\r\n\r\n@Component({\r\n selector: 'user-field',\r\n imports: [\r\n NgClass,\r\n KENDO_ICONS,\r\n UserChooserDialogComponent\r\n ],\r\n templateUrl: './user-field.html',\r\n styleUrl: './user-field.scss',\r\n})\r\nexport class UserFieldComponent {\r\n #services = {\r\n ad: inject(ActiveDirectoryService),\r\n sp: inject(SharePointService)\r\n };\r\n\r\n icons = {\r\n user: userIcon,\r\n group: usersIcon,\r\n unknown: questionCircleIcon\r\n };\r\n\r\n rejectedInvalidAccountNames = output<{users: string[], groups: string[]}>();\r\n showUserChooser = signal(false); // Controls the visibility of the user chooser dialog\r\n \r\n //#region Inputs\r\n userAccountNames = model<string[]>([]);\r\n groupAccountNames = model<string[]>([]);\r\n\r\n //#region Either passed in or pulled from the service\r\n users = input<CleavelandPriceUser[] | undefined>();\r\n #usersFromService$ = toObservable(this.users)\r\n .pipe(switchMap(users => {\r\n if (users) {\r\n return of(users);\r\n }\r\n\r\n return (this.userChooserSettings().emptyDataPullMode === 'All' || this.userChooserSettings().emptyDataPullMode === 'Users')\r\n ? this.#services.ad.getUsers('NgxLibUserChooser')\r\n : of([]);\r\n }));\r\n resolvedUsers = toSignal(this.#usersFromService$, { initialValue: [] });\r\n\r\n groups = input<Group[] | undefined>();\r\n #groupsFromService$ = toObservable(this.groups)\r\n .pipe(switchMap(groups => {\r\n if (groups) {\r\n return of(groups);\r\n }\r\n\r\n return (this.userChooserSettings().emptyDataPullMode === 'All' || this.userChooserSettings().emptyDataPullMode === 'Groups')\r\n ? this.#services.ad.getGroups('NgxLibUserChooser')\r\n : of([]);\r\n }));\r\n resolvedGroups = toSignal(this.#groupsFromService$, { initialValue: [] });\r\n\r\n photos = input<PhotoItem[] | undefined>();\r\n #photosFromService$ = toObservable(this.photos)\r\n .pipe(switchMap(photos => {\r\n if (photos) {\r\n return of(photos);\r\n }\r\n\r\n return (this.displayPhoto())\r\n ? this.#services.sp.getPhotos()\r\n : of([]);\r\n }));\r\n resolvedPhotos = toSignal(this.#photosFromService$, { initialValue: [] });\r\n //#endregion Either passed in or pulled from the service\r\n \r\n maxItemsToDisplay = input<number>(5);\r\n groupItemsOverMax = input(false);\r\n groupItemsOverMaxText = input<string>('users/groups');\r\n \r\n ignoreInvalidAccountNames = input<boolean>(false);\r\n \r\n displayType = input<UserFieldDisplayType>('PhotoAndDisplayName');\r\n emptyUserNameText = input<string>('Select user...');\r\n \r\n enableUserChooser = input(true);\r\n //userChooserUsers = input<CleavelandPriceUser[]>([]);\r\n //userChooserGroups = input<Group[]>([]);\r\n userChooserSettings = input<IUserChooserSettings>({\r\n ...USER_CHOOSER_DEFAULT_SETTINGS\r\n });\r\n \r\n //#region CSS Classes\r\n wrapperClass = input<string>('wrapper');\r\n emptyUserNameClass = input<string>('empty-user');\r\n validUserTextClass = input<string>('valid-user');\r\n manySelectedClass = input<string>('many-selected');\r\n invalidUserTextClass = input<string>('invalid-user');\r\n photoClass = input<string>('user-photo');\r\n userChooserPhotoClass = input<string>('user-chooser-photo');\r\n userChooserEnabledClass = input<string>('user-chooser-enabled');\r\n userChooserDisabledClass = input<string>('user-chooser-disabled');\r\n //#endregion CSS Classes\r\n\r\n //#endregion Inputs\r\n\r\n //#region Computed Properties\r\n totalItemCount = computed(() => this.userObjects().length + this.groupObjects().length);\r\n\r\n userObjects: Signal<UserObject[]> = computed(() => {\r\n const data: UserObject[] = this.userAccountNames()\r\n .map(accountName => ({\r\n accountName,\r\n label: accountName,\r\n user: this.resolvedUsers().find(u => u.sAMAccountName.toLowerCase() === accountName.toLowerCase())\r\n }));\r\n\r\n data.forEach(dataItem => {\r\n if (dataItem.user) {\r\n // Photo\r\n dataItem.photo = this.resolvedPhotos().find(photo =>\r\n // Try to match the photo to the user by employee number, account name, or display name\r\n (photo.employeeNumber ?? 0) === +(dataItem.user!.employeeNumber ?? -1) ||\r\n (photo.accountName ?? 'photoaccountname').toLowerCase() === dataItem.user!.sAMAccountName!.toLowerCase() ||\r\n (photo.displayName ?? 'photodisplayname').toLowerCase() === dataItem.user!.displayName?.toLowerCase()\r\n );\r\n\r\n // Label\r\n switch (this.displayType()) {\r\n case 'PhotoAndDisplayName':\r\n case 'DisplayName':\r\n dataItem.label = dataItem.user!.displayName || dataItem.accountName;\r\n break;\r\n case 'Username':\r\n case 'PhotoAndUsername':\r\n dataItem.label = dataItem.accountName;\r\n break;\r\n case 'DisplayNameAndUsername':\r\n case 'PhotoDisplayNameAndUsername':\r\n dataItem.label = `${dataItem.user!.displayName} (${dataItem.accountName})`;\r\n break;\r\n };\r\n }\r\n });\r\n\r\n return data.filter(dataItem => this.ignoreInvalidAccountNames() ? !!dataItem.user : true);\r\n });\r\n\r\n groupObjects: Signal<GroupObject[]> = computed(() => {\r\n const data: GroupObject[] = this.groupAccountNames()\r\n .map(accountName => ({\r\n accountName,\r\n label: accountName,\r\n group: this.resolvedGroups().find(g => g.sAMAccountName.toLowerCase() === accountName.toLowerCase())\r\n }));\r\n\r\n data.forEach(dataItem => {\r\n if (dataItem.group) {\r\n // Label\r\n dataItem.label = dataItem.group.displayName ?? dataItem.group.name ?? dataItem.accountName;\r\n }\r\n });\r\n\r\n return data.filter(dataItem => this.ignoreInvalidAccountNames() ? !!dataItem.group : true);\r\n });\r\n\r\n displayPhoto = computed(() => ['Photo', 'PhotoAndDisplayName', 'PhotoAndUsername', 'PhotoDisplayNameAndUsername']\r\n .includes(this.displayType()));\r\n displayName = computed(() => this.displayType() !== 'Photo');\r\n //#endregion Computed Properties\r\n\r\n userChooserClosed(event: UserChooserReturnValue | any) {\r\n if (event === this.userChooserSettings().cancelReturnValue) {\r\n // console.log('User chooser canceled'); // debug\r\n } else {\r\n this.userAccountNames.set(this.userChooserSettings().returnType === 'Object' ?\r\n (event.users as CleavelandPriceUser[]).map(u => u.sAMAccountName) :\r\n event.users as string[]);\r\n this.groupAccountNames.set(this.userChooserSettings().returnType === 'Object' ?\r\n (event.groups as Group[]).map(g => g.sAMAccountName) :\r\n event.groups as string[]);\r\n\r\n if (event.invalidUsers.length > 0 || event.invalidGroups.length > 0) {\r\n this.rejectedInvalidAccountNames.emit({\r\n users: event.invalidUsers,\r\n groups: event.invalidGroups\r\n });\r\n }\r\n }\r\n\r\n this.showUserChooser.set(false);\r\n }\r\n}\r\n\r\ntype UserObject = {\r\n accountName: string;\r\n user?: CleavelandPriceUser;\r\n photo?: PhotoItem;\r\n label?: string;\r\n}\r\n\r\ntype GroupObject = {\r\n accountName: string;\r\n group?: Group;\r\n label?: string;\r\n}"," <div (click)=\"enableUserChooser() && showUserChooser.set(true)\"\r\n [ngClass]=\"[wrapperClass(), enableUserChooser() ? userChooserEnabledClass() : userChooserDisabledClass()]\">\r\n\r\n @if (userObjects().length === 0 && groupObjects().length === 0) {\r\n <!-- No data provided, just present an empty user/group chooser -->\r\n <div [ngClass]=\"emptyUserNameClass()\">\r\n <kendo-svg-icon [icon]=\"icons.user\" size=\"small\" [ngClass]=\"photoClass()\"/>\r\n {{ emptyUserNameText() }}\r\n </div>\r\n }\r\n @else if (totalItemCount() > maxItemsToDisplay()) {\r\n <!-- Too many items to display, just show a count -->\r\n <div [ngClass]=\"manySelectedClass()\">\r\n @if (groupObjects().length === 0) {\r\n <!-- We only have Users -->\r\n <kendo-svg-icon [icon]=\"icons.user\" size=\"small\" [ngClass]=\"photoClass()\"/>\r\n {{ totalItemCount() }} users\r\n } @else if (groupObjects().length === 0) {\r\n <!-- We only have Groups -->\r\n <kendo-svg-icon [icon]=\"icons.group\" size=\"small\" [ngClass]=\"photoClass()\"/>\r\n {{ totalItemCount() }} groups\r\n } @else {\r\n <!-- We have both Users and Groups -->\r\n @if (groupItemsOverMax()) {\r\n <!-- Lump users/groups together -->\r\n <kendo-svg-icon [icon]=\"icons.user\" size=\"small\" [ngClass]=\"photoClass()\"/>\r\n {{ totalItemCount() }} {{ groupItemsOverMaxText() }}\r\n } @else {\r\n <!-- List how many users/groups separately -->\r\n <kendo-svg-icon [icon]=\"icons.user\" size=\"small\" [ngClass]=\"photoClass()\"/>\r\n {{ userObjects().length }} users\r\n <kendo-svg-icon [icon]=\"icons.group\" size=\"small\" [ngClass]=\"photoClass()\"/>\r\n {{ groupObjects().length }} groups\r\n }\r\n }\r\n </div>\r\n\r\n }\r\n @else {\r\n <!-- Display the users/groups that were passed in -->\r\n\r\n <!-- Users -->\r\n @for (userObject of userObjects(); track userObject.accountName) {\r\n <div class=\"user-identity\" [class.with-photo]=\"displayPhoto()\">\r\n \r\n @if (displayPhoto()) {\r\n @if (userObject.photo) {\r\n <img [src]=\"userObject.photo!.encodedAbsUrl\" [ngClass]=\"photoClass()\" />\r\n } @else {\r\n @if (userObject.user) {\r\n <kendo-svg-icon [icon]=\"icons.user\" size=\"small\" [ngClass]=\"photoClass()\"/>\r\n } @else {\r\n <kendo-svg-icon [icon]=\"icons.unknown\" size=\"small\" [ngClass]=\"photoClass()\"/>\r\n }\r\n }\r\n }\r\n \r\n @if (displayName()) {\r\n <div id=\"name\"\r\n [ngClass]=\"userObject.user ? validUserTextClass() : invalidUserTextClass()\"\r\n [innerText]=\"userObject.label\">\r\n </div>\r\n }\r\n </div>\r\n }\r\n \r\n <!-- Groups -->\r\n @for (groupObject of groupObjects(); track groupObject.accountName) {\r\n <div class=\"user-identity\" [class.with-photo]=\"displayPhoto()\">\r\n \r\n @if (displayPhoto()) {\r\n @if (groupObject.group) {\r\n <kendo-svg-icon [icon]=\"icons.group\" size=\"small\" [ngClass]=\"photoClass()\"/>\r\n } @else {\r\n <kendo-svg-icon [icon]=\"icons.unknown \" size=\"small\" [ngClass]=\"photoClass()\"/>\r\n }\r\n }\r\n \r\n @if (displayName()) {\r\n <div id=\"name\"\r\n [ngClass]=\"groupObject.group ? validUserTextClass() : invalidUserTextClass()\"\r\n [innerText]=\"groupObject.label\">\r\n </div>\r\n }\r\n </div>\r\n }\r\n }\r\n\r\n</div>\r\n\r\n<!-- Display User Chooser when the user clicks the component -->\r\n@if (showUserChooser()) {\r\n <!--\r\n TODO\r\n If we want to ensure that only valid users/groups are passed in...\r\n [selectedUsers]=\"data().filter(i => i.userOrGroup).map(i => i.accountName!)\"\r\n -->\r\n\r\n <user-chooser-dialog [users]=\"resolvedUsers()\" [groups]=\"resolvedGroups()\" [photos]=\"resolvedPhotos()\"\r\n [settings]=\"userChooserSettings()\"\r\n [photoClass]=\"userChooserPhotoClass()\"\r\n [selectedUsers]=\"userAccountNames()\" [selectedGroups]=\"groupAccountNames()\"\r\n (close)=\"userChooserClosed($event)\" />\r\n}","import { CommonModule } from '@angular/common';\r\nimport { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core';\r\nimport { ReactiveFormsModule } from '@angular/forms';\r\n\r\nimport { ActiveDirectoryServiceOptions, ActiveDirectoryServiceOptionsToken } from '@cleavelandprice/ngx-lib/active-directory';\r\n\r\nimport { IconsModule, SVGIconModule } from '@progress/kendo-angular-icons';\r\nimport { GridModule } from \"@progress/kendo-angular-grid\";\r\nimport { ButtonsModule } from '@progress/kendo-angular-buttons';\r\nimport { DialogsModule } from \"@progress/kendo-angular-dialog\";\r\nimport { InputsModule } from '@progress/kendo-angular-inputs';\r\nimport { LabelModule } from '@progress/kendo-angular-label';\r\nimport { TabStripModule } from '@progress/kendo-angular-layout';\r\n\r\n\r\nimport { UserChooserDialogComponent } from './components/user-chooser-dialog/user-chooser-dialog';\r\nimport { UserChooserList } from './components/user-chooser-list/user-chooser-list';\r\nimport { UserFieldComponent } from './components/user-field/user-field';\r\n\r\n@NgModule({\r\n declarations: [],\r\n imports: [\r\n CommonModule,\r\n ReactiveFormsModule,\r\n\r\n IconsModule, SVGIconModule,\r\n GridModule,\r\n ButtonsModule,\r\n DialogsModule,\r\n InputsModule,\r\n LabelModule,\r\n TabStripModule,\r\n\r\n UserChooserDialogComponent,\r\n UserChooserList,\r\n UserFieldComponent\r\n ],\r\n exports: [\r\n UserChooserDialogComponent,\r\n UserChooserList,\r\n UserFieldComponent\r\n ]\r\n})\r\nexport class KendoActiveDirectoryModule {\r\n static forRoot(config: ActiveDirectoryServiceOptions): ModuleWithProviders<KendoActiveDirectoryModule> {\r\n return {\r\n ngModule: KendoActiveDirectoryModule,\r\n providers: [\r\n {\r\n provide: ActiveDirectoryServiceOptionsToken,\r\n useValue: config\r\n }\r\n ]\r\n };\r\n }\r\n\r\n constructor(@Optional() @SkipSelf() parentModule: KendoActiveDirectoryModule) {\r\n if (parentModule) {\r\n throw new Error(\r\n 'KendoActiveDirectoryModule is already loaded. Import it in the AppModule only');\r\n }\r\n }\r\n}","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './kendo-active-directory.api';\n"],"names":["i1"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAIO,MAAM,6BAA6B,GAAG;AACzC,IAAA,UAAU,EAAE,gBAAgB;AAC5B,IAAA,WAAW,EAAE,iBAAiB;AAC9B,IAAA,8BAA8B,EAAE,IAAI;AACpC,IAAA,2BAA2B,EAAE,IAAI;AACjC,IAAA,oBAAoB,EAAE,IAAI;AAC1B,IAAA,UAAU,EAAE,QAAiD;AAC7D,IAAA,SAAS,EAAE,IAAI;AACf,IAAA,QAAQ,EAAE,IAAI;AACd,IAAA,QAAQ,EAAE,KAAK;AACf,IAAA,QAAQ,EAAE,GAAG;AACb,IAAA,MAAM,EAAE,GAAG;AACX,IAAA,eAAe,EAAE,GAAG;AACpB,IAAA,aAAa,EAAE,IAAI;AACnB,IAAA,gBAAgB,EAAE,EAAE;AACpB,IAAA,UAAU,EAAE,aAAyC;AACrD,IAAA,iBAAiB,EAAE,QAAQ;AAC3B,IAAA,YAAY,EAAE,IAAI;AAClB,IAAA,gBAAgB,EAAE,QAAQ;AAC1B,IAAA,kBAAkB,EAAE,cAAc;AAClC,IAAA,iBAAiB,EAAE,OAAqC;AACxD,IAAA,iBAAiB,EAAE;AACf,QAAA,YAAY,EAAE,KAAK;AACnB,QAAA,IAAI,EAAE,UAAmC;AACzC,QAAA,OAAO,EAAE,IAAI;AACb,QAAA,IAAI,EAAE,IAAI;AACV,QAAA,IAAI,EAAE,KAAK;AACX,QAAA,kBAAkB,EAAE;AACD,KAAA;AACvB,IAAA,WAAW,EAAE;AACT,QAAA,EAAE,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,gBAAgB,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;QACtJ,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,GAAG,EAAE,gBAAgB,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE;QAC7I,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,EAAE,gBAAgB,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE;QACzI,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,gBAAgB,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE;QAC/H,EAAE,KAAK,EAAE,iBAAiB,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,gBAAgB,EAAE,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE;AAC3I,QAAA,EAAE,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,EAAE,gBAAgB,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI;AACnI,KAAA;AACzB,IAAA,YAAY,EAAE;QACV,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,gBAAgB,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE;AAC9H,QAAA,EAAE,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,EAAE,gBAAgB,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK;AAC5J;;;MCnBQ,eAAe,CAAA;AAC1B,IAAA,GAAG;AAUH,IAAA,gBAAgB;AAChB,IAAA,aAAa;AAMb,IAAA,mBAAmB;AAUnB,IAAA,eAAe;AAgBf,IAAA,IAAI;AAIJ,IAAA,WAAA,GAAA;AA/CA,QAAA,IAAA,CAAA,GAAG,GAAG,MAAM,CAAC,iBAAiB,CAAC;QAC/B,IAAA,CAAA,IAAI,GAAG,SAAS,CAAgB,aAAa;iFAAC;QAC9C,IAAA,CAAA,QAAQ,GAAG,KAAK,CAAuB;AACrC,YAAA,GAAG;AACJ,SAAA;qFAAC;QAEF,IAAA,CAAA,IAAI,GAAG,KAAK,CAAkC,EAAE;iFAAC;QACjD,IAAA,CAAA,UAAU,GAAG,KAAK,CAAS,oBAAoB;uFAAC;QAChD,IAAA,CAAA,oBAAoB,GAAG,KAAK,CAAW,EAAE;iGAAC;QAC1C,IAAA,CAAA,MAAM,GAAG,KAAK,CAAS,EAAE;mFAAC;AAC1B,QAAA,IAAA,CAAA,gBAAgB,GAAG,SAAS,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,EAAE,GAAG,CAAC;QACtD,IAAA,CAAA,aAAa,GAAG,MAAM,CAAkC,EAAE;0FAAC;QAC3D,IAAA,CAAA,cAAc,GAAG,KAAK,CAAC,KAAK;2FAAC;QAC7B,IAAA,CAAA,IAAI,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,WAAW,CAAC,GAAG,OAAO,GAAG,QAAQ;iFAAC;;AAG1F,QAAA,IAAA,CAAA,MAAM,GAAG,KAAK;8FAA2B;AACzC,QAAA,IAAA,CAAA,mBAAmB,GAAG,YAAY,CAAC,IAAI,CAAC,MAAM;AAC3C,aAAA,IAAI,CAAC,SAAS,CAAC,MAAM,IAAG;YACvB,IAAI,MAAM,EAAE;AACV,gBAAA,OAAO,EAAE,CAAC,MAAM,CAAC;YACnB;AAEA,YAAA,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,WAAW,CAAC;AACpD,kBAAE,IAAI,CAAC,GAAG,CAAC,SAAS;AACpB,kBAAE,EAAE,CAAC,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;AACL,QAAA,IAAA,CAAA,eAAe,GAAG,QAAQ,CAAC,IAAI,CAAC,mBAAmB,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC;;QAG1E,IAAA,CAAA,aAAa,GAAG,MAAM,CAAS,CAAC;0FAAC;AAEjC,QAAA,IAAA,CAAA,QAAQ,GAAG,QAAQ,CAAC,MAClB,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE;AAC3B,YAAA,IAAI,CAAC,aAAa,EAAE;YACpB,IAAI,CAAC,IAAI;iBACN,MAAM,CAAC,IAAI,IACV,CAAC,IAAI,CAAC,cAAc,EAAE;gBACtB,IAAI,CAAC,oBAAoB;AACtB,qBAAA,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,cAAe,CAAC,WAAW,EAAE,CAAC,CAC3E;qFACN;AAED,QAAA,IAAA,CAAA,IAAI,GAAG,MAAM,CAAC,iBAAiB,CAAC;;AAiDhC,QAAA,IAAA,CAAA,uBAAuB,GAAG,CAAC,OAAgB,KAAY;;YAErD,OAAO,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,WAAW,EAAE;AAC9D,QAAA,CAAC;QA/CC,MAAM,CAAC,MAAK;AACV,YAAA,MAAM,gBAAgB,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;iBACtC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,gBAAgB,IAAI,IAAI;iBACtC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK;AACd,mBAAA,EAAE;YAEP,MAAM,OAAO,GAAG,gBAAgB,CAAC,GAAG,CAAC,KAAK,KAAK;AAC7C,gBAAA,KAAK,EAAE,KAAK;AACZ,gBAAA,QAAQ,EAAE,UAAU;AACpB,gBAAA,KAAK,EAAE,IAAI,CAAC,gBAAgB,CAAC,KAAK;AACnC,aAAA,CAAC,CAAC;AAEH,YAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CACpB,OAAO;;YAEL,IAAI,CAAC,IAAI,EAAE,EACX;gBACE,MAAM,EAAE,OAAO,CAAC,MAAM,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG;aAClE;iBACA;AACA,iBAAA,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,IAAI,CAAC,oBAAoB,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,cAAe,CAAC,WAAW,EAAE,CAAC,CAAC,CACzI;AACL,QAAA,CAAC,CAAC;QAEF,eAAe,CAAC,MAAK;AACnB,YAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,gBAAgB,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC,CAAC;AAE3E,YAAA,IAAI,CAAC,2BAA2B,GAAG,IAAI,CAAC,IAAI,EAAE,EAAE,gBAAgB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,KAAK,KAAI;AAC3F,gBAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,gBAAgB,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC,CAAC;AAC7E,YAAA,CAAC,CAAC;AACJ,QAAA,CAAC,CAAC;IACJ;IAEA,WAAW,GAAA;AACT,QAAA,IAAI,CAAC,2BAA2B,EAAE,WAAW,EAAE;IACjD;AAEA,IAAA,KAAK,CAAC,IAAyB,EAAA;QAC7B,OAAO,IAAI,CAAC,eAAe;AACxB,aAAA,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,WAAW,EAAE,KAAK,IAAI,CAAC,cAAe,CAAC,WAAW,EAAE;AAC3E,eAAA,IAAI;IACX;IAQA,WAAW,GAAA;AACT,QAAA,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,EAAE,CAAC;AACjC,QAAA,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE;AACzB,QAAA,IAAI,CAAC,IAAI,EAAE,EAAE,gBAAgB,CAAC,OAAO,CAAC,IAAI,CAAC,EAAC,YAAY,EAAE,EAAE,EAAE,cAAc,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAC,CAAC;IACrH;AAEA,IAAA,gBAAgB,CAAC,OAAqB,EAAA;AACpC,QAAA,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,QAAQ,EAAE;YAC5B,OAAO;AACL,gBAAA,UAAU,EAAE;aACb;QACH;;QAGA,OAAO;AACL,YAAA,UAAU,EAAE,CAAE,OAAO,CAAC,QAAgC,CAAC;SACxD;IACH;8GAnHW,eAAe,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAf,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,eAAe,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,UAAA,EAAA,MAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,oBAAA,EAAA,EAAA,iBAAA,EAAA,sBAAA,EAAA,UAAA,EAAA,sBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,EAAA,iBAAA,EAAA,gBAAA,EAAA,UAAA,EAAA,gBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,oBAAA,EAAA,4BAAA,EAAA,EAAA,WAAA,EAAA,CAAA,EAAA,YAAA,EAAA,MAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EAEM,aAAa,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EC3B/C,kkFAqDa,+IDnCT,OAAO,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,aAAA,EAAA,QAAA,EAAA,YAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,UAAA,EAAA,QAAA,EAAA,WAAA,EAAA,cAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,YAAA,EAAA,YAAA,EAAA,MAAA,EAAA,MAAA,EAAA,SAAA,EAAA,QAAA,EAAA,OAAA,EAAA,gBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,UAAA,EAAA,WAAA,EAAA,eAAA,EAAA,gBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,UAAA,EAAA,WAAA,EAAA,aAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,WAAA,EAAA,aAAA,EAAA,SAAA,EAAA,YAAA,EAAA,YAAA,EAAA,mBAAA,EAAA,kBAAA,EAAA,iBAAA,EAAA,gBAAA,EAAA,UAAA,EAAA,eAAA,EAAA,kBAAA,EAAA,eAAA,CAAA,EAAA,OAAA,EAAA,CAAA,cAAA,EAAA,YAAA,EAAA,aAAA,EAAA,YAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,cAAA,EAAA,iBAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,eAAA,EAAA,cAAA,EAAA,gBAAA,EAAA,MAAA,EAAA,QAAA,EAAA,MAAA,EAAA,QAAA,EAAA,KAAA,EAAA,WAAA,EAAA,WAAA,EAAA,WAAA,EAAA,aAAA,EAAA,WAAA,EAAA,cAAA,EAAA,eAAA,EAAA,wBAAA,EAAA,oBAAA,EAAA,oBAAA,EAAA,cAAA,EAAA,eAAA,CAAA,EAAA,QAAA,EAAA,CAAA,WAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,MAAA,EAAA,QAAA,EAAA,UAAA,EAAA,OAAA,EAAA,kBAAA,CAAA,EAAA,QAAA,EAAA,CAAA,kBAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,kBAAA,EAAA,QAAA,EAAA,qBAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,QAAA,EAAA,eAAA,EAAA,YAAA,EAAA,UAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,kBAAA,EAAA,QAAA,EAAA,+LAAA,EAAA,MAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,0BAAA,EAAA,QAAA,EAAA,8BAAA,EAAA,MAAA,EAAA,CAAA,4BAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,qBAAA,EAAA,QAAA,EAAA,yBAAA,EAAA,CAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA,CAAA;;2FAOE,eAAe,EAAA,UAAA,EAAA,CAAA;kBAV3B,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,mBAAmB,EAAA,OAAA,EACpB;wBACP,OAAO;wBACP;AACD,qBAAA,EAAA,aAAA,EAGc,iBAAiB,CAAC,IAAI;;gHAIL,aAAa,CAAA,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,QAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,UAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,IAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,MAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,UAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,YAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,oBAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,sBAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,CAAA,MAAA,EAAA,IAAA,EAAA,CAAA,4BAAA,CAAA,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,QAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,cAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,gBAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,QAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,EAAA,CAAA;;MEMlC,0BAA0B,CAAA;AAdvC,IAAA,WAAA,GAAA;AAeE,QAAA,IAAA,CAAA,SAAS,GAAG;AACV,YAAA,EAAE,EAAE,MAAM,CAAC,sBAAsB,CAAC;AAClC,YAAA,EAAE,EAAE,MAAM,CAAC,iBAAiB;SAC7B;QAED,IAAA,CAAA,eAAe,GAAG,SAAS,CAAkB,iBAAiB;4FAAC;QAC/D,IAAA,CAAA,gBAAgB,GAAG,SAAS,CAAkB,kBAAkB;6FAAC;QAEjE,IAAA,CAAA,QAAQ,GAAG,KAAK,CAAuB;AACrC,YAAA,GAAG;AACJ,SAAA;qFAAC;;AAGF,QAAA,IAAA,CAAA,KAAK,GAAG,KAAK;6FAAqC;AAClD,QAAA,IAAA,CAAA,kBAAkB,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK;AACzC,aAAA,IAAI,CAAC,SAAS,CAAC,KAAK,IAAG;YACtB,IAAI,KAAK,EAAE;AACT,gBAAA,OAAO,EAAE,CAAC,KAAK,CAAC;YAClB;AAEA,YAAA,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,iBAAiB,KAAK,KAAK,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC,iBAAiB,KAAK,OAAO;kBAChG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ,CAAC,mBAAmB;AAChD,kBAAE,EAAE,CAAC,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;AACL,QAAA,IAAA,CAAA,aAAa,GAAG,QAAQ,CAAC,IAAI,CAAC,kBAAkB,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC;AAEvE,QAAA,IAAA,CAAA,MAAM,GAAG,KAAK;8FAAuB;AACrC,QAAA,IAAA,CAAA,mBAAmB,GAAG,YAAY,CAAC,IAAI,CAAC,MAAM;AAC3C,aAAA,IAAI,CAAC,SAAS,CAAC,MAAM,IAAG;YACvB,IAAI,MAAM,EAAE;AACV,gBAAA,OAAO,EAAE,CAAC,MAAM,CAAC;YACnB;AAEA,YAAA,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,iBAAiB,KAAK,KAAK,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC,iBAAiB,KAAK,QAAQ;kBACjG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,mBAAmB;AACjD,kBAAE,EAAE,CAAC,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;AACL,QAAA,IAAA,CAAA,cAAc,GAAG,QAAQ,CAAC,IAAI,CAAC,mBAAmB,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC;AAEzE,QAAA,IAAA,CAAA,MAAM,GAAG,KAAK;8FAA2B;AACzC,QAAA,IAAA,CAAA,mBAAmB,GAAG,YAAY,CAAC,IAAI,CAAC,MAAM;AAC3C,aAAA,IAAI,CAAC,SAAS,CAAC,MAAM,IAAG;YACvB,IAAI,MAAM,EAAE;AACV,gBAAA,OAAO,EAAE,CAAC,MAAM,CAAC;YACnB;AAEA,YAAA,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,iBAAiB,KAAK,KAAK,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC,iBAAiB,KAAK,OAAO;kBAChG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS;AAC7B,kBAAE,EAAE,CAAC,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;AACL,QAAA,IAAA,CAAA,cAAc,GAAG,QAAQ,CAAC,IAAI,CAAC,mBAAmB,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC;;QAGzE,IAAA,CAAA,UAAU,GAAG,KAAK,CAAS,oBAAoB;uFAAC;QAEhD,IAAA,CAAA,aAAa,GAAG,KAAK,CAAW,EAAE;0FAAC;QACnC,IAAA,CAAA,cAAc,GAAG,KAAK,CAAW,EAAE;2FAAC;QAEpC,IAAA,CAAA,cAAc,GAAG,MAAM,CAAC,KAAK;2FAAC;AAE9B,QAAA,IAAA,CAAA,WAAW,GAAG,QAAQ,CAAyB,MAAK;YAClD,MAAM,KAAK,GACT,IAAI,CAAC,QAAQ,EAAE,CAAC,UAAU,KAAK,QAAQ;;AAErC,gBAAA,IAAI,CAAC,aAAa,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,cAAc,CAAC,WAAW,EAAE,CAAC,CAAC;;gBAEpH,IAAI,CAAC,aAAa,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,cAAc,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC,WAAW,EAAE,CAAC;YAEjK,MAAM,MAAM,GACV,IAAI,CAAC,QAAQ,EAAE,CAAC,UAAU,KAAK,QAAQ;;AAErC,gBAAA,IAAI,CAAC,cAAc,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,cAAc,CAAC,WAAW,EAAE,CAAC,CAAC;;gBAEtH,IAAI,CAAC,cAAc,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,cAAc,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC,WAAW,EAAE,CAAC;AAEnK,YAAA,MAAM,UAAU,GAAG;gBACjB,IACE,IAAI,CAAC,QAAQ,EAAE,CAAC,UAAU,KAAK,QAAQ;AACpC,oBAAA,KAA+B,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC,WAAW,EAAE,CAAC;AACxE,oBAAA,KAAkB;aAExB;AACD,YAAA,MAAM,YAAY,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AAEjH,YAAA,MAAM,WAAW,GAAG;gBAClB,IACE,IAAI,CAAC,QAAQ,EAAE,CAAC,UAAU,KAAK,QAAQ;AACpC,oBAAA,MAAkB,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC,WAAW,EAAE,CAAC;AAC3D,oBAAA,MAAmB;aAEzB;AACD,YAAA,MAAM,aAAa,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;YAEpH,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE;QACvD,CAAC;wFAAC;AAEF,QAAA,IAAA,CAAA,uBAAuB,GAAG,QAAQ,CAAC,MAAK;YACtC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,8BAA8B,EAAE;AACnD,gBAAA,OAAO,EAAE;YACX;YAEA,MAAM,YAAY,GAAa,EAAE;YAEjC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC,iBAAiB,EAAE,IAAI,KAAK,UAAU,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC,iBAAiB,EAAE,kBAAkB,EAAE;AACnH,gBAAA,YAAY,CAAC,IAAI,CAAC,gDAAgD,CAAC;YACrE;YAEA,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC,iBAAiB,EAAE,IAAI,EAAE;AAC3C,gBAAA,YAAY,CAAC,IAAI,CAAC,4CAA4C,CAAC;YACjE;AAEA,YAAA,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE;AAC7B,gBAAA,OAAO,EAAE;YACX;YAEA,OAAO,CAAA,EAAG,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,qBAAqB;QAC1D,CAAC;oGAAC;QAEF,IAAA,CAAA,KAAK,GAAG,MAAM,EAAO;QACrB,IAAA,CAAA,MAAM,GAAG,MAAM,CAAS,EAAE;mFAAC;QAE3B,IAAA,CAAA,eAAe,GAAG,eAAe;QAEjC,IAAA,CAAA,WAAW,GAAG,QAAQ,CAAC,MACrB,IAAI,CAAC,QAAQ,EAAE,CAAC;aACb,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM;AACrB,aAAA,MAAM,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,KAAK,IAAI,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC,EAAE,CAAC;eACtD,IAAI,CAAC,QAAQ,EAAE,CAAC,eAAe,IAAI,CAAC,CAAC;wFAC3C;QAED,IAAA,CAAA,gBAAgB,GAAG,MAAM,CAAC,CAAC;6FAAC;AAC5B,QAAA,IAAA,CAAA,IAAI,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC,MAAM,GAAG,CAAC,GAAG,MAAM,GAAG,YAAY;iFAAC;AAElH,QAAA,IAAA,CAAA,KAAK,GAAG,QAAQ,CAAC,MAAK;AACpB,YAAA,OAAO,CACH,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,MAAM,IAAI,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC;AACxD,iBAAC,IAAI,CAAC,IAAI,EAAE,KAAK,YAAY,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;gBAEnE,IAAI,CAAC,QAAQ,EAAE,CAAC,UAAU,IAAI,gBAAgB;AAC9C,gBAAA,IAAI,CAAC,QAAQ,EAAE,CAAC,WAAW,IAAI,iBAAiB;QACpD,CAAC;kFAAC;AAaH,IAAA;AAzJC,IAAA,SAAS;AAcT,IAAA,kBAAkB;AAalB,IAAA,mBAAmB;AAanB,IAAA,mBAAmB;IAsGnB,WAAW,GAAA;QACT,MAAM,IAAI,GAAG,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC;YACxC,IAAI,CAAC,eAAe;YACpB,IAAI,CAAC,gBAAgB;AAEvB,QAAA,IAAI,EAAE,EAAE,WAAW,EAAE;IACvB;AAEA,IAAA,WAAW,CAAC,CAAc,EAAA;QACxB,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC;IACpC;8GAzJW,0BAA0B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;kGAA1B,0BAA0B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,qBAAA,EAAA,MAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,aAAA,EAAA,EAAA,iBAAA,EAAA,eAAA,EAAA,UAAA,EAAA,eAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,cAAA,EAAA,EAAA,iBAAA,EAAA,gBAAA,EAAA,UAAA,EAAA,gBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,aAAA,EAAA,qBAAA,EAAA,cAAA,EAAA,sBAAA,EAAA,KAAA,EAAA,OAAA,EAAA,EAAA,WAAA,EAAA,CAAA,EAAA,YAAA,EAAA,iBAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EAAA,CAAA,iBAAA,CAAA,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,EAAA,EAAA,YAAA,EAAA,kBAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EAAA,CAAA,kBAAA,CAAA,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECjCvC,osLA2He,EAAA,MAAA,EAAA,CAAA,6wBAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAAA,IAAA,CAAA,eAAA,EAAA,QAAA,EAAA,cAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,eAAA,EAAA,oBAAA,EAAA,UAAA,EAAA,OAAA,EAAA,OAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,WAAA,EAAA,WAAA,EAAA,WAAA,CAAA,EAAA,OAAA,EAAA,CAAA,QAAA,EAAA,OAAA,CAAA,EAAA,QAAA,EAAA,CAAA,aAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAAA,IAAA,CAAA,uBAAA,EAAA,QAAA,EAAA,uBAAA,EAAA,MAAA,EAAA,CAAA,IAAA,EAAA,YAAA,EAAA,UAAA,CAAA,EAAA,OAAA,EAAA,CAAA,OAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAAA,IAAA,CAAA,sBAAA,EAAA,QAAA,EAAA,sBAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,QAAA,CAAA,EAAA,OAAA,EAAA,CAAA,QAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,qBAAA,EAAA,MAAA,EAAA,CAAA,WAAA,EAAA,YAAA,EAAA,WAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,cAAA,EAAA,WAAA,EAAA,MAAA,EAAA,UAAA,EAAA,MAAA,EAAA,SAAA,EAAA,UAAA,EAAA,YAAA,EAAA,SAAA,CAAA,EAAA,OAAA,EAAA,CAAA,gBAAA,EAAA,OAAA,CAAA,EAAA,QAAA,EAAA,CAAA,aAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,gBAAA,EAAA,QAAA,EAAA,eAAA,EAAA,MAAA,EAAA,CAAA,aAAA,EAAA,OAAA,EAAA,MAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,OAAA,EAAA,eAAA,EAAA,iBAAA,EAAA,eAAA,EAAA,aAAA,EAAA,aAAA,EAAA,gBAAA,EAAA,WAAA,EAAA,cAAA,EAAA,iBAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,SAAA,EAAA,UAAA,EAAA,UAAA,EAAA,aAAA,EAAA,WAAA,EAAA,iBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,aAAA,EAAA,YAAA,EAAA,WAAA,EAAA,OAAA,EAAA,MAAA,CAAA,EAAA,QAAA,EAAA,CAAA,cAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,8BAAA,EAAA,QAAA,EAAA,8BAAA,EAAA,MAAA,EAAA,CAAA,eAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,cAAA,EAAA,MAAA,EAAA,CAAA,aAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,MAAA,EAAA,cAAA,EAAA,cAAA,EAAA,UAAA,CAAA,EAAA,OAAA,EAAA,CAAA,OAAA,EAAA,MAAA,EAAA,aAAA,CAAA,EAAA,QAAA,EAAA,CAAA,aAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,cAAA,EAAA,QAAA,EAAA,aAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,KAAA,EAAA,UAAA,EAAA,eAAA,EAAA,eAAA,CAAA,EAAA,QAAA,EAAA,CAAA,YAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,iBAAA,EAAA,QAAA,EAAA,gBAAA,EAAA,MAAA,EAAA,CAAA,QAAA,EAAA,SAAA,EAAA,cAAA,EAAA,aAAA,EAAA,gBAAA,EAAA,UAAA,EAAA,YAAA,EAAA,MAAA,EAAA,WAAA,EAAA,gBAAA,EAAA,cAAA,EAAA,iBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,WAAA,EAAA,UAAA,EAAA,WAAA,CAAA,EAAA,QAAA,EAAA,CAAA,eAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,WAAA,EAAA,gBAAA,EAAA,cAAA,CAAA,EAAA,QAAA,EAAA,CAAA,kBAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,mBAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,gBAAA,EAAA,QAAA,EAAA,+BAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,SAAA,CAAA,EAAA,QAAA,EAAA,CAAA,cAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,ED/FX,eAAe,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,CAAA,UAAA,EAAA,MAAA,EAAA,YAAA,EAAA,sBAAA,EAAA,QAAA,EAAA,gBAAA,EAAA,QAAA,CAAA,EAAA,OAAA,EAAA,CAAA,4BAAA,CAAA,EAAA,CAAA,EAAA,CAAA,CAAA;;2FAKN,0BAA0B,EAAA,UAAA,EAAA,CAAA;kBAdtC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,qBAAqB,EAAA,OAAA,EACtB;wBACP,aAAa;wBACb,aAAa;wBACb,YAAY;wBACZ,YAAY;wBACZ,cAAc;wBACd,WAAW;wBACX;AACD,qBAAA,EAAA,QAAA,EAAA,osLAAA,EAAA,MAAA,EAAA,CAAA,6wBAAA,CAAA,EAAA;AAU4C,SAAA,CAAA,EAAA,cAAA,EAAA,EAAA,eAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,SAAA,EAAA,IAAA,EAAA,CAAA,iBAAiB,0EAChB,kBAAkB,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,QAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,UAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,KAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,OAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,QAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,QAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,UAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,YAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,aAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,eAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,CAAA,MAAA,EAAA,IAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,CAAA,EAAA,cAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,gBAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,CAAA,MAAA,EAAA,IAAA,EAAA,CAAA,sBAAA,CAAA,EAAA,CAAA,EAAA,KAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,MAAA,EAAA,IAAA,EAAA,CAAA,OAAA,CAAA,EAAA,CAAA,EAAA,EAAA,CAAA;;MEdrD,kBAAkB,CAAA;AAV/B,IAAA,WAAA,GAAA;AAWE,QAAA,IAAA,CAAA,SAAS,GAAG;AACV,YAAA,EAAE,EAAE,MAAM,CAAC,sBAAsB,CAAC;AAClC,YAAA,EAAE,EAAE,MAAM,CAAC,iBAAiB;SAC7B;AAED,QAAA,IAAA,CAAA,KAAK,GAAG;AACN,YAAA,IAAI,EAAE,QAAQ;AACd,YAAA,KAAK,EAAE,SAAS;AAChB,YAAA,OAAO,EAAE;SACV;QAED,IAAA,CAAA,2BAA2B,GAAG,MAAM,EAAuC;QAC3E,IAAA,CAAA,eAAe,GAAG,MAAM,CAAC,KAAK;AAAC,QAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,iBAAA,EAAA,CAAA,8BAAA,EAAA,CAAA,CAAA,CAAC;;QAGhC,IAAA,CAAA,gBAAgB,GAAG,KAAK,CAAW,EAAE;6FAAC;QACtC,IAAA,CAAA,iBAAiB,GAAG,KAAK,CAAW,EAAE;8FAAC;;AAGvC,QAAA,IAAA,CAAA,KAAK,GAAG,KAAK;6FAAqC;AAClD,QAAA,IAAA,CAAA,kBAAkB,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK;AACzC,aAAA,IAAI,CAAC,SAAS,CAAC,KAAK,IAAG;YACtB,IAAI,KAAK,EAAE;AACT,gBAAA,OAAO,EAAE,CAAC,KAAK,CAAC;YAClB;AAEA,YAAA,OAAO,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC,iBAAiB,KAAK,KAAK,IAAI,IAAI,CAAC,mBAAmB,EAAE,CAAC,iBAAiB,KAAK,OAAO;kBACtH,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ,CAAC,mBAAmB;AAChD,kBAAE,EAAE,CAAC,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;AACL,QAAA,IAAA,CAAA,aAAa,GAAG,QAAQ,CAAC,IAAI,CAAC,kBAAkB,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC;AAEvE,QAAA,IAAA,CAAA,MAAM,GAAG,KAAK;8FAAuB;AACrC,QAAA,IAAA,CAAA,mBAAmB,GAAG,YAAY,CAAC,IAAI,CAAC,MAAM;AAC3C,aAAA,IAAI,CAAC,SAAS,CAAC,MAAM,IAAG;YACvB,IAAI,MAAM,EAAE;AACV,gBAAA,OAAO,EAAE,CAAC,MAAM,CAAC;YACnB;AAEA,YAAA,OAAO,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC,iBAAiB,KAAK,KAAK,IAAI,IAAI,CAAC,mBAAmB,EAAE,CAAC,iBAAiB,KAAK,QAAQ;kBACvH,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,mBAAmB;AACjD,kBAAE,EAAE,CAAC,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;AACL,QAAA,IAAA,CAAA,cAAc,GAAG,QAAQ,CAAC,IAAI,CAAC,mBAAmB,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC;AAEzE,QAAA,IAAA,CAAA,MAAM,GAAG,KAAK;8FAA2B;AACzC,QAAA,IAAA,CAAA,mBAAmB,GAAG,YAAY,CAAC,IAAI,CAAC,MAAM;AAC3C,aAAA,IAAI,CAAC,SAAS,CAAC,MAAM,IAAG;YACvB,IAAI,MAAM,EAAE;AACV,gBAAA,OAAO,EAAE,CAAC,MAAM,CAAC;YACnB;AAEA,YAAA,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE;kBACvB,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS;AAC7B,kBAAE,EAAE,CAAC,EAAE,CAAC;QACV,CAAC,CAAC,CAAC;AACP,QAAA,IAAA,CAAA,cAAc,GAAG,QAAQ,CAAC,IAAI,CAAC,mBAAmB,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC;;QAGzE,IAAA,CAAA,iBAAiB,GAAG,KAAK,CAAS,CAAC;8FAAC;QACpC,IAAA,CAAA,iBAAiB,GAAG,KAAK,CAAC,KAAK;8FAAC;QAChC,IAAA,CAAA,qBAAqB,GAAG,KAAK,CAAS,cAAc;kGAAC;QAErD,IAAA,CAAA,yBAAyB,GAAG,KAAK,CAAU,KAAK;sGAAC;QAEjD,IAAA,CAAA,WAAW,GAAG,KAAK,CAAuB,qBAAqB;wFAAC;QAChE,IAAA,CAAA,iBAAiB,GAAG,KAAK,CAAS,gBAAgB;8FAAC;QAEnD,IAAA,CAAA,iBAAiB,GAAG,KAAK,CAAC,IAAI;8FAAC;;;QAG/B,IAAA,CAAA,mBAAmB,GAAG,KAAK,CAAuB;AAChD,YAAA,GAAG;AACJ,SAAA;gGAAC;;QAGF,IAAA,CAAA,YAAY,GAAG,KAAK,CAAS,SAAS;yFAAC;QACvC,IAAA,CAAA,kBAAkB,GAAG,KAAK,CAAS,YAAY;+FAAC;QAChD,IAAA,CAAA,kBAAkB,GAAG,KAAK,CAAS,YAAY;+FAAC;QAChD,IAAA,CAAA,iBAAiB,GAAG,KAAK,CAAS,eAAe;8FAAC;QAClD,IAAA,CAAA,oBAAoB,GAAG,KAAK,CAAS,cAAc;iGAAC;QACpD,IAAA,CAAA,UAAU,GAAG,KAAK,CAAS,YAAY;uFAAC;QACxC,IAAA,CAAA,qBAAqB,GAAG,KAAK,CAAS,oBAAoB;kGAAC;QAC3D,IAAA,CAAA,uBAAuB,GAAG,KAAK,CAAS,sBAAsB;oGAAC;QAC/D,IAAA,CAAA,wBAAwB,GAAG,KAAK,CAAS,uBAAuB;qGAAC;;;;AAMjE,QAAA,IAAA,CAAA,cAAc,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC,MAAM;2FAAC;AAEvF,QAAA,IAAA,CAAA,WAAW,GAAyB,QAAQ,CAAC,MAAK;AAChD,YAAA,MAAM,IAAI,GAAiB,IAAI,CAAC,gBAAgB;AAC7C,iBAAA,GAAG,CAAC,WAAW,KAAK;gBACnB,WAAW;AACX,gBAAA,KAAK,EAAE,WAAW;gBAClB,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC,WAAW,EAAE,KAAK,WAAW,CAAC,WAAW,EAAE;AAClG,aAAA,CAAC,CAAC;AAEL,YAAA,IAAI,CAAC,OAAO,CAAC,QAAQ,IAAG;AACtB,gBAAA,IAAI,QAAQ,CAAC,IAAI,EAAE;;AAEjB,oBAAA,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC,IAAI,CAAC,KAAK;;AAE/C,oBAAA,CAAC,KAAK,CAAC,cAAc,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAK,CAAC,cAAc,IAAI,CAAC,CAAC,CAAC;AACtE,wBAAA,CAAC,KAAK,CAAC,WAAW,IAAI,kBAAkB,EAAE,WAAW,EAAE,KAAK,QAAQ,CAAC,IAAK,CAAC,cAAe,CAAC,WAAW,EAAE;AACxG,wBAAA,CAAC,KAAK,CAAC,WAAW,IAAI,kBAAkB,EAAE,WAAW,EAAE,KAAK,QAAQ,CAAC,IAAK,CAAC,WAAW,EAAE,WAAW,EAAE,CACtG;;AAGD,oBAAA,QAAQ,IAAI,CAAC,WAAW,EAAE;AACxB,wBAAA,KAAK,qBAAqB;AAC1B,wBAAA,KAAK,aAAa;AAChB,4BAAA,QAAQ,CAAC,KAAK,GAAG,QAAQ,CAAC,IAAK,CAAC,WAAW,IAAI,QAAQ,CAAC,WAAW;4BACnE;AACF,wBAAA,KAAK,UAAU;AACf,wBAAA,KAAK,kBAAkB;AACrB,4BAAA,QAAQ,CAAC,KAAK,GAAG,QAAQ,CAAC,WAAW;4BACrC;AACF,wBAAA,KAAK,wBAAwB;AAC7B,wBAAA,KAAK,6BAA6B;AAChC,4BAAA,QAAQ,CAAC,KAAK,GAAG,CAAA,EAAG,QAAQ,CAAC,IAAK,CAAC,WAAW,CAAA,EAAA,EAAK,QAAQ,CAAC,WAAW,GAAG;4BAC1E;;oBACH;gBACH;AACF,YAAA,CAAC,CAAC;YAEF,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,IAAI,CAAC,yBAAyB,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC;QAC3F,CAAC;wFAAC;AAEF,QAAA,IAAA,CAAA,YAAY,GAA0B,QAAQ,CAAC,MAAK;AAClD,YAAA,MAAM,IAAI,GAAkB,IAAI,CAAC,iBAAiB;AAC/C,iBAAA,GAAG,CAAC,WAAW,KAAK;gBACnB,WAAW;AACX,gBAAA,KAAK,EAAE,WAAW;gBAClB,KAAK,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC,WAAW,EAAE,KAAK,WAAW,CAAC,WAAW,EAAE;AACpG,aAAA,CAAC,CAAC;AAEL,YAAA,IAAI,CAAC,OAAO,CAAC,QAAQ,IAAG;AACtB,gBAAA,IAAI,QAAQ,CAAC,KAAK,EAAE;;AAElB,oBAAA,QAAQ,CAAC,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,WAAW,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,IAAI,QAAQ,CAAC,WAAW;gBAC5F;AACF,YAAA,CAAC,CAAC;YAEF,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,IAAI,CAAC,yBAAyB,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC;QAC5F,CAAC;yFAAC;AAEF,QAAA,IAAA,CAAA,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,6BAA6B;AAC7G,aAAA,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;yFAAC;QAChC,IAAA,CAAA,WAAW,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,KAAK,OAAO;wFAAC;AAwB7D,IAAA;AA/KC,IAAA,SAAS;AAoBT,IAAA,kBAAkB;AAalB,IAAA,mBAAmB;AAanB,IAAA,mBAAmB;;AA4GnB,IAAA,iBAAiB,CAAC,KAAmC,EAAA;QACnD,IAAI,KAAK,KAAK,IAAI,CAAC,mBAAmB,EAAE,CAAC,iBAAiB,EAAE;;QAE5D;aAAO;AACL,YAAA,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC,UAAU,KAAK,QAAQ;AACzE,gBAAA,KAAK,CAAC,KAA+B,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC;gBACjE,KAAK,CAAC,KAAiB,CAAC;AAC1B,YAAA,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC,UAAU,KAAK,QAAQ;AAC1E,gBAAA,KAAK,CAAC,MAAkB,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC;gBACpD,KAAK,CAAC,MAAkB,CAAC;AAE3B,YAAA,IAAI,KAAK,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE;AACnE,gBAAA,IAAI,CAAC,2BAA2B,CAAC,IAAI,CAAC;oBACpC,KAAK,EAAE,KAAK,CAAC,YAAY;oBACzB,MAAM,EAAE,KAAK,CAAC;AACf,iBAAA,CAAC;YACJ;QACF;AAEA,QAAA,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC;IACjC;8GA/KW,kBAAkB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAlB,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,kBAAkB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,YAAA,EAAA,MAAA,EAAA,EAAA,gBAAA,EAAA,EAAA,iBAAA,EAAA,kBAAA,EAAA,UAAA,EAAA,kBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,EAAA,iBAAA,EAAA,mBAAA,EAAA,UAAA,EAAA,mBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,KAAA,EAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,EAAA,iBAAA,EAAA,mBAAA,EAAA,UAAA,EAAA,mBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,EAAA,iBAAA,EAAA,mBAAA,EAAA,UAAA,EAAA,mBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,qBAAA,EAAA,EAAA,iBAAA,EAAA,uBAAA,EAAA,UAAA,EAAA,uBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,yBAAA,EAAA,EAAA,iBAAA,EAAA,2BAAA,EAAA,UAAA,EAAA,2BAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,EAAA,iBAAA,EAAA,mBAAA,EAAA,UAAA,EAAA,mBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,EAAA,iBAAA,EAAA,mBAAA,EAAA,UAAA,EAAA,mBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,mBAAA,EAAA,EAAA,iBAAA,EAAA,qBAAA,EAAA,UAAA,EAAA,qBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,YAAA,EAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,UAAA,EAAA,cAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,kBAAA,EAAA,EAAA,iBAAA,EAAA,oBAAA,EAAA,UAAA,EAAA,oBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,kBAAA,EAAA,EAAA,iBAAA,EAAA,oBAAA,EAAA,UAAA,EAAA,oBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,EAAA,iBAAA,EAAA,mBAAA,EAAA,UAAA,EAAA,mBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,oBAAA,EAAA,EAAA,iBAAA,EAAA,sBAAA,EAAA,UAAA,EAAA,sBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,qBAAA,EAAA,EAAA,iBAAA,EAAA,uBAAA,EAAA,UAAA,EAAA,uBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,uBAAA,EAAA,EAAA,iBAAA,EAAA,yBAAA,EAAA,UAAA,EAAA,yBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,wBAAA,EAAA,EAAA,iBAAA,EAAA,0BAAA,EAAA,UAAA,EAAA,0BAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,2BAAA,EAAA,6BAAA,EAAA,gBAAA,EAAA,wBAAA,EAAA,iBAAA,EAAA,yBAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EC1B/B,+5JAuGC,EAAA,MAAA,EAAA,CAAA,gkBAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EDpFG,OAAO,0OAEP,0BAA0B,EAAA,QAAA,EAAA,qBAAA,EAAA,MAAA,EAAA,CAAA,UAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,YAAA,EAAA,eAAA,EAAA,gBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,qBAAA,EAAA,sBAAA,EAAA,OAAA,CAAA,EAAA,CAAA,EAAA,CAAA,CAAA;;2FAKjB,kBAAkB,EAAA,UAAA,EAAA,CAAA;kBAV9B,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,YAAY,EAAA,OAAA,EACb;wBACP,OAAO;wBACP,WAAW;wBACX;AACD,qBAAA,EAAA,QAAA,EAAA,+5JAAA,EAAA,MAAA,EAAA,CAAA,gkBAAA,CAAA,EAAA;;;MEqBU,0BAA0B,CAAA;IACrC,OAAO,OAAO,CAAC,MAAqC,EAAA;QAClD,OAAO;AACL,YAAA,QAAQ,EAAE,0BAA0B;AACpC,YAAA,SAAS,EAAE;AACT,gBAAA;AACE,oBAAA,OAAO,EAAE,kCAAkC;AAC3C,oBAAA,QAAQ,EAAE;AACX;AACF;SACF;IACH;AAEA,IAAA,WAAA,CAAoC,YAAwC,EAAA;QAC1E,IAAI,YAAY,EAAE;AAChB,YAAA,MAAM,IAAI,KAAK,CACb,+EAA+E,CAAC;QACpF;IACF;8GAlBW,0BAA0B,EAAA,IAAA,EAAA,CAAA,EAAA,KAAA,EAAA,0BAAA,EAAA,QAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,QAAA,EAAA,CAAA,CAAA;AAA1B,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,mBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,0BAA0B,YArBnC,YAAY;YACZ,mBAAmB;AAEnB,YAAA,WAAW,EAAE,aAAa;YAC1B,UAAU;YACV,aAAa;YACb,aAAa;YACb,YAAY;YACZ,WAAW;YACX,cAAc;YAEd,0BAA0B;YAC1B,eAAe;AACf,YAAA,kBAAkB,aAGlB,0BAA0B;YAC1B,eAAe;YACf,kBAAkB,CAAA,EAAA,CAAA,CAAA;AAGT,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,mBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,0BAA0B,YArBnC,YAAY;YACZ,mBAAmB;AAEnB,YAAA,WAAW,EAAE,aAAa;YAC1B,UAAU;YACV,aAAa;YACb,aAAa;YACb,YAAY;YACZ,WAAW;YACX,cAAc;YAEd,0BAA0B;YAC1B,eAAe;YACf,kBAAkB,CAAA,EAAA,CAAA,CAAA;;2FAQT,0BAA0B,EAAA,UAAA,EAAA,CAAA;kBAxBtC,QAAQ;AAAC,YAAA,IAAA,EAAA,CAAA;AACR,oBAAA,YAAY,EAAE,EAAE;AAChB,oBAAA,OAAO,EAAE;wBACP,YAAY;wBACZ,mBAAmB;AAEnB,wBAAA,WAAW,EAAE,aAAa;wBAC1B,UAAU;wBACV,aAAa;wBACb,aAAa;wBACb,YAAY;wBACZ,WAAW;wBACX,cAAc;wBAEd,0BAA0B;wBAC1B,eAAe;wBACf;AACD,qBAAA;AACD,oBAAA,OAAO,EAAE;wBACP,0BAA0B;wBAC1B,eAAe;wBACf;AACD;AACF,iBAAA;;0BAcc;;0BAAY;;;ACxD3B;;AAEG;;;;"}
|
|
@@ -34,6 +34,8 @@ class AuthenticationSSOService extends NgxLibServiceBase {
|
|
|
34
34
|
#lastResumeCheckAt;
|
|
35
35
|
// Timer id used to refresh tokens before expiry.
|
|
36
36
|
#tokenRefreshTimeoutId;
|
|
37
|
+
// Treat near-expiry tokens as expired to avoid race conditions during downstream API calls.
|
|
38
|
+
#expirationSkewMilliseconds;
|
|
37
39
|
#expirationEpochSeconds;
|
|
38
40
|
//#endregion
|
|
39
41
|
//#region Properties
|
|
@@ -71,6 +73,8 @@ class AuthenticationSSOService extends NgxLibServiceBase {
|
|
|
71
73
|
// Coalescing flags used when syncing auth after tab visibility/focus resumes.
|
|
72
74
|
this.#resumeCheckInProgress = false;
|
|
73
75
|
this.#lastResumeCheckAt = 0;
|
|
76
|
+
// Treat near-expiry tokens as expired to avoid race conditions during downstream API calls.
|
|
77
|
+
this.#expirationSkewMilliseconds = 30000;
|
|
74
78
|
this.#expirationEpochSeconds = signal(undefined, /* @ts-ignore */
|
|
75
79
|
...(ngDevMode ? [{ debugName: "#expirationEpochSeconds" }] : /* istanbul ignore next */ []));
|
|
76
80
|
const authenticationEndpoint = options.authenticationEndpoint ?? `https://login.microsoftonline.com/${options.tenantId}`;
|
|
@@ -211,9 +215,10 @@ class AuthenticationSSOService extends NgxLibServiceBase {
|
|
|
211
215
|
title: claims.title,
|
|
212
216
|
workShift: claims.workShift
|
|
213
217
|
};
|
|
214
|
-
// Persist id token
|
|
218
|
+
// Persist the most recent id token from the auth result first.
|
|
219
|
+
// account.idToken can lag behind after silent refresh in some MSAL flows.
|
|
215
220
|
if (this.options.tokenName) {
|
|
216
|
-
const token = resolvedAccount
|
|
221
|
+
const token = this.#getLatestIdToken(resolvedResult, resolvedAccount);
|
|
217
222
|
if (token) {
|
|
218
223
|
this.storage.setItem(this.options.tokenName, token);
|
|
219
224
|
}
|
|
@@ -241,7 +246,8 @@ class AuthenticationSSOService extends NgxLibServiceBase {
|
|
|
241
246
|
const account = this.#msal.getActiveAccount() ?? this.#msal.getAllAccounts()[0];
|
|
242
247
|
if (account)
|
|
243
248
|
return this.validateUser(undefined, account);
|
|
244
|
-
|
|
249
|
+
// Ensure stale app token is removed when MSAL has no cached account.
|
|
250
|
+
return this.#logoutLocalOnly(false);
|
|
245
251
|
})
|
|
246
252
|
.catch((error) => {
|
|
247
253
|
console.log('ERROR: Failed to hydrate Microsoft auth state.', error);
|
|
@@ -305,8 +311,10 @@ class AuthenticationSSOService extends NgxLibServiceBase {
|
|
|
305
311
|
try {
|
|
306
312
|
await this.#initializeMsal();
|
|
307
313
|
const account = this.#msal.getActiveAccount() ?? this.#msal.getAllAccounts()[0];
|
|
308
|
-
if (!account)
|
|
314
|
+
if (!account) {
|
|
315
|
+
await this.#logoutLocalOnly(false);
|
|
309
316
|
return;
|
|
317
|
+
}
|
|
310
318
|
await this.validateUser(undefined, account);
|
|
311
319
|
}
|
|
312
320
|
catch (error) {
|
|
@@ -351,10 +359,10 @@ class AuthenticationSSOService extends NgxLibServiceBase {
|
|
|
351
359
|
}
|
|
352
360
|
// Returns true when token expiration is absent or in the past.
|
|
353
361
|
#isTokenExpired(expirationEpochSeconds) {
|
|
354
|
-
if (
|
|
362
|
+
if (expirationEpochSeconds == null || expirationEpochSeconds == undefined || expirationEpochSeconds <= 0) {
|
|
355
363
|
return true;
|
|
356
364
|
}
|
|
357
|
-
return Date.now() >= expirationEpochSeconds * 1000;
|
|
365
|
+
return Date.now() + this.#expirationSkewMilliseconds >= expirationEpochSeconds * 1000;
|
|
358
366
|
}
|
|
359
367
|
// Attempts silent token acquisition for the current account.
|
|
360
368
|
async #refreshToken(account) {
|
|
@@ -369,6 +377,10 @@ class AuthenticationSSOService extends NgxLibServiceBase {
|
|
|
369
377
|
return undefined;
|
|
370
378
|
}
|
|
371
379
|
}
|
|
380
|
+
// Prefers the token returned from the most recent auth result.
|
|
381
|
+
#getLatestIdToken(result, account) {
|
|
382
|
+
return result?.idToken ?? account?.idToken;
|
|
383
|
+
}
|
|
372
384
|
// Schedules token refresh shortly before expiration.
|
|
373
385
|
// If refresh fails, session is terminated to avoid inconsistent auth state.
|
|
374
386
|
#scheduleTokenRefresh(expirationEpochSeconds, account) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cleavelandprice-ngx-lib-authentication-sso.mjs","sources":["../../../../projects/cleavelandprice/ngx-lib/authentication/sso/src/model/authentication-sso-service-options-token.ts","../../../../projects/cleavelandprice/ngx-lib/authentication/sso/src/services/authentication-sso.service.ts","../../../../projects/cleavelandprice/ngx-lib/authentication/sso/src/components/redirect/authentication-sso-redirect.component.ts","../../../../projects/cleavelandprice/ngx-lib/authentication/sso/src/authentication-sso.module.ts","../../../../projects/cleavelandprice/ngx-lib/authentication/sso/src/guards/authentication-sso.guard.ts","../../../../projects/cleavelandprice/ngx-lib/authentication/sso/src/cleavelandprice-ngx-lib-authentication-sso.ts"],"sourcesContent":["import { InjectionToken } from \"@angular/core\";\r\nimport { AuthenticationSSOServiceOptions } from \"./authentication-sso-service-options\";\r\n\r\n// What is a InjectionToken?\r\n// An InjectionToken is a way to create a token that can be used to inject a dependency into an Angular service or component.\r\n// It allows you to define a unique identifier for a dependency, which can then be used to retrieve the dependency from the Angular dependency injection system.\r\n// This is particularly useful when you want to inject a value that is not a class, such as a configuration object or a string.\r\n// Great explaination of InjectionToken: https://youtu.be/GvA7xnBmEto?si=_Nc2DTzdsb0jdvuk\r\nexport const AuthenticationSSOServiceOptionsToken = new InjectionToken<AuthenticationSSOServiceOptions>('AuthenticationSSOServiceOptions');\r\n","import { EventEmitter, Inject, Injectable, Optional, Output, signal } from '@angular/core';\r\n\r\nimport { AbstractAuthenticationService, AuthenticatedUser } from '@cleavelandprice/ngx-lib/authentication';\r\n\r\nimport { NgxLibServiceBase } from '@cleavelandprice/ngx-lib';\r\n\r\nimport { AuthenticationSSOServiceOptions } from '../model/authentication-sso-service-options';\r\nimport { AuthenticationSSOServiceOptionsToken } from './../model/authentication-sso-service-options-token';\r\nimport { AuthenticationSSOClaims } from '../model/authentication-sso-claims';\r\n\r\nimport {\r\n AccountInfo,\r\n AuthenticationResult,\r\n BrowserCacheLocation,\r\n PublicClientApplication,\r\n type Configuration\r\n} from '@azure/msal-browser';\r\n\r\n// This service implements authentication using Microsoft Entra ID (formerly Azure AD) via the Microsoft Authentication Library (MSAL).\r\n// It provides methods for logging in, logging out, and validating the authenticated user, while managing token storage and refresh.\r\n// It also supports cross-tab synchronization of authentication state using the BroadcastChannel API.\r\n// It also supports revalidating authentication state when the user returns to a tab after it has been backgrounded for a period of time.\r\n// It also supports storing the token in either localStorage or sessionStorage, based on the user's preference.\r\n// It also supports determining if the token is expired and refreshing it if necessary, or logging the user out if the token cannot be refreshed.\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class AuthenticationSSOService extends NgxLibServiceBase implements AbstractAuthenticationService {\r\n //#region Fields\r\n authenticating = false; // Flag set to true while the service is attempting to authenticate the user\r\n authenticated = false; // Flag set to true when the user is successfully authenticated\r\n authenticatedUser?: AuthenticatedUser; // Object representing the authenticated user\r\n\r\n // error NG8110: Unsupported call to the output function. This function can only be used as the initializer of a property on a @Component or @Directive class.\r\n /*authenticatedChanged = output<boolean>();\r\n authenticatingChanged = output<boolean>();\r\n authenticationError = output();*/\r\n @Output() authenticatedChanged = new EventEmitter<boolean>();\r\n @Output() authenticatingChanged = new EventEmitter<boolean>();\r\n @Output() authenticationError = new EventEmitter();\r\n\r\n // Microsoft Authentication Library (MSAL) instance for handling authentication\r\n #msal: PublicClientApplication;\r\n // Tracks one-time MSAL initialize() completion.\r\n #initialized = false;\r\n\r\n // Cross-tab messaging channel (same-origin tabs only).\r\n #channel?: BroadcastChannel;\r\n // Broadcast payload sent between tabs to synchronize logout.\r\n #logoutMessage = 'logout';\r\n\r\n // Coalescing flags used when syncing auth after tab visibility/focus resumes.\r\n #resumeCheckInProgress = false;\r\n #lastResumeCheckAt = 0;\r\n\r\n // Timer id used to refresh tokens before expiry.\r\n #tokenRefreshTimeoutId?: ReturnType<typeof setTimeout>;\r\n\r\n #expirationEpochSeconds = signal<number | undefined>(undefined);\r\n //#endregion\r\n\r\n //#region Properties\r\n\r\n // I don't agree with these properties being required in the AbstractAuthenticationService interface\r\n // I think this should be set in the options passed to the service.\r\n // I know this is used in the login components under material but a developer who wants to use their own login with sessionStorage would need to know that they need to create a localStorage item called 'storeTokenInSession' and set it to true\r\n // I have added a cacheLocation option to the AuthenticationSSOServiceOptions interface but if the users don't set it, they can use these properties to set the storage location\r\n\r\n get useSessionStorage(): boolean {\r\n return !!localStorage.getItem('storeTokenInSession');\r\n }\r\n\r\n get storage(): Storage {\r\n return this.useSessionStorage ?\r\n sessionStorage:\r\n localStorage;\r\n }\r\n\r\n //#endregion\r\n\r\n //#region Lifecycle\r\n constructor(@Optional() @Inject(AuthenticationSSOServiceOptionsToken) protected options: AuthenticationSSOServiceOptions) {\r\n super(options);\r\n\r\n const authenticationEndpoint = options.authenticationEndpoint ?? `https://login.microsoftonline.com/${options.tenantId}`;\r\n\r\n this.options = {\r\n ...options,\r\n\r\n tokenName: options.tokenName ?? options.clientId + '-token',\r\n authenticationEndpoint\r\n };\r\n\r\n // if the user didn't set the cacheLocation in the options, we will set it to sessionStorage if useSessionStorage is true, otherwise we will set it to localStorage\r\n this.options.cacheLocation = this.options.cacheLocation ?? (this.useSessionStorage ? 'sessionStorage' : 'localStorage');\r\n\r\n // MSAL configuration for this SPA.\r\n // Cache remains in sessionStorage so each tab has isolated auth cache.\r\n const msalConfig: Configuration = {\r\n auth: {\r\n clientId: this.options.clientId,\r\n authority: this.options.authenticationEndpoint,\r\n redirectUri: this.options.redirectUri,\r\n postLogoutRedirectUri: this.options.postLogoutRedirectUri\r\n },\r\n cache: {\r\n cacheLocation: this.options.cacheLocation === 'sessionStorage' ? BrowserCacheLocation.SessionStorage : BrowserCacheLocation.LocalStorage\r\n }\r\n };\r\n\r\n // Create MSAL client based on the configuration.\r\n // We still need to call initialize() before using it, but this ensures that we only create one instance of the client.\r\n this.#msal = new PublicClientApplication(msalConfig);\r\n\r\n // Initialize the BroadcastChannel for cross-tab communication\r\n this.#initializeBroadcastChannel();\r\n\r\n // Register resume listeners so returning to a tab revalidates auth state.\r\n this.#registerResumeListeners();\r\n\r\n // Attempt to restore authenticated state from any existing Microsoft session.\r\n this.checkForExistingToken();\r\n }\r\n //#endregion\r\n\r\n //#region Utilities\r\n\r\n //Authenticate the user and store the token in Local Storage or Session Storage\r\n login(): void {\r\n // There are times this item is left in sessionStorage after logout, which can cause MSAL to think a login is in progress and block future logins.\r\n // This is a workaround to ensure that the item is removed after logout.\r\n if (typeof sessionStorage !== 'undefined' && sessionStorage.getItem(\"msal.interaction.status\"))\r\n sessionStorage.removeItem(\"msal.interaction.status\");\r\n\r\n this.authenticating = true;\r\n this.authenticatingChanged.emit(this.authenticating);\r\n\r\n console.log('AuthenticationSSOService: login() called. Authenticating user...');\r\n\r\n // Initialize MSAL and then perform login via popup, followed by user validation.\r\n this.#initializeMsal()\r\n .then(() => this.#msal.loginPopup({\r\n scopes: this.options.scopes,\r\n authority: this.options.authenticationEndpoint,\r\n prompt: 'select_account'\r\n }))\r\n .then((result) => this.validateUser(result))\r\n .catch((error: unknown) => {\r\n this.authenticating = false;\r\n this.authenticatingChanged.emit(this.authenticating);\r\n this.authenticationError.emit(error);\r\n });\r\n }\r\n\r\n // Primary logout flow:\r\n // 1) clear local state in this tab,\r\n // 2) notify other tabs to clear their local state,\r\n // 3) initiate Entra sign-out redirect from this initiating tab.\r\n logout(): void {\r\n this.#logoutLocalOnly(false);\r\n this.#publishLogout();\r\n\r\n // Only the initiating tab should call identity-provider logout.\r\n this.#clearTokenRefreshTimer();\r\n\r\n this.#initializeMsal()\r\n .then(() => this.#msal.logoutRedirect({\r\n postLogoutRedirectUri: this.options.postLogoutRedirectUri\r\n }))\r\n .catch((error) => {\r\n console.log('ERROR: Microsoft logout failed.', error);\r\n });\r\n }\r\n\r\n tokenExists(): boolean {\r\n const token = this.storage.getItem(this.options.tokenName ?? '');\r\n return !!token;\r\n }\r\n\r\n // validateUser() = setAuthenticatedUser()\r\n // Resolves current user and token claims into the app's authenticated model.\r\n // Also validates/refreshes token when needed and schedules proactive refresh.\r\n async validateUser(result?: AuthenticationResult, account?: AccountInfo): Promise<void> {\r\n // Resolve account from auth result or fallback account.\r\n let resolvedAccount = result?.account ?? account;\r\n\r\n console.log('AuthenticationSSOService: Validating user. Result:', result, 'Account:', account, 'ResolvedAccount:', resolvedAccount);\r\n\r\n // No account means app should be considered logged out.\r\n if (!resolvedAccount) {\r\n this.logout();\r\n return;\r\n }\r\n\r\n // Keep MSAL active account in sync with resolved account context.\r\n this.#msal.setActiveAccount(resolvedAccount);\r\n\r\n let resolvedResult = result;\r\n let claims = (resolvedResult?.idTokenClaims ?? resolvedAccount.idTokenClaims ?? {}) as AuthenticationSSOClaims;\r\n\r\n // expiresOn comes over as a Date object if it exists, but exp is a number of seconds since epoch.\r\n // therefore, if expiresOn exists convert it to seconds since epoch, otherwise use exp if it exists, otherwise undefined.\r\n // expiresOn is only present when the token is acquired via acquireTokenSilent or acquireTokenPopup, but not when the token is acquired via loginPopup or loginRedirect.\r\n let expirationEpochSeconds = resolvedResult?.expiresOn ? Math.floor(resolvedResult.expiresOn.getTime() / 1000) : claims.exp ?? undefined;\r\n\r\n // If token appears expired, attempt silent refresh before setting user state.\r\n if (this.#isTokenExpired(expirationEpochSeconds)) {\r\n const refreshedResult = await this.#refreshToken(resolvedAccount);\r\n\r\n // Refresh failure means we should end the session.\r\n if (!refreshedResult?.account) {\r\n this.logout();\r\n return;\r\n }\r\n\r\n resolvedResult = refreshedResult;\r\n resolvedAccount = refreshedResult.account;\r\n claims = (resolvedResult.idTokenClaims ?? resolvedAccount.idTokenClaims ?? {}) as AuthenticationSSOClaims;\r\n expirationEpochSeconds = resolvedResult?.expiresOn ? Math.floor(resolvedResult.expiresOn.getTime() / 1000) : claims.exp ?? undefined;\r\n\r\n // Still expired after refresh; terminate session to avoid stale auth.\r\n if (this.#isTokenExpired(expirationEpochSeconds)) {\r\n this.logout();\r\n return;\r\n }\r\n }\r\n\r\n // Derive a stable account name from available claims.\r\n const preferredUsername = String(claims.preferred_username ?? resolvedAccount.username ?? claims.upn ?? claims.email ?? '');\r\n const accountName = preferredUsername.includes('@') ? preferredUsername.split('@')[0] : preferredUsername;\r\n\r\n // Map Entra claims to the app's authenticated user shape.\r\n this.authenticatedUser = {\r\n admin: false,\r\n accountName: claims.accountName ?? accountName,\r\n department: claims.department ?? '',\r\n displayName: claims.displayName ?? '',\r\n distinguishedName: claims.distinguishedName ?? '',\r\n email: claims.mail,\r\n employeeNumber: claims.employeeNumber,\r\n firstName: claims.firstName ?? '',\r\n hireDate: claims.hireDate ?? '',\r\n lastName: claims.lastName ?? '',\r\n manager: claims.manager,\r\n memberOf: claims.memberOf,\r\n phone: claims.phone,\r\n photoUrl: claims.photoUrl,\r\n sid: claims.securityIdentifier ?? '',\r\n title: claims.title,\r\n workShift: claims.workShift\r\n } as AuthenticatedUser;\r\n\r\n // Persist id token into shared auth storage key when configured.\r\n if (this.options.tokenName) {\r\n const token = resolvedAccount?.idToken;\r\n if (token) {\r\n this.storage.setItem(this.options.tokenName, token);\r\n } else {\r\n this.storage.removeItem(this.options.tokenName);\r\n }\r\n }\r\n\r\n this.#expirationEpochSeconds.set(expirationEpochSeconds);\r\n\r\n // Schedule refresh before expiration to keep session uninterrupted.\r\n this.#scheduleTokenRefresh(expirationEpochSeconds, resolvedAccount);\r\n\r\n // Publish authenticated state only when it changes.\r\n const wasAuthenticated = this.authenticated;\r\n this.authenticated = true;\r\n if (wasAuthenticated !== this.authenticated) {\r\n this.authenticatedChanged.emit(this.authenticated);\r\n }\r\n\r\n this.authenticating = false;\r\n this.authenticatingChanged.emit(this.authenticating);\r\n }\r\n\r\n // Rehydrates auth state from existing cached account on startup.\r\n // We intentionally avoid handleRedirectPromise() because this service uses popup login.\r\n checkForExistingToken(): void {\r\n this.#initializeMsal()\r\n .then(() => {\r\n const account = this.#msal.getActiveAccount() ?? this.#msal.getAllAccounts()[0];\r\n if (account)\r\n return this.validateUser(undefined, account);\r\n\r\n return undefined;\r\n })\r\n .catch((error: unknown) => {\r\n console.log('ERROR: Failed to hydrate Microsoft auth state.', error);\r\n });\r\n }\r\n\r\n // Initialize MSAL if it hasn't been initialized yet\r\n // This ensures that we only initialize MSAL once, even if multiple login attempts are made\r\n // This is important because there is startup work that must be completed by MSAL before it can be used, and we don't want to repeat that work unnecessarily\r\n async #initializeMsal(): Promise<void> {\r\n if (this.#initialized) {\r\n return;\r\n }\r\n\r\n\r\n await this.#msal.initialize();\r\n this.#initialized = true;\r\n }\r\n\r\n // Sets up same-origin cross-tab messaging used to fan out logout events.\r\n #initializeBroadcastChannel(): void {\r\n if (typeof BroadcastChannel === 'undefined') {\r\n // Some runtimes may not support BroadcastChannel.\r\n return;\r\n }\r\n\r\n // Create a new BroadcastChannel for cross-tab communication\r\n this.#channel = new BroadcastChannel('sso-authentication-channel');\r\n\r\n // Listen for messages from other tabs for logout events.\r\n // When a logout message is received, the current tab will clear its local state and reload the page.\r\n this.#channel.onmessage = (event) => {\r\n if (event.data === this.#logoutMessage) {\r\n console.log('Received logout message from another tab.');\r\n // Receiving tabs clear local state and reload so route guards re-evaluate immediately.\r\n this.#logoutLocalOnly(true);\r\n }\r\n };\r\n }\r\n\r\n // Registers visibility/focus listeners to re-check auth when user returns to the tab.\r\n // Tabs can be backgrounded for long periods, and the user may have logged out in another tab or session.\r\n #registerResumeListeners(): void {\r\n const handleResume = () => {\r\n void this.#syncAuthOnResume();\r\n };\r\n\r\n if (typeof document !== 'undefined') {\r\n document.addEventListener('visibilitychange', () => {\r\n if (document.visibilityState === 'visible') {\r\n handleResume();\r\n }\r\n });\r\n }\r\n\r\n if (typeof window !== 'undefined') {\r\n window.addEventListener('focus', handleResume);\r\n }\r\n }\r\n\r\n // Syncs auth state after resume while preventing duplicate checks from rapid events.\r\n async #syncAuthOnResume(): Promise<void> {\r\n const now = Date.now();\r\n\r\n // visibilitychange and focus often fire back-to-back; coalesce to one check.\r\n // if now was less than 1 second since last check, skip this one.\r\n if (this.#resumeCheckInProgress || now - this.#lastResumeCheckAt < 1000) {\r\n return;\r\n }\r\n\r\n this.#resumeCheckInProgress = true;\r\n this.#lastResumeCheckAt = now;\r\n\r\n try {\r\n await this.#initializeMsal();\r\n\r\n const account = this.#msal.getActiveAccount() ?? this.#msal.getAllAccounts()[0];\r\n\r\n if (!account)\r\n return;\r\n\r\n await this.validateUser(undefined, account);\r\n }\r\n catch (error) {\r\n console.log('Error: Resume auth sync failed.', error);\r\n }\r\n finally {\r\n this.#resumeCheckInProgress = false;\r\n }\r\n }\r\n\r\n // Sends logout signal to other open tabs.\r\n #publishLogout(): void {\r\n this.#channel?.postMessage(this.#logoutMessage);\r\n }\r\n\r\n // Clears app/MSAL state in current tab without invoking provider-side logout.\r\n // reloadAfterLogout is intended for non-initiating tabs to force UI reset to auth route.\r\n async #logoutLocalOnly(reloadAfterLogout: boolean): Promise<void> {\r\n this.#clearTokenRefreshTimer();\r\n\r\n if (this.options.tokenName && this.storage.getItem(this.options.tokenName)) {\r\n this.storage.removeItem(this.options.tokenName);\r\n }\r\n\r\n const wasAuthenticated = this.authenticated;\r\n this.authenticatedUser = undefined;\r\n this.authenticated = false;\r\n if (wasAuthenticated !== this.authenticated) {\r\n this.authenticatedChanged.emit(false);\r\n }\r\n\r\n try {\r\n await this.#initializeMsal();\r\n await this.#msal.clearCache();\r\n this.#msal.setActiveAccount(null);\r\n\r\n // There are times this item is left in sessionStorage after logout, which can cause MSAL to think a login is in progress and block future logins.\r\n // This is a workaround to ensure that the item is removed after logout.\r\n sessionStorage.removeItem(\"msal.interaction.status\");\r\n\r\n // Secondary tabs should hard-refresh to guarantee route guards and app state reset.\r\n if (reloadAfterLogout && typeof window !== 'undefined') {\r\n window.location.reload();\r\n }\r\n } catch (error) {\r\n console.log('WARN: Local MSAL cache clear failed.', error);\r\n }\r\n }\r\n\r\n // Returns true when token expiration is absent or in the past.\r\n #isTokenExpired(expirationEpochSeconds?: number): boolean {\r\n if (!expirationEpochSeconds) {\r\n return true;\r\n }\r\n\r\n return Date.now() >= expirationEpochSeconds * 1000;\r\n }\r\n\r\n // Attempts silent token acquisition for the current account.\r\n async #refreshToken(account: AccountInfo): Promise<AuthenticationResult | undefined> {\r\n try {\r\n return await this.#msal.acquireTokenSilent({\r\n account,\r\n scopes: this.options.scopes\r\n });\r\n }\r\n catch (error) {\r\n console.log('Error: Silent token refresh failed.', error);\r\n return undefined;\r\n }\r\n }\r\n\r\n // Schedules token refresh shortly before expiration.\r\n // If refresh fails, session is terminated to avoid inconsistent auth state.\r\n #scheduleTokenRefresh(expirationEpochSeconds: number | undefined, account: AccountInfo): void {\r\n this.#clearTokenRefreshTimer();\r\n\r\n if (!expirationEpochSeconds) {\r\n return;\r\n }\r\n\r\n // Convert Unix epoch seconds to milliseconds for Date.now() comparison\r\n const expirationEpochMilliseconds = expirationEpochSeconds * 1000;\r\n // Schedule refresh 1 minute before expiration\r\n const refreshLeadTimeMs = 60000;\r\n // Calculate the delay until the refresh should occur, ensuring it's not negative\r\n const millisecondsUntilRefresh = expirationEpochMilliseconds - Date.now() - refreshLeadTimeMs;\r\n const delay = Math.max(millisecondsUntilRefresh, 0);\r\n\r\n this.#tokenRefreshTimeoutId = setTimeout(() => {\r\n this.#refreshToken(account)\r\n .then((result) => {\r\n console.log('AuthenticationSSOService: Token refresh result.', result);\r\n if (result?.account) {\r\n return this.validateUser(result, result.account);\r\n }\r\n\r\n // No account after refresh implies invalid session.\r\n this.logout();\r\n return undefined;\r\n })\r\n .catch(() => {\r\n // Any refresh exception falls back to logout for safety.\r\n this.logout();\r\n });\r\n }, delay);\r\n }\r\n\r\n // Cancels any pending token refresh timer.\r\n #clearTokenRefreshTimer(): void {\r\n if (!this.#tokenRefreshTimeoutId) {\r\n return;\r\n }\r\n\r\n clearTimeout(this.#tokenRefreshTimeoutId);\r\n this.#tokenRefreshTimeoutId = undefined;\r\n }\r\n //#endregion\r\n}\r\n","import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core';\nimport { broadcastResponseToMainFrame } from '@azure/msal-browser/redirect-bridge';\n\n@Component({\n selector: 'app-authentication-sso-redirect',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.Eager,\n template: '<p>Processing authentication...</p>',\n})\nexport class AuthenticationSSORedirectComponent implements OnInit {\n ngOnInit(): void {\n broadcastResponseToMainFrame().catch((error: Error) => {\n console.error('Error broadcasting response to main frame:', error);\n });\n }\n}\n","import { CommonModule } from '@angular/common';\r\nimport { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core';\r\n\r\nimport { AuthenticationSSOServiceOptions } from './model/authentication-sso-service-options';\r\nimport { AuthenticationSSOServiceOptionsToken } from './model/authentication-sso-service-options-token';\r\nimport { AuthenticationSSORedirectComponent } from './components/redirect/authentication-sso-redirect.component';\r\n\r\n@NgModule({\r\n declarations: [],\r\n imports: [\r\n CommonModule,\r\n AuthenticationSSORedirectComponent\r\n ],\r\n exports: [\r\n AuthenticationSSORedirectComponent\r\n ]\r\n})\r\nexport class AuthenticationSSOModule {\r\n static forRoot(options: AuthenticationSSOServiceOptions): ModuleWithProviders<AuthenticationSSOModule> {\r\n return {\r\n ngModule: AuthenticationSSOModule,\r\n providers: [\r\n {\r\n provide: AuthenticationSSOServiceOptionsToken,\r\n useValue: options\r\n }\r\n ]\r\n };\r\n }\r\n\r\n constructor(@Optional() @SkipSelf() parentModule: AuthenticationSSOModule) {\r\n if (parentModule) {\r\n throw new Error(\r\n 'AuthenticationSSOModule is already loaded. Import it in the AppModule only');\r\n }\r\n }\r\n}\r\n","import { inject } from '@angular/core';\r\nimport { CanActivateFn, Router } from '@angular/router';\r\nimport { map, take } from 'rxjs/operators';\r\nimport { AuthenticationSSOService } from '../authentication-sso.api';\r\n\r\nexport const authenticationSSOGuard: CanActivateFn = (_route, _state) => {\r\n const authenticationService = inject(AuthenticationSSOService);\r\n const router = inject(Router);\r\n\r\n // if the user is already authenticated, allow access to the route\r\n if (authenticationService.authenticated) {\r\n return true;\r\n }\r\n\r\n if (authenticationService.tokenExists()) {\r\n // we're doing this because we could've opened a new tab and the user is already logged in, so we need to check for an existing token\r\n authenticationService.checkForExistingToken();\r\n\r\n return authenticationService.authenticatedChanged.pipe(\r\n take(1),\r\n map(() => {\r\n if (!authenticationService.authenticated) {\r\n router.navigate(['']);\r\n return false;\r\n }\r\n\r\n return true;\r\n })\r\n );\r\n }\r\n else {\r\n router.navigate(['']);\r\n return false;\r\n }\r\n};\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './authentication-sso.api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cleavelandprice-ngx-lib-authentication-sso.mjs","sources":["../../../../projects/cleavelandprice/ngx-lib/authentication/sso/src/model/authentication-sso-service-options-token.ts","../../../../projects/cleavelandprice/ngx-lib/authentication/sso/src/services/authentication-sso.service.ts","../../../../projects/cleavelandprice/ngx-lib/authentication/sso/src/components/redirect/authentication-sso-redirect.component.ts","../../../../projects/cleavelandprice/ngx-lib/authentication/sso/src/authentication-sso.module.ts","../../../../projects/cleavelandprice/ngx-lib/authentication/sso/src/guards/authentication-sso.guard.ts","../../../../projects/cleavelandprice/ngx-lib/authentication/sso/src/cleavelandprice-ngx-lib-authentication-sso.ts"],"sourcesContent":["import { InjectionToken } from \"@angular/core\";\r\nimport { AuthenticationSSOServiceOptions } from \"./authentication-sso-service-options\";\r\n\r\n// What is a InjectionToken?\r\n// An InjectionToken is a way to create a token that can be used to inject a dependency into an Angular service or component.\r\n// It allows you to define a unique identifier for a dependency, which can then be used to retrieve the dependency from the Angular dependency injection system.\r\n// This is particularly useful when you want to inject a value that is not a class, such as a configuration object or a string.\r\n// Great explaination of InjectionToken: https://youtu.be/GvA7xnBmEto?si=_Nc2DTzdsb0jdvuk\r\nexport const AuthenticationSSOServiceOptionsToken = new InjectionToken<AuthenticationSSOServiceOptions>('AuthenticationSSOServiceOptions');\r\n","import { EventEmitter, Inject, Injectable, Optional, Output, signal } from '@angular/core';\r\n\r\nimport { AbstractAuthenticationService, AuthenticatedUser } from '@cleavelandprice/ngx-lib/authentication';\r\n\r\nimport { NgxLibServiceBase } from '@cleavelandprice/ngx-lib';\r\n\r\nimport { AuthenticationSSOServiceOptions } from '../model/authentication-sso-service-options';\r\nimport { AuthenticationSSOServiceOptionsToken } from './../model/authentication-sso-service-options-token';\r\nimport { AuthenticationSSOClaims } from '../model/authentication-sso-claims';\r\n\r\nimport {\r\n AccountInfo,\r\n AuthenticationResult,\r\n BrowserCacheLocation,\r\n PublicClientApplication,\r\n type Configuration\r\n} from '@azure/msal-browser';\r\n\r\n// This service implements authentication using Microsoft Entra ID (formerly Azure AD) via the Microsoft Authentication Library (MSAL).\r\n// It provides methods for logging in, logging out, and validating the authenticated user, while managing token storage and refresh.\r\n// It also supports cross-tab synchronization of authentication state using the BroadcastChannel API.\r\n// It also supports revalidating authentication state when the user returns to a tab after it has been backgrounded for a period of time.\r\n// It also supports storing the token in either localStorage or sessionStorage, based on the user's preference.\r\n// It also supports determining if the token is expired and refreshing it if necessary, or logging the user out if the token cannot be refreshed.\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class AuthenticationSSOService extends NgxLibServiceBase implements AbstractAuthenticationService {\r\n //#region Fields\r\n authenticating = false; // Flag set to true while the service is attempting to authenticate the user\r\n authenticated = false; // Flag set to true when the user is successfully authenticated\r\n authenticatedUser?: AuthenticatedUser; // Object representing the authenticated user\r\n\r\n // error NG8110: Unsupported call to the output function. This function can only be used as the initializer of a property on a @Component or @Directive class.\r\n /*authenticatedChanged = output<boolean>();\r\n authenticatingChanged = output<boolean>();\r\n authenticationError = output();*/\r\n @Output() authenticatedChanged = new EventEmitter<boolean>();\r\n @Output() authenticatingChanged = new EventEmitter<boolean>();\r\n @Output() authenticationError = new EventEmitter();\r\n\r\n // Microsoft Authentication Library (MSAL) instance for handling authentication\r\n #msal: PublicClientApplication;\r\n // Tracks one-time MSAL initialize() completion.\r\n #initialized = false;\r\n\r\n // Cross-tab messaging channel (same-origin tabs only).\r\n #channel?: BroadcastChannel;\r\n // Broadcast payload sent between tabs to synchronize logout.\r\n #logoutMessage = 'logout';\r\n\r\n // Coalescing flags used when syncing auth after tab visibility/focus resumes.\r\n #resumeCheckInProgress = false;\r\n #lastResumeCheckAt = 0;\r\n\r\n // Timer id used to refresh tokens before expiry.\r\n #tokenRefreshTimeoutId?: ReturnType<typeof setTimeout>;\r\n // Treat near-expiry tokens as expired to avoid race conditions during downstream API calls.\r\n #expirationSkewMilliseconds = 30000;\r\n\r\n #expirationEpochSeconds = signal<number | undefined>(undefined);\r\n //#endregion\r\n\r\n //#region Properties\r\n\r\n // I don't agree with these properties being required in the AbstractAuthenticationService interface\r\n // I think this should be set in the options passed to the service.\r\n // I know this is used in the login components under material but a developer who wants to use their own login with sessionStorage would need to know that they need to create a localStorage item called 'storeTokenInSession' and set it to true\r\n // I have added a cacheLocation option to the AuthenticationSSOServiceOptions interface but if the users don't set it, they can use these properties to set the storage location\r\n\r\n get useSessionStorage(): boolean {\r\n return !!localStorage.getItem('storeTokenInSession');\r\n }\r\n\r\n get storage(): Storage {\r\n return this.useSessionStorage ?\r\n sessionStorage:\r\n localStorage;\r\n }\r\n\r\n //#endregion\r\n\r\n //#region Lifecycle\r\n constructor(@Optional() @Inject(AuthenticationSSOServiceOptionsToken) protected options: AuthenticationSSOServiceOptions) {\r\n super(options);\r\n\r\n const authenticationEndpoint = options.authenticationEndpoint ?? `https://login.microsoftonline.com/${options.tenantId}`;\r\n\r\n this.options = {\r\n ...options,\r\n\r\n tokenName: options.tokenName ?? options.clientId + '-token',\r\n authenticationEndpoint\r\n };\r\n\r\n // if the user didn't set the cacheLocation in the options, we will set it to sessionStorage if useSessionStorage is true, otherwise we will set it to localStorage\r\n this.options.cacheLocation = this.options.cacheLocation ?? (this.useSessionStorage ? 'sessionStorage' : 'localStorage');\r\n\r\n // MSAL configuration for this SPA.\r\n // Cache remains in sessionStorage so each tab has isolated auth cache.\r\n const msalConfig: Configuration = {\r\n auth: {\r\n clientId: this.options.clientId,\r\n authority: this.options.authenticationEndpoint,\r\n redirectUri: this.options.redirectUri,\r\n postLogoutRedirectUri: this.options.postLogoutRedirectUri\r\n },\r\n cache: {\r\n cacheLocation: this.options.cacheLocation === 'sessionStorage' ? BrowserCacheLocation.SessionStorage : BrowserCacheLocation.LocalStorage\r\n }\r\n };\r\n\r\n // Create MSAL client based on the configuration.\r\n // We still need to call initialize() before using it, but this ensures that we only create one instance of the client.\r\n this.#msal = new PublicClientApplication(msalConfig);\r\n\r\n // Initialize the BroadcastChannel for cross-tab communication\r\n this.#initializeBroadcastChannel();\r\n\r\n // Register resume listeners so returning to a tab revalidates auth state.\r\n this.#registerResumeListeners();\r\n\r\n // Attempt to restore authenticated state from any existing Microsoft session.\r\n this.checkForExistingToken();\r\n }\r\n //#endregion\r\n\r\n //#region Utilities\r\n\r\n //Authenticate the user and store the token in Local Storage or Session Storage\r\n login(): void {\r\n // There are times this item is left in sessionStorage after logout, which can cause MSAL to think a login is in progress and block future logins.\r\n // This is a workaround to ensure that the item is removed after logout.\r\n if (typeof sessionStorage !== 'undefined' && sessionStorage.getItem(\"msal.interaction.status\"))\r\n sessionStorage.removeItem(\"msal.interaction.status\");\r\n\r\n this.authenticating = true;\r\n this.authenticatingChanged.emit(this.authenticating);\r\n\r\n console.log('AuthenticationSSOService: login() called. Authenticating user...');\r\n\r\n // Initialize MSAL and then perform login via popup, followed by user validation.\r\n this.#initializeMsal()\r\n .then(() => this.#msal.loginPopup({\r\n scopes: this.options.scopes,\r\n authority: this.options.authenticationEndpoint,\r\n prompt: 'select_account'\r\n }))\r\n .then((result) => this.validateUser(result))\r\n .catch((error: unknown) => {\r\n this.authenticating = false;\r\n this.authenticatingChanged.emit(this.authenticating);\r\n this.authenticationError.emit(error);\r\n });\r\n }\r\n\r\n // Primary logout flow:\r\n // 1) clear local state in this tab,\r\n // 2) notify other tabs to clear their local state,\r\n // 3) initiate Entra sign-out redirect from this initiating tab.\r\n logout(): void {\r\n this.#logoutLocalOnly(false);\r\n this.#publishLogout();\r\n\r\n // Only the initiating tab should call identity-provider logout.\r\n this.#clearTokenRefreshTimer();\r\n\r\n this.#initializeMsal()\r\n .then(() => this.#msal.logoutRedirect({\r\n postLogoutRedirectUri: this.options.postLogoutRedirectUri\r\n }))\r\n .catch((error) => {\r\n console.log('ERROR: Microsoft logout failed.', error);\r\n });\r\n }\r\n\r\n tokenExists(): boolean {\r\n const token = this.storage.getItem(this.options.tokenName ?? '');\r\n return !!token;\r\n }\r\n\r\n // validateUser() = setAuthenticatedUser()\r\n // Resolves current user and token claims into the app's authenticated model.\r\n // Also validates/refreshes token when needed and schedules proactive refresh.\r\n async validateUser(result?: AuthenticationResult, account?: AccountInfo): Promise<void> {\r\n // Resolve account from auth result or fallback account.\r\n let resolvedAccount = result?.account ?? account;\r\n\r\n console.log('AuthenticationSSOService: Validating user. Result:', result, 'Account:', account, 'ResolvedAccount:', resolvedAccount);\r\n\r\n // No account means app should be considered logged out.\r\n if (!resolvedAccount) {\r\n this.logout();\r\n return;\r\n }\r\n\r\n // Keep MSAL active account in sync with resolved account context.\r\n this.#msal.setActiveAccount(resolvedAccount);\r\n\r\n let resolvedResult = result;\r\n let claims = (resolvedResult?.idTokenClaims ?? resolvedAccount.idTokenClaims ?? {}) as AuthenticationSSOClaims;\r\n\r\n // expiresOn comes over as a Date object if it exists, but exp is a number of seconds since epoch.\r\n // therefore, if expiresOn exists convert it to seconds since epoch, otherwise use exp if it exists, otherwise undefined.\r\n // expiresOn is only present when the token is acquired via acquireTokenSilent or acquireTokenPopup, but not when the token is acquired via loginPopup or loginRedirect.\r\n let expirationEpochSeconds = resolvedResult?.expiresOn ? Math.floor(resolvedResult.expiresOn.getTime() / 1000) : claims.exp ?? undefined;\r\n\r\n // If token appears expired, attempt silent refresh before setting user state.\r\n if (this.#isTokenExpired(expirationEpochSeconds)) {\r\n const refreshedResult = await this.#refreshToken(resolvedAccount);\r\n\r\n // Refresh failure means we should end the session.\r\n if (!refreshedResult?.account) {\r\n this.logout();\r\n return;\r\n }\r\n\r\n resolvedResult = refreshedResult;\r\n resolvedAccount = refreshedResult.account;\r\n claims = (resolvedResult.idTokenClaims ?? resolvedAccount.idTokenClaims ?? {}) as AuthenticationSSOClaims;\r\n expirationEpochSeconds = resolvedResult?.expiresOn ? Math.floor(resolvedResult.expiresOn.getTime() / 1000) : claims.exp ?? undefined;\r\n\r\n // Still expired after refresh; terminate session to avoid stale auth.\r\n if (this.#isTokenExpired(expirationEpochSeconds)) {\r\n this.logout();\r\n return;\r\n }\r\n }\r\n\r\n // Derive a stable account name from available claims.\r\n const preferredUsername = String(claims.preferred_username ?? resolvedAccount.username ?? claims.upn ?? claims.email ?? '');\r\n const accountName = preferredUsername.includes('@') ? preferredUsername.split('@')[0] : preferredUsername;\r\n\r\n // Map Entra claims to the app's authenticated user shape.\r\n this.authenticatedUser = {\r\n admin: false,\r\n accountName: claims.accountName ?? accountName,\r\n department: claims.department ?? '',\r\n displayName: claims.displayName ?? '',\r\n distinguishedName: claims.distinguishedName ?? '',\r\n email: claims.mail,\r\n employeeNumber: claims.employeeNumber,\r\n firstName: claims.firstName ?? '',\r\n hireDate: claims.hireDate ?? '',\r\n lastName: claims.lastName ?? '',\r\n manager: claims.manager,\r\n memberOf: claims.memberOf,\r\n phone: claims.phone,\r\n photoUrl: claims.photoUrl,\r\n sid: claims.securityIdentifier ?? '',\r\n title: claims.title,\r\n workShift: claims.workShift\r\n } as AuthenticatedUser;\r\n\r\n // Persist the most recent id token from the auth result first.\r\n // account.idToken can lag behind after silent refresh in some MSAL flows.\r\n if (this.options.tokenName) {\r\n const token = this.#getLatestIdToken(resolvedResult, resolvedAccount);\r\n if (token) {\r\n this.storage.setItem(this.options.tokenName, token);\r\n } else {\r\n this.storage.removeItem(this.options.tokenName);\r\n }\r\n }\r\n\r\n this.#expirationEpochSeconds.set(expirationEpochSeconds);\r\n\r\n // Schedule refresh before expiration to keep session uninterrupted.\r\n this.#scheduleTokenRefresh(expirationEpochSeconds, resolvedAccount);\r\n\r\n // Publish authenticated state only when it changes.\r\n const wasAuthenticated = this.authenticated;\r\n this.authenticated = true;\r\n if (wasAuthenticated !== this.authenticated) {\r\n this.authenticatedChanged.emit(this.authenticated);\r\n }\r\n\r\n this.authenticating = false;\r\n this.authenticatingChanged.emit(this.authenticating);\r\n }\r\n\r\n // Rehydrates auth state from existing cached account on startup.\r\n // We intentionally avoid handleRedirectPromise() because this service uses popup login.\r\n checkForExistingToken(): void {\r\n this.#initializeMsal()\r\n .then(() => {\r\n const account = this.#msal.getActiveAccount() ?? this.#msal.getAllAccounts()[0];\r\n if (account)\r\n return this.validateUser(undefined, account);\r\n\r\n // Ensure stale app token is removed when MSAL has no cached account.\r\n return this.#logoutLocalOnly(false);\r\n })\r\n .catch((error: unknown) => {\r\n console.log('ERROR: Failed to hydrate Microsoft auth state.', error);\r\n });\r\n }\r\n\r\n // Initialize MSAL if it hasn't been initialized yet\r\n // This ensures that we only initialize MSAL once, even if multiple login attempts are made\r\n // This is important because there is startup work that must be completed by MSAL before it can be used, and we don't want to repeat that work unnecessarily\r\n async #initializeMsal(): Promise<void> {\r\n if (this.#initialized) {\r\n return;\r\n }\r\n\r\n\r\n await this.#msal.initialize();\r\n this.#initialized = true;\r\n }\r\n\r\n // Sets up same-origin cross-tab messaging used to fan out logout events.\r\n #initializeBroadcastChannel(): void {\r\n if (typeof BroadcastChannel === 'undefined') {\r\n // Some runtimes may not support BroadcastChannel.\r\n return;\r\n }\r\n\r\n // Create a new BroadcastChannel for cross-tab communication\r\n this.#channel = new BroadcastChannel('sso-authentication-channel');\r\n\r\n // Listen for messages from other tabs for logout events.\r\n // When a logout message is received, the current tab will clear its local state and reload the page.\r\n this.#channel.onmessage = (event) => {\r\n if (event.data === this.#logoutMessage) {\r\n console.log('Received logout message from another tab.');\r\n // Receiving tabs clear local state and reload so route guards re-evaluate immediately.\r\n this.#logoutLocalOnly(true);\r\n }\r\n };\r\n }\r\n\r\n // Registers visibility/focus listeners to re-check auth when user returns to the tab.\r\n // Tabs can be backgrounded for long periods, and the user may have logged out in another tab or session.\r\n #registerResumeListeners(): void {\r\n const handleResume = () => {\r\n void this.#syncAuthOnResume();\r\n };\r\n\r\n if (typeof document !== 'undefined') {\r\n document.addEventListener('visibilitychange', () => {\r\n if (document.visibilityState === 'visible') {\r\n handleResume();\r\n }\r\n });\r\n }\r\n\r\n if (typeof window !== 'undefined') {\r\n window.addEventListener('focus', handleResume);\r\n }\r\n }\r\n\r\n // Syncs auth state after resume while preventing duplicate checks from rapid events.\r\n async #syncAuthOnResume(): Promise<void> {\r\n const now = Date.now();\r\n\r\n // visibilitychange and focus often fire back-to-back; coalesce to one check.\r\n // if now was less than 1 second since last check, skip this one.\r\n if (this.#resumeCheckInProgress || now - this.#lastResumeCheckAt < 1000) {\r\n return;\r\n }\r\n\r\n this.#resumeCheckInProgress = true;\r\n this.#lastResumeCheckAt = now;\r\n\r\n try {\r\n await this.#initializeMsal();\r\n\r\n const account = this.#msal.getActiveAccount() ?? this.#msal.getAllAccounts()[0];\r\n\r\n if (!account) {\r\n await this.#logoutLocalOnly(false);\r\n return;\r\n }\r\n\r\n await this.validateUser(undefined, account);\r\n }\r\n catch (error) {\r\n console.log('Error: Resume auth sync failed.', error);\r\n }\r\n finally {\r\n this.#resumeCheckInProgress = false;\r\n }\r\n }\r\n\r\n // Sends logout signal to other open tabs.\r\n #publishLogout(): void {\r\n this.#channel?.postMessage(this.#logoutMessage);\r\n }\r\n\r\n // Clears app/MSAL state in current tab without invoking provider-side logout.\r\n // reloadAfterLogout is intended for non-initiating tabs to force UI reset to auth route.\r\n async #logoutLocalOnly(reloadAfterLogout: boolean): Promise<void> {\r\n this.#clearTokenRefreshTimer();\r\n\r\n if (this.options.tokenName && this.storage.getItem(this.options.tokenName)) {\r\n this.storage.removeItem(this.options.tokenName);\r\n }\r\n\r\n const wasAuthenticated = this.authenticated;\r\n this.authenticatedUser = undefined;\r\n this.authenticated = false;\r\n if (wasAuthenticated !== this.authenticated) {\r\n this.authenticatedChanged.emit(false);\r\n }\r\n\r\n try {\r\n await this.#initializeMsal();\r\n await this.#msal.clearCache();\r\n this.#msal.setActiveAccount(null);\r\n\r\n // There are times this item is left in sessionStorage after logout, which can cause MSAL to think a login is in progress and block future logins.\r\n // This is a workaround to ensure that the item is removed after logout.\r\n sessionStorage.removeItem(\"msal.interaction.status\");\r\n\r\n // Secondary tabs should hard-refresh to guarantee route guards and app state reset.\r\n if (reloadAfterLogout && typeof window !== 'undefined') {\r\n window.location.reload();\r\n }\r\n } catch (error) {\r\n console.log('WARN: Local MSAL cache clear failed.', error);\r\n }\r\n }\r\n\r\n // Returns true when token expiration is absent or in the past.\r\n #isTokenExpired(expirationEpochSeconds?: number): boolean {\r\n if (expirationEpochSeconds == null || expirationEpochSeconds == undefined || expirationEpochSeconds <= 0) {\r\n return true;\r\n }\r\n\r\n return Date.now() + this.#expirationSkewMilliseconds >= expirationEpochSeconds * 1000;\r\n }\r\n\r\n // Attempts silent token acquisition for the current account.\r\n async #refreshToken(account: AccountInfo): Promise<AuthenticationResult | undefined> {\r\n try {\r\n return await this.#msal.acquireTokenSilent({\r\n account,\r\n scopes: this.options.scopes\r\n });\r\n }\r\n catch (error) {\r\n console.log('Error: Silent token refresh failed.', error);\r\n return undefined;\r\n }\r\n }\r\n\r\n // Prefers the token returned from the most recent auth result.\r\n #getLatestIdToken(result?: AuthenticationResult, account?: AccountInfo): string | undefined {\r\n return result?.idToken ?? account?.idToken;\r\n }\r\n\r\n // Schedules token refresh shortly before expiration.\r\n // If refresh fails, session is terminated to avoid inconsistent auth state.\r\n #scheduleTokenRefresh(expirationEpochSeconds: number | undefined, account: AccountInfo): void {\r\n this.#clearTokenRefreshTimer();\r\n\r\n if (!expirationEpochSeconds) {\r\n return;\r\n }\r\n\r\n // Convert Unix epoch seconds to milliseconds for Date.now() comparison\r\n const expirationEpochMilliseconds = expirationEpochSeconds * 1000;\r\n // Schedule refresh 1 minute before expiration\r\n const refreshLeadTimeMs = 60000;\r\n // Calculate the delay until the refresh should occur, ensuring it's not negative\r\n const millisecondsUntilRefresh = expirationEpochMilliseconds - Date.now() - refreshLeadTimeMs;\r\n const delay = Math.max(millisecondsUntilRefresh, 0);\r\n\r\n this.#tokenRefreshTimeoutId = setTimeout(() => {\r\n this.#refreshToken(account)\r\n .then((result) => {\r\n console.log('AuthenticationSSOService: Token refresh result.', result);\r\n if (result?.account) {\r\n return this.validateUser(result, result.account);\r\n }\r\n\r\n // No account after refresh implies invalid session.\r\n this.logout();\r\n return undefined;\r\n })\r\n .catch(() => {\r\n // Any refresh exception falls back to logout for safety.\r\n this.logout();\r\n });\r\n }, delay);\r\n }\r\n\r\n // Cancels any pending token refresh timer.\r\n #clearTokenRefreshTimer(): void {\r\n if (!this.#tokenRefreshTimeoutId) {\r\n return;\r\n }\r\n\r\n clearTimeout(this.#tokenRefreshTimeoutId);\r\n this.#tokenRefreshTimeoutId = undefined;\r\n }\r\n //#endregion\r\n}\r\n","import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core';\nimport { broadcastResponseToMainFrame } from '@azure/msal-browser/redirect-bridge';\n\n@Component({\n selector: 'app-authentication-sso-redirect',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.Eager,\n template: '<p>Processing authentication...</p>',\n})\nexport class AuthenticationSSORedirectComponent implements OnInit {\n ngOnInit(): void {\n broadcastResponseToMainFrame().catch((error: Error) => {\n console.error('Error broadcasting response to main frame:', error);\n });\n }\n}\n","import { CommonModule } from '@angular/common';\r\nimport { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core';\r\n\r\nimport { AuthenticationSSOServiceOptions } from './model/authentication-sso-service-options';\r\nimport { AuthenticationSSOServiceOptionsToken } from './model/authentication-sso-service-options-token';\r\nimport { AuthenticationSSORedirectComponent } from './components/redirect/authentication-sso-redirect.component';\r\n\r\n@NgModule({\r\n declarations: [],\r\n imports: [\r\n CommonModule,\r\n AuthenticationSSORedirectComponent\r\n ],\r\n exports: [\r\n AuthenticationSSORedirectComponent\r\n ]\r\n})\r\nexport class AuthenticationSSOModule {\r\n static forRoot(options: AuthenticationSSOServiceOptions): ModuleWithProviders<AuthenticationSSOModule> {\r\n return {\r\n ngModule: AuthenticationSSOModule,\r\n providers: [\r\n {\r\n provide: AuthenticationSSOServiceOptionsToken,\r\n useValue: options\r\n }\r\n ]\r\n };\r\n }\r\n\r\n constructor(@Optional() @SkipSelf() parentModule: AuthenticationSSOModule) {\r\n if (parentModule) {\r\n throw new Error(\r\n 'AuthenticationSSOModule is already loaded. Import it in the AppModule only');\r\n }\r\n }\r\n}\r\n","import { inject } from '@angular/core';\r\nimport { CanActivateFn, Router } from '@angular/router';\r\nimport { map, take } from 'rxjs/operators';\r\nimport { AuthenticationSSOService } from '../authentication-sso.api';\r\n\r\nexport const authenticationSSOGuard: CanActivateFn = (_route, _state) => {\r\n const authenticationService = inject(AuthenticationSSOService);\r\n const router = inject(Router);\r\n\r\n // if the user is already authenticated, allow access to the route\r\n if (authenticationService.authenticated) {\r\n return true;\r\n }\r\n\r\n if (authenticationService.tokenExists()) {\r\n // we're doing this because we could've opened a new tab and the user is already logged in, so we need to check for an existing token\r\n authenticationService.checkForExistingToken();\r\n\r\n return authenticationService.authenticatedChanged.pipe(\r\n take(1),\r\n map(() => {\r\n if (!authenticationService.authenticated) {\r\n router.navigate(['']);\r\n return false;\r\n }\r\n\r\n return true;\r\n })\r\n );\r\n }\r\n else {\r\n router.navigate(['']);\r\n return false;\r\n }\r\n};\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './authentication-sso.api';\n"],"names":[],"mappings":"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"}
|