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