@arsedizioni/ars-utils 18.2.338 → 18.2.340
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/clipper.common/common/interceptors/auth.interceptor.d.ts +7 -0
- package/clipper.common/common/services/clipper.service.d.ts +35 -65
- package/esm2022/clipper.common/common/interceptors/auth.interceptor.mjs +36 -33
- package/esm2022/clipper.common/common/services/clipper.service.mjs +31 -140
- package/esm2022/ui/ui/dialogs/info/info-dialog.component.mjs +1 -1
- package/esm2022/ui/ui/services/dialog.service.mjs +3 -1
- package/fesm2022/arsedizioni-ars-utils-clipper.common.mjs +61 -170
- package/fesm2022/arsedizioni-ars-utils-clipper.common.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-ui.mjs +2 -0
- package/fesm2022/arsedizioni-ars-utils-ui.mjs.map +1 -1
- package/package.json +12 -12
|
@@ -3,8 +3,15 @@ import { Observable } from 'rxjs';
|
|
|
3
3
|
import * as i0 from "@angular/core";
|
|
4
4
|
export declare class ClipperAuthInterceptor implements HttpInterceptor {
|
|
5
5
|
private clipperService;
|
|
6
|
+
private broadcastService;
|
|
6
7
|
private dialogService;
|
|
7
8
|
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>;
|
|
9
|
+
/**
|
|
10
|
+
* Handle 401 error
|
|
11
|
+
* @param request : the request
|
|
12
|
+
* @param next : the http handler
|
|
13
|
+
*/
|
|
14
|
+
private handle401Error;
|
|
8
15
|
/**
|
|
9
16
|
* Add token to request
|
|
10
17
|
* @param request : the request
|
|
@@ -1,23 +1,18 @@
|
|
|
1
1
|
import { OnDestroy, Signal } from '@angular/core';
|
|
2
2
|
import { ApiResult, FolderTree, NameValueItem } from '@arsedizioni/ars-utils/core';
|
|
3
3
|
import { LoginOAuthType } from '@arsedizioni/ars-utils/ui.oauth';
|
|
4
|
-
import {
|
|
4
|
+
import { Subscription } from 'rxjs';
|
|
5
5
|
import { ClipperDashboard, ClipperDocumentInfo, ClipperDocumentStructure, ClipperDocumentUpdateStateParams, ClipperExportDocumentsParams, ClipperLoginInfo, ClipperLoginResult, ClipperModule, ClipperOTPInfo, ClipperQueryArsEventsParams, ClipperQueryArsEventsResult, ClipperReferencesSearchParams, ClipperSearchFacetsResult, ClipperSearchParams, ClipperSearchResult, ClipperSendDocumentsByEmailParams, ClipperTaxonomyParams, ClipperUserLink, ClipperUserSearch } from '../definitions';
|
|
6
6
|
import * as i0 from "@angular/core";
|
|
7
7
|
export declare class ClipperService implements OnDestroy {
|
|
8
|
-
private readonly REFRESH_INTERVAL;
|
|
9
8
|
private httpClient;
|
|
9
|
+
private broadcastServiceSubscription?;
|
|
10
10
|
private broadcastService;
|
|
11
11
|
private dialogService;
|
|
12
|
-
private tokenRefreshInterval;
|
|
13
|
-
private tokenRefreshTimer?;
|
|
14
|
-
private tokenRefreshTimerSubscription?;
|
|
15
|
-
private broadcastServiceSubscription?;
|
|
16
|
-
private refreshing;
|
|
17
|
-
private _loginInfo;
|
|
18
|
-
get loginInfo(): ClipperLoginInfo;
|
|
19
12
|
private _serviceUri;
|
|
20
13
|
get serviceUri(): string;
|
|
14
|
+
private _loginInfo;
|
|
15
|
+
get loginInfo(): ClipperLoginInfo;
|
|
21
16
|
readonly loggedIn: import("@angular/core").WritableSignal<boolean>;
|
|
22
17
|
readonly loggingIn: import("@angular/core").WritableSignal<boolean>;
|
|
23
18
|
readonly snapshot: import("@angular/core").WritableSignal<ClipperSearchResult>;
|
|
@@ -27,28 +22,17 @@ export declare class ClipperService implements OnDestroy {
|
|
|
27
22
|
readonly bagTotal: Signal<number>;
|
|
28
23
|
readonly visible: import("@angular/core").WritableSignal<boolean>;
|
|
29
24
|
readonly supportsRS: import("@angular/core").WritableSignal<boolean>;
|
|
30
|
-
constructor();
|
|
31
25
|
ngOnDestroy(): void;
|
|
32
26
|
/**
|
|
33
27
|
* Initialize service
|
|
34
28
|
* @param serviceUri : the service uri
|
|
35
|
-
* @param tokenRefreshInterval : the token refresh interval
|
|
36
29
|
*/
|
|
37
|
-
initialize(serviceUri
|
|
38
|
-
/**
|
|
39
|
-
* Set JWT token
|
|
40
|
-
* @param token : token
|
|
41
|
-
*/
|
|
42
|
-
private setToken;
|
|
30
|
+
initialize(serviceUri: string): void;
|
|
43
31
|
/**
|
|
44
32
|
* Set JWT tokens
|
|
45
|
-
* @param
|
|
33
|
+
* @param value : the login result
|
|
46
34
|
*/
|
|
47
|
-
private
|
|
48
|
-
/**
|
|
49
|
-
* Enable JWT token auto refresh
|
|
50
|
-
*/
|
|
51
|
-
private enableTokenRefresh;
|
|
35
|
+
private setToken;
|
|
52
36
|
/**
|
|
53
37
|
* Return current JWT token
|
|
54
38
|
* @param refresh: true to get the refresh token. Default is false.
|
|
@@ -63,21 +47,11 @@ export declare class ClipperService implements OnDestroy {
|
|
|
63
47
|
* @param oauthAccessToken: the optional OAuth2 access token
|
|
64
48
|
* @returns: the login result
|
|
65
49
|
*/
|
|
66
|
-
login(email?: string | null | undefined, password?: string | null | undefined, remember?: boolean | null | undefined, oauth?: LoginOAuthType | null | undefined, oauthAccessToken?: string | null | undefined): Observable<ApiResult<ClipperLoginResult>>;
|
|
67
|
-
/**
|
|
68
|
-
* Perform login
|
|
69
|
-
* @param email: the optioanl email if using OAuth2
|
|
70
|
-
* @parma password: the optional password if using OAuth2
|
|
71
|
-
* @param remember: remember credentials
|
|
72
|
-
* @param oauth: the optional open authentication supported
|
|
73
|
-
* @param oauthAccessToken: the optional OAuth2 access token
|
|
74
|
-
* @returns: the login result
|
|
75
|
-
*/
|
|
76
|
-
login2(email?: string | null | undefined, password?: string | null | undefined, remember?: boolean | null | undefined, oauth?: LoginOAuthType | null | undefined, oauthAccessToken?: string | null | undefined): Observable<ApiResult<ClipperLoginResult>>;
|
|
50
|
+
login(email?: string | null | undefined, password?: string | null | undefined, remember?: boolean | null | undefined, oauth?: LoginOAuthType | null | undefined, oauthAccessToken?: string | null | undefined): import("rxjs").Observable<ApiResult<ClipperLoginResult>>;
|
|
77
51
|
/**
|
|
78
52
|
* Perform logout
|
|
79
53
|
*/
|
|
80
|
-
logout(): Observable<any>;
|
|
54
|
+
logout(): import("rxjs").Observable<any>;
|
|
81
55
|
/**
|
|
82
56
|
* Reset login refresh timer and login state
|
|
83
57
|
*/
|
|
@@ -86,95 +60,91 @@ export declare class ClipperService implements OnDestroy {
|
|
|
86
60
|
* Clear login data
|
|
87
61
|
*/
|
|
88
62
|
clear(): void;
|
|
89
|
-
/**
|
|
90
|
-
* Perform token refresh
|
|
91
|
-
*/
|
|
92
|
-
private refresh;
|
|
93
63
|
/**
|
|
94
64
|
* Perform token refresh
|
|
95
65
|
*/
|
|
96
|
-
|
|
66
|
+
refresh(): import("rxjs").Observable<void>;
|
|
97
67
|
/**
|
|
98
68
|
* Get a new one time password
|
|
99
69
|
* @param id: the optional repository id
|
|
100
70
|
*/
|
|
101
|
-
newOTP(id: string): Observable<ApiResult<ClipperOTPInfo>>;
|
|
71
|
+
newOTP(id: string): import("rxjs").Observable<ApiResult<ClipperOTPInfo>>;
|
|
102
72
|
/**
|
|
103
73
|
* Load Ars events calendar
|
|
104
74
|
*/
|
|
105
|
-
events(params: ClipperQueryArsEventsParams): Observable<ApiResult<ClipperQueryArsEventsResult>>;
|
|
75
|
+
events(params: ClipperQueryArsEventsParams): import("rxjs").Observable<ApiResult<ClipperQueryArsEventsResult>>;
|
|
106
76
|
/**
|
|
107
77
|
* Query documents
|
|
108
78
|
*/
|
|
109
|
-
query(params: ClipperSearchParams): Observable<ApiResult<ClipperSearchResult>>;
|
|
79
|
+
query(params: ClipperSearchParams): import("rxjs").Observable<ApiResult<ClipperSearchResult>>;
|
|
110
80
|
/**
|
|
111
81
|
* Get facets for a query
|
|
112
82
|
*/
|
|
113
|
-
queryFacets(params: ClipperSearchParams): Observable<ApiResult<ClipperSearchFacetsResult>>;
|
|
83
|
+
queryFacets(params: ClipperSearchParams): import("rxjs").Observable<ApiResult<ClipperSearchFacetsResult>>;
|
|
114
84
|
/**
|
|
115
85
|
* Update document state
|
|
116
86
|
*/
|
|
117
|
-
updateState(params: ClipperDocumentUpdateStateParams): Observable<ApiResult<number>>;
|
|
87
|
+
updateState(params: ClipperDocumentUpdateStateParams): import("rxjs").Observable<ApiResult<number>>;
|
|
118
88
|
/**
|
|
119
89
|
* Export a document in pdf format
|
|
120
90
|
*/
|
|
121
|
-
exportPdf(id: string): Observable<Blob>;
|
|
91
|
+
exportPdf(id: string): import("rxjs").Observable<Blob>;
|
|
122
92
|
/**
|
|
123
93
|
* Export document list (query or selected items) or export deadlines as ics
|
|
124
94
|
*/
|
|
125
|
-
export(params: ClipperExportDocumentsParams): Observable<Blob>;
|
|
95
|
+
export(params: ClipperExportDocumentsParams): import("rxjs").Observable<Blob>;
|
|
126
96
|
/**
|
|
127
97
|
* Send documents link by email
|
|
128
98
|
*/
|
|
129
|
-
sendTo(params: ClipperSendDocumentsByEmailParams): Observable<ApiResult<number>>;
|
|
99
|
+
sendTo(params: ClipperSendDocumentsByEmailParams): import("rxjs").Observable<ApiResult<number>>;
|
|
130
100
|
/**
|
|
131
101
|
* Display a page the full document report
|
|
132
102
|
*/
|
|
133
|
-
report(id: string): Observable<Blob>;
|
|
103
|
+
report(id: string): import("rxjs").Observable<Blob>;
|
|
134
104
|
/**
|
|
135
105
|
* Get document comment
|
|
136
106
|
*/
|
|
137
|
-
comment(id: string): Observable<ApiResult<string>>;
|
|
107
|
+
comment(id: string): import("rxjs").Observable<ApiResult<string>>;
|
|
138
108
|
/**
|
|
139
109
|
* Get document info
|
|
140
110
|
*/
|
|
141
|
-
info(id: string): Observable<ApiResult<ClipperDocumentInfo>>;
|
|
111
|
+
info(id: string): import("rxjs").Observable<ApiResult<ClipperDocumentInfo>>;
|
|
142
112
|
/**
|
|
143
113
|
* Get document structure
|
|
144
114
|
*/
|
|
145
|
-
index(id: string): Observable<ApiResult<ClipperDocumentStructure>>;
|
|
115
|
+
index(id: string): import("rxjs").Observable<ApiResult<ClipperDocumentStructure>>;
|
|
146
116
|
/**
|
|
147
117
|
* Get document last update
|
|
148
118
|
*/
|
|
149
|
-
lastUpdate(id: string): Observable<ApiResult<string>>;
|
|
119
|
+
lastUpdate(id: string): import("rxjs").Observable<ApiResult<string>>;
|
|
150
120
|
/**
|
|
151
121
|
* Query document references
|
|
152
122
|
*/
|
|
153
|
-
references(params: ClipperReferencesSearchParams): Observable<ApiResult<ClipperSearchResult>>;
|
|
123
|
+
references(params: ClipperReferencesSearchParams): import("rxjs").Observable<ApiResult<ClipperSearchResult>>;
|
|
154
124
|
/**
|
|
155
125
|
* Get facets for a document references
|
|
156
126
|
*/
|
|
157
|
-
referencesFacets(params: ClipperReferencesSearchParams): Observable<ApiResult<ClipperSearchFacetsResult>>;
|
|
127
|
+
referencesFacets(params: ClipperReferencesSearchParams): import("rxjs").Observable<ApiResult<ClipperSearchFacetsResult>>;
|
|
158
128
|
/**
|
|
159
129
|
* Get document juris articles
|
|
160
130
|
*/
|
|
161
|
-
jurisArticles(params: ClipperSearchParams): Observable<ApiResult<ClipperSearchResult>>;
|
|
131
|
+
jurisArticles(params: ClipperSearchParams): import("rxjs").Observable<ApiResult<ClipperSearchResult>>;
|
|
162
132
|
/**
|
|
163
133
|
* Get calendar snapshot based on the deadlines
|
|
164
134
|
*/
|
|
165
|
-
calendarSnapshot(params: any): Observable<ApiResult<any>>;
|
|
135
|
+
calendarSnapshot(params: any): import("rxjs").Observable<ApiResult<any>>;
|
|
166
136
|
/**
|
|
167
137
|
* Retrieve the taxonomy
|
|
168
138
|
*/
|
|
169
|
-
getTaxonomy(params?: ClipperTaxonomyParams | null): Observable<ApiResult<FolderTree>>;
|
|
139
|
+
getTaxonomy(params?: ClipperTaxonomyParams | null): import("rxjs").Observable<ApiResult<FolderTree>>;
|
|
170
140
|
/**
|
|
171
141
|
* Retrieve topics
|
|
172
142
|
*/
|
|
173
|
-
getTopics(): Observable<ApiResult<NameValueItem<string>[]>>;
|
|
143
|
+
getTopics(): import("rxjs").Observable<ApiResult<NameValueItem<string>[]>>;
|
|
174
144
|
/**
|
|
175
145
|
* Retrieve tags
|
|
176
146
|
*/
|
|
177
|
-
getTags(): Observable<ApiResult<NameValueItem<string>[]>>;
|
|
147
|
+
getTags(): import("rxjs").Observable<ApiResult<NameValueItem<string>[]>>;
|
|
178
148
|
/**
|
|
179
149
|
* Retrieve current dashboard
|
|
180
150
|
*/
|
|
@@ -189,12 +159,12 @@ export declare class ClipperService implements OnDestroy {
|
|
|
189
159
|
* Save a user link
|
|
190
160
|
* @param item: the user link
|
|
191
161
|
*/
|
|
192
|
-
saveLink(item: ClipperUserLink): Observable<ApiResult<boolean>>;
|
|
162
|
+
saveLink(item: ClipperUserLink): import("rxjs").Observable<ApiResult<boolean>>;
|
|
193
163
|
/**
|
|
194
164
|
* Delete a user link
|
|
195
165
|
* @param item: the user link
|
|
196
166
|
*/
|
|
197
|
-
deleteLink(item: ClipperUserLink): Observable<ApiResult<boolean>>;
|
|
167
|
+
deleteLink(item: ClipperUserLink): import("rxjs").Observable<ApiResult<boolean>>;
|
|
198
168
|
/**
|
|
199
169
|
* Load working documents
|
|
200
170
|
*/
|
|
@@ -217,17 +187,17 @@ export declare class ClipperService implements OnDestroy {
|
|
|
217
187
|
* Load working searches
|
|
218
188
|
* @param: module: the module to load searches for
|
|
219
189
|
*/
|
|
220
|
-
loadSearches(module: ClipperModule): Observable<ApiResult<ClipperUserSearch[]>>;
|
|
190
|
+
loadSearches(module: ClipperModule): import("rxjs").Observable<ApiResult<ClipperUserSearch[]>>;
|
|
221
191
|
/**
|
|
222
192
|
* Save a working search
|
|
223
193
|
* @param documentIds : the document ids to add
|
|
224
194
|
*/
|
|
225
|
-
saveSearch(params: ClipperUserSearch): Observable<ApiResult<ClipperUserSearch>>;
|
|
195
|
+
saveSearch(params: ClipperUserSearch): import("rxjs").Observable<ApiResult<ClipperUserSearch>>;
|
|
226
196
|
/**
|
|
227
197
|
* Remove one working search
|
|
228
198
|
* @param id : the id to remove
|
|
229
199
|
*/
|
|
230
|
-
deleteSearch(id: number): Observable<ApiResult<number>>;
|
|
200
|
+
deleteSearch(id: number): import("rxjs").Observable<ApiResult<number>>;
|
|
231
201
|
static ɵfac: i0.ɵɵFactoryDeclaration<ClipperService, never>;
|
|
232
202
|
static ɵprov: i0.ɵɵInjectableDeclaration<ClipperService>;
|
|
233
203
|
}
|
|
@@ -1,49 +1,52 @@
|
|
|
1
|
+
import { HttpErrorResponse } from '@angular/common/http';
|
|
1
2
|
import { Injectable, inject } from '@angular/core';
|
|
2
3
|
import { DialogService } from '@arsedizioni/ars-utils/ui';
|
|
3
|
-
import { catchError, throwError } from 'rxjs';
|
|
4
|
+
import { catchError, switchMap, throwError } from 'rxjs';
|
|
4
5
|
import { ClipperService } from '../services/clipper.service';
|
|
6
|
+
import { BroadcastService } from '@arsedizioni/ars-utils/core';
|
|
7
|
+
import { ClipperMessages } from '../messages';
|
|
5
8
|
import * as i0 from "@angular/core";
|
|
6
9
|
export class ClipperAuthInterceptor {
|
|
7
10
|
constructor() {
|
|
8
11
|
this.clipperService = inject(ClipperService);
|
|
12
|
+
this.broadcastService = inject(BroadcastService);
|
|
9
13
|
this.dialogService = inject(DialogService);
|
|
10
14
|
}
|
|
11
15
|
intercept(request, next) {
|
|
12
16
|
if (request.url.startsWith(this.clipperService.serviceUri)) {
|
|
13
17
|
request = request.clone({ withCredentials: true });
|
|
14
18
|
return next.handle(this.addTokenToRequest(request))
|
|
15
|
-
.pipe(catchError(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
case 0:
|
|
21
|
-
case 500:
|
|
22
|
-
case 502:
|
|
23
|
-
case 503:
|
|
24
|
-
case 504:
|
|
25
|
-
message = null; // No messages
|
|
26
|
-
break;
|
|
27
|
-
case 403:
|
|
28
|
-
message = "<p>Non hai i permessi necessari per eseguire l'operazione richiesta.</p>";
|
|
29
|
-
break;
|
|
30
|
-
default:
|
|
31
|
-
message = '<p>' + message.replaceAll('\r\n', '</p><p>') + '</p>';
|
|
32
|
-
break;
|
|
19
|
+
.pipe(catchError(error => {
|
|
20
|
+
if (error instanceof HttpErrorResponse &&
|
|
21
|
+
!request.url.includes("/login") &&
|
|
22
|
+
error.status === 401) {
|
|
23
|
+
return this.handle401Error(request, next);
|
|
33
24
|
}
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
25
|
+
// Show a message
|
|
26
|
+
const invalidSession = error.status == "403";
|
|
27
|
+
this.dialogService.clearBusy();
|
|
28
|
+
this.dialogService.error("<p>" + (error.error?.message ?? error.message ?? "Impossibile eseguire l'operazione richiesta.").replaceAll("\r\n", "</p><p>") + "</p>", null, "Errore in Clipper", undefined, undefined, invalidSession ? 5000 : 15000).afterClosed().subscribe(() => {
|
|
29
|
+
if (invalidSession) {
|
|
30
|
+
this.clipperService.clear();
|
|
31
|
+
this.broadcastService.sendMessage(ClipperMessages.LOGOUT);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
return throwError(() => error);
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
37
|
+
return next.handle(request);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Handle 401 error
|
|
41
|
+
* @param request : the request
|
|
42
|
+
* @param next : the http handler
|
|
43
|
+
*/
|
|
44
|
+
handle401Error(request, next) {
|
|
45
|
+
if (this.clipperService.loggedIn()) {
|
|
46
|
+
return this.clipperService.refresh().pipe(switchMap(() => {
|
|
47
|
+
return next.handle(this.addTokenToRequest(request));
|
|
48
|
+
}), catchError(error => {
|
|
49
|
+
return throwError(() => error);
|
|
47
50
|
}));
|
|
48
51
|
}
|
|
49
52
|
return next.handle(request);
|
|
@@ -74,4 +77,4 @@ export class ClipperAuthInterceptor {
|
|
|
74
77
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.1.3", ngImport: i0, type: ClipperAuthInterceptor, decorators: [{
|
|
75
78
|
type: Injectable
|
|
76
79
|
}] });
|
|
77
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
80
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC5pbnRlcmNlcHRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2Fycy11dGlscy9jbGlwcGVyLmNvbW1vbi9jb21tb24vaW50ZXJjZXB0b3JzL2F1dGguaW50ZXJjZXB0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGlCQUFpQixFQUF3RCxNQUFNLHNCQUFzQixDQUFDO0FBQy9HLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ25ELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUMxRCxPQUFPLEVBQWMsVUFBVSxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDckUsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQzdELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQy9ELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxhQUFhLENBQUM7O0FBRzlDLE1BQU0sT0FBTyxzQkFBc0I7SUFEbkM7UUFFVSxtQkFBYyxHQUFHLE1BQU0sQ0FBQyxjQUFjLENBQUMsQ0FBQztRQUN4QyxxQkFBZ0IsR0FBRyxNQUFNLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztRQUM1QyxrQkFBYSxHQUFHLE1BQU0sQ0FBQyxhQUFhLENBQUMsQ0FBQztLQWtGL0M7SUEvRUMsU0FBUyxDQUNQLE9BQXlCLEVBQ3pCLElBQWlCO1FBRWpCLElBQUksT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO1lBQzNELE9BQU8sR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDLEVBQUUsZUFBZSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7WUFDbkQsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLElB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RCxPQUFPLE9BQU8sQ0FBQztJQUNqQixDQUFDOzhHQW5GVSxzQkFBc0I7a0hBQXRCLHNCQUFzQjs7MkZBQXRCLHNCQUFzQjtrQkFEbEMsVUFBVSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEh0dHBFcnJvclJlc3BvbnNlLCBIdHRwRXZlbnQsIEh0dHBIYW5kbGVyLCBIdHRwSW50ZXJjZXB0b3IsIEh0dHBSZXF1ZXN0IH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnO1xyXG5pbXBvcnQgeyBJbmplY3RhYmxlLCBpbmplY3QgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgRGlhbG9nU2VydmljZSB9IGZyb20gJ0BhcnNlZGl6aW9uaS9hcnMtdXRpbHMvdWknO1xyXG5pbXBvcnQgeyBPYnNlcnZhYmxlLCBjYXRjaEVycm9yLCBzd2l0Y2hNYXAsIHRocm93RXJyb3IgfSBmcm9tICdyeGpzJztcclxuaW1wb3J0IHsgQ2xpcHBlclNlcnZpY2UgfSBmcm9tICcuLi9zZXJ2aWNlcy9jbGlwcGVyLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBCcm9hZGNhc3RTZXJ2aWNlIH0gZnJvbSAnQGFyc2VkaXppb25pL2Fycy11dGlscy9jb3JlJztcclxuaW1wb3J0IHsgQ2xpcHBlck1lc3NhZ2VzIH0gZnJvbSAnLi4vbWVzc2FnZXMnO1xyXG5cclxuQEluamVjdGFibGUoKVxyXG5leHBvcnQgY2xhc3MgQ2xpcHBlckF1dGhJbnRlcmNlcHRvciBpbXBsZW1lbnRzIEh0dHBJbnRlcmNlcHRvciB7XHJcbiAgcHJpdmF0ZSBjbGlwcGVyU2VydmljZSA9IGluamVjdChDbGlwcGVyU2VydmljZSk7XHJcbiAgcHJpdmF0ZSBicm9hZGNhc3RTZXJ2aWNlID0gaW5qZWN0KEJyb2FkY2FzdFNlcnZpY2UpO1xyXG4gIHByaXZhdGUgZGlhbG9nU2VydmljZSA9IGluamVjdChEaWFsb2dTZXJ2aWNlKTtcclxuXHJcblxyXG4gIGludGVyY2VwdChcclxuICAgIHJlcXVlc3Q6IEh0dHBSZXF1ZXN0PGFueT4sXHJcbiAgICBuZXh0OiBIdHRwSGFuZGxlclxyXG4gICk6IE9ic2VydmFibGU8SHR0cEV2ZW50PGFueT4+IHtcclxuICAgIGlmIChyZXF1ZXN0LnVybC5zdGFydHNXaXRoKHRoaXMuY2xpcHBlclNlcnZpY2Uuc2VydmljZVVyaSkpIHtcclxuICAgICAgcmVxdWVzdCA9IHJlcXVlc3QuY2xvbmUoeyB3aXRoQ3JlZGVudGlhbHM6IHRydWUgfSk7XHJcbiAgICAgIHJldHVybiBuZXh0LmhhbmRsZSh0aGlzLmFkZFRva2VuVG9SZXF1ZXN0KHJlcXVlc3QpKVxyXG4gICAgICAgIC5waXBlKFxyXG4gICAgICAgICAgY2F0Y2hFcnJvcihlcnJvciA9PiB7XHJcbiAgICAgICAgICAgIGlmIChcclxuICAgICAgICAgICAgICBlcnJvciBpbnN0YW5jZW9mIEh0dHBFcnJvclJlc3BvbnNlICYmXHJcbiAgICAgICAgICAgICAgIXJlcXVlc3QudXJsLmluY2x1ZGVzKFwiL2xvZ2luXCIpICYmXHJcbiAgICAgICAgICAgICAgZXJyb3Iuc3RhdHVzID09PSA0MDFcclxuICAgICAgICAgICAgKSB7XHJcbiAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuaGFuZGxlNDAxRXJyb3IocmVxdWVzdCwgbmV4dCk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgLy8gU2hvdyBhIG1lc3NhZ2VcclxuICAgICAgICAgICAgY29uc3QgaW52YWxpZFNlc3Npb24gPSBlcnJvci5zdGF0dXMgPT0gXCI0MDNcIjtcclxuICAgICAgICAgICAgdGhpcy5kaWFsb2dTZXJ2aWNlLmNsZWFyQnVzeSgpO1xyXG4gICAgICAgICAgICB0aGlzLmRpYWxvZ1NlcnZpY2UuZXJyb3IoXHJcbiAgICAgICAgICAgICAgXCI8cD5cIiArIChlcnJvci5lcnJvcj8ubWVzc2FnZSA/PyBlcnJvci5tZXNzYWdlID8/IFwiSW1wb3NzaWJpbGUgZXNlZ3VpcmUgbCdvcGVyYXppb25lIHJpY2hpZXN0YS5cIikucmVwbGFjZUFsbChcIlxcclxcblwiLCBcIjwvcD48cD5cIikgKyBcIjwvcD5cIixcclxuICAgICAgICAgICAgICBudWxsLFxyXG4gICAgICAgICAgICAgIFwiRXJyb3JlIGluIENsaXBwZXJcIixcclxuICAgICAgICAgICAgICB1bmRlZmluZWQsXHJcbiAgICAgICAgICAgICAgdW5kZWZpbmVkLFxyXG4gICAgICAgICAgICAgIGludmFsaWRTZXNzaW9uID8gNTAwMCA6IDE1MDAwKS5hZnRlckNsb3NlZCgpLnN1YnNjcmliZSgoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICBpZiAoaW52YWxpZFNlc3Npb24pIHtcclxuICAgICAgICAgICAgICAgICAgdGhpcy5jbGlwcGVyU2VydmljZS5jbGVhcigpO1xyXG4gICAgICAgICAgICAgICAgICB0aGlzLmJyb2FkY2FzdFNlcnZpY2Uuc2VuZE1lc3NhZ2UoQ2xpcHBlck1lc3NhZ2VzLkxPR09VVCk7ICAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgcmV0dXJuIHRocm93RXJyb3IoKCkgPT4gZXJyb3IpO1xyXG4gICAgICAgICAgfSkpO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIG5leHQuaGFuZGxlKHJlcXVlc3QpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogSGFuZGxlIDQwMSBlcnJvclxyXG4gICAqIEBwYXJhbSByZXF1ZXN0IDogdGhlIHJlcXVlc3RcclxuICAgKiBAcGFyYW0gbmV4dCA6IHRoZSBodHRwIGhhbmRsZXJcclxuICAgKi9cclxuICBwcml2YXRlIGhhbmRsZTQwMUVycm9yKHJlcXVlc3Q6IEh0dHBSZXF1ZXN0PGFueT4sIG5leHQ6IEh0dHBIYW5kbGVyKSB7XHJcbiAgICBpZiAodGhpcy5jbGlwcGVyU2VydmljZS5sb2dnZWRJbigpKSB7XHJcbiAgICAgIHJldHVybiB0aGlzLmNsaXBwZXJTZXJ2aWNlLnJlZnJlc2goKS5waXBlKFxyXG4gICAgICAgIHN3aXRjaE1hcCgoKSA9PiB7XHJcbiAgICAgICAgICByZXR1cm4gbmV4dC5oYW5kbGUodGhpcy5hZGRUb2tlblRvUmVxdWVzdChyZXF1ZXN0KSk7XHJcbiAgICAgICAgfSksXHJcbiAgICAgICAgY2F0Y2hFcnJvcihlcnJvciA9PiB7XHJcbiAgICAgICAgICByZXR1cm4gdGhyb3dFcnJvcigoKSA9PiBlcnJvcik7XHJcbiAgICAgICAgfSlcclxuICAgICAgKTtcclxuICAgIH1cclxuICAgIHJldHVybiBuZXh0LmhhbmRsZShyZXF1ZXN0KTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEFkZCB0b2tlbiB0byByZXF1ZXN0XHJcbiAgICogQHBhcmFtIHJlcXVlc3QgOiB0aGUgcmVxdWVzdFxyXG4gICAqIEBwYXJhbSB0b2tlbjogdGhlIHRva2VuIG9yIG51bGwgdG8gdXNlIGN1cnJlM250XHJcbiAgICovXHJcbiAgcHJpdmF0ZSBhZGRUb2tlblRvUmVxdWVzdChcclxuICAgIHJlcXVlc3Q6IEh0dHBSZXF1ZXN0PGFueT4sXHJcbiAgICB0b2tlbjogc3RyaW5nIHwgbnVsbCA9IG51bGxcclxuICApOiBIdHRwUmVxdWVzdDxhbnk+IHtcclxuICAgIGlmIChyZXF1ZXN0LnVybC5zdGFydHNXaXRoKHRoaXMuY2xpcHBlclNlcnZpY2Uuc2VydmljZVVyaSkpIHtcclxuICAgICAgaWYgKCF0b2tlbikgdG9rZW4gPSB0aGlzLmNsaXBwZXJTZXJ2aWNlLmdldFRva2VuKCk7XHJcbiAgICAgIGlmICh0b2tlbikge1xyXG4gICAgICAgIHJldHVybiByZXF1ZXN0LmNsb25lKHtcclxuICAgICAgICAgIHNldEhlYWRlcnM6IHtcclxuICAgICAgICAgICAgQXV0aG9yaXphdGlvbjogJ0JlYXJlciAnICsgdG9rZW4sXHJcbiAgICAgICAgICAgICduZ3N3LWJ5cGFzcyc6ICduZ3N3LWJ5cGFzcydcclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIHJldHVybiByZXF1ZXN0O1xyXG4gIH1cclxuXHJcbn1cclxuIl19
|