@axa-fr/react-oidc 6.0.0-beta0 → 6.0.0-beta3
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 +12 -9
- package/dist/OidcProvider.d.ts +2 -3
- package/dist/OidcProvider.d.ts.map +1 -1
- package/dist/OidcProvider.js +5 -4
- package/dist/OidcProvider.js.map +1 -1
- package/dist/OidcServiceWorker.js +4 -2
- package/dist/core/default-component/SilentCallback.component.d.ts.map +1 -1
- package/dist/core/default-component/SilentCallback.component.js +5 -19
- package/dist/core/default-component/SilentCallback.component.js.map +1 -1
- package/dist/core/default-component/SilentLogin.component.d.ts +4 -0
- package/dist/core/default-component/SilentLogin.component.d.ts.map +1 -0
- package/dist/core/default-component/{SilentSignin.component.js → SilentLogin.component.js} +3 -3
- package/dist/core/default-component/SilentLogin.component.js.map +1 -0
- package/dist/core/routes/OidcRoutes.d.ts +1 -1
- package/dist/core/routes/OidcRoutes.d.ts.map +1 -1
- package/dist/core/routes/OidcRoutes.js +5 -5
- package/dist/core/routes/OidcRoutes.js.map +1 -1
- package/dist/vanilla/checkSessionIFrame.d.ts +6 -6
- package/dist/vanilla/checkSessionIFrame.d.ts.map +1 -1
- package/dist/vanilla/checkSessionIFrame.js +1 -1
- package/dist/vanilla/checkSessionIFrame.js.map +1 -1
- package/dist/vanilla/oidc.d.ts +10 -9
- package/dist/vanilla/oidc.d.ts.map +1 -1
- package/dist/vanilla/oidc.js +70 -46
- package/dist/vanilla/oidc.js.map +1 -1
- package/package.json +1 -1
- package/src/oidc/OidcProvider.tsx +9 -10
- package/src/oidc/core/default-component/SilentCallback.component.tsx +1 -6
- package/src/oidc/core/default-component/{SilentSignin.component.tsx → SilentLogin.component.tsx} +2 -2
- package/src/oidc/core/routes/OidcRoutes.tsx +6 -6
- package/src/oidc/vanilla/OidcServiceWorker.js +4 -2
- package/src/oidc/vanilla/checkSessionIFrame.ts +7 -7
- package/src/oidc/vanilla/oidc.ts +63 -54
- package/dist/core/default-component/SilentSignin.component.d.ts +0 -4
- package/dist/core/default-component/SilentSignin.component.d.ts.map +0 -1
- package/dist/core/default-component/SilentSignin.component.js.map +0 -1
|
@@ -73,11 +73,13 @@ const getCurrentDatabasesTokenEndpoint = (database, url) => {
|
|
|
73
73
|
return databases;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
const openidWellknownUrlEndWith = "/.well-known/openid-configuration"
|
|
76
77
|
const getCurrentDatabaseDomain = (database, url) => {
|
|
78
|
+
if(url.endsWith(openidWellknownUrlEndWith)){
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
77
81
|
for (const [key, currentDatabase] of Object.entries(database)) {
|
|
78
|
-
|
|
79
82
|
const oidcServerConfiguration = currentDatabase.oidcServerConfiguration;
|
|
80
|
-
|
|
81
83
|
if(url === oidcServerConfiguration.tokenEndpoint){
|
|
82
84
|
continue;
|
|
83
85
|
}
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
const Log = console;
|
|
4
4
|
|
|
5
5
|
export class CheckSessionIFrame {
|
|
6
|
-
private _client_id: any;
|
|
7
|
-
private _callback: any;
|
|
6
|
+
private readonly _client_id: any;
|
|
7
|
+
private readonly _callback: any;
|
|
8
8
|
private _url: any;
|
|
9
|
-
private _interval: number;
|
|
10
|
-
private _stopOnError: boolean;
|
|
11
|
-
private _frame_origin: string;
|
|
12
|
-
private _frame: HTMLIFrameElement;
|
|
9
|
+
private readonly _interval: number;
|
|
10
|
+
private readonly _stopOnError: boolean;
|
|
11
|
+
private readonly _frame_origin: string;
|
|
12
|
+
private readonly _frame: HTMLIFrameElement;
|
|
13
13
|
private _boundMessageEvent: any;
|
|
14
14
|
private _timer: number;
|
|
15
15
|
constructor(callback, client_id, url, interval=DefaultInterval, stopOnError = true) {
|
|
@@ -46,7 +46,7 @@ export class CheckSessionIFrame {
|
|
|
46
46
|
e.source === this._frame.contentWindow
|
|
47
47
|
) {
|
|
48
48
|
if (e.data === "error") {
|
|
49
|
-
|
|
49
|
+
Log.error("CheckSessionIFrame: error message from check session op iframe");
|
|
50
50
|
if (this._stopOnError) {
|
|
51
51
|
this.stop();
|
|
52
52
|
}
|
package/src/oidc/vanilla/oidc.ts
CHANGED
|
@@ -21,8 +21,7 @@ import {getParseQueryStringFromLocation} from "./route-utils";
|
|
|
21
21
|
import {AuthorizationServiceConfigurationJson} from "@openid/appauth/src/authorization_service_configuration";
|
|
22
22
|
|
|
23
23
|
const performTokenRequestAsync= async (url, details, extras) => {
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
|
|
26
25
|
for (let [key, value] of Object.entries(extras)) {
|
|
27
26
|
if (details[key] === undefined) {
|
|
28
27
|
details[key] = value;
|
|
@@ -63,14 +62,13 @@ const performTokenRequestAsync= async (url, details, extras) => {
|
|
|
63
62
|
const internalFetch = async (url, headers, numberRetry=0) => {
|
|
64
63
|
let response;
|
|
65
64
|
try {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
() => reject(new Error('Timeout')), 10000))]);
|
|
65
|
+
let controller = new AbortController();
|
|
66
|
+
setTimeout(() => controller.abort(), 10000);
|
|
67
|
+
response = await fetch(url, {...headers, signal: controller.signal});
|
|
70
68
|
} catch (e) {
|
|
71
|
-
if (e.message === '
|
|
69
|
+
if (e.message === 'AbortError'
|
|
72
70
|
|| e.message === 'Network request failed') {
|
|
73
|
-
if(numberRetry <=
|
|
71
|
+
if(numberRetry <=1) {
|
|
74
72
|
return await internalFetch(url, headers, numberRetry + 1);
|
|
75
73
|
}
|
|
76
74
|
else {
|
|
@@ -156,8 +154,8 @@ export interface AuthorityConfiguration {
|
|
|
156
154
|
client_id: string,
|
|
157
155
|
redirect_uri: string,
|
|
158
156
|
silent_redirect_uri?:string,
|
|
159
|
-
|
|
160
|
-
|
|
157
|
+
silent_login_uri?:string,
|
|
158
|
+
silent_login_timeout?:number,
|
|
161
159
|
scope: string,
|
|
162
160
|
authority: string,
|
|
163
161
|
authority_time_cache_wellknowurl_in_second?: number,
|
|
@@ -245,7 +243,7 @@ const userInfoAsync = async (oidc) => {
|
|
|
245
243
|
const res = await fetch(url, {
|
|
246
244
|
headers: {
|
|
247
245
|
authorization: `Bearer ${accessToken}`,
|
|
248
|
-
credentials: '
|
|
246
|
+
credentials: 'include'
|
|
249
247
|
}
|
|
250
248
|
});
|
|
251
249
|
|
|
@@ -298,47 +296,42 @@ const eventNames = {
|
|
|
298
296
|
tryKeepExistingSessionAsync_begin: "tryKeepExistingSessionAsync_begin",
|
|
299
297
|
tryKeepExistingSessionAsync_end: "tryKeepExistingSessionAsync_end",
|
|
300
298
|
tryKeepExistingSessionAsync_error: "tryKeepExistingSessionAsync_error",
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
299
|
+
silentLoginAsync_begin: "silentLoginAsync_begin",
|
|
300
|
+
silentLoginAsync: "silentLoginAsync",
|
|
301
|
+
silentLoginAsync_end: "silentLoginAsync_end",
|
|
302
|
+
silentLoginAsync_error: "silentLoginAsync_error",
|
|
305
303
|
syncTokensAsync_begin: "syncTokensAsync_begin",
|
|
306
304
|
syncTokensAsync_end: "syncTokensAsync_end",
|
|
307
305
|
syncTokensAsync_error: "syncTokensAsync_error"
|
|
308
|
-
|
|
309
306
|
}
|
|
310
307
|
|
|
311
308
|
const getRandomInt = (max) => {
|
|
312
309
|
return Math.floor(Math.random() * max);
|
|
313
310
|
}
|
|
314
311
|
|
|
315
|
-
const WELL_KNOWN_PATH = '.well-known';
|
|
316
|
-
const OPENID_CONFIGURATION = 'openid-configuration';
|
|
317
|
-
|
|
318
|
-
|
|
319
312
|
const oneHourSecond = 60 * 60;
|
|
313
|
+
let fetchFromIssuerCache = null;
|
|
320
314
|
const fetchFromIssuer = async (openIdIssuerUrl: string, timeCacheSecond = oneHourSecond):
|
|
321
315
|
Promise<OidcAuthorizationServiceConfiguration> => {
|
|
322
|
-
const fullUrl = `${openIdIssuerUrl}
|
|
316
|
+
const fullUrl = `${openIdIssuerUrl}/.well-known/openid-configuration`;
|
|
323
317
|
|
|
324
|
-
const localStorageKey = `oidc.server:${openIdIssuerUrl}`;
|
|
325
|
-
const cacheJson = window.
|
|
318
|
+
//const localStorageKey = `oidc.server:${openIdIssuerUrl}`;
|
|
319
|
+
//const cacheJson = window.sessionStorage.getItem(localStorageKey);
|
|
326
320
|
|
|
327
321
|
const oneHourMinisecond = 1000 * timeCacheSecond;
|
|
328
322
|
// @ts-ignore
|
|
329
|
-
if(
|
|
330
|
-
return new OidcAuthorizationServiceConfiguration(
|
|
323
|
+
if(fetchFromIssuerCache && (fetchFromIssuerCache.timestamp + oneHourMinisecond) > Date.now()){
|
|
324
|
+
return new OidcAuthorizationServiceConfiguration(fetchFromIssuerCache.result);
|
|
331
325
|
}
|
|
332
|
-
|
|
333
326
|
const response = await fetch(fullUrl);
|
|
334
327
|
|
|
335
328
|
if (response.status != 200) {
|
|
336
329
|
return null;
|
|
337
330
|
}
|
|
338
331
|
|
|
339
|
-
|
|
340
332
|
const result = await response.json();
|
|
341
|
-
|
|
333
|
+
fetchFromIssuerCache = {result, timestamp:Date.now()};
|
|
334
|
+
//window.sessionStorage.setItem(localStorageKey, JSON.stringify({result, timestamp:Date.now()}));
|
|
342
335
|
|
|
343
336
|
return new OidcAuthorizationServiceConfiguration(result);
|
|
344
337
|
}
|
|
@@ -368,7 +361,12 @@ export class Oidc {
|
|
|
368
361
|
private session?: any;
|
|
369
362
|
private checkSessionIFrame: CheckSessionIFrame;
|
|
370
363
|
constructor(configuration:OidcConfiguration, configurationName="default") {
|
|
371
|
-
|
|
364
|
+
let silent_login_uri = configuration.silent_login_uri;
|
|
365
|
+
if(configuration.silent_redirect_uri && !configuration.silent_login_uri){
|
|
366
|
+
silent_login_uri = `${configuration.silent_redirect_uri}-login`;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
this.configuration = {...configuration, silent_login_uri};
|
|
372
370
|
this.configurationName= configurationName;
|
|
373
371
|
this.tokens = null
|
|
374
372
|
this.userInfo = null;
|
|
@@ -385,6 +383,7 @@ export class Oidc {
|
|
|
385
383
|
this.removeEventSubscription.bind(this);
|
|
386
384
|
this.publishEvent.bind(this);
|
|
387
385
|
this.destroyAsync.bind(this);
|
|
386
|
+
this.logoutAsync.bind(this);
|
|
388
387
|
}
|
|
389
388
|
|
|
390
389
|
subscriveEvents(func){
|
|
@@ -416,29 +415,40 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
416
415
|
}
|
|
417
416
|
static eventNames = eventNames;
|
|
418
417
|
|
|
419
|
-
|
|
420
|
-
if (this.configuration.silent_redirect_uri && this.configuration.
|
|
418
|
+
_silentLoginCallbackFromIFrame(){
|
|
419
|
+
if (this.configuration.silent_redirect_uri && this.configuration.silent_login_uri) {
|
|
421
420
|
const queryParams = getParseQueryStringFromLocation(window.location.href);
|
|
422
421
|
window.top.postMessage(`${this.configurationName}_oidc_tokens:${JSON.stringify({tokens:this.tokens, sessionState:queryParams.session_state})}`, window.location.origin);
|
|
423
422
|
}
|
|
424
423
|
}
|
|
425
|
-
|
|
426
|
-
if (this.configuration.silent_redirect_uri && this.configuration.
|
|
424
|
+
_silentLoginErrorCallbackFromIFrame() {
|
|
425
|
+
if (this.configuration.silent_redirect_uri && this.configuration.silent_login_uri) {
|
|
427
426
|
const queryParams = getParseQueryStringFromLocation(window.location.href);
|
|
428
|
-
window.top.postMessage(`${this.configurationName}_oidc_error:${JSON.stringify({error:queryParams.error})}`, window.location.origin);
|
|
427
|
+
window.top.postMessage(`${this.configurationName}_oidc_error:${JSON.stringify({error: queryParams.error})}`, window.location.origin);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
async silentLoginCallBackAsync() {
|
|
432
|
+
try {
|
|
433
|
+
await this.loginCallbackAsync(true);
|
|
434
|
+
this._silentLoginCallbackFromIFrame();
|
|
435
|
+
} catch (error) {
|
|
436
|
+
console.error(error)
|
|
437
|
+
this._silentLoginErrorCallbackFromIFrame();
|
|
429
438
|
}
|
|
430
439
|
}
|
|
431
|
-
|
|
432
|
-
|
|
440
|
+
|
|
441
|
+
async silentLoginAsync(extras:StringMap=null, state:string=null, scope:string=null) {
|
|
442
|
+
if (!this.configuration.silent_redirect_uri || !this.configuration.silent_login_uri) {
|
|
433
443
|
return Promise.resolve(null);
|
|
434
444
|
}
|
|
435
445
|
while (document.hidden) {
|
|
436
446
|
await sleepAsync(1000);
|
|
437
|
-
this.publishEvent(eventNames.
|
|
447
|
+
this.publishEvent(eventNames.silentLoginAsync, {message:"wait because document is hidden"});
|
|
438
448
|
}
|
|
439
449
|
|
|
440
450
|
try {
|
|
441
|
-
this.publishEvent(eventNames.
|
|
451
|
+
this.publishEvent(eventNames.silentLoginAsync_begin, {});
|
|
442
452
|
const configuration = this.configuration
|
|
443
453
|
let queries = "";
|
|
444
454
|
|
|
@@ -465,7 +475,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
465
475
|
}
|
|
466
476
|
}
|
|
467
477
|
}
|
|
468
|
-
const link = configuration.
|
|
478
|
+
const link = configuration.silent_login_uri + queries;
|
|
469
479
|
const idx = link.indexOf("/", link.indexOf("//") + 2);
|
|
470
480
|
const iFrameOrigin = link.substr(0, idx);
|
|
471
481
|
const iframe = document.createElement('iframe');
|
|
@@ -490,14 +500,14 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
490
500
|
if (!isResolved) {
|
|
491
501
|
if(data.startsWith(key)) {
|
|
492
502
|
const result = JSON.parse(e.data.replace(key, ''));
|
|
493
|
-
self.publishEvent(eventNames.
|
|
503
|
+
self.publishEvent(eventNames.silentLoginAsync_end, {});
|
|
494
504
|
iframe.remove();
|
|
495
505
|
isResolved = true;
|
|
496
506
|
resolve(result);
|
|
497
507
|
}
|
|
498
508
|
else if(data.startsWith(key_error)) {
|
|
499
509
|
const result = JSON.parse(e.data.replace(key_error, ''));
|
|
500
|
-
self.publishEvent(eventNames.
|
|
510
|
+
self.publishEvent(eventNames.silentLoginAsync_error, result);
|
|
501
511
|
iframe.remove();
|
|
502
512
|
isResolved = true;
|
|
503
513
|
reject(result);
|
|
@@ -506,10 +516,10 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
506
516
|
}
|
|
507
517
|
}
|
|
508
518
|
};
|
|
509
|
-
const silentSigninTimeout = configuration.
|
|
519
|
+
const silentSigninTimeout = configuration.silent_login_timeout ?? 12000
|
|
510
520
|
setTimeout(() => {
|
|
511
521
|
if (!isResolved) {
|
|
512
|
-
self.publishEvent(eventNames.
|
|
522
|
+
self.publishEvent(eventNames.silentLoginAsync_error, "timeout");
|
|
513
523
|
iframe.remove();
|
|
514
524
|
isResolved = true;
|
|
515
525
|
reject("timeout");
|
|
@@ -517,12 +527,12 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
517
527
|
}, silentSigninTimeout);
|
|
518
528
|
} catch (e) {
|
|
519
529
|
iframe.remove();
|
|
520
|
-
self.publishEvent(eventNames.
|
|
530
|
+
self.publishEvent(eventNames.silentLoginAsync_error, e);
|
|
521
531
|
reject(e);
|
|
522
532
|
}
|
|
523
533
|
});
|
|
524
534
|
} catch (e) {
|
|
525
|
-
this.publishEvent(eventNames.
|
|
535
|
+
this.publishEvent(eventNames.silentLoginAsync_error, e);
|
|
526
536
|
throw e;
|
|
527
537
|
}
|
|
528
538
|
}
|
|
@@ -712,12 +722,11 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
712
722
|
this.loginPromise = null;
|
|
713
723
|
return result;
|
|
714
724
|
});
|
|
715
|
-
|
|
716
725
|
}
|
|
717
726
|
|
|
718
727
|
async startCheckSessionAsync(checkSessionIFrameUri, clientId, sessionState, isSilentSignin=false){
|
|
719
728
|
return new Promise((resolve:Function, reject) => {
|
|
720
|
-
if (this.configuration.
|
|
729
|
+
if (this.configuration.silent_login_uri && this.configuration.silent_redirect_uri && this.configuration.monitor_session && checkSessionIFrameUri && sessionState && !isSilentSignin) {
|
|
721
730
|
const checkSessionCallback = () => {
|
|
722
731
|
this.checkSessionIFrame.stop();
|
|
723
732
|
|
|
@@ -728,7 +737,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
728
737
|
const idToken = this.tokens.idToken;
|
|
729
738
|
// @ts-ignore
|
|
730
739
|
const idTokenPayload = this.tokens.idTokenPayload;
|
|
731
|
-
this.
|
|
740
|
+
this.silentLoginAsync({
|
|
732
741
|
prompt: "none",
|
|
733
742
|
id_token_hint: idToken,
|
|
734
743
|
scope: "openid"
|
|
@@ -911,9 +920,9 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
911
920
|
|
|
912
921
|
async refreshTokensAsync(refreshToken) {
|
|
913
922
|
|
|
914
|
-
const
|
|
923
|
+
const localsilentLoginAsync= async () => {
|
|
915
924
|
try {
|
|
916
|
-
const silent_token_response = await this.
|
|
925
|
+
const silent_token_response = await this.silentLoginAsync();
|
|
917
926
|
if (silent_token_response) {
|
|
918
927
|
return silent_token_response.tokens;
|
|
919
928
|
}
|
|
@@ -935,7 +944,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
935
944
|
|
|
936
945
|
if(!refreshToken)
|
|
937
946
|
{
|
|
938
|
-
return await
|
|
947
|
+
return await localsilentLoginAsync();
|
|
939
948
|
}
|
|
940
949
|
|
|
941
950
|
let extras = {};
|
|
@@ -969,11 +978,11 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
969
978
|
return tokenResponse.data;
|
|
970
979
|
} else {
|
|
971
980
|
this.publishEvent(eventNames.refreshTokensAsync_silent_error, {message: "bad request" , tokenResponse: tokenResponse});
|
|
972
|
-
return await
|
|
981
|
+
return await localsilentLoginAsync();
|
|
973
982
|
}
|
|
974
983
|
} catch (exception) {
|
|
975
984
|
console.error(exception);
|
|
976
|
-
this.publishEvent(eventNames.refreshTokensAsync_silent_error, {message: "exception" ,exception: exception});
|
|
985
|
+
this.publishEvent(eventNames.refreshTokensAsync_silent_error, {message: "exception" ,exception: exception.message});
|
|
977
986
|
}
|
|
978
987
|
index++;
|
|
979
988
|
}
|
|
@@ -999,7 +1008,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
|
|
|
999
1008
|
else if (isLogin == null){
|
|
1000
1009
|
try {
|
|
1001
1010
|
this.publishEvent(eventNames.syncTokensAsync_begin, {});
|
|
1002
|
-
this.syncTokensAsyncPromise = this.
|
|
1011
|
+
this.syncTokensAsyncPromise = this.silentLoginAsync({prompt:"none"});
|
|
1003
1012
|
const silent_token_response = await this.syncTokensAsyncPromise;
|
|
1004
1013
|
if (silent_token_response && silent_token_response.tokens) {
|
|
1005
1014
|
this.tokens = await setTokensAsync(serviceWorker, silent_token_response.tokens);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SilentSignin.component.d.ts","sourceRoot":"","sources":["../../../src/oidc/core/default-component/SilentSignin.component.tsx"],"names":[],"mappings":"AAAA,OAAc,EAAY,aAAa,EAAC,MAAM,OAAO,CAAC;AAKtD,QAAA,MAAM,YAAY,EAAE,aAAa,CAAC,GAAG,CA2BnC,CAAC;AAEH,eAAe,YAAY,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SilentSignin.component.js","sourceRoot":"","sources":["../../../src/oidc/core/default-component/SilentSignin.component.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,6CAAsD;AACtD,4DAAsC;AACtC,yDAA0E;AAG1E,IAAM,YAAY,GAAuB,CAAC,UAAC,EAAoB;QAAnB,iBAAiB,uBAAA;IACzD,IAAM,WAAW,GAAG,IAAA,6CAA+B,EAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAE1E,IAAM,OAAO,GAAI,cAAI,CAAC,GAAG,CAAC;IAC1B,IAAM,IAAI,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAExC,IAAI,MAAM,GAAG,IAAI,CAAC;IAElB,KAAyB,UAA2B,EAA3B,KAAA,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAA3B,cAA2B,EAA3B,IAA2B,EAAE;QAA7C,IAAA,WAAY,EAAX,GAAG,QAAA,EAAE,KAAK,QAAA;QAChB,IAAG,GAAG,KAAK,OAAO,IAAI,GAAG,IAAI,OAAO,EAAC;YACjC,SAAS;SACZ;QACD,IAAG,MAAM,KAAK,IAAI,EAAC;YACf,MAAM,GAAG,EAAE,CAAC;SACf;QACD,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;KACvB;IAED,IAAA,iBAAS,EAAC;QACN,IAAG,CAAC,IAAI,CAAC,MAAM,EAAC;YACZ,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC;SACnF;QACD,OAAO;QACP,CAAC,CAAA;IACL,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,6DAAK,CAAC;AACjB,CAAC,CAAC,CAAC;AAEH,kBAAe,YAAY,CAAC"}
|