quang 19.0.19-2
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/README.md +25 -0
- package/auth/README.md +160 -0
- package/auth/auth-providers.d.ts +39 -0
- package/auth/auth.service.d.ts +52 -0
- package/auth/directives/has-at-least-one-role.directive.d.ts +26 -0
- package/auth/directives/has-every-role.directive.d.ts +26 -0
- package/auth/directives/is-authenticated.directive.d.ts +14 -0
- package/auth/directives/is-not-authenticated.directive.d.ts +14 -0
- package/auth/guards/index.d.ts +2 -0
- package/auth/guards/is-allowed.guard.d.ts +2 -0
- package/auth/guards/is-authenticated.guard.d.ts +2 -0
- package/auth/index.d.ts +9 -0
- package/auth/logout-on-error.interceptor.d.ts +9 -0
- package/auth/mobile/index.d.ts +1 -0
- package/auth/mobile/mobile-auth-feature.d.ts +2 -0
- package/auth/token-storage/index.d.ts +3 -0
- package/auth/token-storage/local-storage-feature.d.ts +2 -0
- package/auth/token-storage/memory-storage-feature.d.ts +12 -0
- package/auth/token-storage/session-storage-feature.d.ts +2 -0
- package/components/autocomplete/autocomplete.component.d.ts +43 -0
- package/components/autocomplete/index.d.ts +1 -0
- package/components/checkbox/checkbox.component.d.ts +11 -0
- package/components/checkbox/index.d.ts +1 -0
- package/components/date/date.component.d.ts +85 -0
- package/components/date/global-date.component.scss +1 -0
- package/components/date/index.d.ts +1 -0
- package/components/input/index.d.ts +1 -0
- package/components/input/input.component.d.ts +15 -0
- package/components/paginator/index.d.ts +5 -0
- package/components/paginator/paginator-language.service.d.ts +10 -0
- package/components/paginator/paginator.component.d.ts +30 -0
- package/components/paginator/paginator.module.d.ts +7 -0
- package/components/paginator/paginator.service.d.ts +6 -0
- package/components/paginator/paginatorIntl.d.ts +12 -0
- package/components/select/index.d.ts +1 -0
- package/components/select/select.component.d.ts +29 -0
- package/components/shared/ErrorData.d.ts +4 -0
- package/components/shared/index.d.ts +4 -0
- package/components/shared/makeId.d.ts +1 -0
- package/components/shared/option-list/option-list.component.d.ts +50 -0
- package/components/shared/quang-base-component.directive.d.ts +50 -0
- package/components/table/index.d.ts +1 -0
- package/components/table/table.component.d.ts +66 -0
- package/components/wysiwyg/global-wysiswyg.component.scss +1 -0
- package/components/wysiwyg/index.d.ts +1 -0
- package/components/wysiwyg/wysiwyg.component.d.ts +46 -0
- package/device/index.d.ts +1 -0
- package/device/resize-observable.service.d.ts +11 -0
- package/fesm2022/quang-auth-mobile.mjs +48 -0
- package/fesm2022/quang-auth-mobile.mjs.map +1 -0
- package/fesm2022/quang-auth.mjs +473 -0
- package/fesm2022/quang-auth.mjs.map +1 -0
- package/fesm2022/quang-components-autocomplete.mjs +196 -0
- package/fesm2022/quang-components-autocomplete.mjs.map +1 -0
- package/fesm2022/quang-components-checkbox.mjs +53 -0
- package/fesm2022/quang-components-checkbox.mjs.map +1 -0
- package/fesm2022/quang-components-date.mjs +392 -0
- package/fesm2022/quang-components-date.mjs.map +1 -0
- package/fesm2022/quang-components-input.mjs +54 -0
- package/fesm2022/quang-components-input.mjs.map +1 -0
- package/fesm2022/quang-components-paginator.mjs +157 -0
- package/fesm2022/quang-components-paginator.mjs.map +1 -0
- package/fesm2022/quang-components-select.mjs +123 -0
- package/fesm2022/quang-components-select.mjs.map +1 -0
- package/fesm2022/quang-components-shared.mjs +386 -0
- package/fesm2022/quang-components-shared.mjs.map +1 -0
- package/fesm2022/quang-components-table.mjs +162 -0
- package/fesm2022/quang-components-table.mjs.map +1 -0
- package/fesm2022/quang-components-wysiwyg.mjs +230 -0
- package/fesm2022/quang-components-wysiwyg.mjs.map +1 -0
- package/fesm2022/quang-device.mjs +42 -0
- package/fesm2022/quang-device.mjs.map +1 -0
- package/fesm2022/quang-forms.mjs +188 -0
- package/fesm2022/quang-forms.mjs.map +1 -0
- package/fesm2022/quang-loader.mjs +116 -0
- package/fesm2022/quang-loader.mjs.map +1 -0
- package/fesm2022/quang-overlay-modal.mjs +118 -0
- package/fesm2022/quang-overlay-modal.mjs.map +1 -0
- package/fesm2022/quang-overlay-popover.mjs +70 -0
- package/fesm2022/quang-overlay-popover.mjs.map +1 -0
- package/fesm2022/quang-overlay-shared.mjs +359 -0
- package/fesm2022/quang-overlay-shared.mjs.map +1 -0
- package/fesm2022/quang-overlay-toast.mjs +105 -0
- package/fesm2022/quang-overlay-toast.mjs.map +1 -0
- package/fesm2022/quang-overlay-tooltip.mjs +56 -0
- package/fesm2022/quang-overlay-tooltip.mjs.map +1 -0
- package/fesm2022/quang-shared.mjs +29 -0
- package/fesm2022/quang-shared.mjs.map +1 -0
- package/fesm2022/quang-translation.mjs +119 -0
- package/fesm2022/quang-translation.mjs.map +1 -0
- package/fesm2022/quang.mjs +23 -0
- package/fesm2022/quang.mjs.map +1 -0
- package/forms/README.md +6 -0
- package/forms/form-group-model.d.ts +18 -0
- package/forms/index.d.ts +2 -0
- package/forms/validators.d.ts +43 -0
- package/index.d.ts +30 -0
- package/loader/README.md +14 -0
- package/loader/index.d.ts +4 -0
- package/loader/loader-providers.d.ts +23 -0
- package/loader/loader.component.d.ts +23 -0
- package/loader/loader.interceptor.d.ts +10 -0
- package/loader/loader.service.d.ts +9 -0
- package/overlay/modal/index.d.ts +1 -0
- package/overlay/modal/modal.component.d.ts +29 -0
- package/overlay/popover/index.d.ts +1 -0
- package/overlay/popover/popover.component.d.ts +13 -0
- package/overlay/popover/popover.directive.d.ts +11 -0
- package/overlay/shared/CustomViewportRuler.d.ts +63 -0
- package/overlay/shared/index.d.ts +3 -0
- package/overlay/shared/quang-base-overlay.component.d.ts +9 -0
- package/overlay/shared/quang-base-overlay.directive.d.ts +44 -0
- package/overlay/toast/index.d.ts +2 -0
- package/overlay/toast/toast.component.d.ts +13 -0
- package/overlay/toast/toast.service.d.ts +27 -0
- package/overlay/tooltip/index.d.ts +2 -0
- package/overlay/tooltip/tooltip.component.d.ts +11 -0
- package/overlay/tooltip/tooltip.directive.d.ts +11 -0
- package/package.json +146 -0
- package/shared/index.d.ts +1 -0
- package/shared/intercept-utils.d.ts +13 -0
- package/translation/README.md +21 -0
- package/translation/index.d.ts +4 -0
- package/translation/translation-loader.service.d.ts +10 -0
- package/translation/translation-providers.d.ts +28 -0
- package/translation/translation.service.d.ts +15 -0
- package/translation/translations.tokens.d.ts +5 -0
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { InjectionToken, makeEnvironmentProviders, inject, computed, Injectable, provideAppInitializer, input, ViewContainerRef, TemplateRef, ChangeDetectorRef, effect, Directive } from '@angular/core';
|
|
3
|
+
import { OAuthService, OAuthErrorEvent, provideOAuthClient, OAuthStorage } from 'angular-oauth2-oidc';
|
|
4
|
+
import { QUANG_LOGGING_BEHAVIOR, quangFeature } from 'quang';
|
|
5
|
+
import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
|
|
6
|
+
import { signalState, patchState } from '@ngrx/signals';
|
|
7
|
+
import { firstValueFrom, filter, retry, catchError, from, tap, switchMap, throwError } from 'rxjs';
|
|
8
|
+
import { getExcludedUrlsByMethod, isHttpMethod } from 'quang/shared';
|
|
9
|
+
|
|
10
|
+
const AUTH_CONFIG = new InjectionToken('AUTH_CONFIG');
|
|
11
|
+
function provideQuangAuthConfig(authConfig) {
|
|
12
|
+
return makeEnvironmentProviders([{ provide: AUTH_CONFIG, useValue: authConfig }]);
|
|
13
|
+
}
|
|
14
|
+
const OPEN_URI = new InjectionToken('OPEN_URI');
|
|
15
|
+
function provideOpenURI(openURI) {
|
|
16
|
+
return makeEnvironmentProviders([{ provide: OPEN_URI, deps: [], useFactory: openURI }]);
|
|
17
|
+
}
|
|
18
|
+
const initialState = {
|
|
19
|
+
loginStatus: {
|
|
20
|
+
checked: false,
|
|
21
|
+
authenticationError: false,
|
|
22
|
+
},
|
|
23
|
+
tokenStatus: {
|
|
24
|
+
accessToken: null,
|
|
25
|
+
accessTokenExpiresAt: null,
|
|
26
|
+
idToken: null,
|
|
27
|
+
idTokenExpiresAt: null,
|
|
28
|
+
refreshToken: null,
|
|
29
|
+
},
|
|
30
|
+
roles: new Set(),
|
|
31
|
+
user: null,
|
|
32
|
+
};
|
|
33
|
+
// Subset of situations from https://openid.net/specs/openid-connect-core-1_0.html#AuthError
|
|
34
|
+
// Only the ones where it's reasonably sure that sending the user to the IdServer will help.
|
|
35
|
+
const errorResponsesRequiringUserInteraction = [
|
|
36
|
+
'interaction_required',
|
|
37
|
+
'login_required',
|
|
38
|
+
'account_selection_required',
|
|
39
|
+
'consent_required',
|
|
40
|
+
];
|
|
41
|
+
class QuangAuthService {
|
|
42
|
+
constructor() {
|
|
43
|
+
this.logLevel = inject(QUANG_LOGGING_BEHAVIOR, { optional: true });
|
|
44
|
+
this.oAuthService = inject(OAuthService, { optional: true });
|
|
45
|
+
this.state = signalState(initialState);
|
|
46
|
+
this.loginChecked = this.state.loginStatus.checked;
|
|
47
|
+
this.isAuthenticated = computed(() => !!this.state.tokenStatus.accessToken());
|
|
48
|
+
this.authenticationError = this.state.loginStatus.authenticationError;
|
|
49
|
+
this.tokenStatus = this.state.tokenStatus;
|
|
50
|
+
this.roles = this.state.roles;
|
|
51
|
+
this.user = this.state.user;
|
|
52
|
+
const authConfig = inject(AUTH_CONFIG);
|
|
53
|
+
if (!authConfig)
|
|
54
|
+
throw new Error('Missing auth config');
|
|
55
|
+
const openUri = inject(OPEN_URI, { optional: true });
|
|
56
|
+
if (openUri)
|
|
57
|
+
authConfig.openUri = openUri;
|
|
58
|
+
this.config = authConfig;
|
|
59
|
+
this.oAuthService?.events.pipe(takeUntilDestroyed()).subscribe((event) => {
|
|
60
|
+
if (this.logLevel === 'verbose')
|
|
61
|
+
console.debug('Auth service event', event);
|
|
62
|
+
if (event instanceof OAuthErrorEvent && this.loginChecked())
|
|
63
|
+
this.loginError();
|
|
64
|
+
if (event.type === 'token_received')
|
|
65
|
+
this.setTokens();
|
|
66
|
+
});
|
|
67
|
+
this.oAuthService?.configure(this.config);
|
|
68
|
+
}
|
|
69
|
+
async init() {
|
|
70
|
+
this.oAuthService?.setupAutomaticSilentRefresh();
|
|
71
|
+
await this.oAuthService?.loadDiscoveryDocumentAndTryLogin();
|
|
72
|
+
await this.checkForAuthentication();
|
|
73
|
+
if (this.config.autoLogin && !this.isAuthenticated())
|
|
74
|
+
this.login();
|
|
75
|
+
}
|
|
76
|
+
async checkForAuthentication(forceRefresh = false) {
|
|
77
|
+
let hasValidToken = this.oAuthService?.hasValidAccessToken();
|
|
78
|
+
try {
|
|
79
|
+
if (forceRefresh)
|
|
80
|
+
hasValidToken = await this.refreshAuth();
|
|
81
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
const reason = error?.reason;
|
|
85
|
+
if (this.config.autoLogin && reason && errorResponsesRequiringUserInteraction.includes(reason))
|
|
86
|
+
this.login();
|
|
87
|
+
hasValidToken = false;
|
|
88
|
+
}
|
|
89
|
+
this.setTokens();
|
|
90
|
+
patchState(this.state, {
|
|
91
|
+
loginStatus: {
|
|
92
|
+
...this.state().loginStatus,
|
|
93
|
+
checked: true,
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
if (hasValidToken && this.config.getUserProfileOnLoginSuccess)
|
|
97
|
+
await this.getUserProfile();
|
|
98
|
+
return hasValidToken;
|
|
99
|
+
}
|
|
100
|
+
async refreshAuth() {
|
|
101
|
+
if (this.config.responseType === 'code')
|
|
102
|
+
await this.oAuthService?.refreshToken();
|
|
103
|
+
else
|
|
104
|
+
await this.oAuthService?.silentRefresh();
|
|
105
|
+
return this.oAuthService?.hasValidAccessToken();
|
|
106
|
+
}
|
|
107
|
+
login() {
|
|
108
|
+
this.oAuthService?.initLoginFlow();
|
|
109
|
+
}
|
|
110
|
+
async logout() {
|
|
111
|
+
if (!this.isAuthenticated())
|
|
112
|
+
return;
|
|
113
|
+
if (this.config.revokeTokensOnLogout)
|
|
114
|
+
await this.oAuthService?.revokeTokenAndLogout();
|
|
115
|
+
else
|
|
116
|
+
this.oAuthService?.logOut();
|
|
117
|
+
patchState(this.state, { ...initialState });
|
|
118
|
+
}
|
|
119
|
+
loginError() {
|
|
120
|
+
patchState(this.state, {
|
|
121
|
+
loginStatus: {
|
|
122
|
+
...this.state().loginStatus,
|
|
123
|
+
authenticationError: true,
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
this.logout();
|
|
127
|
+
}
|
|
128
|
+
async getUserProfile() {
|
|
129
|
+
const user = await this.oAuthService?.loadUserProfile();
|
|
130
|
+
if (user)
|
|
131
|
+
patchState(this.state, { user });
|
|
132
|
+
}
|
|
133
|
+
setTokens() {
|
|
134
|
+
const tokenStatus = {
|
|
135
|
+
accessToken: this.oAuthService?.getAccessToken() ?? null,
|
|
136
|
+
accessTokenExpiresAt: this.oAuthService?.getAccessTokenExpiration() ?? null,
|
|
137
|
+
idToken: this.oAuthService?.getIdToken() ?? null,
|
|
138
|
+
idTokenExpiresAt: this.oAuthService?.getIdTokenExpiration() ?? null,
|
|
139
|
+
refreshToken: this.oAuthService?.getRefreshToken() ?? null,
|
|
140
|
+
};
|
|
141
|
+
if (this.logLevel === 'verbose') {
|
|
142
|
+
const now = new Date();
|
|
143
|
+
const accessTokenDate = new Date(tokenStatus.accessTokenExpiresAt ?? '');
|
|
144
|
+
const idTokenDate = new Date(tokenStatus.idTokenExpiresAt ?? '');
|
|
145
|
+
console.table(tokenStatus);
|
|
146
|
+
console.debug(`Id token expires at ${idTokenDate} in ${Math.abs(idTokenDate.valueOf() - now.valueOf()) / 1000 / 60} minutes`);
|
|
147
|
+
console.debug(`Access token expires at ${accessTokenDate} in ${Math.abs(accessTokenDate.valueOf() - now.valueOf()) / 1000 / 60} minutes`);
|
|
148
|
+
}
|
|
149
|
+
patchState(this.state, {
|
|
150
|
+
tokenStatus,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
async waitForLoginCheck() {
|
|
154
|
+
await firstValueFrom(toObservable(this.loginChecked).pipe(filter((checked) => checked)));
|
|
155
|
+
}
|
|
156
|
+
async getAuthResult() {
|
|
157
|
+
await this.waitForLoginCheck();
|
|
158
|
+
return this.isAuthenticated();
|
|
159
|
+
}
|
|
160
|
+
addRoles(rolesToAdd) {
|
|
161
|
+
patchState(this.state, { roles: new Set([...this.state.roles().values(), ...rolesToAdd]) });
|
|
162
|
+
}
|
|
163
|
+
removeRoles(rolesToRemove) {
|
|
164
|
+
const newRoles = new Set(this.roles().values());
|
|
165
|
+
for (const roleToRemove of rolesToRemove) {
|
|
166
|
+
newRoles.delete(roleToRemove);
|
|
167
|
+
}
|
|
168
|
+
patchState(this.state, { roles: newRoles });
|
|
169
|
+
}
|
|
170
|
+
hasEveryRole(roles) {
|
|
171
|
+
return roles.every((role) => this.roles().has(role));
|
|
172
|
+
}
|
|
173
|
+
hasAtLeastOneRole(roles) {
|
|
174
|
+
return roles.some((role) => this.roles().has(role));
|
|
175
|
+
}
|
|
176
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: QuangAuthService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
177
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: QuangAuthService, providedIn: 'root' }); }
|
|
178
|
+
}
|
|
179
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: QuangAuthService, decorators: [{
|
|
180
|
+
type: Injectable,
|
|
181
|
+
args: [{
|
|
182
|
+
providedIn: 'root',
|
|
183
|
+
}]
|
|
184
|
+
}], ctorParameters: () => [] });
|
|
185
|
+
|
|
186
|
+
function initializeAuthService(authService) {
|
|
187
|
+
return () => authService.init();
|
|
188
|
+
}
|
|
189
|
+
function provideAuth(authConfig, ...features) {
|
|
190
|
+
return makeEnvironmentProviders([
|
|
191
|
+
provideQuangAuthConfig(authConfig),
|
|
192
|
+
provideOAuthClient({
|
|
193
|
+
resourceServer: {
|
|
194
|
+
sendAccessToken: authConfig?.sendAccessToken ?? true,
|
|
195
|
+
allowedUrls: authConfig?.urlsToSendToken ?? [],
|
|
196
|
+
},
|
|
197
|
+
}),
|
|
198
|
+
...features.map((feature) => feature.ɵproviders),
|
|
199
|
+
provideAppInitializer(() => {
|
|
200
|
+
const initializerFn = initializeAuthService(inject(QuangAuthService));
|
|
201
|
+
return initializerFn();
|
|
202
|
+
}),
|
|
203
|
+
]);
|
|
204
|
+
}
|
|
205
|
+
function withAuth(authConfig, ...features) {
|
|
206
|
+
return quangFeature(2 /* QuangFeatureKind.LoaderFeature */, [provideAuth(authConfig, ...features)]);
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Helper function to create an object that represents a QuangAuth feature.
|
|
210
|
+
*/
|
|
211
|
+
function quangAuthFeature(kind, providers) {
|
|
212
|
+
return { ɵkind: kind, ɵproviders: providers };
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* This directive conditionally renders the associated template if the authenticated user
|
|
217
|
+
* has at least one of the specified roles. By using the `QuangAuthService.hasAtLeastOneRole()` method it checks the user's roles against
|
|
218
|
+
* the required roles provided through the `quangHasAtLeastOneRole` directive.
|
|
219
|
+
*
|
|
220
|
+
* @example
|
|
221
|
+
* <div *quangHasAtLeastOneRole="['admin', 'editor']">
|
|
222
|
+
* This content will only be visible to users with 'admin' or 'editor' roles.
|
|
223
|
+
* </div>
|
|
224
|
+
*/
|
|
225
|
+
class QuangHasAtLeastOneRoleDirective {
|
|
226
|
+
constructor() {
|
|
227
|
+
this.logLevel = inject(QUANG_LOGGING_BEHAVIOR, { optional: true });
|
|
228
|
+
this.targetRoles = input.required({ alias: 'quangHasAtLeastOneRole' });
|
|
229
|
+
this.viewContainerRef = inject(ViewContainerRef);
|
|
230
|
+
this.embeddedViewRef = null;
|
|
231
|
+
this.templateRef = inject(TemplateRef);
|
|
232
|
+
this.authService = inject(QuangAuthService);
|
|
233
|
+
this.takeUntilDestroyed = takeUntilDestroyed();
|
|
234
|
+
this.changeDetectorRef = inject(ChangeDetectorRef);
|
|
235
|
+
this.hideViewIfNotAllowed = effect(() => {
|
|
236
|
+
if (this.logLevel === 'verbose')
|
|
237
|
+
console.debug({ userRoles: this.authService.roles(), rolesToCheck: this.targetRoles() });
|
|
238
|
+
const isAllowed = this.authService.hasAtLeastOneRole(this.targetRoles());
|
|
239
|
+
if (isAllowed) {
|
|
240
|
+
if (!this.embeddedViewRef)
|
|
241
|
+
this.embeddedViewRef = this.viewContainerRef.createEmbeddedView(this.templateRef);
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
this.viewContainerRef.clear();
|
|
245
|
+
this.embeddedViewRef = null;
|
|
246
|
+
}
|
|
247
|
+
this.changeDetectorRef.markForCheck();
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: QuangHasAtLeastOneRoleDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
251
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.5", type: QuangHasAtLeastOneRoleDirective, isStandalone: true, selector: "[quangHasAtLeastOneRole]", inputs: { targetRoles: { classPropertyName: "targetRoles", publicName: "quangHasAtLeastOneRole", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 }); }
|
|
252
|
+
}
|
|
253
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: QuangHasAtLeastOneRoleDirective, decorators: [{
|
|
254
|
+
type: Directive,
|
|
255
|
+
args: [{
|
|
256
|
+
selector: '[quangHasAtLeastOneRole]',
|
|
257
|
+
}]
|
|
258
|
+
}] });
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* This directive conditionally renders the associated template if the authenticated user
|
|
262
|
+
* has every of the specified roles. By using the `QuangAuthService.hasEveryRole()` method it checks the user's roles against
|
|
263
|
+
* the required roles provided through the `quangHasEveryRole` required input.
|
|
264
|
+
*
|
|
265
|
+
* @example
|
|
266
|
+
* <div *quangHasEveryRole="['admin', 'editor']">
|
|
267
|
+
* This content will only be visible to users with 'admin' and 'editor' roles.
|
|
268
|
+
* </div>
|
|
269
|
+
*/
|
|
270
|
+
class QuangHasEveryRoleDirective {
|
|
271
|
+
constructor() {
|
|
272
|
+
this.logLevel = inject(QUANG_LOGGING_BEHAVIOR, { optional: true });
|
|
273
|
+
this.targetRoles = input.required({ alias: 'quangHasEveryRole' });
|
|
274
|
+
this.viewContainerRef = inject(ViewContainerRef);
|
|
275
|
+
this.embeddedViewRef = null;
|
|
276
|
+
this.templateRef = inject(TemplateRef);
|
|
277
|
+
this.authService = inject(QuangAuthService);
|
|
278
|
+
this.takeUntilDestroyed = takeUntilDestroyed();
|
|
279
|
+
this.changeDetectorRef = inject(ChangeDetectorRef);
|
|
280
|
+
this.hideViewIfNotAllowed = effect(() => {
|
|
281
|
+
if (this.logLevel === 'verbose')
|
|
282
|
+
console.debug({ userRoles: this.authService.roles(), rolesToCheck: this.targetRoles() });
|
|
283
|
+
const isAllowed = this.authService.hasEveryRole(this.targetRoles());
|
|
284
|
+
if (isAllowed) {
|
|
285
|
+
if (!this.embeddedViewRef)
|
|
286
|
+
this.embeddedViewRef = this.viewContainerRef.createEmbeddedView(this.templateRef);
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
this.viewContainerRef.clear();
|
|
290
|
+
this.embeddedViewRef = null;
|
|
291
|
+
}
|
|
292
|
+
this.changeDetectorRef.markForCheck();
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: QuangHasEveryRoleDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
296
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.5", type: QuangHasEveryRoleDirective, isStandalone: true, selector: "[quangHasEveryRole]", inputs: { targetRoles: { classPropertyName: "targetRoles", publicName: "quangHasEveryRole", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 }); }
|
|
297
|
+
}
|
|
298
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: QuangHasEveryRoleDirective, decorators: [{
|
|
299
|
+
type: Directive,
|
|
300
|
+
args: [{
|
|
301
|
+
selector: '[quangHasEveryRole]',
|
|
302
|
+
}]
|
|
303
|
+
}] });
|
|
304
|
+
|
|
305
|
+
class QuangIsAuthenticatedDirective {
|
|
306
|
+
constructor() {
|
|
307
|
+
this.viewContainerRef = inject(ViewContainerRef);
|
|
308
|
+
this.templateRef = inject(TemplateRef);
|
|
309
|
+
this.embeddedViewRef = null;
|
|
310
|
+
this.authService = inject(QuangAuthService);
|
|
311
|
+
this.takeUntilDestroyed = takeUntilDestroyed();
|
|
312
|
+
this.changeDetectorRef = inject(ChangeDetectorRef);
|
|
313
|
+
this.hideViewIfNotAuthenticated = effect(() => {
|
|
314
|
+
if (this.authService.isAuthenticated()) {
|
|
315
|
+
if (!this.embeddedViewRef)
|
|
316
|
+
this.viewContainerRef.createEmbeddedView(this.templateRef);
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
this.viewContainerRef.clear();
|
|
320
|
+
this.embeddedViewRef = null;
|
|
321
|
+
}
|
|
322
|
+
this.changeDetectorRef.markForCheck();
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: QuangIsAuthenticatedDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
326
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.5", type: QuangIsAuthenticatedDirective, isStandalone: true, selector: "[quangIsAuthenticated]", ngImport: i0 }); }
|
|
327
|
+
}
|
|
328
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: QuangIsAuthenticatedDirective, decorators: [{
|
|
329
|
+
type: Directive,
|
|
330
|
+
args: [{
|
|
331
|
+
selector: '[quangIsAuthenticated]',
|
|
332
|
+
}]
|
|
333
|
+
}] });
|
|
334
|
+
|
|
335
|
+
class QuangIsNotAuthenticatedDirective {
|
|
336
|
+
constructor() {
|
|
337
|
+
this.viewContainerRef = inject(ViewContainerRef);
|
|
338
|
+
this.templateRef = inject(TemplateRef);
|
|
339
|
+
this.embeddedViewRef = null;
|
|
340
|
+
this.authService = inject(QuangAuthService);
|
|
341
|
+
this.takeUntilDestroyed = takeUntilDestroyed();
|
|
342
|
+
this.changeDetectorRef = inject(ChangeDetectorRef);
|
|
343
|
+
this.showViewIfNotAuthenticated = effect(() => {
|
|
344
|
+
if (this.authService.isAuthenticated()) {
|
|
345
|
+
this.viewContainerRef.clear();
|
|
346
|
+
this.embeddedViewRef = null;
|
|
347
|
+
}
|
|
348
|
+
else if (!this.embeddedViewRef) {
|
|
349
|
+
this.embeddedViewRef = this.viewContainerRef.createEmbeddedView(this.templateRef);
|
|
350
|
+
}
|
|
351
|
+
this.changeDetectorRef.markForCheck();
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: QuangIsNotAuthenticatedDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
355
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.5", type: QuangIsNotAuthenticatedDirective, isStandalone: true, selector: "[quangIsNotAuthenticated]", ngImport: i0 }); }
|
|
356
|
+
}
|
|
357
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: QuangIsNotAuthenticatedDirective, decorators: [{
|
|
358
|
+
type: Directive,
|
|
359
|
+
args: [{
|
|
360
|
+
selector: '[quangIsNotAuthenticated]',
|
|
361
|
+
}]
|
|
362
|
+
}] });
|
|
363
|
+
|
|
364
|
+
const quangIsAllowedGuardFactory = (roles, behavior) => async () => {
|
|
365
|
+
const authService = inject(QuangAuthService);
|
|
366
|
+
const isAuthenticated = await authService.getAuthResult();
|
|
367
|
+
if (!isAuthenticated)
|
|
368
|
+
return false;
|
|
369
|
+
const isAllowedFunction = behavior === 'every' ? authService.hasEveryRole : authService.hasAtLeastOneRole;
|
|
370
|
+
return isAllowedFunction.call(authService, roles);
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
const quangIsAuthenticatedGuard = async () => {
|
|
374
|
+
const authService = inject(QuangAuthService);
|
|
375
|
+
return authService.getAuthResult();
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
const LOGOUT_RETRIES = new InjectionToken('LOGOUT_RETRIES');
|
|
379
|
+
const LOGOUT_STATUSES = new InjectionToken('LOGOUT_STATUSES');
|
|
380
|
+
const LOGOUT_EXCLUDED_URLS = new InjectionToken('LOGOUT_EXCLUDED_URLS');
|
|
381
|
+
const logoutOnErrorInterceptor = (request, next) => {
|
|
382
|
+
const quangAuthService = inject(QuangAuthService);
|
|
383
|
+
const logoutStatuses = inject(LOGOUT_STATUSES, { optional: true }) ?? [401];
|
|
384
|
+
const excludedUrlsByMethod = getExcludedUrlsByMethod(inject(LOGOUT_EXCLUDED_URLS, { optional: true }) ?? []);
|
|
385
|
+
const retries = inject(LOGOUT_RETRIES, { optional: true }) ?? 4;
|
|
386
|
+
if (!isHttpMethod(request.method)) {
|
|
387
|
+
return next(request);
|
|
388
|
+
}
|
|
389
|
+
if (Array.from(excludedUrlsByMethod.get(request.method) ?? []).some((excludedUrl) => request.url.match(excludedUrl.replace(/\//g, '\\/')))) {
|
|
390
|
+
return next(request);
|
|
391
|
+
}
|
|
392
|
+
return next(request).pipe(retry({ count: retries, delay: 300 }), catchError((error) => {
|
|
393
|
+
if (logoutStatuses.includes(error?.status))
|
|
394
|
+
return from(quangAuthService.checkForAuthentication(true)).pipe(tap((isAuthenticated) => {
|
|
395
|
+
if (!isAuthenticated)
|
|
396
|
+
quangAuthService.logout();
|
|
397
|
+
}), switchMap(() => throwError(() => error)));
|
|
398
|
+
return throwError(() => error);
|
|
399
|
+
}), retry({ count: 1, delay: 500 }));
|
|
400
|
+
};
|
|
401
|
+
function withLogoutOnError(excludedUrls = [], statuses = [401], retries = 4) {
|
|
402
|
+
const providers = [
|
|
403
|
+
{
|
|
404
|
+
provide: LOGOUT_STATUSES,
|
|
405
|
+
useValue: statuses,
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
provide: LOGOUT_EXCLUDED_URLS,
|
|
409
|
+
useValue: excludedUrls,
|
|
410
|
+
},
|
|
411
|
+
{
|
|
412
|
+
provide: LOGOUT_RETRIES,
|
|
413
|
+
useValue: retries,
|
|
414
|
+
},
|
|
415
|
+
];
|
|
416
|
+
return quangAuthFeature(4 /* QuangAuthFeatureKind.LogoutOnErrorFeature */, providers);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
function withLocalStorage() {
|
|
420
|
+
const providers = [
|
|
421
|
+
{
|
|
422
|
+
provide: OAuthStorage,
|
|
423
|
+
useValue: localStorage,
|
|
424
|
+
},
|
|
425
|
+
];
|
|
426
|
+
return quangAuthFeature(2 /* QuangAuthFeatureKind.LocalStorageFeature */, providers);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
class MemoryStorage {
|
|
430
|
+
constructor() {
|
|
431
|
+
this.data = new Map();
|
|
432
|
+
}
|
|
433
|
+
getItem(key) {
|
|
434
|
+
return this.data.get(key) ?? '';
|
|
435
|
+
}
|
|
436
|
+
removeItem(key) {
|
|
437
|
+
this.data.delete(key);
|
|
438
|
+
}
|
|
439
|
+
setItem(key, data) {
|
|
440
|
+
this.data.set(key, data);
|
|
441
|
+
}
|
|
442
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: MemoryStorage, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
443
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: MemoryStorage }); }
|
|
444
|
+
}
|
|
445
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.5", ngImport: i0, type: MemoryStorage, decorators: [{
|
|
446
|
+
type: Injectable
|
|
447
|
+
}] });
|
|
448
|
+
function withMemoryStorage() {
|
|
449
|
+
const providers = [
|
|
450
|
+
{
|
|
451
|
+
provide: OAuthStorage,
|
|
452
|
+
useFactory: () => new MemoryStorage(),
|
|
453
|
+
},
|
|
454
|
+
];
|
|
455
|
+
return quangAuthFeature(3 /* QuangAuthFeatureKind.MemoryStorageFeature */, providers);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
function withSessionStorage() {
|
|
459
|
+
const providers = [
|
|
460
|
+
{
|
|
461
|
+
provide: OAuthStorage,
|
|
462
|
+
useValue: sessionStorage,
|
|
463
|
+
},
|
|
464
|
+
];
|
|
465
|
+
return quangAuthFeature(1 /* QuangAuthFeatureKind.SessionStorageFeature */, providers);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Generated bundle index. Do not edit.
|
|
470
|
+
*/
|
|
471
|
+
|
|
472
|
+
export { AUTH_CONFIG, LOGOUT_EXCLUDED_URLS, LOGOUT_RETRIES, LOGOUT_STATUSES, MemoryStorage, OPEN_URI, QuangAuthService, QuangHasAtLeastOneRoleDirective, QuangHasEveryRoleDirective, QuangIsAuthenticatedDirective, QuangIsNotAuthenticatedDirective, logoutOnErrorInterceptor, provideAuth, provideOpenURI, provideQuangAuthConfig, quangAuthFeature, quangIsAllowedGuardFactory, quangIsAuthenticatedGuard, withAuth, withLocalStorage, withLogoutOnError, withMemoryStorage, withSessionStorage };
|
|
473
|
+
//# sourceMappingURL=quang-auth.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quang-auth.mjs","sources":["../../../projects/quang/auth/auth.service.ts","../../../projects/quang/auth/auth-providers.ts","../../../projects/quang/auth/directives/has-at-least-one-role.directive.ts","../../../projects/quang/auth/directives/has-every-role.directive.ts","../../../projects/quang/auth/directives/is-authenticated.directive.ts","../../../projects/quang/auth/directives/is-not-authenticated.directive.ts","../../../projects/quang/auth/guards/is-allowed.guard.ts","../../../projects/quang/auth/guards/is-authenticated.guard.ts","../../../projects/quang/auth/logout-on-error.interceptor.ts","../../../projects/quang/auth/token-storage/local-storage-feature.ts","../../../projects/quang/auth/token-storage/memory-storage-feature.ts","../../../projects/quang/auth/token-storage/session-storage-feature.ts","../../../projects/quang/auth/quang-auth.ts"],"sourcesContent":["import {\n EnvironmentProviders,\n Injectable,\n InjectionToken,\n computed,\n inject,\n makeEnvironmentProviders,\n} from '@angular/core'\nimport { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop'\n\nimport { patchState, signalState } from '@ngrx/signals'\n\nimport { AuthConfig, OAuthErrorEvent, OAuthEvent, OAuthService } from 'angular-oauth2-oidc'\nimport { QUANG_LOGGING_BEHAVIOR } from 'quang'\nimport { filter, firstValueFrom } from 'rxjs'\n\nexport const AUTH_CONFIG = new InjectionToken<QuangAuthConfig | undefined>('AUTH_CONFIG')\n\nexport interface QuangAuthConfig extends AuthConfig {\n autoLogin: boolean\n sendAccessToken: boolean\n urlsToSendToken: string[]\n revokeTokensOnLogout?: boolean\n getUserProfileOnLoginSuccess?: boolean\n useSilentRefresh: boolean\n}\n\nexport function provideQuangAuthConfig(authConfig?: QuangAuthConfig): EnvironmentProviders {\n return makeEnvironmentProviders([{ provide: AUTH_CONFIG, useValue: authConfig }])\n}\n\nexport const OPEN_URI = new InjectionToken<(uri: string) => void | undefined>('OPEN_URI')\n\nexport function provideOpenURI(openURI: (uri: string) => void | undefined): EnvironmentProviders {\n return makeEnvironmentProviders([{ provide: OPEN_URI, deps: [], useFactory: openURI }])\n}\n\ninterface LoginStatus {\n checked: boolean\n authenticationError: boolean\n}\n\ninterface TokenStatus {\n accessToken: string | null\n accessTokenExpiresAt: number | null\n idToken: string | null\n idTokenExpiresAt: number | null\n refreshToken: string | null\n}\n\ninterface AuthState {\n loginStatus: LoginStatus\n tokenStatus: TokenStatus\n roles: Set<string>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n user: Record<string, any> | null\n}\n\nconst initialState: AuthState = {\n loginStatus: {\n checked: false,\n authenticationError: false,\n },\n tokenStatus: {\n accessToken: null,\n accessTokenExpiresAt: null,\n idToken: null,\n idTokenExpiresAt: null,\n refreshToken: null,\n },\n roles: new Set<string>(),\n user: null,\n}\n\n// Subset of situations from https://openid.net/specs/openid-connect-core-1_0.html#AuthError\n// Only the ones where it's reasonably sure that sending the user to the IdServer will help.\nconst errorResponsesRequiringUserInteraction = [\n 'interaction_required',\n 'login_required',\n 'account_selection_required',\n 'consent_required',\n]\n\n@Injectable({\n providedIn: 'root',\n})\nexport class QuangAuthService {\n private config: QuangAuthConfig\n\n logLevel = inject(QUANG_LOGGING_BEHAVIOR, { optional: true })\n\n private oAuthService = inject(OAuthService, { optional: true })\n\n private state = signalState<AuthState>(initialState)\n\n loginChecked = this.state.loginStatus.checked\n\n isAuthenticated = computed(() => !!this.state.tokenStatus.accessToken())\n\n authenticationError = this.state.loginStatus.authenticationError\n\n tokenStatus = this.state.tokenStatus\n\n roles = this.state.roles\n\n user = this.state.user\n\n constructor() {\n const authConfig = inject(AUTH_CONFIG)\n if (!authConfig) throw new Error('Missing auth config')\n\n const openUri = inject(OPEN_URI, { optional: true })\n if (openUri) authConfig.openUri = openUri\n\n this.config = authConfig\n\n this.oAuthService?.events.pipe(takeUntilDestroyed()).subscribe((event: OAuthEvent) => {\n if (this.logLevel === 'verbose') console.debug('Auth service event', event)\n if (event instanceof OAuthErrorEvent && this.loginChecked()) this.loginError()\n if (event.type === 'token_received') this.setTokens()\n })\n this.oAuthService?.configure(this.config)\n }\n\n public async init() {\n this.oAuthService?.setupAutomaticSilentRefresh()\n\n await this.oAuthService?.loadDiscoveryDocumentAndTryLogin()\n\n await this.checkForAuthentication()\n\n if (this.config.autoLogin && !this.isAuthenticated()) this.login()\n }\n\n public async checkForAuthentication(forceRefresh = false) {\n let hasValidToken = this.oAuthService?.hasValidAccessToken()\n\n try {\n if (forceRefresh) hasValidToken = await this.refreshAuth()\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (error: any) {\n const reason = error?.reason\n if (this.config.autoLogin && reason && errorResponsesRequiringUserInteraction.includes(reason)) this.login()\n hasValidToken = false\n }\n\n this.setTokens()\n patchState(this.state, {\n loginStatus: {\n ...this.state().loginStatus,\n checked: true,\n },\n })\n\n if (hasValidToken && this.config.getUserProfileOnLoginSuccess) await this.getUserProfile()\n\n return hasValidToken\n }\n\n private async refreshAuth() {\n if (this.config.responseType === 'code') await this.oAuthService?.refreshToken()\n else await this.oAuthService?.silentRefresh()\n return this.oAuthService?.hasValidAccessToken()\n }\n\n public login() {\n this.oAuthService?.initLoginFlow()\n }\n\n public async logout() {\n if (!this.isAuthenticated()) return\n if (this.config.revokeTokensOnLogout) await this.oAuthService?.revokeTokenAndLogout()\n else this.oAuthService?.logOut()\n patchState(this.state, { ...initialState })\n }\n\n private loginError() {\n patchState(this.state, {\n loginStatus: {\n ...this.state().loginStatus,\n authenticationError: true,\n },\n })\n this.logout()\n }\n\n public async getUserProfile() {\n const user = await this.oAuthService?.loadUserProfile()\n if (user) patchState(this.state, { user })\n }\n\n private setTokens() {\n const tokenStatus = {\n accessToken: this.oAuthService?.getAccessToken() ?? null,\n accessTokenExpiresAt: this.oAuthService?.getAccessTokenExpiration() ?? null,\n idToken: this.oAuthService?.getIdToken() ?? null,\n idTokenExpiresAt: this.oAuthService?.getIdTokenExpiration() ?? null,\n refreshToken: this.oAuthService?.getRefreshToken() ?? null,\n }\n if (this.logLevel === 'verbose') {\n const now = new Date()\n const accessTokenDate = new Date(tokenStatus.accessTokenExpiresAt ?? '')\n const idTokenDate = new Date(tokenStatus.idTokenExpiresAt ?? '')\n console.table(tokenStatus)\n console.debug(\n `Id token expires at ${idTokenDate} in ${Math.abs(idTokenDate.valueOf() - now.valueOf()) / 1000 / 60} minutes`\n )\n console.debug(\n `Access token expires at ${accessTokenDate} in ${Math.abs(accessTokenDate.valueOf() - now.valueOf()) / 1000 / 60} minutes`\n )\n }\n patchState(this.state, {\n tokenStatus,\n })\n }\n\n async waitForLoginCheck(): Promise<void> {\n await firstValueFrom(toObservable(this.loginChecked).pipe(filter((checked) => checked)))\n }\n\n async getAuthResult(): Promise<boolean> {\n await this.waitForLoginCheck()\n return this.isAuthenticated()\n }\n\n addRoles(rolesToAdd: string[]) {\n patchState(this.state, { roles: new Set([...this.state.roles().values(), ...rolesToAdd]) })\n }\n\n removeRoles(rolesToRemove: string[]) {\n const newRoles = new Set(this.roles().values())\n for (const roleToRemove of rolesToRemove) {\n newRoles.delete(roleToRemove)\n }\n patchState(this.state, { roles: newRoles })\n }\n\n hasEveryRole(roles: string[]) {\n return roles.every((role) => this.roles().has(role))\n }\n\n hasAtLeastOneRole(roles: string[]) {\n return roles.some((role) => this.roles().has(role))\n }\n}\n","import { EnvironmentProviders, Provider, inject, makeEnvironmentProviders, provideAppInitializer } from '@angular/core'\n\nimport { provideOAuthClient } from 'angular-oauth2-oidc'\nimport { type QuangFeature, QuangFeatureKind, quangFeature } from 'quang'\n\nimport { type QuangAuthConfig, QuangAuthService, provideQuangAuthConfig } from './auth.service'\n\nfunction initializeAuthService(authService: QuangAuthService) {\n return () => authService.init()\n}\n\nexport function provideAuth(authConfig?: QuangAuthConfig, ...features: QuangAuthFeatures[]): EnvironmentProviders {\n return makeEnvironmentProviders([\n provideQuangAuthConfig(authConfig),\n provideOAuthClient({\n resourceServer: {\n sendAccessToken: authConfig?.sendAccessToken ?? true,\n allowedUrls: authConfig?.urlsToSendToken ?? [],\n },\n }),\n ...features.map((feature) => feature.ɵproviders),\n provideAppInitializer(() => {\n const initializerFn = initializeAuthService(inject(QuangAuthService))\n return initializerFn()\n }),\n ])\n}\n\nexport function withAuth(\n authConfig?: QuangAuthConfig,\n ...features: QuangAuthFeatures[]\n): QuangFeature<QuangFeatureKind.LoaderFeature> {\n return quangFeature(QuangFeatureKind.LoaderFeature, [provideAuth(authConfig, ...features)])\n}\n\n/**\n * Helper type to represent a QuangAuth feature.\n *\n * @publicApi\n */\nexport interface QuangAuthFeature<FeatureKind extends QuangAuthFeatureKind> {\n ɵkind: FeatureKind\n ɵproviders: (Provider | EnvironmentProviders)[]\n}\n\n/**\n * Helper function to create an object that represents a QuangAuth feature.\n */\nexport function quangAuthFeature<FeatureKind extends QuangAuthFeatureKind>(\n kind: FeatureKind,\n providers: (Provider | EnvironmentProviders)[]\n): QuangAuthFeature<FeatureKind> {\n return { ɵkind: kind, ɵproviders: providers }\n}\n\n/**\n * A type alias that represents all QuangAuth features available for use with `provideAuth`.\n * Features can be enabled by adding special functions to the `provideAuth` call.\n * See documentation for each symbol to find corresponding function name. See also `provideAuth`\n * documentation on how to use those functions.\n *\n * @see {@link provideAuth}\n *\n * @publicApi\n */\nexport type QuangAuthFeatures = QuangAuthFeature<QuangAuthFeatureKind>\n\n/**\n * The list of features as an enum to uniquely type each feature.\n */\nexport const enum QuangAuthFeatureKind {\n MobileAuthFeature,\n SessionStorageFeature,\n LocalStorageFeature,\n MemoryStorageFeature,\n LogoutOnErrorFeature,\n}\n","import {\n ChangeDetectorRef,\n Directive,\n EmbeddedViewRef,\n TemplateRef,\n ViewContainerRef,\n effect,\n inject,\n input,\n} from '@angular/core'\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop'\n\nimport { QUANG_LOGGING_BEHAVIOR } from 'quang'\n\nimport { QuangAuthService } from '../auth.service'\n\n/**\n * This directive conditionally renders the associated template if the authenticated user\n * has at least one of the specified roles. By using the `QuangAuthService.hasAtLeastOneRole()` method it checks the user's roles against\n * the required roles provided through the `quangHasAtLeastOneRole` directive.\n *\n * @example\n * <div *quangHasAtLeastOneRole=\"['admin', 'editor']\">\n * This content will only be visible to users with 'admin' or 'editor' roles.\n * </div>\n */\n@Directive({\n selector: '[quangHasAtLeastOneRole]',\n})\nexport class QuangHasAtLeastOneRoleDirective {\n logLevel = inject(QUANG_LOGGING_BEHAVIOR, { optional: true })\n\n targetRoles = input.required<string[]>({ alias: 'quangHasAtLeastOneRole' })\n\n viewContainerRef = inject(ViewContainerRef)\n\n embeddedViewRef: EmbeddedViewRef<unknown> | null = null\n\n templateRef = inject(TemplateRef)\n\n authService = inject(QuangAuthService)\n\n takeUntilDestroyed = takeUntilDestroyed()\n\n changeDetectorRef = inject(ChangeDetectorRef)\n\n hideViewIfNotAllowed = effect(() => {\n if (this.logLevel === 'verbose')\n console.debug({ userRoles: this.authService.roles(), rolesToCheck: this.targetRoles() })\n const isAllowed = this.authService.hasAtLeastOneRole(this.targetRoles())\n if (isAllowed) {\n if (!this.embeddedViewRef) this.embeddedViewRef = this.viewContainerRef.createEmbeddedView(this.templateRef)\n } else {\n this.viewContainerRef.clear()\n this.embeddedViewRef = null\n }\n this.changeDetectorRef.markForCheck()\n })\n}\n","import {\n ChangeDetectorRef,\n Directive,\n EmbeddedViewRef,\n TemplateRef,\n ViewContainerRef,\n effect,\n inject,\n input,\n} from '@angular/core'\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop'\n\nimport { QUANG_LOGGING_BEHAVIOR } from 'quang'\n\nimport { QuangAuthService } from '../auth.service'\n\n/**\n * This directive conditionally renders the associated template if the authenticated user\n * has every of the specified roles. By using the `QuangAuthService.hasEveryRole()` method it checks the user's roles against\n * the required roles provided through the `quangHasEveryRole` required input.\n *\n * @example\n * <div *quangHasEveryRole=\"['admin', 'editor']\">\n * This content will only be visible to users with 'admin' and 'editor' roles.\n * </div>\n */\n@Directive({\n selector: '[quangHasEveryRole]',\n})\nexport class QuangHasEveryRoleDirective {\n logLevel = inject(QUANG_LOGGING_BEHAVIOR, { optional: true })\n\n targetRoles = input.required<string[]>({ alias: 'quangHasEveryRole' })\n\n viewContainerRef = inject(ViewContainerRef)\n\n embeddedViewRef: EmbeddedViewRef<unknown> | null = null\n\n templateRef = inject(TemplateRef)\n\n authService = inject(QuangAuthService)\n\n takeUntilDestroyed = takeUntilDestroyed()\n\n changeDetectorRef = inject(ChangeDetectorRef)\n\n hideViewIfNotAllowed = effect(() => {\n if (this.logLevel === 'verbose')\n console.debug({ userRoles: this.authService.roles(), rolesToCheck: this.targetRoles() })\n const isAllowed = this.authService.hasEveryRole(this.targetRoles())\n if (isAllowed) {\n if (!this.embeddedViewRef) this.embeddedViewRef = this.viewContainerRef.createEmbeddedView(this.templateRef)\n } else {\n this.viewContainerRef.clear()\n this.embeddedViewRef = null\n }\n this.changeDetectorRef.markForCheck()\n })\n}\n","import {\n ChangeDetectorRef,\n Directive,\n EmbeddedViewRef,\n TemplateRef,\n ViewContainerRef,\n effect,\n inject,\n} from '@angular/core'\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop'\n\nimport { QuangAuthService } from '../auth.service'\n\n@Directive({\n selector: '[quangIsAuthenticated]',\n})\nexport class QuangIsAuthenticatedDirective {\n viewContainerRef = inject(ViewContainerRef)\n\n templateRef = inject(TemplateRef)\n\n embeddedViewRef: EmbeddedViewRef<any> | null = null\n\n authService = inject(QuangAuthService)\n\n takeUntilDestroyed = takeUntilDestroyed()\n\n changeDetectorRef = inject(ChangeDetectorRef)\n\n hideViewIfNotAuthenticated = effect(() => {\n if (this.authService.isAuthenticated()) {\n if (!this.embeddedViewRef) this.viewContainerRef.createEmbeddedView(this.templateRef)\n } else {\n this.viewContainerRef.clear()\n this.embeddedViewRef = null\n }\n this.changeDetectorRef.markForCheck()\n })\n}\n","import {\n ChangeDetectorRef,\n Directive,\n EmbeddedViewRef,\n TemplateRef,\n ViewContainerRef,\n effect,\n inject,\n} from '@angular/core'\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop'\n\nimport { QuangAuthService } from '../auth.service'\n\n@Directive({\n selector: '[quangIsNotAuthenticated]',\n})\nexport class QuangIsNotAuthenticatedDirective {\n viewContainerRef = inject(ViewContainerRef)\n\n templateRef = inject(TemplateRef)\n\n embeddedViewRef: EmbeddedViewRef<any> | null = null\n\n authService = inject(QuangAuthService)\n\n takeUntilDestroyed = takeUntilDestroyed()\n\n changeDetectorRef = inject(ChangeDetectorRef)\n\n showViewIfNotAuthenticated = effect(() => {\n if (this.authService.isAuthenticated()) {\n this.viewContainerRef.clear()\n this.embeddedViewRef = null\n } else if (!this.embeddedViewRef) {\n this.embeddedViewRef = this.viewContainerRef.createEmbeddedView(this.templateRef)\n }\n this.changeDetectorRef.markForCheck()\n })\n}\n","import { inject } from '@angular/core'\nimport type { CanActivateFn } from '@angular/router'\n\nimport { QuangAuthService } from '../auth.service'\n\nexport const quangIsAllowedGuardFactory =\n (roles: string[], behavior: 'every' | 'atLeastOne'): CanActivateFn =>\n async () => {\n const authService = inject(QuangAuthService)\n const isAuthenticated = await authService.getAuthResult()\n if (!isAuthenticated) return false\n const isAllowedFunction = behavior === 'every' ? authService.hasEveryRole : authService.hasAtLeastOneRole\n return isAllowedFunction.call(authService, roles)\n }\n","import { inject } from '@angular/core'\nimport type { CanActivateFn } from '@angular/router'\n\nimport { QuangAuthService } from '../auth.service'\n\nexport const quangIsAuthenticatedGuard: CanActivateFn = async () => {\n const authService = inject(QuangAuthService)\n return authService.getAuthResult()\n}\n","import { HttpErrorResponse, HttpInterceptorFn } from '@angular/common/http'\nimport { InjectionToken, Provider, inject } from '@angular/core'\n\nimport { UrlData, getExcludedUrlsByMethod, isHttpMethod } from 'quang/shared'\nimport { catchError, from, retry, switchMap, tap, throwError } from 'rxjs'\n\nimport { QuangAuthService } from './auth.service'\n\nimport { QuangAuthFeature, QuangAuthFeatureKind, quangAuthFeature } from './auth-providers'\n\nexport const LOGOUT_RETRIES = new InjectionToken<number>('LOGOUT_RETRIES')\nexport const LOGOUT_STATUSES = new InjectionToken<number[]>('LOGOUT_STATUSES')\nexport const LOGOUT_EXCLUDED_URLS = new InjectionToken<UrlData[]>('LOGOUT_EXCLUDED_URLS')\n\nexport const logoutOnErrorInterceptor: HttpInterceptorFn = (request, next) => {\n const quangAuthService = inject(QuangAuthService)\n const logoutStatuses = inject(LOGOUT_STATUSES, { optional: true }) ?? [401]\n const excludedUrlsByMethod = getExcludedUrlsByMethod(inject(LOGOUT_EXCLUDED_URLS, { optional: true }) ?? [])\n const retries = inject(LOGOUT_RETRIES, { optional: true }) ?? 4\n\n if (!isHttpMethod(request.method)) {\n return next(request)\n }\n\n if (\n Array.from(excludedUrlsByMethod.get(request.method) ?? []).some((excludedUrl) =>\n request.url.match(excludedUrl.replace(/\\//g, '\\\\/'))\n )\n ) {\n return next(request)\n }\n\n return next(request).pipe(\n retry({ count: retries, delay: 300 }),\n catchError((error: HttpErrorResponse) => {\n if (logoutStatuses.includes(error?.status))\n return from(quangAuthService.checkForAuthentication(true)).pipe(\n tap((isAuthenticated) => {\n if (!isAuthenticated) quangAuthService.logout()\n }),\n switchMap(() => throwError(() => error))\n )\n return throwError(() => error)\n }),\n retry({ count: 1, delay: 500 })\n )\n}\n\nexport function withLogoutOnError(\n excludedUrls: UrlData[] = [],\n statuses = [401],\n retries = 4\n): QuangAuthFeature<QuangAuthFeatureKind.LogoutOnErrorFeature> {\n const providers: Provider[] = [\n {\n provide: LOGOUT_STATUSES,\n useValue: statuses,\n },\n {\n provide: LOGOUT_EXCLUDED_URLS,\n useValue: excludedUrls,\n },\n {\n provide: LOGOUT_RETRIES,\n useValue: retries,\n },\n ]\n return quangAuthFeature(QuangAuthFeatureKind.LogoutOnErrorFeature, providers)\n}\n","import { Provider } from '@angular/core'\n\nimport { OAuthStorage } from 'angular-oauth2-oidc'\n\nimport { QuangAuthFeature, QuangAuthFeatureKind, quangAuthFeature } from '../auth-providers'\n\nexport function withLocalStorage(): QuangAuthFeature<QuangAuthFeatureKind.LocalStorageFeature> {\n const providers: Provider[] = [\n {\n provide: OAuthStorage,\n useValue: localStorage,\n },\n ]\n return quangAuthFeature(QuangAuthFeatureKind.LocalStorageFeature, providers)\n}\n","import { Injectable, Provider } from '@angular/core'\n\nimport { OAuthStorage } from 'angular-oauth2-oidc'\n\nimport { QuangAuthFeature, QuangAuthFeatureKind, quangAuthFeature } from '../auth-providers'\n\n@Injectable()\nexport class MemoryStorage implements OAuthStorage {\n private data = new Map<string, string>()\n\n getItem(key: string): string {\n return this.data.get(key) ?? ''\n }\n\n removeItem(key: string): void {\n this.data.delete(key)\n }\n\n setItem(key: string, data: string): void {\n this.data.set(key, data)\n }\n}\n\nexport function withMemoryStorage(): QuangAuthFeature<QuangAuthFeatureKind.MemoryStorageFeature> {\n const providers: Provider[] = [\n {\n provide: OAuthStorage,\n useFactory: () => new MemoryStorage(),\n },\n ]\n return quangAuthFeature(QuangAuthFeatureKind.MemoryStorageFeature, providers)\n}\n","import { Provider } from '@angular/core'\n\nimport { OAuthStorage } from 'angular-oauth2-oidc'\n\nimport { QuangAuthFeature, QuangAuthFeatureKind, quangAuthFeature } from '../auth-providers'\n\nexport function withSessionStorage(): QuangAuthFeature<QuangAuthFeatureKind.SessionStorageFeature> {\n const providers: Provider[] = [\n {\n provide: OAuthStorage,\n useValue: sessionStorage,\n },\n ]\n return quangAuthFeature(QuangAuthFeatureKind.SessionStorageFeature, providers)\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;;;;;;MAgBa,WAAW,GAAG,IAAI,cAAc,CAA8B,aAAa;AAWlF,SAAU,sBAAsB,CAAC,UAA4B,EAAA;AACjE,IAAA,OAAO,wBAAwB,CAAC,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;AACnF;MAEa,QAAQ,GAAG,IAAI,cAAc,CAAoC,UAAU;AAElF,SAAU,cAAc,CAAC,OAA0C,EAAA;AACvE,IAAA,OAAO,wBAAwB,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC;AACzF;AAuBA,MAAM,YAAY,GAAc;AAC9B,IAAA,WAAW,EAAE;AACX,QAAA,OAAO,EAAE,KAAK;AACd,QAAA,mBAAmB,EAAE,KAAK;AAC3B,KAAA;AACD,IAAA,WAAW,EAAE;AACX,QAAA,WAAW,EAAE,IAAI;AACjB,QAAA,oBAAoB,EAAE,IAAI;AAC1B,QAAA,OAAO,EAAE,IAAI;AACb,QAAA,gBAAgB,EAAE,IAAI;AACtB,QAAA,YAAY,EAAE,IAAI;AACnB,KAAA;IACD,KAAK,EAAE,IAAI,GAAG,EAAU;AACxB,IAAA,IAAI,EAAE,IAAI;CACX;AAED;AACA;AACA,MAAM,sCAAsC,GAAG;IAC7C,sBAAsB;IACtB,gBAAgB;IAChB,4BAA4B;IAC5B,kBAAkB;CACnB;MAKY,gBAAgB,CAAA;AAqB3B,IAAA,WAAA,GAAA;QAlBA,IAAQ,CAAA,QAAA,GAAG,MAAM,CAAC,sBAAsB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QAErD,IAAY,CAAA,YAAA,GAAG,MAAM,CAAC,YAAY,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAEvD,QAAA,IAAA,CAAA,KAAK,GAAG,WAAW,CAAY,YAAY,CAAC;QAEpD,IAAY,CAAA,YAAA,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,OAAO;AAE7C,QAAA,IAAA,CAAA,eAAe,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC;QAExE,IAAmB,CAAA,mBAAA,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,mBAAmB;AAEhE,QAAA,IAAA,CAAA,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW;AAEpC,QAAA,IAAA,CAAA,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK;AAExB,QAAA,IAAA,CAAA,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI;AAGpB,QAAA,MAAM,UAAU,GAAG,MAAM,CAAC,WAAW,CAAC;AACtC,QAAA,IAAI,CAAC,UAAU;AAAE,YAAA,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC;AAEvD,QAAA,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AACpD,QAAA,IAAI,OAAO;AAAE,YAAA,UAAU,CAAC,OAAO,GAAG,OAAO;AAEzC,QAAA,IAAI,CAAC,MAAM,GAAG,UAAU;AAExB,QAAA,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,KAAiB,KAAI;AACnF,YAAA,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS;AAAE,gBAAA,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,KAAK,CAAC;AAC3E,YAAA,IAAI,KAAK,YAAY,eAAe,IAAI,IAAI,CAAC,YAAY,EAAE;gBAAE,IAAI,CAAC,UAAU,EAAE;AAC9E,YAAA,IAAI,KAAK,CAAC,IAAI,KAAK,gBAAgB;gBAAE,IAAI,CAAC,SAAS,EAAE;AACvD,SAAC,CAAC;QACF,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC;;AAGpC,IAAA,MAAM,IAAI,GAAA;AACf,QAAA,IAAI,CAAC,YAAY,EAAE,2BAA2B,EAAE;AAEhD,QAAA,MAAM,IAAI,CAAC,YAAY,EAAE,gCAAgC,EAAE;AAE3D,QAAA,MAAM,IAAI,CAAC,sBAAsB,EAAE;QAEnC,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE;YAAE,IAAI,CAAC,KAAK,EAAE;;AAG7D,IAAA,MAAM,sBAAsB,CAAC,YAAY,GAAG,KAAK,EAAA;QACtD,IAAI,aAAa,GAAG,IAAI,CAAC,YAAY,EAAE,mBAAmB,EAAE;AAE5D,QAAA,IAAI;AACF,YAAA,IAAI,YAAY;AAAE,gBAAA,aAAa,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE;;;QAE1D,OAAO,KAAU,EAAE;AACnB,YAAA,MAAM,MAAM,GAAG,KAAK,EAAE,MAAM;AAC5B,YAAA,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,MAAM,IAAI,sCAAsC,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAAE,IAAI,CAAC,KAAK,EAAE;YAC5G,aAAa,GAAG,KAAK;;QAGvB,IAAI,CAAC,SAAS,EAAE;AAChB,QAAA,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE;AACrB,YAAA,WAAW,EAAE;AACX,gBAAA,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,WAAW;AAC3B,gBAAA,OAAO,EAAE,IAAI;AACd,aAAA;AACF,SAAA,CAAC;AAEF,QAAA,IAAI,aAAa,IAAI,IAAI,CAAC,MAAM,CAAC,4BAA4B;AAAE,YAAA,MAAM,IAAI,CAAC,cAAc,EAAE;AAE1F,QAAA,OAAO,aAAa;;AAGd,IAAA,MAAM,WAAW,GAAA;AACvB,QAAA,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,KAAK,MAAM;AAAE,YAAA,MAAM,IAAI,CAAC,YAAY,EAAE,YAAY,EAAE;;AAC3E,YAAA,MAAM,IAAI,CAAC,YAAY,EAAE,aAAa,EAAE;AAC7C,QAAA,OAAO,IAAI,CAAC,YAAY,EAAE,mBAAmB,EAAE;;IAG1C,KAAK,GAAA;AACV,QAAA,IAAI,CAAC,YAAY,EAAE,aAAa,EAAE;;AAG7B,IAAA,MAAM,MAAM,GAAA;AACjB,QAAA,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE;YAAE;AAC7B,QAAA,IAAI,IAAI,CAAC,MAAM,CAAC,oBAAoB;AAAE,YAAA,MAAM,IAAI,CAAC,YAAY,EAAE,oBAAoB,EAAE;;AAChF,YAAA,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE;QAChC,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,GAAG,YAAY,EAAE,CAAC;;IAGrC,UAAU,GAAA;AAChB,QAAA,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE;AACrB,YAAA,WAAW,EAAE;AACX,gBAAA,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,WAAW;AAC3B,gBAAA,mBAAmB,EAAE,IAAI;AAC1B,aAAA;AACF,SAAA,CAAC;QACF,IAAI,CAAC,MAAM,EAAE;;AAGR,IAAA,MAAM,cAAc,GAAA;QACzB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,YAAY,EAAE,eAAe,EAAE;AACvD,QAAA,IAAI,IAAI;YAAE,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC;;IAGpC,SAAS,GAAA;AACf,QAAA,MAAM,WAAW,GAAG;YAClB,WAAW,EAAE,IAAI,CAAC,YAAY,EAAE,cAAc,EAAE,IAAI,IAAI;YACxD,oBAAoB,EAAE,IAAI,CAAC,YAAY,EAAE,wBAAwB,EAAE,IAAI,IAAI;YAC3E,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,UAAU,EAAE,IAAI,IAAI;YAChD,gBAAgB,EAAE,IAAI,CAAC,YAAY,EAAE,oBAAoB,EAAE,IAAI,IAAI;YACnE,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,eAAe,EAAE,IAAI,IAAI;SAC3D;AACD,QAAA,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE;AAC/B,YAAA,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE;YACtB,MAAM,eAAe,GAAG,IAAI,IAAI,CAAC,WAAW,CAAC,oBAAoB,IAAI,EAAE,CAAC;YACxE,MAAM,WAAW,GAAG,IAAI,IAAI,CAAC,WAAW,CAAC,gBAAgB,IAAI,EAAE,CAAC;AAChE,YAAA,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC;YAC1B,OAAO,CAAC,KAAK,CACX,CAAuB,oBAAA,EAAA,WAAW,CAAO,IAAA,EAAA,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,OAAO,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI,GAAG,EAAE,CAAU,QAAA,CAAA,CAC/G;YACD,OAAO,CAAC,KAAK,CACX,CAA2B,wBAAA,EAAA,eAAe,CAAO,IAAA,EAAA,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,OAAO,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI,GAAG,EAAE,CAAU,QAAA,CAAA,CAC3H;;AAEH,QAAA,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE;YACrB,WAAW;AACZ,SAAA,CAAC;;AAGJ,IAAA,MAAM,iBAAiB,GAAA;QACrB,MAAM,cAAc,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC;;AAG1F,IAAA,MAAM,aAAa,GAAA;AACjB,QAAA,MAAM,IAAI,CAAC,iBAAiB,EAAE;AAC9B,QAAA,OAAO,IAAI,CAAC,eAAe,EAAE;;AAG/B,IAAA,QAAQ,CAAC,UAAoB,EAAA;AAC3B,QAAA,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,EAAE,GAAG,UAAU,CAAC,CAAC,EAAE,CAAC;;AAG7F,IAAA,WAAW,CAAC,aAAuB,EAAA;AACjC,QAAA,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,CAAC;AAC/C,QAAA,KAAK,MAAM,YAAY,IAAI,aAAa,EAAE;AACxC,YAAA,QAAQ,CAAC,MAAM,CAAC,YAAY,CAAC;;QAE/B,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;;AAG7C,IAAA,YAAY,CAAC,KAAe,EAAA;AAC1B,QAAA,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;;AAGtD,IAAA,iBAAiB,CAAC,KAAe,EAAA;AAC/B,QAAA,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;;8GA5J1C,gBAAgB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;AAAhB,IAAA,SAAA,IAAA,CAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,gBAAgB,cAFf,MAAM,EAAA,CAAA,CAAA;;2FAEP,gBAAgB,EAAA,UAAA,EAAA,CAAA;kBAH5B,UAAU;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,UAAU,EAAE,MAAM;AACnB,iBAAA;;;AC9ED,SAAS,qBAAqB,CAAC,WAA6B,EAAA;AAC1D,IAAA,OAAO,MAAM,WAAW,CAAC,IAAI,EAAE;AACjC;SAEgB,WAAW,CAAC,UAA4B,EAAE,GAAG,QAA6B,EAAA;AACxF,IAAA,OAAO,wBAAwB,CAAC;QAC9B,sBAAsB,CAAC,UAAU,CAAC;AAClC,QAAA,kBAAkB,CAAC;AACjB,YAAA,cAAc,EAAE;AACd,gBAAA,eAAe,EAAE,UAAU,EAAE,eAAe,IAAI,IAAI;AACpD,gBAAA,WAAW,EAAE,UAAU,EAAE,eAAe,IAAI,EAAE;AAC/C,aAAA;SACF,CAAC;AACF,QAAA,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,UAAU,CAAC;QAChD,qBAAqB,CAAC,MAAK;YACzB,MAAM,aAAa,GAAG,qBAAqB,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;YACrE,OAAO,aAAa,EAAE;AACxB,SAAC,CAAC;AACH,KAAA,CAAC;AACJ;SAEgB,QAAQ,CACtB,UAA4B,EAC5B,GAAG,QAA6B,EAAA;AAEhC,IAAA,OAAO,YAAY,CAAA,CAAA,uCAAiC,CAAC,WAAW,CAAC,UAAU,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC;AAC7F;AAYA;;AAEG;AACa,SAAA,gBAAgB,CAC9B,IAAiB,EACjB,SAA8C,EAAA;IAE9C,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE;AAC/C;;ACrCA;;;;;;;;;AASG;MAIU,+BAA+B,CAAA;AAH5C,IAAA,WAAA,GAAA;QAIE,IAAQ,CAAA,QAAA,GAAG,MAAM,CAAC,sBAAsB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QAE7D,IAAW,CAAA,WAAA,GAAG,KAAK,CAAC,QAAQ,CAAW,EAAE,KAAK,EAAE,wBAAwB,EAAE,CAAC;AAE3E,QAAA,IAAA,CAAA,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,CAAC;QAE3C,IAAe,CAAA,eAAA,GAAoC,IAAI;AAEvD,QAAA,IAAA,CAAA,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;AAEjC,QAAA,IAAA,CAAA,WAAW,GAAG,MAAM,CAAC,gBAAgB,CAAC;QAEtC,IAAkB,CAAA,kBAAA,GAAG,kBAAkB,EAAE;AAEzC,QAAA,IAAA,CAAA,iBAAiB,GAAG,MAAM,CAAC,iBAAiB,CAAC;AAE7C,QAAA,IAAA,CAAA,oBAAoB,GAAG,MAAM,CAAC,MAAK;AACjC,YAAA,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS;gBAC7B,OAAO,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,EAAE,YAAY,EAAE,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;AAC1F,YAAA,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,iBAAiB,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACxE,IAAI,SAAS,EAAE;gBACb,IAAI,CAAC,IAAI,CAAC,eAAe;AAAE,oBAAA,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,IAAI,CAAC,WAAW,CAAC;;iBACvG;AACL,gBAAA,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE;AAC7B,gBAAA,IAAI,CAAC,eAAe,GAAG,IAAI;;AAE7B,YAAA,IAAI,CAAC,iBAAiB,CAAC,YAAY,EAAE;AACvC,SAAC,CAAC;AACH;8GA7BY,+BAA+B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;kGAA/B,+BAA+B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,0BAAA,EAAA,MAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,wBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA,CAAA;;2FAA/B,+BAA+B,EAAA,UAAA,EAAA,CAAA;kBAH3C,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,0BAA0B;AACrC,iBAAA;;;ACZD;;;;;;;;;AASG;MAIU,0BAA0B,CAAA;AAHvC,IAAA,WAAA,GAAA;QAIE,IAAQ,CAAA,QAAA,GAAG,MAAM,CAAC,sBAAsB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QAE7D,IAAW,CAAA,WAAA,GAAG,KAAK,CAAC,QAAQ,CAAW,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC;AAEtE,QAAA,IAAA,CAAA,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,CAAC;QAE3C,IAAe,CAAA,eAAA,GAAoC,IAAI;AAEvD,QAAA,IAAA,CAAA,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;AAEjC,QAAA,IAAA,CAAA,WAAW,GAAG,MAAM,CAAC,gBAAgB,CAAC;QAEtC,IAAkB,CAAA,kBAAA,GAAG,kBAAkB,EAAE;AAEzC,QAAA,IAAA,CAAA,iBAAiB,GAAG,MAAM,CAAC,iBAAiB,CAAC;AAE7C,QAAA,IAAA,CAAA,oBAAoB,GAAG,MAAM,CAAC,MAAK;AACjC,YAAA,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS;gBAC7B,OAAO,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,EAAE,YAAY,EAAE,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;AAC1F,YAAA,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACnE,IAAI,SAAS,EAAE;gBACb,IAAI,CAAC,IAAI,CAAC,eAAe;AAAE,oBAAA,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,IAAI,CAAC,WAAW,CAAC;;iBACvG;AACL,gBAAA,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE;AAC7B,gBAAA,IAAI,CAAC,eAAe,GAAG,IAAI;;AAE7B,YAAA,IAAI,CAAC,iBAAiB,CAAC,YAAY,EAAE;AACvC,SAAC,CAAC;AACH;8GA7BY,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,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,mBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA,CAAA;;2FAA1B,0BAA0B,EAAA,UAAA,EAAA,CAAA;kBAHtC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,qBAAqB;AAChC,iBAAA;;;MCZY,6BAA6B,CAAA;AAH1C,IAAA,WAAA,GAAA;AAIE,QAAA,IAAA,CAAA,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,CAAC;AAE3C,QAAA,IAAA,CAAA,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;QAEjC,IAAe,CAAA,eAAA,GAAgC,IAAI;AAEnD,QAAA,IAAA,CAAA,WAAW,GAAG,MAAM,CAAC,gBAAgB,CAAC;QAEtC,IAAkB,CAAA,kBAAA,GAAG,kBAAkB,EAAE;AAEzC,QAAA,IAAA,CAAA,iBAAiB,GAAG,MAAM,CAAC,iBAAiB,CAAC;AAE7C,QAAA,IAAA,CAAA,0BAA0B,GAAG,MAAM,CAAC,MAAK;AACvC,YAAA,IAAI,IAAI,CAAC,WAAW,CAAC,eAAe,EAAE,EAAE;gBACtC,IAAI,CAAC,IAAI,CAAC,eAAe;oBAAE,IAAI,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,IAAI,CAAC,WAAW,CAAC;;iBAChF;AACL,gBAAA,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE;AAC7B,gBAAA,IAAI,CAAC,eAAe,GAAG,IAAI;;AAE7B,YAAA,IAAI,CAAC,iBAAiB,CAAC,YAAY,EAAE;AACvC,SAAC,CAAC;AACH;8GAtBY,6BAA6B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;kGAA7B,6BAA6B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,wBAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA,CAAA;;2FAA7B,6BAA6B,EAAA,UAAA,EAAA,CAAA;kBAHzC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,wBAAwB;AACnC,iBAAA;;;MCCY,gCAAgC,CAAA;AAH7C,IAAA,WAAA,GAAA;AAIE,QAAA,IAAA,CAAA,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,CAAC;AAE3C,QAAA,IAAA,CAAA,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;QAEjC,IAAe,CAAA,eAAA,GAAgC,IAAI;AAEnD,QAAA,IAAA,CAAA,WAAW,GAAG,MAAM,CAAC,gBAAgB,CAAC;QAEtC,IAAkB,CAAA,kBAAA,GAAG,kBAAkB,EAAE;AAEzC,QAAA,IAAA,CAAA,iBAAiB,GAAG,MAAM,CAAC,iBAAiB,CAAC;AAE7C,QAAA,IAAA,CAAA,0BAA0B,GAAG,MAAM,CAAC,MAAK;AACvC,YAAA,IAAI,IAAI,CAAC,WAAW,CAAC,eAAe,EAAE,EAAE;AACtC,gBAAA,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE;AAC7B,gBAAA,IAAI,CAAC,eAAe,GAAG,IAAI;;AACtB,iBAAA,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE;AAChC,gBAAA,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,IAAI,CAAC,WAAW,CAAC;;AAEnF,YAAA,IAAI,CAAC,iBAAiB,CAAC,YAAY,EAAE;AACvC,SAAC,CAAC;AACH;8GAtBY,gCAAgC,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;kGAAhC,gCAAgC,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,2BAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA,CAAA;;2FAAhC,gCAAgC,EAAA,UAAA,EAAA,CAAA;kBAH5C,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,2BAA2B;AACtC,iBAAA;;;ACVM,MAAM,0BAA0B,GACrC,CAAC,KAAe,EAAE,QAAgC,KAClD,YAAW;AACT,IAAA,MAAM,WAAW,GAAG,MAAM,CAAC,gBAAgB,CAAC;AAC5C,IAAA,MAAM,eAAe,GAAG,MAAM,WAAW,CAAC,aAAa,EAAE;AACzD,IAAA,IAAI,CAAC,eAAe;AAAE,QAAA,OAAO,KAAK;AAClC,IAAA,MAAM,iBAAiB,GAAG,QAAQ,KAAK,OAAO,GAAG,WAAW,CAAC,YAAY,GAAG,WAAW,CAAC,iBAAiB;IACzG,OAAO,iBAAiB,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC;AACnD;;ACRW,MAAA,yBAAyB,GAAkB,YAAW;AACjE,IAAA,MAAM,WAAW,GAAG,MAAM,CAAC,gBAAgB,CAAC;AAC5C,IAAA,OAAO,WAAW,CAAC,aAAa,EAAE;AACpC;;MCEa,cAAc,GAAG,IAAI,cAAc,CAAS,gBAAgB;MAC5D,eAAe,GAAG,IAAI,cAAc,CAAW,iBAAiB;MAChE,oBAAoB,GAAG,IAAI,cAAc,CAAY,sBAAsB;MAE3E,wBAAwB,GAAsB,CAAC,OAAO,EAAE,IAAI,KAAI;AAC3E,IAAA,MAAM,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,CAAC;AACjD,IAAA,MAAM,cAAc,GAAG,MAAM,CAAC,eAAe,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC;AAC3E,IAAA,MAAM,oBAAoB,GAAG,uBAAuB,CAAC,MAAM,CAAC,oBAAoB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;AAC5G,IAAA,MAAM,OAAO,GAAG,MAAM,CAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC;IAE/D,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;AACjC,QAAA,OAAO,IAAI,CAAC,OAAO,CAAC;;AAGtB,IAAA,IACE,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,KAC1E,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CACrD,EACD;AACA,QAAA,OAAO,IAAI,CAAC,OAAO,CAAC;;IAGtB,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CACvB,KAAK,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,EACrC,UAAU,CAAC,CAAC,KAAwB,KAAI;AACtC,QAAA,IAAI,cAAc,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;AACxC,YAAA,OAAO,IAAI,CAAC,gBAAgB,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAC7D,GAAG,CAAC,CAAC,eAAe,KAAI;AACtB,gBAAA,IAAI,CAAC,eAAe;oBAAE,gBAAgB,CAAC,MAAM,EAAE;AACjD,aAAC,CAAC,EACF,SAAS,CAAC,MAAM,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC,CACzC;AACH,QAAA,OAAO,UAAU,CAAC,MAAM,KAAK,CAAC;AAChC,KAAC,CAAC,EACF,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAChC;AACH;AAEgB,SAAA,iBAAiB,CAC/B,YAAA,GAA0B,EAAE,EAC5B,QAAQ,GAAG,CAAC,GAAG,CAAC,EAChB,OAAO,GAAG,CAAC,EAAA;AAEX,IAAA,MAAM,SAAS,GAAe;AAC5B,QAAA;AACE,YAAA,OAAO,EAAE,eAAe;AACxB,YAAA,QAAQ,EAAE,QAAQ;AACnB,SAAA;AACD,QAAA;AACE,YAAA,OAAO,EAAE,oBAAoB;AAC7B,YAAA,QAAQ,EAAE,YAAY;AACvB,SAAA;AACD,QAAA;AACE,YAAA,OAAO,EAAE,cAAc;AACvB,YAAA,QAAQ,EAAE,OAAO;AAClB,SAAA;KACF;AACD,IAAA,OAAO,gBAAgB,CAAA,CAAA,kDAA4C,SAAS,CAAC;AAC/E;;SC9DgB,gBAAgB,GAAA;AAC9B,IAAA,MAAM,SAAS,GAAe;AAC5B,QAAA;AACE,YAAA,OAAO,EAAE,YAAY;AACrB,YAAA,QAAQ,EAAE,YAAY;AACvB,SAAA;KACF;AACD,IAAA,OAAO,gBAAgB,CAAA,CAAA,iDAA2C,SAAS,CAAC;AAC9E;;MCPa,aAAa,CAAA;AAD1B,IAAA,WAAA,GAAA;AAEU,QAAA,IAAA,CAAA,IAAI,GAAG,IAAI,GAAG,EAAkB;AAazC;AAXC,IAAA,OAAO,CAAC,GAAW,EAAA;QACjB,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE;;AAGjC,IAAA,UAAU,CAAC,GAAW,EAAA;AACpB,QAAA,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC;;IAGvB,OAAO,CAAC,GAAW,EAAE,IAAY,EAAA;QAC/B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC;;8GAZf,aAAa,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;kHAAb,aAAa,EAAA,CAAA,CAAA;;2FAAb,aAAa,EAAA,UAAA,EAAA,CAAA;kBADzB;;SAiBe,iBAAiB,GAAA;AAC/B,IAAA,MAAM,SAAS,GAAe;AAC5B,QAAA;AACE,YAAA,OAAO,EAAE,YAAY;AACrB,YAAA,UAAU,EAAE,MAAM,IAAI,aAAa,EAAE;AACtC,SAAA;KACF;AACD,IAAA,OAAO,gBAAgB,CAAA,CAAA,kDAA4C,SAAS,CAAC;AAC/E;;SCzBgB,kBAAkB,GAAA;AAChC,IAAA,MAAM,SAAS,GAAe;AAC5B,QAAA;AACE,YAAA,OAAO,EAAE,YAAY;AACrB,YAAA,QAAQ,EAAE,cAAc;AACzB,SAAA;KACF;AACD,IAAA,OAAO,gBAAgB,CAAA,CAAA,mDAA6C,SAAS,CAAC;AAChF;;ACdA;;AAEG;;;;"}
|