@esfaenza/httpservice 16.2.26 → 17.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/esfaenza-httpservice.mjs +4 -4
- package/esm2022/lib/config/HttpServiceExtensions.mjs +86 -86
- package/esm2022/lib/config/HttpServiceModuleConfig.mjs +5 -5
- package/esm2022/lib/config/IHttpServiceExtensions.mjs +1 -1
- package/esm2022/lib/httpservice.module.mjs +22 -22
- package/esm2022/lib/httpservice.service.mjs +842 -842
- package/esm2022/lib/models/CacheInfos.mjs +9 -9
- package/esm2022/lib/models/Download.mjs +2 -2
- package/esm2022/lib/tokens.mjs +21 -21
- package/esm2022/public-api.mjs +10 -10
- package/fesm2022/esfaenza-httpservice.mjs +962 -962
- package/fesm2022/esfaenza-httpservice.mjs.map +1 -1
- package/index.d.ts +5 -5
- package/lib/config/HttpServiceExtensions.d.ts +65 -65
- package/lib/config/HttpServiceModuleConfig.d.ts +25 -25
- package/lib/config/IHttpServiceExtensions.d.ts +61 -61
- package/lib/httpservice.module.d.ts +9 -9
- package/lib/httpservice.service.d.ts +379 -379
- package/lib/models/CacheInfos.d.ts +8 -8
- package/lib/models/Download.d.ts +5 -5
- package/lib/tokens.d.ts +21 -21
- package/package.json +7 -7
- package/public-api.d.ts +7 -7
|
@@ -1,842 +1,842 @@
|
|
|
1
|
-
// Angular
|
|
2
|
-
import { HttpErrorResponse, HttpEventType, HttpHeaders, HttpParams } from "@angular/common/http";
|
|
3
|
-
import { Injectable, Inject, Optional } from "@angular/core";
|
|
4
|
-
// Direttive, Componenti, Librerie
|
|
5
|
-
import { catchError, concatMap, delay, finalize, first, map, scan } from "rxjs/operators";
|
|
6
|
-
import { forkJoin, from, Observable, of, Subject, throwError } from "rxjs";
|
|
7
|
-
// Chiamate ai Repository / tokens
|
|
8
|
-
import { HTTP_INVALIDATION, CLIENT_CACHE_DURATION_S, CACHE_BY_USER, HTTP_DEBUG_MODE } from './tokens';
|
|
9
|
-
// Modelli
|
|
10
|
-
import { HttpServiceExtensions } from './config/HttpServiceExtensions';
|
|
11
|
-
import { CacheInfos } from "./models/CacheInfos";
|
|
12
|
-
import * as i0 from "@angular/core";
|
|
13
|
-
import * as i1 from "./config/HttpServiceExtensions";
|
|
14
|
-
import * as i2 from "@esfaenza/localizations";
|
|
15
|
-
import * as i3 from "@angular/common/http";
|
|
16
|
-
import * as i4 from "@esfaenza/preferences";
|
|
17
|
-
import * as i5 from "@esfaenza/extensions";
|
|
18
|
-
/**
|
|
19
|
-
* Servizio utilizzato per effettuare qualsiasi tipo di chiamata HTTP dall'applicazione, gestisce errori e cache delle risposte nativamente e ne può essere
|
|
20
|
-
* esteso/modificato il comportamento implementando la classe di "hook" **IHttpServiceExtensions** e registrandola nel provider della classe **HttpServiceExtensions**
|
|
21
|
-
*/
|
|
22
|
-
export class HTTPService {
|
|
23
|
-
/**
|
|
24
|
-
* @ignore
|
|
25
|
-
*/
|
|
26
|
-
constructor(EXTENSION_CLASS, HTTP_INVALIDATION, CLIENT_CACHE_DURATION_S, CACHE_BY_USER, HTTP_DEBUG_MODE, bc, http, localStorage, hash, utisExts) {
|
|
27
|
-
this.EXTENSION_CLASS = EXTENSION_CLASS;
|
|
28
|
-
this.HTTP_INVALIDATION = HTTP_INVALIDATION;
|
|
29
|
-
this.CLIENT_CACHE_DURATION_S = CLIENT_CACHE_DURATION_S;
|
|
30
|
-
this.CACHE_BY_USER = CACHE_BY_USER;
|
|
31
|
-
this.HTTP_DEBUG_MODE = HTTP_DEBUG_MODE;
|
|
32
|
-
this.bc = bc;
|
|
33
|
-
this.http = http;
|
|
34
|
-
this.localStorage = localStorage;
|
|
35
|
-
this.hash = hash;
|
|
36
|
-
this.utisExts = utisExts;
|
|
37
|
-
/** Cache dello stato delle chiamate HTTP attualmente effettuate. Ogni chiamata è rappresentata da un GUID e lo status assume valore **false** solo sugli errori */
|
|
38
|
-
this.callStatus = {};
|
|
39
|
-
/** Nome della cache in cui vengono storicizzate le informazioni sulle risposte delle chiamate sotto forma di dictionary */
|
|
40
|
-
this.localStorageHttpCacheKey = null;
|
|
41
|
-
/** Nome della cache in cui vengono storicizzate le informazioni sulle risposte delle chiamate sotto forma di dictionary, solo per le chiamate con un tempo definito di caching */
|
|
42
|
-
this.localStorageHttpTimedCacheKey = null;
|
|
43
|
-
/** Nome della cache in cui vengono storicizzate le informazioni sullo scadere della cache stessa */
|
|
44
|
-
this.localStorageHttpCacheExpireKey = null;
|
|
45
|
-
/** Identità collegata al token di autenticazione da usare, richiesta al programma che utilizza la libreria attraverso l'hook **retrieveIdentity** della **HttpServiceExtensions** */
|
|
46
|
-
this.me = null;
|
|
47
|
-
/** Indica che la cache a tempo dev'essere persistita il prima possibile */
|
|
48
|
-
this.PersistTimedCacheASAP = false;
|
|
49
|
-
/** Indica che la cache senza limiti di tempo dev'essere persistita il prima possibile */
|
|
50
|
-
this.PersistUntimedCacheASAP = false;
|
|
51
|
-
/** Subject emesso quando il servizio http si stabilizza, cioè quando non c'è nessuna chiamata pending o in corso da qualche istante */
|
|
52
|
-
this.Stabilized = new Subject();
|
|
53
|
-
/** Lista delle ultime 3 chiamate completate con successo in ordine di completamento (in posizione 0 c'è l'ultima completata eccetera...) */
|
|
54
|
-
this.LastThreeCompletedCalls = [];
|
|
55
|
-
this.CacheInitialized = false;
|
|
56
|
-
/*****************************************************************************************************************************************
|
|
57
|
-
***************************************************** TRANSACTION HELPERS ***************************************************************
|
|
58
|
-
*****************************************************************************************************************************************/
|
|
59
|
-
this.GET_Trans_BeginTrans = "/api/Trans/BeginTrans";
|
|
60
|
-
this.GET_Trans_CheckExecution = "/api/Trans/CheckExecution";
|
|
61
|
-
this.GET_Trans_EndTrans = "/api/Trans/EndTrans";
|
|
62
|
-
this.ExtensionsImpl = this.EXTENSION_CLASS || new HttpServiceExtensions();
|
|
63
|
-
}
|
|
64
|
-
setAppConfig(myconfig) {
|
|
65
|
-
this.localStorageHttpCacheKey = (myconfig.AppData.ModuleDescription).replace(/\s/g, '_') + "_HttpCache";
|
|
66
|
-
this.localStorageHttpTimedCacheKey = (myconfig.AppData.ModuleDescription).replace(/\s/g, '_') + "_HttpTimedCache";
|
|
67
|
-
this.localStorageHttpCacheExpireKey = this.localStorageHttpCacheKey + "_Expire";
|
|
68
|
-
this.adjustOldStorageSystem();
|
|
69
|
-
this.CacheInitialized = true;
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Se vedo che ci sono elementi salvati nel localStorage provo a toglierli e a risalvarli via preference.
|
|
73
|
-
* Nel caso migliore li sposto dal localStorage al DB di preference, nel caso peggiore li tolgo e li risalvo nel localStorage
|
|
74
|
-
*/
|
|
75
|
-
async adjustOldStorageSystem() {
|
|
76
|
-
var lsTimed = localStorage.getItem(this.localStorageHttpTimedCacheKey);
|
|
77
|
-
var lsUntimed = localStorage.getItem(this.localStorageHttpCacheKey);
|
|
78
|
-
if (!lsTimed && !lsUntimed)
|
|
79
|
-
return;
|
|
80
|
-
localStorage.removeItem(this.localStorageHttpTimedCacheKey);
|
|
81
|
-
localStorage.removeItem(this.localStorageHttpCacheKey);
|
|
82
|
-
lsTimed = lsTimed ? JSON.parse(lsTimed) : {};
|
|
83
|
-
lsUntimed = lsUntimed ? JSON.parse(lsUntimed) : {};
|
|
84
|
-
await forkJoin([
|
|
85
|
-
this.localStorage.setItem(this.localStorageHttpTimedCacheKey, lsTimed),
|
|
86
|
-
this.localStorage.setItem(this.localStorageHttpCacheKey, lsUntimed)
|
|
87
|
-
]).toPromise();
|
|
88
|
-
this.log(this.loc("Converted old storage system to new one"));
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Esecuzione di una GET HTTP con eventualmente la gestione della cache qualora la chiamata termini con la convenzione "#cache"
|
|
92
|
-
*
|
|
93
|
-
* @param {string} url URL su cui effettuare la chiamata
|
|
94
|
-
* @param {HttpParams} params Parametri della chiamata
|
|
95
|
-
* @param {string} transaction Codice transazione collegato a questa chiamata. Viene inserito nell'Header "X-TX-ID" e lato Backend dovrà essere gestito di conseguenza
|
|
96
|
-
* @param {boolean} succesfulResultMandatory Indica che questa chiamata deve assolutamente andare bene. In caso contrario viene fisicamente fatto il throw che può essere
|
|
97
|
-
* raccolto da chi usa la libreria nella pipe "onError" dell'Observable restituito ed essere gestito in maniera non standard
|
|
98
|
-
* @param {Function} errorCallback Callback chiamato in caso di errore
|
|
99
|
-
*
|
|
100
|
-
* @returns {Observable<T>} Observable che contiene il risultato della chiamata
|
|
101
|
-
*/
|
|
102
|
-
get(url, params = null, transaction = "", succesfulResultMandatory = true, errorCallback = null) {
|
|
103
|
-
return forkJoin({
|
|
104
|
-
myGuid: from([this.defaultStartCall(url)]),
|
|
105
|
-
locale: this.bc.Locale.pipe(first())
|
|
106
|
-
}).pipe(concatMap((ret) => {
|
|
107
|
-
let cachedInfos = this.tryGetCacheInformations(url, params);
|
|
108
|
-
if (cachedInfos.cache && cachedInfos.cacheItem) {
|
|
109
|
-
this.log(this.loc("Result for") + " " + url + " " + this.loc("retrieved from cache"));
|
|
110
|
-
return of(cachedInfos.cacheItem).pipe(delay(0), finalize(() => { this.tryFinalizeByGuid(ret.myGuid); }));
|
|
111
|
-
}
|
|
112
|
-
var httpCall = this.http.get(cachedInfos.finalUrl, { headers: this.getHeaders(ret.locale, transaction), params: params });
|
|
113
|
-
return httpCall.pipe(map((res) => {
|
|
114
|
-
let responseItem = res;
|
|
115
|
-
if (cachedInfos.cache) {
|
|
116
|
-
this.cacheResponse(this.utisExts.deepClone(responseItem), cachedInfos);
|
|
117
|
-
this.log(this.loc("Cached result for") + " " + url);
|
|
118
|
-
}
|
|
119
|
-
return responseItem;
|
|
120
|
-
}), catchError((err, caught) => {
|
|
121
|
-
if (errorCallback)
|
|
122
|
-
errorCallback();
|
|
123
|
-
return !succesfulResultMandatory ? throwError(err) : this.registerErrorAndReturnEmptyObservable(err, ret.myGuid);
|
|
124
|
-
}), finalize(() => { this.tryFinalizeByGuid(ret.myGuid, cachedInfos); }));
|
|
125
|
-
}));
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* Esecuzione di una GET HTTP con eventualmente la gestione della cache qualora la chiamata termini con la convenzione "#cache"
|
|
129
|
-
*
|
|
130
|
-
* Caso specifico di chiamata che deve restituire un Blob o un ArrayBuffer nativo da elaborare
|
|
131
|
-
*
|
|
132
|
-
* @param {string} url URL su cui effettuare la chiamata
|
|
133
|
-
* @param {HttpParams} params Parametri della chiamata
|
|
134
|
-
* @param {"arraybuffer"| "blob"} type Tipo di ritorno richiesto
|
|
135
|
-
* @param {string} transaction Codice transazione collegato a questa chiamata. Viene inserito nell'Header "X-TX-ID" e lato Backend dovrà essere gestito di conseguenza
|
|
136
|
-
* @param {boolean} succesfulResultMandatory Indica che questa chiamata deve assolutamente andare bene. In caso contrario viene fisicamente fatto il throw che può essere
|
|
137
|
-
* raccolto da chi usa la libreria nella pipe "onError" dell'Observable restituito ed essere gestito in maniera non standard
|
|
138
|
-
* @param {Function} errorCallback Callback chiamato in caso di errore
|
|
139
|
-
*
|
|
140
|
-
* @returns {Observable<Blob | ArrayBuffer>} Observable che contiene il risultato della chiamata
|
|
141
|
-
*/
|
|
142
|
-
getRaw(url, params = null, type = "arraybuffer", transaction = "", succesfulResultMandatory = true, errorCallback = null) {
|
|
143
|
-
return forkJoin({
|
|
144
|
-
myGuid: from([this.defaultStartCall(url)]),
|
|
145
|
-
locale: this.bc.Locale.pipe(first())
|
|
146
|
-
}).pipe(concatMap((ret) => {
|
|
147
|
-
let cachedInfos = this.tryGetCacheInformations(url, params);
|
|
148
|
-
if (cachedInfos.cache && cachedInfos.cacheItem) {
|
|
149
|
-
this.log(this.loc("Result for") + " " + url + " " + this.loc("retrieved from cache"));
|
|
150
|
-
return of(cachedInfos.cacheItem).pipe(delay(0), finalize(() => { this.tryFinalizeByGuid(ret.myGuid); }));
|
|
151
|
-
}
|
|
152
|
-
var httpCall = this.http.get(cachedInfos.finalUrl, { responseType: type, headers: this.getHeaders(ret.locale, transaction), params: params });
|
|
153
|
-
return httpCall.pipe(map((blob) => {
|
|
154
|
-
if (cachedInfos.cache) {
|
|
155
|
-
this.cacheResponse(blob, cachedInfos);
|
|
156
|
-
this.log(this.loc("Cached result for") + " " + url);
|
|
157
|
-
}
|
|
158
|
-
return blob;
|
|
159
|
-
}), catchError((err, caught) => {
|
|
160
|
-
if (errorCallback)
|
|
161
|
-
errorCallback();
|
|
162
|
-
return !succesfulResultMandatory ? throwError(err) : this.registerErrorAndReturnEmptyObservable(err, ret.myGuid);
|
|
163
|
-
}), finalize(() => { this.tryFinalizeByGuid(ret.myGuid, cachedInfos); }));
|
|
164
|
-
}));
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Esecuzione di una POST HTTP
|
|
168
|
-
*
|
|
169
|
-
* @param {string} url URL su cui effettuare la chiamata
|
|
170
|
-
* @param {any} bodyData DTO per la chiamata
|
|
171
|
-
* @param {HttpParams} params Parametri della chiamata
|
|
172
|
-
* @param {string} transaction Codice transazione collegato a questa chiamata. Viene inserito nell'Header "X-TX-ID" e lato Backend dovrà essere gestito di conseguenza
|
|
173
|
-
* @param {boolean} succesfulResultMandatory Indica che questa chiamata deve assolutamente andare bene. In caso contrario viene fisicamente fatto il throw che può essere
|
|
174
|
-
* raccolto da chi usa la libreria nella pipe "onError" dell'Observable restituito ed essere gestito in maniera non standard
|
|
175
|
-
*
|
|
176
|
-
* @returns {Observable<T>} Observable che contiene il risultato della chiamata
|
|
177
|
-
*/
|
|
178
|
-
post(url, bodyData, params = null, transaction = "", succesfulResultMandatory = true) {
|
|
179
|
-
return forkJoin({
|
|
180
|
-
myGuid: from([this.defaultStartCall(url)]),
|
|
181
|
-
locale: this.bc.Locale.pipe(first())
|
|
182
|
-
}).pipe(concatMap((ret) => {
|
|
183
|
-
// Se è una ricerca, shallow copy e rimuovo gli "items" per evitare di farli andare su e giù al backend
|
|
184
|
-
if (!!bodyData?.items && !!bodyData?.page) {
|
|
185
|
-
bodyData = { ...bodyData };
|
|
186
|
-
delete bodyData.items;
|
|
187
|
-
}
|
|
188
|
-
var httpCall = this.http.post(url, bodyData, { headers: this.getHeaders(ret.locale, transaction), params: params });
|
|
189
|
-
return httpCall.pipe(catchError((err, _) => {
|
|
190
|
-
return !succesfulResultMandatory ? throwError(err) : this.registerErrorAndReturnEmptyObservable(err, ret.myGuid);
|
|
191
|
-
}), finalize(() => { this.tryFinalizeByGuid(ret.myGuid); }));
|
|
192
|
-
}));
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* Esecuzione di una DELETE HTTP
|
|
196
|
-
*
|
|
197
|
-
* @param {string} url URL su cui effettuare la chiamata
|
|
198
|
-
* @param {HttpParams} params Parametri della chiamata
|
|
199
|
-
* @param {string} transaction Codice transazione collegato a questa chiamata. Viene inserito nell'Header "X-TX-ID" e lato Backend dovrà essere gestito di conseguenza
|
|
200
|
-
* @param {boolean} succesfulResultMandatory Indica che questa chiamata deve assolutamente andare bene. In caso contrario viene fisicamente fatto il throw che può essere
|
|
201
|
-
* raccolto da chi usa la libreria nella pipe "onError" dell'Observable restituito ed essere gestito in maniera non standard
|
|
202
|
-
*
|
|
203
|
-
* @returns {Observable<T>} Observable che contiene il risultato della chiamata
|
|
204
|
-
*/
|
|
205
|
-
delete(url, params = null, transaction = "", succesfulResultMandatory = true) {
|
|
206
|
-
return forkJoin({
|
|
207
|
-
myGuid: from([this.defaultStartCall(url)]),
|
|
208
|
-
locale: this.bc.Locale.pipe(first())
|
|
209
|
-
}).pipe(concatMap((ret) => {
|
|
210
|
-
var httpCall = this.http.delete(url, { headers: this.getHeaders(ret.locale, transaction), params: params });
|
|
211
|
-
return httpCall.pipe(catchError((err, caught) => {
|
|
212
|
-
return !succesfulResultMandatory ? throwError(err) : this.registerErrorAndReturnEmptyObservable(err, ret.myGuid);
|
|
213
|
-
}), finalize(() => { this.tryFinalizeByGuid(ret.myGuid); }));
|
|
214
|
-
}));
|
|
215
|
-
}
|
|
216
|
-
/**
|
|
217
|
-
* Esecuzione di una PUT HTTP
|
|
218
|
-
*
|
|
219
|
-
* @param {string} url URL su cui effettuare la chiamata
|
|
220
|
-
* @param {any} bodyData DTO per la chiamata
|
|
221
|
-
* @param {HttpParams} params Parametri della chiamata
|
|
222
|
-
* @param {string} transaction Codice transazione collegato a questa chiamata. Viene inserito nell'Header "X-TX-ID" e lato Backend dovrà essere gestito di conseguenza
|
|
223
|
-
* @param {boolean} succesfulResultMandatory Indica che questa chiamata deve assolutamente andare bene. In caso contrario viene fisicamente fatto il throw che può essere
|
|
224
|
-
* raccolto da chi usa la libreria nella pipe "onError" dell'Observable restituito ed essere gestito in maniera non standard
|
|
225
|
-
*
|
|
226
|
-
* @returns {Observable<T>} Observable che contiene il risultato della chiamata
|
|
227
|
-
*/
|
|
228
|
-
put(url, bodyData, params = null, transaction = "", succesfulResultMandatory = true) {
|
|
229
|
-
return forkJoin({
|
|
230
|
-
myGuid: from([this.defaultStartCall(url)]),
|
|
231
|
-
locale: this.bc.Locale.pipe(first())
|
|
232
|
-
}).pipe(concatMap((ret) => {
|
|
233
|
-
var httpCall = this.http.put(url, bodyData, { headers: this.getHeaders(ret.locale, transaction), params: params });
|
|
234
|
-
return httpCall.pipe(catchError((err, caught) => {
|
|
235
|
-
return !succesfulResultMandatory ? throwError(err) : this.registerErrorAndReturnEmptyObservable(err, ret.myGuid);
|
|
236
|
-
}), finalize(() => { this.tryFinalizeByGuid(ret.myGuid); }));
|
|
237
|
-
}));
|
|
238
|
-
}
|
|
239
|
-
/**
|
|
240
|
-
* Esecuzione di una POST HTTP
|
|
241
|
-
*
|
|
242
|
-
* Casistica particolare in cui bisogna anche inviare dei File
|
|
243
|
-
*
|
|
244
|
-
* @param {string} url URL su cui effettuare la chiamata
|
|
245
|
-
* @param {any} bodyData DTO per la chiamata
|
|
246
|
-
* @param {File[] | File} fileArrayOrFile Singolo file o lista di file da inviare. Il tipo **File** è quello nativo del Javascript
|
|
247
|
-
*
|
|
248
|
-
* @returns {Observable<T>} Observable che contiene il risultato della chiamata
|
|
249
|
-
*/
|
|
250
|
-
postwithFiles(url, bodyData, fileArrayOrFile, params = null, succesfulResultMandatory = true, onError) {
|
|
251
|
-
return forkJoin({
|
|
252
|
-
myGuid: from([this.defaultStartCall(url)]),
|
|
253
|
-
locale: this.bc.Locale.pipe(first())
|
|
254
|
-
}).pipe(concatMap((ret) => {
|
|
255
|
-
var formData = this.getFilesFormData(fileArrayOrFile);
|
|
256
|
-
formData.append("body", JSON.stringify(bodyData));
|
|
257
|
-
var httpCall = this.http.post(url, formData, { params: params, headers: this.getHeaders(ret.locale, null, true, null, null) });
|
|
258
|
-
return httpCall.pipe(catchError((err, caught) => {
|
|
259
|
-
onError?.();
|
|
260
|
-
return !succesfulResultMandatory ? throwError(err) : this.registerErrorAndReturnEmptyObservable(err, ret.myGuid);
|
|
261
|
-
}), finalize(() => { this.tryFinalizeByGuid(ret.myGuid); }));
|
|
262
|
-
}));
|
|
263
|
-
}
|
|
264
|
-
/**
|
|
265
|
-
* Esecuzione di una POST HTTP
|
|
266
|
-
*
|
|
267
|
-
* Casistica particolare in cui viene restituito un file gestito come ObjectURL il cui URL si può gestire dal parametro di callback **getFileCallback**.
|
|
268
|
-
* La chiamata non ha un tipo restituito in quanto il risultato dev'essere gestito attraverso la callback **getFileCallback**
|
|
269
|
-
*
|
|
270
|
-
* @param {string} url URL su cui effettuare la chiamata
|
|
271
|
-
* @param {K} bodyData DTO per la chiamata
|
|
272
|
-
* @param {string} filename Nome del file che si sta richiedendo, rimane lato Frontend e serve per assegnare arbitrariamente un nome al file restituito, se vuoto viene utilizzata la Content-Disposition della risposta
|
|
273
|
-
* @param {Function} getFileCallback Callback a due parametri (url: string, filename: string) per gestire il risultato del file richiesto. **Utilizzare UtilityService.fileDownload** di @esfaenza/extensions
|
|
274
|
-
* @param {Function} afterGetFile Callback da chiamare dopo aver gestito la risposta del **getFileCallback**, in caso **handleError** fosse **false** verrà richiamato anche in caso di errore
|
|
275
|
-
* @param {boolean} handleError Indica se di default gli errori devono essere gestiti dalla libreria o se devono essere ignorati
|
|
276
|
-
*/
|
|
277
|
-
async postGetFile(url, bodyData, filename, getFileCallback, afterGetFile = null, handleError = true, pars) {
|
|
278
|
-
let myGuid = this.defaultStartCall(url);
|
|
279
|
-
let locale = await this.bc.Locale.pipe(first()).toPromise();
|
|
280
|
-
this.http.post(url, bodyData, { params: pars, headers: this.getHeaders(locale), observe: 'response', responseType: "blob" }).pipe(catchError((err, caught) => {
|
|
281
|
-
if (afterGetFile && !handleError)
|
|
282
|
-
afterGetFile();
|
|
283
|
-
return this.registerErrorAndReturnEmptyObservable(err, myGuid, handleError);
|
|
284
|
-
}), finalize(() => { this.tryFinalizeByGuid(myGuid); })).subscribe((response) => {
|
|
285
|
-
let retUrl = window.URL.createObjectURL(response.body);
|
|
286
|
-
let fn = response.headers.get('content-disposition')?.split(';')[1]?.split('filename')[1]?.split('=')[1]?.trim().replace(/\"/g, '');
|
|
287
|
-
getFileCallback(retUrl, filename || fn);
|
|
288
|
-
if (afterGetFile)
|
|
289
|
-
afterGetFile();
|
|
290
|
-
});
|
|
291
|
-
}
|
|
292
|
-
/**
|
|
293
|
-
* Esecuzione di una GET HTTP
|
|
294
|
-
*
|
|
295
|
-
* Casistica particolare in cui viene restituito un file gestito come ObjectURL il cui URL si può gestire dal parametro di callback **getFileCallback**.
|
|
296
|
-
* La chiamata non ha un tipo restituito in quanto il risultato dev'essere gestito attraverso la callback **getFileCallback**
|
|
297
|
-
*
|
|
298
|
-
* @param {string} url URL su cui effettuare la chiamata
|
|
299
|
-
* @param {HttpParams} params Parametri della chiamata
|
|
300
|
-
* @param {string} filename Nome del file che si sta richiedendo, rimane lato Frontend e serve per assegnare arbitrariamente un nome al file restituito, se vuoto viene utilizzata la Content-Disposition della risposta
|
|
301
|
-
* @param {Function} getFileCallback Callback a due parametri (url: string, filename: string) per gestire il risultato del file richiesto. **Utilizzare UtilityService.fileDownload** di @esfaenza/extensions
|
|
302
|
-
* @param {Function} afterGetFile Callback da chiamare dopo aver gestito la risposta del **getFileCallback**, in caso **handleError** fosse **false** verrà richiamato anche in caso di errore
|
|
303
|
-
* @param {boolean} handleError Indica se di default gli errori devono essere gestiti dalla libreria o se devono essere ignorati
|
|
304
|
-
*/
|
|
305
|
-
async getFile(url, params = null, filename, getFileCallback, afterGetFile = null, handleError = true) {
|
|
306
|
-
let myGuid = this.defaultStartCall(url);
|
|
307
|
-
let locale = await this.bc.Locale.pipe(first()).toPromise();
|
|
308
|
-
this.http.get(url, { params: params, headers: this.getHeaders(locale), observe: 'response', responseType: "blob" }).pipe(catchError((err, caught) => {
|
|
309
|
-
if (afterGetFile && !handleError)
|
|
310
|
-
afterGetFile();
|
|
311
|
-
return this.registerErrorAndReturnEmptyObservable(err, myGuid, handleError);
|
|
312
|
-
}), finalize(() => { this.tryFinalizeByGuid(myGuid); })).subscribe((response) => {
|
|
313
|
-
let retUrl = window.URL.createObjectURL(response.body);
|
|
314
|
-
let fn = response.headers.get('content-disposition')?.split(';')[1]?.split('filename')[1]?.split('=')[1]?.trim().replace(/\"/g, '');
|
|
315
|
-
getFileCallback(retUrl, filename || fn);
|
|
316
|
-
if (afterGetFile)
|
|
317
|
-
afterGetFile();
|
|
318
|
-
});
|
|
319
|
-
}
|
|
320
|
-
/**
|
|
321
|
-
* Download nativo di un file. Internamente utilizza il pattern **window.location.href = "..."**
|
|
322
|
-
*
|
|
323
|
-
* @param {string} url URL su cui effettuare la chiamata
|
|
324
|
-
* @param {HttpParams} params Parametri della chiamata
|
|
325
|
-
*/
|
|
326
|
-
getFileNative(url, params = null) {
|
|
327
|
-
// Encodo tutti i parametri per evitare casi particolari
|
|
328
|
-
// var encodedParams = new HttpParams();
|
|
329
|
-
// let parKeys = params.keys();
|
|
330
|
-
// for (let i = 0; i < parKeys.length; i++)
|
|
331
|
-
// encodedParams = encodedParams.set(parKeys[i], encodeURIComponent(params.get(parKeys[i])));
|
|
332
|
-
let finalUrl = url + (params ? "?" + params.toString().replace(/\+/g, '%2b') : "");
|
|
333
|
-
window.location.href = finalUrl;
|
|
334
|
-
}
|
|
335
|
-
/**
|
|
336
|
-
* Esecuzione di una GET di un file che emette i vari eventi di progresso di download.
|
|
337
|
-
* Utilizzarla per overridare la dialog nativa di progress del browser e sostituirla con qualcosa tipo quello che fa MEGA.
|
|
338
|
-
*
|
|
339
|
-
* In caso si voglia ottenere il risultato nativo del browser del download utilizzare **getFileNative(url, pars)**
|
|
340
|
-
*
|
|
341
|
-
* @param {string} url URL su cui effettuare la chiamata
|
|
342
|
-
* @param {HttpParams} params Parametri della chiamata
|
|
343
|
-
* @param {Function} getFileCallback Callback a due parametri (url: string, filename: string) per gestire il risultato del file richiesto. **Utilizzare UtilityService.fileDownload** di @esfaenza/extensions
|
|
344
|
-
*
|
|
345
|
-
* @returns {Observable<Download>} Observable dei vari step di progresso del download
|
|
346
|
-
*/
|
|
347
|
-
getFileWithProgress(url, params = null, getFileCallback) {
|
|
348
|
-
return forkJoin({
|
|
349
|
-
myGuid: from([this.defaultStartCall(url)]),
|
|
350
|
-
locale: this.bc.Locale.pipe(first())
|
|
351
|
-
}).pipe(concatMap((ret) => {
|
|
352
|
-
return this.http.get(url, { responseType: 'blob', headers: this.getHeaders(ret.locale), params: params, observe: 'events', reportProgress: true })
|
|
353
|
-
.pipe(scan((previous, event) => {
|
|
354
|
-
if (this.isHttpProgressEvent(event)) {
|
|
355
|
-
let progress = event.total ? (event.loaded > event.total ? 100 : Math.round((100 * event.loaded) / event.total)) : previous.progress;
|
|
356
|
-
return { progress: progress, state: 'IN_PROGRESS', content: null };
|
|
357
|
-
}
|
|
358
|
-
if (this.isHttpResponse(event)) {
|
|
359
|
-
if (event.body) {
|
|
360
|
-
let cdisp = event.headers.get('content-disposition');
|
|
361
|
-
let cdispFilename = cdisp.split(';')[1].split('filename')[1].split('=')[1].trim().replace(/\"/g, '');
|
|
362
|
-
let retUrl = window.URL.createObjectURL(event.body);
|
|
363
|
-
getFileCallback(retUrl, cdispFilename);
|
|
364
|
-
}
|
|
365
|
-
return { progress: 100, state: 'DONE', content: event.body };
|
|
366
|
-
}
|
|
367
|
-
return previous;
|
|
368
|
-
}, { state: 'PENDING', progress: 0, content: null }), catchError((err, _) => { return this.registerErrorAndReturnEmptyObservable(err, ret.myGuid); }), finalize(() => { this.tryFinalizeByGuid(ret.myGuid); }));
|
|
369
|
-
}));
|
|
370
|
-
}
|
|
371
|
-
/**
|
|
372
|
-
* Riconosce se l'evento HTTP è di tipo **HttpResponse** e, se sì, lo casta al tipo corretto per essere utilizzato correttamente nel blocco di codice successivo
|
|
373
|
-
*/
|
|
374
|
-
isHttpResponse(event) {
|
|
375
|
-
return event.type === HttpEventType.Response;
|
|
376
|
-
}
|
|
377
|
-
/**
|
|
378
|
-
* Riconosce se l'evento HTTP è di tipo **HttpProgressEvent** e, se sì, lo casta al tipo corretto per essere utilizzato correttamente nel blocco di codice successivo
|
|
379
|
-
*/
|
|
380
|
-
isHttpProgressEvent(event) {
|
|
381
|
-
return event.type === HttpEventType.DownloadProgress || event.type === HttpEventType.UploadProgress;
|
|
382
|
-
}
|
|
383
|
-
/**
|
|
384
|
-
* Gestione dell'inizio di una chiamata ad un certo URL, viene generato un GUID da assegnarci, controllata la scadenza della cache,
|
|
385
|
-
* e eventualmente loggato il fatto che sta per essere effettuata una chiamata HTTP
|
|
386
|
-
*
|
|
387
|
-
* @param {string} url Url a cui effettuare la chiamata
|
|
388
|
-
* @returns {string} GUID assegnato alla chiamata
|
|
389
|
-
*/
|
|
390
|
-
defaultStartCall(url) {
|
|
391
|
-
let myGuid = this.getGUID();
|
|
392
|
-
this.checkCacheInvalidation(url);
|
|
393
|
-
this.callStatus[myGuid] = { url: url, success: true };
|
|
394
|
-
this.log(this.loc("Starting call") + " " + myGuid + " " + this.loc("at URL") + ": " + url);
|
|
395
|
-
return myGuid;
|
|
396
|
-
}
|
|
397
|
-
/**
|
|
398
|
-
* Dato un url vengono controllate le informazioni su tutti gli url da invalidare collegati all'url chiamato e, se presenti in cache, invalidati
|
|
399
|
-
*
|
|
400
|
-
* @param {string} url URL per cui controllare se ci sono chiamate in cache da invalidare
|
|
401
|
-
*/
|
|
402
|
-
checkCacheInvalidation(url) {
|
|
403
|
-
if (!this.CacheInitialized)
|
|
404
|
-
return;
|
|
405
|
-
let cache = this.localStorage.getLocalItem(this.localStorageHttpCacheKey);
|
|
406
|
-
let tmp = /#cache(:?-(\d+))/gi.exec(url);
|
|
407
|
-
let cacheTime = tmp ? tmp[2] : null;
|
|
408
|
-
let normalizedUrl_tmp = url.replace("#cache" + (cacheTime ? "-" + cacheTime : ""), "");
|
|
409
|
-
let normalizedUrl = normalizedUrl_tmp.substring(normalizedUrl_tmp.indexOf('/api'));
|
|
410
|
-
if (!cache || !this.HTTP_INVALIDATION || !this.HTTP_INVALIDATION[normalizedUrl])
|
|
411
|
-
return;
|
|
412
|
-
let apisToInvalidate = this.HTTP_INVALIDATION[normalizedUrl];
|
|
413
|
-
if (!apisToInvalidate || apisToInvalidate.length == 0)
|
|
414
|
-
return;
|
|
415
|
-
let keysToRemove = [];
|
|
416
|
-
apisToInvalidate.forEach(api => {
|
|
417
|
-
let cacheKey = this.makeCacheKey(api, null);
|
|
418
|
-
for (let item in cache)
|
|
419
|
-
if (item.indexOf(cacheKey) != -1)
|
|
420
|
-
keysToRemove.push(item);
|
|
421
|
-
});
|
|
422
|
-
for (let i = 0; i < keysToRemove.length; i++) {
|
|
423
|
-
let k = keysToRemove[i];
|
|
424
|
-
this.log(this.loc("Invlalidating cache element") + " " + k);
|
|
425
|
-
delete cache[k];
|
|
426
|
-
}
|
|
427
|
-
this.localStorage.setItem(this.localStorageHttpCacheKey, cache);
|
|
428
|
-
}
|
|
429
|
-
/**
|
|
430
|
-
* Finalizzazione di una chiamata
|
|
431
|
-
*
|
|
432
|
-
* @param {string} guid GUID collegato alla chiamata appena terminata
|
|
433
|
-
* @param {boolean} persistCacheIfIdle Effettua il persist della cache HTTP solo se non ci sono altre chiamate in corso, per evitare
|
|
434
|
-
* che mi cambi sotto l'oggetto di cache mentre sto salvando le informazioni
|
|
435
|
-
*/
|
|
436
|
-
async tryFinalizeByGuid(guid, cacheInfos) {
|
|
437
|
-
this.log(this.loc("Finalizing call") + " " + guid + " " + this.loc("with status") + ": " + (!this.callStatus[guid] ? 'Unknown' : this.callStatus[guid].success ? this.loc('Success') : this.loc('Failure')));
|
|
438
|
-
// TODO: Perdere 3-4 ore per capire perché ogni tanto arriva null in casi pesanti di Observable spammati a random
|
|
439
|
-
if (this.callStatus[guid]) {
|
|
440
|
-
// Alla prima chiamata buona, significa che almeno il login ce l'ho. Posso mettermi in modalità redirectInProgress false
|
|
441
|
-
// e riiniziare a valutare errori di javashit
|
|
442
|
-
if (this.callStatus[guid].success && this.ExtensionsImpl.readRedirectionStatus())
|
|
443
|
-
this.ExtensionsImpl.writeRedirectionStatus(false);
|
|
444
|
-
// Aggiungo la chiamata alla lista delle ultime 3 completate
|
|
445
|
-
this.LastThreeCompletedCalls.unshift(this.callStatus[guid].url);
|
|
446
|
-
if (this.LastThreeCompletedCalls.length > 3)
|
|
447
|
-
this.LastThreeCompletedCalls.pop();
|
|
448
|
-
// In ogni caso questa posso rimuoverla
|
|
449
|
-
delete this.callStatus[guid];
|
|
450
|
-
}
|
|
451
|
-
// Se non ho nessun'altra chiamata in corso considero la situazione stabilizzatasi
|
|
452
|
-
if (Object.keys(this.callStatus).length == 0)
|
|
453
|
-
this.Stabilized.next(true);
|
|
454
|
-
// Se vengo da una chiamata che ha aggiornato la cache a timer o globale marco il fatto che quella cache dev'essere aggiornata
|
|
455
|
-
if (cacheInfos && cacheInfos.cache) {
|
|
456
|
-
this.PersistTimedCacheASAP = this.PersistTimedCacheASAP || !!cacheInfos.cacheTime;
|
|
457
|
-
this.PersistUntimedCacheASAP = this.PersistTimedCacheASAP || !cacheInfos.cacheTime;
|
|
458
|
-
this.log(this.loc("Marking cache to be persisted as soon as possible"));
|
|
459
|
-
}
|
|
460
|
-
// Se una delle due cache devono essere aggiornate e non ho nessuna chiamata in corso effettuo l'aggiornamento in base a quale delle due va aggiornata
|
|
461
|
-
// Alla fine di tutto marco come fatto
|
|
462
|
-
if ((this.PersistTimedCacheASAP || this.PersistUntimedCacheASAP) && Object.keys(this.callStatus).length == 0 && this.CacheInitialized) {
|
|
463
|
-
var toCall = [];
|
|
464
|
-
let tmpKey = "";
|
|
465
|
-
if (this.PersistTimedCacheASAP) {
|
|
466
|
-
tmpKey = this.localStorageHttpTimedCacheKey;
|
|
467
|
-
toCall.push(this.localStorage.setItem(tmpKey, this.localStorage.getLocalItem(tmpKey)));
|
|
468
|
-
}
|
|
469
|
-
if (this.PersistUntimedCacheASAP) {
|
|
470
|
-
tmpKey = this.localStorageHttpCacheKey;
|
|
471
|
-
toCall.push(this.localStorage.setItem(tmpKey, this.localStorage.getLocalItem(tmpKey)));
|
|
472
|
-
}
|
|
473
|
-
this.log(this.loc("No more HTTP calls to be executed, entering idle state and persisting modified caches") + "...");
|
|
474
|
-
var ret = await forkJoin(toCall).toPromise();
|
|
475
|
-
if (ret)
|
|
476
|
-
this.log(this.loc("Caches succesfully persisted"));
|
|
477
|
-
else
|
|
478
|
-
this.log(this.loc("Errors persisting modified caches"));
|
|
479
|
-
this.PersistTimedCacheASAP = false;
|
|
480
|
-
this.PersistUntimedCacheASAP = false;
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
/**
|
|
484
|
-
* Helper che dato un unico File o una lista di File crea un oggetto FormData che può essere inviato comodamente
|
|
485
|
-
* ad un backend ASP.NET da cui si potrà accedere a Request.Form.Files
|
|
486
|
-
*
|
|
487
|
-
* @param {File | File[]} fileArrayOrFile Singolo File o lista di File. N.B: nella firma della funzione viene considerato **any** per fare test sulle proprietà
|
|
488
|
-
* invece che fare test con l'**istanceof**
|
|
489
|
-
*
|
|
490
|
-
* @returns {FormData} FormData contenente tutti i file passati
|
|
491
|
-
*/
|
|
492
|
-
getFilesFormData(fileArrayOrFile) {
|
|
493
|
-
var formData = new FormData();
|
|
494
|
-
if (fileArrayOrFile) {
|
|
495
|
-
if (fileArrayOrFile.length)
|
|
496
|
-
fileArrayOrFile.forEach(t => { formData.append("file", t, t.name); });
|
|
497
|
-
else if (fileArrayOrFile.name)
|
|
498
|
-
formData.append("files", fileArrayOrFile, fileArrayOrFile.name);
|
|
499
|
-
}
|
|
500
|
-
return formData;
|
|
501
|
-
}
|
|
502
|
-
/**
|
|
503
|
-
* Helper che in base ai parametri disponibili genera gli Header HTTP per la chiamata da effettuare
|
|
504
|
-
*
|
|
505
|
-
* @param {string} contentType Indica se aggiungere agli header "Content-Type", valorizzato al valore del parametro
|
|
506
|
-
* @param {string} accept Indica se aggiungere agli header "Accept", valorizzato al valore del parametro
|
|
507
|
-
* @param {boolean} includeAuth Indica se aggiungere agli header "Authorization", valorizzato col token recuperato dall'hook **retrieveAccessToken** della classe di estensione
|
|
508
|
-
* @param {string} transactionId Indica se aggiungere agli header "X-TX-ID", valorizzato al valore del parametro
|
|
509
|
-
*
|
|
510
|
-
* @returns {HttpHeaders} Header generati in base ai parametri
|
|
511
|
-
*/
|
|
512
|
-
getHeaders(locale = 'it-IT', transactionId = "", includeAuth = true, contentType = "application/json", accept = "application/json") {
|
|
513
|
-
var headers = new HttpHeaders();
|
|
514
|
-
var authtoken = this.ExtensionsImpl.retrieveAccessToken();
|
|
515
|
-
headers = headers.append("ngsw-bypass", "");
|
|
516
|
-
if (contentType)
|
|
517
|
-
headers = headers.append("Content-Type", contentType);
|
|
518
|
-
if (transactionId)
|
|
519
|
-
headers = headers.append("X-TX-ID", transactionId);
|
|
520
|
-
if (authtoken && includeAuth)
|
|
521
|
-
headers = headers.append("Authorization", "Bearer " + authtoken);
|
|
522
|
-
if (accept)
|
|
523
|
-
headers = headers.append("Accept", accept);
|
|
524
|
-
headers = headers.append("Accept-Language", locale);
|
|
525
|
-
return headers;
|
|
526
|
-
}
|
|
527
|
-
/**
|
|
528
|
-
* Gestione di default degli errori
|
|
529
|
-
*
|
|
530
|
-
* @param {any} res Risultato della chiamata effettuata
|
|
531
|
-
* @param {string} guid Identificativo GUID della chiamata effettuata
|
|
532
|
-
*/
|
|
533
|
-
async onError(res, guid) {
|
|
534
|
-
if (this.callStatus[guid])
|
|
535
|
-
this.callStatus[guid].success = false;
|
|
536
|
-
//Mi assicuro che tutti gli errori durante il redirect al login vengano ignorati
|
|
537
|
-
if (this.ExtensionsImpl.readRedirectingToLogin()) {
|
|
538
|
-
this.log(this.loc("Redirecting to Login, ignoring HTTP error on call") + " " + guid);
|
|
539
|
-
return;
|
|
540
|
-
}
|
|
541
|
-
//Mi assicuro che venga gestito un solo errore per volta
|
|
542
|
-
if (this.ExtensionsImpl.readHandlingErrorStatus()) {
|
|
543
|
-
this.log(this.loc("Already Handling an error, ignoring HTTP error on call") + " " + guid);
|
|
544
|
-
return;
|
|
545
|
-
}
|
|
546
|
-
else
|
|
547
|
-
this.ExtensionsImpl.writeHandlingErrorStatus(true);
|
|
548
|
-
let finalError = "";
|
|
549
|
-
let finalStatus = "";
|
|
550
|
-
if (this.isTypeError(res)) {
|
|
551
|
-
finalError = res.message;
|
|
552
|
-
finalStatus = "HTTP Service Internal Error";
|
|
553
|
-
}
|
|
554
|
-
else if (this.isHttpErrorResponse(res)) {
|
|
555
|
-
finalError = await this.getHttpErrorText(res.error);
|
|
556
|
-
finalStatus = res.status.toString();
|
|
557
|
-
switch (res.status) {
|
|
558
|
-
// Unauthorized
|
|
559
|
-
case 401:
|
|
560
|
-
if (this.ExtensionsImpl.readRedirectionStatus()) {
|
|
561
|
-
this.log(this.loc("Error 401 on call") + " " + guid + " " + this.loc("with redirect already in progress. Ignoring this event"));
|
|
562
|
-
return;
|
|
563
|
-
}
|
|
564
|
-
this.log(this.loc("Error 401 on call") + " " + guid + " " + this.loc("redirecting to login."));
|
|
565
|
-
this.ExtensionsImpl.writeRedirectionStatus(true);
|
|
566
|
-
this.ExtensionsImpl.writeRedirectingToLogin(true);
|
|
567
|
-
this.ExtensionsImpl.redirectToLogin();
|
|
568
|
-
return;
|
|
569
|
-
// Handled exception
|
|
570
|
-
case 400:
|
|
571
|
-
// No Permissions
|
|
572
|
-
case 403:
|
|
573
|
-
this.ExtensionsImpl.handleBlockingException(res.status, finalError);
|
|
574
|
-
return;
|
|
575
|
-
// Not found
|
|
576
|
-
case 404:
|
|
577
|
-
this.ExtensionsImpl.handleBlockingException(res.status, this.loc("Resource not found"));
|
|
578
|
-
return;
|
|
579
|
-
// NotConfiguredException
|
|
580
|
-
case 444:
|
|
581
|
-
if (this.ExtensionsImpl.readRedirectionStatus())
|
|
582
|
-
this.log(this.loc("Error 444 on call") + " " + guid + " " + this.loc("with redirect already in progress. Ignoring this event"));
|
|
583
|
-
else if (!this.ExtensionsImpl.handleNotConfiguredException())
|
|
584
|
-
this.ExtensionsImpl.handleBlockingException(res.status, finalError);
|
|
585
|
-
return;
|
|
586
|
-
case 0:
|
|
587
|
-
finalError = `Generic connection error while calling '[${guid}] - ${this.callStatus[guid].url}' at ${dayjs().format()}. Response: ${JSON.stringify(res)}`;
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
this.ExtensionsImpl.handleException(finalStatus, finalError);
|
|
591
|
-
}
|
|
592
|
-
/**
|
|
593
|
-
* Dato un errore restituisce una promise con la stringa finale dell'errore in modo da poter fare un await
|
|
594
|
-
*
|
|
595
|
-
* @param {any} err Errore da controllare
|
|
596
|
-
*
|
|
597
|
-
* @returns {Promise<string>} Promise che risolve con la stringa finale dell'errore
|
|
598
|
-
*/
|
|
599
|
-
getHttpErrorText(err) {
|
|
600
|
-
// Se ho un Blob può essere o un CallResult o suppongo una semplice stringa,
|
|
601
|
-
// altrimenti potrebbe essere direttamente un CallResult, oppure una semplice stringa
|
|
602
|
-
return new Promise((resolve) => {
|
|
603
|
-
if (err instanceof Blob) {
|
|
604
|
-
let reader = new FileReader();
|
|
605
|
-
reader.onload = (e) => {
|
|
606
|
-
let errMsg = e.target.result;
|
|
607
|
-
let jsonerrMsg;
|
|
608
|
-
try {
|
|
609
|
-
jsonerrMsg = JSON.parse(errMsg);
|
|
610
|
-
}
|
|
611
|
-
catch (e) { }
|
|
612
|
-
return resolve(jsonerrMsg && this.isCallResult(jsonerrMsg) ? jsonerrMsg.error.message : errMsg);
|
|
613
|
-
};
|
|
614
|
-
reader.readAsText(err);
|
|
615
|
-
}
|
|
616
|
-
else if (this.isCallResult(err))
|
|
617
|
-
return resolve(err.error.message);
|
|
618
|
-
else
|
|
619
|
-
return resolve(err?.toString());
|
|
620
|
-
});
|
|
621
|
-
}
|
|
622
|
-
/**
|
|
623
|
-
* Riconosce se l'oggetto è di tipo **CallResult** e, se sì, lo casta al tipo corretto per essere utilizzato correttamente nel blocco di codice successivo
|
|
624
|
-
*
|
|
625
|
-
* @param {any} err Errore da controllare
|
|
626
|
-
*/
|
|
627
|
-
isCallResult(err) {
|
|
628
|
-
return !!err?.error?.message;
|
|
629
|
-
}
|
|
630
|
-
/**
|
|
631
|
-
* Riconosce se l'errore è di tipo **HttpErrorResponse** e, se sì, lo casta al tipo corretto per essere utilizzato correttamente nel blocco di codice successivo
|
|
632
|
-
*
|
|
633
|
-
* @param {any} err Errore da controllare
|
|
634
|
-
*/
|
|
635
|
-
isHttpErrorResponse(err) {
|
|
636
|
-
return err instanceof HttpErrorResponse;
|
|
637
|
-
}
|
|
638
|
-
/**
|
|
639
|
-
* Riconosce se l'errore è di tipo **TypeError** e, se sì, lo casta al tipo corretto per essere utilizzato correttamente nel blocco di codice successivo
|
|
640
|
-
*
|
|
641
|
-
* @param {any} err Errore da controllare
|
|
642
|
-
*/
|
|
643
|
-
isTypeError(err) {
|
|
644
|
-
return err.name == "TypeError";
|
|
645
|
-
}
|
|
646
|
-
/**
|
|
647
|
-
* Come dice il nome, registra un errore e restituisce un Observable vuoto come risultato della chiamata
|
|
648
|
-
*
|
|
649
|
-
* @param {any} res Risultato della chiamata effettuata
|
|
650
|
-
* @param {string} guid Identificativo GUID della chiamata effettuata
|
|
651
|
-
* @param {boolean} handleError Indica se gestire l'errore via libreria o se limitarsi a restituire l'Observable vuoto
|
|
652
|
-
*
|
|
653
|
-
* @returns {Observable<any>} Observable vuoto
|
|
654
|
-
*/
|
|
655
|
-
registerErrorAndReturnEmptyObservable(res, guid, handleError = true) {
|
|
656
|
-
if (handleError)
|
|
657
|
-
this.onError(res, guid);
|
|
658
|
-
return new Observable(() => { });
|
|
659
|
-
}
|
|
660
|
-
/**
|
|
661
|
-
* Dato un Url e dei parametri cerca di recuperare l'eventuale oggetto già salvato in cache con le informazioni base della cache stessa
|
|
662
|
-
*
|
|
663
|
-
* @param {string} url URL su cui effettuare la chiamata
|
|
664
|
-
* @param {HttpParams} params Parametri della chiamata (nulli in caso di POST)
|
|
665
|
-
*
|
|
666
|
-
* @returns {CacheInfos} Oggetto contenente le informazioni sulla cache per l'oggetto specificato
|
|
667
|
-
*/
|
|
668
|
-
tryGetCacheInformations(url, params) {
|
|
669
|
-
let cachingKey = null, cacheTime = null, item = null;
|
|
670
|
-
let useCaching = !!(/#cache/gi.exec(url));
|
|
671
|
-
if (useCaching && this.CacheInitialized) {
|
|
672
|
-
let tmp = /#cache(:?-(\d+))/gi.exec(url);
|
|
673
|
-
cacheTime = tmp ? tmp[2] : null;
|
|
674
|
-
url = url.replace("#cache" + (cacheTime ? "-" + cacheTime : ""), "");
|
|
675
|
-
if (this.untimedCacheExpired() && !cacheTime)
|
|
676
|
-
this.resetHttpUntimedCacheStorage();
|
|
677
|
-
cachingKey = this.makeCacheKey(url, params);
|
|
678
|
-
let cacheKey = cacheTime ? this.localStorageHttpTimedCacheKey : this.localStorageHttpCacheKey;
|
|
679
|
-
let cacheLs = this.localStorage.getLocalItem(cacheKey);
|
|
680
|
-
let cache = cacheLs ? cacheLs : {};
|
|
681
|
-
if (cache && cache[cachingKey] && !this.timedCacheItemExpired(cache[cachingKey])) {
|
|
682
|
-
// Se gestisco il tempo esatto della cache prima di restituire l'oggetto cachato lo ripulisco
|
|
683
|
-
// dalle proprietà interne che gli ho aggiunto per controllarne la scadenza
|
|
684
|
-
if (cacheTime)
|
|
685
|
-
delete cache[cachingKey].__expire;
|
|
686
|
-
item = cache[cachingKey];
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
// Per assicurarmi che il rifeirmento degli oggetti sia diverso utilizzo il deepClone
|
|
690
|
-
return new CacheInfos(url, useCaching && this.CacheInitialized, cachingKey, cacheTime, this.utisExts.deepClone(item));
|
|
691
|
-
}
|
|
692
|
-
/**
|
|
693
|
-
* Inserisce un oggetto nella cache appropriata in base alle informazioni contenute nel parametro **cacheInfos**
|
|
694
|
-
*
|
|
695
|
-
* @param {T} item Oggetto da inserire nella cache
|
|
696
|
-
* @param {CacheInfos} cacheInfos Informazioni sulla cache recuperate da una chiamata precedente a **tryGetCacheInformations**
|
|
697
|
-
*/
|
|
698
|
-
cacheResponse(item, cacheInfos) {
|
|
699
|
-
let cacheKey = cacheInfos.cacheTime ? this.localStorageHttpTimedCacheKey : this.localStorageHttpCacheKey;
|
|
700
|
-
let cacheLs = this.localStorage.getLocalItem(cacheKey);
|
|
701
|
-
let cache = cacheLs ? cacheLs : {};
|
|
702
|
-
cache[cacheInfos.cacheKey] = item;
|
|
703
|
-
if (cacheInfos.cacheTime)
|
|
704
|
-
cache[cacheInfos.cacheKey].__expire = dayjs().add(cacheInfos.cacheTime, "seconds");
|
|
705
|
-
this.localStorage.setLocalItem(cacheKey, cache);
|
|
706
|
-
}
|
|
707
|
-
/**
|
|
708
|
-
* Controlla se la cache per le chiamate senza expire time è scaduta
|
|
709
|
-
*
|
|
710
|
-
* @returns {boolean} **true** se la cache è scaduta e dev'essere ripulita, **false** altrimenti
|
|
711
|
-
*/
|
|
712
|
-
untimedCacheExpired() {
|
|
713
|
-
let expire = JSON.parse(localStorage.getItem(this.localStorageHttpCacheExpireKey));
|
|
714
|
-
return !expire || expire && dayjs(expire) < dayjs();
|
|
715
|
-
}
|
|
716
|
-
/**
|
|
717
|
-
* Controlla se la cache per una chiamata che ha un tempo di vita ben definito è scaduta o meno
|
|
718
|
-
*
|
|
719
|
-
* @param {any} item Oggetto recuperato dalla cache a cui ho aggiunto la chiave interna __expire
|
|
720
|
-
*
|
|
721
|
-
* @returns {boolean} **true** se la cache è scaduta e dev'essere ripulita, **false** altrimenti
|
|
722
|
-
*/
|
|
723
|
-
timedCacheItemExpired(item) {
|
|
724
|
-
return dayjs(item.__expire) < dayjs();
|
|
725
|
-
}
|
|
726
|
-
/**
|
|
727
|
-
* Ripulisce la cache e imposta la prossima scadenza ad adesso + **CLIENT_CACHE_DURATION_S** (token valorizzato in fase di configurazione dalla proprietà **clientCacheDurationS** della classe **HttpServiceModuleConfig**)
|
|
728
|
-
*/
|
|
729
|
-
async resetHttpUntimedCacheStorage() {
|
|
730
|
-
if (!this.CacheInitialized)
|
|
731
|
-
return;
|
|
732
|
-
await this.localStorage.setItem(this.localStorageHttpCacheKey, {}).toPromise();
|
|
733
|
-
localStorage.setItem(this.localStorageHttpCacheExpireKey, JSON.stringify(dayjs().add(this.CLIENT_CACHE_DURATION_S, "second")));
|
|
734
|
-
}
|
|
735
|
-
/**
|
|
736
|
-
* Ripulisce la cache delle chiamate con un tempo di expire definito
|
|
737
|
-
*/
|
|
738
|
-
async resetHttpTimedCacheStorage() {
|
|
739
|
-
if (!this.CacheInitialized)
|
|
740
|
-
return;
|
|
741
|
-
await this.localStorage.setItem(this.localStorageHttpTimedCacheKey, {}).toPromise();
|
|
742
|
-
}
|
|
743
|
-
/**
|
|
744
|
-
* Genera una chiave per la cache delle chiamate in base ad URL e Parametri HTTP
|
|
745
|
-
*
|
|
746
|
-
* @param {string} url URL su cui effettuare la chiamata
|
|
747
|
-
* @param {HttpParams} params Parametri della chiamata
|
|
748
|
-
*
|
|
749
|
-
* @returns {string} Chiave che rappresenta in maniera univoca la chiamata
|
|
750
|
-
*/
|
|
751
|
-
makeCacheKey(url, params) {
|
|
752
|
-
this.me = this.me || this.ExtensionsImpl.retrieveIdentity();
|
|
753
|
-
let authKeyPart = (this.me ? this.me.Idtenant : "") + (this.me && this.CACHE_BY_USER ? this.me.IdUser : "");
|
|
754
|
-
let paramsKeyPart = params && params.keys().length > 0 ? params.keys().reduce((prev, next) => prev + "," + next + '=' + params.get(next), "") : "";
|
|
755
|
-
return authKeyPart + "_" + url.substring(url.indexOf("api") + 4) + "?" + paramsKeyPart;
|
|
756
|
-
}
|
|
757
|
-
/**
|
|
758
|
-
* Generazione GUID
|
|
759
|
-
*
|
|
760
|
-
* @returns {string} Nuovo GUID generato in maniera casuale
|
|
761
|
-
*/
|
|
762
|
-
getGUID() {
|
|
763
|
-
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
|
764
|
-
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
|
|
765
|
-
return v.toString(16);
|
|
766
|
-
});
|
|
767
|
-
}
|
|
768
|
-
/**
|
|
769
|
-
* Metodo per scrivere log a console qualora **DEBUG_MODE** risultasse **true**
|
|
770
|
-
*
|
|
771
|
-
* @param {string} message Messaggio di log
|
|
772
|
-
*/
|
|
773
|
-
log(message) {
|
|
774
|
-
if (this.HTTP_DEBUG_MODE)
|
|
775
|
-
console.log("@httpservice: " + message);
|
|
776
|
-
}
|
|
777
|
-
/**
|
|
778
|
-
* Helper per la localizzazione dei messaggi
|
|
779
|
-
*
|
|
780
|
-
* @param {string} message Messaggio da localizzare
|
|
781
|
-
*
|
|
782
|
-
* @returns {string} Messaggio localizzato
|
|
783
|
-
*/
|
|
784
|
-
loc(message) {
|
|
785
|
-
// Togliamo velocemente ste localizzazioni inutili....
|
|
786
|
-
return message;
|
|
787
|
-
}
|
|
788
|
-
/**
|
|
789
|
-
* Helper per lanciare la selezione di tutto quello che è relativo a un api di ricerca con AppSearch (di cui non utilizzo il tipo vero per ridurre le dipendenze)
|
|
790
|
-
*/
|
|
791
|
-
getAll(view, api, pars, transaction) {
|
|
792
|
-
if (!view.selection.all)
|
|
793
|
-
return of(view.selection.items);
|
|
794
|
-
var jsonView = this.utisExts.deepClone(view);
|
|
795
|
-
jsonView.page = 1;
|
|
796
|
-
jsonView.itemsperpageoverride = 999999;
|
|
797
|
-
return this.post(api, jsonView, pars, transaction).pipe(map(res => {
|
|
798
|
-
let items = res.items;
|
|
799
|
-
items.forEach(t => t.hash = this.hash.hashObject(t, null, false));
|
|
800
|
-
if (res.selection.exclusions?.length > 0)
|
|
801
|
-
items = items.filter((t) => !res.selection.exclusions.find((e) => this.hash.hashObject(e, null, false) == t.hash));
|
|
802
|
-
return items;
|
|
803
|
-
}));
|
|
804
|
-
}
|
|
805
|
-
beginTransaction(executionKey, secondsTimeout) {
|
|
806
|
-
this.log("beginTransaction call received: " + executionKey);
|
|
807
|
-
var pars = new HttpParams().set("executionKey", executionKey);
|
|
808
|
-
if (secondsTimeout)
|
|
809
|
-
pars = pars.set("secondsTimeout", secondsTimeout.toString());
|
|
810
|
-
return this.get(this.GET_Trans_BeginTrans, pars);
|
|
811
|
-
}
|
|
812
|
-
checkTransaction(executionKey) {
|
|
813
|
-
this.log("checkTransaction call received: " + executionKey);
|
|
814
|
-
return this.get(this.GET_Trans_CheckExecution, new HttpParams().set("executionKey", executionKey));
|
|
815
|
-
}
|
|
816
|
-
endTransaction(transactionKey, transactionResult) {
|
|
817
|
-
this.log("endTransaction call received: " + transactionKey + " Commit: " + transactionResult);
|
|
818
|
-
let pars = new HttpParams().set("idtrans", transactionKey).set("success", transactionResult.toString());
|
|
819
|
-
return this.get(this.GET_Trans_EndTrans, pars);
|
|
820
|
-
}
|
|
821
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
822
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "
|
|
823
|
-
}
|
|
824
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
825
|
-
type: Injectable,
|
|
826
|
-
args: [{ providedIn: 'root' }]
|
|
827
|
-
}], ctorParameters:
|
|
828
|
-
type: Optional
|
|
829
|
-
}, {
|
|
830
|
-
type: Inject,
|
|
831
|
-
args: [HTTP_INVALIDATION]
|
|
832
|
-
}] }, { type: undefined, decorators: [{
|
|
833
|
-
type: Inject,
|
|
834
|
-
args: [CLIENT_CACHE_DURATION_S]
|
|
835
|
-
}] }, { type: undefined, decorators: [{
|
|
836
|
-
type: Inject,
|
|
837
|
-
args: [CACHE_BY_USER]
|
|
838
|
-
}] }, { type: undefined, decorators: [{
|
|
839
|
-
type: Inject,
|
|
840
|
-
args: [HTTP_DEBUG_MODE]
|
|
841
|
-
}] }, { type: i2.BaseLocalization }, { type: i3.HttpClient }, { type: i4.CacheService }, { type: i5.HashingService }, { type: i5.UtilityService }]
|
|
842
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHR0cHNlcnZpY2Uuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL2h0dHBzZXJ2aWNlL3NyYy9saWIvaHR0cHNlcnZpY2Uuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxVQUFVO0FBQ1YsT0FBTyxFQUFjLGlCQUFpQixFQUFhLGFBQWEsRUFBRSxXQUFXLEVBQUUsVUFBVSxFQUFtQyxNQUFNLHNCQUFzQixDQUFDO0FBQ3pKLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQU83RCxrQ0FBa0M7QUFDbEMsT0FBTyxFQUFFLFVBQVUsRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzFGLE9BQU8sRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLFVBQVUsRUFBRSxFQUFFLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUUzRSxrQ0FBa0M7QUFDbEMsT0FBTyxFQUFFLGlCQUFpQixFQUFFLHVCQUF1QixFQUFFLGFBQWEsRUFBRSxlQUFlLEVBQUUsTUFBTSxVQUFVLENBQUM7QUFFdEcsV0FBVztBQUNYLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBRXZFLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQzs7Ozs7OztBQVFqRDs7O0dBR0c7QUFFSCxNQUFNLE9BQU8sV0FBVztJQThCdEI7O09BRUc7SUFDSCxZQUNVLGVBQXNDLEVBQ0MsaUJBQWlCLEVBQ3ZCLHVCQUF1QixFQUNqQyxhQUFzQixFQUNwQixlQUF3QixFQUNqRCxFQUFvQixFQUNwQixJQUFnQixFQUNoQixZQUEwQixFQUMxQixJQUFvQixFQUNwQixRQUF3QjtRQVR4QixvQkFBZSxHQUFmLGVBQWUs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QWtDLEdBQUcsWUFBWSxDQUFDLENBQUM7UUFDNUQsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFTLElBQUksQ0FBQyx3QkFBd0IsRUFBRSxJQUFJLFVBQVUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxjQUFjLEVBQUUsWUFBWSxDQUFDLENBQUMsQ0FBQztJQUM3RyxDQUFDO0lBRU0sY0FBYyxDQUFDLGNBQXNCLEVBQUUsaUJBQTBCO1FBQ3RFLElBQUksQ0FBQyxHQUFHLENBQUMsZ0NBQWdDLEdBQUcsY0FBYyxHQUFHLFdBQVcsR0FBRyxpQkFBaUIsQ0FBQyxDQUFDO1FBQzlGLElBQUksSUFBSSxHQUFHLElBQUksVUFBVSxFQUFFLENBQUMsR0FBRyxDQUFDLFNBQVMsRUFBRSxjQUFjLENBQUMsQ0FBQyxHQUFHLENBQUMsU0FBUyxFQUFFLGlCQUFpQixDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUM7UUFDeEcsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFTLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxJQUFJLENBQUMsQ0FBQztJQUN6RCxDQUFDOytHQXg4QlUsV0FBVyx1REFtQ0EsaUJBQWlCLDZCQUM3Qix1QkFBdUIsYUFDdkIsYUFBYSxhQUNiLGVBQWU7bUhBdENkLFdBQVcsY0FERSxNQUFNOzs0RkFDbkIsV0FBVztrQkFEdkIsVUFBVTttQkFBQyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUU7OzBCQW9DN0IsUUFBUTs7MEJBQUksTUFBTTsyQkFBQyxpQkFBaUI7OzBCQUNwQyxNQUFNOzJCQUFDLHVCQUF1Qjs7MEJBQzlCLE1BQU07MkJBQUMsYUFBYTs7MEJBQ3BCLE1BQU07MkJBQUMsZUFBZSIsInNvdXJjZXNDb250ZW50IjpbIi8vIEFuZ3VsYXJcclxuaW1wb3J0IHsgSHR0cENsaWVudCwgSHR0cEVycm9yUmVzcG9uc2UsIEh0dHBFdmVudCwgSHR0cEV2ZW50VHlwZSwgSHR0cEhlYWRlcnMsIEh0dHBQYXJhbXMsIEh0dHBQcm9ncmVzc0V2ZW50LCBIdHRwUmVzcG9uc2UgfSBmcm9tIFwiQGFuZ3VsYXIvY29tbW9uL2h0dHBcIjtcclxuaW1wb3J0IHsgSW5qZWN0YWJsZSwgSW5qZWN0LCBPcHRpb25hbCB9IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XHJcblxyXG4vLyBFcyBGYWVuemFcclxuaW1wb3J0IHsgQ2FjaGVTZXJ2aWNlIH0gZnJvbSBcIkBlc2ZhZW56YS9wcmVmZXJlbmNlc1wiO1xyXG5pbXBvcnQgeyBIYXNoaW5nU2VydmljZSwgVXRpbGl0eVNlcnZpY2UgfSBmcm9tIFwiQGVzZmFlbnphL2V4dGVuc2lvbnNcIjtcclxuaW1wb3J0IHsgQmFzZUxvY2FsaXphdGlvbiB9IGZyb20gXCJAZXNmYWVuemEvbG9jYWxpemF0aW9uc1wiO1xyXG5cclxuLy8gRGlyZXR0aXZlLCBDb21wb25lbnRpLCBMaWJyZXJpZVxyXG5pbXBvcnQgeyBjYXRjaEVycm9yLCBjb25jYXRNYXAsIGRlbGF5LCBmaW5hbGl6ZSwgZmlyc3QsIG1hcCwgc2NhbiB9IGZyb20gXCJyeGpzL29wZXJhdG9yc1wiO1xyXG5pbXBvcnQgeyBmb3JrSm9pbiwgZnJvbSwgT2JzZXJ2YWJsZSwgb2YsIFN1YmplY3QsIHRocm93RXJyb3IgfSBmcm9tIFwicnhqc1wiO1xyXG5cclxuLy8gQ2hpYW1hdGUgYWkgUmVwb3NpdG9yeSAvIHRva2Vuc1xyXG5pbXBvcnQgeyBIVFRQX0lOVkFMSURBVElPTiwgQ0xJRU5UX0NBQ0hFX0RVUkFUSU9OX1MsIENBQ0hFX0JZX1VTRVIsIEhUVFBfREVCVUdfTU9ERSB9IGZyb20gJy4vdG9rZW5zJztcclxuXHJcbi8vIE1vZGVsbGkgXHJcbmltcG9ydCB7IEh0dHBTZXJ2aWNlRXh0ZW5zaW9ucyB9IGZyb20gJy4vY29uZmlnL0h0dHBTZXJ2aWNlRXh0ZW5zaW9ucyc7XHJcbmltcG9ydCB7IERvd25sb2FkIH0gZnJvbSAnLi9tb2RlbHMvRG93bmxvYWQnO1xyXG5pbXBvcnQgeyBDYWNoZUluZm9zIH0gZnJvbSBcIi4vbW9kZWxzL0NhY2hlSW5mb3NcIjtcclxuXHJcbi8qKlxyXG4gKiBEaWNoaWFyYXppb25lIGRlbGxhIHZhcmlhYmlsZSBnbG9iYWxlIGRheWpzLiBMJ29uZXJlIGRpIFwiY3JlYXJsYVwiIMOoIGFmZmlkYXRvIGFsbCdhcHBsaWNhemlvbmUgY2hlIHV0aWxpenphIHF1ZXN0YSBsaWJyZXJpYSwgXHJcbiAqIGNoZSBkb3Zyw6AgaW1wb3J0YXJlIGxvIHNjcmlwdCBnbG9iYWxlIGRpIGRheWpzIG5lbGxhIENMSVxyXG4gKi9cclxuZGVjbGFyZSB2YXIgZGF5anM6IGFueTtcclxuXHJcbi8qKlxyXG4gKiBTZXJ2aXppbyB1dGlsaXp6YXRvIHBlciBlZmZldHR1YXJlIHF1YWxzaWFzaSB0aXBvIGRpIGNoaWFtYXRhIEhUVFAgZGFsbCdhcHBsaWNhemlvbmUsIGdlc3Rpc2NlIGVycm9yaSBlIGNhY2hlIGRlbGxlIHJpc3Bvc3RlIG5hdGl2YW1lbnRlIGUgbmUgcHXDsiBlc3NlcmUgXHJcbiAqIGVzdGVzby9tb2RpZmljYXRvIGlsIGNvbXBvcnRhbWVudG8gaW1wbGVtZW50YW5kbyBsYSBjbGFzc2UgZGkgXCJob29rXCIgKipJSHR0cFNlcnZpY2VFeHRlbnNpb25zKiogZSByZWdpc3RyYW5kb2xhIG5lbCBwcm92aWRlciBkZWxsYSBjbGFzc2UgKipIdHRwU2VydmljZUV4dGVuc2lvbnMqKlxyXG4gKi9cclxuQEluamVjdGFibGUoeyBwcm92aWRlZEluOiAncm9vdCcgfSlcclxuZXhwb3J0IGNsYXNzIEhUVFBTZXJ2aWNlIHtcclxuXHJcbiAgLyoqIENhY2hlIGRlbGxvIHN0YXRvIGRlbGxlIGNoaWFtYXRlIEhUVFAgYXR0dWFsbWVudGUgZWZmZXR0dWF0ZS4gT2duaSBjaGlhbWF0YSDDqCByYXBwcmVzZW50YXRhIGRhIHVuIEdVSUQgZSBsbyBzdGF0dXMgYXNzdW1lIHZhbG9yZSAqKmZhbHNlKiogc29sbyBzdWdsaSBlcnJvcmkgKi9cclxuICBwcml2YXRlIGNhbGxTdGF0dXM6IHsgW2lkOiBzdHJpbmddOiB7IHVybDogc3RyaW5nLCBzdWNjZXNzOiBib29sZWFuIH0gfSA9IHt9O1xyXG4gIC8qKiBOb21lIGRlbGxhIGNhY2hlIGluIGN1aSB2ZW5nb25vIHN0b3JpY2l6emF0ZSBsZSBpbmZvcm1hemlvbmkgc3VsbGUgcmlzcG9zdGUgZGVsbGUgY2hpYW1hdGUgc290dG8gZm9ybWEgZGkgZGljdGlvbmFyeSAqL1xyXG4gIHByaXZhdGUgbG9jYWxTdG9yYWdlSHR0cENhY2hlS2V5ID0gbnVsbDtcclxuICAvKiogTm9tZSBkZWxsYSBjYWNoZSBpbiBjdWkgdmVuZ29ubyBzdG9yaWNpenphdGUgbGUgaW5mb3JtYXppb25pIHN1bGxlIHJpc3Bvc3RlIGRlbGxlIGNoaWFtYXRlIHNvdHRvIGZvcm1hIGRpIGRpY3Rpb25hcnksIHNvbG8gcGVyIGxlIGNoaWFtYXRlIGNvbiB1biB0ZW1wbyBkZWZpbml0byBkaSBjYWNoaW5nICovXHJcbiAgcHJpdmF0ZSBsb2NhbFN0b3JhZ2VIdHRwVGltZWRDYWNoZUtleSA9IG51bGw7XHJcbiAgLyoqIE5vbWUgZGVsbGEgY2FjaGUgaW4gY3VpIHZlbmdvbm8gc3RvcmljaXp6YXRlIGxlIGluZm9ybWF6aW9uaSBzdWxsbyBzY2FkZXJlIGRlbGxhIGNhY2hlIHN0ZXNzYSAqL1xyXG4gIHByaXZhdGUgbG9jYWxTdG9yYWdlSHR0cENhY2hlRXhwaXJlS2V5ID0gbnVsbDtcclxuICAvKiogSWRlbnRpdMOgIGNvbGxlZ2F0YSBhbCB0b2tlbiBkaSBhdXRlbnRpY2F6aW9uZSBkYSB1c2FyZSwgcmljaGllc3RhIGFsIHByb2dyYW1tYSBjaGUgdXRpbGl6emEgbGEgbGlicmVyaWEgYXR0cmF2ZXJzbyBsJ2hvb2sgKipyZXRyaWV2ZUlkZW50aXR5KiogZGVsbGEgKipIdHRwU2VydmljZUV4dGVuc2lvbnMqKiAqL1xyXG4gIHByaXZhdGUgbWU6IHsgSWR0ZW5hbnQ6IHN0cmluZywgSWRVc2VyOiBzdHJpbmcgfSA9IG51bGw7XHJcbiAgLyoqIEluZGljYSBjaGUgbGEgY2FjaGUgYSB0ZW1wbyBkZXYnZXNzZXJlIHBlcnNpc3RpdGEgaWwgcHJpbWEgcG9zc2liaWxlICovXHJcbiAgcHJpdmF0ZSBQZXJzaXN0VGltZWRDYWNoZUFTQVA6IGJvb2xlYW4gPSBmYWxzZTtcclxuICAvKiogSW5kaWNhIGNoZSBsYSBjYWNoZSBzZW56YSBsaW1pdGkgZGkgdGVtcG8gZGV2J2Vzc2VyZSBwZXJzaXN0aXRhIGlsIHByaW1hIHBvc3NpYmlsZSAqL1xyXG4gIHByaXZhdGUgUGVyc2lzdFVudGltZWRDYWNoZUFTQVA6IGJvb2xlYW4gPSBmYWxzZTtcclxuICAvKiogU3ViamVjdCBlbWVzc28gcXVhbmRvIGlsIHNlcnZpemlvIGh0dHAgc2kgc3RhYmlsaXp6YSwgY2lvw6ggcXVhbmRvIG5vbiBjJ8OoIG5lc3N1bmEgY2hpYW1hdGEgcGVuZGluZyBvIGluIGNvcnNvIGRhIHF1YWxjaGUgaXN0YW50ZSAqL1xyXG4gIHB1YmxpYyBTdGFiaWxpemVkOiBTdWJqZWN0PHRydWU+ID0gbmV3IFN1YmplY3Q8dHJ1ZT4oKTtcclxuXHJcbiAgLyoqXHJcbiAgICogSW1wbGVtZW50YXppb25lIGRlbGxhIGNsYXNzZSBkaSBlc3RlbnNpb25lIHBlciBjb2xsZWdhcmUgaSBjb21wb3J0YW1lbnRpIGRlbGxhIGxpYnJlcmlhIGFsbCdhcHBsaWNhemlvbmUgaW4gY3VpIMOoIHVzYXRhLiBcclxuICAgKiBcclxuICAgKiBTZSDDqCBzdGF0byBlZmZldHR1YXRvIGlsIHByb3ZpZGUgZGVsbGEgY2xhc3NlICoqSHR0cFNlcnZpY2VFeHRlbnNpb25zKiogdmVycsOgIHVzYXRvIHF1ZWwgcHJvdmlkZXIsIGFsdHJpbWVudGkgdmVycsOgIGNyZWF0YSB1bmEgbnVvdmEgaXN0YW56YSBkaSBkZWZhdWx0XHJcbiAgICovXHJcbiAgcHJpdmF0ZSBFeHRlbnNpb25zSW1wbDogSHR0cFNlcnZpY2VFeHRlbnNpb25zO1xyXG5cclxuICAvKiogTGlzdGEgZGVsbGUgdWx0aW1lIDMgY2hpYW1hdGUgY29tcGxldGF0ZSBjb24gc3VjY2Vzc28gaW4gb3JkaW5lIGRpIGNvbXBsZXRhbWVudG8gKGluIHBvc2l6aW9uZSAwIGMnw6ggbCd1bHRpbWEgY29tcGxldGF0YSBlY2NldGVyYS4uLikgKi9cclxuICBwdWJsaWMgTGFzdFRocmVlQ29tcGxldGVkQ2FsbHM6IHN0cmluZ1tdID0gW107XHJcblxyXG4gIHByaXZhdGUgQ2FjaGVJbml0aWFsaXplZDogYm9vbGVhbiA9IGZhbHNlO1xyXG4gIC8qKlxyXG4gICAqIEBpZ25vcmVcclxuICAgKi9cclxuICBjb25zdHJ1Y3RvcihcclxuICAgIHByaXZhdGUgRVhURU5TSU9OX0NMQVNTOiBIdHRwU2VydmljZUV4dGVuc2lvbnMsXHJcbiAgICBAT3B0aW9uYWwoKSBASW5qZWN0KEhUVFBfSU5WQUxJREFUSU9OKSBwcml2YXRlIEhUVFBfSU5WQUxJREFUSU9OLFxyXG4gICAgQEluamVjdChDTElFTlRfQ0FDSEVfRFVSQVRJT05fUykgcHJpdmF0ZSBDTElFTlRfQ0FDSEVfRFVSQVRJT05fUyxcclxuICAgIEBJbmplY3QoQ0FDSEVfQllfVVNFUikgcHJpdmF0ZSBDQUNIRV9CWV9VU0VSOiBib29sZWFuLFxyXG4gICAgQEluamVjdChIVFRQX0RFQlVHX01PREUpIHByaXZhdGUgSFRUUF9ERUJVR19NT0RFOiBib29sZWFuLFxyXG4gICAgcHJpdmF0ZSBiYzogQmFzZUxvY2FsaXphdGlvbixcclxuICAgIHByaXZhdGUgaHR0cDogSHR0cENsaWVudCxcclxuICAgIHByaXZhdGUgbG9jYWxTdG9yYWdlOiBDYWNoZVNlcnZpY2UsXHJcbiAgICBwcml2YXRlIGhhc2g6IEhhc2hpbmdTZXJ2aWNlLFxyXG4gICAgcHJpdmF0ZSB1dGlzRXh0czogVXRpbGl0eVNlcnZpY2VcclxuICApIHtcclxuICAgIHRoaXMuRXh0ZW5zaW9uc0ltcGwgPSB0aGlzLkVYVEVOU0lPTl9DTEFTUyB8fCBuZXcgSHR0cFNlcnZpY2VFeHRlbnNpb25zKCk7XHJcbiAgfVxyXG5cclxuICBwdWJsaWMgc2V0QXBwQ29uZmlnKG15Y29uZmlnOiB7IEFwcERhdGE6IHsgTW9kdWxlSWQ6IHN0cmluZywgTW9kdWxlRGVmSWQ6IG51bWJlciwgQ29tcG9uZW50RW52aXJvbm1lbnQ6IHN0cmluZywgQ29tcG9uZW50VmVyc2lvbjogc3RyaW5nLCBNb2R1bGVEZXNjcmlwdGlvbjogc3RyaW5nIH0gfSl7XHJcbiAgICB0aGlzLmxvY2FsU3RvcmFnZUh0dHBDYWNoZUtleSA9IChteWNvbmZpZy5BcHBEYXRhLk1vZHVsZURlc2NyaXB0aW9uKS5yZXBsYWNlKC9cXHMvZywgJ18nKSArIFwiX0h0dHBDYWNoZVwiO1xyXG4gICAgdGhpcy5sb2NhbFN0b3JhZ2VIdHRwVGltZWRDYWNoZUtleSA9IChteWNvbmZpZy5BcHBEYXRhLk1vZHVsZURlc2NyaXB0aW9uKS5yZXBsYWNlKC9cXHMvZywgJ18nKSArIFwiX0h0dHBUaW1lZENhY2hlXCI7XHJcbiAgICB0aGlzLmxvY2FsU3RvcmFnZUh0dHBDYWNoZUV4cGlyZUtleSA9IHRoaXMubG9jYWxTdG9yYWdlSHR0cENhY2hlS2V5ICsgXCJfRXhwaXJlXCI7XHJcbiAgICB0aGlzLmFkanVzdE9sZFN0b3JhZ2VTeXN0ZW0oKTtcclxuXHJcbiAgICB0aGlzLkNhY2hlSW5pdGlhbGl6ZWQgPSB0cnVlO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogU2UgdmVkbyBjaGUgY2kgc29ubyBlbGVtZW50aSBzYWx2YXRpIG5lbCBsb2NhbFN0b3JhZ2UgcHJvdm8gYSB0b2dsaWVybGkgZSBhIHJpc2FsdmFybGkgdmlhIHByZWZlcmVuY2UuXHJcbiAgICogTmVsIGNhc28gbWlnbGlvcmUgbGkgc3Bvc3RvIGRhbCBsb2NhbFN0b3JhZ2UgYWwgREIgZGkgcHJlZmVyZW5jZSwgbmVsIGNhc28gcGVnZ2lvcmUgbGkgdG9sZ28gZSBsaSByaXNhbHZvIG5lbCBsb2NhbFN0b3JhZ2VcclxuICAgKi9cclxuICBwcml2YXRlIGFzeW5jIGFkanVzdE9sZFN0b3JhZ2VTeXN0ZW0oKSB7XHJcbiAgICB2YXIgbHNUaW1lZCA9IGxvY2FsU3RvcmFnZS5nZXRJdGVtKHRoaXMubG9jYWxTdG9yYWdlSHR0cFRpbWVkQ2FjaGVLZXkpO1xyXG4gICAgdmFyIGxzVW50aW1lZCA9IGxvY2FsU3RvcmFnZS5nZXRJdGVtKHRoaXMubG9jYWxTdG9yYWdlSHR0cENhY2hlS2V5KTtcclxuICAgIGlmICghbHNUaW1lZCAmJiAhbHNVbnRpbWVkKVxyXG4gICAgICByZXR1cm47XHJcblxyXG4gICAgbG9jYWxTdG9yYWdlLnJlbW92ZUl0ZW0odGhpcy5sb2NhbFN0b3JhZ2VIdHRwVGltZWRDYWNoZUtleSk7XHJcbiAgICBsb2NhbFN0b3JhZ2UucmVtb3ZlSXRlbSh0aGlzLmxvY2FsU3RvcmFnZUh0dHBDYWNoZUtleSk7XHJcbiAgICBsc1RpbWVkID0gbHNUaW1lZCA/IEpTT04ucGFyc2UobHNUaW1lZCkgOiB7fTtcclxuICAgIGxzVW50aW1lZCA9IGxzVW50aW1lZCA/IEpTT04ucGFyc2UobHNVbnRpbWVkKSA6IHt9O1xyXG5cclxuICAgIGF3YWl0IGZvcmtKb2luKFtcclxuICAgICAgdGhpcy5sb2NhbFN0b3JhZ2Uuc2V0SXRlbSh0aGlzLmxvY2FsU3RvcmFnZUh0dHBUaW1lZENhY2hlS2V5LCBsc1RpbWVkKSxcclxuICAgICAgdGhpcy5sb2NhbFN0b3JhZ2Uuc2V0SXRlbSh0aGlzLmxvY2FsU3RvcmFnZUh0dHBDYWNoZUtleSwgbHNVbnRpbWVkKVxyXG4gICAgXSkudG9Qcm9taXNlKCk7XHJcblxyXG4gICAgdGhpcy5sb2codGhpcy5sb2MoXCJDb252ZXJ0ZWQgb2xkIHN0b3JhZ2Ugc3lzdGVtIHRvIG5ldyBvbmVcIikpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogRXNlY3V6aW9uZSBkaSB1bmEgR0VUIEhUVFAgY29uIGV2ZW50dWFsbWVudGUgbGEgZ2VzdGlvbmUgZGVsbGEgY2FjaGUgcXVhbG9yYSBsYSBjaGlhbWF0YSB0ZXJtaW5pIGNvbiBsYSBjb252ZW56aW9uZSBcIiNjYWNoZVwiXHJcbiAgICogXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHVybCBVUkwgc3UgY3VpIGVmZmV0dHVhcmUgbGEgY2hpYW1hdGFcclxuICAgKiBAcGFyYW0ge0h0dHBQYXJhbXN9IHBhcmFtcyBQYXJhbWV0cmkgZGVsbGEgY2hpYW1hdGFcclxuICAgKiBAcGFyYW0ge3N0cmluZ30gdHJhbnNhY3Rpb24gQ29kaWNlIHRyYW5zYXppb25lIGNvbGxlZ2F0byBhIHF1ZXN0YSBjaGlhbWF0YS4gVmllbmUgaW5zZXJpdG8gbmVsbCdIZWFkZXIgXCJYLVRYLUlEXCIgZSBsYXRvIEJhY2tlbmQgZG92csOgIGVzc2VyZSBnZXN0aXRvIGRpIGNvbnNlZ3VlbnphXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdWNjZXNmdWxSZXN1bHRNYW5kYXRvcnkgSW5kaWNhIGNoZSBxdWVzdGEgY2hpYW1hdGEgZGV2ZSBhc3NvbHV0YW1lbnRlIGFuZGFyZSBiZW5lLiBJbiBjYXNvIGNvbnRyYXJpbyB2aWVuZSBmaXNpY2FtZW50ZSBmYXR0byBpbCB0aHJvdyBjaGUgcHXDsiBlc3NlcmUgXHJcbiAgICogcmFjY29sdG8gZGEgY2hpIHVzYSBsYSBsaWJyZXJpYSBuZWxsYSBwaXBlIFwib25FcnJvclwiIGRlbGwnT2JzZXJ2YWJsZSByZXN0aXR1aXRvIGVkIGVzc2VyZSBnZXN0aXRvIGluIG1hbmllcmEgbm9uIHN0YW5kYXJkXHJcbiAgICogQHBhcmFtIHtGdW5jdGlvbn0gZXJyb3JDYWxsYmFjayBDYWxsYmFjayBjaGlhbWF0byBpbiBjYXNvIGRpIGVycm9yZVxyXG4gICAqIFxyXG4gICAqIEByZXR1cm5zIHtPYnNlcnZhYmxlPFQ+fSBPYnNlcnZhYmxlIGNoZSBjb250aWVuZSBpbCByaXN1bHRhdG8gZGVsbGEgY2hpYW1hdGFcclxuICAgKi9cclxuICBwdWJsaWMgZ2V0PFQ+KHVybDogc3RyaW5nLCBwYXJhbXM6IEh0dHBQYXJhbXMgPSBudWxsLCB0cmFuc2FjdGlvbiA9IFwiXCIsIHN1Y2Nlc2Z1bFJlc3VsdE1hbmRhdG9yeTogYm9vbGVhbiA9IHRydWUsIGVycm9yQ2FsbGJhY2s6IEZ1bmN0aW9uID0gbnVsbCk6IE9ic2VydmFibGU8VD4ge1xyXG4gICAgcmV0dXJuIGZvcmtKb2luKFxyXG4gICAgICB7XHJcbiAgICAgICAgbXlHdWlkOiBmcm9tKFt0aGlzLmRlZmF1bHRTdGFydENhbGwodXJsKV0pLFxyXG4gICAgICAgIGxvY2FsZTogdGhpcy5iYy5Mb2NhbGUucGlwZShmaXJzdCgpKVxyXG4gICAgICB9KS5waXBlKFxyXG4gICAgICAgIGNvbmNhdE1hcCgocmV0OiB7IG15R3VpZDogc3RyaW5nLCBsb2NhbGU6IHN0cmluZyB9KSA9PiB7XHJcbiAgICAgICAgICBsZXQgY2FjaGVkSW5mb3MgPSB0aGlzLnRyeUdldENhY2hlSW5mb3JtYXRpb25zKHVybCwgcGFyYW1zKTtcclxuICAgICAgICAgIGlmIChjYWNoZWRJbmZvcy5jYWNoZSAmJiBjYWNoZWRJbmZvcy5jYWNoZUl0ZW0pIHtcclxuICAgICAgICAgICAgdGhpcy5sb2codGhpcy5sb2MoXCJSZXN1bHQgZm9yXCIpICsgXCIgXCIgKyB1cmwgKyBcIiBcIiArIHRoaXMubG9jKFwicmV0cmlldmVkIGZyb20gY2FjaGVcIikpO1xyXG4gICAgICAgICAgICByZXR1cm4gb2Y8VD4oY2FjaGVkSW5mb3MuY2FjaGVJdGVtKS5waXBlKGRlbGF5KDApLCBmaW5hbGl6ZSgoKSA9PiB7IHRoaXMudHJ5RmluYWxpemVCeUd1aWQocmV0Lm15R3VpZCk7IH0pKTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICB2YXIgaHR0cENhbGwgPSB0aGlzLmh0dHAuZ2V0PFQ+KGNhY2hlZEluZm9zLmZpbmFsVXJsLCB7IGhlYWRlcnM6IHRoaXMuZ2V0SGVhZGVycyhyZXQubG9jYWxlLCB0cmFuc2FjdGlvbiksIHBhcmFtczogcGFyYW1zIH0pO1xyXG5cclxuICAgICAgICAgIHJldHVybiBodHRwQ2FsbC5waXBlKFxyXG4gICAgICAgICAgICBtYXAoKHJlczogVCkgPT4ge1xyXG4gICAgICAgICAgICAgIGxldCByZXNwb25zZUl0ZW0gPSA8VD5yZXM7XHJcblxyXG4gICAgICAgICAgICAgIGlmIChjYWNoZWRJbmZvcy5jYWNoZSkge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5jYWNoZVJlc3BvbnNlKHRoaXMudXRpc0V4dHMuZGVlcENsb25lKHJlc3BvbnNlSXRlbSksIGNhY2hlZEluZm9zKTtcclxuICAgICAgICAgICAgICAgIHRoaXMubG9nKHRoaXMubG9jKFwiQ2FjaGVkIHJlc3VsdCBmb3JcIikgKyBcIiBcIiArIHVybCk7XHJcbiAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICByZXR1cm4gcmVzcG9uc2VJdGVtO1xyXG4gICAgICAgICAgICB9KSxcclxuICAgICAgICAgICAgY2F0Y2hFcnJvcigoZXJyLCBjYXVnaHQpOiBPYnNlcnZhYmxlPFQ+ID0+IHtcclxuICAgICAgICAgICAgICBpZiAoZXJyb3JDYWxsYmFjaykgZXJyb3JDYWxsYmFjaygpO1xyXG4gICAgICAgICAgICAgIHJldHVybiAhc3VjY2VzZnVsUmVzdWx0TWFuZGF0b3J5ID8gdGhyb3dFcnJvcihlcnIpIDogdGhpcy5yZWdpc3RlckVycm9yQW5kUmV0dXJuRW1wdHlPYnNlcnZhYmxlKGVyciwgcmV0Lm15R3VpZCk7XHJcbiAgICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgICBmaW5hbGl6ZSgoKSA9PiB7IHRoaXMudHJ5RmluYWxpemVCeUd1aWQocmV0Lm15R3VpZCwgY2FjaGVkSW5mb3MpOyB9KVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9KVxyXG4gICAgICApO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogRXNlY3V6aW9uZSBkaSB1bmEgR0VUIEhUVFAgY29uIGV2ZW50dWFsbWVudGUgbGEgZ2VzdGlvbmUgZGVsbGEgY2FjaGUgcXVhbG9yYSBsYSBjaGlhbWF0YSB0ZXJtaW5pIGNvbiBsYSBjb252ZW56aW9uZSBcIiNjYWNoZVwiXHJcbiAgICogXHJcbiAgICogQ2FzbyBzcGVjaWZpY28gZGkgY2hpYW1hdGEgY2hlIGRldmUgcmVzdGl0dWlyZSB1biBCbG9iIG8gdW4gQXJyYXlCdWZmZXIgbmF0aXZvIGRhIGVsYWJvcmFyZVxyXG4gICAqIFxyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgVVJMIHN1IGN1aSBlZmZldHR1YXJlIGxhIGNoaWFtYXRhXHJcbiAgICogQHBhcmFtIHtIdHRwUGFyYW1zfSBwYXJhbXMgUGFyYW1ldHJpIGRlbGxhIGNoaWFtYXRhXHJcbiAgICogQHBhcmFtIHtcImFycmF5YnVmZmVyXCJ8IFwiYmxvYlwifSB0eXBlIFRpcG8gZGkgcml0b3JubyByaWNoaWVzdG9cclxuICAgKiBAcGFyYW0ge3N0cmluZ30gdHJhbnNhY3Rpb24gQ29kaWNlIHRyYW5zYXppb25lIGNvbGxlZ2F0byBhIHF1ZXN0YSBjaGlhbWF0YS4gVmllbmUgaW5zZXJpdG8gbmVsbCdIZWFkZXIgXCJYLVRYLUlEXCIgZSBsYXRvIEJhY2tlbmQgZG92csOgIGVzc2VyZSBnZXN0aXRvIGRpIGNvbnNlZ3VlbnphXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdWNjZXNmdWxSZXN1bHRNYW5kYXRvcnkgSW5kaWNhIGNoZSBxdWVzdGEgY2hpYW1hdGEgZGV2ZSBhc3NvbHV0YW1lbnRlIGFuZGFyZSBiZW5lLiBJbiBjYXNvIGNvbnRyYXJpbyB2aWVuZSBmaXNpY2FtZW50ZSBmYXR0byBpbCB0aHJvdyBjaGUgcHXDsiBlc3NlcmUgXHJcbiAgICogcmFjY29sdG8gZGEgY2hpIHVzYSBsYSBsaWJyZXJpYSBuZWxsYSBwaXBlIFwib25FcnJvclwiIGRlbGwnT2JzZXJ2YWJsZSByZXN0aXR1aXRvIGVkIGVzc2VyZSBnZXN0aXRvIGluIG1hbmllcmEgbm9uIHN0YW5kYXJkXHJcbiAgICogQHBhcmFtIHtGdW5jdGlvbn0gZXJyb3JDYWxsYmFjayBDYWxsYmFjayBjaGlhbWF0byBpbiBjYXNvIGRpIGVycm9yZVxyXG4gICAqIFxyXG4gICAqIEByZXR1cm5zIHtPYnNlcnZhYmxlPEJsb2IgfCBBcnJheUJ1ZmZlcj59IE9ic2VydmFibGUgY2hlIGNvbnRpZW5lIGlsIHJpc3VsdGF0byBkZWxsYSBjaGlhbWF0YVxyXG4gICAqL1xyXG4gIHB1YmxpYyBnZXRSYXcodXJsOiBzdHJpbmcsIHBhcmFtczogSHR0cFBhcmFtcyA9IG51bGwsIHR5cGU6IFwiYXJyYXlidWZmZXJcIiB8IFwiYmxvYlwiID0gXCJhcnJheWJ1ZmZlclwiLCB0cmFuc2FjdGlvbiA9IFwiXCIsIHN1Y2Nlc2Z1bFJlc3VsdE1hbmRhdG9yeTogYm9vbGVhbiA9IHRydWUsIGVycm9yQ2FsbGJhY2sgPSBudWxsKTogT2JzZXJ2YWJsZTxCbG9iIHwgQXJyYXlCdWZmZXI+IHtcclxuICAgIHJldHVybiBmb3JrSm9pbihcclxuICAgICAge1xyXG4gICAgICAgIG15R3VpZDogZnJvbShbdGhpcy5kZWZhdWx0U3RhcnRDYWxsKHVybCldKSxcclxuICAgICAgICBsb2NhbGU6IHRoaXMuYmMuTG9jYWxlLnBpcGUoZmlyc3QoKSlcclxuICAgICAgfSkucGlwZShcclxuICAgICAgICBjb25jYXRNYXAoKHJldDogeyBteUd1aWQ6IHN0cmluZywgbG9jYWxlOiBzdHJpbmcgfSkgPT4ge1xyXG4gICAgICAgICAgbGV0IGNhY2hlZEluZm9zID0gdGhpcy50cnlHZXRDYWNoZUluZm9ybWF0aW9ucyh1cmwsIHBhcmFtcyk7XHJcbiAgICAgICAgICBpZiAoY2FjaGVkSW5mb3MuY2FjaGUgJiYgY2FjaGVkSW5mb3MuY2FjaGVJdGVtKSB7XHJcbiAgICAgICAgICAgIHRoaXMubG9nKHRoaXMubG9jKFwiUmVzdWx0IGZvclwiKSArIFwiIFwiICsgdXJsICsgXCIgXCIgKyB0aGlzLmxvYyhcInJldHJpZXZlZCBmcm9tIGNhY2hlXCIpKTtcclxuICAgICAgICAgICAgcmV0dXJuIG9mPGFueT4oY2FjaGVkSW5mb3MuY2FjaGVJdGVtKS5waXBlKGRlbGF5KDApLCBmaW5hbGl6ZSgoKSA9PiB7IHRoaXMudHJ5RmluYWxpemVCeUd1aWQocmV0Lm15R3VpZCk7IH0pKTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICB2YXIgaHR0cENhbGwgPSB0aGlzLmh0dHAuZ2V0KGNhY2hlZEluZm9zLmZpbmFsVXJsLCB7IHJlc3BvbnNlVHlwZTogPGFueT50eXBlLCBoZWFkZXJzOiB0aGlzLmdldEhlYWRlcnMocmV0LmxvY2FsZSwgdHJhbnNhY3Rpb24pLCBwYXJhbXM6IHBhcmFtcyB9KTtcclxuXHJcbiAgICAgICAgICByZXR1cm4gaHR0cENhbGwucGlwZShcclxuICAgICAgICAgICAgbWFwKChibG9iOiBCbG9iIHwgQXJyYXlCdWZmZXIpID0+IHtcclxuXHJcbiAgICAgICAgICAgICAgaWYgKGNhY2hlZEluZm9zLmNhY2hlKSB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmNhY2hlUmVzcG9uc2UoYmxvYiwgY2FjaGVkSW5mb3MpO1xyXG4gICAgICAgICAgICAgICAgdGhpcy5sb2codGhpcy5sb2MoXCJDYWNoZWQgcmVzdWx0IGZvclwiKSArIFwiIFwiICsgdXJsKTtcclxuICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgIHJldHVybiBibG9iO1xyXG4gICAgICAgICAgICB9KSxcclxuICAgICAgICAgICAgY2F0Y2hFcnJvcigoZXJyLCBjYXVnaHQpOiBPYnNlcnZhYmxlPEJsb2I+ID0+IHtcclxuICAgICAgICAgICAgICBpZiAoZXJyb3JDYWxsYmFjaykgZXJyb3JDYWxsYmFjaygpO1xyXG4gICAgICAgICAgICAgIHJldHVybiAhc3VjY2VzZnVsUmVzdWx0TWFuZGF0b3J5ID8gdGhyb3dFcnJvcihlcnIpIDogdGhpcy5yZWdpc3RlckVycm9yQW5kUmV0dXJuRW1wdHlPYnNlcnZhYmxlKGVyciwgcmV0Lm15R3VpZCk7XHJcbiAgICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgICBmaW5hbGl6ZSgoKSA9PiB7IHRoaXMudHJ5RmluYWxpemVCeUd1aWQocmV0Lm15R3VpZCwgY2FjaGVkSW5mb3MpOyB9KVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9KVxyXG4gICAgICApO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgKiBFc2VjdXppb25lIGRpIHVuYSBQT1NUIEhUVFBcclxuICAqIFxyXG4gICogQHBhcmFtIHtzdHJpbmd9IHVybCBVUkwgc3UgY3VpIGVmZmV0dHVhcmUgbGEgY2hpYW1hdGFcclxuICAqIEBwYXJhbSB7YW55fSBib2R5RGF0YSBEVE8gcGVyIGxhIGNoaWFtYXRhXHJcbiAgKiBAcGFyYW0ge0h0dHBQYXJhbXN9IHBhcmFtcyBQYXJhbWV0cmkgZGVsbGEgY2hpYW1hdGFcclxuICAqIEBwYXJhbSB7c3RyaW5nfSB0cmFuc2FjdGlvbiBDb2RpY2UgdHJhbnNhemlvbmUgY29sbGVnYXRvIGEgcXVlc3RhIGNoaWFtYXRhLiBWaWVuZSBpbnNlcml0byBuZWxsJ0hlYWRlciBcIlgtVFgtSURcIiBlIGxhdG8gQmFja2VuZCBkb3Zyw6AgZXNzZXJlIGdlc3RpdG8gZGkgY29uc2VndWVuemFcclxuICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3VjY2VzZnVsUmVzdWx0TWFuZGF0b3J5IEluZGljYSBjaGUgcXVlc3RhIGNoaWFtYXRhIGRldmUgYXNzb2x1dGFtZW50ZSBhbmRhcmUgYmVuZS4gSW4gY2FzbyBjb250cmFyaW8gdmllbmUgZmlzaWNhbWVudGUgZmF0dG8gaWwgdGhyb3cgY2hlIHB1w7IgZXNzZXJlIFxyXG4gICogcmFjY29sdG8gZGEgY2hpIHVzYSBsYSBsaWJyZXJpYSBuZWxsYSBwaXBlIFwib25FcnJvclwiIGRlbGwnT2JzZXJ2YWJsZSByZXN0aXR1aXRvIGVkIGVzc2VyZSBnZXN0aXRvIGluIG1hbmllcmEgbm9uIHN0YW5kYXJkXHJcbiAgKiBcclxuICAqIEByZXR1cm5zIHtPYnNlcnZhYmxlPFQ+fSBPYnNlcnZhYmxlIGNoZSBjb250aWVuZSBpbCByaXN1bHRhdG8gZGVsbGEgY2hpYW1hdGFcclxuICAqL1xyXG4gIHB1YmxpYyBwb3N0PFQ+KHVybDogc3RyaW5nLCBib2R5RGF0YTogYW55LCBwYXJhbXM6IEh0dHBQYXJhbXMgPSBudWxsLCB0cmFuc2FjdGlvbiA9IFwiXCIsIHN1Y2Nlc2Z1bFJlc3VsdE1hbmRhdG9yeTogYm9vbGVhbiA9IHRydWUpOiBPYnNlcnZhYmxlPFQ+IHtcclxuICAgIHJldHVybiBmb3JrSm9pbihcclxuICAgICAge1xyXG4gICAgICAgIG15R3VpZDogZnJvbShbdGhpcy5kZWZhdWx0U3RhcnRDYWxsKHVybCldKSxcclxuICAgICAgICBsb2NhbGU6IHRoaXMuYmMuTG9jYWxlLnBpcGUoZmlyc3QoKSlcclxuICAgICAgfSkucGlwZShcclxuICAgICAgICBjb25jYXRNYXAoKHJldDogeyBteUd1aWQ6IHN0cmluZywgbG9jYWxlOiBzdHJpbmcgfSkgPT4ge1xyXG5cclxuICAgICAgICAgIC8vIFNlIMOoIHVuYSByaWNlcmNhLCBzaGFsbG93IGNvcHkgZSByaW11b3ZvIGdsaSBcIml0ZW1zXCIgcGVyIGV2aXRhcmUgZGkgZmFybGkgYW5kYXJlIHN1IGUgZ2nDuSBhbCBiYWNrZW5kXHJcbiAgICAgICAgICBpZiAoISFib2R5RGF0YT8uaXRlbXMgJiYgISFib2R5RGF0YT8ucGFnZSkge1xyXG4gICAgICAgICAgICBib2R5RGF0YSA9IHsgLi4uYm9keURhdGEgfTtcclxuICAgICAgICAgICAgZGVsZXRlIGJvZHlEYXRhLml0ZW1zO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIHZhciBodHRwQ2FsbCA9IHRoaXMuaHR0cC5wb3N0PFQ+KHVybCwgYm9keURhdGEsIHsgaGVhZGVyczogdGhpcy5nZXRIZWFkZXJzKHJldC5sb2NhbGUsIHRyYW5zYWN0aW9uKSwgcGFyYW1zOiBwYXJhbXMgfSk7XHJcblxyXG4gICAgICAgICAgcmV0dXJuIGh0dHBDYWxsLnBpcGUoXHJcbiAgICAgICAgICAgIGNhdGNoRXJyb3IoKGVyciwgXyk6IE9ic2VydmFibGU8VD4gPT4ge1xyXG4gICAgICAgICAgICAgIHJldHVybiAhc3VjY2VzZnVsUmVzdWx0TWFuZGF0b3J5ID8gdGhyb3dFcnJvcihlcnIpIDogdGhpcy5yZWdpc3RlckVycm9yQW5kUmV0dXJuRW1wdHlPYnNlcnZhYmxlKGVyciwgcmV0Lm15R3VpZCk7XHJcbiAgICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgICBmaW5hbGl6ZSgoKSA9PiB7IHRoaXMudHJ5RmluYWxpemVCeUd1aWQocmV0Lm15R3VpZCk7IH0pXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0pXHJcbiAgICAgICk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAqIEVzZWN1emlvbmUgZGkgdW5hIERFTEVURSBIVFRQXHJcbiAgKlxyXG4gICogQHBhcmFtIHtzdHJpbmd9IHVybCBVUkwgc3UgY3VpIGVmZmV0dHVhcmUgbGEgY2hpYW1hdGFcclxuICAqIEBwYXJhbSB7SHR0cFBhcmFtc30gcGFyYW1zIFBhcmFtZXRyaSBkZWxsYSBjaGlhbWF0YVxyXG4gICogQHBhcmFtIHtzdHJpbmd9IHRyYW5zYWN0aW9uIENvZGljZSB0cmFuc2F6aW9uZSBjb2xsZWdhdG8gYSBxdWVzdGEgY2hpYW1hdGEuIFZpZW5lIGluc2VyaXRvIG5lbGwnSGVhZGVyIFwiWC1UWC1JRFwiIGUgbGF0byBCYWNrZW5kIGRvdnLDoCBlc3NlcmUgZ2VzdGl0byBkaSBjb25zZWd1ZW56YVxyXG4gICogQHBhcmFtIHtib29sZWFufSBzdWNjZXNmdWxSZXN1bHRNYW5kYXRvcnkgSW5kaWNhIGNoZSBxdWVzdGEgY2hpYW1hdGEgZGV2ZSBhc3NvbHV0YW1lbnRlIGFuZGFyZSBiZW5lLiBJbiBjYXNvIGNvbnRyYXJpbyB2aWVuZSBmaXNpY2FtZW50ZSBmYXR0byBpbCB0aHJvdyBjaGUgcHXDsiBlc3NlcmUgXHJcbiAgKiByYWNjb2x0byBkYSBjaGkgdXNhIGxhIGxpYnJlcmlhIG5lbGxhIHBpcGUgXCJvbkVycm9yXCIgZGVsbCdPYnNlcnZhYmxlIHJlc3RpdHVpdG8gZWQgZXNzZXJlIGdlc3RpdG8gaW4gbWFuaWVyYSBub24gc3RhbmRhcmRcclxuICAqIFxyXG4gICogQHJldHVybnMge09ic2VydmFibGU8VD59IE9ic2VydmFibGUgY2hlIGNvbnRpZW5lIGlsIHJpc3VsdGF0byBkZWxsYSBjaGlhbWF0YVxyXG4gICovXHJcbiAgcHVibGljIGRlbGV0ZTxUPih1cmw6IHN0cmluZywgcGFyYW1zOiBIdHRwUGFyYW1zID0gbnVsbCwgdHJhbnNhY3Rpb24gPSBcIlwiLCBzdWNjZXNmdWxSZXN1bHRNYW5kYXRvcnk6IGJvb2xlYW4gPSB0cnVlKTogT2JzZXJ2YWJsZTxUPiB7XHJcbiAgICByZXR1cm4gZm9ya0pvaW4oXHJcbiAgICAgIHtcclxuICAgICAgICBteUd1aWQ6IGZyb20oW3RoaXMuZGVmYXVsdFN0YXJ0Q2FsbCh1cmwpXSksXHJcbiAgICAgICAgbG9jYWxlOiB0aGlzLmJjLkxvY2FsZS5waXBlKGZpcnN0KCkpXHJcbiAgICAgIH0pLnBpcGUoXHJcbiAgICAgICAgY29uY2F0TWFwKChyZXQ6IHsgbXlHdWlkOiBzdHJpbmcsIGxvY2FsZTogc3RyaW5nIH0pID0+IHtcclxuXHJcbiAgICAgICAgICB2YXIgaHR0cENhbGwgPSB0aGlzLmh0dHAuZGVsZXRlPFQ+KHVybCwgeyBoZWFkZXJzOiB0aGlzLmdldEhlYWRlcnMocmV0LmxvY2FsZSwgdHJhbnNhY3Rpb24pLCBwYXJhbXM6IHBhcmFtcyB9KTtcclxuXHJcbiAgICAgICAgICByZXR1cm4gaHR0cENhbGwucGlwZShcclxuICAgICAgICAgICAgY2F0Y2hFcnJvcigoZXJyLCBjYXVnaHQpOiBPYnNlcnZhYmxlPFQ+ID0+IHtcclxuICAgICAgICAgICAgICByZXR1cm4gIXN1Y2Nlc2Z1bFJlc3VsdE1hbmRhdG9yeSA/IHRocm93RXJyb3IoZXJyKSA6IHRoaXMucmVnaXN0ZXJFcnJvckFuZFJldHVybkVtcHR5T2JzZXJ2YWJsZShlcnIsIHJldC5teUd1aWQpO1xyXG4gICAgICAgICAgICB9KSxcclxuICAgICAgICAgICAgZmluYWxpemUoKCkgPT4geyB0aGlzLnRyeUZpbmFsaXplQnlHdWlkKHJldC5teUd1aWQpOyB9KVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9KVxyXG4gICAgICApO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogRXNlY3V6aW9uZSBkaSB1bmEgUFVUIEhUVFBcclxuICAgKiBcclxuICAgKiBAcGFyYW0ge3N0cmluZ30gdXJsIFVSTCBzdSBjdWkgZWZmZXR0dWFyZSBsYSBjaGlhbWF0YVxyXG4gICAqIEBwYXJhbSB7YW55fSBib2R5RGF0YSBEVE8gcGVyIGxhIGNoaWFtYXRhXHJcbiAgICogQHBhcmFtIHtIdHRwUGFyYW1zfSBwYXJhbXMgUGFyYW1ldHJpIGRlbGxhIGNoaWFtYXRhXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRyYW5zYWN0aW9uIENvZGljZSB0cmFuc2F6aW9uZSBjb2xsZWdhdG8gYSBxdWVzdGEgY2hpYW1hdGEuIFZpZW5lIGluc2VyaXRvIG5lbGwnSGVhZGVyIFwiWC1UWC1JRFwiIGUgbGF0byBCYWNrZW5kIGRvdnLDoCBlc3NlcmUgZ2VzdGl0byBkaSBjb25zZWd1ZW56YVxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3VjY2VzZnVsUmVzdWx0TWFuZGF0b3J5IEluZGljYSBjaGUgcXVlc3RhIGNoaWFtYXRhIGRldmUgYXNzb2x1dGFtZW50ZSBhbmRhcmUgYmVuZS4gSW4gY2FzbyBjb250cmFyaW8gdmllbmUgZmlzaWNhbWVudGUgZmF0dG8gaWwgdGhyb3cgY2hlIHB1w7IgZXNzZXJlIFxyXG4gICAqIHJhY2NvbHRvIGRhIGNoaSB1c2EgbGEgbGlicmVyaWEgbmVsbGEgcGlwZSBcIm9uRXJyb3JcIiBkZWxsJ09ic2VydmFibGUgcmVzdGl0dWl0byBlZCBlc3NlcmUgZ2VzdGl0byBpbiBtYW5pZXJhIG5vbiBzdGFuZGFyZFxyXG4gICAqIFxyXG4gICAqIEByZXR1cm5zIHtPYnNlcnZhYmxlPFQ+fSBPYnNlcnZhYmxlIGNoZSBjb250aWVuZSBpbCByaXN1bHRhdG8gZGVsbGEgY2hpYW1hdGFcclxuICAgKi9cclxuICBwdWJsaWMgcHV0PFQ+KHVybDogc3RyaW5nLCBib2R5RGF0YTogYW55LCBwYXJhbXM6IEh0dHBQYXJhbXMgPSBudWxsLCB0cmFuc2FjdGlvbiA9IFwiXCIsIHN1Y2Nlc2Z1bFJlc3VsdE1hbmRhdG9yeTogYm9vbGVhbiA9IHRydWUpOiBPYnNlcnZhYmxlPFQ+IHtcclxuICAgIHJldHVybiBmb3JrSm9pbihcclxuICAgICAge1xyXG4gICAgICAgIG15R3VpZDogZnJvbShbdGhpcy5kZWZhdWx0U3RhcnRDYWxsKHVybCldKSxcclxuICAgICAgICBsb2NhbGU6IHRoaXMuYmMuTG9jYWxlLnBpcGUoZmlyc3QoKSlcclxuICAgICAgfSkucGlwZShcclxuICAgICAgICBjb25jYXRNYXAoKHJldDogeyBteUd1aWQ6IHN0cmluZywgbG9jYWxlOiBzdHJpbmcgfSkgPT4ge1xyXG5cclxuICAgICAgICAgIHZhciBodHRwQ2FsbCA9IHRoaXMuaHR0cC5wdXQ8VD4odXJsLCBib2R5RGF0YSwgeyBoZWFkZXJzOiB0aGlzLmdldEhlYWRlcnMocmV0LmxvY2FsZSwgdHJhbnNhY3Rpb24pLCBwYXJhbXM6IHBhcmFtcyB9KTtcclxuXHJcbiAgICAgICAgICByZXR1cm4gaHR0cENhbGwucGlwZShcclxuICAgICAgICAgICAgY2F0Y2hFcnJvcigoZXJyLCBjYXVnaHQpOiBPYnNlcnZhYmxlPFQ+ID0+IHtcclxuICAgICAgICAgICAgICByZXR1cm4gIXN1Y2Nlc2Z1bFJlc3VsdE1hbmRhdG9yeSA/IHRocm93RXJyb3IoZXJyKSA6IHRoaXMucmVnaXN0ZXJFcnJvckFuZFJldHVybkVtcHR5T2JzZXJ2YWJsZShlcnIsIHJldC5teUd1aWQpO1xyXG4gICAgICAgICAgICB9KSxcclxuICAgICAgICAgICAgZmluYWxpemUoKCkgPT4geyB0aGlzLnRyeUZpbmFsaXplQnlHdWlkKHJldC5teUd1aWQpOyB9KVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9KVxyXG4gICAgICApO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogRXNlY3V6aW9uZSBkaSB1bmEgUE9TVCBIVFRQXHJcbiAgICogXHJcbiAgICogQ2FzaXN0aWNhIHBhcnRpY29sYXJlIGluIGN1aSBiaXNvZ25hIGFuY2hlIGludmlhcmUgZGVpIEZpbGVcclxuICAgKiBcclxuICAgKiBAcGFyYW0ge3N0cmluZ30gdXJsIFVSTCBzdSBjdWkgZWZmZXR0dWFyZSBsYSBjaGlhbWF0YVxyXG4gICAqIEBwYXJhbSB7YW55fSBib2R5RGF0YSBEVE8gcGVyIGxhIGNoaWFtYXRhXHJcbiAgICogQHBhcmFtIHtGaWxlW10gfCBGaWxlfSBmaWxlQXJyYXlPckZpbGUgU2luZ29sbyBmaWxlIG8gbGlzdGEgZGkgZmlsZSBkYSBpbnZpYXJlLiBJbCB0aXBvICoqRmlsZSoqIMOoIHF1ZWxsbyBuYXRpdm8gZGVsIEphdmFzY3JpcHRcclxuICAgKiBcclxuICAgKiBAcmV0dXJucyB7T2JzZXJ2YWJsZTxUPn0gT2JzZXJ2YWJsZSBjaGUgY29udGllbmUgaWwgcmlzdWx0YXRvIGRlbGxhIGNoaWFtYXRhXHJcbiAgICovXHJcbiAgcHVibGljIHBvc3R3aXRoRmlsZXM8VD4odXJsOiBzdHJpbmcsIGJvZHlEYXRhOiBhbnksIGZpbGVBcnJheU9yRmlsZTogRmlsZVtdIHwgRmlsZSwgcGFyYW1zOiBIdHRwUGFyYW1zID0gbnVsbCwgc3VjY2VzZnVsUmVzdWx0TWFuZGF0b3J5OiBib29sZWFuID0gdHJ1ZSwgb25FcnJvcj86ICgpID0+IHZvaWQpOiBPYnNlcnZhYmxlPFQ+IHtcclxuICAgIHJldHVybiBmb3JrSm9pbihcclxuICAgICAge1xyXG4gICAgICAgIG15R3VpZDogZnJvbShbdGhpcy5kZWZhdWx0U3RhcnRDYWxsKHVybCldKSxcclxuICAgICAgICBsb2NhbGU6IHRoaXMuYmMuTG9jYWxlLnBpcGUoZmlyc3QoKSlcclxuICAgICAgfSkucGlwZShcclxuICAgICAgICBjb25jYXRNYXAoKHJldDogeyBteUd1aWQ6IHN0cmluZywgbG9jYWxlOiBzdHJpbmcgfSkgPT4ge1xyXG5cclxuICAgICAgICAgIHZhciBmb3JtRGF0YSA9IHRoaXMuZ2V0RmlsZXNGb3JtRGF0YShmaWxlQXJyYXlPckZpbGUpO1xyXG4gICAgICAgICAgZm9ybURhdGEuYXBwZW5kKFwiYm9keVwiLCBKU09OLnN0cmluZ2lmeShib2R5RGF0YSkpO1xyXG5cclxuICAgICAgICAgIHZhciBodHRwQ2FsbCA9IHRoaXMuaHR0cC5wb3N0PFQ+KHVybCwgZm9ybURhdGEsIHsgcGFyYW1zOiBwYXJhbXMsIGhlYWRlcnM6IHRoaXMuZ2V0SGVhZGVycyhyZXQubG9jYWxlLCBudWxsLCB0cnVlLCBudWxsLCBudWxsKSB9KTtcclxuXHJcbiAgICAgICAgcmV0dXJuIGh0dHBDYWxsLnBpcGUoXHJcbiAgICAgICAgICBjYXRjaEVycm9yKChlcnIsIGNhdWdodCk6IE9ic2VydmFibGU8VD4gPT4geyBcclxuICAgICAgICAgICAgb25FcnJvcj8uKCk7XHJcbiAgICAgICAgICAgIHJldHVybiAhc3VjY2VzZnVsUmVzdWx0TWFuZGF0b3J5ID8gdGhyb3dFcnJvcihlcnIpIDogdGhpcy5yZWdpc3RlckVycm9yQW5kUmV0dXJuRW1wdHlPYnNlcnZhYmxlKGVyciwgcmV0Lm15R3VpZCk7IFxyXG4gICAgICAgICAgfSksXHJcbiAgICAgICAgICBmaW5hbGl6ZSgoKSA9PiB7IHRoaXMudHJ5RmluYWxpemVCeUd1aWQocmV0Lm15R3VpZCk7IH0pXHJcbiAgICAgICAgKTtcclxuICAgICAgfSlcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBFc2VjdXppb25lIGRpIHVuYSBQT1NUIEhUVFBcclxuICAgKiBcclxuICAgKiBDYXNpc3RpY2EgcGFydGljb2xhcmUgaW4gY3VpIHZpZW5lIHJlc3RpdHVpdG8gdW4gZmlsZSBnZXN0aXRvIGNvbWUgT2JqZWN0VVJMIGlsIGN1aSBVUkwgc2kgcHXDsiBnZXN0aXJlIGRhbCBwYXJhbWV0cm8gZGkgY2FsbGJhY2sgKipnZXRGaWxlQ2FsbGJhY2sqKi4gXHJcbiAgICogTGEgY2hpYW1hdGEgbm9uIGhhIHVuIHRpcG8gcmVzdGl0dWl0byBpbiBxdWFudG8gaWwgcmlzdWx0YXRvIGRldidlc3NlcmUgZ2VzdGl0byBhdHRyYXZlcnNvIGxhIGNhbGxiYWNrICoqZ2V0RmlsZUNhbGxiYWNrKipcclxuICAgKiBcclxuICAgKiBAcGFyYW0ge3N0cmluZ30gdXJsIFVSTCBzdSBjdWkgZWZmZXR0dWFyZSBsYSBjaGlhbWF0YVxyXG4gICAqIEBwYXJhbSB7S30gYm9keURhdGEgRFRPIHBlciBsYSBjaGlhbWF0YVxyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBmaWxlbmFtZSBOb21lIGRlbCBmaWxlIGNoZSBzaSBzdGEgcmljaGllZGVuZG8sIHJpbWFuZSBsYXRvIEZyb250ZW5kIGUgc2VydmUgcGVyIGFzc2VnbmFyZSBhcmJpdHJhcmlhbWVudGUgdW4gbm9tZSBhbCBmaWxlIHJlc3RpdHVpdG8sIHNlIHZ1b3RvIHZpZW5lIHV0aWxpenphdGEgbGEgQ29udGVudC1EaXNwb3NpdGlvbiBkZWxsYSByaXNwb3N0YVxyXG4gICAqIEBwYXJhbSB7RnVuY3Rpb259IGdldEZpbGVDYWxsYmFjayBDYWxsYmFjayBhIGR1ZSBwYXJhbWV0cmkgKHVybDogc3RyaW5nLCBmaWxlbmFtZTogc3RyaW5nKSBwZXIgZ2VzdGlyZSBpbCByaXN1bHRhdG8gZGVsIGZpbGUgcmljaGllc3RvLiAqKlV0aWxpenphcmUgVXRpbGl0eVNlcnZpY2UuZmlsZURvd25sb2FkKiogZGkgQGVzZmFlbnphL2V4dGVuc2lvbnNcclxuICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBhZnRlckdldEZpbGUgQ2FsbGJhY2sgZGEgY2hpYW1hcmUgZG9wbyBhdmVyIGdlc3RpdG8gbGEgcmlzcG9zdGEgZGVsICoqZ2V0RmlsZUNhbGxiYWNrKiosIGluIGNhc28gKipoYW5kbGVFcnJvcioqIGZvc3NlICoqZmFsc2UqKiB2ZXJyw6AgcmljaGlhbWF0byBhbmNoZSBpbiBjYXNvIGRpIGVycm9yZVxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gaGFuZGxlRXJyb3IgSW5kaWNhIHNlIGRpIGRlZmF1bHQgZ2xpIGVycm9yaSBkZXZvbm8gZXNzZXJlIGdlc3RpdGkgZGFsbGEgbGlicmVyaWEgbyBzZSBkZXZvbm8gZXNzZXJlIGlnbm9yYXRpXHJcbiAgICovXHJcbiAgcHVibGljIGFzeW5jIHBvc3RHZXRGaWxlPEs+KHVybDogc3RyaW5nLCBib2R5RGF0YTogSywgZmlsZW5hbWU6IHN0cmluZywgZ2V0RmlsZUNhbGxiYWNrOiAodXJsOiBzdHJpbmcsIGZpbGVuYW1lOiBzdHJpbmcpID0+IGFueSwgYWZ0ZXJHZXRGaWxlOiAoKSA9PiBhbnkgPSBudWxsLCBoYW5kbGVFcnJvcjogYm9vbGVhbiA9IHRydWUsIHBhcnM/OiBIdHRwUGFyYW1zKSB7XHJcbiAgICBsZXQgbXlHdWlkID0gdGhpcy5kZWZhdWx0U3RhcnRDYWxsKHVybCk7XHJcbiAgICBsZXQgbG9jYWxlID0gYXdhaXQgdGhpcy5iYy5Mb2NhbGUucGlwZShmaXJzdCgpKS50b1Byb21pc2UoKTtcclxuXHJcbiAgICB0aGlzLmh0dHAucG9zdCh1cmwsIGJvZHlEYXRhLCB7IHBhcmFtczogcGFycywgaGVhZGVyczogdGhpcy5nZXRIZWFkZXJzKGxvY2FsZSksIG9ic2VydmU6ICdyZXNwb25zZScsIHJlc3BvbnNlVHlwZTogXCJibG9iXCIgfSkucGlwZShcclxuICAgICAgY2F0Y2hFcnJvcigoZXJyLCBjYXVnaHQpOiBPYnNlcnZhYmxlPHN0cmluZz4gPT4ge1xyXG4gICAgICAgIGlmIChhZnRlckdldEZpbGUgJiYgIWhhbmRsZUVycm9yKSBhZnRlckdldEZpbGUoKTtcclxuICAgICAgICByZXR1cm4gdGhpcy5yZWdpc3RlckVycm9yQW5kUmV0dXJuRW1wdHlPYnNlcnZhYmxlKGVyciwgbXlHdWlkLCBoYW5kbGVFcnJvcik7XHJcbiAgICAgIH0pLFxyXG4gICAgICBmaW5hbGl6ZSgoKSA9PiB7IHRoaXMudHJ5RmluYWxpemVCeUd1aWQobXlHdWlkKTsgfSlcclxuICAgICkuc3Vic2NyaWJlKChyZXNwb25zZTogSHR0cFJlc3BvbnNlPEJsb2I+KSA9PiB7XHJcbiAgICAgIGxldCByZXRVcmwgPSB3aW5kb3cuVVJMLmNyZWF0ZU9iamVjdFVSTChyZXNwb25zZS5ib2R5KTtcclxuICAgICAgbGV0IGZuID0gcmVzcG9uc2UuaGVhZGVycy5nZXQoJ2NvbnRlbnQtZGlzcG9zaXRpb24nKT8uc3BsaXQoJzsnKVsxXT8uc3BsaXQoJ2ZpbGVuYW1lJylbMV0/LnNwbGl0KCc9JylbMV0/LnRyaW0oKS5yZXBsYWNlKC9cXFwiL2csICcnKTtcclxuXHJcbiAgICAgIGdldEZpbGVDYWxsYmFjayhyZXRVcmwsIGZpbGVuYW1lIHx8IGZuKTtcclxuICAgICAgaWYgKGFmdGVyR2V0RmlsZSkgYWZ0ZXJHZXRGaWxlKCk7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEVzZWN1emlvbmUgZGkgdW5hIEdFVCBIVFRQXHJcbiAgICogXHJcbiAgICogQ2FzaXN0aWNhIHBhcnRpY29sYXJlIGluIGN1aSB2aWVuZSByZXN0aXR1aXRvIHVuIGZpbGUgZ2VzdGl0byBjb21lIE9iamVjdFVSTCBpbCBjdWkgVVJMIHNpIHB1w7IgZ2VzdGlyZSBkYWwgcGFyYW1ldHJvIGRpIGNhbGxiYWNrICoqZ2V0RmlsZUNhbGxiYWNrKiouIFxyXG4gICAqIExhIGNoaWFtYXRhIG5vbiBoYSB1biB0aXBvIHJlc3RpdHVpdG8gaW4gcXVhbnRvIGlsIHJpc3VsdGF0byBkZXYnZXNzZXJlIGdlc3RpdG8gYXR0cmF2ZXJzbyBsYSBjYWxsYmFjayAqKmdldEZpbGVDYWxsYmFjayoqXHJcbiAgICogXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHVybCBVUkwgc3UgY3VpIGVmZmV0dHVhcmUgbGEgY2hpYW1hdGFcclxuICAgKiBAcGFyYW0ge0h0dHBQYXJhbXN9IHBhcmFtcyBQYXJhbWV0cmkgZGVsbGEgY2hpYW1hdGFcclxuICAgKiBAcGFyYW0ge3N0cmluZ30gZmlsZW5hbWUgTm9tZSBkZWwgZmlsZSBjaGUgc2kgc3RhIHJpY2hpZWRlbmRvLCByaW1hbmUgbGF0byBGcm9udGVuZCBlIHNlcnZlIHBlciBhc3NlZ25hcmUgYXJiaXRyYXJpYW1lbnRlIHVuIG5vbWUgYWwgZmlsZSByZXN0aXR1aXRvLCBzZSB2dW90byB2aWVuZSB1dGlsaXp6YXRhIGxhIENvbnRlbnQtRGlzcG9zaXRpb24gZGVsbGEgcmlzcG9zdGFcclxuICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBnZXRGaWxlQ2FsbGJhY2sgQ2FsbGJhY2sgYSBkdWUgcGFyYW1ldHJpICh1cmw6IHN0cmluZywgZmlsZW5hbWU6IHN0cmluZykgcGVyIGdlc3RpcmUgaWwgcmlzdWx0YXRvIGRlbCBmaWxlIHJpY2hpZXN0by4gKipVdGlsaXp6YXJlIFV0aWxpdHlTZXJ2aWNlLmZpbGVEb3dubG9hZCoqIGRpIEBlc2ZhZW56YS9leHRlbnNpb25zXHJcbiAgICogQHBhcmFtIHtGdW5jdGlvbn0gYWZ0ZXJHZXRGaWxlIENhbGxiYWNrIGRhIGNoaWFtYXJlIGRvcG8gYXZlciBnZXN0aXRvIGxhIHJpc3Bvc3RhIGRlbCAqKmdldEZpbGVDYWxsYmFjayoqLCBpbiBjYXNvICoqaGFuZGxlRXJyb3IqKiBmb3NzZSAqKmZhbHNlKiogdmVycsOgIHJpY2hpYW1hdG8gYW5jaGUgaW4gY2FzbyBkaSBlcnJvcmVcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IGhhbmRsZUVycm9yIEluZGljYSBzZSBkaSBkZWZhdWx0IGdsaSBlcnJvcmkgZGV2b25vIGVzc2VyZSBnZXN0aXRpIGRhbGxhIGxpYnJlcmlhIG8gc2UgZGV2b25vIGVzc2VyZSBpZ25vcmF0aVxyXG4gICAqL1xyXG4gIHB1YmxpYyBhc3luYyBnZXRGaWxlKHVybDogc3RyaW5nLCBwYXJhbXM6IEh0dHBQYXJhbXMgPSBudWxsLCBmaWxlbmFtZTogc3RyaW5nLCBnZXRGaWxlQ2FsbGJhY2s6ICh1cmw6IHN0cmluZywgZmlsZW5hbWU6IHN0cmluZykgPT4gYW55LCBhZnRlckdldEZpbGU6ICgpID0+IGFueSA9IG51bGwsIGhhbmRsZUVycm9yOiBib29sZWFuID0gdHJ1ZSkge1xyXG4gICAgbGV0IG15R3VpZCA9IHRoaXMuZGVmYXVsdFN0YXJ0Q2FsbCh1cmwpO1xyXG4gICAgbGV0IGxvY2FsZSA9IGF3YWl0IHRoaXMuYmMuTG9jYWxlLnBpcGUoZmlyc3QoKSkudG9Qcm9taXNlKCk7XHJcblxyXG4gICAgdGhpcy5odHRwLmdldCh1cmwsIHsgcGFyYW1zOiBwYXJhbXMsIGhlYWRlcnM6IHRoaXMuZ2V0SGVhZGVycyhsb2NhbGUpLCBvYnNlcnZlOiAncmVzcG9uc2UnLCByZXNwb25zZVR5cGU6IFwiYmxvYlwiIH0pLnBpcGUoXHJcbiAgICAgIGNhdGNoRXJyb3IoKGVyciwgY2F1Z2h0KTogT2JzZXJ2YWJsZTxzdHJpbmc+ID0+IHtcclxuICAgICAgICBpZiAoYWZ0ZXJHZXRGaWxlICYmICFoYW5kbGVFcnJvcikgYWZ0ZXJHZXRGaWxlKCk7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMucmVnaXN0ZXJFcnJvckFuZFJldHVybkVtcHR5T2JzZXJ2YWJsZShlcnIsIG15R3VpZCwgaGFuZGxlRXJyb3IpO1xyXG4gICAgICB9KSxcclxuICAgICAgZmluYWxpemUoKCkgPT4geyB0aGlzLnRyeUZpbmFsaXplQnlHdWlkKG15R3VpZCk7IH0pXHJcbiAgICApLnN1YnNjcmliZSgocmVzcG9uc2U6IEh0dHBSZXNwb25zZTxCbG9iPikgPT4ge1xyXG4gICAgICBsZXQgcmV0VXJsID0gd2luZG93LlVSTC5jcmVhdGVPYmplY3RVUkwocmVzcG9uc2UuYm9keSk7XHJcbiAgICAgIGxldCBmbiA9IHJlc3BvbnNlLmhlYWRlcnMuZ2V0KCdjb250ZW50LWRpc3Bvc2l0aW9uJyk/LnNwbGl0KCc7JylbMV0/LnNwbGl0KCdmaWxlbmFtZScpWzFdPy5zcGxpdCgnPScpWzFdPy50cmltKCkucmVwbGFjZSgvXFxcIi9nLCAnJyk7XHJcblxyXG4gICAgICBnZXRGaWxlQ2FsbGJhY2socmV0VXJsLCBmaWxlbmFtZSB8fCBmbik7XHJcbiAgICAgIGlmIChhZnRlckdldEZpbGUpIGFmdGVyR2V0RmlsZSgpO1xyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBEb3dubG9hZCBuYXRpdm8gZGkgdW4gZmlsZS4gSW50ZXJuYW1lbnRlIHV0aWxpenphIGlsIHBhdHRlcm4gKip3aW5kb3cubG9jYXRpb24uaHJlZiA9IFwiLi4uXCIqKlxyXG4gICAqIFxyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgVVJMIHN1IGN1aSBlZmZldHR1YXJlIGxhIGNoaWFtYXRhXHJcbiAgICogQHBhcmFtIHtIdHRwUGFyYW1zfSBwYXJhbXMgUGFyYW1ldHJpIGRlbGxhIGNoaWFtYXRhXHJcbiAgICovXHJcbiAgcHVibGljIGdldEZpbGVOYXRpdmUodXJsOiBzdHJpbmcsIHBhcmFtczogSHR0cFBhcmFtcyA9IG51bGwpOiB2b2lkIHtcclxuXHJcbiAgICAvLyBFbmNvZG8gdHV0dGkgaSBwYXJhbWV0cmkgcGVyIGV2aXRhcmUgY2FzaSBwYXJ0aWNvbGFyaVxyXG4gICAgLy8gdmFyIGVuY29kZWRQYXJhbXMgPSBuZXcgSHR0cFBhcmFtcygpO1xyXG4gICAgLy8gbGV0IHBhcktleXMgPSBwYXJhbXMua2V5cygpO1xyXG4gICAgLy8gZm9yIChsZXQgaSA9IDA7IGkgPCBwYXJLZXlzLmxlbmd0aDsgaSsrKVxyXG4gICAgLy8gICBlbmNvZGVkUGFyYW1zID0gZW5jb2RlZFBhcmFtcy5zZXQocGFyS2V5c1tpXSwgZW5jb2RlVVJJQ29tcG9uZW50KHBhcmFtcy5nZXQocGFyS2V5c1tpXSkpKTtcclxuXHJcbiAgICBsZXQgZmluYWxVcmwgPSB1cmwgKyAocGFyYW1zID8gXCI/XCIgKyBwYXJhbXMudG9TdHJpbmcoKS5yZXBsYWNlKC9cXCsvZywgJyUyYicpIDogXCJcIik7XHJcbiAgICB3aW5kb3cubG9jYXRpb24uaHJlZiA9IGZpbmFsVXJsO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogRXNlY3V6aW9uZSBkaSB1bmEgR0VUIGRpIHVuIGZpbGUgY2hlIGVtZXR0ZSBpIHZhcmkgZXZlbnRpIGRpIHByb2dyZXNzbyBkaSBkb3dubG9hZC5cclxuICAgKiBVdGlsaXp6YXJsYSBwZXIgb3ZlcnJpZGFyZSBsYSBkaWFsb2cgbmF0aXZhIGRpIHByb2dyZXNzIGRlbCBicm93c2VyIGUgc29zdGl0dWlybGEgY29uIHF1YWxjb3NhIHRpcG8gcXVlbGxvIGNoZSBmYSBNRUdBLlxyXG4gICAqIFxyXG4gICAqIEluIGNhc28gc2kgdm9nbGlhIG90dGVuZXJlIGlsIHJpc3VsdGF0byBuYXRpdm8gZGVsIGJyb3dzZXIgZGVsIGRvd25sb2FkIHV0aWxpenphcmUgKipnZXRGaWxlTmF0aXZlKHVybCwgcGFycykqKlxyXG4gICAqIFxyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgVVJMIHN1IGN1aSBlZmZldHR1YXJlIGxhIGNoaWFtYXRhXHJcbiAgICogQHBhcmFtIHtIdHRwUGFyYW1zfSBwYXJhbXMgUGFyYW1ldHJpIGRlbGxhIGNoaWFtYXRhXHJcbiAgICogQHBhcmFtIHtGdW5jdGlvbn0gZ2V0RmlsZUNhbGxiYWNrIENhbGxiYWNrIGEgZHVlIHBhcmFtZXRyaSAodXJsOiBzdHJpbmcsIGZpbGVuYW1lOiBzdHJpbmcpIHBlciBnZXN0aXJlIGlsIHJpc3VsdGF0byBkZWwgZmlsZSByaWNoaWVzdG8uICoqVXRpbGl6emFyZSBVdGlsaXR5U2VydmljZS5maWxlRG93bmxvYWQqKiBkaSBAZXNmYWVuemEvZXh0ZW5zaW9uc1xyXG4gICAqIFxyXG4gICAqIEByZXR1cm5zIHtPYnNlcnZhYmxlPERvd25sb2FkPn0gT2JzZXJ2YWJsZSBkZWkgdmFyaSBzdGVwIGRpIHByb2dyZXNzbyBkZWwgZG93bmxvYWRcclxuICAgKi9cclxuICBwdWJsaWMgZ2V0RmlsZVdpdGhQcm9ncmVzcyh1cmw6IHN0cmluZywgcGFyYW1zOiBIdHRwUGFyYW1zID0gbnVsbCwgZ2V0RmlsZUNhbGxiYWNrOiAodXJsOiBzdHJpbmcsIGZpbGVuYW1lOiBzdHJpbmcpID0+IGFueSk6IE9ic2VydmFibGU8RG93bmxvYWQ+IHtcclxuICAgIHJldHVybiBmb3JrSm9pbihcclxuICAgICAge1xyXG4gICAgICAgIG15R3VpZDogZnJvbShbdGhpcy5kZWZhdWx0U3RhcnRDYWxsKHVybCldKSxcclxuICAgICAgICBsb2NhbGU6IHRoaXMuYmMuTG9jYWxlLnBpcGUoZmlyc3QoKSlcclxuICAgICAgfSkucGlwZShcclxuICAgICAgICBjb25jYXRNYXAoKHJldDogeyBteUd1aWQ6IHN0cmluZywgbG9jYWxlOiBzdHJpbmcgfSkgPT4ge1xyXG5cclxuICAgICAgICAgIHJldHVybiB0aGlzLmh0dHAuZ2V0KHVybCwgeyByZXNwb25zZVR5cGU6ICdibG9iJywgaGVhZGVyczogdGhpcy5nZXRIZWFkZXJzKHJldC5sb2NhbGUpLCBwYXJhbXM6IHBhcmFtcywgb2JzZXJ2ZTogJ2V2ZW50cycsIHJlcG9ydFByb2dyZXNzOiB0cnVlIH0pXHJcbiAgICAgICAgICAgIC5waXBlKFxyXG4gICAgICAgICAgICAgIHNjYW4oKHByZXZpb3VzOiBEb3dubG9hZCwgZXZlbnQ6IEh0dHBFdmVudDxCbG9iPik6IERvd25sb2FkID0+IHtcclxuXHJcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5pc0h0dHBQcm9ncmVzc0V2ZW50KGV2ZW50KSkge1xyXG4gICAgICAgICAgICAgICAgICBsZXQgcHJvZ3Jlc3MgPSBldmVudC50b3RhbCA/IChldmVudC5sb2FkZWQgPiBldmVudC50b3RhbCA/IDEwMCA6IE1hdGgucm91bmQoKDEwMCAqIGV2ZW50LmxvYWRlZCkgLyBldmVudC50b3RhbCkpIDogcHJldmlvdXMucHJvZ3Jlc3M7XHJcbiAgICAgICAgICAgICAgICAgIHJldHVybiB7IHByb2dyZXNzOiBwcm9ncmVzcywgc3RhdGU6ICdJTl9QUk9HUkVTUycsIGNvbnRlbnQ6IG51bGwgfVxyXG4gICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgIGlmICh0aGlzLmlzSHR0cFJlc3BvbnNlKGV2ZW50KSkge1xyXG4gICAgICAgICAgICAgICAgICBpZiAoZXZlbnQuYm9keSkge1xyXG4gICAgICAgICAgICAgICAgICAgIGxldCBjZGlzcCA9IGV2ZW50LmhlYWRlcnMuZ2V0KCdjb250ZW50LWRpc3Bvc2l0aW9uJyk7XHJcbiAgICAgICAgICAgICAgICAgICAgbGV0IGNkaXNwRmlsZW5hbWUgPSBjZGlzcC5zcGxpdCgnOycpWzFdLnNwbGl0KCdmaWxlbmFtZScpWzFdLnNwbGl0KCc9JylbMV0udHJpbSgpLnJlcGxhY2UoL1xcXCIvZywgJycpO1xyXG4gICAgICAgICAgICAgICAgICAgIGxldCByZXRVcmwgPSB3aW5kb3cuVVJMLmNyZWF0ZU9iamVjdFVSTChldmVudC5ib2R5KTtcclxuICAgICAgICAgICAgICAgICAgICBnZXRGaWxlQ2FsbGJhY2socmV0VXJsLCBjZGlzcEZpbGVuYW1lKTtcclxuICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICByZXR1cm4geyBwcm9ncmVzczogMTAwLCBzdGF0ZTogJ0RPTkUnLCBjb250ZW50OiBldmVudC5ib2R5IH1cclxuICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICByZXR1cm4gcHJldmlvdXM7XHJcbiAgICAgICAgICAgICAgfSwgeyBzdGF0ZTogJ1BFTkRJTkcnLCBwcm9ncmVzczogMCwgY29udGVudDogbnVsbCB9KSxcclxuICAgICAgICAgICAgICBjYXRjaEVycm9yKChlcnIsIF8pOiBPYnNlcnZhYmxlPERvd25sb2FkPiA9PiB7IHJldHVybiB0aGlzLnJlZ2lzdGVyRXJyb3JBbmRSZXR1cm5FbXB0eU9ic2VydmFibGUoZXJyLCByZXQubXlHdWlkKSB9KSxcclxuICAgICAgICAgICAgICBmaW5hbGl6ZSgoKSA9PiB7IHRoaXMudHJ5RmluYWxpemVCeUd1aWQocmV0Lm15R3VpZCk7IH0pXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgfSlcclxuICAgICAgKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFJpY29ub3NjZSBzZSBsJ2V2ZW50byBIVFRQIMOoIGRpIHRpcG8gKipIdHRwUmVzcG9uc2UqKiBlLCBzZSBzw6wsIGxvIGNhc3RhIGFsIHRpcG8gY29ycmV0dG8gcGVyIGVzc2VyZSB1dGlsaXp6YXRvIGNvcnJldHRhbWVudGUgbmVsIGJsb2NjbyBkaSBjb2RpY2Ugc3VjY2Vzc2l2b1xyXG4gICAqL1xyXG4gIHByaXZhdGUgaXNIdHRwUmVzcG9uc2U8VD4oZXZlbnQ6IEh0dHBFdmVudDxUPik6IGV2ZW50IGlzIEh0dHBSZXNwb25zZTxUPiB7XHJcbiAgICByZXR1cm4gZXZlbnQudHlwZSA9PT0gSHR0cEV2ZW50VHlwZS5SZXNwb25zZVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogUmljb25vc2NlIHNlIGwnZXZlbnRvIEhUVFAgw6ggZGkgdGlwbyAqKkh0dHBQcm9ncmVzc0V2ZW50KiogZSwgc2Ugc8OsLCBsbyBjYXN0YSBhbCB0aXBvIGNvcnJldHRvIHBlciBlc3NlcmUgdXRpbGl6emF0byBjb3JyZXR0YW1lbnRlIG5lbCBibG9jY28gZGkgY29kaWNlIHN1Y2Nlc3Npdm9cclxuICAgKi9cclxuICBwcml2YXRlIGlzSHR0cFByb2dyZXNzRXZlbnQoZXZlbnQ6IEh0dHBFdmVudDx1bmtub3duPik6IGV2ZW50IGlzIEh0dHBQcm9ncmVzc0V2ZW50IHtcclxuICAgIHJldHVybiBldmVudC50eXBlID09PSBIdHRwRXZlbnRUeXBlLkRvd25sb2FkUHJvZ3Jlc3MgfHwgZXZlbnQudHlwZSA9PT0gSHR0cEV2ZW50VHlwZS5VcGxvYWRQcm9ncmVzc1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogR2VzdGlvbmUgZGVsbCdpbml6aW8gZGkgdW5hIGNoaWFtYXRhIGFkIHVuIGNlcnRvIFVSTCwgdmllbmUgZ2VuZXJhdG8gdW4gR1VJRCBkYSBhc3NlZ25hcmNpLCBjb250cm9sbGF0YSBsYSBzY2FkZW56YSBkZWxsYSBjYWNoZSwgXHJcbiAgICogZSBldmVudHVhbG1lbnRlIGxvZ2dhdG8gaWwgZmF0dG8gY2hlIHN0YSBwZXIgZXNzZXJlIGVmZmV0dHVhdGEgdW5hIGNoaWFtYXRhIEhUVFBcclxuICAgKiBcclxuICAgKiBAcGFyYW0ge3N0cmluZ30gdXJsIFVybCBhIGN1aSBlZmZldHR1YXJlIGxhIGNoaWFtYXRhXHJcbiAgICogQHJldHVybnMge3N0cmluZ30gR1VJRCBhc3NlZ25hdG8gYWxsYSBjaGlhbWF0YVxyXG4gICAqL1xyXG4gIHByaXZhdGUgZGVmYXVsdFN0YXJ0Q2FsbCh1cmw6IHN0cmluZyk6IHN0cmluZyB7XHJcbiAgICBsZXQgbXlHdWlkID0gdGhpcy5nZXRHVUlEKCk7XHJcbiAgICB0aGlzLmNoZWNrQ2FjaGVJbnZhbGlkYXRpb24odXJsKTtcclxuICAgIHRoaXMuY2FsbFN0YXR1c1tteUd1aWRdID0geyB1cmw6IHVybCwgc3VjY2VzczogdHJ1ZSB9O1xyXG4gICAgdGhpcy5sb2codGhpcy5sb2MoXCJTdGFydGluZyBjYWxsXCIpICsgXCIgXCIgKyBteUd1aWQgKyBcIiBcIiArIHRoaXMubG9jKFwiYXQgVVJMXCIpICsgXCI6IFwiICsgdXJsKTtcclxuICAgIHJldHVybiBteUd1aWQ7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBEYXRvIHVuIHVybCB2ZW5nb25vIGNvbnRyb2xsYXRlIGxlIGluZm9ybWF6aW9uaSBzdSB0dXR0aSBnbGkgdXJsIGRhIGludmFsaWRhcmUgY29sbGVnYXRpIGFsbCd1cmwgY2hpYW1hdG8gZSwgc2UgcHJlc2VudGkgaW4gY2FjaGUsIGludmFsaWRhdGlcclxuICAgKiBcclxuICAgKiBAcGFyYW0ge3N0cmluZ30gdXJsIFVSTCBwZXIgY3VpIGNvbnRyb2xsYXJlIHNlIGNpIHNvbm8gY2hpYW1hdGUgaW4gY2FjaGUgZGEgaW52YWxpZGFyZVxyXG4gICAqL1xyXG4gIHByaXZhdGUgY2hlY2tDYWNoZUludmFsaWRhdGlvbih1cmw6IHN0cmluZykge1xyXG4gICAgaWYoIXRoaXMuQ2FjaGVJbml0aWFsaXplZClcclxuICAgICAgcmV0dXJuO1xyXG5cclxuICAgIGxldCBjYWNoZSA9IHRoaXMubG9jYWxTdG9yYWdlLmdldExvY2FsSXRlbTxhbnk+KHRoaXMubG9jYWxTdG9yYWdlSHR0cENhY2hlS2V5KTtcclxuICAgIGxldCB0bXAgPSAvI2NhY2hlKDo/LShcXGQrKSkvZ2kuZXhlYyh1cmwpO1xyXG4gICAgbGV0IGNhY2hlVGltZSA9IHRtcCA/IHRtcFsyXSA6IG51bGw7XHJcbiAgICBsZXQgbm9ybWFsaXplZFVybF90bXAgPSB1cmwucmVwbGFjZShcIiNjYWNoZVwiICsgKGNhY2hlVGltZSA/IFwiLVwiICsgY2FjaGVUaW1lIDogXCJcIiksIFwiXCIpO1xyXG4gICAgbGV0IG5vcm1hbGl6ZWRVcmwgPSBub3JtYWxpemVkVXJsX3RtcC5zdWJzdHJpbmcobm9ybWFsaXplZFVybF90bXAuaW5kZXhPZignL2FwaScpKVxyXG5cclxuICAgIGlmICghY2FjaGUgfHwgIXRoaXMuSFRUUF9JTlZBTElEQVRJT04gfHwgIXRoaXMuSFRUUF9JTlZBTElEQVRJT05bbm9ybWFsaXplZFVybF0pXHJcbiAgICAgIHJldHVybjtcclxuXHJcbiAgICBsZXQgYXBpc1RvSW52YWxpZGF0ZTogc3RyaW5nW10gPSB0aGlzLkhUVFBfSU5WQUxJREFUSU9OW25vcm1hbGl6ZWRVcmxdO1xyXG4gICAgaWYgKCFhcGlzVG9JbnZhbGlkYXRlIHx8IGFwaXNUb0ludmFsaWRhdGUubGVuZ3RoID09IDApXHJcbiAgICAgIHJldHVybjtcclxuXHJcbiAgICBsZXQga2V5c1RvUmVtb3ZlOiBzdHJpbmdbXSA9IFtdO1xyXG4gICAgYXBpc1RvSW52YWxpZGF0ZS5mb3JFYWNoKGFwaSA9PiB7XHJcbiAgICAgIGxldCBjYWNoZUtleSA9IHRoaXMubWFrZUNhY2hlS2V5KGFwaSwgbnVsbCk7XHJcbiAgICAgIGZvciAobGV0IGl0ZW0gaW4gY2FjaGUpXHJcbiAgICAgICAgaWYgKGl0ZW0uaW5kZXhPZihjYWNoZUtleSkgIT0gLTEpXHJcbiAgICAgICAgICBrZXlzVG9SZW1vdmUucHVzaChpdGVtKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwga2V5c1RvUmVtb3ZlLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgIGxldCBrID0ga2V5c1RvUmVtb3ZlW2ldO1xyXG4gICAgICB0aGlzLmxvZyh0aGlzLmxvYyhcIkludmxhbGlkYXRpbmcgY2FjaGUgZWxlbWVudFwiKSArIFwiIFwiICsgayk7XHJcbiAgICAgIGRlbGV0ZSBjYWNoZVtrXTtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLmxvY2FsU3RvcmFnZS5zZXRJdGVtKHRoaXMubG9jYWxTdG9yYWdlSHR0cENhY2hlS2V5LCBjYWNoZSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBGaW5hbGl6emF6aW9uZSBkaSB1bmEgY2hpYW1hdGFcclxuICAgKiBcclxuICAgKiBAcGFyYW0ge3N0cmluZ30gZ3VpZCBHVUlEIGNvbGxlZ2F0byBhbGxhIGNoaWFtYXRhIGFwcGVuYSB0ZXJtaW5hdGFcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHBlcnNpc3RDYWNoZUlmSWRsZSBFZmZldHR1YSBpbCBwZXJzaXN0IGRlbGxhIGNhY2hlIEhUVFAgc29sbyBzZSBub24gY2kgc29ubyBhbHRyZSBjaGlhbWF0ZSBpbiBjb3JzbywgcGVyIGV2aXRhcmVcclxuICAgKiBjaGUgbWkgY2FtYmkgc290dG8gbCdvZ2dldHRvIGRpIGNhY2hlIG1lbnRyZSBzdG8gc2FsdmFuZG8gbGUgaW5mb3JtYXppb25pXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBhc3luYyB0cnlGaW5hbGl6ZUJ5R3VpZChndWlkOiBzdHJpbmcsIGNhY2hlSW5mb3M/OiBDYWNoZUluZm9zKSB7XHJcbiAgICB0aGlzLmxvZyh0aGlzLmxvYyhcIkZpbmFsaXppbmcgY2FsbFwiKSArIFwiIFwiICsgZ3VpZCArIFwiIFwiICsgdGhpcy5sb2MoXCJ3aXRoIHN0YXR1c1wiKSArIFwiOiBcIiArICghdGhpcy5jYWxsU3RhdHVzW2d1aWRdID8gJ1Vua25vd24nIDogdGhpcy5jYWxsU3RhdHVzW2d1aWRdLnN1Y2Nlc3MgPyB0aGlzLmxvYygnU3VjY2VzcycpIDogdGhpcy5sb2MoJ0ZhaWx1cmUnKSkpO1xyXG5cclxuICAgIC8vIFRPRE86IFBlcmRlcmUgMy00IG9yZSBwZXIgY2FwaXJlIHBlcmNow6kgb2duaSB0YW50byBhcnJpdmEgbnVsbCBpbiBjYXNpIHBlc2FudGkgZGkgT2JzZXJ2YWJsZSBzcGFtbWF0aSBhIHJhbmRvbVxyXG4gICAgaWYgKHRoaXMuY2FsbFN0YXR1c1tndWlkXSkge1xyXG4gICAgICAvLyBBbGxhIHByaW1hIGNoaWFtYXRhIGJ1b25hLCBzaWduaWZpY2EgY2hlIGFsbWVubyBpbCBsb2dpbiBjZSBsJ2hvLiBQb3NzbyBtZXR0ZXJtaSBpbiBtb2RhbGl0w6AgcmVkaXJlY3RJblByb2dyZXNzIGZhbHNlXHJcbiAgICAgIC8vIGUgcmlpbml6aWFyZSBhIHZhbHV0YXJlIGVycm9yaSBkaSBqYXZhc2hpdFxyXG4gICAgICBpZiAodGhpcy5jYWxsU3RhdHVzW2d1aWRdLnN1Y2Nlc3MgJiYgdGhpcy5FeHRlbnNpb25zSW1wbC5yZWFkUmVkaXJlY3Rpb25TdGF0dXMoKSlcclxuICAgICAgICB0aGlzLkV4dGVuc2lvbnNJbXBsLndyaXRlUmVkaXJlY3Rpb25TdGF0dXMoZmFsc2UpO1xyXG5cclxuICAgICAgLy8gQWdnaXVuZ28gbGEgY2hpYW1hdGEgYWxsYSBsaXN0YSBkZWxsZSB1bHRpbWUgMyBjb21wbGV0YXRlXHJcbiAgICAgIHRoaXMuTGFzdFRocmVlQ29tcGxldGVkQ2FsbHMudW5zaGlmdCh0aGlzLmNhbGxTdGF0dXNbZ3VpZF0udXJsKVxyXG4gICAgICBpZiAodGhpcy5MYXN0VGhyZWVDb21wbGV0ZWRDYWxscy5sZW5ndGggPiAzKVxyXG4gICAgICAgIHRoaXMuTGFzdFRocmVlQ29tcGxldGVkQ2FsbHMucG9wKCk7XHJcblxyXG4gICAgICAvLyBJbiBvZ25pIGNhc28gcXVlc3RhIHBvc3NvIHJpbXVvdmVybGFcclxuICAgICAgZGVsZXRlIHRoaXMuY2FsbFN0YXR1c1tndWlkXTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTZSBub24gaG8gbmVzc3VuJ2FsdHJhIGNoaWFtYXRhIGluIGNvcnNvIGNvbnNpZGVybyBsYSBzaXR1YXppb25lIHN0YWJpbGl6emF0YXNpXHJcbiAgICBpZiAoT2JqZWN0LmtleXModGhpcy5jYWxsU3RhdHVzKS5sZW5ndGggPT0gMClcclxuICAgICAgdGhpcy5TdGFiaWxpemVkLm5leHQodHJ1ZSk7XHJcblxyXG4gICAgLy8gU2UgdmVuZ28gZGEgdW5hIGNoaWFtYXRhIGNoZSBoYSBhZ2dpb3JuYXRvIGxhIGNhY2hlIGEgdGltZXIgbyBnbG9iYWxlIG1hcmNvIGlsIGZhdHRvIGNoZSBxdWVsbGEgY2FjaGUgZGV2J2Vzc2VyZSBhZ2dpb3JuYXRhXHJcbiAgICBpZiAoY2FjaGVJbmZvcyAmJiBjYWNoZUluZm9zLmNhY2hlKSB7XHJcbiAgICAgIHRoaXMuUGVyc2lzdFRpbWVkQ2FjaGVBU0FQID0gdGhpcy5QZXJzaXN0VGltZWRDYWNoZUFTQVAgfHwgISFjYWNoZUluZm9zLmNhY2hlVGltZTtcclxuICAgICAgdGhpcy5QZXJzaXN0VW50aW1lZENhY2hlQVNBUCA9IHRoaXMuUGVyc2lzdFRpbWVkQ2FjaGVBU0FQIHx8ICFjYWNoZUluZm9zLmNhY2hlVGltZTtcclxuICAgICAgdGhpcy5sb2codGhpcy5sb2MoXCJNYXJraW5nIGNhY2hlIHRvIGJlIHBlcnNpc3RlZCBhcyBzb29uIGFzIHBvc3NpYmxlXCIpKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTZSB1bmEgZGVsbGUgZHVlIGNhY2hlIGRldm9ubyBlc3NlcmUgYWdnaW9ybmF0ZSBlIG5vbiBobyBuZXNzdW5hIGNoaWFtYXRhIGluIGNvcnNvIGVmZmV0dHVvIGwnYWdnaW9ybmFtZW50byBpbiBiYXNlIGEgcXVhbGUgZGVsbGUgZHVlIHZhIGFnZ2lvcm5hdGFcclxuICAgIC8vIEFsbGEgZmluZSBkaSB0dXR0byBtYXJjbyBjb21lIGZhdHRvXHJcbiAgICBpZiAoKHRoaXMuUGVyc2lzdFRpbWVkQ2FjaGVBU0FQIHx8IHRoaXMuUGVyc2lzdFVudGltZWRDYWNoZUFTQVApICYmIE9iamVjdC5rZXlzKHRoaXMuY2FsbFN0YXR1cykubGVuZ3RoID09IDAgJiYgdGhpcy5DYWNoZUluaXRpYWxpemVkKSB7XHJcblxyXG4gICAgICB2YXIgdG9DYWxsID0gW107XHJcbiAgICAgIGxldCB0bXBLZXkgPSBcIlwiO1xyXG4gICAgICBpZiAodGhpcy5QZXJzaXN0VGltZWRDYWNoZUFTQVApIHtcclxuICAgICAgICB0bXBLZXkgPSB0aGlzLmxvY2FsU3RvcmFnZUh0dHBUaW1lZENhY2hlS2V5O1xyXG4gICAgICAgIHRvQ2FsbC5wdXNoKHRoaXMubG9jYWxTdG9yYWdlLnNldEl0ZW0odG1wS2V5LCB0aGlzLmxvY2FsU3RvcmFnZS5nZXRMb2NhbEl0ZW0odG1wS2V5KSkpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAodGhpcy5QZXJzaXN0VW50aW1lZENhY2hlQVNBUCkge1xyXG4gICAgICAgIHRtcEtleSA9IHRoaXMubG9jYWxTdG9yYWdlSHR0cENhY2hlS2V5O1xyXG4gICAgICAgIHRvQ2FsbC5wdXNoKHRoaXMubG9jYWxTdG9yYWdlLnNldEl0ZW0odG1wS2V5LCB0aGlzLmxvY2FsU3RvcmFnZS5nZXRMb2NhbEl0ZW0odG1wS2V5KSkpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICB0aGlzLmxvZyh0aGlzLmxvYyhcIk5vIG1vcmUgSFRUUCBjYWxscyB0byBiZSBleGVjdXRlZCwgZW50ZXJpbmcgaWRsZSBzdGF0ZSBhbmQgcGVyc2lzdGluZyBtb2RpZmllZCBjYWNoZXNcIikgKyBcIi4uLlwiKTtcclxuXHJcbiAgICAgIHZhciByZXQgPSBhd2FpdCBmb3JrSm9pbih0b0NhbGwpLnRvUHJvbWlzZSgpO1xyXG4gICAgICBpZiAocmV0KVxyXG4gICAgICAgIHRoaXMubG9nKHRoaXMubG9jKFwiQ2FjaGVzIHN1Y2Nlc2Z1bGx5IHBlcnNpc3RlZFwiKSk7XHJcbiAgICAgIGVsc2VcclxuICAgICAgICB0aGlzLmxvZyh0aGlzLmxvYyhcIkVycm9ycyBwZXJzaXN0aW5nIG1vZGlmaWVkIGNhY2hlc1wiKSk7XHJcbiAgICAgIHRoaXMuUGVyc2lzdFRpbWVkQ2FjaGVBU0FQID0gZmFsc2U7XHJcbiAgICAgIHRoaXMuUGVyc2lzdFVudGltZWRDYWNoZUFTQVAgPSBmYWxzZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEhlbHBlciBjaGUgZGF0byB1biB1bmljbyBGaWxlIG8gdW5hIGxpc3RhIGRpIEZpbGUgY3JlYSB1biBvZ2dldHRvIEZvcm1EYXRhIGNoZSBwdcOyIGVzc2VyZSBpbnZpYXRvIGNvbW9kYW1lbnRlIFxyXG4gICAqIGFkIHVuIGJhY2tlbmQgQVNQLk5FVCBkYSBjdWkgc2kgcG90csOgIGFjY2VkZXJlIGEgUmVxdWVzdC5Gb3JtLkZpbGVzXHJcbiAgICogXHJcbiAgICogQHBhcmFtIHtGaWxlIHwgRmlsZVtdfSBmaWxlQXJyYXlPckZpbGUgU2luZ29sbyBGaWxlIG8gbGlzdGEgZGkgRmlsZS4gTi5COiBuZWxsYSBmaXJtYSBkZWxsYSBmdW56aW9uZSB2aWVuZSBjb25zaWRlcmF0byAqKmFueSoqIHBlciBmYXJlIHRlc3Qgc3VsbGUgcHJvcHJpZXTDoCBcclxuICAgKiBpbnZlY2UgY2hlIGZhcmUgdGVzdCBjb24gbCcqKmlzdGFuY2VvZioqXHJcbiAgICogXHJcbiAgICogQHJldHVybnMge0Zvcm1EYXRhfSBGb3JtRGF0YSBjb250ZW5lbnRlIHR1dHRpIGkgZmlsZSBwYXNzYXRpXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBnZXRGaWxlc0Zvcm1EYXRhKGZpbGVBcnJheU9yRmlsZTogYW55KTogRm9ybURhdGEge1xyXG4gICAgdmFyIGZvcm1EYXRhOiBGb3JtRGF0YSA9IG5ldyBGb3JtRGF0YSgpO1xyXG5cclxuICAgIGlmIChmaWxlQXJyYXlPckZpbGUpIHtcclxuICAgICAgaWYgKGZpbGVBcnJheU9yRmlsZS5sZW5ndGgpXHJcbiAgICAgICAgZmlsZUFycmF5T3JGaWxlLmZvckVhY2godCA9PiB7IGZvcm1EYXRhLmFwcGVuZChcImZpbGVcIiwgdCwgdC5uYW1lKTsgfSk7XHJcbiAgICAgIGVsc2UgaWYgKGZpbGVBcnJheU9yRmlsZS5uYW1lKVxyXG4gICAgICAgIGZvcm1EYXRhLmFwcGVuZChcImZpbGVzXCIsIGZpbGVBcnJheU9yRmlsZSwgZmlsZUFycmF5T3JGaWxlLm5hbWUpO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiBmb3JtRGF0YTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEhlbHBlciBjaGUgaW4gYmFzZSBhaSBwYXJhbWV0cmkgZGlzcG9uaWJpbGkgZ2VuZXJhIGdsaSBIZWFkZXIgSFRUUCBwZXIgbGEgY2hpYW1hdGEgZGEgZWZmZXR0dWFyZVxyXG4gICAqIFxyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjb250ZW50VHlwZSBJbmRpY2Egc2UgYWdnaXVuZ2VyZSBhZ2xpIGhlYWRlciBcIkNvbnRlbnQtVHlwZVwiLCB2YWxvcml6emF0byBhbCB2YWxvcmUgZGVsIHBhcmFtZXRyb1xyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhY2NlcHQgSW5kaWNhIHNlIGFnZ2l1bmdlcmUgYWdsaSBoZWFkZXIgXCJBY2NlcHRcIiwgdmFsb3JpenphdG8gYWwgdmFsb3JlIGRlbCBwYXJhbWV0cm9cclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IGluY2x1ZGVBdXRoIEluZGljYSBzZSBhZ2dpdW5nZXJlIGFnbGkgaGVhZGVyIFwiQXV0aG9yaXphdGlvblwiLCB2YWxvcml6emF0byBjb2wgdG9rZW4gcmVjdXBlcmF0byBkYWxsJ2hvb2sgKipyZXRyaWV2ZUFjY2Vzc1Rva2VuKiogZGVsbGEgY2xhc3NlIGRpIGVzdGVuc2lvbmVcclxuICAgKiBAcGFyYW0ge3N0cmluZ30gdHJhbnNhY3Rpb25JZCBJbmRpY2Egc2UgYWdnaXVuZ2VyZSBhZ2xpIGhlYWRlciBcIlgtVFgtSURcIiwgdmFsb3JpenphdG8gYWwgdmFsb3JlIGRlbCBwYXJhbWV0cm9cclxuICAgKiBcclxuICAgKiBAcmV0dXJucyB7SHR0cEhlYWRlcnN9IEhlYWRlciBnZW5lcmF0aSBpbiBiYXNlIGFpIHBhcmFtZXRyaVxyXG4gICAqL1xyXG4gIHByaXZhdGUgZ2V0SGVhZGVycyhsb2NhbGUgPSAnaXQtSVQnLCB0cmFuc2FjdGlvbklkID0gXCJcIiwgaW5jbHVkZUF1dGg6IGJvb2xlYW4gPSB0cnVlLCBjb250ZW50VHlwZTogc3RyaW5nID0gXCJhcHBsaWNhdGlvbi9qc29uXCIsIGFjY2VwdDogc3RyaW5nID0gXCJhcHBsaWNhdGlvbi9qc29uXCIpOiBIdHRwSGVhZGVycyB7XHJcbiAgICB2YXIgaGVhZGVycyA9IG5ldyBIdHRwSGVhZGVycygpO1xyXG4gICAgdmFyIGF1dGh0b2tlbiA9IHRoaXMuRXh0ZW5zaW9uc0ltcGwucmV0cmlldmVBY2Nlc3NUb2tlbigpO1xyXG5cclxuICAgIGhlYWRlcnMgPSBoZWFkZXJzLmFwcGVuZChcIm5nc3ctYnlwYXNzXCIsIFwiXCIpO1xyXG5cclxuICAgIGlmIChjb250ZW50VHlwZSlcclxuICAgICAgaGVhZGVycyA9IGhlYWRlcnMuYXBwZW5kKFwiQ29udGVudC1UeXBlXCIsIGNvbnRlbnRUeXBlKTtcclxuXHJcbiAgICBpZiAodHJhbnNhY3Rpb25JZClcclxuICAgICAgaGVhZGVycyA9IGhlYWRlcnMuYXBwZW5kKFwiWC1UWC1JRFwiLCB0cmFuc2FjdGlvbklkKTtcclxuXHJcbiAgICBpZiAoYXV0aHRva2VuICYmIGluY2x1ZGVBdXRoKVxyXG4gICAgICBoZWFkZXJzID0gaGVhZGVycy5hcHBlbmQoXCJBdXRob3JpemF0aW9uXCIsIFwiQmVhcmVyIFwiICsgYXV0aHRva2VuKTtcclxuXHJcbiAgICBpZiAoYWNjZXB0KVxyXG4gICAgICBoZWFkZXJzID0gaGVhZGVycy5hcHBlbmQoXCJBY2NlcHRcIiwgYWNjZXB0KTtcclxuXHJcbiAgICBoZWFkZXJzID0gaGVhZGVycy5hcHBlbmQoXCJBY2NlcHQtTGFuZ3VhZ2VcIiwgbG9jYWxlKTtcclxuICAgIHJldHVybiBoZWFkZXJzO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogR2VzdGlvbmUgZGkgZGVmYXVsdCBkZWdsaSBlcnJvcmlcclxuICAgKiBcclxuICAgKiBAcGFyYW0ge2FueX0gcmVzIFJpc3VsdGF0byBkZWxsYSBjaGlhbWF0YSBlZmZldHR1YXRhXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IGd1aWQgSWRlbnRpZmljYXRpdm8gR1VJRCBkZWxsYSBjaGlhbWF0YSBlZmZldHR1YXRhXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBhc3luYyBvbkVycm9yKHJlczogSHR0cEVycm9yUmVzcG9uc2UgfCBUeXBlRXJyb3IsIGd1aWQ6IHN0cmluZykge1xyXG4gICAgaWYgKHRoaXMuY2FsbFN0YXR1c1tndWlkXSlcclxuICAgICAgdGhpcy5jYWxsU3RhdHVzW2d1aWRdLnN1Y2Nlc3MgPSBmYWxzZTtcclxuXHJcbiAgICAvL01pIGFzc2ljdXJvIGNoZSB0dXR0aSBnbGkgZXJyb3JpIGR1cmFudGUgaWwgcmVkaXJlY3QgYWwgbG9naW4gdmVuZ2FubyBpZ25vcmF0aVxyXG4gICAgaWYgKHRoaXMuRXh0ZW5zaW9uc0ltcGwucmVhZFJlZGlyZWN0aW5nVG9Mb2dpbigpKSB7XHJcbiAgICAgIHRoaXMubG9nKHRoaXMubG9jKFwiUmVkaXJlY3RpbmcgdG8gTG9naW4sIGlnbm9yaW5nIEhUVFAgZXJyb3Igb24gY2FsbFwiKSArIFwiIFwiICsgZ3VpZCk7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICAvL01pIGFzc2ljdXJvIGNoZSB2ZW5nYSBnZXN0aXRvIHVuIHNvbG8gZXJyb3JlIHBlciB2b2x0YVxyXG4gICAgaWYgKHRoaXMuRXh0ZW5zaW9uc0ltcGwucmVhZEhhbmRsaW5nRXJyb3JTdGF0dXMoKSkge1xyXG4gICAgICB0aGlzLmxvZyh0aGlzLmxvYyhcIkFscmVhZHkgSGFuZGxpbmcgYW4gZXJyb3IsIGlnbm9yaW5nIEhUVFAgZXJyb3Igb24gY2FsbFwiKSArIFwiIFwiICsgZ3VpZCk7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuICAgIGVsc2VcclxuICAgICAgdGhpcy5FeHRlbnNpb25zSW1wbC53cml0ZUhhbmRsaW5nRXJyb3JTdGF0dXModHJ1ZSk7XHJcblxyXG4gICAgbGV0IGZpbmFsRXJyb3IgPSBcIlwiO1xyXG4gICAgbGV0IGZpbmFsU3RhdHVzID0gXCJcIjtcclxuICAgIGlmICh0aGlzLmlzVHlwZUVycm9yKHJlcykpIHtcclxuICAgICAgZmluYWxFcnJvciA9IHJlcy5tZXNzYWdlO1xyXG4gICAgICBmaW5hbFN0YXR1cyA9IFwiSFRUUCBTZXJ2aWNlIEludGVybmFsIEVycm9yXCI7XHJcbiAgICB9XHJcbiAgICBlbHNlIGlmICh0aGlzLmlzSHR0cEVycm9yUmVzcG9uc2UocmVzKSkge1xyXG5cclxuICAgICAgZmluYWxFcnJvciA9IGF3YWl0IHRoaXMuZ2V0SHR0cEVycm9yVGV4dChyZXMuZXJyb3IpO1xyXG4gICAgICBmaW5hbFN0YXR1cyA9IHJlcy5zdGF0dXMudG9TdHJpbmcoKTtcclxuXHJcbiAgICAgIHN3aXRjaCAocmVzLnN0YXR1cykge1xyXG4gICAgICAgIC8vIFVuYXV0aG9yaXplZFxyXG4gICAgICAgIGNhc2UgNDAxOlxyXG4gICAgICAgICAgaWYgKHRoaXMuRXh0ZW5zaW9uc0ltcGwucmVhZFJlZGlyZWN0aW9uU3RhdHVzKCkpIHtcclxuICAgICAgICAgICAgdGhpcy5sb2codGhpcy5sb2MoXCJFcnJvciA0MDEgb24gY2FsbFwiKSArIFwiIFwiICsgZ3VpZCArIFwiIFwiICsgdGhpcy5sb2MoXCJ3aXRoIHJlZGlyZWN0IGFscmVhZHkgaW4gcHJvZ3Jlc3MuIElnbm9yaW5nIHRoaXMgZXZlbnRcIikpO1xyXG4gICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICB0aGlzLmxvZyh0aGlzLmxvYyhcIkVycm9yIDQwMSBvbiBjYWxsXCIpICsgXCIgXCIgKyBndWlkICsgXCIgXCIgKyB0aGlzLmxvYyhcInJlZGlyZWN0aW5nIHRvIGxvZ2luLlwiKSk7XHJcbiAgICAgICAgICB0aGlzLkV4dGVuc2lvbnNJbXBsLndyaXRlUmVkaXJlY3Rpb25TdGF0dXModHJ1ZSk7XHJcbiAgICAgICAgICB0aGlzLkV4dGVuc2lvbnNJbXBsLndyaXRlUmVkaXJlY3RpbmdUb0xvZ2luKHRydWUpO1xyXG4gICAgICAgICAgdGhpcy5FeHRlbnNpb25zSW1wbC5yZWRpcmVjdFRvTG9naW4oKTtcclxuICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAvLyBIYW5kbGVkIGV4Y2VwdGlvblxyXG4gICAgICAgIGNhc2UgNDAwOlxyXG4gICAgICAgIC8vIE5vIFBlcm1pc3Npb25zXHJcbiAgICAgICAgY2FzZSA0MDM6XHJcbiAgICAgICAgICB0aGlzLkV4dGVuc2lvbnNJbXBsLmhhbmRsZUJsb2NraW5nRXhjZXB0aW9uKHJlcy5zdGF0dXMsIGZpbmFsRXJyb3IpO1xyXG4gICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgIC8vIE5vdCBmb3VuZFxyXG4gICAgICAgIGNhc2UgNDA0OlxyXG4gICAgICAgICAgdGhpcy5FeHRlbnNpb25zSW1wbC5oYW5kbGVCbG9ja2luZ0V4Y2VwdGlvbihyZXMuc3RhdHVzLCB0aGlzLmxvYyhcIlJlc291cmNlIG5vdCBmb3VuZFwiKSk7XHJcbiAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgLy8gTm90Q29uZmlndXJlZEV4Y2VwdGlvblxyXG4gICAgICAgIGNhc2UgNDQ0OlxyXG4gICAgICAgICAgaWYgKHRoaXMuRXh0ZW5zaW9uc0ltcGwucmVhZFJlZGlyZWN0aW9uU3RhdHVzKCkpXHJcbiAgICAgICAgICAgIHRoaXMubG9nKHRoaXMubG9jKFwiRXJyb3IgNDQ0IG9uIGNhbGxcIikgKyBcIiBcIiArIGd1aWQgKyBcIiBcIiArIHRoaXMubG9jKFwid2l0aCByZWRpcmVjdCBhbHJlYWR5IGluIHByb2dyZXNzLiBJZ25vcmluZyB0aGlzIGV2ZW50XCIpKTtcclxuICAgICAgICAgIGVsc2UgaWYgKCF0aGlzLkV4dGVuc2lvbnNJbXBsLmhhbmRsZU5vdENvbmZpZ3VyZWRFeGNlcHRpb24oKSlcclxuICAgICAgICAgICAgdGhpcy5FeHRlbnNpb25zSW1wbC5oYW5kbGVCbG9ja2luZ0V4Y2VwdGlvbihyZXMuc3RhdHVzLCBmaW5hbEVycm9yKTtcclxuICAgICAgICAgIHJldHVybjtcclxuICAgICAgICBjYXNlIDA6XHJcbiAgICAgICAgICBmaW5hbEVycm9yID0gYEdlbmVyaWMgY29ubmVjdGlvbiBlcnJvciB3aGlsZSBjYWxsaW5nICdbJHtndWlkfV0gLSAke3RoaXMuY2FsbFN0YXR1c1tndWlkXS51cmx9JyBhdCAke2RheWpzKCkuZm9ybWF0KCl9LiBSZXNwb25zZTogJHtKU09OLnN0cmluZ2lmeShyZXMpfWA7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICB0aGlzLkV4dGVuc2lvbnNJbXBsLmhhbmRsZUV4Y2VwdGlvbihmaW5hbFN0YXR1cywgZmluYWxFcnJvcik7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBEYXRvIHVuIGVycm9yZSByZXN0aXR1aXNjZSB1bmEgcHJvbWlzZSBjb24gbGEgc3RyaW5nYSBmaW5hbGUgZGVsbCdlcnJvcmUgaW4gbW9kbyBkYSBwb3RlciBmYXJlIHVuIGF3YWl0XHJcbiAgICogXHJcbiAgICogQHBhcmFtIHthbnl9IGVyciBFcnJvcmUgZGEgY29udHJvbGxhcmVcclxuICAgKiBcclxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBQcm9taXNlIGNoZSByaXNvbHZlIGNvbiBsYSBzdHJpbmdhIGZpbmFsZSBkZWxsJ2Vycm9yZVxyXG4gICAqL1xyXG4gIHByaXZhdGUgZ2V0SHR0cEVycm9yVGV4dChlcnI6IGFueSk6IFByb21pc2U8c3RyaW5nPiB7XHJcbiAgICAvLyBTZSBobyB1biBCbG9iIHB1w7IgZXNzZXJlIG8gdW4gQ2FsbFJlc3VsdCBvIHN1cHBvbmdvIHVuYSBzZW1wbGljZSBzdHJpbmdhLFxyXG4gICAgLy8gYWx0cmltZW50aSBwb3RyZWJiZSBlc3NlcmUgZGlyZXR0YW1lbnRlIHVuIENhbGxSZXN1bHQsIG9wcHVyZSB1bmEgc2VtcGxpY2Ugc3RyaW5nYVxyXG4gICAgcmV0dXJuIG5ldyBQcm9taXNlPHN0cmluZz4oKHJlc29sdmUpID0+IHtcclxuICAgICAgaWYgKGVyciBpbnN0YW5jZW9mIEJsb2IpIHtcclxuICAgICAgICBsZXQgcmVhZGVyID0gbmV3IEZpbGVSZWFkZXIoKTtcclxuICAgICAgICByZWFkZXIub25sb2FkID0gKGU6IEV2ZW50KSA9PiB7XHJcbiAgICAgICAgICBsZXQgZXJyTXNnID0gKDxhbnk+ZS50YXJnZXQpLnJlc3VsdDtcclxuICAgICAgICAgIGxldCBqc29uZXJyTXNnOiBhbnk7XHJcbiAgICAgICAgICB0cnkgeyBqc29uZXJyTXNnID0gSlNPTi5wYXJzZShlcnJNc2cpOyB9IGNhdGNoIChlKSB7IH1cclxuICAgICAgICAgIHJldHVybiByZXNvbHZlKGpzb25lcnJNc2cgJiYgdGhpcy5pc0NhbGxSZXN1bHQoanNvbmVyck1zZykgPyBqc29uZXJyTXNnLmVycm9yLm1lc3NhZ2UgOiBlcnJNc2cpO1xyXG4gICAgICAgIH07XHJcbiAgICAgICAgcmVhZGVyLnJlYWRBc1RleHQoZXJyKVxyXG4gICAgICB9XHJcbiAgICAgIGVsc2UgaWYgKHRoaXMuaXNDYWxsUmVzdWx0KGVycikpXHJcbiAgICAgICAgcmV0dXJuIHJlc29sdmUoZXJyLmVycm9yLm1lc3NhZ2UpO1xyXG4gICAgICBlbHNlXHJcbiAgICAgICAgcmV0dXJuIHJlc29sdmUoZXJyPy50b1N0cmluZygpKTtcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogUmljb25vc2NlIHNlIGwnb2dnZXR0byDDqCBkaSB0aXBvICoqQ2FsbFJlc3VsdCoqIGUsIHNlIHPDrCwgbG8gY2FzdGEgYWwgdGlwbyBjb3JyZXR0byBwZXIgZXNzZXJlIHV0aWxpenphdG8gY29ycmV0dGFtZW50ZSBuZWwgYmxvY2NvIGRpIGNvZGljZSBzdWNjZXNzaXZvXHJcbiAgICogXHJcbiAgICogQHBhcmFtIHthbnl9IGVyciBFcnJvcmUgZGEgY29udHJvbGxhcmVcclxuICAgKi9cclxuICBwcml2YXRlIGlzQ2FsbFJlc3VsdChlcnI6IGFueSk6IGVyciBpcyB7IGVycm9yOiB7IG1lc3NhZ2U6IHN0cmluZyB9IH0ge1xyXG4gICAgcmV0dXJuICEhZXJyPy5lcnJvcj8ubWVzc2FnZTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFJpY29ub3NjZSBzZSBsJ2Vycm9yZSDDqCBkaSB0aXBvICoqSHR0cEVycm9yUmVzcG9uc2UqKiBlLCBzZSBzw6wsIGxvIGNhc3RhIGFsIHRpcG8gY29ycmV0dG8gcGVyIGVzc2VyZSB1dGlsaXp6YXRvIGNvcnJldHRhbWVudGUgbmVsIGJsb2NjbyBkaSBjb2RpY2Ugc3VjY2Vzc2l2b1xyXG4gICAqIFxyXG4gICAqIEBwYXJhbSB7YW55fSBlcnIgRXJyb3JlIGRhIGNvbnRyb2xsYXJlXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBpc0h0dHBFcnJvclJlc3BvbnNlKGVycjogYW55KTogZXJyIGlzIEh0dHBFcnJvclJlc3BvbnNlIHtcclxuICAgIHJldHVybiBlcnIgaW5zdGFuY2VvZiBIdHRwRXJyb3JSZXNwb25zZTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICogUmljb25vc2NlIHNlIGwnZXJyb3JlIMOoIGRpIHRpcG8gKipUeXBlRXJyb3IqKiBlLCBzZSBzw6wsIGxvIGNhc3RhIGFsIHRpcG8gY29ycmV0dG8gcGVyIGVzc2VyZSB1dGlsaXp6YXRvIGNvcnJldHRhbWVudGUgbmVsIGJsb2NjbyBkaSBjb2RpY2Ugc3VjY2Vzc2l2b1xyXG4gICogXHJcbiAgKiBAcGFyYW0ge2FueX0gZXJyIEVycm9yZSBkYSBjb250cm9sbGFyZVxyXG4gICovXHJcbiAgcHJpdmF0ZSBpc1R5cGVFcnJvcihlcnI6IGFueSk6IGVyciBpcyBUeXBlRXJyb3Ige1xyXG4gICAgcmV0dXJuIGVyci5uYW1lID09IFwiVHlwZUVycm9yXCI7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBDb21lIGRpY2UgaWwgbm9tZSwgcmVnaXN0cmEgdW4gZXJyb3JlIGUgcmVzdGl0dWlzY2UgdW4gT2JzZXJ2YWJsZSB2dW90byBjb21lIHJpc3VsdGF0byBkZWxsYSBjaGlhbWF0YVxyXG4gICAqIFxyXG4gICAqIEBwYXJhbSB7YW55fSByZXMgUmlzdWx0YXRvIGRlbGxhIGNoaWFtYXRhIGVmZmV0dHVhdGFcclxuICAgKiBAcGFyYW0ge3N0cmluZ30gZ3VpZCBJZGVudGlmaWNhdGl2byBHVUlEIGRlbGxhIGNoaWFtYXRhIGVmZmV0dHVhdGFcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IGhhbmRsZUVycm9yIEluZGljYSBzZSBnZXN0aXJlIGwnZXJyb3JlIHZpYSBsaWJyZXJpYSBvIHNlIGxpbWl0YXJzaSBhIHJlc3RpdHVpcmUgbCdPYnNlcnZhYmxlIHZ1b3RvXHJcbiAgICogXHJcbiAgICogQHJldHVybnMge09ic2VydmFibGU8YW55Pn0gT2JzZXJ2YWJsZSB2dW90b1xyXG4gICAqL1xyXG4gIHByaXZhdGUgcmVnaXN0ZXJFcnJvckFuZFJldHVybkVtcHR5T2JzZXJ2YWJsZShyZXM6IGFueSwgZ3VpZDogc3RyaW5nLCBoYW5kbGVFcnJvcjogYm9vbGVhbiA9IHRydWUpOiBPYnNlcnZhYmxlPGFueT4ge1xyXG4gICAgaWYgKGhhbmRsZUVycm9yKVxyXG4gICAgICB0aGlzLm9uRXJyb3IocmVzLCBndWlkKTtcclxuICAgIHJldHVybiBuZXcgT2JzZXJ2YWJsZSgoKSA9PiB7IH0pO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogRGF0byB1biBVcmwgZSBkZWkgcGFyYW1ldHJpIGNlcmNhIGRpIHJlY3VwZXJhcmUgbCdldmVudHVhbGUgb2dnZXR0byBnacOgIHNhbHZhdG8gaW4gY2FjaGUgY29uIGxlIGluZm9ybWF6aW9uaSBiYXNlIGRlbGxhIGNhY2hlIHN0ZXNzYVxyXG4gICAqIFxyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgVVJMIHN1IGN1aSBlZmZldHR1YXJlIGxhIGNoaWFtYXRhXHJcbiAgICogQHBhcmFtIHtIdHRwUGFyYW1zfSBwYXJhbXMgUGFyYW1ldHJpIGRlbGxhIGNoaWFtYXRhIChudWxsaSBpbiBjYXNvIGRpIFBPU1QpXHJcbiAgICogXHJcbiAgICogQHJldHVybnMge0NhY2hlSW5mb3N9IE9nZ2V0dG8gY29udGVuZW50ZSBsZSBpbmZvcm1hemlvbmkgc3VsbGEgY2FjaGUgcGVyIGwnb2dnZXR0byBzcGVjaWZpY2F0b1xyXG4gICAqL1xyXG4gIHByaXZhdGUgdHJ5R2V0Q2FjaGVJbmZvcm1hdGlvbnModXJsOiBzdHJpbmcsIHBhcmFtczogSHR0cFBhcmFtcyk6IENhY2hlSW5mb3Mge1xyXG5cclxuICAgIGxldCBjYWNoaW5nS2V5ID0gbnVsbCwgY2FjaGVUaW1lID0gbnVsbCwgaXRlbSA9IG51bGw7XHJcbiAgICBsZXQgdXNlQ2FjaGluZyA9ICEhKC8jY2FjaGUvZ2kuZXhlYyh1cmwpKTtcclxuXHJcbiAgICBpZiAodXNlQ2FjaGluZyAmJiB0aGlzLkNhY2hlSW5pdGlhbGl6ZWQpIHtcclxuICAgICAgbGV0IHRtcCA9IC8jY2FjaGUoOj8tKFxcZCspKS9naS5leGVjKHVybCk7XHJcbiAgICAgIGNhY2hlVGltZSA9IHRtcCA/IHRtcFsyXSA6IG51bGw7XHJcblxyXG4gICAgICB1cmwgPSB1cmwucmVwbGFjZShcIiNjYWNoZVwiICsgKGNhY2hlVGltZSA/IFwiLVwiICsgY2FjaGVUaW1lIDogXCJcIiksIFwiXCIpO1xyXG4gICAgICBpZiAodGhpcy51bnRpbWVkQ2FjaGVFeHBpcmVkKCkgJiYgIWNhY2hlVGltZSlcclxuICAgICAgICB0aGlzLnJlc2V0SHR0cFVudGltZWRDYWNoZVN0b3JhZ2UoKTtcclxuXHJcbiAgICAgIGNhY2hpbmdLZXkgPSB0aGlzLm1ha2VDYWNoZUtleSh1cmwsIHBhcmFtcyk7XHJcbiAgICAgIGxldCBjYWNoZUtleSA9IGNhY2hlVGltZSA/IHRoaXMubG9jYWxTdG9yYWdlSHR0cFRpbWVkQ2FjaGVLZXkgOiB0aGlzLmxvY2FsU3RvcmFnZUh0dHBDYWNoZUtleVxyXG4gICAgICBsZXQgY2FjaGVMcyA9IHRoaXMubG9jYWxTdG9yYWdlLmdldExvY2FsSXRlbShjYWNoZUtleSk7XHJcbiAgICAgIGxldCBjYWNoZSA9IGNhY2hlTHMgPyBjYWNoZUxzIDoge307XHJcblxyXG4gICAgICBpZiAoY2FjaGUgJiYgY2FjaGVbY2FjaGluZ0tleV0gJiYgIXRoaXMudGltZWRDYWNoZUl0ZW1FeHBpcmVkKGNhY2hlW2NhY2hpbmdLZXldKSkge1xyXG4gICAgICAgIC8vIFNlIGdlc3Rpc2NvIGlsIHRlbXBvIGVzYXR0byBkZWxsYSBjYWNoZSBwcmltYSBkaSByZXN0aXR1aXJlIGwnb2dnZXR0byBjYWNoYXRvIGxvIHJpcHVsaXNjbyBcclxuICAgICAgICAvLyBkYWxsZSBwcm9wcmlldMOgIGludGVybmUgY2hlIGdsaSBobyBhZ2dpdW50byBwZXIgY29udHJvbGxhcm5lIGxhIHNjYWRlbnphXHJcbiAgICAgICAgaWYgKGNhY2hlVGltZSlcclxuICAgICAgICAgIGRlbGV0ZSBjYWNoZVtjYWNoaW5nS2V5XS5fX2V4cGlyZTtcclxuXHJcbiAgICAgICAgaXRlbSA9IGNhY2hlW2NhY2hpbmdLZXldXHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBQZXIgYXNzaWN1cmFybWkgY2hlIGlsIHJpZmVpcm1lbnRvIGRlZ2xpIG9nZ2V0dGkgc2lhIGRpdmVyc28gdXRpbGl6em8gaWwgZGVlcENsb25lXHJcbiAgICByZXR1cm4gbmV3IENhY2hlSW5mb3ModXJsLCB1c2VDYWNoaW5nICYmIHRoaXMuQ2FjaGVJbml0aWFsaXplZCwgY2FjaGluZ0tleSwgY2FjaGVUaW1lLCB0aGlzLnV0aXNFeHRzLmRlZXBDbG9uZShpdGVtKSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBJbnNlcmlzY2UgdW4gb2dnZXR0byBuZWxsYSBjYWNoZSBhcHByb3ByaWF0YSBpbiBiYXNlIGFsbGUgaW5mb3JtYXppb25pIGNvbnRlbnV0ZSBuZWwgcGFyYW1ldHJvICoqY2FjaGVJbmZvcyoqXHJcbiAgICogXHJcbiAgICogQHBhcmFtIHtUfSBpdGVtIE9nZ2V0dG8gZGEgaW5zZXJpcmUgbmVsbGEgY2FjaGVcclxuICAgKiBAcGFyYW0ge0NhY2hlSW5mb3N9IGNhY2hlSW5mb3MgSW5mb3JtYXppb25pIHN1bGxhIGNhY2hlIHJlY3VwZXJhdGUgZGEgdW5hIGNoaWFtYXRhIHByZWNlZGVudGUgYSAqKnRyeUdldENhY2hlSW5mb3JtYXRpb25zKipcclxuICAgKi9cclxuICBwcml2YXRlIGNhY2hlUmVzcG9uc2U8VD4oaXRlbTogVCwgY2FjaGVJbmZvczogQ2FjaGVJbmZvcyk6IHZvaWQge1xyXG4gICAgbGV0IGNhY2hlS2V5ID0gY2FjaGVJbmZvcy5jYWNoZVRpbWUgPyB0aGlzLmxvY2FsU3RvcmFnZUh0dHBUaW1lZENhY2hlS2V5IDogdGhpcy5sb2NhbFN0b3JhZ2VIdHRwQ2FjaGVLZXlcclxuICAgIGxldCBjYWNoZUxzID0gdGhpcy5sb2NhbFN0b3JhZ2UuZ2V0TG9jYWxJdGVtKGNhY2hlS2V5KTtcclxuICAgIGxldCBjYWNoZSA9IGNhY2hlTHMgPyBjYWNoZUxzIDoge307XHJcblxyXG4gICAgY2FjaGVbY2FjaGVJbmZvcy5jYWNoZUtleV0gPSBpdGVtO1xyXG4gICAgaWYgKGNhY2hlSW5mb3MuY2FjaGVUaW1lKVxyXG4gICAgICBjYWNoZVtjYWNoZUluZm9zLmNhY2hlS2V5XS5fX2V4cGlyZSA9IGRheWpzKCkuYWRkKGNhY2hlSW5mb3MuY2FjaGVUaW1lLCBcInNlY29uZHNcIik7XHJcblxyXG4gICAgdGhpcy5sb2NhbFN0b3JhZ2Uuc2V0TG9jYWxJdGVtKGNhY2hlS2V5LCBjYWNoZSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBDb250cm9sbGEgc2UgbGEgY2FjaGUgcGVyIGxlIGNoaWFtYXRlIHNlbnphIGV4cGlyZSB0aW1lIMOoIHNjYWR1dGFcclxuICAgKiBcclxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gKip0cnVlKiogc2UgbGEgY2FjaGUgw6ggc2NhZHV0YSBlIGRldidlc3NlcmUgcmlwdWxpdGEsICoqZmFsc2UqKiBhbHRyaW1lbnRpXHJcbiAgICovXHJcbiAgcHJpdmF0ZSB1bnRpbWVkQ2FjaGVFeHBpcmVkKCk6IGJvb2xlYW4ge1xyXG4gICAgbGV0IGV4cGlyZSA9IEpTT04ucGFyc2UobG9jYWxTdG9yYWdlLmdldEl0ZW0odGhpcy5sb2NhbFN0b3JhZ2VIdHRwQ2FjaGVFeHBpcmVLZXkpKTtcclxuICAgIHJldHVybiAhZXhwaXJlIHx8IGV4cGlyZSAmJiBkYXlqcyhleHBpcmUpIDwgZGF5anMoKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIENvbnRyb2xsYSBzZSBsYSBjYWNoZSBwZXIgdW5hIGNoaWFtYXRhIGNoZSBoYSB1biB0ZW1wbyBkaSB2aXRhIGJlbiBkZWZpbml0byDDqCBzY2FkdXRhIG8gbWVub1xyXG4gICAqIFxyXG4gICAqIEBwYXJhbSB7YW55fSBpdGVtIE9nZ2V0dG8gcmVjdXBlcmF0byBkYWxsYSBjYWNoZSBhIGN1aSBobyBhZ2dpdW50byBsYSBjaGlhdmUgaW50ZXJuYSBfX2V4cGlyZVxyXG4gICAqIFxyXG4gICAqIEByZXR1cm5zIHtib29sZWFufSAqKnRydWUqKiBzZSBsYSBjYWNoZSDDqCBzY2FkdXRhIGUgZGV2J2Vzc2VyZSByaXB1bGl0YSwgKipmYWxzZSoqIGFsdHJpbWVudGlcclxuICAgKi9cclxuICBwcml2YXRlIHRpbWVkQ2FjaGVJdGVtRXhwaXJlZChpdGVtOiBhbnkpOiBib29sZWFuIHtcclxuICAgIHJldHVybiBkYXlqcyhpdGVtLl9fZXhwaXJlKSA8IGRheWpzKCk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBSaXB1bGlzY2UgbGEgY2FjaGUgZSBpbXBvc3RhIGxhIHByb3NzaW1hIHNjYWRlbnphIGFkIGFkZXNzbyArICoqQ0xJRU5UX0NBQ0hFX0RVUkFUSU9OX1MqKiAodG9rZW4gdmFsb3JpenphdG8gaW4gZmFzZSBkaSBjb25maWd1cmF6aW9uZSBkYWxsYSBwcm9wcmlldMOgICoqY2xpZW50Q2FjaGVEdXJhdGlvblMqKiBkZWxsYSBjbGFzc2UgKipIdHRwU2VydmljZU1vZHVsZUNvbmZpZyoqKVxyXG4gICAqL1xyXG4gIHB1YmxpYyBhc3luYyByZXNldEh0dHBVbnRpbWVkQ2FjaGVTdG9yYWdlKCkge1xyXG4gICAgaWYoIXRoaXMuQ2FjaGVJbml0aWFsaXplZClcclxuICAgICAgcmV0dXJuO1xyXG5cclxuICAgIGF3YWl0IHRoaXMubG9jYWxTdG9yYWdlLnNldEl0ZW0odGhpcy5sb2NhbFN0b3JhZ2VIdHRwQ2FjaGVLZXksIHt9KS50b1Byb21pc2UoKTtcclxuICAgIGxvY2FsU3RvcmFnZS5zZXRJdGVtKHRoaXMubG9jYWxTdG9yYWdlSHR0cENhY2hlRXhwaXJlS2V5LCBKU09OLnN0cmluZ2lmeShkYXlqcygpLmFkZCh0aGlzLkNMSUVOVF9DQUNIRV9EVVJBVElPTl9TLCBcInNlY29uZFwiKSkpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogUmlwdWxpc2NlIGxhIGNhY2hlIGRlbGxlIGNoaWFtYXRlIGNvbiB1biB0ZW1wbyBkaSBleHBpcmUgZGVmaW5pdG9cclxuICAgKi9cclxuICBwdWJsaWMgYXN5bmMgcmVzZXRIdHRwVGltZWRDYWNoZVN0b3JhZ2UoKSB7XHJcbiAgICBpZighdGhpcy5DYWNoZUluaXRpYWxpemVkKVxyXG4gICAgICByZXR1cm47XHJcbiAgICBcclxuICAgIGF3YWl0IHRoaXMubG9jYWxTdG9yYWdlLnNldEl0ZW0odGhpcy5sb2NhbFN0b3JhZ2VIdHRwVGltZWRDYWNoZUtleSwge30pLnRvUHJvbWlzZSgpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogR2VuZXJhIHVuYSBjaGlhdmUgcGVyIGxhIGNhY2hlIGRlbGxlIGNoaWFtYXRlIGluIGJhc2UgYWQgVVJMIGUgUGFyYW1ldHJpIEhUVFBcclxuICAgKiBcclxuICAgKiBAcGFyYW0ge3N0cmluZ30gdXJsIFVSTCBzdSBjdWkgZWZmZXR0dWFyZSBsYSBjaGlhbWF0YVxyXG4gICAqIEBwYXJhbSB7SHR0cFBhcmFtc30gcGFyYW1zIFBhcmFtZXRyaSBkZWxsYSBjaGlhbWF0YVxyXG4gICAqIFxyXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IENoaWF2ZSBjaGUgcmFwcHJlc2VudGEgaW4gbWFuaWVyYSB1bml2b2NhIGxhIGNoaWFtYXRhXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBtYWtlQ2FjaGVLZXkodXJsOiBzdHJpbmcsIHBhcmFtczogSHR0cFBhcmFtcyk6IHN0cmluZyB7XHJcbiAgICB0aGlzLm1lID0gdGhpcy5tZSB8fCB0aGlzLkV4dGVuc2lvbnNJbXBsLnJldHJpZXZlSWRlbnRpdHkoKTtcclxuXHJcbiAgICBsZXQgYXV0aEtleVBhcnQgPSAodGhpcy5tZSA/IHRoaXMubWUuSWR0ZW5hbnQgOiBcIlwiKSArICh0aGlzLm1lICYmIHRoaXMuQ0FDSEVfQllfVVNFUiA/IHRoaXMubWUuSWRVc2VyIDogXCJcIik7XHJcbiAgICBsZXQgcGFyYW1zS2V5UGFydCA9IHBhcmFtcyAmJiBwYXJhbXMua2V5cygpLmxlbmd0aCA+IDAgPyBwYXJhbXMua2V5cygpLnJlZHVjZSgocHJldjogYW55LCBuZXh0OiBhbnkpID0+IHByZXYgKyBcIixcIiArIG5leHQgKyAnPScgKyBwYXJhbXMuZ2V0KG5leHQpLCBcIlwiKSA6IFwiXCI7XHJcbiAgICByZXR1cm4gYXV0aEtleVBhcnQgKyBcIl9cIiArIHVybC5zdWJzdHJpbmcodXJsLmluZGV4T2YoXCJhcGlcIikgKyA0KSArIFwiP1wiICsgcGFyYW1zS2V5UGFydDtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEdlbmVyYXppb25lIEdVSURcclxuICAgKiBcclxuICAgKiBAcmV0dXJucyB7c3RyaW5nfSBOdW92byBHVUlEIGdlbmVyYXRvIGluIG1hbmllcmEgY2FzdWFsZVxyXG4gICAqL1xyXG4gIHByaXZhdGUgZ2V0R1VJRCgpOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuICd4eHh4eHh4eC14eHh4LTR4eHgteXh4eC14eHh4eHh4eHh4eHgnLnJlcGxhY2UoL1t4eV0vZywgZnVuY3Rpb24gKGMpIHtcclxuICAgICAgdmFyIHIgPSBNYXRoLnJhbmRvbSgpICogMTYgfCAwLCB2ID0gYyA9PSAneCcgPyByIDogKHIgJiAweDMgfCAweDgpO1xyXG4gICAgICByZXR1cm4gdi50b1N0cmluZygxNik7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIE1ldG9kbyBwZXIgc2NyaXZlcmUgbG9nIGEgY29uc29sZSBxdWFsb3JhICoqREVCVUdfTU9ERSoqIHJpc3VsdGFzc2UgKip0cnVlKipcclxuICAgKiBcclxuICAgKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZSBNZXNzYWdnaW8gZGkgbG9nXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBsb2cobWVzc2FnZTogc3RyaW5nKTogdm9pZCB7XHJcbiAgICBpZiAodGhpcy5IVFRQX0RFQlVHX01PREUpXHJcbiAgICAgIGNvbnNvbGUubG9nKFwiQGh0dHBzZXJ2aWNlOiBcIiArIG1lc3NhZ2UpXHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBIZWxwZXIgcGVyIGxhIGxvY2FsaXp6YXppb25lIGRlaSBtZXNzYWdnaVxyXG4gICAqIFxyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlIE1lc3NhZ2dpbyBkYSBsb2NhbGl6emFyZVxyXG4gICAqIFxyXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IE1lc3NhZ2dpbyBsb2NhbGl6emF0b1xyXG4gICAqL1xyXG4gIHByaXZhdGUgbG9jKG1lc3NhZ2U6IHN0cmluZyk6IHN0cmluZyB7XHJcbiAgICAvLyBUb2dsaWFtbyB2ZWxvY2VtZW50ZSBzdGUgbG9jYWxpenphemlvbmkgaW51dGlsaS4uLi5cclxuICAgIHJldHVybiBtZXNzYWdlO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogSGVscGVyIHBlciBsYW5jaWFyZSBsYSBzZWxlemlvbmUgZGkgdHV0dG8gcXVlbGxvIGNoZSDDqCByZWxhdGl2byBhIHVuIGFwaSBkaSByaWNlcmNhIGNvbiBBcHBTZWFyY2ggKGRpIGN1aSBub24gdXRpbGl6em8gaWwgdGlwbyB2ZXJvIHBlciByaWR1cnJlIGxlIGRpcGVuZGVuemUpXHJcbiAgICovXHJcbiAgcHVibGljIGdldEFsbDxUPih2aWV3OiB7IGl0ZW1zOiBUW10sIHBhZ2U6IG51bWJlciwgaXRlbXNwZXJwYWdlb3ZlcnJpZGU6IG51bWJlciwgc2VsZWN0aW9uOiB7IGV4Y2x1c2lvbnM6IFRbXSwgYWxsOiBib29sZWFuLCBpdGVtczogVFtdIH0gfSwgYXBpOiBzdHJpbmcsIHBhcnM/OiBIdHRwUGFyYW1zLCB0cmFuc2FjdGlvbj86IHN0cmluZyk6IE9ic2VydmFibGU8VFtdPiB7XHJcbiAgICBpZiAoIXZpZXcuc2VsZWN0aW9uLmFsbClcclxuICAgICAgcmV0dXJuIG9mKHZpZXcuc2VsZWN0aW9uLml0ZW1zKTtcclxuXHJcbiAgICB2YXIganNvblZpZXcgPSB0aGlzLnV0aXNFeHRzLmRlZXBDbG9uZSh2aWV3KTtcclxuICAgIGpzb25WaWV3LnBhZ2UgPSAxO1xyXG4gICAganNvblZpZXcuaXRlbXNwZXJwYWdlb3ZlcnJpZGUgPSA5OTk5OTk7XHJcblxyXG4gICAgcmV0dXJuIHRoaXMucG9zdDx7IGl0ZW1zOiBUW10sIHNlbGVjdGlvbjogeyBleGNsdXNpb25zOiBUW10gfSB9PihhcGksIGpzb25WaWV3LCBwYXJzLCB0cmFuc2FjdGlvbikucGlwZShtYXA8eyBpdGVtczogVFtdLCBzZWxlY3Rpb246IHsgZXhjbHVzaW9uczogVFtdIH0gfSwgVFtdPihyZXMgPT4ge1xyXG4gICAgICBsZXQgaXRlbXMgPSA8VFtdPnJlcy5pdGVtcztcclxuICAgICAgaXRlbXMuZm9yRWFjaCh0ID0+ICg8YW55PnQpLmhhc2ggPSB0aGlzLmhhc2guaGFzaE9iamVjdCh0LCBudWxsLCBmYWxzZSkpO1xyXG4gICAgICBpZiAocmVzLnNlbGVjdGlvbi5leGNsdXNpb25zPy5sZW5ndGggPiAwKVxyXG4gICAgICAgIGl0ZW1zID0gaXRlbXMuZmlsdGVyKCh0OiBhbnkpID0+ICFyZXMuc2VsZWN0aW9uLmV4Y2x1c2lvbnMuZmluZCgoZTogYW55KSA9PiB0aGlzLmhhc2guaGFzaE9iamVjdChlLCBudWxsLCBmYWxzZSkgPT0gdC5oYXNoKSk7XHJcbiAgICAgIHJldHVybiBpdGVtcztcclxuICAgIH0pKTtcclxuICB9XHJcblxyXG4gIC8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG4gICAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiBUUkFOU0FDVElPTiBIRUxQRVJTICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG4gICAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuICBwcml2YXRlIEdFVF9UcmFuc19CZWdpblRyYW5zOiBzdHJpbmcgPSBcIi9hcGkvVHJhbnMvQmVnaW5UcmFuc1wiO1xyXG4gIHByaXZhdGUgR0VUX1RyYW5zX0NoZWNrRXhlY3V0aW9uOiBzdHJpbmcgPSBcIi9hcGkvVHJhbnMvQ2hlY2tFeGVjdXRpb25cIjtcclxuICBwcml2YXRlIEdFVF9UcmFuc19FbmRUcmFuczogc3RyaW5nID0gXCIvYXBpL1RyYW5zL0VuZFRyYW5zXCI7XHJcblxyXG4gIHB1YmxpYyBiZWdpblRyYW5zYWN0aW9uKGV4ZWN1dGlvbktleTogc3RyaW5nLCBzZWNvbmRzVGltZW91dD86IG51bWJlcik6IE9ic2VydmFibGU8c3RyaW5nPiB7XHJcbiAgICB0aGlzLmxvZyhcImJlZ2luVHJhbnNhY3Rpb24gY2FsbCByZWNlaXZlZDogXCIgKyBleGVjdXRpb25LZXkpO1xyXG4gICAgdmFyIHBhcnMgPSBuZXcgSHR0cFBhcmFtcygpLnNldChcImV4ZWN1dGlvbktleVwiLCBleGVjdXRpb25LZXkpO1xyXG4gICAgaWYgKHNlY29uZHNUaW1lb3V0KVxyXG4gICAgICBwYXJzID0gcGFycy5zZXQoXCJzZWNvbmRzVGltZW91dFwiLCBzZWNvbmRzVGltZW91dC50b1N0cmluZygpKTtcclxuICAgIHJldHVybiB0aGlzLmdldDxzdHJpbmc+KHRoaXMuR0VUX1RyYW5zX0JlZ2luVHJhbnMsIHBhcnMpO1xyXG4gIH1cclxuXHJcbiAgcHVibGljIGNoZWNrVHJhbnNhY3Rpb24oZXhlY3V0aW9uS2V5OiBzdHJpbmcpOiBPYnNlcnZhYmxlPG51bWJlcj4ge1xyXG5cclxuICAgIHRoaXMubG9nKFwiY2hlY2tUcmFuc2FjdGlvbiBjYWxsIHJlY2VpdmVkOiBcIiArIGV4ZWN1dGlvbktleSk7XHJcbiAgICByZXR1cm4gdGhpcy5nZXQ8bnVtYmVyPih0aGlzLkdFVF9UcmFuc19DaGVja0V4ZWN1dGlvbiwgbmV3IEh0dHBQYXJhbXMoKS5zZXQoXCJleGVjdXRpb25LZXlcIiwgZXhlY3V0aW9uS2V5KSk7XHJcbiAgfVxyXG5cclxuICBwdWJsaWMgZW5kVHJhbnNhY3Rpb24odHJhbnNhY3Rpb25LZXk6IHN0cmluZywgdHJhbnNhY3Rpb25SZXN1bHQ6IGJvb2xlYW4pOiBPYnNlcnZhYmxlPHN0cmluZz4ge1xyXG4gICAgdGhpcy5sb2coXCJlbmRUcmFuc2FjdGlvbiBjYWxsIHJlY2VpdmVkOiBcIiArIHRyYW5zYWN0aW9uS2V5ICsgXCIgQ29tbWl0OiBcIiArIHRyYW5zYWN0aW9uUmVzdWx0KTtcclxuICAgIGxldCBwYXJzID0gbmV3IEh0dHBQYXJhbXMoKS5zZXQoXCJpZHRyYW5zXCIsIHRyYW5zYWN0aW9uS2V5KS5zZXQoXCJzdWNjZXNzXCIsIHRyYW5zYWN0aW9uUmVzdWx0LnRvU3RyaW5nKCkpO1xyXG4gICAgcmV0dXJuIHRoaXMuZ2V0PHN0cmluZz4odGhpcy5HRVRfVHJhbnNfRW5kVHJhbnMsIHBhcnMpO1xyXG4gIH1cclxufSJdfQ==
|
|
1
|
+
// Angular
|
|
2
|
+
import { HttpErrorResponse, HttpEventType, HttpHeaders, HttpParams } from "@angular/common/http";
|
|
3
|
+
import { Injectable, Inject, Optional } from "@angular/core";
|
|
4
|
+
// Direttive, Componenti, Librerie
|
|
5
|
+
import { catchError, concatMap, delay, finalize, first, map, scan } from "rxjs/operators";
|
|
6
|
+
import { forkJoin, from, Observable, of, Subject, throwError } from "rxjs";
|
|
7
|
+
// Chiamate ai Repository / tokens
|
|
8
|
+
import { HTTP_INVALIDATION, CLIENT_CACHE_DURATION_S, CACHE_BY_USER, HTTP_DEBUG_MODE } from './tokens';
|
|
9
|
+
// Modelli
|
|
10
|
+
import { HttpServiceExtensions } from './config/HttpServiceExtensions';
|
|
11
|
+
import { CacheInfos } from "./models/CacheInfos";
|
|
12
|
+
import * as i0 from "@angular/core";
|
|
13
|
+
import * as i1 from "./config/HttpServiceExtensions";
|
|
14
|
+
import * as i2 from "@esfaenza/localizations";
|
|
15
|
+
import * as i3 from "@angular/common/http";
|
|
16
|
+
import * as i4 from "@esfaenza/preferences";
|
|
17
|
+
import * as i5 from "@esfaenza/extensions";
|
|
18
|
+
/**
|
|
19
|
+
* Servizio utilizzato per effettuare qualsiasi tipo di chiamata HTTP dall'applicazione, gestisce errori e cache delle risposte nativamente e ne può essere
|
|
20
|
+
* esteso/modificato il comportamento implementando la classe di "hook" **IHttpServiceExtensions** e registrandola nel provider della classe **HttpServiceExtensions**
|
|
21
|
+
*/
|
|
22
|
+
export class HTTPService {
|
|
23
|
+
/**
|
|
24
|
+
* @ignore
|
|
25
|
+
*/
|
|
26
|
+
constructor(EXTENSION_CLASS, HTTP_INVALIDATION, CLIENT_CACHE_DURATION_S, CACHE_BY_USER, HTTP_DEBUG_MODE, bc, http, localStorage, hash, utisExts) {
|
|
27
|
+
this.EXTENSION_CLASS = EXTENSION_CLASS;
|
|
28
|
+
this.HTTP_INVALIDATION = HTTP_INVALIDATION;
|
|
29
|
+
this.CLIENT_CACHE_DURATION_S = CLIENT_CACHE_DURATION_S;
|
|
30
|
+
this.CACHE_BY_USER = CACHE_BY_USER;
|
|
31
|
+
this.HTTP_DEBUG_MODE = HTTP_DEBUG_MODE;
|
|
32
|
+
this.bc = bc;
|
|
33
|
+
this.http = http;
|
|
34
|
+
this.localStorage = localStorage;
|
|
35
|
+
this.hash = hash;
|
|
36
|
+
this.utisExts = utisExts;
|
|
37
|
+
/** Cache dello stato delle chiamate HTTP attualmente effettuate. Ogni chiamata è rappresentata da un GUID e lo status assume valore **false** solo sugli errori */
|
|
38
|
+
this.callStatus = {};
|
|
39
|
+
/** Nome della cache in cui vengono storicizzate le informazioni sulle risposte delle chiamate sotto forma di dictionary */
|
|
40
|
+
this.localStorageHttpCacheKey = null;
|
|
41
|
+
/** Nome della cache in cui vengono storicizzate le informazioni sulle risposte delle chiamate sotto forma di dictionary, solo per le chiamate con un tempo definito di caching */
|
|
42
|
+
this.localStorageHttpTimedCacheKey = null;
|
|
43
|
+
/** Nome della cache in cui vengono storicizzate le informazioni sullo scadere della cache stessa */
|
|
44
|
+
this.localStorageHttpCacheExpireKey = null;
|
|
45
|
+
/** Identità collegata al token di autenticazione da usare, richiesta al programma che utilizza la libreria attraverso l'hook **retrieveIdentity** della **HttpServiceExtensions** */
|
|
46
|
+
this.me = null;
|
|
47
|
+
/** Indica che la cache a tempo dev'essere persistita il prima possibile */
|
|
48
|
+
this.PersistTimedCacheASAP = false;
|
|
49
|
+
/** Indica che la cache senza limiti di tempo dev'essere persistita il prima possibile */
|
|
50
|
+
this.PersistUntimedCacheASAP = false;
|
|
51
|
+
/** Subject emesso quando il servizio http si stabilizza, cioè quando non c'è nessuna chiamata pending o in corso da qualche istante */
|
|
52
|
+
this.Stabilized = new Subject();
|
|
53
|
+
/** Lista delle ultime 3 chiamate completate con successo in ordine di completamento (in posizione 0 c'è l'ultima completata eccetera...) */
|
|
54
|
+
this.LastThreeCompletedCalls = [];
|
|
55
|
+
this.CacheInitialized = false;
|
|
56
|
+
/*****************************************************************************************************************************************
|
|
57
|
+
***************************************************** TRANSACTION HELPERS ***************************************************************
|
|
58
|
+
*****************************************************************************************************************************************/
|
|
59
|
+
this.GET_Trans_BeginTrans = "/api/Trans/BeginTrans";
|
|
60
|
+
this.GET_Trans_CheckExecution = "/api/Trans/CheckExecution";
|
|
61
|
+
this.GET_Trans_EndTrans = "/api/Trans/EndTrans";
|
|
62
|
+
this.ExtensionsImpl = this.EXTENSION_CLASS || new HttpServiceExtensions();
|
|
63
|
+
}
|
|
64
|
+
setAppConfig(myconfig) {
|
|
65
|
+
this.localStorageHttpCacheKey = (myconfig.AppData.ModuleDescription).replace(/\s/g, '_') + "_HttpCache";
|
|
66
|
+
this.localStorageHttpTimedCacheKey = (myconfig.AppData.ModuleDescription).replace(/\s/g, '_') + "_HttpTimedCache";
|
|
67
|
+
this.localStorageHttpCacheExpireKey = this.localStorageHttpCacheKey + "_Expire";
|
|
68
|
+
this.adjustOldStorageSystem();
|
|
69
|
+
this.CacheInitialized = true;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Se vedo che ci sono elementi salvati nel localStorage provo a toglierli e a risalvarli via preference.
|
|
73
|
+
* Nel caso migliore li sposto dal localStorage al DB di preference, nel caso peggiore li tolgo e li risalvo nel localStorage
|
|
74
|
+
*/
|
|
75
|
+
async adjustOldStorageSystem() {
|
|
76
|
+
var lsTimed = localStorage.getItem(this.localStorageHttpTimedCacheKey);
|
|
77
|
+
var lsUntimed = localStorage.getItem(this.localStorageHttpCacheKey);
|
|
78
|
+
if (!lsTimed && !lsUntimed)
|
|
79
|
+
return;
|
|
80
|
+
localStorage.removeItem(this.localStorageHttpTimedCacheKey);
|
|
81
|
+
localStorage.removeItem(this.localStorageHttpCacheKey);
|
|
82
|
+
lsTimed = lsTimed ? JSON.parse(lsTimed) : {};
|
|
83
|
+
lsUntimed = lsUntimed ? JSON.parse(lsUntimed) : {};
|
|
84
|
+
await forkJoin([
|
|
85
|
+
this.localStorage.setItem(this.localStorageHttpTimedCacheKey, lsTimed),
|
|
86
|
+
this.localStorage.setItem(this.localStorageHttpCacheKey, lsUntimed)
|
|
87
|
+
]).toPromise();
|
|
88
|
+
this.log(this.loc("Converted old storage system to new one"));
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Esecuzione di una GET HTTP con eventualmente la gestione della cache qualora la chiamata termini con la convenzione "#cache"
|
|
92
|
+
*
|
|
93
|
+
* @param {string} url URL su cui effettuare la chiamata
|
|
94
|
+
* @param {HttpParams} params Parametri della chiamata
|
|
95
|
+
* @param {string} transaction Codice transazione collegato a questa chiamata. Viene inserito nell'Header "X-TX-ID" e lato Backend dovrà essere gestito di conseguenza
|
|
96
|
+
* @param {boolean} succesfulResultMandatory Indica che questa chiamata deve assolutamente andare bene. In caso contrario viene fisicamente fatto il throw che può essere
|
|
97
|
+
* raccolto da chi usa la libreria nella pipe "onError" dell'Observable restituito ed essere gestito in maniera non standard
|
|
98
|
+
* @param {Function} errorCallback Callback chiamato in caso di errore
|
|
99
|
+
*
|
|
100
|
+
* @returns {Observable<T>} Observable che contiene il risultato della chiamata
|
|
101
|
+
*/
|
|
102
|
+
get(url, params = null, transaction = "", succesfulResultMandatory = true, errorCallback = null) {
|
|
103
|
+
return forkJoin({
|
|
104
|
+
myGuid: from([this.defaultStartCall(url)]),
|
|
105
|
+
locale: this.bc.Locale.pipe(first())
|
|
106
|
+
}).pipe(concatMap((ret) => {
|
|
107
|
+
let cachedInfos = this.tryGetCacheInformations(url, params);
|
|
108
|
+
if (cachedInfos.cache && cachedInfos.cacheItem) {
|
|
109
|
+
this.log(this.loc("Result for") + " " + url + " " + this.loc("retrieved from cache"));
|
|
110
|
+
return of(cachedInfos.cacheItem).pipe(delay(0), finalize(() => { this.tryFinalizeByGuid(ret.myGuid); }));
|
|
111
|
+
}
|
|
112
|
+
var httpCall = this.http.get(cachedInfos.finalUrl, { headers: this.getHeaders(ret.locale, transaction), params: params });
|
|
113
|
+
return httpCall.pipe(map((res) => {
|
|
114
|
+
let responseItem = res;
|
|
115
|
+
if (cachedInfos.cache) {
|
|
116
|
+
this.cacheResponse(this.utisExts.deepClone(responseItem), cachedInfos);
|
|
117
|
+
this.log(this.loc("Cached result for") + " " + url);
|
|
118
|
+
}
|
|
119
|
+
return responseItem;
|
|
120
|
+
}), catchError((err, caught) => {
|
|
121
|
+
if (errorCallback)
|
|
122
|
+
errorCallback();
|
|
123
|
+
return !succesfulResultMandatory ? throwError(err) : this.registerErrorAndReturnEmptyObservable(err, ret.myGuid);
|
|
124
|
+
}), finalize(() => { this.tryFinalizeByGuid(ret.myGuid, cachedInfos); }));
|
|
125
|
+
}));
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Esecuzione di una GET HTTP con eventualmente la gestione della cache qualora la chiamata termini con la convenzione "#cache"
|
|
129
|
+
*
|
|
130
|
+
* Caso specifico di chiamata che deve restituire un Blob o un ArrayBuffer nativo da elaborare
|
|
131
|
+
*
|
|
132
|
+
* @param {string} url URL su cui effettuare la chiamata
|
|
133
|
+
* @param {HttpParams} params Parametri della chiamata
|
|
134
|
+
* @param {"arraybuffer"| "blob"} type Tipo di ritorno richiesto
|
|
135
|
+
* @param {string} transaction Codice transazione collegato a questa chiamata. Viene inserito nell'Header "X-TX-ID" e lato Backend dovrà essere gestito di conseguenza
|
|
136
|
+
* @param {boolean} succesfulResultMandatory Indica che questa chiamata deve assolutamente andare bene. In caso contrario viene fisicamente fatto il throw che può essere
|
|
137
|
+
* raccolto da chi usa la libreria nella pipe "onError" dell'Observable restituito ed essere gestito in maniera non standard
|
|
138
|
+
* @param {Function} errorCallback Callback chiamato in caso di errore
|
|
139
|
+
*
|
|
140
|
+
* @returns {Observable<Blob | ArrayBuffer>} Observable che contiene il risultato della chiamata
|
|
141
|
+
*/
|
|
142
|
+
getRaw(url, params = null, type = "arraybuffer", transaction = "", succesfulResultMandatory = true, errorCallback = null) {
|
|
143
|
+
return forkJoin({
|
|
144
|
+
myGuid: from([this.defaultStartCall(url)]),
|
|
145
|
+
locale: this.bc.Locale.pipe(first())
|
|
146
|
+
}).pipe(concatMap((ret) => {
|
|
147
|
+
let cachedInfos = this.tryGetCacheInformations(url, params);
|
|
148
|
+
if (cachedInfos.cache && cachedInfos.cacheItem) {
|
|
149
|
+
this.log(this.loc("Result for") + " " + url + " " + this.loc("retrieved from cache"));
|
|
150
|
+
return of(cachedInfos.cacheItem).pipe(delay(0), finalize(() => { this.tryFinalizeByGuid(ret.myGuid); }));
|
|
151
|
+
}
|
|
152
|
+
var httpCall = this.http.get(cachedInfos.finalUrl, { responseType: type, headers: this.getHeaders(ret.locale, transaction), params: params });
|
|
153
|
+
return httpCall.pipe(map((blob) => {
|
|
154
|
+
if (cachedInfos.cache) {
|
|
155
|
+
this.cacheResponse(blob, cachedInfos);
|
|
156
|
+
this.log(this.loc("Cached result for") + " " + url);
|
|
157
|
+
}
|
|
158
|
+
return blob;
|
|
159
|
+
}), catchError((err, caught) => {
|
|
160
|
+
if (errorCallback)
|
|
161
|
+
errorCallback();
|
|
162
|
+
return !succesfulResultMandatory ? throwError(err) : this.registerErrorAndReturnEmptyObservable(err, ret.myGuid);
|
|
163
|
+
}), finalize(() => { this.tryFinalizeByGuid(ret.myGuid, cachedInfos); }));
|
|
164
|
+
}));
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Esecuzione di una POST HTTP
|
|
168
|
+
*
|
|
169
|
+
* @param {string} url URL su cui effettuare la chiamata
|
|
170
|
+
* @param {any} bodyData DTO per la chiamata
|
|
171
|
+
* @param {HttpParams} params Parametri della chiamata
|
|
172
|
+
* @param {string} transaction Codice transazione collegato a questa chiamata. Viene inserito nell'Header "X-TX-ID" e lato Backend dovrà essere gestito di conseguenza
|
|
173
|
+
* @param {boolean} succesfulResultMandatory Indica che questa chiamata deve assolutamente andare bene. In caso contrario viene fisicamente fatto il throw che può essere
|
|
174
|
+
* raccolto da chi usa la libreria nella pipe "onError" dell'Observable restituito ed essere gestito in maniera non standard
|
|
175
|
+
*
|
|
176
|
+
* @returns {Observable<T>} Observable che contiene il risultato della chiamata
|
|
177
|
+
*/
|
|
178
|
+
post(url, bodyData, params = null, transaction = "", succesfulResultMandatory = true) {
|
|
179
|
+
return forkJoin({
|
|
180
|
+
myGuid: from([this.defaultStartCall(url)]),
|
|
181
|
+
locale: this.bc.Locale.pipe(first())
|
|
182
|
+
}).pipe(concatMap((ret) => {
|
|
183
|
+
// Se è una ricerca, shallow copy e rimuovo gli "items" per evitare di farli andare su e giù al backend
|
|
184
|
+
if (!!bodyData?.items && !!bodyData?.page) {
|
|
185
|
+
bodyData = { ...bodyData };
|
|
186
|
+
delete bodyData.items;
|
|
187
|
+
}
|
|
188
|
+
var httpCall = this.http.post(url, bodyData, { headers: this.getHeaders(ret.locale, transaction), params: params });
|
|
189
|
+
return httpCall.pipe(catchError((err, _) => {
|
|
190
|
+
return !succesfulResultMandatory ? throwError(err) : this.registerErrorAndReturnEmptyObservable(err, ret.myGuid);
|
|
191
|
+
}), finalize(() => { this.tryFinalizeByGuid(ret.myGuid); }));
|
|
192
|
+
}));
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Esecuzione di una DELETE HTTP
|
|
196
|
+
*
|
|
197
|
+
* @param {string} url URL su cui effettuare la chiamata
|
|
198
|
+
* @param {HttpParams} params Parametri della chiamata
|
|
199
|
+
* @param {string} transaction Codice transazione collegato a questa chiamata. Viene inserito nell'Header "X-TX-ID" e lato Backend dovrà essere gestito di conseguenza
|
|
200
|
+
* @param {boolean} succesfulResultMandatory Indica che questa chiamata deve assolutamente andare bene. In caso contrario viene fisicamente fatto il throw che può essere
|
|
201
|
+
* raccolto da chi usa la libreria nella pipe "onError" dell'Observable restituito ed essere gestito in maniera non standard
|
|
202
|
+
*
|
|
203
|
+
* @returns {Observable<T>} Observable che contiene il risultato della chiamata
|
|
204
|
+
*/
|
|
205
|
+
delete(url, params = null, transaction = "", succesfulResultMandatory = true) {
|
|
206
|
+
return forkJoin({
|
|
207
|
+
myGuid: from([this.defaultStartCall(url)]),
|
|
208
|
+
locale: this.bc.Locale.pipe(first())
|
|
209
|
+
}).pipe(concatMap((ret) => {
|
|
210
|
+
var httpCall = this.http.delete(url, { headers: this.getHeaders(ret.locale, transaction), params: params });
|
|
211
|
+
return httpCall.pipe(catchError((err, caught) => {
|
|
212
|
+
return !succesfulResultMandatory ? throwError(err) : this.registerErrorAndReturnEmptyObservable(err, ret.myGuid);
|
|
213
|
+
}), finalize(() => { this.tryFinalizeByGuid(ret.myGuid); }));
|
|
214
|
+
}));
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Esecuzione di una PUT HTTP
|
|
218
|
+
*
|
|
219
|
+
* @param {string} url URL su cui effettuare la chiamata
|
|
220
|
+
* @param {any} bodyData DTO per la chiamata
|
|
221
|
+
* @param {HttpParams} params Parametri della chiamata
|
|
222
|
+
* @param {string} transaction Codice transazione collegato a questa chiamata. Viene inserito nell'Header "X-TX-ID" e lato Backend dovrà essere gestito di conseguenza
|
|
223
|
+
* @param {boolean} succesfulResultMandatory Indica che questa chiamata deve assolutamente andare bene. In caso contrario viene fisicamente fatto il throw che può essere
|
|
224
|
+
* raccolto da chi usa la libreria nella pipe "onError" dell'Observable restituito ed essere gestito in maniera non standard
|
|
225
|
+
*
|
|
226
|
+
* @returns {Observable<T>} Observable che contiene il risultato della chiamata
|
|
227
|
+
*/
|
|
228
|
+
put(url, bodyData, params = null, transaction = "", succesfulResultMandatory = true) {
|
|
229
|
+
return forkJoin({
|
|
230
|
+
myGuid: from([this.defaultStartCall(url)]),
|
|
231
|
+
locale: this.bc.Locale.pipe(first())
|
|
232
|
+
}).pipe(concatMap((ret) => {
|
|
233
|
+
var httpCall = this.http.put(url, bodyData, { headers: this.getHeaders(ret.locale, transaction), params: params });
|
|
234
|
+
return httpCall.pipe(catchError((err, caught) => {
|
|
235
|
+
return !succesfulResultMandatory ? throwError(err) : this.registerErrorAndReturnEmptyObservable(err, ret.myGuid);
|
|
236
|
+
}), finalize(() => { this.tryFinalizeByGuid(ret.myGuid); }));
|
|
237
|
+
}));
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Esecuzione di una POST HTTP
|
|
241
|
+
*
|
|
242
|
+
* Casistica particolare in cui bisogna anche inviare dei File
|
|
243
|
+
*
|
|
244
|
+
* @param {string} url URL su cui effettuare la chiamata
|
|
245
|
+
* @param {any} bodyData DTO per la chiamata
|
|
246
|
+
* @param {File[] | File} fileArrayOrFile Singolo file o lista di file da inviare. Il tipo **File** è quello nativo del Javascript
|
|
247
|
+
*
|
|
248
|
+
* @returns {Observable<T>} Observable che contiene il risultato della chiamata
|
|
249
|
+
*/
|
|
250
|
+
postwithFiles(url, bodyData, fileArrayOrFile, params = null, succesfulResultMandatory = true, onError) {
|
|
251
|
+
return forkJoin({
|
|
252
|
+
myGuid: from([this.defaultStartCall(url)]),
|
|
253
|
+
locale: this.bc.Locale.pipe(first())
|
|
254
|
+
}).pipe(concatMap((ret) => {
|
|
255
|
+
var formData = this.getFilesFormData(fileArrayOrFile);
|
|
256
|
+
formData.append("body", JSON.stringify(bodyData));
|
|
257
|
+
var httpCall = this.http.post(url, formData, { params: params, headers: this.getHeaders(ret.locale, null, true, null, null) });
|
|
258
|
+
return httpCall.pipe(catchError((err, caught) => {
|
|
259
|
+
onError?.();
|
|
260
|
+
return !succesfulResultMandatory ? throwError(err) : this.registerErrorAndReturnEmptyObservable(err, ret.myGuid);
|
|
261
|
+
}), finalize(() => { this.tryFinalizeByGuid(ret.myGuid); }));
|
|
262
|
+
}));
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Esecuzione di una POST HTTP
|
|
266
|
+
*
|
|
267
|
+
* Casistica particolare in cui viene restituito un file gestito come ObjectURL il cui URL si può gestire dal parametro di callback **getFileCallback**.
|
|
268
|
+
* La chiamata non ha un tipo restituito in quanto il risultato dev'essere gestito attraverso la callback **getFileCallback**
|
|
269
|
+
*
|
|
270
|
+
* @param {string} url URL su cui effettuare la chiamata
|
|
271
|
+
* @param {K} bodyData DTO per la chiamata
|
|
272
|
+
* @param {string} filename Nome del file che si sta richiedendo, rimane lato Frontend e serve per assegnare arbitrariamente un nome al file restituito, se vuoto viene utilizzata la Content-Disposition della risposta
|
|
273
|
+
* @param {Function} getFileCallback Callback a due parametri (url: string, filename: string) per gestire il risultato del file richiesto. **Utilizzare UtilityService.fileDownload** di @esfaenza/extensions
|
|
274
|
+
* @param {Function} afterGetFile Callback da chiamare dopo aver gestito la risposta del **getFileCallback**, in caso **handleError** fosse **false** verrà richiamato anche in caso di errore
|
|
275
|
+
* @param {boolean} handleError Indica se di default gli errori devono essere gestiti dalla libreria o se devono essere ignorati
|
|
276
|
+
*/
|
|
277
|
+
async postGetFile(url, bodyData, filename, getFileCallback, afterGetFile = null, handleError = true, pars) {
|
|
278
|
+
let myGuid = this.defaultStartCall(url);
|
|
279
|
+
let locale = await this.bc.Locale.pipe(first()).toPromise();
|
|
280
|
+
this.http.post(url, bodyData, { params: pars, headers: this.getHeaders(locale), observe: 'response', responseType: "blob" }).pipe(catchError((err, caught) => {
|
|
281
|
+
if (afterGetFile && !handleError)
|
|
282
|
+
afterGetFile();
|
|
283
|
+
return this.registerErrorAndReturnEmptyObservable(err, myGuid, handleError);
|
|
284
|
+
}), finalize(() => { this.tryFinalizeByGuid(myGuid); })).subscribe((response) => {
|
|
285
|
+
let retUrl = window.URL.createObjectURL(response.body);
|
|
286
|
+
let fn = response.headers.get('content-disposition')?.split(';')[1]?.split('filename')[1]?.split('=')[1]?.trim().replace(/\"/g, '');
|
|
287
|
+
getFileCallback(retUrl, filename || fn);
|
|
288
|
+
if (afterGetFile)
|
|
289
|
+
afterGetFile();
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Esecuzione di una GET HTTP
|
|
294
|
+
*
|
|
295
|
+
* Casistica particolare in cui viene restituito un file gestito come ObjectURL il cui URL si può gestire dal parametro di callback **getFileCallback**.
|
|
296
|
+
* La chiamata non ha un tipo restituito in quanto il risultato dev'essere gestito attraverso la callback **getFileCallback**
|
|
297
|
+
*
|
|
298
|
+
* @param {string} url URL su cui effettuare la chiamata
|
|
299
|
+
* @param {HttpParams} params Parametri della chiamata
|
|
300
|
+
* @param {string} filename Nome del file che si sta richiedendo, rimane lato Frontend e serve per assegnare arbitrariamente un nome al file restituito, se vuoto viene utilizzata la Content-Disposition della risposta
|
|
301
|
+
* @param {Function} getFileCallback Callback a due parametri (url: string, filename: string) per gestire il risultato del file richiesto. **Utilizzare UtilityService.fileDownload** di @esfaenza/extensions
|
|
302
|
+
* @param {Function} afterGetFile Callback da chiamare dopo aver gestito la risposta del **getFileCallback**, in caso **handleError** fosse **false** verrà richiamato anche in caso di errore
|
|
303
|
+
* @param {boolean} handleError Indica se di default gli errori devono essere gestiti dalla libreria o se devono essere ignorati
|
|
304
|
+
*/
|
|
305
|
+
async getFile(url, params = null, filename, getFileCallback, afterGetFile = null, handleError = true) {
|
|
306
|
+
let myGuid = this.defaultStartCall(url);
|
|
307
|
+
let locale = await this.bc.Locale.pipe(first()).toPromise();
|
|
308
|
+
this.http.get(url, { params: params, headers: this.getHeaders(locale), observe: 'response', responseType: "blob" }).pipe(catchError((err, caught) => {
|
|
309
|
+
if (afterGetFile && !handleError)
|
|
310
|
+
afterGetFile();
|
|
311
|
+
return this.registerErrorAndReturnEmptyObservable(err, myGuid, handleError);
|
|
312
|
+
}), finalize(() => { this.tryFinalizeByGuid(myGuid); })).subscribe((response) => {
|
|
313
|
+
let retUrl = window.URL.createObjectURL(response.body);
|
|
314
|
+
let fn = response.headers.get('content-disposition')?.split(';')[1]?.split('filename')[1]?.split('=')[1]?.trim().replace(/\"/g, '');
|
|
315
|
+
getFileCallback(retUrl, filename || fn);
|
|
316
|
+
if (afterGetFile)
|
|
317
|
+
afterGetFile();
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Download nativo di un file. Internamente utilizza il pattern **window.location.href = "..."**
|
|
322
|
+
*
|
|
323
|
+
* @param {string} url URL su cui effettuare la chiamata
|
|
324
|
+
* @param {HttpParams} params Parametri della chiamata
|
|
325
|
+
*/
|
|
326
|
+
getFileNative(url, params = null) {
|
|
327
|
+
// Encodo tutti i parametri per evitare casi particolari
|
|
328
|
+
// var encodedParams = new HttpParams();
|
|
329
|
+
// let parKeys = params.keys();
|
|
330
|
+
// for (let i = 0; i < parKeys.length; i++)
|
|
331
|
+
// encodedParams = encodedParams.set(parKeys[i], encodeURIComponent(params.get(parKeys[i])));
|
|
332
|
+
let finalUrl = url + (params ? "?" + params.toString().replace(/\+/g, '%2b') : "");
|
|
333
|
+
window.location.href = finalUrl;
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Esecuzione di una GET di un file che emette i vari eventi di progresso di download.
|
|
337
|
+
* Utilizzarla per overridare la dialog nativa di progress del browser e sostituirla con qualcosa tipo quello che fa MEGA.
|
|
338
|
+
*
|
|
339
|
+
* In caso si voglia ottenere il risultato nativo del browser del download utilizzare **getFileNative(url, pars)**
|
|
340
|
+
*
|
|
341
|
+
* @param {string} url URL su cui effettuare la chiamata
|
|
342
|
+
* @param {HttpParams} params Parametri della chiamata
|
|
343
|
+
* @param {Function} getFileCallback Callback a due parametri (url: string, filename: string) per gestire il risultato del file richiesto. **Utilizzare UtilityService.fileDownload** di @esfaenza/extensions
|
|
344
|
+
*
|
|
345
|
+
* @returns {Observable<Download>} Observable dei vari step di progresso del download
|
|
346
|
+
*/
|
|
347
|
+
getFileWithProgress(url, params = null, getFileCallback) {
|
|
348
|
+
return forkJoin({
|
|
349
|
+
myGuid: from([this.defaultStartCall(url)]),
|
|
350
|
+
locale: this.bc.Locale.pipe(first())
|
|
351
|
+
}).pipe(concatMap((ret) => {
|
|
352
|
+
return this.http.get(url, { responseType: 'blob', headers: this.getHeaders(ret.locale), params: params, observe: 'events', reportProgress: true })
|
|
353
|
+
.pipe(scan((previous, event) => {
|
|
354
|
+
if (this.isHttpProgressEvent(event)) {
|
|
355
|
+
let progress = event.total ? (event.loaded > event.total ? 100 : Math.round((100 * event.loaded) / event.total)) : previous.progress;
|
|
356
|
+
return { progress: progress, state: 'IN_PROGRESS', content: null };
|
|
357
|
+
}
|
|
358
|
+
if (this.isHttpResponse(event)) {
|
|
359
|
+
if (event.body) {
|
|
360
|
+
let cdisp = event.headers.get('content-disposition');
|
|
361
|
+
let cdispFilename = cdisp.split(';')[1].split('filename')[1].split('=')[1].trim().replace(/\"/g, '');
|
|
362
|
+
let retUrl = window.URL.createObjectURL(event.body);
|
|
363
|
+
getFileCallback(retUrl, cdispFilename);
|
|
364
|
+
}
|
|
365
|
+
return { progress: 100, state: 'DONE', content: event.body };
|
|
366
|
+
}
|
|
367
|
+
return previous;
|
|
368
|
+
}, { state: 'PENDING', progress: 0, content: null }), catchError((err, _) => { return this.registerErrorAndReturnEmptyObservable(err, ret.myGuid); }), finalize(() => { this.tryFinalizeByGuid(ret.myGuid); }));
|
|
369
|
+
}));
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Riconosce se l'evento HTTP è di tipo **HttpResponse** e, se sì, lo casta al tipo corretto per essere utilizzato correttamente nel blocco di codice successivo
|
|
373
|
+
*/
|
|
374
|
+
isHttpResponse(event) {
|
|
375
|
+
return event.type === HttpEventType.Response;
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Riconosce se l'evento HTTP è di tipo **HttpProgressEvent** e, se sì, lo casta al tipo corretto per essere utilizzato correttamente nel blocco di codice successivo
|
|
379
|
+
*/
|
|
380
|
+
isHttpProgressEvent(event) {
|
|
381
|
+
return event.type === HttpEventType.DownloadProgress || event.type === HttpEventType.UploadProgress;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Gestione dell'inizio di una chiamata ad un certo URL, viene generato un GUID da assegnarci, controllata la scadenza della cache,
|
|
385
|
+
* e eventualmente loggato il fatto che sta per essere effettuata una chiamata HTTP
|
|
386
|
+
*
|
|
387
|
+
* @param {string} url Url a cui effettuare la chiamata
|
|
388
|
+
* @returns {string} GUID assegnato alla chiamata
|
|
389
|
+
*/
|
|
390
|
+
defaultStartCall(url) {
|
|
391
|
+
let myGuid = this.getGUID();
|
|
392
|
+
this.checkCacheInvalidation(url);
|
|
393
|
+
this.callStatus[myGuid] = { url: url, success: true };
|
|
394
|
+
this.log(this.loc("Starting call") + " " + myGuid + " " + this.loc("at URL") + ": " + url);
|
|
395
|
+
return myGuid;
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Dato un url vengono controllate le informazioni su tutti gli url da invalidare collegati all'url chiamato e, se presenti in cache, invalidati
|
|
399
|
+
*
|
|
400
|
+
* @param {string} url URL per cui controllare se ci sono chiamate in cache da invalidare
|
|
401
|
+
*/
|
|
402
|
+
checkCacheInvalidation(url) {
|
|
403
|
+
if (!this.CacheInitialized)
|
|
404
|
+
return;
|
|
405
|
+
let cache = this.localStorage.getLocalItem(this.localStorageHttpCacheKey);
|
|
406
|
+
let tmp = /#cache(:?-(\d+))/gi.exec(url);
|
|
407
|
+
let cacheTime = tmp ? tmp[2] : null;
|
|
408
|
+
let normalizedUrl_tmp = url.replace("#cache" + (cacheTime ? "-" + cacheTime : ""), "");
|
|
409
|
+
let normalizedUrl = normalizedUrl_tmp.substring(normalizedUrl_tmp.indexOf('/api'));
|
|
410
|
+
if (!cache || !this.HTTP_INVALIDATION || !this.HTTP_INVALIDATION[normalizedUrl])
|
|
411
|
+
return;
|
|
412
|
+
let apisToInvalidate = this.HTTP_INVALIDATION[normalizedUrl];
|
|
413
|
+
if (!apisToInvalidate || apisToInvalidate.length == 0)
|
|
414
|
+
return;
|
|
415
|
+
let keysToRemove = [];
|
|
416
|
+
apisToInvalidate.forEach(api => {
|
|
417
|
+
let cacheKey = this.makeCacheKey(api, null);
|
|
418
|
+
for (let item in cache)
|
|
419
|
+
if (item.indexOf(cacheKey) != -1)
|
|
420
|
+
keysToRemove.push(item);
|
|
421
|
+
});
|
|
422
|
+
for (let i = 0; i < keysToRemove.length; i++) {
|
|
423
|
+
let k = keysToRemove[i];
|
|
424
|
+
this.log(this.loc("Invlalidating cache element") + " " + k);
|
|
425
|
+
delete cache[k];
|
|
426
|
+
}
|
|
427
|
+
this.localStorage.setItem(this.localStorageHttpCacheKey, cache);
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Finalizzazione di una chiamata
|
|
431
|
+
*
|
|
432
|
+
* @param {string} guid GUID collegato alla chiamata appena terminata
|
|
433
|
+
* @param {boolean} persistCacheIfIdle Effettua il persist della cache HTTP solo se non ci sono altre chiamate in corso, per evitare
|
|
434
|
+
* che mi cambi sotto l'oggetto di cache mentre sto salvando le informazioni
|
|
435
|
+
*/
|
|
436
|
+
async tryFinalizeByGuid(guid, cacheInfos) {
|
|
437
|
+
this.log(this.loc("Finalizing call") + " " + guid + " " + this.loc("with status") + ": " + (!this.callStatus[guid] ? 'Unknown' : this.callStatus[guid].success ? this.loc('Success') : this.loc('Failure')));
|
|
438
|
+
// TODO: Perdere 3-4 ore per capire perché ogni tanto arriva null in casi pesanti di Observable spammati a random
|
|
439
|
+
if (this.callStatus[guid]) {
|
|
440
|
+
// Alla prima chiamata buona, significa che almeno il login ce l'ho. Posso mettermi in modalità redirectInProgress false
|
|
441
|
+
// e riiniziare a valutare errori di javashit
|
|
442
|
+
if (this.callStatus[guid].success && this.ExtensionsImpl.readRedirectionStatus())
|
|
443
|
+
this.ExtensionsImpl.writeRedirectionStatus(false);
|
|
444
|
+
// Aggiungo la chiamata alla lista delle ultime 3 completate
|
|
445
|
+
this.LastThreeCompletedCalls.unshift(this.callStatus[guid].url);
|
|
446
|
+
if (this.LastThreeCompletedCalls.length > 3)
|
|
447
|
+
this.LastThreeCompletedCalls.pop();
|
|
448
|
+
// In ogni caso questa posso rimuoverla
|
|
449
|
+
delete this.callStatus[guid];
|
|
450
|
+
}
|
|
451
|
+
// Se non ho nessun'altra chiamata in corso considero la situazione stabilizzatasi
|
|
452
|
+
if (Object.keys(this.callStatus).length == 0)
|
|
453
|
+
this.Stabilized.next(true);
|
|
454
|
+
// Se vengo da una chiamata che ha aggiornato la cache a timer o globale marco il fatto che quella cache dev'essere aggiornata
|
|
455
|
+
if (cacheInfos && cacheInfos.cache) {
|
|
456
|
+
this.PersistTimedCacheASAP = this.PersistTimedCacheASAP || !!cacheInfos.cacheTime;
|
|
457
|
+
this.PersistUntimedCacheASAP = this.PersistTimedCacheASAP || !cacheInfos.cacheTime;
|
|
458
|
+
this.log(this.loc("Marking cache to be persisted as soon as possible"));
|
|
459
|
+
}
|
|
460
|
+
// Se una delle due cache devono essere aggiornate e non ho nessuna chiamata in corso effettuo l'aggiornamento in base a quale delle due va aggiornata
|
|
461
|
+
// Alla fine di tutto marco come fatto
|
|
462
|
+
if ((this.PersistTimedCacheASAP || this.PersistUntimedCacheASAP) && Object.keys(this.callStatus).length == 0 && this.CacheInitialized) {
|
|
463
|
+
var toCall = [];
|
|
464
|
+
let tmpKey = "";
|
|
465
|
+
if (this.PersistTimedCacheASAP) {
|
|
466
|
+
tmpKey = this.localStorageHttpTimedCacheKey;
|
|
467
|
+
toCall.push(this.localStorage.setItem(tmpKey, this.localStorage.getLocalItem(tmpKey)));
|
|
468
|
+
}
|
|
469
|
+
if (this.PersistUntimedCacheASAP) {
|
|
470
|
+
tmpKey = this.localStorageHttpCacheKey;
|
|
471
|
+
toCall.push(this.localStorage.setItem(tmpKey, this.localStorage.getLocalItem(tmpKey)));
|
|
472
|
+
}
|
|
473
|
+
this.log(this.loc("No more HTTP calls to be executed, entering idle state and persisting modified caches") + "...");
|
|
474
|
+
var ret = await forkJoin(toCall).toPromise();
|
|
475
|
+
if (ret)
|
|
476
|
+
this.log(this.loc("Caches succesfully persisted"));
|
|
477
|
+
else
|
|
478
|
+
this.log(this.loc("Errors persisting modified caches"));
|
|
479
|
+
this.PersistTimedCacheASAP = false;
|
|
480
|
+
this.PersistUntimedCacheASAP = false;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Helper che dato un unico File o una lista di File crea un oggetto FormData che può essere inviato comodamente
|
|
485
|
+
* ad un backend ASP.NET da cui si potrà accedere a Request.Form.Files
|
|
486
|
+
*
|
|
487
|
+
* @param {File | File[]} fileArrayOrFile Singolo File o lista di File. N.B: nella firma della funzione viene considerato **any** per fare test sulle proprietà
|
|
488
|
+
* invece che fare test con l'**istanceof**
|
|
489
|
+
*
|
|
490
|
+
* @returns {FormData} FormData contenente tutti i file passati
|
|
491
|
+
*/
|
|
492
|
+
getFilesFormData(fileArrayOrFile) {
|
|
493
|
+
var formData = new FormData();
|
|
494
|
+
if (fileArrayOrFile) {
|
|
495
|
+
if (fileArrayOrFile.length)
|
|
496
|
+
fileArrayOrFile.forEach(t => { formData.append("file", t, t.name); });
|
|
497
|
+
else if (fileArrayOrFile.name)
|
|
498
|
+
formData.append("files", fileArrayOrFile, fileArrayOrFile.name);
|
|
499
|
+
}
|
|
500
|
+
return formData;
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Helper che in base ai parametri disponibili genera gli Header HTTP per la chiamata da effettuare
|
|
504
|
+
*
|
|
505
|
+
* @param {string} contentType Indica se aggiungere agli header "Content-Type", valorizzato al valore del parametro
|
|
506
|
+
* @param {string} accept Indica se aggiungere agli header "Accept", valorizzato al valore del parametro
|
|
507
|
+
* @param {boolean} includeAuth Indica se aggiungere agli header "Authorization", valorizzato col token recuperato dall'hook **retrieveAccessToken** della classe di estensione
|
|
508
|
+
* @param {string} transactionId Indica se aggiungere agli header "X-TX-ID", valorizzato al valore del parametro
|
|
509
|
+
*
|
|
510
|
+
* @returns {HttpHeaders} Header generati in base ai parametri
|
|
511
|
+
*/
|
|
512
|
+
getHeaders(locale = 'it-IT', transactionId = "", includeAuth = true, contentType = "application/json", accept = "application/json") {
|
|
513
|
+
var headers = new HttpHeaders();
|
|
514
|
+
var authtoken = this.ExtensionsImpl.retrieveAccessToken();
|
|
515
|
+
headers = headers.append("ngsw-bypass", "");
|
|
516
|
+
if (contentType)
|
|
517
|
+
headers = headers.append("Content-Type", contentType);
|
|
518
|
+
if (transactionId)
|
|
519
|
+
headers = headers.append("X-TX-ID", transactionId);
|
|
520
|
+
if (authtoken && includeAuth)
|
|
521
|
+
headers = headers.append("Authorization", "Bearer " + authtoken);
|
|
522
|
+
if (accept)
|
|
523
|
+
headers = headers.append("Accept", accept);
|
|
524
|
+
headers = headers.append("Accept-Language", locale);
|
|
525
|
+
return headers;
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Gestione di default degli errori
|
|
529
|
+
*
|
|
530
|
+
* @param {any} res Risultato della chiamata effettuata
|
|
531
|
+
* @param {string} guid Identificativo GUID della chiamata effettuata
|
|
532
|
+
*/
|
|
533
|
+
async onError(res, guid) {
|
|
534
|
+
if (this.callStatus[guid])
|
|
535
|
+
this.callStatus[guid].success = false;
|
|
536
|
+
//Mi assicuro che tutti gli errori durante il redirect al login vengano ignorati
|
|
537
|
+
if (this.ExtensionsImpl.readRedirectingToLogin()) {
|
|
538
|
+
this.log(this.loc("Redirecting to Login, ignoring HTTP error on call") + " " + guid);
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
//Mi assicuro che venga gestito un solo errore per volta
|
|
542
|
+
if (this.ExtensionsImpl.readHandlingErrorStatus()) {
|
|
543
|
+
this.log(this.loc("Already Handling an error, ignoring HTTP error on call") + " " + guid);
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
546
|
+
else
|
|
547
|
+
this.ExtensionsImpl.writeHandlingErrorStatus(true);
|
|
548
|
+
let finalError = "";
|
|
549
|
+
let finalStatus = "";
|
|
550
|
+
if (this.isTypeError(res)) {
|
|
551
|
+
finalError = res.message;
|
|
552
|
+
finalStatus = "HTTP Service Internal Error";
|
|
553
|
+
}
|
|
554
|
+
else if (this.isHttpErrorResponse(res)) {
|
|
555
|
+
finalError = await this.getHttpErrorText(res.error);
|
|
556
|
+
finalStatus = res.status.toString();
|
|
557
|
+
switch (res.status) {
|
|
558
|
+
// Unauthorized
|
|
559
|
+
case 401:
|
|
560
|
+
if (this.ExtensionsImpl.readRedirectionStatus()) {
|
|
561
|
+
this.log(this.loc("Error 401 on call") + " " + guid + " " + this.loc("with redirect already in progress. Ignoring this event"));
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
this.log(this.loc("Error 401 on call") + " " + guid + " " + this.loc("redirecting to login."));
|
|
565
|
+
this.ExtensionsImpl.writeRedirectionStatus(true);
|
|
566
|
+
this.ExtensionsImpl.writeRedirectingToLogin(true);
|
|
567
|
+
this.ExtensionsImpl.redirectToLogin();
|
|
568
|
+
return;
|
|
569
|
+
// Handled exception
|
|
570
|
+
case 400:
|
|
571
|
+
// No Permissions
|
|
572
|
+
case 403:
|
|
573
|
+
this.ExtensionsImpl.handleBlockingException(res.status, finalError);
|
|
574
|
+
return;
|
|
575
|
+
// Not found
|
|
576
|
+
case 404:
|
|
577
|
+
this.ExtensionsImpl.handleBlockingException(res.status, this.loc("Resource not found"));
|
|
578
|
+
return;
|
|
579
|
+
// NotConfiguredException
|
|
580
|
+
case 444:
|
|
581
|
+
if (this.ExtensionsImpl.readRedirectionStatus())
|
|
582
|
+
this.log(this.loc("Error 444 on call") + " " + guid + " " + this.loc("with redirect already in progress. Ignoring this event"));
|
|
583
|
+
else if (!this.ExtensionsImpl.handleNotConfiguredException())
|
|
584
|
+
this.ExtensionsImpl.handleBlockingException(res.status, finalError);
|
|
585
|
+
return;
|
|
586
|
+
case 0:
|
|
587
|
+
finalError = `Generic connection error while calling '[${guid}] - ${this.callStatus[guid].url}' at ${dayjs().format()}. Response: ${JSON.stringify(res)}`;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
this.ExtensionsImpl.handleException(finalStatus, finalError);
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* Dato un errore restituisce una promise con la stringa finale dell'errore in modo da poter fare un await
|
|
594
|
+
*
|
|
595
|
+
* @param {any} err Errore da controllare
|
|
596
|
+
*
|
|
597
|
+
* @returns {Promise<string>} Promise che risolve con la stringa finale dell'errore
|
|
598
|
+
*/
|
|
599
|
+
getHttpErrorText(err) {
|
|
600
|
+
// Se ho un Blob può essere o un CallResult o suppongo una semplice stringa,
|
|
601
|
+
// altrimenti potrebbe essere direttamente un CallResult, oppure una semplice stringa
|
|
602
|
+
return new Promise((resolve) => {
|
|
603
|
+
if (err instanceof Blob) {
|
|
604
|
+
let reader = new FileReader();
|
|
605
|
+
reader.onload = (e) => {
|
|
606
|
+
let errMsg = e.target.result;
|
|
607
|
+
let jsonerrMsg;
|
|
608
|
+
try {
|
|
609
|
+
jsonerrMsg = JSON.parse(errMsg);
|
|
610
|
+
}
|
|
611
|
+
catch (e) { }
|
|
612
|
+
return resolve(jsonerrMsg && this.isCallResult(jsonerrMsg) ? jsonerrMsg.error.message : errMsg);
|
|
613
|
+
};
|
|
614
|
+
reader.readAsText(err);
|
|
615
|
+
}
|
|
616
|
+
else if (this.isCallResult(err))
|
|
617
|
+
return resolve(err.error.message);
|
|
618
|
+
else
|
|
619
|
+
return resolve(err?.toString());
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* Riconosce se l'oggetto è di tipo **CallResult** e, se sì, lo casta al tipo corretto per essere utilizzato correttamente nel blocco di codice successivo
|
|
624
|
+
*
|
|
625
|
+
* @param {any} err Errore da controllare
|
|
626
|
+
*/
|
|
627
|
+
isCallResult(err) {
|
|
628
|
+
return !!err?.error?.message;
|
|
629
|
+
}
|
|
630
|
+
/**
|
|
631
|
+
* Riconosce se l'errore è di tipo **HttpErrorResponse** e, se sì, lo casta al tipo corretto per essere utilizzato correttamente nel blocco di codice successivo
|
|
632
|
+
*
|
|
633
|
+
* @param {any} err Errore da controllare
|
|
634
|
+
*/
|
|
635
|
+
isHttpErrorResponse(err) {
|
|
636
|
+
return err instanceof HttpErrorResponse;
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* Riconosce se l'errore è di tipo **TypeError** e, se sì, lo casta al tipo corretto per essere utilizzato correttamente nel blocco di codice successivo
|
|
640
|
+
*
|
|
641
|
+
* @param {any} err Errore da controllare
|
|
642
|
+
*/
|
|
643
|
+
isTypeError(err) {
|
|
644
|
+
return err.name == "TypeError";
|
|
645
|
+
}
|
|
646
|
+
/**
|
|
647
|
+
* Come dice il nome, registra un errore e restituisce un Observable vuoto come risultato della chiamata
|
|
648
|
+
*
|
|
649
|
+
* @param {any} res Risultato della chiamata effettuata
|
|
650
|
+
* @param {string} guid Identificativo GUID della chiamata effettuata
|
|
651
|
+
* @param {boolean} handleError Indica se gestire l'errore via libreria o se limitarsi a restituire l'Observable vuoto
|
|
652
|
+
*
|
|
653
|
+
* @returns {Observable<any>} Observable vuoto
|
|
654
|
+
*/
|
|
655
|
+
registerErrorAndReturnEmptyObservable(res, guid, handleError = true) {
|
|
656
|
+
if (handleError)
|
|
657
|
+
this.onError(res, guid);
|
|
658
|
+
return new Observable(() => { });
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Dato un Url e dei parametri cerca di recuperare l'eventuale oggetto già salvato in cache con le informazioni base della cache stessa
|
|
662
|
+
*
|
|
663
|
+
* @param {string} url URL su cui effettuare la chiamata
|
|
664
|
+
* @param {HttpParams} params Parametri della chiamata (nulli in caso di POST)
|
|
665
|
+
*
|
|
666
|
+
* @returns {CacheInfos} Oggetto contenente le informazioni sulla cache per l'oggetto specificato
|
|
667
|
+
*/
|
|
668
|
+
tryGetCacheInformations(url, params) {
|
|
669
|
+
let cachingKey = null, cacheTime = null, item = null;
|
|
670
|
+
let useCaching = !!(/#cache/gi.exec(url));
|
|
671
|
+
if (useCaching && this.CacheInitialized) {
|
|
672
|
+
let tmp = /#cache(:?-(\d+))/gi.exec(url);
|
|
673
|
+
cacheTime = tmp ? tmp[2] : null;
|
|
674
|
+
url = url.replace("#cache" + (cacheTime ? "-" + cacheTime : ""), "");
|
|
675
|
+
if (this.untimedCacheExpired() && !cacheTime)
|
|
676
|
+
this.resetHttpUntimedCacheStorage();
|
|
677
|
+
cachingKey = this.makeCacheKey(url, params);
|
|
678
|
+
let cacheKey = cacheTime ? this.localStorageHttpTimedCacheKey : this.localStorageHttpCacheKey;
|
|
679
|
+
let cacheLs = this.localStorage.getLocalItem(cacheKey);
|
|
680
|
+
let cache = cacheLs ? cacheLs : {};
|
|
681
|
+
if (cache && cache[cachingKey] && !this.timedCacheItemExpired(cache[cachingKey])) {
|
|
682
|
+
// Se gestisco il tempo esatto della cache prima di restituire l'oggetto cachato lo ripulisco
|
|
683
|
+
// dalle proprietà interne che gli ho aggiunto per controllarne la scadenza
|
|
684
|
+
if (cacheTime)
|
|
685
|
+
delete cache[cachingKey].__expire;
|
|
686
|
+
item = cache[cachingKey];
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
// Per assicurarmi che il rifeirmento degli oggetti sia diverso utilizzo il deepClone
|
|
690
|
+
return new CacheInfos(url, useCaching && this.CacheInitialized, cachingKey, cacheTime, this.utisExts.deepClone(item));
|
|
691
|
+
}
|
|
692
|
+
/**
|
|
693
|
+
* Inserisce un oggetto nella cache appropriata in base alle informazioni contenute nel parametro **cacheInfos**
|
|
694
|
+
*
|
|
695
|
+
* @param {T} item Oggetto da inserire nella cache
|
|
696
|
+
* @param {CacheInfos} cacheInfos Informazioni sulla cache recuperate da una chiamata precedente a **tryGetCacheInformations**
|
|
697
|
+
*/
|
|
698
|
+
cacheResponse(item, cacheInfos) {
|
|
699
|
+
let cacheKey = cacheInfos.cacheTime ? this.localStorageHttpTimedCacheKey : this.localStorageHttpCacheKey;
|
|
700
|
+
let cacheLs = this.localStorage.getLocalItem(cacheKey);
|
|
701
|
+
let cache = cacheLs ? cacheLs : {};
|
|
702
|
+
cache[cacheInfos.cacheKey] = item;
|
|
703
|
+
if (cacheInfos.cacheTime)
|
|
704
|
+
cache[cacheInfos.cacheKey].__expire = dayjs().add(cacheInfos.cacheTime, "seconds");
|
|
705
|
+
this.localStorage.setLocalItem(cacheKey, cache);
|
|
706
|
+
}
|
|
707
|
+
/**
|
|
708
|
+
* Controlla se la cache per le chiamate senza expire time è scaduta
|
|
709
|
+
*
|
|
710
|
+
* @returns {boolean} **true** se la cache è scaduta e dev'essere ripulita, **false** altrimenti
|
|
711
|
+
*/
|
|
712
|
+
untimedCacheExpired() {
|
|
713
|
+
let expire = JSON.parse(localStorage.getItem(this.localStorageHttpCacheExpireKey));
|
|
714
|
+
return !expire || expire && dayjs(expire) < dayjs();
|
|
715
|
+
}
|
|
716
|
+
/**
|
|
717
|
+
* Controlla se la cache per una chiamata che ha un tempo di vita ben definito è scaduta o meno
|
|
718
|
+
*
|
|
719
|
+
* @param {any} item Oggetto recuperato dalla cache a cui ho aggiunto la chiave interna __expire
|
|
720
|
+
*
|
|
721
|
+
* @returns {boolean} **true** se la cache è scaduta e dev'essere ripulita, **false** altrimenti
|
|
722
|
+
*/
|
|
723
|
+
timedCacheItemExpired(item) {
|
|
724
|
+
return dayjs(item.__expire) < dayjs();
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* Ripulisce la cache e imposta la prossima scadenza ad adesso + **CLIENT_CACHE_DURATION_S** (token valorizzato in fase di configurazione dalla proprietà **clientCacheDurationS** della classe **HttpServiceModuleConfig**)
|
|
728
|
+
*/
|
|
729
|
+
async resetHttpUntimedCacheStorage() {
|
|
730
|
+
if (!this.CacheInitialized)
|
|
731
|
+
return;
|
|
732
|
+
await this.localStorage.setItem(this.localStorageHttpCacheKey, {}).toPromise();
|
|
733
|
+
localStorage.setItem(this.localStorageHttpCacheExpireKey, JSON.stringify(dayjs().add(this.CLIENT_CACHE_DURATION_S, "second")));
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* Ripulisce la cache delle chiamate con un tempo di expire definito
|
|
737
|
+
*/
|
|
738
|
+
async resetHttpTimedCacheStorage() {
|
|
739
|
+
if (!this.CacheInitialized)
|
|
740
|
+
return;
|
|
741
|
+
await this.localStorage.setItem(this.localStorageHttpTimedCacheKey, {}).toPromise();
|
|
742
|
+
}
|
|
743
|
+
/**
|
|
744
|
+
* Genera una chiave per la cache delle chiamate in base ad URL e Parametri HTTP
|
|
745
|
+
*
|
|
746
|
+
* @param {string} url URL su cui effettuare la chiamata
|
|
747
|
+
* @param {HttpParams} params Parametri della chiamata
|
|
748
|
+
*
|
|
749
|
+
* @returns {string} Chiave che rappresenta in maniera univoca la chiamata
|
|
750
|
+
*/
|
|
751
|
+
makeCacheKey(url, params) {
|
|
752
|
+
this.me = this.me || this.ExtensionsImpl.retrieveIdentity();
|
|
753
|
+
let authKeyPart = (this.me ? this.me.Idtenant : "") + (this.me && this.CACHE_BY_USER ? this.me.IdUser : "");
|
|
754
|
+
let paramsKeyPart = params && params.keys().length > 0 ? params.keys().reduce((prev, next) => prev + "," + next + '=' + params.get(next), "") : "";
|
|
755
|
+
return authKeyPart + "_" + url.substring(url.indexOf("api") + 4) + "?" + paramsKeyPart;
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* Generazione GUID
|
|
759
|
+
*
|
|
760
|
+
* @returns {string} Nuovo GUID generato in maniera casuale
|
|
761
|
+
*/
|
|
762
|
+
getGUID() {
|
|
763
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
|
764
|
+
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
|
|
765
|
+
return v.toString(16);
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
/**
|
|
769
|
+
* Metodo per scrivere log a console qualora **DEBUG_MODE** risultasse **true**
|
|
770
|
+
*
|
|
771
|
+
* @param {string} message Messaggio di log
|
|
772
|
+
*/
|
|
773
|
+
log(message) {
|
|
774
|
+
if (this.HTTP_DEBUG_MODE)
|
|
775
|
+
console.log("@httpservice: " + message);
|
|
776
|
+
}
|
|
777
|
+
/**
|
|
778
|
+
* Helper per la localizzazione dei messaggi
|
|
779
|
+
*
|
|
780
|
+
* @param {string} message Messaggio da localizzare
|
|
781
|
+
*
|
|
782
|
+
* @returns {string} Messaggio localizzato
|
|
783
|
+
*/
|
|
784
|
+
loc(message) {
|
|
785
|
+
// Togliamo velocemente ste localizzazioni inutili....
|
|
786
|
+
return message;
|
|
787
|
+
}
|
|
788
|
+
/**
|
|
789
|
+
* Helper per lanciare la selezione di tutto quello che è relativo a un api di ricerca con AppSearch (di cui non utilizzo il tipo vero per ridurre le dipendenze)
|
|
790
|
+
*/
|
|
791
|
+
getAll(view, api, pars, transaction) {
|
|
792
|
+
if (!view.selection.all)
|
|
793
|
+
return of(view.selection.items);
|
|
794
|
+
var jsonView = this.utisExts.deepClone(view);
|
|
795
|
+
jsonView.page = 1;
|
|
796
|
+
jsonView.itemsperpageoverride = 999999;
|
|
797
|
+
return this.post(api, jsonView, pars, transaction).pipe(map(res => {
|
|
798
|
+
let items = res.items;
|
|
799
|
+
items.forEach(t => t.hash = this.hash.hashObject(t, null, false));
|
|
800
|
+
if (res.selection.exclusions?.length > 0)
|
|
801
|
+
items = items.filter((t) => !res.selection.exclusions.find((e) => this.hash.hashObject(e, null, false) == t.hash));
|
|
802
|
+
return items;
|
|
803
|
+
}));
|
|
804
|
+
}
|
|
805
|
+
beginTransaction(executionKey, secondsTimeout) {
|
|
806
|
+
this.log("beginTransaction call received: " + executionKey);
|
|
807
|
+
var pars = new HttpParams().set("executionKey", executionKey);
|
|
808
|
+
if (secondsTimeout)
|
|
809
|
+
pars = pars.set("secondsTimeout", secondsTimeout.toString());
|
|
810
|
+
return this.get(this.GET_Trans_BeginTrans, pars);
|
|
811
|
+
}
|
|
812
|
+
checkTransaction(executionKey) {
|
|
813
|
+
this.log("checkTransaction call received: " + executionKey);
|
|
814
|
+
return this.get(this.GET_Trans_CheckExecution, new HttpParams().set("executionKey", executionKey));
|
|
815
|
+
}
|
|
816
|
+
endTransaction(transactionKey, transactionResult) {
|
|
817
|
+
this.log("endTransaction call received: " + transactionKey + " Commit: " + transactionResult);
|
|
818
|
+
let pars = new HttpParams().set("idtrans", transactionKey).set("success", transactionResult.toString());
|
|
819
|
+
return this.get(this.GET_Trans_EndTrans, pars);
|
|
820
|
+
}
|
|
821
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HTTPService, deps: [{ token: i1.HttpServiceExtensions }, { token: HTTP_INVALIDATION, optional: true }, { token: CLIENT_CACHE_DURATION_S }, { token: CACHE_BY_USER }, { token: HTTP_DEBUG_MODE }, { token: i2.BaseLocalization }, { token: i3.HttpClient }, { token: i4.CacheService }, { token: i5.HashingService }, { token: i5.UtilityService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
822
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HTTPService, providedIn: 'root' }); }
|
|
823
|
+
}
|
|
824
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HTTPService, decorators: [{
|
|
825
|
+
type: Injectable,
|
|
826
|
+
args: [{ providedIn: 'root' }]
|
|
827
|
+
}], ctorParameters: () => [{ type: i1.HttpServiceExtensions }, { type: undefined, decorators: [{
|
|
828
|
+
type: Optional
|
|
829
|
+
}, {
|
|
830
|
+
type: Inject,
|
|
831
|
+
args: [HTTP_INVALIDATION]
|
|
832
|
+
}] }, { type: undefined, decorators: [{
|
|
833
|
+
type: Inject,
|
|
834
|
+
args: [CLIENT_CACHE_DURATION_S]
|
|
835
|
+
}] }, { type: undefined, decorators: [{
|
|
836
|
+
type: Inject,
|
|
837
|
+
args: [CACHE_BY_USER]
|
|
838
|
+
}] }, { type: undefined, decorators: [{
|
|
839
|
+
type: Inject,
|
|
840
|
+
args: [HTTP_DEBUG_MODE]
|
|
841
|
+
}] }, { type: i2.BaseLocalization }, { type: i3.HttpClient }, { type: i4.CacheService }, { type: i5.HashingService }, { type: i5.UtilityService }] });
|
|
842
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHR0cHNlcnZpY2Uuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL2h0dHBzZXJ2aWNlL3NyYy9saWIvaHR0cHNlcnZpY2Uuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxVQUFVO0FBQ1YsT0FBTyxFQUFjLGlCQUFpQixFQUFhLGFBQWEsRUFBRSxXQUFXLEVBQUUsVUFBVSxFQUFtQyxNQUFNLHNCQUFzQixDQUFDO0FBQ3pKLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQU83RCxrQ0FBa0M7QUFDbEMsT0FBTyxFQUFFLFVBQVUsRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzFGLE9BQU8sRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLFVBQVUsRUFBRSxFQUFFLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUUzRSxrQ0FBa0M7QUFDbEMsT0FBTyxFQUFFLGlCQUFpQixFQUFFLHVCQUF1QixFQUFFLGFBQWEsRUFBRSxlQUFlLEVBQUUsTUFBTSxVQUFVLENBQUM7QUFFdEcsV0FBVztBQUNYLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBRXZFLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQzs7Ozs7OztBQVFqRDs7O0dBR0c7QUFFSCxNQUFNLE9BQU8sV0FBVztJQThCdEI7O09BRUc7SUFDSCxZQUNVLGVBQXNDLEVBQ0MsaUJBQWlCLEVBQ3ZCLHVCQUF1QixFQUNqQyxhQUFzQixFQUNwQixlQUF3QixFQUNqRCxFQUFvQixFQUNwQixJQUFnQixFQUNoQixZQUEwQixFQUMxQixJQUFvQixFQUNwQixRQUF3QjtRQVR4QixvQkFBZSxHQUFmLGVBQWUs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Qjs7MEJBQ3BDLE1BQU07MkJBQUMsdUJBQXVCOzswQkFDOUIsTUFBTTsyQkFBQyxhQUFhOzswQkFDcEIsTUFBTTsyQkFBQyxlQUFlIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQW5ndWxhclxyXG5pbXBvcnQgeyBIdHRwQ2xpZW50LCBIdHRwRXJyb3JSZXNwb25zZSwgSHR0cEV2ZW50LCBIdHRwRXZlbnRUeXBlLCBIdHRwSGVhZGVycywgSHR0cFBhcmFtcywgSHR0cFByb2dyZXNzRXZlbnQsIEh0dHBSZXNwb25zZSB9IGZyb20gXCJAYW5ndWxhci9jb21tb24vaHR0cFwiO1xyXG5pbXBvcnQgeyBJbmplY3RhYmxlLCBJbmplY3QsIE9wdGlvbmFsIH0gZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcclxuXHJcbi8vIEVzIEZhZW56YVxyXG5pbXBvcnQgeyBDYWNoZVNlcnZpY2UgfSBmcm9tIFwiQGVzZmFlbnphL3ByZWZlcmVuY2VzXCI7XHJcbmltcG9ydCB7IEhhc2hpbmdTZXJ2aWNlLCBVdGlsaXR5U2VydmljZSB9IGZyb20gXCJAZXNmYWVuemEvZXh0ZW5zaW9uc1wiO1xyXG5pbXBvcnQgeyBCYXNlTG9jYWxpemF0aW9uIH0gZnJvbSBcIkBlc2ZhZW56YS9sb2NhbGl6YXRpb25zXCI7XHJcblxyXG4vLyBEaXJldHRpdmUsIENvbXBvbmVudGksIExpYnJlcmllXHJcbmltcG9ydCB7IGNhdGNoRXJyb3IsIGNvbmNhdE1hcCwgZGVsYXksIGZpbmFsaXplLCBmaXJzdCwgbWFwLCBzY2FuIH0gZnJvbSBcInJ4anMvb3BlcmF0b3JzXCI7XHJcbmltcG9ydCB7IGZvcmtKb2luLCBmcm9tLCBPYnNlcnZhYmxlLCBvZiwgU3ViamVjdCwgdGhyb3dFcnJvciB9IGZyb20gXCJyeGpzXCI7XHJcblxyXG4vLyBDaGlhbWF0ZSBhaSBSZXBvc2l0b3J5IC8gdG9rZW5zXHJcbmltcG9ydCB7IEhUVFBfSU5WQUxJREFUSU9OLCBDTElFTlRfQ0FDSEVfRFVSQVRJT05fUywgQ0FDSEVfQllfVVNFUiwgSFRUUF9ERUJVR19NT0RFIH0gZnJvbSAnLi90b2tlbnMnO1xyXG5cclxuLy8gTW9kZWxsaSBcclxuaW1wb3J0IHsgSHR0cFNlcnZpY2VFeHRlbnNpb25zIH0gZnJvbSAnLi9jb25maWcvSHR0cFNlcnZpY2VFeHRlbnNpb25zJztcclxuaW1wb3J0IHsgRG93bmxvYWQgfSBmcm9tICcuL21vZGVscy9Eb3dubG9hZCc7XHJcbmltcG9ydCB7IENhY2hlSW5mb3MgfSBmcm9tIFwiLi9tb2RlbHMvQ2FjaGVJbmZvc1wiO1xyXG5cclxuLyoqXHJcbiAqIERpY2hpYXJhemlvbmUgZGVsbGEgdmFyaWFiaWxlIGdsb2JhbGUgZGF5anMuIEwnb25lcmUgZGkgXCJjcmVhcmxhXCIgw6ggYWZmaWRhdG8gYWxsJ2FwcGxpY2F6aW9uZSBjaGUgdXRpbGl6emEgcXVlc3RhIGxpYnJlcmlhLCBcclxuICogY2hlIGRvdnLDoCBpbXBvcnRhcmUgbG8gc2NyaXB0IGdsb2JhbGUgZGkgZGF5anMgbmVsbGEgQ0xJXHJcbiAqL1xyXG5kZWNsYXJlIHZhciBkYXlqczogYW55O1xyXG5cclxuLyoqXHJcbiAqIFNlcnZpemlvIHV0aWxpenphdG8gcGVyIGVmZmV0dHVhcmUgcXVhbHNpYXNpIHRpcG8gZGkgY2hpYW1hdGEgSFRUUCBkYWxsJ2FwcGxpY2F6aW9uZSwgZ2VzdGlzY2UgZXJyb3JpIGUgY2FjaGUgZGVsbGUgcmlzcG9zdGUgbmF0aXZhbWVudGUgZSBuZSBwdcOyIGVzc2VyZSBcclxuICogZXN0ZXNvL21vZGlmaWNhdG8gaWwgY29tcG9ydGFtZW50byBpbXBsZW1lbnRhbmRvIGxhIGNsYXNzZSBkaSBcImhvb2tcIiAqKklIdHRwU2VydmljZUV4dGVuc2lvbnMqKiBlIHJlZ2lzdHJhbmRvbGEgbmVsIHByb3ZpZGVyIGRlbGxhIGNsYXNzZSAqKkh0dHBTZXJ2aWNlRXh0ZW5zaW9ucyoqXHJcbiAqL1xyXG5ASW5qZWN0YWJsZSh7IHByb3ZpZGVkSW46ICdyb290JyB9KVxyXG5leHBvcnQgY2xhc3MgSFRUUFNlcnZpY2Uge1xyXG5cclxuICAvKiogQ2FjaGUgZGVsbG8gc3RhdG8gZGVsbGUgY2hpYW1hdGUgSFRUUCBhdHR1YWxtZW50ZSBlZmZldHR1YXRlLiBPZ25pIGNoaWFtYXRhIMOoIHJhcHByZXNlbnRhdGEgZGEgdW4gR1VJRCBlIGxvIHN0YXR1cyBhc3N1bWUgdmFsb3JlICoqZmFsc2UqKiBzb2xvIHN1Z2xpIGVycm9yaSAqL1xyXG4gIHByaXZhdGUgY2FsbFN0YXR1czogeyBbaWQ6IHN0cmluZ106IHsgdXJsOiBzdHJpbmcsIHN1Y2Nlc3M6IGJvb2xlYW4gfSB9ID0ge307XHJcbiAgLyoqIE5vbWUgZGVsbGEgY2FjaGUgaW4gY3VpIHZlbmdvbm8gc3RvcmljaXp6YXRlIGxlIGluZm9ybWF6aW9uaSBzdWxsZSByaXNwb3N0ZSBkZWxsZSBjaGlhbWF0ZSBzb3R0byBmb3JtYSBkaSBkaWN0aW9uYXJ5ICovXHJcbiAgcHJpdmF0ZSBsb2NhbFN0b3JhZ2VIdHRwQ2FjaGVLZXkgPSBudWxsO1xyXG4gIC8qKiBOb21lIGRlbGxhIGNhY2hlIGluIGN1aSB2ZW5nb25vIHN0b3JpY2l6emF0ZSBsZSBpbmZvcm1hemlvbmkgc3VsbGUgcmlzcG9zdGUgZGVsbGUgY2hpYW1hdGUgc290dG8gZm9ybWEgZGkgZGljdGlvbmFyeSwgc29sbyBwZXIgbGUgY2hpYW1hdGUgY29uIHVuIHRlbXBvIGRlZmluaXRvIGRpIGNhY2hpbmcgKi9cclxuICBwcml2YXRlIGxvY2FsU3RvcmFnZUh0dHBUaW1lZENhY2hlS2V5ID0gbnVsbDtcclxuICAvKiogTm9tZSBkZWxsYSBjYWNoZSBpbiBjdWkgdmVuZ29ubyBzdG9yaWNpenphdGUgbGUgaW5mb3JtYXppb25pIHN1bGxvIHNjYWRlcmUgZGVsbGEgY2FjaGUgc3Rlc3NhICovXHJcbiAgcHJpdmF0ZSBsb2NhbFN0b3JhZ2VIdHRwQ2FjaGVFeHBpcmVLZXkgPSBudWxsO1xyXG4gIC8qKiBJZGVudGl0w6AgY29sbGVnYXRhIGFsIHRva2VuIGRpIGF1dGVudGljYXppb25lIGRhIHVzYXJlLCByaWNoaWVzdGEgYWwgcHJvZ3JhbW1hIGNoZSB1dGlsaXp6YSBsYSBsaWJyZXJpYSBhdHRyYXZlcnNvIGwnaG9vayAqKnJldHJpZXZlSWRlbnRpdHkqKiBkZWxsYSAqKkh0dHBTZXJ2aWNlRXh0ZW5zaW9ucyoqICovXHJcbiAgcHJpdmF0ZSBtZTogeyBJZHRlbmFudDogc3RyaW5nLCBJZFVzZXI6IHN0cmluZyB9ID0gbnVsbDtcclxuICAvKiogSW5kaWNhIGNoZSBsYSBjYWNoZSBhIHRlbXBvIGRldidlc3NlcmUgcGVyc2lzdGl0YSBpbCBwcmltYSBwb3NzaWJpbGUgKi9cclxuICBwcml2YXRlIFBlcnNpc3RUaW1lZENhY2hlQVNBUDogYm9vbGVhbiA9IGZhbHNlO1xyXG4gIC8qKiBJbmRpY2EgY2hlIGxhIGNhY2hlIHNlbnphIGxpbWl0aSBkaSB0ZW1wbyBkZXYnZXNzZXJlIHBlcnNpc3RpdGEgaWwgcHJpbWEgcG9zc2liaWxlICovXHJcbiAgcHJpdmF0ZSBQZXJzaXN0VW50aW1lZENhY2hlQVNBUDogYm9vbGVhbiA9IGZhbHNlO1xyXG4gIC8qKiBTdWJqZWN0IGVtZXNzbyBxdWFuZG8gaWwgc2Vydml6aW8gaHR0cCBzaSBzdGFiaWxpenphLCBjaW/DqCBxdWFuZG8gbm9uIGMnw6ggbmVzc3VuYSBjaGlhbWF0YSBwZW5kaW5nIG8gaW4gY29yc28gZGEgcXVhbGNoZSBpc3RhbnRlICovXHJcbiAgcHVibGljIFN0YWJpbGl6ZWQ6IFN1YmplY3Q8dHJ1ZT4gPSBuZXcgU3ViamVjdDx0cnVlPigpO1xyXG5cclxuICAvKipcclxuICAgKiBJbXBsZW1lbnRhemlvbmUgZGVsbGEgY2xhc3NlIGRpIGVzdGVuc2lvbmUgcGVyIGNvbGxlZ2FyZSBpIGNvbXBvcnRhbWVudGkgZGVsbGEgbGlicmVyaWEgYWxsJ2FwcGxpY2F6aW9uZSBpbiBjdWkgw6ggdXNhdGEuIFxyXG4gICAqIFxyXG4gICAqIFNlIMOoIHN0YXRvIGVmZmV0dHVhdG8gaWwgcHJvdmlkZSBkZWxsYSBjbGFzc2UgKipIdHRwU2VydmljZUV4dGVuc2lvbnMqKiB2ZXJyw6AgdXNhdG8gcXVlbCBwcm92aWRlciwgYWx0cmltZW50aSB2ZXJyw6AgY3JlYXRhIHVuYSBudW92YSBpc3RhbnphIGRpIGRlZmF1bHRcclxuICAgKi9cclxuICBwcml2YXRlIEV4dGVuc2lvbnNJbXBsOiBIdHRwU2VydmljZUV4dGVuc2lvbnM7XHJcblxyXG4gIC8qKiBMaXN0YSBkZWxsZSB1bHRpbWUgMyBjaGlhbWF0ZSBjb21wbGV0YXRlIGNvbiBzdWNjZXNzbyBpbiBvcmRpbmUgZGkgY29tcGxldGFtZW50byAoaW4gcG9zaXppb25lIDAgYyfDqCBsJ3VsdGltYSBjb21wbGV0YXRhIGVjY2V0ZXJhLi4uKSAqL1xyXG4gIHB1YmxpYyBMYXN0VGhyZWVDb21wbGV0ZWRDYWxsczogc3RyaW5nW10gPSBbXTtcclxuXHJcbiAgcHJpdmF0ZSBDYWNoZUluaXRpYWxpemVkOiBib29sZWFuID0gZmFsc2U7XHJcbiAgLyoqXHJcbiAgICogQGlnbm9yZVxyXG4gICAqL1xyXG4gIGNvbnN0cnVjdG9yKFxyXG4gICAgcHJpdmF0ZSBFWFRFTlNJT05fQ0xBU1M6IEh0dHBTZXJ2aWNlRXh0ZW5zaW9ucyxcclxuICAgIEBPcHRpb25hbCgpIEBJbmplY3QoSFRUUF9JTlZBTElEQVRJT04pIHByaXZhdGUgSFRUUF9JTlZBTElEQVRJT04sXHJcbiAgICBASW5qZWN0KENMSUVOVF9DQUNIRV9EVVJBVElPTl9TKSBwcml2YXRlIENMSUVOVF9DQUNIRV9EVVJBVElPTl9TLFxyXG4gICAgQEluamVjdChDQUNIRV9CWV9VU0VSKSBwcml2YXRlIENBQ0hFX0JZX1VTRVI6IGJvb2xlYW4sXHJcbiAgICBASW5qZWN0KEhUVFBfREVCVUdfTU9ERSkgcHJpdmF0ZSBIVFRQX0RFQlVHX01PREU6IGJvb2xlYW4sXHJcbiAgICBwcml2YXRlIGJjOiBCYXNlTG9jYWxpemF0aW9uLFxyXG4gICAgcHJpdmF0ZSBodHRwOiBIdHRwQ2xpZW50LFxyXG4gICAgcHJpdmF0ZSBsb2NhbFN0b3JhZ2U6IENhY2hlU2VydmljZSxcclxuICAgIHByaXZhdGUgaGFzaDogSGFzaGluZ1NlcnZpY2UsXHJcbiAgICBwcml2YXRlIHV0aXNFeHRzOiBVdGlsaXR5U2VydmljZVxyXG4gICkge1xyXG4gICAgdGhpcy5FeHRlbnNpb25zSW1wbCA9IHRoaXMuRVhURU5TSU9OX0NMQVNTIHx8IG5ldyBIdHRwU2VydmljZUV4dGVuc2lvbnMoKTtcclxuICB9XHJcblxyXG4gIHB1YmxpYyBzZXRBcHBDb25maWcobXljb25maWc6IHsgQXBwRGF0YTogeyBNb2R1bGVJZDogc3RyaW5nLCBNb2R1bGVEZWZJZDogbnVtYmVyLCBDb21wb25lbnRFbnZpcm9ubWVudDogc3RyaW5nLCBDb21wb25lbnRWZXJzaW9uOiBzdHJpbmcsIE1vZHVsZURlc2NyaXB0aW9uOiBzdHJpbmcgfSB9KXtcclxuICAgIHRoaXMubG9jYWxTdG9yYWdlSHR0cENhY2hlS2V5ID0gKG15Y29uZmlnLkFwcERhdGEuTW9kdWxlRGVzY3JpcHRpb24pLnJlcGxhY2UoL1xccy9nLCAnXycpICsgXCJfSHR0cENhY2hlXCI7XHJcbiAgICB0aGlzLmxvY2FsU3RvcmFnZUh0dHBUaW1lZENhY2hlS2V5ID0gKG15Y29uZmlnLkFwcERhdGEuTW9kdWxlRGVzY3JpcHRpb24pLnJlcGxhY2UoL1xccy9nLCAnXycpICsgXCJfSHR0cFRpbWVkQ2FjaGVcIjtcclxuICAgIHRoaXMubG9jYWxTdG9yYWdlSHR0cENhY2hlRXhwaXJlS2V5ID0gdGhpcy5sb2NhbFN0b3JhZ2VIdHRwQ2FjaGVLZXkgKyBcIl9FeHBpcmVcIjtcclxuICAgIHRoaXMuYWRqdXN0T2xkU3RvcmFnZVN5c3RlbSgpO1xyXG5cclxuICAgIHRoaXMuQ2FjaGVJbml0aWFsaXplZCA9IHRydWU7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBTZSB2ZWRvIGNoZSBjaSBzb25vIGVsZW1lbnRpIHNhbHZhdGkgbmVsIGxvY2FsU3RvcmFnZSBwcm92byBhIHRvZ2xpZXJsaSBlIGEgcmlzYWx2YXJsaSB2aWEgcHJlZmVyZW5jZS5cclxuICAgKiBOZWwgY2FzbyBtaWdsaW9yZSBsaSBzcG9zdG8gZGFsIGxvY2FsU3RvcmFnZSBhbCBEQiBkaSBwcmVmZXJlbmNlLCBuZWwgY2FzbyBwZWdnaW9yZSBsaSB0b2xnbyBlIGxpIHJpc2Fsdm8gbmVsIGxvY2FsU3RvcmFnZVxyXG4gICAqL1xyXG4gIHByaXZhdGUgYXN5bmMgYWRqdXN0T2xkU3RvcmFnZVN5c3RlbSgpIHtcclxuICAgIHZhciBsc1RpbWVkID0gbG9jYWxTdG9yYWdlLmdldEl0ZW0odGhpcy5sb2NhbFN0b3JhZ2VIdHRwVGltZWRDYWNoZUtleSk7XHJcbiAgICB2YXIgbHNVbnRpbWVkID0gbG9jYWxTdG9yYWdlLmdldEl0ZW0odGhpcy5sb2NhbFN0b3JhZ2VIdHRwQ2FjaGVLZXkpO1xyXG4gICAgaWYgKCFsc1RpbWVkICYmICFsc1VudGltZWQpXHJcbiAgICAgIHJldHVybjtcclxuXHJcbiAgICBsb2NhbFN0b3JhZ2UucmVtb3ZlSXRlbSh0aGlzLmxvY2FsU3RvcmFnZUh0dHBUaW1lZENhY2hlS2V5KTtcclxuICAgIGxvY2FsU3RvcmFnZS5yZW1vdmVJdGVtKHRoaXMubG9jYWxTdG9yYWdlSHR0cENhY2hlS2V5KTtcclxuICAgIGxzVGltZWQgPSBsc1RpbWVkID8gSlNPTi5wYXJzZShsc1RpbWVkKSA6IHt9O1xyXG4gICAgbHNVbnRpbWVkID0gbHNVbnRpbWVkID8gSlNPTi5wYXJzZShsc1VudGltZWQpIDoge307XHJcblxyXG4gICAgYXdhaXQgZm9ya0pvaW4oW1xyXG4gICAgICB0aGlzLmxvY2FsU3RvcmFnZS5zZXRJdGVtKHRoaXMubG9jYWxTdG9yYWdlSHR0cFRpbWVkQ2FjaGVLZXksIGxzVGltZWQpLFxyXG4gICAgICB0aGlzLmxvY2FsU3RvcmFnZS5zZXRJdGVtKHRoaXMubG9jYWxTdG9yYWdlSHR0cENhY2hlS2V5LCBsc1VudGltZWQpXHJcbiAgICBdKS50b1Byb21pc2UoKTtcclxuXHJcbiAgICB0aGlzLmxvZyh0aGlzLmxvYyhcIkNvbnZlcnRlZCBvbGQgc3RvcmFnZSBzeXN0ZW0gdG8gbmV3IG9uZVwiKSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBFc2VjdXppb25lIGRpIHVuYSBHRVQgSFRUUCBjb24gZXZlbnR1YWxtZW50ZSBsYSBnZXN0aW9uZSBkZWxsYSBjYWNoZSBxdWFsb3JhIGxhIGNoaWFtYXRhIHRlcm1pbmkgY29uIGxhIGNvbnZlbnppb25lIFwiI2NhY2hlXCJcclxuICAgKiBcclxuICAgKiBAcGFyYW0ge3N0cmluZ30gdXJsIFVSTCBzdSBjdWkgZWZmZXR0dWFyZSBsYSBjaGlhbWF0YVxyXG4gICAqIEBwYXJhbSB7SHR0cFBhcmFtc30gcGFyYW1zIFBhcmFtZXRyaSBkZWxsYSBjaGlhbWF0YVxyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0cmFuc2FjdGlvbiBDb2RpY2UgdHJhbnNhemlvbmUgY29sbGVnYXRvIGEgcXVlc3RhIGNoaWFtYXRhLiBWaWVuZSBpbnNlcml0byBuZWxsJ0hlYWRlciBcIlgtVFgtSURcIiBlIGxhdG8gQmFja2VuZCBkb3Zyw6AgZXNzZXJlIGdlc3RpdG8gZGkgY29uc2VndWVuemFcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN1Y2Nlc2Z1bFJlc3VsdE1hbmRhdG9yeSBJbmRpY2EgY2hlIHF1ZXN0YSBjaGlhbWF0YSBkZXZlIGFzc29sdXRhbWVudGUgYW5kYXJlIGJlbmUuIEluIGNhc28gY29udHJhcmlvIHZpZW5lIGZpc2ljYW1lbnRlIGZhdHRvIGlsIHRocm93IGNoZSBwdcOyIGVzc2VyZSBcclxuICAgKiByYWNjb2x0byBkYSBjaGkgdXNhIGxhIGxpYnJlcmlhIG5lbGxhIHBpcGUgXCJvbkVycm9yXCIgZGVsbCdPYnNlcnZhYmxlIHJlc3RpdHVpdG8gZWQgZXNzZXJlIGdlc3RpdG8gaW4gbWFuaWVyYSBub24gc3RhbmRhcmRcclxuICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBlcnJvckNhbGxiYWNrIENhbGxiYWNrIGNoaWFtYXRvIGluIGNhc28gZGkgZXJyb3JlXHJcbiAgICogXHJcbiAgICogQHJldHVybnMge09ic2VydmFibGU8VD59IE9ic2VydmFibGUgY2hlIGNvbnRpZW5lIGlsIHJpc3VsdGF0byBkZWxsYSBjaGlhbWF0YVxyXG4gICAqL1xyXG4gIHB1YmxpYyBnZXQ8VD4odXJsOiBzdHJpbmcsIHBhcmFtczogSHR0cFBhcmFtcyA9IG51bGwsIHRyYW5zYWN0aW9uID0gXCJcIiwgc3VjY2VzZnVsUmVzdWx0TWFuZGF0b3J5OiBib29sZWFuID0gdHJ1ZSwgZXJyb3JDYWxsYmFjazogRnVuY3Rpb24gPSBudWxsKTogT2JzZXJ2YWJsZTxUPiB7XHJcbiAgICByZXR1cm4gZm9ya0pvaW4oXHJcbiAgICAgIHtcclxuICAgICAgICBteUd1aWQ6IGZyb20oW3RoaXMuZGVmYXVsdFN0YXJ0Q2FsbCh1cmwpXSksXHJcbiAgICAgICAgbG9jYWxlOiB0aGlzLmJjLkxvY2FsZS5waXBlKGZpcnN0KCkpXHJcbiAgICAgIH0pLnBpcGUoXHJcbiAgICAgICAgY29uY2F0TWFwKChyZXQ6IHsgbXlHdWlkOiBzdHJpbmcsIGxvY2FsZTogc3RyaW5nIH0pID0+IHtcclxuICAgICAgICAgIGxldCBjYWNoZWRJbmZvcyA9IHRoaXMudHJ5R2V0Q2FjaGVJbmZvcm1hdGlvbnModXJsLCBwYXJhbXMpO1xyXG4gICAgICAgICAgaWYgKGNhY2hlZEluZm9zLmNhY2hlICYmIGNhY2hlZEluZm9zLmNhY2hlSXRlbSkge1xyXG4gICAgICAgICAgICB0aGlzLmxvZyh0aGlzLmxvYyhcIlJlc3VsdCBmb3JcIikgKyBcIiBcIiArIHVybCArIFwiIFwiICsgdGhpcy5sb2MoXCJyZXRyaWV2ZWQgZnJvbSBjYWNoZVwiKSk7XHJcbiAgICAgICAgICAgIHJldHVybiBvZjxUPihjYWNoZWRJbmZvcy5jYWNoZUl0ZW0pLnBpcGUoZGVsYXkoMCksIGZpbmFsaXplKCgpID0+IHsgdGhpcy50cnlGaW5hbGl6ZUJ5R3VpZChyZXQubXlHdWlkKTsgfSkpO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIHZhciBodHRwQ2FsbCA9IHRoaXMuaHR0cC5nZXQ8VD4oY2FjaGVkSW5mb3MuZmluYWxVcmwsIHsgaGVhZGVyczogdGhpcy5nZXRIZWFkZXJzKHJldC5sb2NhbGUsIHRyYW5zYWN0aW9uKSwgcGFyYW1zOiBwYXJhbXMgfSk7XHJcblxyXG4gICAgICAgICAgcmV0dXJuIGh0dHBDYWxsLnBpcGUoXHJcbiAgICAgICAgICAgIG1hcCgocmVzOiBUKSA9PiB7XHJcbiAgICAgICAgICAgICAgbGV0IHJlc3BvbnNlSXRlbSA9IDxUPnJlcztcclxuXHJcbiAgICAgICAgICAgICAgaWYgKGNhY2hlZEluZm9zLmNhY2hlKSB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmNhY2hlUmVzcG9uc2UodGhpcy51dGlzRXh0cy5kZWVwQ2xvbmUocmVzcG9uc2VJdGVtKSwgY2FjaGVkSW5mb3MpO1xyXG4gICAgICAgICAgICAgICAgdGhpcy5sb2codGhpcy5sb2MoXCJDYWNoZWQgcmVzdWx0IGZvclwiKSArIFwiIFwiICsgdXJsKTtcclxuICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgIHJldHVybiByZXNwb25zZUl0ZW07XHJcbiAgICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgICBjYXRjaEVycm9yKChlcnIsIGNhdWdodCk6IE9ic2VydmFibGU8VD4gPT4ge1xyXG4gICAgICAgICAgICAgIGlmIChlcnJvckNhbGxiYWNrKSBlcnJvckNhbGxiYWNrKCk7XHJcbiAgICAgICAgICAgICAgcmV0dXJuICFzdWNjZXNmdWxSZXN1bHRNYW5kYXRvcnkgPyB0aHJvd0Vycm9yKGVycikgOiB0aGlzLnJlZ2lzdGVyRXJyb3JBbmRSZXR1cm5FbXB0eU9ic2VydmFibGUoZXJyLCByZXQubXlHdWlkKTtcclxuICAgICAgICAgICAgfSksXHJcbiAgICAgICAgICAgIGZpbmFsaXplKCgpID0+IHsgdGhpcy50cnlGaW5hbGl6ZUJ5R3VpZChyZXQubXlHdWlkLCBjYWNoZWRJbmZvcyk7IH0pXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0pXHJcbiAgICAgICk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBFc2VjdXppb25lIGRpIHVuYSBHRVQgSFRUUCBjb24gZXZlbnR1YWxtZW50ZSBsYSBnZXN0aW9uZSBkZWxsYSBjYWNoZSBxdWFsb3JhIGxhIGNoaWFtYXRhIHRlcm1pbmkgY29uIGxhIGNvbnZlbnppb25lIFwiI2NhY2hlXCJcclxuICAgKiBcclxuICAgKiBDYXNvIHNwZWNpZmljbyBkaSBjaGlhbWF0YSBjaGUgZGV2ZSByZXN0aXR1aXJlIHVuIEJsb2IgbyB1biBBcnJheUJ1ZmZlciBuYXRpdm8gZGEgZWxhYm9yYXJlXHJcbiAgICogXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHVybCBVUkwgc3UgY3VpIGVmZmV0dHVhcmUgbGEgY2hpYW1hdGFcclxuICAgKiBAcGFyYW0ge0h0dHBQYXJhbXN9IHBhcmFtcyBQYXJhbWV0cmkgZGVsbGEgY2hpYW1hdGFcclxuICAgKiBAcGFyYW0ge1wiYXJyYXlidWZmZXJcInwgXCJibG9iXCJ9IHR5cGUgVGlwbyBkaSByaXRvcm5vIHJpY2hpZXN0b1xyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0cmFuc2FjdGlvbiBDb2RpY2UgdHJhbnNhemlvbmUgY29sbGVnYXRvIGEgcXVlc3RhIGNoaWFtYXRhLiBWaWVuZSBpbnNlcml0byBuZWxsJ0hlYWRlciBcIlgtVFgtSURcIiBlIGxhdG8gQmFja2VuZCBkb3Zyw6AgZXNzZXJlIGdlc3RpdG8gZGkgY29uc2VndWVuemFcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN1Y2Nlc2Z1bFJlc3VsdE1hbmRhdG9yeSBJbmRpY2EgY2hlIHF1ZXN0YSBjaGlhbWF0YSBkZXZlIGFzc29sdXRhbWVudGUgYW5kYXJlIGJlbmUuIEluIGNhc28gY29udHJhcmlvIHZpZW5lIGZpc2ljYW1lbnRlIGZhdHRvIGlsIHRocm93IGNoZSBwdcOyIGVzc2VyZSBcclxuICAgKiByYWNjb2x0byBkYSBjaGkgdXNhIGxhIGxpYnJlcmlhIG5lbGxhIHBpcGUgXCJvbkVycm9yXCIgZGVsbCdPYnNlcnZhYmxlIHJlc3RpdHVpdG8gZWQgZXNzZXJlIGdlc3RpdG8gaW4gbWFuaWVyYSBub24gc3RhbmRhcmRcclxuICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBlcnJvckNhbGxiYWNrIENhbGxiYWNrIGNoaWFtYXRvIGluIGNhc28gZGkgZXJyb3JlXHJcbiAgICogXHJcbiAgICogQHJldHVybnMge09ic2VydmFibGU8QmxvYiB8IEFycmF5QnVmZmVyPn0gT2JzZXJ2YWJsZSBjaGUgY29udGllbmUgaWwgcmlzdWx0YXRvIGRlbGxhIGNoaWFtYXRhXHJcbiAgICovXHJcbiAgcHVibGljIGdldFJhdyh1cmw6IHN0cmluZywgcGFyYW1zOiBIdHRwUGFyYW1zID0gbnVsbCwgdHlwZTogXCJhcnJheWJ1ZmZlclwiIHwgXCJibG9iXCIgPSBcImFycmF5YnVmZmVyXCIsIHRyYW5zYWN0aW9uID0gXCJcIiwgc3VjY2VzZnVsUmVzdWx0TWFuZGF0b3J5OiBib29sZWFuID0gdHJ1ZSwgZXJyb3JDYWxsYmFjayA9IG51bGwpOiBPYnNlcnZhYmxlPEJsb2IgfCBBcnJheUJ1ZmZlcj4ge1xyXG4gICAgcmV0dXJuIGZvcmtKb2luKFxyXG4gICAgICB7XHJcbiAgICAgICAgbXlHdWlkOiBmcm9tKFt0aGlzLmRlZmF1bHRTdGFydENhbGwodXJsKV0pLFxyXG4gICAgICAgIGxvY2FsZTogdGhpcy5iYy5Mb2NhbGUucGlwZShmaXJzdCgpKVxyXG4gICAgICB9KS5waXBlKFxyXG4gICAgICAgIGNvbmNhdE1hcCgocmV0OiB7IG15R3VpZDogc3RyaW5nLCBsb2NhbGU6IHN0cmluZyB9KSA9PiB7XHJcbiAgICAgICAgICBsZXQgY2FjaGVkSW5mb3MgPSB0aGlzLnRyeUdldENhY2hlSW5mb3JtYXRpb25zKHVybCwgcGFyYW1zKTtcclxuICAgICAgICAgIGlmIChjYWNoZWRJbmZvcy5jYWNoZSAmJiBjYWNoZWRJbmZvcy5jYWNoZUl0ZW0pIHtcclxuICAgICAgICAgICAgdGhpcy5sb2codGhpcy5sb2MoXCJSZXN1bHQgZm9yXCIpICsgXCIgXCIgKyB1cmwgKyBcIiBcIiArIHRoaXMubG9jKFwicmV0cmlldmVkIGZyb20gY2FjaGVcIikpO1xyXG4gICAgICAgICAgICByZXR1cm4gb2Y8YW55PihjYWNoZWRJbmZvcy5jYWNoZUl0ZW0pLnBpcGUoZGVsYXkoMCksIGZpbmFsaXplKCgpID0+IHsgdGhpcy50cnlGaW5hbGl6ZUJ5R3VpZChyZXQubXlHdWlkKTsgfSkpO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIHZhciBodHRwQ2FsbCA9IHRoaXMuaHR0cC5nZXQoY2FjaGVkSW5mb3MuZmluYWxVcmwsIHsgcmVzcG9uc2VUeXBlOiA8YW55PnR5cGUsIGhlYWRlcnM6IHRoaXMuZ2V0SGVhZGVycyhyZXQubG9jYWxlLCB0cmFuc2FjdGlvbiksIHBhcmFtczogcGFyYW1zIH0pO1xyXG5cclxuICAgICAgICAgIHJldHVybiBodHRwQ2FsbC5waXBlKFxyXG4gICAgICAgICAgICBtYXAoKGJsb2I6IEJsb2IgfCBBcnJheUJ1ZmZlcikgPT4ge1xyXG5cclxuICAgICAgICAgICAgICBpZiAoY2FjaGVkSW5mb3MuY2FjaGUpIHtcclxuICAgICAgICAgICAgICAgIHRoaXMuY2FjaGVSZXNwb25zZShibG9iLCBjYWNoZWRJbmZvcyk7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmxvZyh0aGlzLmxvYyhcIkNhY2hlZCByZXN1bHQgZm9yXCIpICsgXCIgXCIgKyB1cmwpO1xyXG4gICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgcmV0dXJuIGJsb2I7XHJcbiAgICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgICBjYXRjaEVycm9yKChlcnIsIGNhdWdodCk6IE9ic2VydmFibGU8QmxvYj4gPT4ge1xyXG4gICAgICAgICAgICAgIGlmIChlcnJvckNhbGxiYWNrKSBlcnJvckNhbGxiYWNrKCk7XHJcbiAgICAgICAgICAgICAgcmV0dXJuICFzdWNjZXNmdWxSZXN1bHRNYW5kYXRvcnkgPyB0aHJvd0Vycm9yKGVycikgOiB0aGlzLnJlZ2lzdGVyRXJyb3JBbmRSZXR1cm5FbXB0eU9ic2VydmFibGUoZXJyLCByZXQubXlHdWlkKTtcclxuICAgICAgICAgICAgfSksXHJcbiAgICAgICAgICAgIGZpbmFsaXplKCgpID0+IHsgdGhpcy50cnlGaW5hbGl6ZUJ5R3VpZChyZXQubXlHdWlkLCBjYWNoZWRJbmZvcyk7IH0pXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0pXHJcbiAgICAgICk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAqIEVzZWN1emlvbmUgZGkgdW5hIFBPU1QgSFRUUFxyXG4gICogXHJcbiAgKiBAcGFyYW0ge3N0cmluZ30gdXJsIFVSTCBzdSBjdWkgZWZmZXR0dWFyZSBsYSBjaGlhbWF0YVxyXG4gICogQHBhcmFtIHthbnl9IGJvZHlEYXRhIERUTyBwZXIgbGEgY2hpYW1hdGFcclxuICAqIEBwYXJhbSB7SHR0cFBhcmFtc30gcGFyYW1zIFBhcmFtZXRyaSBkZWxsYSBjaGlhbWF0YVxyXG4gICogQHBhcmFtIHtzdHJpbmd9IHRyYW5zYWN0aW9uIENvZGljZSB0cmFuc2F6aW9uZSBjb2xsZWdhdG8gYSBxdWVzdGEgY2hpYW1hdGEuIFZpZW5lIGluc2VyaXRvIG5lbGwnSGVhZGVyIFwiWC1UWC1JRFwiIGUgbGF0byBCYWNrZW5kIGRvdnLDoCBlc3NlcmUgZ2VzdGl0byBkaSBjb25zZWd1ZW56YVxyXG4gICogQHBhcmFtIHtib29sZWFufSBzdWNjZXNmdWxSZXN1bHRNYW5kYXRvcnkgSW5kaWNhIGNoZSBxdWVzdGEgY2hpYW1hdGEgZGV2ZSBhc3NvbHV0YW1lbnRlIGFuZGFyZSBiZW5lLiBJbiBjYXNvIGNvbnRyYXJpbyB2aWVuZSBmaXNpY2FtZW50ZSBmYXR0byBpbCB0aHJvdyBjaGUgcHXDsiBlc3NlcmUgXHJcbiAgKiByYWNjb2x0byBkYSBjaGkgdXNhIGxhIGxpYnJlcmlhIG5lbGxhIHBpcGUgXCJvbkVycm9yXCIgZGVsbCdPYnNlcnZhYmxlIHJlc3RpdHVpdG8gZWQgZXNzZXJlIGdlc3RpdG8gaW4gbWFuaWVyYSBub24gc3RhbmRhcmRcclxuICAqIFxyXG4gICogQHJldHVybnMge09ic2VydmFibGU8VD59IE9ic2VydmFibGUgY2hlIGNvbnRpZW5lIGlsIHJpc3VsdGF0byBkZWxsYSBjaGlhbWF0YVxyXG4gICovXHJcbiAgcHVibGljIHBvc3Q8VD4odXJsOiBzdHJpbmcsIGJvZHlEYXRhOiBhbnksIHBhcmFtczogSHR0cFBhcmFtcyA9IG51bGwsIHRyYW5zYWN0aW9uID0gXCJcIiwgc3VjY2VzZnVsUmVzdWx0TWFuZGF0b3J5OiBib29sZWFuID0gdHJ1ZSk6IE9ic2VydmFibGU8VD4ge1xyXG4gICAgcmV0dXJuIGZvcmtKb2luKFxyXG4gICAgICB7XHJcbiAgICAgICAgbXlHdWlkOiBmcm9tKFt0aGlzLmRlZmF1bHRTdGFydENhbGwodXJsKV0pLFxyXG4gICAgICAgIGxvY2FsZTogdGhpcy5iYy5Mb2NhbGUucGlwZShmaXJzdCgpKVxyXG4gICAgICB9KS5waXBlKFxyXG4gICAgICAgIGNvbmNhdE1hcCgocmV0OiB7IG15R3VpZDogc3RyaW5nLCBsb2NhbGU6IHN0cmluZyB9KSA9PiB7XHJcblxyXG4gICAgICAgICAgLy8gU2Ugw6ggdW5hIHJpY2VyY2EsIHNoYWxsb3cgY29weSBlIHJpbXVvdm8gZ2xpIFwiaXRlbXNcIiBwZXIgZXZpdGFyZSBkaSBmYXJsaSBhbmRhcmUgc3UgZSBnacO5IGFsIGJhY2tlbmRcclxuICAgICAgICAgIGlmICghIWJvZHlEYXRhPy5pdGVtcyAmJiAhIWJvZHlEYXRhPy5wYWdlKSB7XHJcbiAgICAgICAgICAgIGJvZHlEYXRhID0geyAuLi5ib2R5RGF0YSB9O1xyXG4gICAgICAgICAgICBkZWxldGUgYm9keURhdGEuaXRlbXM7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgdmFyIGh0dHBDYWxsID0gdGhpcy5odHRwLnBvc3Q8VD4odXJsLCBib2R5RGF0YSwgeyBoZWFkZXJzOiB0aGlzLmdldEhlYWRlcnMocmV0LmxvY2FsZSwgdHJhbnNhY3Rpb24pLCBwYXJhbXM6IHBhcmFtcyB9KTtcclxuXHJcbiAgICAgICAgICByZXR1cm4gaHR0cENhbGwucGlwZShcclxuICAgICAgICAgICAgY2F0Y2hFcnJvcigoZXJyLCBfKTogT2JzZXJ2YWJsZTxUPiA9PiB7XHJcbiAgICAgICAgICAgICAgcmV0dXJuICFzdWNjZXNmdWxSZXN1bHRNYW5kYXRvcnkgPyB0aHJvd0Vycm9yKGVycikgOiB0aGlzLnJlZ2lzdGVyRXJyb3JBbmRSZXR1cm5FbXB0eU9ic2VydmFibGUoZXJyLCByZXQubXlHdWlkKTtcclxuICAgICAgICAgICAgfSksXHJcbiAgICAgICAgICAgIGZpbmFsaXplKCgpID0+IHsgdGhpcy50cnlGaW5hbGl6ZUJ5R3VpZChyZXQubXlHdWlkKTsgfSlcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfSlcclxuICAgICAgKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICogRXNlY3V6aW9uZSBkaSB1bmEgREVMRVRFIEhUVFBcclxuICAqXHJcbiAgKiBAcGFyYW0ge3N0cmluZ30gdXJsIFVSTCBzdSBjdWkgZWZmZXR0dWFyZSBsYSBjaGlhbWF0YVxyXG4gICogQHBhcmFtIHtIdHRwUGFyYW1zfSBwYXJhbXMgUGFyYW1ldHJpIGRlbGxhIGNoaWFtYXRhXHJcbiAgKiBAcGFyYW0ge3N0cmluZ30gdHJhbnNhY3Rpb24gQ29kaWNlIHRyYW5zYXppb25lIGNvbGxlZ2F0byBhIHF1ZXN0YSBjaGlhbWF0YS4gVmllbmUgaW5zZXJpdG8gbmVsbCdIZWFkZXIgXCJYLVRYLUlEXCIgZSBsYXRvIEJhY2tlbmQgZG92csOgIGVzc2VyZSBnZXN0aXRvIGRpIGNvbnNlZ3VlbnphXHJcbiAgKiBAcGFyYW0ge2Jvb2xlYW59IHN1Y2Nlc2Z1bFJlc3VsdE1hbmRhdG9yeSBJbmRpY2EgY2hlIHF1ZXN0YSBjaGlhbWF0YSBkZXZlIGFzc29sdXRhbWVudGUgYW5kYXJlIGJlbmUuIEluIGNhc28gY29udHJhcmlvIHZpZW5lIGZpc2ljYW1lbnRlIGZhdHRvIGlsIHRocm93IGNoZSBwdcOyIGVzc2VyZSBcclxuICAqIHJhY2NvbHRvIGRhIGNoaSB1c2EgbGEgbGlicmVyaWEgbmVsbGEgcGlwZSBcIm9uRXJyb3JcIiBkZWxsJ09ic2VydmFibGUgcmVzdGl0dWl0byBlZCBlc3NlcmUgZ2VzdGl0byBpbiBtYW5pZXJhIG5vbiBzdGFuZGFyZFxyXG4gICogXHJcbiAgKiBAcmV0dXJucyB7T2JzZXJ2YWJsZTxUPn0gT2JzZXJ2YWJsZSBjaGUgY29udGllbmUgaWwgcmlzdWx0YXRvIGRlbGxhIGNoaWFtYXRhXHJcbiAgKi9cclxuICBwdWJsaWMgZGVsZXRlPFQ+KHVybDogc3RyaW5nLCBwYXJhbXM6IEh0dHBQYXJhbXMgPSBudWxsLCB0cmFuc2FjdGlvbiA9IFwiXCIsIHN1Y2Nlc2Z1bFJlc3VsdE1hbmRhdG9yeTogYm9vbGVhbiA9IHRydWUpOiBPYnNlcnZhYmxlPFQ+IHtcclxuICAgIHJldHVybiBmb3JrSm9pbihcclxuICAgICAge1xyXG4gICAgICAgIG15R3VpZDogZnJvbShbdGhpcy5kZWZhdWx0U3RhcnRDYWxsKHVybCldKSxcclxuICAgICAgICBsb2NhbGU6IHRoaXMuYmMuTG9jYWxlLnBpcGUoZmlyc3QoKSlcclxuICAgICAgfSkucGlwZShcclxuICAgICAgICBjb25jYXRNYXAoKHJldDogeyBteUd1aWQ6IHN0cmluZywgbG9jYWxlOiBzdHJpbmcgfSkgPT4ge1xyXG5cclxuICAgICAgICAgIHZhciBodHRwQ2FsbCA9IHRoaXMuaHR0cC5kZWxldGU8VD4odXJsLCB7IGhlYWRlcnM6IHRoaXMuZ2V0SGVhZGVycyhyZXQubG9jYWxlLCB0cmFuc2FjdGlvbiksIHBhcmFtczogcGFyYW1zIH0pO1xyXG5cclxuICAgICAgICAgIHJldHVybiBodHRwQ2FsbC5waXBlKFxyXG4gICAgICAgICAgICBjYXRjaEVycm9yKChlcnIsIGNhdWdodCk6IE9ic2VydmFibGU8VD4gPT4ge1xyXG4gICAgICAgICAgICAgIHJldHVybiAhc3VjY2VzZnVsUmVzdWx0TWFuZGF0b3J5ID8gdGhyb3dFcnJvcihlcnIpIDogdGhpcy5yZWdpc3RlckVycm9yQW5kUmV0dXJuRW1wdHlPYnNlcnZhYmxlKGVyciwgcmV0Lm15R3VpZCk7XHJcbiAgICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgICBmaW5hbGl6ZSgoKSA9PiB7IHRoaXMudHJ5RmluYWxpemVCeUd1aWQocmV0Lm15R3VpZCk7IH0pXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0pXHJcbiAgICAgICk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBFc2VjdXppb25lIGRpIHVuYSBQVVQgSFRUUFxyXG4gICAqIFxyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgVVJMIHN1IGN1aSBlZmZldHR1YXJlIGxhIGNoaWFtYXRhXHJcbiAgICogQHBhcmFtIHthbnl9IGJvZHlEYXRhIERUTyBwZXIgbGEgY2hpYW1hdGFcclxuICAgKiBAcGFyYW0ge0h0dHBQYXJhbXN9IHBhcmFtcyBQYXJhbWV0cmkgZGVsbGEgY2hpYW1hdGFcclxuICAgKiBAcGFyYW0ge3N0cmluZ30gdHJhbnNhY3Rpb24gQ29kaWNlIHRyYW5zYXppb25lIGNvbGxlZ2F0byBhIHF1ZXN0YSBjaGlhbWF0YS4gVmllbmUgaW5zZXJpdG8gbmVsbCdIZWFkZXIgXCJYLVRYLUlEXCIgZSBsYXRvIEJhY2tlbmQgZG92csOgIGVzc2VyZSBnZXN0aXRvIGRpIGNvbnNlZ3VlbnphXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdWNjZXNmdWxSZXN1bHRNYW5kYXRvcnkgSW5kaWNhIGNoZSBxdWVzdGEgY2hpYW1hdGEgZGV2ZSBhc3NvbHV0YW1lbnRlIGFuZGFyZSBiZW5lLiBJbiBjYXNvIGNvbnRyYXJpbyB2aWVuZSBmaXNpY2FtZW50ZSBmYXR0byBpbCB0aHJvdyBjaGUgcHXDsiBlc3NlcmUgXHJcbiAgICogcmFjY29sdG8gZGEgY2hpIHVzYSBsYSBsaWJyZXJpYSBuZWxsYSBwaXBlIFwib25FcnJvclwiIGRlbGwnT2JzZXJ2YWJsZSByZXN0aXR1aXRvIGVkIGVzc2VyZSBnZXN0aXRvIGluIG1hbmllcmEgbm9uIHN0YW5kYXJkXHJcbiAgICogXHJcbiAgICogQHJldHVybnMge09ic2VydmFibGU8VD59IE9ic2VydmFibGUgY2hlIGNvbnRpZW5lIGlsIHJpc3VsdGF0byBkZWxsYSBjaGlhbWF0YVxyXG4gICAqL1xyXG4gIHB1YmxpYyBwdXQ8VD4odXJsOiBzdHJpbmcsIGJvZHlEYXRhOiBhbnksIHBhcmFtczogSHR0cFBhcmFtcyA9IG51bGwsIHRyYW5zYWN0aW9uID0gXCJcIiwgc3VjY2VzZnVsUmVzdWx0TWFuZGF0b3J5OiBib29sZWFuID0gdHJ1ZSk6IE9ic2VydmFibGU8VD4ge1xyXG4gICAgcmV0dXJuIGZvcmtKb2luKFxyXG4gICAgICB7XHJcbiAgICAgICAgbXlHdWlkOiBmcm9tKFt0aGlzLmRlZmF1bHRTdGFydENhbGwodXJsKV0pLFxyXG4gICAgICAgIGxvY2FsZTogdGhpcy5iYy5Mb2NhbGUucGlwZShmaXJzdCgpKVxyXG4gICAgICB9KS5waXBlKFxyXG4gICAgICAgIGNvbmNhdE1hcCgocmV0OiB7IG15R3VpZDogc3RyaW5nLCBsb2NhbGU6IHN0cmluZyB9KSA9PiB7XHJcblxyXG4gICAgICAgICAgdmFyIGh0dHBDYWxsID0gdGhpcy5odHRwLnB1dDxUPih1cmwsIGJvZHlEYXRhLCB7IGhlYWRlcnM6IHRoaXMuZ2V0SGVhZGVycyhyZXQubG9jYWxlLCB0cmFuc2FjdGlvbiksIHBhcmFtczogcGFyYW1zIH0pO1xyXG5cclxuICAgICAgICAgIHJldHVybiBodHRwQ2FsbC5waXBlKFxyXG4gICAgICAgICAgICBjYXRjaEVycm9yKChlcnIsIGNhdWdodCk6IE9ic2VydmFibGU8VD4gPT4ge1xyXG4gICAgICAgICAgICAgIHJldHVybiAhc3VjY2VzZnVsUmVzdWx0TWFuZGF0b3J5ID8gdGhyb3dFcnJvcihlcnIpIDogdGhpcy5yZWdpc3RlckVycm9yQW5kUmV0dXJuRW1wdHlPYnNlcnZhYmxlKGVyciwgcmV0Lm15R3VpZCk7XHJcbiAgICAgICAgICAgIH0pLFxyXG4gICAgICAgICAgICBmaW5hbGl6ZSgoKSA9PiB7IHRoaXMudHJ5RmluYWxpemVCeUd1aWQocmV0Lm15R3VpZCk7IH0pXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0pXHJcbiAgICAgICk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBFc2VjdXppb25lIGRpIHVuYSBQT1NUIEhUVFBcclxuICAgKiBcclxuICAgKiBDYXNpc3RpY2EgcGFydGljb2xhcmUgaW4gY3VpIGJpc29nbmEgYW5jaGUgaW52aWFyZSBkZWkgRmlsZVxyXG4gICAqIFxyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgVVJMIHN1IGN1aSBlZmZldHR1YXJlIGxhIGNoaWFtYXRhXHJcbiAgICogQHBhcmFtIHthbnl9IGJvZHlEYXRhIERUTyBwZXIgbGEgY2hpYW1hdGFcclxuICAgKiBAcGFyYW0ge0ZpbGVbXSB8IEZpbGV9IGZpbGVBcnJheU9yRmlsZSBTaW5nb2xvIGZpbGUgbyBsaXN0YSBkaSBmaWxlIGRhIGludmlhcmUuIElsIHRpcG8gKipGaWxlKiogw6ggcXVlbGxvIG5hdGl2byBkZWwgSmF2YXNjcmlwdFxyXG4gICAqIFxyXG4gICAqIEByZXR1cm5zIHtPYnNlcnZhYmxlPFQ+fSBPYnNlcnZhYmxlIGNoZSBjb250aWVuZSBpbCByaXN1bHRhdG8gZGVsbGEgY2hpYW1hdGFcclxuICAgKi9cclxuICBwdWJsaWMgcG9zdHdpdGhGaWxlczxUPih1cmw6IHN0cmluZywgYm9keURhdGE6IGFueSwgZmlsZUFycmF5T3JGaWxlOiBGaWxlW10gfCBGaWxlLCBwYXJhbXM6IEh0dHBQYXJhbXMgPSBudWxsLCBzdWNjZXNmdWxSZXN1bHRNYW5kYXRvcnk6IGJvb2xlYW4gPSB0cnVlLCBvbkVycm9yPzogKCkgPT4gdm9pZCk6IE9ic2VydmFibGU8VD4ge1xyXG4gICAgcmV0dXJuIGZvcmtKb2luKFxyXG4gICAgICB7XHJcbiAgICAgICAgbXlHdWlkOiBmcm9tKFt0aGlzLmRlZmF1bHRTdGFydENhbGwodXJsKV0pLFxyXG4gICAgICAgIGxvY2FsZTogdGhpcy5iYy5Mb2NhbGUucGlwZShmaXJzdCgpKVxyXG4gICAgICB9KS5waXBlKFxyXG4gICAgICAgIGNvbmNhdE1hcCgocmV0OiB7IG15R3VpZDogc3RyaW5nLCBsb2NhbGU6IHN0cmluZyB9KSA9PiB7XHJcblxyXG4gICAgICAgICAgdmFyIGZvcm1EYXRhID0gdGhpcy5nZXRGaWxlc0Zvcm1EYXRhKGZpbGVBcnJheU9yRmlsZSk7XHJcbiAgICAgICAgICBmb3JtRGF0YS5hcHBlbmQoXCJib2R5XCIsIEpTT04uc3RyaW5naWZ5KGJvZHlEYXRhKSk7XHJcblxyXG4gICAgICAgICAgdmFyIGh0dHBDYWxsID0gdGhpcy5odHRwLnBvc3Q8VD4odXJsLCBmb3JtRGF0YSwgeyBwYXJhbXM6IHBhcmFtcywgaGVhZGVyczogdGhpcy5nZXRIZWFkZXJzKHJldC5sb2NhbGUsIG51bGwsIHRydWUsIG51bGwsIG51bGwpIH0pO1xyXG5cclxuICAgICAgICByZXR1cm4gaHR0cENhbGwucGlwZShcclxuICAgICAgICAgIGNhdGNoRXJyb3IoKGVyciwgY2F1Z2h0KTogT2JzZXJ2YWJsZTxUPiA9PiB7IFxyXG4gICAgICAgICAgICBvbkVycm9yPy4oKTtcclxuICAgICAgICAgICAgcmV0dXJuICFzdWNjZXNmdWxSZXN1bHRNYW5kYXRvcnkgPyB0aHJvd0Vycm9yKGVycikgOiB0aGlzLnJlZ2lzdGVyRXJyb3JBbmRSZXR1cm5FbXB0eU9ic2VydmFibGUoZXJyLCByZXQubXlHdWlkKTsgXHJcbiAgICAgICAgICB9KSxcclxuICAgICAgICAgIGZpbmFsaXplKCgpID0+IHsgdGhpcy50cnlGaW5hbGl6ZUJ5R3VpZChyZXQubXlHdWlkKTsgfSlcclxuICAgICAgICApO1xyXG4gICAgICB9KVxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEVzZWN1emlvbmUgZGkgdW5hIFBPU1QgSFRUUFxyXG4gICAqIFxyXG4gICAqIENhc2lzdGljYSBwYXJ0aWNvbGFyZSBpbiBjdWkgdmllbmUgcmVzdGl0dWl0byB1biBmaWxlIGdlc3RpdG8gY29tZSBPYmplY3RVUkwgaWwgY3VpIFVSTCBzaSBwdcOyIGdlc3RpcmUgZGFsIHBhcmFtZXRybyBkaSBjYWxsYmFjayAqKmdldEZpbGVDYWxsYmFjayoqLiBcclxuICAgKiBMYSBjaGlhbWF0YSBub24gaGEgdW4gdGlwbyByZXN0aXR1aXRvIGluIHF1YW50byBpbCByaXN1bHRhdG8gZGV2J2Vzc2VyZSBnZXN0aXRvIGF0dHJhdmVyc28gbGEgY2FsbGJhY2sgKipnZXRGaWxlQ2FsbGJhY2sqKlxyXG4gICAqIFxyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgVVJMIHN1IGN1aSBlZmZldHR1YXJlIGxhIGNoaWFtYXRhXHJcbiAgICogQHBhcmFtIHtLfSBib2R5RGF0YSBEVE8gcGVyIGxhIGNoaWFtYXRhXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IGZpbGVuYW1lIE5vbWUgZGVsIGZpbGUgY2hlIHNpIHN0YSByaWNoaWVkZW5kbywgcmltYW5lIGxhdG8gRnJvbnRlbmQgZSBzZXJ2ZSBwZXIgYXNzZWduYXJlIGFyYml0cmFyaWFtZW50ZSB1biBub21lIGFsIGZpbGUgcmVzdGl0dWl0bywgc2UgdnVvdG8gdmllbmUgdXRpbGl6emF0YSBsYSBDb250ZW50LURpc3Bvc2l0aW9uIGRlbGxhIHJpc3Bvc3RhXHJcbiAgICogQHBhcmFtIHtGdW5jdGlvbn0gZ2V0RmlsZUNhbGxiYWNrIENhbGxiYWNrIGEgZHVlIHBhcmFtZXRyaSAodXJsOiBzdHJpbmcsIGZpbGVuYW1lOiBzdHJpbmcpIHBlciBnZXN0aXJlIGlsIHJpc3VsdGF0byBkZWwgZmlsZSByaWNoaWVzdG8uICoqVXRpbGl6emFyZSBVdGlsaXR5U2VydmljZS5maWxlRG93bmxvYWQqKiBkaSBAZXNmYWVuemEvZXh0ZW5zaW9uc1xyXG4gICAqIEBwYXJhbSB7RnVuY3Rpb259IGFmdGVyR2V0RmlsZSBDYWxsYmFjayBkYSBjaGlhbWFyZSBkb3BvIGF2ZXIgZ2VzdGl0byBsYSByaXNwb3N0YSBkZWwgKipnZXRGaWxlQ2FsbGJhY2sqKiwgaW4gY2FzbyAqKmhhbmRsZUVycm9yKiogZm9zc2UgKipmYWxzZSoqIHZlcnLDoCByaWNoaWFtYXRvIGFuY2hlIGluIGNhc28gZGkgZXJyb3JlXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBoYW5kbGVFcnJvciBJbmRpY2Egc2UgZGkgZGVmYXVsdCBnbGkgZXJyb3JpIGRldm9ubyBlc3NlcmUgZ2VzdGl0aSBkYWxsYSBsaWJyZXJpYSBvIHNlIGRldm9ubyBlc3NlcmUgaWdub3JhdGlcclxuICAgKi9cclxuICBwdWJsaWMgYXN5bmMgcG9zdEdldEZpbGU8Sz4odXJsOiBzdHJpbmcsIGJvZHlEYXRhOiBLLCBmaWxlbmFtZTogc3RyaW5nLCBnZXRGaWxlQ2FsbGJhY2s6ICh1cmw6IHN0cmluZywgZmlsZW5hbWU6IHN0cmluZykgPT4gYW55LCBhZnRlckdldEZpbGU6ICgpID0+IGFueSA9IG51bGwsIGhhbmRsZUVycm9yOiBib29sZWFuID0gdHJ1ZSwgcGFycz86IEh0dHBQYXJhbXMpIHtcclxuICAgIGxldCBteUd1aWQgPSB0aGlzLmRlZmF1bHRTdGFydENhbGwodXJsKTtcclxuICAgIGxldCBsb2NhbGUgPSBhd2FpdCB0aGlzLmJjLkxvY2FsZS5waXBlKGZpcnN0KCkpLnRvUHJvbWlzZSgpO1xyXG5cclxuICAgIHRoaXMuaHR0cC5wb3N0KHVybCwgYm9keURhdGEsIHsgcGFyYW1zOiBwYXJzLCBoZWFkZXJzOiB0aGlzLmdldEhlYWRlcnMobG9jYWxlKSwgb2JzZXJ2ZTogJ3Jlc3BvbnNlJywgcmVzcG9uc2VUeXBlOiBcImJsb2JcIiB9KS5waXBlKFxyXG4gICAgICBjYXRjaEVycm9yKChlcnIsIGNhdWdodCk6IE9ic2VydmFibGU8c3RyaW5nPiA9PiB7XHJcbiAgICAgICAgaWYgKGFmdGVyR2V0RmlsZSAmJiAhaGFuZGxlRXJyb3IpIGFmdGVyR2V0RmlsZSgpO1xyXG4gICAgICAgIHJldHVybiB0aGlzLnJlZ2lzdGVyRXJyb3JBbmRSZXR1cm5FbXB0eU9ic2VydmFibGUoZXJyLCBteUd1aWQsIGhhbmRsZUVycm9yKTtcclxuICAgICAgfSksXHJcbiAgICAgIGZpbmFsaXplKCgpID0+IHsgdGhpcy50cnlGaW5hbGl6ZUJ5R3VpZChteUd1aWQpOyB9KVxyXG4gICAgKS5zdWJzY3JpYmUoKHJlc3BvbnNlOiBIdHRwUmVzcG9uc2U8QmxvYj4pID0+IHtcclxuICAgICAgbGV0IHJldFVybCA9IHdpbmRvdy5VUkwuY3JlYXRlT2JqZWN0VVJMKHJlc3BvbnNlLmJvZHkpO1xyXG4gICAgICBsZXQgZm4gPSByZXNwb25zZS5oZWFkZXJzLmdldCgnY29udGVudC1kaXNwb3NpdGlvbicpPy5zcGxpdCgnOycpWzFdPy5zcGxpdCgnZmlsZW5hbWUnKVsxXT8uc3BsaXQoJz0nKVsxXT8udHJpbSgpLnJlcGxhY2UoL1xcXCIvZywgJycpO1xyXG5cclxuICAgICAgZ2V0RmlsZUNhbGxiYWNrKHJldFVybCwgZmlsZW5hbWUgfHwgZm4pO1xyXG4gICAgICBpZiAoYWZ0ZXJHZXRGaWxlKSBhZnRlckdldEZpbGUoKTtcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogRXNlY3V6aW9uZSBkaSB1bmEgR0VUIEhUVFBcclxuICAgKiBcclxuICAgKiBDYXNpc3RpY2EgcGFydGljb2xhcmUgaW4gY3VpIHZpZW5lIHJlc3RpdHVpdG8gdW4gZmlsZSBnZXN0aXRvIGNvbWUgT2JqZWN0VVJMIGlsIGN1aSBVUkwgc2kgcHXDsiBnZXN0aXJlIGRhbCBwYXJhbWV0cm8gZGkgY2FsbGJhY2sgKipnZXRGaWxlQ2FsbGJhY2sqKi4gXHJcbiAgICogTGEgY2hpYW1hdGEgbm9uIGhhIHVuIHRpcG8gcmVzdGl0dWl0byBpbiBxdWFudG8gaWwgcmlzdWx0YXRvIGRldidlc3NlcmUgZ2VzdGl0byBhdHRyYXZlcnNvIGxhIGNhbGxiYWNrICoqZ2V0RmlsZUNhbGxiYWNrKipcclxuICAgKiBcclxuICAgKiBAcGFyYW0ge3N0cmluZ30gdXJsIFVSTCBzdSBjdWkgZWZmZXR0dWFyZSBsYSBjaGlhbWF0YVxyXG4gICAqIEBwYXJhbSB7SHR0cFBhcmFtc30gcGFyYW1zIFBhcmFtZXRyaSBkZWxsYSBjaGlhbWF0YVxyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBmaWxlbmFtZSBOb21lIGRlbCBmaWxlIGNoZSBzaSBzdGEgcmljaGllZGVuZG8sIHJpbWFuZSBsYXRvIEZyb250ZW5kIGUgc2VydmUgcGVyIGFzc2VnbmFyZSBhcmJpdHJhcmlhbWVudGUgdW4gbm9tZSBhbCBmaWxlIHJlc3RpdHVpdG8sIHNlIHZ1b3RvIHZpZW5lIHV0aWxpenphdGEgbGEgQ29udGVudC1EaXNwb3NpdGlvbiBkZWxsYSByaXNwb3N0YVxyXG4gICAqIEBwYXJhbSB7RnVuY3Rpb259IGdldEZpbGVDYWxsYmFjayBDYWxsYmFjayBhIGR1ZSBwYXJhbWV0cmkgKHVybDogc3RyaW5nLCBmaWxlbmFtZTogc3RyaW5nKSBwZXIgZ2VzdGlyZSBpbCByaXN1bHRhdG8gZGVsIGZpbGUgcmljaGllc3RvLiAqKlV0aWxpenphcmUgVXRpbGl0eVNlcnZpY2UuZmlsZURvd25sb2FkKiogZGkgQGVzZmFlbnphL2V4dGVuc2lvbnNcclxuICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBhZnRlckdldEZpbGUgQ2FsbGJhY2sgZGEgY2hpYW1hcmUgZG9wbyBhdmVyIGdlc3RpdG8gbGEgcmlzcG9zdGEgZGVsICoqZ2V0RmlsZUNhbGxiYWNrKiosIGluIGNhc28gKipoYW5kbGVFcnJvcioqIGZvc3NlICoqZmFsc2UqKiB2ZXJyw6AgcmljaGlhbWF0byBhbmNoZSBpbiBjYXNvIGRpIGVycm9yZVxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gaGFuZGxlRXJyb3IgSW5kaWNhIHNlIGRpIGRlZmF1bHQgZ2xpIGVycm9yaSBkZXZvbm8gZXNzZXJlIGdlc3RpdGkgZGFsbGEgbGlicmVyaWEgbyBzZSBkZXZvbm8gZXNzZXJlIGlnbm9yYXRpXHJcbiAgICovXHJcbiAgcHVibGljIGFzeW5jIGdldEZpbGUodXJsOiBzdHJpbmcsIHBhcmFtczogSHR0cFBhcmFtcyA9IG51bGwsIGZpbGVuYW1lOiBzdHJpbmcsIGdldEZpbGVDYWxsYmFjazogKHVybDogc3RyaW5nLCBmaWxlbmFtZTogc3RyaW5nKSA9PiBhbnksIGFmdGVyR2V0RmlsZTogKCkgPT4gYW55ID0gbnVsbCwgaGFuZGxlRXJyb3I6IGJvb2xlYW4gPSB0cnVlKSB7XHJcbiAgICBsZXQgbXlHdWlkID0gdGhpcy5kZWZhdWx0U3RhcnRDYWxsKHVybCk7XHJcbiAgICBsZXQgbG9jYWxlID0gYXdhaXQgdGhpcy5iYy5Mb2NhbGUucGlwZShmaXJzdCgpKS50b1Byb21pc2UoKTtcclxuXHJcbiAgICB0aGlzLmh0dHAuZ2V0KHVybCwgeyBwYXJhbXM6IHBhcmFtcywgaGVhZGVyczogdGhpcy5nZXRIZWFkZXJzKGxvY2FsZSksIG9ic2VydmU6ICdyZXNwb25zZScsIHJlc3BvbnNlVHlwZTogXCJibG9iXCIgfSkucGlwZShcclxuICAgICAgY2F0Y2hFcnJvcigoZXJyLCBjYXVnaHQpOiBPYnNlcnZhYmxlPHN0cmluZz4gPT4ge1xyXG4gICAgICAgIGlmIChhZnRlckdldEZpbGUgJiYgIWhhbmRsZUVycm9yKSBhZnRlckdldEZpbGUoKTtcclxuICAgICAgICByZXR1cm4gdGhpcy5yZWdpc3RlckVycm9yQW5kUmV0dXJuRW1wdHlPYnNlcnZhYmxlKGVyciwgbXlHdWlkLCBoYW5kbGVFcnJvcik7XHJcbiAgICAgIH0pLFxyXG4gICAgICBmaW5hbGl6ZSgoKSA9PiB7IHRoaXMudHJ5RmluYWxpemVCeUd1aWQobXlHdWlkKTsgfSlcclxuICAgICkuc3Vic2NyaWJlKChyZXNwb25zZTogSHR0cFJlc3BvbnNlPEJsb2I+KSA9PiB7XHJcbiAgICAgIGxldCByZXRVcmwgPSB3aW5kb3cuVVJMLmNyZWF0ZU9iamVjdFVSTChyZXNwb25zZS5ib2R5KTtcclxuICAgICAgbGV0IGZuID0gcmVzcG9uc2UuaGVhZGVycy5nZXQoJ2NvbnRlbnQtZGlzcG9zaXRpb24nKT8uc3BsaXQoJzsnKVsxXT8uc3BsaXQoJ2ZpbGVuYW1lJylbMV0/LnNwbGl0KCc9JylbMV0/LnRyaW0oKS5yZXBsYWNlKC9cXFwiL2csICcnKTtcclxuXHJcbiAgICAgIGdldEZpbGVDYWxsYmFjayhyZXRVcmwsIGZpbGVuYW1lIHx8IGZuKTtcclxuICAgICAgaWYgKGFmdGVyR2V0RmlsZSkgYWZ0ZXJHZXRGaWxlKCk7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIERvd25sb2FkIG5hdGl2byBkaSB1biBmaWxlLiBJbnRlcm5hbWVudGUgdXRpbGl6emEgaWwgcGF0dGVybiAqKndpbmRvdy5sb2NhdGlvbi5ocmVmID0gXCIuLi5cIioqXHJcbiAgICogXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHVybCBVUkwgc3UgY3VpIGVmZmV0dHVhcmUgbGEgY2hpYW1hdGFcclxuICAgKiBAcGFyYW0ge0h0dHBQYXJhbXN9IHBhcmFtcyBQYXJhbWV0cmkgZGVsbGEgY2hpYW1hdGFcclxuICAgKi9cclxuICBwdWJsaWMgZ2V0RmlsZU5hdGl2ZSh1cmw6IHN0cmluZywgcGFyYW1zOiBIdHRwUGFyYW1zID0gbnVsbCk6IHZvaWQge1xyXG5cclxuICAgIC8vIEVuY29kbyB0dXR0aSBpIHBhcmFtZXRyaSBwZXIgZXZpdGFyZSBjYXNpIHBhcnRpY29sYXJpXHJcbiAgICAvLyB2YXIgZW5jb2RlZFBhcmFtcyA9IG5ldyBIdHRwUGFyYW1zKCk7XHJcbiAgICAvLyBsZXQgcGFyS2V5cyA9IHBhcmFtcy5rZXlzKCk7XHJcbiAgICAvLyBmb3IgKGxldCBpID0gMDsgaSA8IHBhcktleXMubGVuZ3RoOyBpKyspXHJcbiAgICAvLyAgIGVuY29kZWRQYXJhbXMgPSBlbmNvZGVkUGFyYW1zLnNldChwYXJLZXlzW2ldLCBlbmNvZGVVUklDb21wb25lbnQocGFyYW1zLmdldChwYXJLZXlzW2ldKSkpO1xyXG5cclxuICAgIGxldCBmaW5hbFVybCA9IHVybCArIChwYXJhbXMgPyBcIj9cIiArIHBhcmFtcy50b1N0cmluZygpLnJlcGxhY2UoL1xcKy9nLCAnJTJiJykgOiBcIlwiKTtcclxuICAgIHdpbmRvdy5sb2NhdGlvbi5ocmVmID0gZmluYWxVcmw7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBFc2VjdXppb25lIGRpIHVuYSBHRVQgZGkgdW4gZmlsZSBjaGUgZW1ldHRlIGkgdmFyaSBldmVudGkgZGkgcHJvZ3Jlc3NvIGRpIGRvd25sb2FkLlxyXG4gICAqIFV0aWxpenphcmxhIHBlciBvdmVycmlkYXJlIGxhIGRpYWxvZyBuYXRpdmEgZGkgcHJvZ3Jlc3MgZGVsIGJyb3dzZXIgZSBzb3N0aXR1aXJsYSBjb24gcXVhbGNvc2EgdGlwbyBxdWVsbG8gY2hlIGZhIE1FR0EuXHJcbiAgICogXHJcbiAgICogSW4gY2FzbyBzaSB2b2dsaWEgb3R0ZW5lcmUgaWwgcmlzdWx0YXRvIG5hdGl2byBkZWwgYnJvd3NlciBkZWwgZG93bmxvYWQgdXRpbGl6emFyZSAqKmdldEZpbGVOYXRpdmUodXJsLCBwYXJzKSoqXHJcbiAgICogXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHVybCBVUkwgc3UgY3VpIGVmZmV0dHVhcmUgbGEgY2hpYW1hdGFcclxuICAgKiBAcGFyYW0ge0h0dHBQYXJhbXN9IHBhcmFtcyBQYXJhbWV0cmkgZGVsbGEgY2hpYW1hdGFcclxuICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBnZXRGaWxlQ2FsbGJhY2sgQ2FsbGJhY2sgYSBkdWUgcGFyYW1ldHJpICh1cmw6IHN0cmluZywgZmlsZW5hbWU6IHN0cmluZykgcGVyIGdlc3RpcmUgaWwgcmlzdWx0YXRvIGRlbCBmaWxlIHJpY2hpZXN0by4gKipVdGlsaXp6YXJlIFV0aWxpdHlTZXJ2aWNlLmZpbGVEb3dubG9hZCoqIGRpIEBlc2ZhZW56YS9leHRlbnNpb25zXHJcbiAgICogXHJcbiAgICogQHJldHVybnMge09ic2VydmFibGU8RG93bmxvYWQ+fSBPYnNlcnZhYmxlIGRlaSB2YXJpIHN0ZXAgZGkgcHJvZ3Jlc3NvIGRlbCBkb3dubG9hZFxyXG4gICAqL1xyXG4gIHB1YmxpYyBnZXRGaWxlV2l0aFByb2dyZXNzKHVybDogc3RyaW5nLCBwYXJhbXM6IEh0dHBQYXJhbXMgPSBudWxsLCBnZXRGaWxlQ2FsbGJhY2s6ICh1cmw6IHN0cmluZywgZmlsZW5hbWU6IHN0cmluZykgPT4gYW55KTogT2JzZXJ2YWJsZTxEb3dubG9hZD4ge1xyXG4gICAgcmV0dXJuIGZvcmtKb2luKFxyXG4gICAgICB7XHJcbiAgICAgICAgbXlHdWlkOiBmcm9tKFt0aGlzLmRlZmF1bHRTdGFydENhbGwodXJsKV0pLFxyXG4gICAgICAgIGxvY2FsZTogdGhpcy5iYy5Mb2NhbGUucGlwZShmaXJzdCgpKVxyXG4gICAgICB9KS5waXBlKFxyXG4gICAgICAgIGNvbmNhdE1hcCgocmV0OiB7IG15R3VpZDogc3RyaW5nLCBsb2NhbGU6IHN0cmluZyB9KSA9PiB7XHJcblxyXG4gICAgICAgICAgcmV0dXJuIHRoaXMuaHR0cC5nZXQodXJsLCB7IHJlc3BvbnNlVHlwZTogJ2Jsb2InLCBoZWFkZXJzOiB0aGlzLmdldEhlYWRlcnMocmV0LmxvY2FsZSksIHBhcmFtczogcGFyYW1zLCBvYnNlcnZlOiAnZXZlbnRzJywgcmVwb3J0UHJvZ3Jlc3M6IHRydWUgfSlcclxuICAgICAgICAgICAgLnBpcGUoXHJcbiAgICAgICAgICAgICAgc2NhbigocHJldmlvdXM6IERvd25sb2FkLCBldmVudDogSHR0cEV2ZW50PEJsb2I+KTogRG93bmxvYWQgPT4ge1xyXG5cclxuICAgICAgICAgICAgICAgIGlmICh0aGlzLmlzSHR0cFByb2dyZXNzRXZlbnQoZXZlbnQpKSB7XHJcbiAgICAgICAgICAgICAgICAgIGxldCBwcm9ncmVzcyA9IGV2ZW50LnRvdGFsID8gKGV2ZW50LmxvYWRlZCA+IGV2ZW50LnRvdGFsID8gMTAwIDogTWF0aC5yb3VuZCgoMTAwICogZXZlbnQubG9hZGVkKSAvIGV2ZW50LnRvdGFsKSkgOiBwcmV2aW91cy5wcm9ncmVzcztcclxuICAgICAgICAgICAgICAgICAgcmV0dXJuIHsgcHJvZ3Jlc3M6IHByb2dyZXNzLCBzdGF0ZTogJ0lOX1BST0dSRVNTJywgY29udGVudDogbnVsbCB9XHJcbiAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuaXNIdHRwUmVzcG9uc2UoZXZlbnQpKSB7XHJcbiAgICAgICAgICAgICAgICAgIGlmIChldmVudC5ib2R5KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgbGV0IGNkaXNwID0gZXZlbnQuaGVhZGVycy5nZXQoJ2NvbnRlbnQtZGlzcG9zaXRpb24nKTtcclxuICAgICAgICAgICAgICAgICAgICBsZXQgY2Rpc3BGaWxlbmFtZSA9IGNkaXNwLnNwbGl0KCc7JylbMV0uc3BsaXQoJ2ZpbGVuYW1lJylbMV0uc3BsaXQoJz0nKVsxXS50cmltKCkucmVwbGFjZSgvXFxcIi9nLCAnJyk7XHJcbiAgICAgICAgICAgICAgICAgICAgbGV0IHJldFVybCA9IHdpbmRvdy5VUkwuY3JlYXRlT2JqZWN0VVJMKGV2ZW50LmJvZHkpO1xyXG4gICAgICAgICAgICAgICAgICAgIGdldEZpbGVDYWxsYmFjayhyZXRVcmwsIGNkaXNwRmlsZW5hbWUpO1xyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgIHJldHVybiB7IHByb2dyZXNzOiAxMDAsIHN0YXRlOiAnRE9ORScsIGNvbnRlbnQ6IGV2ZW50LmJvZHkgfVxyXG4gICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgIHJldHVybiBwcmV2aW91cztcclxuICAgICAgICAgICAgICB9LCB7IHN0YXRlOiAnUEVORElORycsIHByb2dyZXNzOiAwLCBjb250ZW50OiBudWxsIH0pLFxyXG4gICAgICAgICAgICAgIGNhdGNoRXJyb3IoKGVyciwgXyk6IE9ic2VydmFibGU8RG93bmxvYWQ+ID0+IHsgcmV0dXJuIHRoaXMucmVnaXN0ZXJFcnJvckFuZFJldHVybkVtcHR5T2JzZXJ2YWJsZShlcnIsIHJldC5teUd1aWQpIH0pLFxyXG4gICAgICAgICAgICAgIGZpbmFsaXplKCgpID0+IHsgdGhpcy50cnlGaW5hbGl6ZUJ5R3VpZChyZXQubXlHdWlkKTsgfSlcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICB9KVxyXG4gICAgICApO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogUmljb25vc2NlIHNlIGwnZXZlbnRvIEhUVFAgw6ggZGkgdGlwbyAqKkh0dHBSZXNwb25zZSoqIGUsIHNlIHPDrCwgbG8gY2FzdGEgYWwgdGlwbyBjb3JyZXR0byBwZXIgZXNzZXJlIHV0aWxpenphdG8gY29ycmV0dGFtZW50ZSBuZWwgYmxvY2NvIGRpIGNvZGljZSBzdWNjZXNzaXZvXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBpc0h0dHBSZXNwb25zZTxUPihldmVudDogSHR0cEV2ZW50PFQ+KTogZXZlbnQgaXMgSHR0cFJlc3BvbnNlPFQ+IHtcclxuICAgIHJldHVybiBldmVudC50eXBlID09PSBIdHRwRXZlbnRUeXBlLlJlc3BvbnNlXHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBSaWNvbm9zY2Ugc2UgbCdldmVudG8gSFRUUCDDqCBkaSB0aXBvICoqSHR0cFByb2dyZXNzRXZlbnQqKiBlLCBzZSBzw6wsIGxvIGNhc3RhIGFsIHRpcG8gY29ycmV0dG8gcGVyIGVzc2VyZSB1dGlsaXp6YXRvIGNvcnJldHRhbWVudGUgbmVsIGJsb2NjbyBkaSBjb2RpY2Ugc3VjY2Vzc2l2b1xyXG4gICAqL1xyXG4gIHByaXZhdGUgaXNIdHRwUHJvZ3Jlc3NFdmVudChldmVudDogSHR0cEV2ZW50PHVua25vd24+KTogZXZlbnQgaXMgSHR0cFByb2dyZXNzRXZlbnQge1xyXG4gICAgcmV0dXJuIGV2ZW50LnR5cGUgPT09IEh0dHBFdmVudFR5cGUuRG93bmxvYWRQcm9ncmVzcyB8fCBldmVudC50eXBlID09PSBIdHRwRXZlbnRUeXBlLlVwbG9hZFByb2dyZXNzXHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBHZXN0aW9uZSBkZWxsJ2luaXppbyBkaSB1bmEgY2hpYW1hdGEgYWQgdW4gY2VydG8gVVJMLCB2aWVuZSBnZW5lcmF0byB1biBHVUlEIGRhIGFzc2VnbmFyY2ksIGNvbnRyb2xsYXRhIGxhIHNjYWRlbnphIGRlbGxhIGNhY2hlLCBcclxuICAgKiBlIGV2ZW50dWFsbWVudGUgbG9nZ2F0byBpbCBmYXR0byBjaGUgc3RhIHBlciBlc3NlcmUgZWZmZXR0dWF0YSB1bmEgY2hpYW1hdGEgSFRUUFxyXG4gICAqIFxyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgVXJsIGEgY3VpIGVmZmV0dHVhcmUgbGEgY2hpYW1hdGFcclxuICAgKiBAcmV0dXJucyB7c3RyaW5nfSBHVUlEIGFzc2VnbmF0byBhbGxhIGNoaWFtYXRhXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBkZWZhdWx0U3RhcnRDYWxsKHVybDogc3RyaW5nKTogc3RyaW5nIHtcclxuICAgIGxldCBteUd1aWQgPSB0aGlzLmdldEdVSUQoKTtcclxuICAgIHRoaXMuY2hlY2tDYWNoZUludmFsaWRhdGlvbih1cmwpO1xyXG4gICAgdGhpcy5jYWxsU3RhdHVzW215R3VpZF0gPSB7IHVybDogdXJsLCBzdWNjZXNzOiB0cnVlIH07XHJcbiAgICB0aGlzLmxvZyh0aGlzLmxvYyhcIlN0YXJ0aW5nIGNhbGxcIikgKyBcIiBcIiArIG15R3VpZCArIFwiIFwiICsgdGhpcy5sb2MoXCJhdCBVUkxcIikgKyBcIjogXCIgKyB1cmwpO1xyXG4gICAgcmV0dXJuIG15R3VpZDtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIERhdG8gdW4gdXJsIHZlbmdvbm8gY29udHJvbGxhdGUgbGUgaW5mb3JtYXppb25pIHN1IHR1dHRpIGdsaSB1cmwgZGEgaW52YWxpZGFyZSBjb2xsZWdhdGkgYWxsJ3VybCBjaGlhbWF0byBlLCBzZSBwcmVzZW50aSBpbiBjYWNoZSwgaW52YWxpZGF0aVxyXG4gICAqIFxyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgVVJMIHBlciBjdWkgY29udHJvbGxhcmUgc2UgY2kgc29ubyBjaGlhbWF0ZSBpbiBjYWNoZSBkYSBpbnZhbGlkYXJlXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBjaGVja0NhY2hlSW52YWxpZGF0aW9uKHVybDogc3RyaW5nKSB7XHJcbiAgICBpZighdGhpcy5DYWNoZUluaXRpYWxpemVkKVxyXG4gICAgICByZXR1cm47XHJcblxyXG4gICAgbGV0IGNhY2hlID0gdGhpcy5sb2NhbFN0b3JhZ2UuZ2V0TG9jYWxJdGVtPGFueT4odGhpcy5sb2NhbFN0b3JhZ2VIdHRwQ2FjaGVLZXkpO1xyXG4gICAgbGV0IHRtcCA9IC8jY2FjaGUoOj8tKFxcZCspKS9naS5leGVjKHVybCk7XHJcbiAgICBsZXQgY2FjaGVUaW1lID0gdG1wID8gdG1wWzJdIDogbnVsbDtcclxuICAgIGxldCBub3JtYWxpemVkVXJsX3RtcCA9IHVybC5yZXBsYWNlKFwiI2NhY2hlXCIgKyAoY2FjaGVUaW1lID8gXCItXCIgKyBjYWNoZVRpbWUgOiBcIlwiKSwgXCJcIik7XHJcbiAgICBsZXQgbm9ybWFsaXplZFVybCA9IG5vcm1hbGl6ZWRVcmxfdG1wLnN1YnN0cmluZyhub3JtYWxpemVkVXJsX3RtcC5pbmRleE9mKCcvYXBpJykpXHJcblxyXG4gICAgaWYgKCFjYWNoZSB8fCAhdGhpcy5IVFRQX0lOVkFMSURBVElPTiB8fCAhdGhpcy5IVFRQX0lOVkFMSURBVElPTltub3JtYWxpemVkVXJsXSlcclxuICAgICAgcmV0dXJuO1xyXG5cclxuICAgIGxldCBhcGlzVG9JbnZhbGlkYXRlOiBzdHJpbmdbXSA9IHRoaXMuSFRUUF9JTlZBTElEQVRJT05bbm9ybWFsaXplZFVybF07XHJcbiAgICBpZiAoIWFwaXNUb0ludmFsaWRhdGUgfHwgYXBpc1RvSW52YWxpZGF0ZS5sZW5ndGggPT0gMClcclxuICAgICAgcmV0dXJuO1xyXG5cclxuICAgIGxldCBrZXlzVG9SZW1vdmU6IHN0cmluZ1tdID0gW107XHJcbiAgICBhcGlzVG9JbnZhbGlkYXRlLmZvckVhY2goYXBpID0+IHtcclxuICAgICAgbGV0IGNhY2hlS2V5ID0gdGhpcy5tYWtlQ2FjaGVLZXkoYXBpLCBudWxsKTtcclxuICAgICAgZm9yIChsZXQgaXRlbSBpbiBjYWNoZSlcclxuICAgICAgICBpZiAoaXRlbS5pbmRleE9mKGNhY2hlS2V5KSAhPSAtMSlcclxuICAgICAgICAgIGtleXNUb1JlbW92ZS5wdXNoKGl0ZW0pO1xyXG4gICAgfSk7XHJcblxyXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBrZXlzVG9SZW1vdmUubGVuZ3RoOyBpKyspIHtcclxuICAgICAgbGV0IGsgPSBrZXlzVG9SZW1vdmVbaV07XHJcbiAgICAgIHRoaXMubG9nKHRoaXMubG9jKFwiSW52bGFsaWRhdGluZyBjYWNoZSBlbGVtZW50XCIpICsgXCIgXCIgKyBrKTtcclxuICAgICAgZGVsZXRlIGNhY2hlW2tdO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMubG9jYWxTdG9yYWdlLnNldEl0ZW0odGhpcy5sb2NhbFN0b3JhZ2VIdHRwQ2FjaGVLZXksIGNhY2hlKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEZpbmFsaXp6YXppb25lIGRpIHVuYSBjaGlhbWF0YVxyXG4gICAqIFxyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBndWlkIEdVSUQgY29sbGVnYXRvIGFsbGEgY2hpYW1hdGEgYXBwZW5hIHRlcm1pbmF0YVxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gcGVyc2lzdENhY2hlSWZJZGxlIEVmZmV0dHVhIGlsIHBlcnNpc3QgZGVsbGEgY2FjaGUgSFRUUCBzb2xvIHNlIG5vbiBjaSBzb25vIGFsdHJlIGNoaWFtYXRlIGluIGNvcnNvLCBwZXIgZXZpdGFyZVxyXG4gICAqIGNoZSBtaSBjYW1iaSBzb3R0byBsJ29nZ2V0dG8gZGkgY2FjaGUgbWVudHJlIHN0byBzYWx2YW5kbyBsZSBpbmZvcm1hemlvbmlcclxuICAgKi9cclxuICBwcml2YXRlIGFzeW5jIHRyeUZpbmFsaXplQnlHdWlkKGd1aWQ6IHN0cmluZywgY2FjaGVJbmZvcz86IENhY2hlSW5mb3MpIHtcclxuICAgIHRoaXMubG9nKHRoaXMubG9jKFwiRmluYWxpemluZyBjYWxsXCIpICsgXCIgXCIgKyBndWlkICsgXCIgXCIgKyB0aGlzLmxvYyhcIndpdGggc3RhdHVzXCIpICsgXCI6IFwiICsgKCF0aGlzLmNhbGxTdGF0dXNbZ3VpZF0gPyAnVW5rbm93bicgOiB0aGlzLmNhbGxTdGF0dXNbZ3VpZF0uc3VjY2VzcyA/IHRoaXMubG9jKCdTdWNjZXNzJykgOiB0aGlzLmxvYygnRmFpbHVyZScpKSk7XHJcblxyXG4gICAgLy8gVE9ETzogUGVyZGVyZSAzLTQgb3JlIHBlciBjYXBpcmUgcGVyY2jDqSBvZ25pIHRhbnRvIGFycml2YSBudWxsIGluIGNhc2kgcGVzYW50aSBkaSBPYnNlcnZhYmxlIHNwYW1tYXRpIGEgcmFuZG9tXHJcbiAgICBpZiAodGhpcy5jYWxsU3RhdHVzW2d1aWRdKSB7XHJcbiAgICAgIC8vIEFsbGEgcHJpbWEgY2hpYW1hdGEgYnVvbmEsIHNpZ25pZmljYSBjaGUgYWxtZW5vIGlsIGxvZ2luIGNlIGwnaG8uIFBvc3NvIG1ldHRlcm1pIGluIG1vZGFsaXTDoCByZWRpcmVjdEluUHJvZ3Jlc3MgZmFsc2VcclxuICAgICAgLy8gZSByaWluaXppYXJlIGEgdmFsdXRhcmUgZXJyb3JpIGRpIGphdmFzaGl0XHJcbiAgICAgIGlmICh0aGlzLmNhbGxTdGF0dXNbZ3VpZF0uc3VjY2VzcyAmJiB0aGlzLkV4dGVuc2lvbnNJbXBsLnJlYWRSZWRpcmVjdGlvblN0YXR1cygpKVxyXG4gICAgICAgIHRoaXMuRXh0ZW5zaW9uc0ltcGwud3JpdGVSZWRpcmVjdGlvblN0YXR1cyhmYWxzZSk7XHJcblxyXG4gICAgICAvLyBBZ2dpdW5nbyBsYSBjaGlhbWF0YSBhbGxhIGxpc3RhIGRlbGxlIHVsdGltZSAzIGNvbXBsZXRhdGVcclxuICAgICAgdGhpcy5MYXN0VGhyZWVDb21wbGV0ZWRDYWxscy51bnNoaWZ0KHRoaXMuY2FsbFN0YXR1c1tndWlkXS51cmwpXHJcbiAgICAgIGlmICh0aGlzLkxhc3RUaHJlZUNvbXBsZXRlZENhbGxzLmxlbmd0aCA+IDMpXHJcbiAgICAgICAgdGhpcy5MYXN0VGhyZWVDb21wbGV0ZWRDYWxscy5wb3AoKTtcclxuXHJcbiAgICAgIC8vIEluIG9nbmkgY2FzbyBxdWVzdGEgcG9zc28gcmltdW92ZXJsYVxyXG4gICAgICBkZWxldGUgdGhpcy5jYWxsU3RhdHVzW2d1aWRdO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNlIG5vbiBobyBuZXNzdW4nYWx0cmEgY2hpYW1hdGEgaW4gY29yc28gY29uc2lkZXJvIGxhIHNpdHVhemlvbmUgc3RhYmlsaXp6YXRhc2lcclxuICAgIGlmIChPYmplY3Qua2V5cyh0aGlzLmNhbGxTdGF0dXMpLmxlbmd0aCA9PSAwKVxyXG4gICAgICB0aGlzLlN0YWJpbGl6ZWQubmV4dCh0cnVlKTtcclxuXHJcbiAgICAvLyBTZSB2ZW5nbyBkYSB1bmEgY2hpYW1hdGEgY2hlIGhhIGFnZ2lvcm5hdG8gbGEgY2FjaGUgYSB0aW1lciBvIGdsb2JhbGUgbWFyY28gaWwgZmF0dG8gY2hlIHF1ZWxsYSBjYWNoZSBkZXYnZXNzZXJlIGFnZ2lvcm5hdGFcclxuICAgIGlmIChjYWNoZUluZm9zICYmIGNhY2hlSW5mb3MuY2FjaGUpIHtcclxuICAgICAgdGhpcy5QZXJzaXN0VGltZWRDYWNoZUFTQVAgPSB0aGlzLlBlcnNpc3RUaW1lZENhY2hlQVNBUCB8fCAhIWNhY2hlSW5mb3MuY2FjaGVUaW1lO1xyXG4gICAgICB0aGlzLlBlcnNpc3RVbnRpbWVkQ2FjaGVBU0FQID0gdGhpcy5QZXJzaXN0VGltZWRDYWNoZUFTQVAgfHwgIWNhY2hlSW5mb3MuY2FjaGVUaW1lO1xyXG4gICAgICB0aGlzLmxvZyh0aGlzLmxvYyhcIk1hcmtpbmcgY2FjaGUgdG8gYmUgcGVyc2lzdGVkIGFzIHNvb24gYXMgcG9zc2libGVcIikpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNlIHVuYSBkZWxsZSBkdWUgY2FjaGUgZGV2b25vIGVzc2VyZSBhZ2dpb3JuYXRlIGUgbm9uIGhvIG5lc3N1bmEgY2hpYW1hdGEgaW4gY29yc28gZWZmZXR0dW8gbCdhZ2dpb3JuYW1lbnRvIGluIGJhc2UgYSBxdWFsZSBkZWxsZSBkdWUgdmEgYWdnaW9ybmF0YVxyXG4gICAgLy8gQWxsYSBmaW5lIGRpIHR1dHRvIG1hcmNvIGNvbWUgZmF0dG9cclxuICAgIGlmICgodGhpcy5QZXJzaXN0VGltZWRDYWNoZUFTQVAgfHwgdGhpcy5QZXJzaXN0VW50aW1lZENhY2hlQVNBUCkgJiYgT2JqZWN0LmtleXModGhpcy5jYWxsU3RhdHVzKS5sZW5ndGggPT0gMCAmJiB0aGlzLkNhY2hlSW5pdGlhbGl6ZWQpIHtcclxuXHJcbiAgICAgIHZhciB0b0NhbGwgPSBbXTtcclxuICAgICAgbGV0IHRtcEtleSA9IFwiXCI7XHJcbiAgICAgIGlmICh0aGlzLlBlcnNpc3RUaW1lZENhY2hlQVNBUCkge1xyXG4gICAgICAgIHRtcEtleSA9IHRoaXMubG9jYWxTdG9yYWdlSHR0cFRpbWVkQ2FjaGVLZXk7XHJcbiAgICAgICAgdG9DYWxsLnB1c2godGhpcy5sb2NhbFN0b3JhZ2Uuc2V0SXRlbSh0bXBLZXksIHRoaXMubG9jYWxTdG9yYWdlLmdldExvY2FsSXRlbSh0bXBLZXkpKSk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmICh0aGlzLlBlcnNpc3RVbnRpbWVkQ2FjaGVBU0FQKSB7XHJcbiAgICAgICAgdG1wS2V5ID0gdGhpcy5sb2NhbFN0b3JhZ2VIdHRwQ2FjaGVLZXk7XHJcbiAgICAgICAgdG9DYWxsLnB1c2godGhpcy5sb2NhbFN0b3JhZ2Uuc2V0SXRlbSh0bXBLZXksIHRoaXMubG9jYWxTdG9yYWdlLmdldExvY2FsSXRlbSh0bXBLZXkpKSk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHRoaXMubG9nKHRoaXMubG9jKFwiTm8gbW9yZSBIVFRQIGNhbGxzIHRvIGJlIGV4ZWN1dGVkLCBlbnRlcmluZyBpZGxlIHN0YXRlIGFuZCBwZXJzaXN0aW5nIG1vZGlmaWVkIGNhY2hlc1wiKSArIFwiLi4uXCIpO1xyXG5cclxuICAgICAgdmFyIHJldCA9IGF3YWl0IGZvcmtKb2luKHRvQ2FsbCkudG9Qcm9taXNlKCk7XHJcbiAgICAgIGlmIChyZXQpXHJcbiAgICAgICAgdGhpcy5sb2codGhpcy5sb2MoXCJDYWNoZXMgc3VjY2VzZnVsbHkgcGVyc2lzdGVkXCIpKTtcclxuICAgICAgZWxzZVxyXG4gICAgICAgIHRoaXMubG9nKHRoaXMubG9jKFwiRXJyb3JzIHBlcnNpc3RpbmcgbW9kaWZpZWQgY2FjaGVzXCIpKTtcclxuICAgICAgdGhpcy5QZXJzaXN0VGltZWRDYWNoZUFTQVAgPSBmYWxzZTtcclxuICAgICAgdGhpcy5QZXJzaXN0VW50aW1lZENhY2hlQVNBUCA9IGZhbHNlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogSGVscGVyIGNoZSBkYXRvIHVuIHVuaWNvIEZpbGUgbyB1bmEgbGlzdGEgZGkgRmlsZSBjcmVhIHVuIG9nZ2V0dG8gRm9ybURhdGEgY2hlIHB1w7IgZXNzZXJlIGludmlhdG8gY29tb2RhbWVudGUgXHJcbiAgICogYWQgdW4gYmFja2VuZCBBU1AuTkVUIGRhIGN1aSBzaSBwb3Ryw6AgYWNjZWRlcmUgYSBSZXF1ZXN0LkZvcm0uRmlsZXNcclxuICAgKiBcclxuICAgKiBAcGFyYW0ge0ZpbGUgfCBGaWxlW119IGZpbGVBcnJheU9yRmlsZSBTaW5nb2xvIEZpbGUgbyBsaXN0YSBkaSBGaWxlLiBOLkI6IG5lbGxhIGZpcm1hIGRlbGxhIGZ1bnppb25lIHZpZW5lIGNvbnNpZGVyYXRvICoqYW55KiogcGVyIGZhcmUgdGVzdCBzdWxsZSBwcm9wcmlldMOgIFxyXG4gICAqIGludmVjZSBjaGUgZmFyZSB0ZXN0IGNvbiBsJyoqaXN0YW5jZW9mKipcclxuICAgKiBcclxuICAgKiBAcmV0dXJucyB7Rm9ybURhdGF9IEZvcm1EYXRhIGNvbnRlbmVudGUgdHV0dGkgaSBmaWxlIHBhc3NhdGlcclxuICAgKi9cclxuICBwcml2YXRlIGdldEZpbGVzRm9ybURhdGEoZmlsZUFycmF5T3JGaWxlOiBhbnkpOiBGb3JtRGF0YSB7XHJcbiAgICB2YXIgZm9ybURhdGE6IEZvcm1EYXRhID0gbmV3IEZvcm1EYXRhKCk7XHJcblxyXG4gICAgaWYgKGZpbGVBcnJheU9yRmlsZSkge1xyXG4gICAgICBpZiAoZmlsZUFycmF5T3JGaWxlLmxlbmd0aClcclxuICAgICAgICBmaWxlQXJyYXlPckZpbGUuZm9yRWFjaCh0ID0+IHsgZm9ybURhdGEuYXBwZW5kKFwiZmlsZVwiLCB0LCB0Lm5hbWUpOyB9KTtcclxuICAgICAgZWxzZSBpZiAoZmlsZUFycmF5T3JGaWxlLm5hbWUpXHJcbiAgICAgICAgZm9ybURhdGEuYXBwZW5kKFwiZmlsZXNcIiwgZmlsZUFycmF5T3JGaWxlLCBmaWxlQXJyYXlPckZpbGUubmFtZSk7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIGZvcm1EYXRhO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogSGVscGVyIGNoZSBpbiBiYXNlIGFpIHBhcmFtZXRyaSBkaXNwb25pYmlsaSBnZW5lcmEgZ2xpIEhlYWRlciBIVFRQIHBlciBsYSBjaGlhbWF0YSBkYSBlZmZldHR1YXJlXHJcbiAgICogXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IGNvbnRlbnRUeXBlIEluZGljYSBzZSBhZ2dpdW5nZXJlIGFnbGkgaGVhZGVyIFwiQ29udGVudC1UeXBlXCIsIHZhbG9yaXp6YXRvIGFsIHZhbG9yZSBkZWwgcGFyYW1ldHJvXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IGFjY2VwdCBJbmRpY2Egc2UgYWdnaXVuZ2VyZSBhZ2xpIGhlYWRlciBcIkFjY2VwdFwiLCB2YWxvcml6emF0byBhbCB2YWxvcmUgZGVsIHBhcmFtZXRyb1xyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gaW5jbHVkZUF1dGggSW5kaWNhIHNlIGFnZ2l1bmdlcmUgYWdsaSBoZWFkZXIgXCJBdXRob3JpemF0aW9uXCIsIHZhbG9yaXp6YXRvIGNvbCB0b2tlbiByZWN1cGVyYXRvIGRhbGwnaG9vayAqKnJldHJpZXZlQWNjZXNzVG9rZW4qKiBkZWxsYSBjbGFzc2UgZGkgZXN0ZW5zaW9uZVxyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0cmFuc2FjdGlvbklkIEluZGljYSBzZSBhZ2dpdW5nZXJlIGFnbGkgaGVhZGVyIFwiWC1UWC1JRFwiLCB2YWxvcml6emF0byBhbCB2YWxvcmUgZGVsIHBhcmFtZXRyb1xyXG4gICAqIFxyXG4gICAqIEByZXR1cm5zIHtIdHRwSGVhZGVyc30gSGVhZGVyIGdlbmVyYXRpIGluIGJhc2UgYWkgcGFyYW1ldHJpXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBnZXRIZWFkZXJzKGxvY2FsZSA9ICdpdC1JVCcsIHRyYW5zYWN0aW9uSWQgPSBcIlwiLCBpbmNsdWRlQXV0aDogYm9vbGVhbiA9IHRydWUsIGNvbnRlbnRUeXBlOiBzdHJpbmcgPSBcImFwcGxpY2F0aW9uL2pzb25cIiwgYWNjZXB0OiBzdHJpbmcgPSBcImFwcGxpY2F0aW9uL2pzb25cIik6IEh0dHBIZWFkZXJzIHtcclxuICAgIHZhciBoZWFkZXJzID0gbmV3IEh0dHBIZWFkZXJzKCk7XHJcbiAgICB2YXIgYXV0aHRva2VuID0gdGhpcy5FeHRlbnNpb25zSW1wbC5yZXRyaWV2ZUFjY2Vzc1Rva2VuKCk7XHJcblxyXG4gICAgaGVhZGVycyA9IGhlYWRlcnMuYXBwZW5kKFwibmdzdy1ieXBhc3NcIiwgXCJcIik7XHJcblxyXG4gICAgaWYgKGNvbnRlbnRUeXBlKVxyXG4gICAgICBoZWFkZXJzID0gaGVhZGVycy5hcHBlbmQoXCJDb250ZW50LVR5cGVcIiwgY29udGVudFR5cGUpO1xyXG5cclxuICAgIGlmICh0cmFuc2FjdGlvbklkKVxyXG4gICAgICBoZWFkZXJzID0gaGVhZGVycy5hcHBlbmQoXCJYLVRYLUlEXCIsIHRyYW5zYWN0aW9uSWQpO1xyXG5cclxuICAgIGlmIChhdXRodG9rZW4gJiYgaW5jbHVkZUF1dGgpXHJcbiAgICAgIGhlYWRlcnMgPSBoZWFkZXJzLmFwcGVuZChcIkF1dGhvcml6YXRpb25cIiwgXCJCZWFyZXIgXCIgKyBhdXRodG9rZW4pO1xyXG5cclxuICAgIGlmIChhY2NlcHQpXHJcbiAgICAgIGhlYWRlcnMgPSBoZWFkZXJzLmFwcGVuZChcIkFjY2VwdFwiLCBhY2NlcHQpO1xyXG5cclxuICAgIGhlYWRlcnMgPSBoZWFkZXJzLmFwcGVuZChcIkFjY2VwdC1MYW5ndWFnZVwiLCBsb2NhbGUpO1xyXG4gICAgcmV0dXJuIGhlYWRlcnM7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBHZXN0aW9uZSBkaSBkZWZhdWx0IGRlZ2xpIGVycm9yaVxyXG4gICAqIFxyXG4gICAqIEBwYXJhbSB7YW55fSByZXMgUmlzdWx0YXRvIGRlbGxhIGNoaWFtYXRhIGVmZmV0dHVhdGFcclxuICAgKiBAcGFyYW0ge3N0cmluZ30gZ3VpZCBJZGVudGlmaWNhdGl2byBHVUlEIGRlbGxhIGNoaWFtYXRhIGVmZmV0dHVhdGFcclxuICAgKi9cclxuICBwcml2YXRlIGFzeW5jIG9uRXJyb3IocmVzOiBIdHRwRXJyb3JSZXNwb25zZSB8IFR5cGVFcnJvciwgZ3VpZDogc3RyaW5nKSB7XHJcbiAgICBpZiAodGhpcy5jYWxsU3RhdHVzW2d1aWRdKVxyXG4gICAgICB0aGlzLmNhbGxTdGF0dXNbZ3VpZF0uc3VjY2VzcyA9IGZhbHNlO1xyXG5cclxuICAgIC8vTWkgYXNzaWN1cm8gY2hlIHR1dHRpIGdsaSBlcnJvcmkgZHVyYW50ZSBpbCByZWRpcmVjdCBhbCBsb2dpbiB2ZW5nYW5vIGlnbm9yYXRpXHJcbiAgICBpZiAodGhpcy5FeHRlbnNpb25zSW1wbC5yZWFkUmVkaXJlY3RpbmdUb0xvZ2luKCkpIHtcclxuICAgICAgdGhpcy5sb2codGhpcy5sb2MoXCJSZWRpcmVjdGluZyB0byBMb2dpbiwgaWdub3JpbmcgSFRUUCBlcnJvciBvbiBjYWxsXCIpICsgXCIgXCIgKyBndWlkKTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIC8vTWkgYXNzaWN1cm8gY2hlIHZlbmdhIGdlc3RpdG8gdW4gc29sbyBlcnJvcmUgcGVyIHZvbHRhXHJcbiAgICBpZiAodGhpcy5FeHRlbnNpb25zSW1wbC5yZWFkSGFuZGxpbmdFcnJvclN0YXR1cygpKSB7XHJcbiAgICAgIHRoaXMubG9nKHRoaXMubG9jKFwiQWxyZWFkeSBIYW5kbGluZyBhbiBlcnJvciwgaWdub3JpbmcgSFRUUCBlcnJvciBvbiBjYWxsXCIpICsgXCIgXCIgKyBndWlkKTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gICAgZWxzZVxyXG4gICAgICB0aGlzLkV4dGVuc2lvbnNJbXBsLndyaXRlSGFuZGxpbmdFcnJvclN0YXR1cyh0cnVlKTtcclxuXHJcbiAgICBsZXQgZmluYWxFcnJvciA9IFwiXCI7XHJcbiAgICBsZXQgZmluYWxTdGF0dXMgPSBcIlwiO1xyXG4gICAgaWYgKHRoaXMuaXNUeXBlRXJyb3IocmVzKSkge1xyXG4gICAgICBmaW5hbEVycm9yID0gcmVzLm1lc3NhZ2U7XHJcbiAgICAgIGZpbmFsU3RhdHVzID0gXCJIVFRQIFNlcnZpY2UgSW50ZXJuYWwgRXJyb3JcIjtcclxuICAgIH1cclxuICAgIGVsc2UgaWYgKHRoaXMuaXNIdHRwRXJyb3JSZXNwb25zZShyZXMpKSB7XHJcblxyXG4gICAgICBmaW5hbEVycm9yID0gYXdhaXQgdGhpcy5nZXRIdHRwRXJyb3JUZXh0KHJlcy5lcnJvcik7XHJcbiAgICAgIGZpbmFsU3RhdHVzID0gcmVzLnN0YXR1cy50b1N0cmluZygpO1xyXG5cclxuICAgICAgc3dpdGNoIChyZXMuc3RhdHVzKSB7XHJcbiAgICAgICAgLy8gVW5hdXRob3JpemVkXHJcbiAgICAgICAgY2FzZSA0MDE6XHJcbiAgICAgICAgICBpZiAodGhpcy5FeHRlbnNpb25zSW1wbC5yZWFkUmVkaXJlY3Rpb25TdGF0dXMoKSkge1xyXG4gICAgICAgICAgICB0aGlzLmxvZyh0aGlzLmxvYyhcIkVycm9yIDQwMSBvbiBjYWxsXCIpICsgXCIgXCIgKyBndWlkICsgXCIgXCIgKyB0aGlzLmxvYyhcIndpdGggcmVkaXJlY3QgYWxyZWFkeSBpbiBwcm9ncmVzcy4gSWdub3JpbmcgdGhpcyBldmVudFwiKSk7XHJcbiAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIHRoaXMubG9nKHRoaXMubG9jKFwiRXJyb3IgNDAxIG9uIGNhbGxcIikgKyBcIiBcIiArIGd1aWQgKyBcIiBcIiArIHRoaXMubG9jKFwicmVkaXJlY3RpbmcgdG8gbG9naW4uXCIpKTtcclxuICAgICAgICAgIHRoaXMuRXh0ZW5zaW9uc0ltcGwud3JpdGVSZWRpcmVjdGlvblN0YXR1cyh0cnVlKTtcclxuICAgICAgICAgIHRoaXMuRXh0ZW5zaW9uc0ltcGwud3JpdGVSZWRpcmVjdGluZ1RvTG9naW4odHJ1ZSk7XHJcbiAgICAgICAgICB0aGlzLkV4dGVuc2lvbnNJbXBsLnJlZGlyZWN0VG9Mb2dpbigpO1xyXG4gICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgIC8vIEhhbmRsZWQgZXhjZXB0aW9uXHJcbiAgICAgICAgY2FzZSA0MDA6XHJcbiAgICAgICAgLy8gTm8gUGVybWlzc2lvbnNcclxuICAgICAgICBjYXNlIDQwMzpcclxuICAgICAgICAgIHRoaXMuRXh0ZW5zaW9uc0ltcGwuaGFuZGxlQmxvY2tpbmdFeGNlcHRpb24ocmVzLnN0YXR1cywgZmluYWxFcnJvcik7XHJcbiAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgLy8gTm90IGZvdW5kXHJcbiAgICAgICAgY2FzZSA0MDQ6XHJcbiAgICAgICAgICB0aGlzLkV4dGVuc2lvbnNJbXBsLmhhbmRsZUJsb2NraW5nRXhjZXB0aW9uKHJlcy5zdGF0dXMsIHRoaXMubG9jKFwiUmVzb3VyY2Ugbm90IGZvdW5kXCIpKTtcclxuICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAvLyBOb3RDb25maWd1cmVkRXhjZXB0aW9uXHJcbiAgICAgICAgY2FzZSA0NDQ6XHJcbiAgICAgICAgICBpZiAodGhpcy5FeHRlbnNpb25zSW1wbC5yZWFkUmVkaXJlY3Rpb25TdGF0dXMoKSlcclxuICAgICAgICAgICAgdGhpcy5sb2codGhpcy5sb2MoXCJFcnJvciA0NDQgb24gY2FsbFwiKSArIFwiIFwiICsgZ3VpZCArIFwiIFwiICsgdGhpcy5sb2MoXCJ3aXRoIHJlZGlyZWN0IGFscmVhZHkgaW4gcHJvZ3Jlc3MuIElnbm9yaW5nIHRoaXMgZXZlbnRcIikpO1xyXG4gICAgICAgICAgZWxzZSBpZiAoIXRoaXMuRXh0ZW5zaW9uc0ltcGwuaGFuZGxlTm90Q29uZmlndXJlZEV4Y2VwdGlvbigpKVxyXG4gICAgICAgICAgICB0aGlzLkV4dGVuc2lvbnNJbXBsLmhhbmRsZUJsb2NraW5nRXhjZXB0aW9uKHJlcy5zdGF0dXMsIGZpbmFsRXJyb3IpO1xyXG4gICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgIGNhc2UgMDpcclxuICAgICAgICAgIGZpbmFsRXJyb3IgPSBgR2VuZXJpYyBjb25uZWN0aW9uIGVycm9yIHdoaWxlIGNhbGxpbmcgJ1ske2d1aWR9XSAtICR7dGhpcy5jYWxsU3RhdHVzW2d1aWRdLnVybH0nIGF0ICR7ZGF5anMoKS5mb3JtYXQoKX0uIFJlc3BvbnNlOiAke0pTT04uc3RyaW5naWZ5KHJlcyl9YDtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuRXh0ZW5zaW9uc0ltcGwuaGFuZGxlRXhjZXB0aW9uKGZpbmFsU3RhdHVzLCBmaW5hbEVycm9yKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIERhdG8gdW4gZXJyb3JlIHJlc3RpdHVpc2NlIHVuYSBwcm9taXNlIGNvbiBsYSBzdHJpbmdhIGZpbmFsZSBkZWxsJ2Vycm9yZSBpbiBtb2RvIGRhIHBvdGVyIGZhcmUgdW4gYXdhaXRcclxuICAgKiBcclxuICAgKiBAcGFyYW0ge2FueX0gZXJyIEVycm9yZSBkYSBjb250cm9sbGFyZVxyXG4gICAqIFxyXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IFByb21pc2UgY2hlIHJpc29sdmUgY29uIGxhIHN0cmluZ2EgZmluYWxlIGRlbGwnZXJyb3JlXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBnZXRIdHRwRXJyb3JUZXh0KGVycjogYW55KTogUHJvbWlzZTxzdHJpbmc+IHtcclxuICAgIC8vIFNlIGhvIHVuIEJsb2IgcHXDsiBlc3NlcmUgbyB1biBDYWxsUmVzdWx0IG8gc3VwcG9uZ28gdW5hIHNlbXBsaWNlIHN0cmluZ2EsXHJcbiAgICAvLyBhbHRyaW1lbnRpIHBvdHJlYmJlIGVzc2VyZSBkaXJldHRhbWVudGUgdW4gQ2FsbFJlc3VsdCwgb3BwdXJlIHVuYSBzZW1wbGljZSBzdHJpbmdhXHJcbiAgICByZXR1cm4gbmV3IFByb21pc2U8c3RyaW5nPigocmVzb2x2ZSkgPT4ge1xyXG4gICAgICBpZiAoZXJyIGluc3RhbmNlb2YgQmxvYikge1xyXG4gICAgICAgIGxldCByZWFkZXIgPSBuZXcgRmlsZVJlYWRlcigpO1xyXG4gICAgICAgIHJlYWRlci5vbmxvYWQgPSAoZTogRXZlbnQpID0+IHtcclxuICAgICAgICAgIGxldCBlcnJNc2cgPSAoPGFueT5lLnRhcmdldCkucmVzdWx0O1xyXG4gICAgICAgICAgbGV0IGpzb25lcnJNc2c6IGFueTtcclxuICAgICAgICAgIHRyeSB7IGpzb25lcnJNc2cgPSBKU09OLnBhcnNlKGVyck1zZyk7IH0gY2F0Y2ggKGUpIHsgfVxyXG4gICAgICAgICAgcmV0dXJuIHJlc29sdmUoanNvbmVyck1zZyAmJiB0aGlzLmlzQ2FsbFJlc3VsdChqc29uZXJyTXNnKSA/IGpzb25lcnJNc2cuZXJyb3IubWVzc2FnZSA6IGVyck1zZyk7XHJcbiAgICAgICAgfTtcclxuICAgICAgICByZWFkZXIucmVhZEFzVGV4dChlcnIpXHJcbiAgICAgIH1cclxuICAgICAgZWxzZSBpZiAodGhpcy5pc0NhbGxSZXN1bHQoZXJyKSlcclxuICAgICAgICByZXR1cm4gcmVzb2x2ZShlcnIuZXJyb3IubWVzc2FnZSk7XHJcbiAgICAgIGVsc2VcclxuICAgICAgICByZXR1cm4gcmVzb2x2ZShlcnI/LnRvU3RyaW5nKCkpO1xyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBSaWNvbm9zY2Ugc2UgbCdvZ2dldHRvIMOoIGRpIHRpcG8gKipDYWxsUmVzdWx0KiogZSwgc2Ugc8OsLCBsbyBjYXN0YSBhbCB0aXBvIGNvcnJldHRvIHBlciBlc3NlcmUgdXRpbGl6emF0byBjb3JyZXR0YW1lbnRlIG5lbCBibG9jY28gZGkgY29kaWNlIHN1Y2Nlc3Npdm9cclxuICAgKiBcclxuICAgKiBAcGFyYW0ge2FueX0gZXJyIEVycm9yZSBkYSBjb250cm9sbGFyZVxyXG4gICAqL1xyXG4gIHByaXZhdGUgaXNDYWxsUmVzdWx0KGVycjogYW55KTogZXJyIGlzIHsgZXJyb3I6IHsgbWVzc2FnZTogc3RyaW5nIH0gfSB7XHJcbiAgICByZXR1cm4gISFlcnI/LmVycm9yPy5tZXNzYWdlO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogUmljb25vc2NlIHNlIGwnZXJyb3JlIMOoIGRpIHRpcG8gKipIdHRwRXJyb3JSZXNwb25zZSoqIGUsIHNlIHPDrCwgbG8gY2FzdGEgYWwgdGlwbyBjb3JyZXR0byBwZXIgZXNzZXJlIHV0aWxpenphdG8gY29ycmV0dGFtZW50ZSBuZWwgYmxvY2NvIGRpIGNvZGljZSBzdWNjZXNzaXZvXHJcbiAgICogXHJcbiAgICogQHBhcmFtIHthbnl9IGVyciBFcnJvcmUgZGEgY29udHJvbGxhcmVcclxuICAgKi9cclxuICBwcml2YXRlIGlzSHR0cEVycm9yUmVzcG9uc2UoZXJyOiBhbnkpOiBlcnIgaXMgSHR0cEVycm9yUmVzcG9uc2Uge1xyXG4gICAgcmV0dXJuIGVyciBpbnN0YW5jZW9mIEh0dHBFcnJvclJlc3BvbnNlO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgKiBSaWNvbm9zY2Ugc2UgbCdlcnJvcmUgw6ggZGkgdGlwbyAqKlR5cGVFcnJvcioqIGUsIHNlIHPDrCwgbG8gY2FzdGEgYWwgdGlwbyBjb3JyZXR0byBwZXIgZXNzZXJlIHV0aWxpenphdG8gY29ycmV0dGFtZW50ZSBuZWwgYmxvY2NvIGRpIGNvZGljZSBzdWNjZXNzaXZvXHJcbiAgKiBcclxuICAqIEBwYXJhbSB7YW55fSBlcnIgRXJyb3JlIGRhIGNvbnRyb2xsYXJlXHJcbiAgKi9cclxuICBwcml2YXRlIGlzVHlwZUVycm9yKGVycjogYW55KTogZXJyIGlzIFR5cGVFcnJvciB7XHJcbiAgICByZXR1cm4gZXJyLm5hbWUgPT0gXCJUeXBlRXJyb3JcIjtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIENvbWUgZGljZSBpbCBub21lLCByZWdpc3RyYSB1biBlcnJvcmUgZSByZXN0aXR1aXNjZSB1biBPYnNlcnZhYmxlIHZ1b3RvIGNvbWUgcmlzdWx0YXRvIGRlbGxhIGNoaWFtYXRhXHJcbiAgICogXHJcbiAgICogQHBhcmFtIHthbnl9IHJlcyBSaXN1bHRhdG8gZGVsbGEgY2hpYW1hdGEgZWZmZXR0dWF0YVxyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBndWlkIElkZW50aWZpY2F0aXZvIEdVSUQgZGVsbGEgY2hpYW1hdGEgZWZmZXR0dWF0YVxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gaGFuZGxlRXJyb3IgSW5kaWNhIHNlIGdlc3RpcmUgbCdlcnJvcmUgdmlhIGxpYnJlcmlhIG8gc2UgbGltaXRhcnNpIGEgcmVzdGl0dWlyZSBsJ09ic2VydmFibGUgdnVvdG9cclxuICAgKiBcclxuICAgKiBAcmV0dXJucyB7T2JzZXJ2YWJsZTxhbnk+fSBPYnNlcnZhYmxlIHZ1b3RvXHJcbiAgICovXHJcbiAgcHJpdmF0ZSByZWdpc3RlckVycm9yQW5kUmV0dXJuRW1wdHlPYnNlcnZhYmxlKHJlczogYW55LCBndWlkOiBzdHJpbmcsIGhhbmRsZUVycm9yOiBib29sZWFuID0gdHJ1ZSk6IE9ic2VydmFibGU8YW55PiB7XHJcbiAgICBpZiAoaGFuZGxlRXJyb3IpXHJcbiAgICAgIHRoaXMub25FcnJvcihyZXMsIGd1aWQpO1xyXG4gICAgcmV0dXJuIG5ldyBPYnNlcnZhYmxlKCgpID0+IHsgfSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBEYXRvIHVuIFVybCBlIGRlaSBwYXJhbWV0cmkgY2VyY2EgZGkgcmVjdXBlcmFyZSBsJ2V2ZW50dWFsZSBvZ2dldHRvIGdpw6Agc2FsdmF0byBpbiBjYWNoZSBjb24gbGUgaW5mb3JtYXppb25pIGJhc2UgZGVsbGEgY2FjaGUgc3Rlc3NhXHJcbiAgICogXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHVybCBVUkwgc3UgY3VpIGVmZmV0dHVhcmUgbGEgY2hpYW1hdGFcclxuICAgKiBAcGFyYW0ge0h0dHBQYXJhbXN9IHBhcmFtcyBQYXJhbWV0cmkgZGVsbGEgY2hpYW1hdGEgKG51bGxpIGluIGNhc28gZGkgUE9TVClcclxuICAgKiBcclxuICAgKiBAcmV0dXJucyB7Q2FjaGVJbmZvc30gT2dnZXR0byBjb250ZW5lbnRlIGxlIGluZm9ybWF6aW9uaSBzdWxsYSBjYWNoZSBwZXIgbCdvZ2dldHRvIHNwZWNpZmljYXRvXHJcbiAgICovXHJcbiAgcHJpdmF0ZSB0cnlHZXRDYWNoZUluZm9ybWF0aW9ucyh1cmw6IHN0cmluZywgcGFyYW1zOiBIdHRwUGFyYW1zKTogQ2FjaGVJbmZvcyB7XHJcblxyXG4gICAgbGV0IGNhY2hpbmdLZXkgPSBudWxsLCBjYWNoZVRpbWUgPSBudWxsLCBpdGVtID0gbnVsbDtcclxuICAgIGxldCB1c2VDYWNoaW5nID0gISEoLyNjYWNoZS9naS5leGVjKHVybCkpO1xyXG5cclxuICAgIGlmICh1c2VDYWNoaW5nICYmIHRoaXMuQ2FjaGVJbml0aWFsaXplZCkge1xyXG4gICAgICBsZXQgdG1wID0gLyNjYWNoZSg6Py0oXFxkKykpL2dpLmV4ZWModXJsKTtcclxuICAgICAgY2FjaGVUaW1lID0gdG1wID8gdG1wWzJdIDogbnVsbDtcclxuXHJcbiAgICAgIHVybCA9IHVybC5yZXBsYWNlKFwiI2NhY2hlXCIgKyAoY2FjaGVUaW1lID8gXCItXCIgKyBjYWNoZVRpbWUgOiBcIlwiKSwgXCJcIik7XHJcbiAgICAgIGlmICh0aGlzLnVudGltZWRDYWNoZUV4cGlyZWQoKSAmJiAhY2FjaGVUaW1lKVxyXG4gICAgICAgIHRoaXMucmVzZXRIdHRwVW50aW1lZENhY2hlU3RvcmFnZSgpO1xyXG5cclxuICAgICAgY2FjaGluZ0tleSA9IHRoaXMubWFrZUNhY2hlS2V5KHVybCwgcGFyYW1zKTtcclxuICAgICAgbGV0IGNhY2hlS2V5ID0gY2FjaGVUaW1lID8gdGhpcy5sb2NhbFN0b3JhZ2VIdHRwVGltZWRDYWNoZUtleSA6IHRoaXMubG9jYWxTdG9yYWdlSHR0cENhY2hlS2V5XHJcbiAgICAgIGxldCBjYWNoZUxzID0gdGhpcy5sb2NhbFN0b3JhZ2UuZ2V0TG9jYWxJdGVtKGNhY2hlS2V5KTtcclxuICAgICAgbGV0IGNhY2hlID0gY2FjaGVMcyA/IGNhY2hlTHMgOiB7fTtcclxuXHJcbiAgICAgIGlmIChjYWNoZSAmJiBjYWNoZVtjYWNoaW5nS2V5XSAmJiAhdGhpcy50aW1lZENhY2hlSXRlbUV4cGlyZWQoY2FjaGVbY2FjaGluZ0tleV0pKSB7XHJcbiAgICAgICAgLy8gU2UgZ2VzdGlzY28gaWwgdGVtcG8gZXNhdHRvIGRlbGxhIGNhY2hlIHByaW1hIGRpIHJlc3RpdHVpcmUgbCdvZ2dldHRvIGNhY2hhdG8gbG8gcmlwdWxpc2NvIFxyXG4gICAgICAgIC8vIGRhbGxlIHByb3ByaWV0w6AgaW50ZXJuZSBjaGUgZ2xpIGhvIGFnZ2l1bnRvIHBlciBjb250cm9sbGFybmUgbGEgc2NhZGVuemFcclxuICAgICAgICBpZiAoY2FjaGVUaW1lKVxyXG4gICAgICAgICAgZGVsZXRlIGNhY2hlW2NhY2hpbmdLZXldLl9fZXhwaXJlO1xyXG5cclxuICAgICAgICBpdGVtID0gY2FjaGVbY2FjaGluZ0tleV1cclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIFBlciBhc3NpY3VyYXJtaSBjaGUgaWwgcmlmZWlybWVudG8gZGVnbGkgb2dnZXR0aSBzaWEgZGl2ZXJzbyB1dGlsaXp6byBpbCBkZWVwQ2xvbmVcclxuICAgIHJldHVybiBuZXcgQ2FjaGVJbmZvcyh1cmwsIHVzZUNhY2hpbmcgJiYgdGhpcy5DYWNoZUluaXRpYWxpemVkLCBjYWNoaW5nS2V5LCBjYWNoZVRpbWUsIHRoaXMudXRpc0V4dHMuZGVlcENsb25lKGl0ZW0pKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEluc2VyaXNjZSB1biBvZ2dldHRvIG5lbGxhIGNhY2hlIGFwcHJvcHJpYXRhIGluIGJhc2UgYWxsZSBpbmZvcm1hemlvbmkgY29udGVudXRlIG5lbCBwYXJhbWV0cm8gKipjYWNoZUluZm9zKipcclxuICAgKiBcclxuICAgKiBAcGFyYW0ge1R9IGl0ZW0gT2dnZXR0byBkYSBpbnNlcmlyZSBuZWxsYSBjYWNoZVxyXG4gICAqIEBwYXJhbSB7Q2FjaGVJbmZvc30gY2FjaGVJbmZvcyBJbmZvcm1hemlvbmkgc3VsbGEgY2FjaGUgcmVjdXBlcmF0ZSBkYSB1bmEgY2hpYW1hdGEgcHJlY2VkZW50ZSBhICoqdHJ5R2V0Q2FjaGVJbmZvcm1hdGlvbnMqKlxyXG4gICAqL1xyXG4gIHByaXZhdGUgY2FjaGVSZXNwb25zZTxUPihpdGVtOiBULCBjYWNoZUluZm9zOiBDYWNoZUluZm9zKTogdm9pZCB7XHJcbiAgICBsZXQgY2FjaGVLZXkgPSBjYWNoZUluZm9zLmNhY2hlVGltZSA/IHRoaXMubG9jYWxTdG9yYWdlSHR0cFRpbWVkQ2FjaGVLZXkgOiB0aGlzLmxvY2FsU3RvcmFnZUh0dHBDYWNoZUtleVxyXG4gICAgbGV0IGNhY2hlTHMgPSB0aGlzLmxvY2FsU3RvcmFnZS5nZXRMb2NhbEl0ZW0oY2FjaGVLZXkpO1xyXG4gICAgbGV0IGNhY2hlID0gY2FjaGVMcyA/IGNhY2hlTHMgOiB7fTtcclxuXHJcbiAgICBjYWNoZVtjYWNoZUluZm9zLmNhY2hlS2V5XSA9IGl0ZW07XHJcbiAgICBpZiAoY2FjaGVJbmZvcy5jYWNoZVRpbWUpXHJcbiAgICAgIGNhY2hlW2NhY2hlSW5mb3MuY2FjaGVLZXldLl9fZXhwaXJlID0gZGF5anMoKS5hZGQoY2FjaGVJbmZvcy5jYWNoZVRpbWUsIFwic2Vjb25kc1wiKTtcclxuXHJcbiAgICB0aGlzLmxvY2FsU3RvcmFnZS5zZXRMb2NhbEl0ZW0oY2FjaGVLZXksIGNhY2hlKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIENvbnRyb2xsYSBzZSBsYSBjYWNoZSBwZXIgbGUgY2hpYW1hdGUgc2VuemEgZXhwaXJlIHRpbWUgw6ggc2NhZHV0YVxyXG4gICAqIFxyXG4gICAqIEByZXR1cm5zIHtib29sZWFufSAqKnRydWUqKiBzZSBsYSBjYWNoZSDDqCBzY2FkdXRhIGUgZGV2J2Vzc2VyZSByaXB1bGl0YSwgKipmYWxzZSoqIGFsdHJpbWVudGlcclxuICAgKi9cclxuICBwcml2YXRlIHVudGltZWRDYWNoZUV4cGlyZWQoKTogYm9vbGVhbiB7XHJcbiAgICBsZXQgZXhwaXJlID0gSlNPTi5wYXJzZShsb2NhbFN0b3JhZ2UuZ2V0SXRlbSh0aGlzLmxvY2FsU3RvcmFnZUh0dHBDYWNoZUV4cGlyZUtleSkpO1xyXG4gICAgcmV0dXJuICFleHBpcmUgfHwgZXhwaXJlICYmIGRheWpzKGV4cGlyZSkgPCBkYXlqcygpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogQ29udHJvbGxhIHNlIGxhIGNhY2hlIHBlciB1bmEgY2hpYW1hdGEgY2hlIGhhIHVuIHRlbXBvIGRpIHZpdGEgYmVuIGRlZmluaXRvIMOoIHNjYWR1dGEgbyBtZW5vXHJcbiAgICogXHJcbiAgICogQHBhcmFtIHthbnl9IGl0ZW0gT2dnZXR0byByZWN1cGVyYXRvIGRhbGxhIGNhY2hlIGEgY3VpIGhvIGFnZ2l1bnRvIGxhIGNoaWF2ZSBpbnRlcm5hIF9fZXhwaXJlXHJcbiAgICogXHJcbiAgICogQHJldHVybnMge2Jvb2xlYW59ICoqdHJ1ZSoqIHNlIGxhIGNhY2hlIMOoIHNjYWR1dGEgZSBkZXYnZXNzZXJlIHJpcHVsaXRhLCAqKmZhbHNlKiogYWx0cmltZW50aVxyXG4gICAqL1xyXG4gIHByaXZhdGUgdGltZWRDYWNoZUl0ZW1FeHBpcmVkKGl0ZW06IGFueSk6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuIGRheWpzKGl0ZW0uX19leHBpcmUpIDwgZGF5anMoKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFJpcHVsaXNjZSBsYSBjYWNoZSBlIGltcG9zdGEgbGEgcHJvc3NpbWEgc2NhZGVuemEgYWQgYWRlc3NvICsgKipDTElFTlRfQ0FDSEVfRFVSQVRJT05fUyoqICh0b2tlbiB2YWxvcml6emF0byBpbiBmYXNlIGRpIGNvbmZpZ3VyYXppb25lIGRhbGxhIHByb3ByaWV0w6AgKipjbGllbnRDYWNoZUR1cmF0aW9uUyoqIGRlbGxhIGNsYXNzZSAqKkh0dHBTZXJ2aWNlTW9kdWxlQ29uZmlnKiopXHJcbiAgICovXHJcbiAgcHVibGljIGFzeW5jIHJlc2V0SHR0cFVudGltZWRDYWNoZVN0b3JhZ2UoKSB7XHJcbiAgICBpZighdGhpcy5DYWNoZUluaXRpYWxpemVkKVxyXG4gICAgICByZXR1cm47XHJcblxyXG4gICAgYXdhaXQgdGhpcy5sb2NhbFN0b3JhZ2Uuc2V0SXRlbSh0aGlzLmxvY2FsU3RvcmFnZUh0dHBDYWNoZUtleSwge30pLnRvUHJvbWlzZSgpO1xyXG4gICAgbG9jYWxTdG9yYWdlLnNldEl0ZW0odGhpcy5sb2NhbFN0b3JhZ2VIdHRwQ2FjaGVFeHBpcmVLZXksIEpTT04uc3RyaW5naWZ5KGRheWpzKCkuYWRkKHRoaXMuQ0xJRU5UX0NBQ0hFX0RVUkFUSU9OX1MsIFwic2Vjb25kXCIpKSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBSaXB1bGlzY2UgbGEgY2FjaGUgZGVsbGUgY2hpYW1hdGUgY29uIHVuIHRlbXBvIGRpIGV4cGlyZSBkZWZpbml0b1xyXG4gICAqL1xyXG4gIHB1YmxpYyBhc3luYyByZXNldEh0dHBUaW1lZENhY2hlU3RvcmFnZSgpIHtcclxuICAgIGlmKCF0aGlzLkNhY2hlSW5pdGlhbGl6ZWQpXHJcbiAgICAgIHJldHVybjtcclxuICAgIFxyXG4gICAgYXdhaXQgdGhpcy5sb2NhbFN0b3JhZ2Uuc2V0SXRlbSh0aGlzLmxvY2FsU3RvcmFnZUh0dHBUaW1lZENhY2hlS2V5LCB7fSkudG9Qcm9taXNlKCk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBHZW5lcmEgdW5hIGNoaWF2ZSBwZXIgbGEgY2FjaGUgZGVsbGUgY2hpYW1hdGUgaW4gYmFzZSBhZCBVUkwgZSBQYXJhbWV0cmkgSFRUUFxyXG4gICAqIFxyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgVVJMIHN1IGN1aSBlZmZldHR1YXJlIGxhIGNoaWFtYXRhXHJcbiAgICogQHBhcmFtIHtIdHRwUGFyYW1zfSBwYXJhbXMgUGFyYW1ldHJpIGRlbGxhIGNoaWFtYXRhXHJcbiAgICogXHJcbiAgICogQHJldHVybnMge3N0cmluZ30gQ2hpYXZlIGNoZSByYXBwcmVzZW50YSBpbiBtYW5pZXJhIHVuaXZvY2EgbGEgY2hpYW1hdGFcclxuICAgKi9cclxuICBwcml2YXRlIG1ha2VDYWNoZUtleSh1cmw6IHN0cmluZywgcGFyYW1zOiBIdHRwUGFyYW1zKTogc3RyaW5nIHtcclxuICAgIHRoaXMubWUgPSB0aGlzLm1lIHx8IHRoaXMuRXh0ZW5zaW9uc0ltcGwucmV0cmlldmVJZGVudGl0eSgpO1xyXG5cclxuICAgIGxldCBhdXRoS2V5UGFydCA9ICh0aGlzLm1lID8gdGhpcy5tZS5JZHRlbmFudCA6IFwiXCIpICsgKHRoaXMubWUgJiYgdGhpcy5DQUNIRV9CWV9VU0VSID8gdGhpcy5tZS5JZFVzZXIgOiBcIlwiKTtcclxuICAgIGxldCBwYXJhbXNLZXlQYXJ0ID0gcGFyYW1zICYmIHBhcmFtcy5rZXlzKCkubGVuZ3RoID4gMCA/IHBhcmFtcy5rZXlzKCkucmVkdWNlKChwcmV2OiBhbnksIG5leHQ6IGFueSkgPT4gcHJldiArIFwiLFwiICsgbmV4dCArICc9JyArIHBhcmFtcy5nZXQobmV4dCksIFwiXCIpIDogXCJcIjtcclxuICAgIHJldHVybiBhdXRoS2V5UGFydCArIFwiX1wiICsgdXJsLnN1YnN0cmluZyh1cmwuaW5kZXhPZihcImFwaVwiKSArIDQpICsgXCI/XCIgKyBwYXJhbXNLZXlQYXJ0O1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogR2VuZXJhemlvbmUgR1VJRFxyXG4gICAqIFxyXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IE51b3ZvIEdVSUQgZ2VuZXJhdG8gaW4gbWFuaWVyYSBjYXN1YWxlXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBnZXRHVUlEKCk6IHN0cmluZyB7XHJcbiAgICByZXR1cm4gJ3h4eHh4eHh4LXh4eHgtNHh4eC15eHh4LXh4eHh4eHh4eHh4eCcucmVwbGFjZSgvW3h5XS9nLCBmdW5jdGlvbiAoYykge1xyXG4gICAgICB2YXIgciA9IE1hdGgucmFuZG9tKCkgKiAxNiB8IDAsIHYgPSBjID09ICd4JyA/IHIgOiAociAmIDB4MyB8IDB4OCk7XHJcbiAgICAgIHJldHVybiB2LnRvU3RyaW5nKDE2KTtcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogTWV0b2RvIHBlciBzY3JpdmVyZSBsb2cgYSBjb25zb2xlIHF1YWxvcmEgKipERUJVR19NT0RFKiogcmlzdWx0YXNzZSAqKnRydWUqKlxyXG4gICAqIFxyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlIE1lc3NhZ2dpbyBkaSBsb2dcclxuICAgKi9cclxuICBwcml2YXRlIGxvZyhtZXNzYWdlOiBzdHJpbmcpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLkhUVFBfREVCVUdfTU9ERSlcclxuICAgICAgY29uc29sZS5sb2coXCJAaHR0cHNlcnZpY2U6IFwiICsgbWVzc2FnZSlcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEhlbHBlciBwZXIgbGEgbG9jYWxpenphemlvbmUgZGVpIG1lc3NhZ2dpXHJcbiAgICogXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IG1lc3NhZ2UgTWVzc2FnZ2lvIGRhIGxvY2FsaXp6YXJlXHJcbiAgICogXHJcbiAgICogQHJldHVybnMge3N0cmluZ30gTWVzc2FnZ2lvIGxvY2FsaXp6YXRvXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBsb2MobWVzc2FnZTogc3RyaW5nKTogc3RyaW5nIHtcclxuICAgIC8vIFRvZ2xpYW1vIHZlbG9jZW1lbnRlIHN0ZSBsb2NhbGl6emF6aW9uaSBpbnV0aWxpLi4uLlxyXG4gICAgcmV0dXJuIG1lc3NhZ2U7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBIZWxwZXIgcGVyIGxhbmNpYXJlIGxhIHNlbGV6aW9uZSBkaSB0dXR0byBxdWVsbG8gY2hlIMOoIHJlbGF0aXZvIGEgdW4gYXBpIGRpIHJpY2VyY2EgY29uIEFwcFNlYXJjaCAoZGkgY3VpIG5vbiB1dGlsaXp6byBpbCB0aXBvIHZlcm8gcGVyIHJpZHVycmUgbGUgZGlwZW5kZW56ZSlcclxuICAgKi9cclxuICBwdWJsaWMgZ2V0QWxsPFQ+KHZpZXc6IHsgaXRlbXM6IFRbXSwgcGFnZTogbnVtYmVyLCBpdGVtc3BlcnBhZ2VvdmVycmlkZTogbnVtYmVyLCBzZWxlY3Rpb246IHsgZXhjbHVzaW9uczogVFtdLCBhbGw6IGJvb2xlYW4sIGl0ZW1zOiBUW10gfSB9LCBhcGk6IHN0cmluZywgcGFycz86IEh0dHBQYXJhbXMsIHRyYW5zYWN0aW9uPzogc3RyaW5nKTogT2JzZXJ2YWJsZTxUW10+IHtcclxuICAgIGlmICghdmlldy5zZWxlY3Rpb24uYWxsKVxyXG4gICAgICByZXR1cm4gb2Yodmlldy5zZWxlY3Rpb24uaXRlbXMpO1xyXG5cclxuICAgIHZhciBqc29uVmlldyA9IHRoaXMudXRpc0V4dHMuZGVlcENsb25lKHZpZXcpO1xyXG4gICAganNvblZpZXcucGFnZSA9IDE7XHJcbiAgICBqc29uVmlldy5pdGVtc3BlcnBhZ2VvdmVycmlkZSA9IDk5OTk5OTtcclxuXHJcbiAgICByZXR1cm4gdGhpcy5wb3N0PHsgaXRlbXM6IFRbXSwgc2VsZWN0aW9uOiB7IGV4Y2x1c2lvbnM6IFRbXSB9IH0+KGFwaSwganNvblZpZXcsIHBhcnMsIHRyYW5zYWN0aW9uKS5waXBlKG1hcDx7IGl0ZW1zOiBUW10sIHNlbGVjdGlvbjogeyBleGNsdXNpb25zOiBUW10gfSB9LCBUW10+KHJlcyA9PiB7XHJcbiAgICAgIGxldCBpdGVtcyA9IDxUW10+cmVzLml0ZW1zO1xyXG4gICAgICBpdGVtcy5mb3JFYWNoKHQgPT4gKDxhbnk+dCkuaGFzaCA9IHRoaXMuaGFzaC5oYXNoT2JqZWN0KHQsIG51bGwsIGZhbHNlKSk7XHJcbiAgICAgIGlmIChyZXMuc2VsZWN0aW9uLmV4Y2x1c2lvbnM/Lmxlbmd0aCA+IDApXHJcbiAgICAgICAgaXRlbXMgPSBpdGVtcy5maWx0ZXIoKHQ6IGFueSkgPT4gIXJlcy5zZWxlY3Rpb24uZXhjbHVzaW9ucy5maW5kKChlOiBhbnkpID0+IHRoaXMuaGFzaC5oYXNoT2JqZWN0KGUsIG51bGwsIGZhbHNlKSA9PSB0Lmhhc2gpKTtcclxuICAgICAgcmV0dXJuIGl0ZW1zO1xyXG4gICAgfSkpO1xyXG4gIH1cclxuXHJcbiAgLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcbiAgICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqIFRSQU5TQUNUSU9OIEhFTFBFUlMgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcbiAgICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG4gIHByaXZhdGUgR0VUX1RyYW5zX0JlZ2luVHJhbnM6IHN0cmluZyA9IFwiL2FwaS9UcmFucy9CZWdpblRyYW5zXCI7XHJcbiAgcHJpdmF0ZSBHRVRfVHJhbnNfQ2hlY2tFeGVjdXRpb246IHN0cmluZyA9IFwiL2FwaS9UcmFucy9DaGVja0V4ZWN1dGlvblwiO1xyXG4gIHByaXZhdGUgR0VUX1RyYW5zX0VuZFRyYW5zOiBzdHJpbmcgPSBcIi9hcGkvVHJhbnMvRW5kVHJhbnNcIjtcclxuXHJcbiAgcHVibGljIGJlZ2luVHJhbnNhY3Rpb24oZXhlY3V0aW9uS2V5OiBzdHJpbmcsIHNlY29uZHNUaW1lb3V0PzogbnVtYmVyKTogT2JzZXJ2YWJsZTxzdHJpbmc+IHtcclxuICAgIHRoaXMubG9nKFwiYmVnaW5UcmFuc2FjdGlvbiBjYWxsIHJlY2VpdmVkOiBcIiArIGV4ZWN1dGlvbktleSk7XHJcbiAgICB2YXIgcGFycyA9IG5ldyBIdHRwUGFyYW1zKCkuc2V0KFwiZXhlY3V0aW9uS2V5XCIsIGV4ZWN1dGlvbktleSk7XHJcbiAgICBpZiAoc2Vjb25kc1RpbWVvdXQpXHJcbiAgICAgIHBhcnMgPSBwYXJzLnNldChcInNlY29uZHNUaW1lb3V0XCIsIHNlY29uZHNUaW1lb3V0LnRvU3RyaW5nKCkpO1xyXG4gICAgcmV0dXJuIHRoaXMuZ2V0PHN0cmluZz4odGhpcy5HRVRfVHJhbnNfQmVnaW5UcmFucywgcGFycyk7XHJcbiAgfVxyXG5cclxuICBwdWJsaWMgY2hlY2tUcmFuc2FjdGlvbihleGVjdXRpb25LZXk6IHN0cmluZyk6IE9ic2VydmFibGU8bnVtYmVyPiB7XHJcblxyXG4gICAgdGhpcy5sb2coXCJjaGVja1RyYW5zYWN0aW9uIGNhbGwgcmVjZWl2ZWQ6IFwiICsgZXhlY3V0aW9uS2V5KTtcclxuICAgIHJldHVybiB0aGlzLmdldDxudW1iZXI+KHRoaXMuR0VUX1RyYW5zX0NoZWNrRXhlY3V0aW9uLCBuZXcgSHR0cFBhcmFtcygpLnNldChcImV4ZWN1dGlvbktleVwiLCBleGVjdXRpb25LZXkpKTtcclxuICB9XHJcblxyXG4gIHB1YmxpYyBlbmRUcmFuc2FjdGlvbih0cmFuc2FjdGlvbktleTogc3RyaW5nLCB0cmFuc2FjdGlvblJlc3VsdDogYm9vbGVhbik6IE9ic2VydmFibGU8c3RyaW5nPiB7XHJcbiAgICB0aGlzLmxvZyhcImVuZFRyYW5zYWN0aW9uIGNhbGwgcmVjZWl2ZWQ6IFwiICsgdHJhbnNhY3Rpb25LZXkgKyBcIiBDb21taXQ6IFwiICsgdHJhbnNhY3Rpb25SZXN1bHQpO1xyXG4gICAgbGV0IHBhcnMgPSBuZXcgSHR0cFBhcmFtcygpLnNldChcImlkdHJhbnNcIiwgdHJhbnNhY3Rpb25LZXkpLnNldChcInN1Y2Nlc3NcIiwgdHJhbnNhY3Rpb25SZXN1bHQudG9TdHJpbmcoKSk7XHJcbiAgICByZXR1cm4gdGhpcy5nZXQ8c3RyaW5nPih0aGlzLkdFVF9UcmFuc19FbmRUcmFucywgcGFycyk7XHJcbiAgfVxyXG59Il19
|