turbogui-angular 15.2.0 → 15.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.
Files changed (43) hide show
  1. package/esm2022/main/controller/dialog.service.mjs +3 -3
  2. package/esm2022/main/controller/locales.service.mjs +492 -0
  3. package/esm2022/main/controller/turbo-api-caller.service.mjs +41 -9
  4. package/esm2022/main/controller/views.service.mjs +20 -17
  5. package/esm2022/main/model/classes/View.mjs +2 -2
  6. package/esm2022/main/view/components/busy-state-base/busy-state-base.component.mjs +1 -1
  7. package/esm2022/main/view/components/button-container/button-container.component.mjs +1 -1
  8. package/esm2022/main/view/components/button-image/button-image.component.mjs +1 -1
  9. package/esm2022/main/view/components/dialog-date-selection/dialog-date-selection.component.mjs +1 -1
  10. package/esm2022/main/view/components/dialog-error/dialog-error.component.mjs +1 -1
  11. package/esm2022/main/view/components/dialog-multiple-option/dialog-multiple-option.component.mjs +1 -1
  12. package/esm2022/main/view/components/dialog-single-input/dialog-single-input.component.mjs +25 -8
  13. package/esm2022/public_api.mjs +2 -2
  14. package/fesm2022/turbogui-angular.mjs +559 -41
  15. package/fesm2022/turbogui-angular.mjs.map +1 -1
  16. package/main/controller/dialog.service.d.ts +2 -2
  17. package/main/controller/locales.service.d.ts +295 -0
  18. package/main/controller/locales.service.d.ts.map +1 -0
  19. package/main/controller/turbo-api-caller.service.d.ts +28 -8
  20. package/main/controller/turbo-api-caller.service.d.ts.map +1 -1
  21. package/main/controller/views.service.d.ts +11 -10
  22. package/main/controller/views.service.d.ts.map +1 -1
  23. package/main/model/classes/View.d.ts +1 -1
  24. package/main/view/components/busy-state-base/busy-state-base.component.d.ts +0 -9
  25. package/main/view/components/busy-state-base/busy-state-base.component.d.ts.map +1 -1
  26. package/main/view/components/button-container/button-container.component.d.ts +0 -3
  27. package/main/view/components/button-container/button-container.component.d.ts.map +1 -1
  28. package/main/view/components/button-image/button-image.component.d.ts +0 -3
  29. package/main/view/components/button-image/button-image.component.d.ts.map +1 -1
  30. package/main/view/components/dialog-date-selection/dialog-date-selection.component.d.ts +0 -3
  31. package/main/view/components/dialog-date-selection/dialog-date-selection.component.d.ts.map +1 -1
  32. package/main/view/components/dialog-error/dialog-error.component.d.ts +0 -3
  33. package/main/view/components/dialog-error/dialog-error.component.d.ts.map +1 -1
  34. package/main/view/components/dialog-multiple-option/dialog-multiple-option.component.d.ts +0 -3
  35. package/main/view/components/dialog-multiple-option/dialog-multiple-option.component.d.ts.map +1 -1
  36. package/main/view/components/dialog-single-input/dialog-single-input.component.d.ts +5 -5
  37. package/main/view/components/dialog-single-input/dialog-single-input.component.d.ts.map +1 -1
  38. package/package.json +1 -1
  39. package/public_api.d.ts +1 -1
  40. package/public_api.d.ts.map +1 -1
  41. package/esm2022/main/controller/localization.service.mjs +0 -25
  42. package/main/controller/localization.service.d.ts +0 -10
  43. package/main/controller/localization.service.d.ts.map +0 -1
@@ -0,0 +1,492 @@
1
+ /**
2
+ * TurboGUI is A library that helps with the most common and generic UI elements and functionalities
3
+ *
4
+ * Website : -> http://www.turbogui.org
5
+ * License : -> Licensed under the Apache License, Version 2.0. You may not use this file except in compliance with the License.
6
+ * License Url : -> http://www.apache.org/licenses/LICENSE-2.0
7
+ * CopyRight : -> Copyright 2018 Edertone Advanded Solutions. https://www.edertone.com
8
+ */
9
+ import { Injectable } from '@angular/core';
10
+ import { SingletoneStrictClass } from '../model/classes/SingletoneStrictClass';
11
+ import * as i0 from "@angular/core";
12
+ /**
13
+ * Manages application text translations and languages
14
+ */
15
+ export class LocalesService extends SingletoneStrictClass {
16
+ /**
17
+ * Fully featured translation manager to be used with any application that requires text internationalization.
18
+ */
19
+ constructor() {
20
+ super(LocalesService);
21
+ /**
22
+ * if the class has been correctly initialized and translations have been correctly loaded
23
+ */
24
+ this._isInitialized = false;
25
+ /**
26
+ * @see getLocales()
27
+ */
28
+ this._locales = [];
29
+ /**
30
+ * @see getLanguages()
31
+ */
32
+ this._languages = [];
33
+ /**
34
+ * Stores all the loaded localization data by library name, bundle name, key and locales
35
+ */
36
+ this._loadedTranslations = {};
37
+ /**
38
+ * Stores a memory cache to improve performance when outputing translations
39
+ */
40
+ this._keyValuesCache = {};
41
+ /**
42
+ * @see setWildCardsFormat()
43
+ */
44
+ this._wildCardsFormat = '{N}';
45
+ /**
46
+ * @see setMissingKeyFormat()
47
+ */
48
+ this._missingKeyFormat = '$exception';
49
+ /**
50
+ * Stores a hash value that is used to improve the performance for translation t() methods.
51
+ * This is computed based on _wildCardsFormat plus _missingKeyFormat plus the current primary locale
52
+ * Methods that change these values will recalculate the hash string, so when calling translation methods, the
53
+ * performance will be as fast as possible.
54
+ */
55
+ this._cacheHashBaseString = '';
56
+ }
57
+ /**
58
+ * Wildcards are string fragments that are placed inside the translated texts. Their main purpose is to be replaced at
59
+ * runtime by custom values like for example a user name, a date, a numeric value, etc..
60
+ *
61
+ * This class helps with this process by including a parameter called 'toReplace' on all ->t methods which allows us
62
+ * to specify a string or list of strings that will replace the respective wildcards on the translated text. Each wildcard
63
+ * must follow the format specified here, and contain a numeric digit that will be used to find the replacement text at the
64
+ * 'toReplace' list. For example, if we define $N as the wildcard format, and we have a translation that contains $0, $1, $2,
65
+ * $0 will be replaced with the first element on toReplace, $1 with the second and so.
66
+ *
67
+ * We usually set this before initializing the class translation data
68
+ *
69
+ * Notice that N is mandayory on the wildcards format and the first index value is 0.
70
+ *
71
+ * @param value The wildcards format we want to set
72
+ *
73
+ * @returns The value that's been set
74
+ */
75
+ setWildCardsFormat(value) {
76
+ if (!value.includes('N')) {
77
+ throw new Error("N is mandatory to replace wildcards");
78
+ }
79
+ this._cacheHashBaseString = value + this._missingKeyFormat + ((this._locales.length > 0) ? this._locales[0] : '');
80
+ this._wildCardsFormat = value;
81
+ return value;
82
+ }
83
+ /**
84
+ * Defines the behaviour for get(), getStartCase(), etc... methods when a key is not found on
85
+ * a bundle or the bundle does not exist
86
+ *
87
+ * If missingKeyFormat is an empty string, all missing keys will return an empty value (not recommended)
88
+ *
89
+ * If missingKeyFormat contains a string, that string will be always returned for missing keys
90
+ *
91
+ * If missingKeyFormat contains a string with one of the following predefined wildcards:<br>
92
+ * - $key will be replaced with key name. Example: get("NAME") will output [NAME] if key is not found and missingKeyFormat = '[$key]'<br>
93
+ * - $exception (default value) will throw an exception with the problem cause description.
94
+ *
95
+ * @param value The missing key format we want to set
96
+ *
97
+ * @returns The value that's been set
98
+ */
99
+ setMissingKeyFormat(value) {
100
+ this._cacheHashBaseString = this._wildCardsFormat + value + ((this._locales.length > 0) ? this._locales[0] : '');
101
+ this._missingKeyFormat = value;
102
+ return value;
103
+ }
104
+ /**
105
+ * @see setMissingKeyFormat()
106
+ */
107
+ getMissingKeyFormat() {
108
+ return this._missingKeyFormat;
109
+ }
110
+ /**
111
+ * Initializes the translation system by loading and parsing bundle files from the specified translations path.
112
+ *
113
+ * @param translationsPath - Url where the translations Json structure of libraries/bundles/locales/keys is available.
114
+ * @param locales An array of locale codes (e.g., ['en_US', 'es_ES', 'fr_FR']) to load. These will be added to the translation
115
+ * path using the following format: translationsPath/en_US-es_ES-fr_FR. The order of this array will determine the
116
+ * translation priority
117
+ * @param parameters Any extra parameters to be attached to the translationsPath after the locales like /param1/param2/ etc
118
+ *
119
+ * @return A promise that will resolve if the translations get correctly loaded, or reject with an error if load fails
120
+ */
121
+ initialize(translationsPath, locales, parameters) {
122
+ this._isInitialized = false;
123
+ this._loadedTranslations = {};
124
+ // Validate received locales are correct
125
+ for (const locale of locales) {
126
+ this._validateLocaleString(locale);
127
+ }
128
+ let translationsFullPath = translationsPath + '/' + locales.join('-') + '/' + parameters.join('/');
129
+ return new Promise((resolve, reject) => {
130
+ fetch(translationsFullPath).then(response => {
131
+ if (!response.ok) {
132
+ throw new Error(`HTTP error! status: ${response.status}`);
133
+ }
134
+ return response.json();
135
+ }).then(data => {
136
+ this._loadedTranslations = data;
137
+ this._isInitialized = true;
138
+ this._locales = locales;
139
+ this._languages = locales.map((l) => l.substring(0, 2));
140
+ this._cacheHashBaseString = this._wildCardsFormat + this._missingKeyFormat + this._locales[0];
141
+ resolve(undefined);
142
+ }).catch(error => {
143
+ reject(new Error(`ERROR LOADING LOCALES FROM: ${translationsFullPath}\n` + error));
144
+ });
145
+ });
146
+ }
147
+ /**
148
+ * Check if the class has been correctly initialized and translations have been correctly loaded
149
+ */
150
+ isInitialized() {
151
+ return this._isInitialized;
152
+ }
153
+ /**
154
+ * Aux method to verify that this class is correctly initialized with translation data
155
+ */
156
+ _validateInitialized() {
157
+ if (!this._isInitialized) {
158
+ throw new Error('LocalesManager not initialized');
159
+ }
160
+ }
161
+ /**
162
+ * Checks if the specified locale is currently loaded for the currently defined bundles and paths.
163
+ *
164
+ * @param locale A locale to check. For example 'en_US'
165
+ *
166
+ * @return True if the locale is currently loaded on the class, false if not.
167
+ */
168
+ isLocaleLoaded(locale) {
169
+ this._validateLocaleString(locale);
170
+ return this._locales.includes(locale);
171
+ }
172
+ /**
173
+ * Aux method to validate that a locale string is correctly formatted
174
+ *
175
+ * @param string $locale A locale string
176
+ */
177
+ _validateLocaleString(locale) {
178
+ if (!/^[a-z]{2}_[A-Z]{2}$/.test(locale)) {
179
+ throw new Error('locale must be a valid xx_XX value');
180
+ }
181
+ }
182
+ /**
183
+ * Checks if the specified 2 digit language is currently loaded for the currently defined bundles and paths.
184
+ *
185
+ * @param language A language to check. For example 'en'
186
+ *
187
+ * @return True if the language is currently loaded on the class, false if not.
188
+ */
189
+ isLanguageLoaded(language) {
190
+ this._validateLanguageString(language);
191
+ return this._languages.includes(language);
192
+ }
193
+ /**
194
+ * Aux method to validate that a language string is correctly formatted
195
+ *
196
+ * @param language A 2 digit language string
197
+ */
198
+ _validateLanguageString(language) {
199
+ if (!/^[a-z]{2}$/.test(language)) {
200
+ throw new Error('language must be a valid 2 digit value');
201
+ }
202
+ }
203
+ /**
204
+ * Get the translation to the current primary locale for the given key, library and bundle
205
+ *
206
+ * @param string key The key we want to read from the specified resource bundle
207
+ * @param string bundlePath A string with the format 'library_name/bundle_name' that is used to locate the bundle were the key to translate is found
208
+ * @param array replaceWildcards A list of values that will replace wildcards that may be found on the translated text. Each wildcard
209
+ * will be replaced with the element whose index on toReplace matches it. Check the documentation for this.wildCardsFormat
210
+ * property to know more about how to setup wildcards.
211
+ *
212
+ * @see setWildCardsFormat()
213
+ *
214
+ * @return The translated text
215
+ */
216
+ t(key, bundlePath, replaceWildcards = []) {
217
+ this._validateInitialized();
218
+ // Create a cache key to improve performance when requesting the same key translation several times
219
+ const cacheKey = `${this._cacheHashBaseString}${key}${bundlePath}${replaceWildcards.join('')}`;
220
+ if (!this._keyValuesCache[cacheKey]) {
221
+ this._forceNonEmptyString(key, '', 'key must be non empty string');
222
+ this._forceNonEmptyString(bundlePath, '', 'bundlePath must be non empty string');
223
+ const [library, bundle] = bundlePath.split('/');
224
+ this._forceNonEmptyString(library, '', 'no library specified on bundlePath');
225
+ this._forceNonEmptyString(bundle, '', 'no bundle specified on bundlePath');
226
+ const replacementsCount = replaceWildcards.length;
227
+ // Loop all the locales to find the first one with a value for the specified key
228
+ for (const locale of this._locales) {
229
+ if (this._loadedTranslations[library]?.[bundle]?.[locale]?.[key]) {
230
+ let result = this._loadedTranslations[library][bundle][locale][key];
231
+ // Replace all wildcards on the text with the specified replacements if any
232
+ for (let i = 0; i < replacementsCount; i++) {
233
+ result = this._replace(result, this._replace(this._wildCardsFormat, 'N', i.toString()), replaceWildcards[i]);
234
+ }
235
+ this._keyValuesCache[cacheKey] = result;
236
+ return result;
237
+ }
238
+ }
239
+ // Check if an exception needs to be thrown if the specified key is not found on this bundle
240
+ if (this._missingKeyFormat.includes('$exception')) {
241
+ throw new Error(`key <${key}> not found on ${bundlePath}`);
242
+ }
243
+ this._keyValuesCache[cacheKey] = this._replace(this._missingKeyFormat, '$key', key);
244
+ }
245
+ return this._keyValuesCache[cacheKey];
246
+ }
247
+ /**
248
+ * Get the translation for the given key and bundle as a string with all words first character capitalized
249
+ * and all the rest of the word with lower case
250
+ *
251
+ * @see t()
252
+ *
253
+ * @returns The localized and case formatted text
254
+ */
255
+ tStartCase(key, bundlePath, replaceWildcards = []) {
256
+ return this.t(key, bundlePath, replaceWildcards).split(' ')
257
+ .map((word) => word ? word[0].toUpperCase() + word.slice(1).toLowerCase() : '').join(' ');
258
+ }
259
+ /**
260
+ * Get the translation for the given key and bundle as an all upper case string
261
+ *
262
+ * @see t()
263
+ *
264
+ * @returns The localized and case formatted text
265
+ */
266
+ tAllUpperCase(key, bundlePath, replaceWildcards = []) {
267
+ return this.t(key, bundlePath, replaceWildcards).toUpperCase();
268
+ }
269
+ /**
270
+ * Get the translation for the given key and bundle as an all lower case string
271
+ *
272
+ * @see t()
273
+ *
274
+ * @returns The localized and case formatted text
275
+ */
276
+ tAllLowerCase(key, bundlePath, replaceWildcards = []) {
277
+ return this.t(key, bundlePath, replaceWildcards).toLowerCase();
278
+ }
279
+ /**
280
+ * Get the translation for the given key and bundle as a string with the first character as Upper case
281
+ * and all the rest as lower case
282
+ *
283
+ * @see t()
284
+ *
285
+ * @returns The localized and case formatted text
286
+ */
287
+ tFirstUpperRestLower(key, bundlePath, replaceWildcards = []) {
288
+ const string = this.t(key, bundlePath, replaceWildcards);
289
+ return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
290
+ }
291
+ /**
292
+ * A list of strings containing the locales that are used by this class to translate the given keys, sorted by preference.
293
+ * Each string is formatted as a standard locale code with language and country joined by an underscore, like: en_US, fr_FR
294
+ *
295
+ * When a key and bundle are requested for translation, the class will check on the first language of this
296
+ * list for a translated text. If missing, the next one will be used, and so. This list is constructed after initialize
297
+ * methods is called.
298
+ *
299
+ * @example: After loading the following list of locales ['en_US', 'es_ES', 'fr_FR'] if we call LocalesManager.t('HELLO', 'lib1/greetings')
300
+ * the localization manager will try to locate the en_US value for the HELLO tag on the greetings bundle for the library lib1.
301
+ * If the tag is not found for the specified locale and bundle, the same search will be performed for the es_ES locale, and so, till a
302
+ * value is found or no more locales are defined.
303
+ */
304
+ getLocales() {
305
+ return this._locales;
306
+ }
307
+ /**
308
+ * A list of strings containing the languages that are used by this class to translate the given keys, sorted by preference.
309
+ * Each string is formatted as a 2 digit language code, like: en, fr
310
+ *
311
+ * This list is the same as the locales() one, but containing only the language part of each locale (the first two digits)
312
+ *
313
+ * @see getLocales()
314
+ */
315
+ getLanguages() {
316
+ return this._languages;
317
+ }
318
+ /**
319
+ * Get the first locale from the list of loaded locales, which is the currently used to search for translated texts.
320
+ *
321
+ * @returns The locale that is defined as the primary one. For example: en_US, es_ES, ..
322
+ */
323
+ getPrimaryLocale() {
324
+ this._validateInitialized();
325
+ return this._locales[0];
326
+ }
327
+ /**
328
+ * Get the first language from the list of loaded locales, which is the currently used to search for translated texts.
329
+ *
330
+ * @returns The 2 digit language code that is defined as the primary one. For example: en, es, ..
331
+ */
332
+ getPrimaryLanguage() {
333
+ this._validateInitialized();
334
+ return this._languages[0];
335
+ }
336
+ /**
337
+ * Define the locale that will be placed at the front of the currently loaded locales list (moving all the others one position to the right).
338
+ *
339
+ * This will be the first locale to use when trying to get a translation.
340
+ *
341
+ * @param locale A currently loaded locale that will be moved to the first position of the loaded locales list. If the specified locale
342
+ * is not currently loaded, an exception will happen.
343
+ *
344
+ * @returns void
345
+ */
346
+ setPrimaryLocale(locale) {
347
+ this._validateInitialized();
348
+ if (!this.isLocaleLoaded(locale)) {
349
+ throw new Error(locale + ' not loaded');
350
+ }
351
+ let result = [locale];
352
+ for (let l of this._locales) {
353
+ if (l !== locale) {
354
+ result.push(l);
355
+ }
356
+ }
357
+ this._locales = result;
358
+ this._languages = this._locales.map((l) => l.substring(0, 2));
359
+ this._cacheHashBaseString = this._wildCardsFormat + this._missingKeyFormat + this._locales[0];
360
+ }
361
+ /**
362
+ * Moves the specified locales to the beginning of the locales list. This also alters the translation priority by setting the first
363
+ * provided locale as the most prioritary, the second as the next one and so.
364
+ *
365
+ * This method basically works exactly the same way as setPrimaryLocale but letting us add many locales at once.
366
+ *
367
+ * @see setPrimaryLocale()
368
+ *
369
+ * @param locales A list of locales to be moved to the beginning of the translation priority. First locales item will be the prefered
370
+ * locale for translation, second will be the next one in case some key is not translated for the first one and so. If any of the
371
+ * specified locales is not currently loaded, an exception will happen.
372
+ *
373
+ * @returns void
374
+ */
375
+ setPrimaryLocales(locales) {
376
+ if (!Array.isArray(locales) ||
377
+ (new Set(locales).size !== locales.length) ||
378
+ locales.length === 0) {
379
+ throw new Error('locales must be non empty string array with no duplicate elements');
380
+ }
381
+ for (let i = locales.length - 1; i >= 0; i--) {
382
+ this.setPrimaryLocale(locales[i]);
383
+ }
384
+ }
385
+ /**
386
+ * Define the 2 digit language that will be placed at the front of the currently loaded locales list (moving all the others one position to the right).
387
+ *
388
+ * This will be the first language to use when trying to get a translation.
389
+ *
390
+ * @param language A 2 digit language code that matches with any of the currently loaded locales, which will
391
+ * be moved to the first position of the loaded locales list. If the specified language does not match with
392
+ * a locale that is currently loaded, an exception will happen.
393
+ *
394
+ * @returns void
395
+ */
396
+ setPrimaryLanguage(language) {
397
+ for (let locale of this._locales) {
398
+ if (locale.substring(0, 2) === language) {
399
+ this.setPrimaryLocale(locale);
400
+ return;
401
+ }
402
+ }
403
+ throw new Error(language + ' not loaded');
404
+ }
405
+ /**
406
+ * Moves the locales that match the specified languages to the beginning of the locales list.
407
+ * Works the same as setPrimaryLocales() but with a list of the 2 digit language codes that match the respective locales.
408
+ *
409
+ * @see setPrimaryLocale()
410
+ * @see setPrimaryLanguage()
411
+ *
412
+ * @param languages A list of 2 digit language codes to be moved to the beginning of the translation priority. If any of the
413
+ * specified languages does not match with a locale that is currently loaded, an exception will happen.
414
+ *
415
+ * @returns void
416
+ */
417
+ setPrimaryLanguages(languages) {
418
+ if (!Array.isArray(languages) ||
419
+ (new Set(languages).size !== languages.length) ||
420
+ languages.length === 0) {
421
+ throw new Error('languages must be non empty string array with no duplicate elements');
422
+ }
423
+ for (let i = languages.length - 1; i >= 0; i--) {
424
+ this.setPrimaryLanguage(languages[i]);
425
+ }
426
+ }
427
+ /**
428
+ * Change the loaded locales translation preference order. The same locales that are currently loaded must be passed
429
+ * but with a different order to change the translation priority.
430
+ *
431
+ * @param locales A list with the new locales translation priority
432
+ *
433
+ * @returns void
434
+ */
435
+ setLocalesOrder(locales) {
436
+ if (locales.length !== this._locales.length) {
437
+ throw new Error('locales must contain all the currently loaded locales');
438
+ }
439
+ this._validateInitialized();
440
+ for (let locale of locales) {
441
+ if (!this.isLocaleLoaded(locale)) {
442
+ throw new Error(locale + ' not loaded');
443
+ }
444
+ }
445
+ this._locales = locales;
446
+ this._languages = this._locales.map((l) => l.substring(0, 2));
447
+ this._cacheHashBaseString = this._wildCardsFormat + this._missingKeyFormat + this._locales[0];
448
+ }
449
+ /**
450
+ * This is an aux method to implement the TurboCommons StringUtils replace method.
451
+ * It is exactly the same as the one on the library, but we implement it here to avoid having a dependency with TurboCommons
452
+ */
453
+ _replace(string, search, replacement) {
454
+ const escapedSearch = search.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
455
+ return string.replace(new RegExp(escapedSearch, 'g'), replacement);
456
+ }
457
+ /**
458
+ * This is an aux method to implement the TurboCommons StringUtils isEmpty method.
459
+ * It is exactly the same as the one on the library, but we implement it here to avoid having a dependency with TurboCommons
460
+ */
461
+ _isEmpty(string) {
462
+ let isString = (typeof string === 'string' || string instanceof String);
463
+ // Throw exception if non string value was received
464
+ if (!isString) {
465
+ // Empty or null value is considered empty
466
+ if (string == null || string == '') {
467
+ return true;
468
+ }
469
+ throw new Error("value is not a string");
470
+ }
471
+ return string.replace(/[ \n\r\t]/g, '') === '';
472
+ }
473
+ /**
474
+ * This is an aux method to implement the TurboCommons StringUtils forceNonEmptyString method.
475
+ * It is exactly the same as the one on the library, but we implement it here to avoid having a dependency with TurboCommons
476
+ */
477
+ _forceNonEmptyString(value, valueName = '', errorMessage = 'must be a non empty string') {
478
+ let isString = (typeof value === 'string' || value instanceof String);
479
+ if (!isString || this._isEmpty(value)) {
480
+ throw new Error(valueName + ' ' + errorMessage);
481
+ }
482
+ }
483
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.8", ngImport: i0, type: LocalesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
484
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.0.8", ngImport: i0, type: LocalesService, providedIn: 'root' }); }
485
+ }
486
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.8", ngImport: i0, type: LocalesService, decorators: [{
487
+ type: Injectable,
488
+ args: [{
489
+ providedIn: 'root',
490
+ }]
491
+ }], ctorParameters: () => [] });
492
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9jYWxlcy5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvdHVyYm9ndWktYW5ndWxhci9zcmMvbWFpbi9jb250cm9sbGVyL2xvY2FsZXMuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7OztHQU9HO0FBRUgsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzQyxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQzs7QUFHL0U7O0dBRUc7QUFJSCxNQUFNLE9BQU8sY0FBZSxTQUFRLHFCQUFxQjtJQXNEckQ7O09BRUc7SUFDSDtRQUVJLEtBQUssQ0FBQyxjQUFjLENBQUMsQ0FBQztRQXhEMUI7O1dBRUc7UUFDSyxtQkFBYyxHQUFHLEtBQUssQ0FBQztRQUcvQjs7V0FFRztRQUNLLGFBQVEsR0FBWSxFQUFFLENBQUM7UUFHL0I7O1dBRUc7UUFDSyxlQUFVLEdBQVksRUFBRSxDQUFDO1FBR2pDOztXQUVHO1FBQ0ssd0JBQW1CLEdBQU8sRUFBRSxDQUFDO1FBR3JDOztXQUVHO1FBQ0ssb0JBQWUsR0FBTyxFQUFFLENBQUM7UUFHakM7O1dBRUc7UUFDSyxxQkFBZ0IsR0FBRyxLQUFLLENBQUM7UUFHakM7O1dBRUc7UUFDSyxzQkFBaUIsR0FBRyxZQUFZLENBQUM7UUFHekM7Ozs7O1dBS0c7UUFDSyx5QkFBb0IsR0FBRyxFQUFFLENBQUM7SUFTbEMsQ0FBQztJQUdEOzs7Ozs7Ozs7Ozs7Ozs7OztPQWlCRztJQUNILGtCQUFrQixDQUFDLEtBQVk7UUFFM0IsSUFBRyxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLEVBQUM7WUFFcEIsTUFBTSxJQUFJLEtBQUssQ0FBQyxxQ0FBcUMsQ0FBQyxDQUFDO1NBQzFEO1FBRUQsSUFBSSxDQUFDLG9CQUFvQixHQUFHLEtBQUssR0FBRyxJQUFJLENBQUMsaUJBQWlCLEdBQUcsQ0FB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LG1EQUFtRDtRQUNuRCxJQUFHLENBQUMsUUFBUSxFQUFDO1lBRVQsMENBQTBDO1lBQzFDLElBQUcsTUFBTSxJQUFJLElBQUksSUFBSSxNQUFNLElBQUksRUFBRSxFQUFDO2dCQUU5QixPQUFPLElBQUksQ0FBQzthQUNmO1lBRUQsTUFBTSxJQUFJLEtBQUssQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO1NBQzVDO1FBRUQsT0FBTyxNQUFNLENBQUMsT0FBTyxDQUFDLFlBQVksRUFBRSxFQUFFLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDbkQsQ0FBQztJQUdEOzs7T0FHRztJQUNLLG9CQUFvQixDQUFDLEtBQVMsRUFBRSxTQUFTLEdBQUcsRUFBRSxFQUFFLFlBQVksR0FBRyw0QkFBNEI7UUFFL0YsSUFBSSxRQUFRLEdBQUcsQ0FBQyxPQUFPLEtBQUssS0FBSyxRQUFRLElBQUksS0FBSyxZQUFZLE1BQU0sQ0FBQyxDQUFDO1FBRXRFLElBQUcsQ0FBQyxRQUFRLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBQztZQUVqQyxNQUFNLElBQUksS0FBSyxDQUFDLFNBQVMsR0FBRyxHQUFHLEdBQUcsWUFBWSxDQUFDLENBQUM7U0FDbkQ7SUFDTCxDQUFDOzhHQWxvQlEsY0FBYztrSEFBZCxjQUFjLGNBRmIsTUFBTTs7MkZBRVAsY0FBYztrQkFIMUIsVUFBVTttQkFBQztvQkFDVixVQUFVLEVBQUUsTUFBTTtpQkFDbkIiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcclxuICogVHVyYm9HVUkgaXMgQSBsaWJyYXJ5IHRoYXQgaGVscHMgd2l0aCB0aGUgbW9zdCBjb21tb24gYW5kIGdlbmVyaWMgVUkgZWxlbWVudHMgYW5kIGZ1bmN0aW9uYWxpdGllc1xyXG4gKlxyXG4gKiBXZWJzaXRlIDogLT4gaHR0cDovL3d3dy50dXJib2d1aS5vcmdcclxuICogTGljZW5zZSA6IC0+IExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAuIFlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cclxuICogTGljZW5zZSBVcmwgOiAtPiBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcclxuICogQ29weVJpZ2h0IDogLT4gQ29weXJpZ2h0IDIwMTggRWRlcnRvbmUgQWR2YW5kZWQgU29sdXRpb25zLiBodHRwczovL3d3dy5lZGVydG9uZS5jb21cclxuICovXHJcblxyXG5pbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IFNpbmdsZXRvbmVTdHJpY3RDbGFzcyB9IGZyb20gJy4uL21vZGVsL2NsYXNzZXMvU2luZ2xldG9uZVN0cmljdENsYXNzJztcclxuXHJcblxyXG4vKipcclxuICogTWFuYWdlcyBhcHBsaWNhdGlvbiB0ZXh0IHRyYW5zbGF0aW9ucyBhbmQgbGFuZ3VhZ2VzXHJcbiAqL1xyXG5ASW5qZWN0YWJsZSh7XHJcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnLFxyXG59KVxyXG5leHBvcnQgY2xhc3MgTG9jYWxlc1NlcnZpY2UgZXh0ZW5kcyBTaW5nbGV0b25lU3RyaWN0Q2xhc3Mge1xyXG5cclxuXHJcbiAgICAvKipcclxuICAgICAqIGlmIHRoZSBjbGFzcyBoYXMgYmVlbiBjb3JyZWN0bHkgaW5pdGlhbGl6ZWQgYW5kIHRyYW5zbGF0aW9ucyBoYXZlIGJlZW4gY29ycmVjdGx5IGxvYWRlZFxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIF9pc0luaXRpYWxpemVkID0gZmFsc2U7XHJcbiAgICAgICAgXHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBAc2VlIGdldExvY2FsZXMoKVxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIF9sb2NhbGVzOnN0cmluZ1tdID0gW107XHJcbiAgICBcclxuICAgIFxyXG4gICAgLyoqXHJcbiAgICAgKiBAc2VlIGdldExhbmd1YWdlcygpXHJcbiAgICAgKi9cclxuICAgIHByaXZhdGUgX2xhbmd1YWdlczpzdHJpbmdbXSA9IFtdO1xyXG4gICAgICAgIFxyXG4gICAgXHJcbiAgICAvKipcclxuICAgICAqIFN0b3JlcyBhbGwgdGhlIGxvYWRlZCBsb2NhbGl6YXRpb24gZGF0YSBieSBsaWJyYXJ5IG5hbWUsIGJ1bmRsZSBuYW1lLCBrZXkgYW5kIGxvY2FsZXNcclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSBfbG9hZGVkVHJhbnNsYXRpb25zOmFueSA9IHt9O1xyXG4gICAgXHJcbiAgICBcclxuICAgIC8qKlxyXG4gICAgICogU3RvcmVzIGEgbWVtb3J5IGNhY2hlIHRvIGltcHJvdmUgcGVyZm9ybWFuY2Ugd2hlbiBvdXRwdXRpbmcgdHJhbnNsYXRpb25zXHJcbiAgICAgKi9cclxuICAgIHByaXZhdGUgX2tleVZhbHVlc0NhY2hlOmFueSA9IHt9O1xyXG5cclxuXHJcbiAgICAvKipcclxuICAgICAqIEBzZWUgc2V0V2lsZENhcmRzRm9ybWF0KClcclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSBfd2lsZENhcmRzRm9ybWF0ID0gJ3tOfSc7XHJcblxyXG5cclxuICAgIC8qKlxyXG4gICAgICogQHNlZSBzZXRNaXNzaW5nS2V5Rm9ybWF0KClcclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSBfbWlzc2luZ0tleUZvcm1hdCA9ICckZXhjZXB0aW9uJztcclxuXHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBTdG9yZXMgYSBoYXNoIHZhbHVlIHRoYXQgaXMgdXNlZCB0byBpbXByb3ZlIHRoZSBwZXJmb3JtYW5jZSBmb3IgdHJhbnNsYXRpb24gdCgpIG1ldGhvZHMuXHJcbiAgICAgKiBUaGlzIGlzIGNvbXB1dGVkIGJhc2VkIG9uIF93aWxkQ2FyZHNGb3JtYXQgcGx1cyBfbWlzc2luZ0tleUZvcm1hdCBwbHVzIHRoZSBjdXJyZW50IHByaW1hcnkgbG9jYWxlXHJcbiAgICAgKiBNZXRob2RzIHRoYXQgY2hhbmdlIHRoZXNlIHZhbHVlcyB3aWxsIHJlY2FsY3VsYXRlIHRoZSBoYXNoIHN0cmluZywgc28gd2hlbiBjYWxsaW5nIHRyYW5zbGF0aW9uIG1ldGhvZHMsIHRoZVxyXG4gICAgICogcGVyZm9ybWFuY2Ugd2lsbCBiZSBhcyBmYXN0IGFzIHBvc3NpYmxlLlxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIF9jYWNoZUhhc2hCYXNlU3RyaW5nID0gJyc7XHJcbiAgICBcclxuICAgIFxyXG4gICAgLyoqXHJcbiAgICAgKiBGdWxseSBmZWF0dXJlZCB0cmFuc2xhdGlvbiBtYW5hZ2VyIHRvIGJlIHVzZWQgd2l0aCBhbnkgYXBwbGljYXRpb24gdGhhdCByZXF1aXJlcyB0ZXh0IGludGVybmF0aW9uYWxpemF0aW9uLlxyXG4gICAgICovXHJcbiAgICBjb25zdHJ1Y3RvcigpIHtcclxuXHJcbiAgICAgICAgc3VwZXIoTG9jYWxlc1NlcnZpY2UpO1xyXG4gICAgfVxyXG4gICAgXHJcbiAgICBcclxuICAgIC8qKlxyXG4gICAgICogV2lsZGNhcmRzIGFyZSBzdHJpbmcgZnJhZ21lbnRzIHRoYXQgYXJlIHBsYWNlZCBpbnNpZGUgdGhlIHRyYW5zbGF0ZWQgdGV4dHMuIFRoZWlyIG1haW4gcHVycG9zZSBpcyB0byBiZSByZXBsYWNlZCBhdFxyXG4gICAgICogcnVudGltZSBieSBjdXN0b20gdmFsdWVzIGxpa2UgZm9yIGV4YW1wbGUgYSB1c2VyIG5hbWUsIGEgZGF0ZSwgYSBudW1lcmljIHZhbHVlLCBldGMuLlxyXG4gICAgICpcclxuICAgICAqIFRoaXMgY2xhc3MgaGVscHMgd2l0aCB0aGlzIHByb2Nlc3MgYnkgaW5jbHVkaW5nIGEgcGFyYW1ldGVyIGNhbGxlZCAndG9SZXBsYWNlJyBvbiBhbGwgLT50IG1ldGhvZHMgd2hpY2ggYWxsb3dzIHVzXHJcbiAgICAgKiB0byBzcGVjaWZ5IGEgc3RyaW5nIG9yIGxpc3Qgb2Ygc3RyaW5ncyB0aGF0IHdpbGwgcmVwbGFjZSB0aGUgcmVzcGVjdGl2ZSB3aWxkY2FyZHMgb24gdGhlIHRyYW5zbGF0ZWQgdGV4dC4gRWFjaCB3aWxkY2FyZFxyXG4gICAgICogbXVzdCBmb2xsb3cgdGhlIGZvcm1hdCBzcGVjaWZpZWQgaGVyZSwgYW5kIGNvbnRhaW4gYSBudW1lcmljIGRpZ2l0IHRoYXQgd2lsbCBiZSB1c2VkIHRvIGZpbmQgdGhlIHJlcGxhY2VtZW50IHRleHQgYXQgdGhlXHJcbiAgICAgKiAndG9SZXBsYWNlJyBsaXN0LiBGb3IgZXhhbXBsZSwgaWYgd2UgZGVmaW5lICROIGFzIHRoZSB3aWxkY2FyZCBmb3JtYXQsIGFuZCB3ZSBoYXZlIGEgdHJhbnNsYXRpb24gdGhhdCBjb250YWlucyAkMCwgJDEsICQyLFxyXG4gICAgICogJDAgd2lsbCBiZSByZXBsYWNlZCB3aXRoIHRoZSBmaXJzdCBlbGVtZW50IG9uIHRvUmVwbGFjZSwgJDEgd2l0aCB0aGUgc2Vjb25kIGFuZCBzby5cclxuICAgICAqXHJcbiAgICAgKiBXZSB1c3VhbGx5IHNldCB0aGlzIGJlZm9yZSBpbml0aWFsaXppbmcgdGhlIGNsYXNzIHRyYW5zbGF0aW9uIGRhdGFcclxuICAgICAqXHJcbiAgICAgKiBOb3RpY2UgdGhhdCBOIGlzIG1hbmRheW9yeSBvbiB0aGUgd2lsZGNhcmRzIGZvcm1hdCBhbmQgdGhlIGZpcnN0IGluZGV4IHZhbHVlIGlzIDAuXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIHZhbHVlIFRoZSB3aWxkY2FyZHMgZm9ybWF0IHdlIHdhbnQgdG8gc2V0XHJcbiAgICAgKiBcclxuICAgICAqIEByZXR1cm5zIFRoZSB2YWx1ZSB0aGF0J3MgYmVlbiBzZXRcclxuICAgICAqL1xyXG4gICAgc2V0V2lsZENhcmRzRm9ybWF0KHZhbHVlOnN0cmluZykge1xyXG5cclxuICAgICAgICBpZighdmFsdWUuaW5jbHVkZXMoJ04nKSl7XHJcbiAgICAgICAgXHJcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIk4gaXMgbWFuZGF0b3J5IHRvIHJlcGxhY2Ugd2lsZGNhcmRzXCIpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgdGhpcy5fY2FjaGVIYXNoQmFzZVN0cmluZyA9IHZhbHVlICsgdGhpcy5fbWlzc2luZ0tleUZvcm1hdCArICgodGhpcy5fbG9jYWxlcy5sZW5ndGggPiAwKSA/IHRoaXMuX2xvY2FsZXNbMF0gOiAnJyk7XHJcblxyXG4gICAgICAgIHRoaXMuX3dpbGRDYXJkc0Zvcm1hdCA9IHZhbHVlO1xyXG4gICAgICAgIFxyXG4gICAgICAgIHJldHVybiB2YWx1ZTtcclxuICAgIH1cclxuICAgIFxyXG4gICAgXHJcbiAgICAvKipcclxuICAgICAqIERlZmluZXMgdGhlIGJlaGF2aW91ciBmb3IgZ2V0KCksIGdldFN0YXJ0Q2FzZSgpLCBldGMuLi4gbWV0aG9kcyB3aGVuIGEga2V5IGlzIG5vdCBmb3VuZCBvblxyXG4gICAgICogYSBidW5kbGUgb3IgdGhlIGJ1bmRsZSBkb2VzIG5vdCBleGlzdFxyXG4gICAgICpcclxuICAgICAqIElmIG1pc3NpbmdLZXlGb3JtYXQgaXMgYW4gZW1wdHkgc3RyaW5nLCBhbGwgbWlzc2luZyBrZXlzIHdpbGwgcmV0dXJuIGFuIGVtcHR5IHZhbHVlIChub3QgcmVjb21tZW5kZWQpXHJcbiAgICAgKlxyXG4gICAgICogSWYgbWlzc2luZ0tleUZvcm1hdCBjb250YWlucyBhIHN0cmluZywgdGhhdCBzdHJpbmcgd2lsbCBiZSBhbHdheXMgcmV0dXJuZWQgZm9yIG1pc3Npbmcga2V5c1xyXG4gICAgICpcclxuICAgICAqIElmIG1pc3NpbmdLZXlGb3JtYXQgY29udGFpbnMgYSBzdHJpbmcgd2l0aCBvbmUgb2YgdGhlIGZvbGxvd2luZyBwcmVkZWZpbmVkIHdpbGRjYXJkczo8YnI+XHJcbiAgICAgKiAgICAtICRrZXkgd2lsbCBiZSByZXBsYWNlZCB3aXRoIGtleSBuYW1lLiBFeGFtcGxlOiBnZXQoXCJOQU1FXCIpIHdpbGwgb3V0cHV0IFtOQU1FXSBpZiBrZXkgaXMgbm90IGZvdW5kIGFuZCBtaXNzaW5nS2V5Rm9ybWF0ID0gJ1ska2V5XSc8YnI+XHJcbiAgICAgKiAgICAtICRleGNlcHRpb24gKGRlZmF1bHQgdmFsdWUpIHdpbGwgdGhyb3cgYW4gZXhjZXB0aW9uIHdpdGggdGhlIHByb2JsZW0gY2F1c2UgZGVzY3JpcHRpb24uXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIHZhbHVlIFRoZSBtaXNzaW5nIGtleSBmb3JtYXQgd2Ugd2FudCB0byBzZXRcclxuICAgICAqIFxyXG4gICAgICogQHJldHVybnMgVGhlIHZhbHVlIHRoYXQncyBiZWVuIHNldFxyXG4gICAgICovXHJcbiAgICBzZXRNaXNzaW5nS2V5Rm9ybWF0KHZhbHVlOnN0cmluZykge1xyXG5cclxuICAgICAgICB0aGlzLl9jYWNoZUhhc2hCYXNlU3RyaW5nID0gdGhpcy5fd2lsZENhcmRzRm9ybWF0ICsgdmFsdWUgKyAoKHRoaXMuX2xvY2FsZXMubGVuZ3RoID4gMCkgPyB0aGlzLl9sb2NhbGVzWzBdIDogJycpO1xyXG5cclxuICAgICAgICB0aGlzLl9taXNzaW5nS2V5Rm9ybWF0ID0gdmFsdWU7XHJcbiAgICAgICAgXHJcbiAgICAgICAgcmV0dXJuIHZhbHVlO1xyXG4gICAgfVxyXG4gICAgXHJcbiAgICBcclxuICAgIC8qKlxyXG4gICAgICogQHNlZSBzZXRNaXNzaW5nS2V5Rm9ybWF0KClcclxuICAgICAqL1xyXG4gICAgZ2V0TWlzc2luZ0tleUZvcm1hdCgpIHtcclxuXHJcbiAgICAgICAgcmV0dXJuIHRoaXMuX21pc3NpbmdLZXlGb3JtYXQ7XHJcbiAgICB9XHJcbiAgICBcclxuICAgIFxyXG4gICAgLyoqXHJcbiAgICAgKiBJbml0aWFsaXplcyB0aGUgdHJhbnNsYXRpb24gc3lzdGVtIGJ5IGxvYWRpbmcgYW5kIHBhcnNpbmcgYnVuZGxlIGZpbGVzIGZyb20gdGhlIHNwZWNpZmllZCB0cmFuc2xhdGlvbnMgcGF0aC5cclxuICAgICAqIFxyXG4gICAgICogQHBhcmFtIHRyYW5zbGF0aW9uc1BhdGggLSBVcmwgd2hlcmUgdGhlIHRyYW5zbGF0aW9ucyBKc29uIHN0cnVjdHVyZSBvZiBsaWJyYXJpZXMvYnVuZGxlcy9sb2NhbGVzL2tleXMgaXMgYXZhaWxhYmxlLlxyXG4gICAgICogQHBhcmFtIGxvY2FsZXMgQW4gYXJyYXkgb2YgbG9jYWxlIGNvZGVzIChlLmcuLCBbJ2VuX1VTJywgJ2VzX0VTJywgJ2ZyX0ZSJ10pIHRvIGxvYWQuIFRoZXNlIHdpbGwgYmUgYWRkZWQgdG8gdGhlIHRyYW5zbGF0aW9uXHJcbiAgICAgKiAgICAgICAgcGF0aCB1c2luZyB0aGUgZm9sbG93aW5nIGZvcm1hdDogdHJhbnNsYXRpb25zUGF0aC9lbl9VUy1lc19FUy1mcl9GUi4gVGhlIG9yZGVyIG9mIHRoaXMgYXJyYXkgd2lsbCBkZXRlcm1pbmUgdGhlXHJcbiAgICAgKiAgICAgICAgdHJhbnNsYXRpb24gcHJpb3JpdHlcclxuICAgICAqIEBwYXJhbSBwYXJhbWV0ZXJzIEFueSBleHRyYSBwYXJhbWV0ZXJzIHRvIGJlIGF0dGFjaGVkIHRvIHRoZSB0cmFuc2xhdGlvbnNQYXRoIGFmdGVyIHRoZSBsb2NhbGVzIGxpa2UgL3BhcmFtMS9wYXJhbTIvIGV0Y1xyXG4gICAgICogXHJcbiAgICAgKiBAcmV0dXJuIEEgcHJvbWlzZSB0aGF0IHdpbGwgcmVzb2x2ZSBpZiB0aGUgdHJhbnNsYXRpb25zIGdldCBjb3JyZWN0bHkgbG9hZGVkLCBvciByZWplY3Qgd2l0aCBhbiBlcnJvciBpZiBsb2FkIGZhaWxzIFxyXG4gICAgICovXHJcbiAgICBpbml0aWFsaXplKHRyYW5zbGF0aW9uc1BhdGg6c3RyaW5nLCBsb2NhbGVzOnN0cmluZ1tdLCBwYXJhbWV0ZXJzOnN0cmluZ1tdKXtcclxuICAgIFxyXG4gICAgICAgIHRoaXMuX2lzSW5pdGlhbGl6ZWQgPSBmYWxzZTtcclxuICAgICAgICB0aGlzLl9sb2FkZWRUcmFuc2xhdGlvbnMgPSB7fTtcclxuICAgICAgICBcclxuICAgICAgICAvLyBWYWxpZGF0ZSByZWNlaXZlZCBsb2NhbGVzIGFyZSBjb3JyZWN0XHJcbiAgICAgICAgZm9yKGNvbnN0IGxvY2FsZSBvZiBsb2NhbGVzKSB7XHJcblxyXG4gICAgICAgICAgICB0aGlzLl92YWxpZGF0ZUxvY2FsZVN0cmluZyhsb2NhbGUpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBcclxuICAgICAgICBsZXQgdHJhbnNsYXRpb25zRnVsbFBhdGggPSB0cmFuc2xhdGlvbnNQYXRoICsgJy8nICsgbG9jYWxlcy5qb2luKCctJykgKyAnLycgKyBwYXJhbWV0ZXJzLmpvaW4oJy8nKTtcclxuICAgICAgICBcclxuICAgICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgICAgIFxyXG4gICAgICAgICAgICBmZXRjaCh0cmFuc2xhdGlvbnNGdWxsUGF0aCkudGhlbihyZXNwb25zZSA9PiB7XHJcbiAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgIGlmICghcmVzcG9uc2Uub2spIHtcclxuICAgICAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBIVFRQIGVycm9yISBzdGF0dXM6ICR7cmVzcG9uc2Uuc3RhdHVzfWApO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgXHJcbiAgICAgICAgICAgICAgICByZXR1cm4gcmVzcG9uc2UuanNvbigpO1xyXG4gICAgICAgICAgXHJcbiAgICAgICAgICAgIH0pLnRoZW4oZGF0YSA9PiB7XHJcbiAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgIHRoaXMuX2xvYWRlZFRyYW5zbGF0aW9ucyA9IGRhdGE7XHJcbiAgICAgICAgICAgICAgICB0aGlzLl9pc0luaXRpYWxpemVkID0gdHJ1ZTtcclxuICAgICAgICAgICAgICAgIHRoaXMuX2xvY2FsZXMgPSBsb2NhbGVzO1xyXG4gICAgICAgICAgICAgICAgdGhpcy5fbGFuZ3VhZ2VzID0gbG9jYWxlcy5tYXAoKGw6IHN0cmluZykgPT4gbC5zdWJzdHJpbmcoMCwgMikpO1xyXG4gICAgICAgICAgICAgICAgdGhpcy5fY2FjaGVIYXNoQmFzZVN0cmluZyA9IHRoaXMuX3dpbGRDYXJkc0Zvcm1hdCArIHRoaXMuX21pc3NpbmdLZXlGb3JtYXQgKyB0aGlzLl9sb2NhbGVzWzBdO1xyXG4gICAgICAgICAgICAgICAgXHJcbiAgICAgICAgICAgICAgICByZXNvbHZlKHVuZGVmaW5lZCk7XHJcbiAgICAgICAgICBcclxuICAgICAgICAgICAgfSkuY2F0Y2goZXJyb3IgPT4ge1xyXG4gICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgIHJlamVjdChuZXcgRXJyb3IoYEVSUk9SIExPQURJTkcgTE9DQUxFUyBGUk9NOiAke3RyYW5zbGF0aW9uc0Z1bGxQYXRofVxcbmAgKyBlcnJvcikpO1xyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICB9KTtcclxuICAgIH1cclxuICAgIFxyXG4gICAgXHJcbiAgICAvKipcclxuICAgICAqIENoZWNrIGlmIHRoZSBjbGFzcyBoYXMgYmVlbiBjb3JyZWN0bHkgaW5pdGlhbGl6ZWQgYW5kIHRyYW5zbGF0aW9ucyBoYXZlIGJlZW4gY29ycmVjdGx5IGxvYWRlZFxyXG4gICAgICovXHJcbiAgICBpc0luaXRpYWxpemVkKCl7XHJcblxyXG4gICAgICAgIHJldHVybiB0aGlzLl9pc0luaXRpYWxpemVkO1xyXG4gICAgfVxyXG5cclxuXHJcbiAgICAvKipcclxuICAgICAqIEF1eCBtZXRob2QgdG8gdmVyaWZ5IHRoYXQgdGhpcyBjbGFzcyBpcyBjb3JyZWN0bHkgaW5pdGlhbGl6ZWQgd2l0aCB0cmFuc2xhdGlvbiBkYXRhXHJcbiAgICAgKi9cclxuICAgIHByaXZhdGUgX3ZhbGlkYXRlSW5pdGlhbGl6ZWQoKXtcclxuXHJcbiAgICAgICAgaWYoIXRoaXMuX2lzSW5pdGlhbGl6ZWQpe1xyXG5cclxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdMb2NhbGVzTWFuYWdlciBub3QgaW5pdGlhbGl6ZWQnKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICBcclxuICAgIFxyXG4gICAgLyoqXHJcbiAgICAgKiBDaGVja3MgaWYgdGhlIHNwZWNpZmllZCBsb2NhbGUgaXMgY3VycmVudGx5IGxvYWRlZCBmb3IgdGhlIGN1cnJlbnRseSBkZWZpbmVkIGJ1bmRsZXMgYW5kIHBhdGhzLlxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSBsb2NhbGUgQSBsb2NhbGUgdG8gY2hlY2suIEZvciBleGFtcGxlICdlbl9VUydcclxuICAgICAqXHJcbiAgICAgKiBAcmV0dXJuIFRydWUgaWYgdGhlIGxvY2FsZSBpcyBjdXJyZW50bHkgbG9hZGVkIG9uIHRoZSBjbGFzcywgZmFsc2UgaWYgbm90LlxyXG4gICAgICovXHJcbiAgICBpc0xvY2FsZUxvYWRlZChsb2NhbGU6c3RyaW5nKXtcclxuXHJcbiAgICAgICAgdGhpcy5fdmFsaWRhdGVMb2NhbGVTdHJpbmcobG9jYWxlKTtcclxuXHJcbiAgICAgICAgcmV0dXJuIHRoaXMuX2xvY2FsZXMuaW5jbHVkZXMobG9jYWxlKTtcclxuICAgIH1cclxuICAgIFxyXG4gICAgXHJcbiAgICAvKipcclxuICAgICAqIEF1eCBtZXRob2QgdG8gdmFsaWRhdGUgdGhhdCBhIGxvY2FsZSBzdHJpbmcgaXMgY29ycmVjdGx5IGZvcm1hdHRlZFxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSBzdHJpbmcgJGxvY2FsZSBBIGxvY2FsZSBzdHJpbmdcclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSBfdmFsaWRhdGVMb2NhbGVTdHJpbmcobG9jYWxlOnN0cmluZyl7XHJcbiAgICAgICAgXHJcbiAgICAgICAgaWYoIS9eW2Etel17Mn1fW0EtWl17Mn0kLy50ZXN0KGxvY2FsZSkpIHtcclxuXHJcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignbG9jYWxlIG11c3QgYmUgYSB2YWxpZCB4eF9YWCB2YWx1ZScpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIFxyXG4gICAgXHJcbiAgICAvKipcclxuICAgICAqIENoZWNrcyBpZiB0aGUgc3BlY2lmaWVkIDIgZGlnaXQgbGFuZ3VhZ2UgaXMgY3VycmVudGx5IGxvYWRlZCBmb3IgdGhlIGN1cnJlbnRseSBkZWZpbmVkIGJ1bmRsZXMgYW5kIHBhdGhzLlxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSBsYW5ndWFnZSBBIGxhbmd1YWdlIHRvIGNoZWNrLiBGb3IgZXhhbXBsZSAnZW4nXHJcbiAgICAgKlxyXG4gICAgICogQHJldHVybiBUcnVlIGlmIHRoZSBsYW5ndWFnZSBpcyBjdXJyZW50bHkgbG9hZGVkIG9uIHRoZSBjbGFzcywgZmFsc2UgaWYgbm90LlxyXG4gICAgICovXHJcbiAgICBpc0xhbmd1YWdlTG9hZGVkKGxhbmd1YWdlOnN0cmluZyl7XHJcblxyXG4gICAgICAgIHRoaXMuX3ZhbGlkYXRlTGFuZ3VhZ2VTdHJpbmcobGFuZ3VhZ2UpO1xyXG5cclxuICAgICAgICByZXR1cm4gdGhpcy5fbGFuZ3VhZ2VzLmluY2x1ZGVzKGxhbmd1YWdlKTtcclxuICAgIH1cclxuICAgIFxyXG4gICAgXHJcbiAgICAvKipcclxuICAgICAqIEF1eCBtZXRob2QgdG8gdmFsaWRhdGUgdGhhdCBhIGxhbmd1YWdlIHN0cmluZyBpcyBjb3JyZWN0bHkgZm9ybWF0dGVkXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIGxhbmd1YWdlIEEgMiBkaWdpdCBsYW5ndWFnZSBzdHJpbmdcclxuICAgICAqL1xyXG4gICAgX3ZhbGlkYXRlTGFuZ3VhZ2VTdHJpbmcobGFuZ3VhZ2U6c3RyaW5nKXtcclxuXHJcbiAgICAgICAgaWYgKCEvXlthLXpdezJ9JC8udGVzdChsYW5ndWFnZSkpIHtcclxuXHJcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignbGFuZ3VhZ2UgbXVzdCBiZSBhIHZhbGlkIDIgZGlnaXQgdmFsdWUnKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICBcclxuICAgIFxyXG4gICAgLyoqXHJcbiAgICAgKiBHZXQgdGhlIHRyYW5zbGF0aW9uIHRvIHRoZSBjdXJyZW50IHByaW1hcnkgbG9jYWxlIGZvciB0aGUgZ2l2ZW4ga2V5LCBsaWJyYXJ5IGFuZCBidW5kbGVcclxuICAgICAqXHJcbiAgICAgKiBAcGFyYW0gc3RyaW5nIGtleSBUaGUga2V5IHdlIHdhbnQgdG8gcmVhZCBmcm9tIHRoZSBzcGVjaWZpZWQgcmVzb3VyY2UgYnVuZGxlXHJcbiAgICAgKiBAcGFyYW0gc3RyaW5nIGJ1bmRsZVBhdGggQSBzdHJpbmcgd2l0aCB0aGUgZm9ybWF0ICdsaWJyYXJ5X25hbWUvYnVuZGxlX25hbWUnIHRoYXQgaXMgdXNlZCB0byBsb2NhdGUgdGhlIGJ1bmRsZSB3ZXJlIHRoZSBrZXkgdG8gdHJhbnNsYXRlIGlzIGZvdW5kXHJcbiAgICAgKiBAcGFyYW0gYXJyYXkgcmVwbGFjZVdpbGRjYXJkcyBBIGxpc3Qgb2YgdmFsdWVzIHRoYXQgd2lsbCByZXBsYWNlIHdpbGRjYXJkcyB0aGF0IG1heSBiZSBmb3VuZCBvbiB0aGUgdHJhbnNsYXRlZCB0ZXh0LiBFYWNoIHdpbGRjYXJkXHJcbiAgICAgKiAgICAgICAgd2lsbCBiZSByZXBsYWNlZCB3aXRoIHRoZSBlbGVtZW50IHdob3NlIGluZGV4IG9uIHRvUmVwbGFjZSBtYXRjaGVzIGl0LiBDaGVjayB0aGUgZG9jdW1lbnRhdGlvbiBmb3IgdGhpcy53aWxkQ2FyZHNGb3JtYXRcclxuICAgICAqICAgICAgICBwcm9wZXJ0eSB0byBrbm93IG1vcmUgYWJvdXQgaG93IHRvIHNldHVwIHdpbGRjYXJkcy5cclxuICAgICAqXHJcbiAgICAgKiBAc2VlIHNldFdpbGRDYXJkc0Zvcm1hdCgpXHJcbiAgICAgKlxyXG4gICAgICogQHJldHVybiBUaGUgdHJhbnNsYXRlZCB0ZXh0XHJcbiAgICAgKi9cclxuICAgIHQoa2V5OnN0cmluZywgYnVuZGxlUGF0aDpzdHJpbmcsIHJlcGxhY2VXaWxkY2FyZHM6c3RyaW5nW10gPSBbXSkge1xyXG5cclxuICAgICAgICB0aGlzLl92YWxpZGF0ZUluaXRpYWxpemVkKCk7XHJcblxyXG4gICAgICAgIC8vIENyZWF0ZSBhIGNhY2hlIGtleSB0byBpbXByb3ZlIHBlcmZvcm1hbmNlIHdoZW4gcmVxdWVzdGluZyB0aGUgc2FtZSBrZXkgdHJhbnNsYXRpb24gc2V2ZXJhbCB0aW1lc1xyXG4gICAgICAgIGNvbnN0IGNhY2hlS2V5ID0gYCR7dGhpcy5fY2FjaGVIYXNoQmFzZVN0cmluZ30ke2tleX0ke2J1bmRsZVBhdGh9JHtyZXBsYWNlV2lsZGNhcmRzLmpvaW4oJycpfWA7XHJcblxyXG4gICAgICAgIGlmICghdGhpcy5fa2V5VmFsdWVzQ2FjaGVbY2FjaGVLZXldKSB7XHJcblxyXG4gICAgICAgICAgICB0aGlzLl9mb3JjZU5vbkVtcHR5U3RyaW5nKGtleSwgJycsICdrZXkgbXVzdCBiZSBub24gZW1wdHkgc3RyaW5nJyk7XHJcbiAgICAgICAgICAgIHRoaXMuX2ZvcmNlTm9uRW1wdHlTdHJpbmcoYnVuZGxlUGF0aCwgJycsICdidW5kbGVQYXRoIG11c3QgYmUgbm9uIGVtcHR5IHN0cmluZycpO1xyXG4gICAgICAgICAgICBcclxuICAgICAgICAgICAgY29uc3QgW2xpYnJhcnksIGJ1bmRsZV0gPSBidW5kbGVQYXRoLnNwbGl0KCcvJyk7XHJcblxyXG4gICAgICAgICAgICB0aGlzLl9mb3JjZU5vbkVtcHR5U3RyaW5nKGxpYnJhcnksICcnLCAnbm8gbGlicmFyeSBzcGVjaWZpZWQgb24gYnVuZGxlUGF0aCcpO1xyXG4gICAgICAgICAgICB0aGlzLl9mb3JjZU5vbkVtcHR5U3RyaW5nKGJ1bmRsZSwgJycsICdubyBidW5kbGUgc3BlY2lmaWVkIG9uIGJ1bmRsZVBhdGgnKTtcclxuICAgICAgICAgICAgXHJcbiAgICAgICAgICAgIGNvbnN0IHJlcGxhY2VtZW50c0NvdW50ID0gcmVwbGFjZVdpbGRjYXJkcy5sZW5ndGg7XHJcblxyXG4gICAgICAgICAgICAvLyBMb29wIGFsbCB0aGUgbG9jYWxlcyB0byBmaW5kIHRoZSBmaXJzdCBvbmUgd2l0aCBhIHZhbHVlIGZvciB0aGUgc3BlY2lmaWVkIGtleVxyXG4gICAgICAgICAgICBmb3IgKGNvbnN0IGxvY2FsZSBvZiB0aGlzLl9sb2NhbGVzKSB7XHJcblxyXG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuX2xvYWRlZFRyYW5zbGF0aW9uc1tsaWJyYXJ5XT8uW2J1bmRsZV0/Lltsb2NhbGVdPy5ba2V5XSkge1xyXG5cclxuICAgICAgICAgICAgICAgICAgICBsZXQgcmVzdWx0ID0gdGhpcy5fbG9hZGVkVHJhbnNsYXRpb25zW2xpYnJhcnldW2J1bmRsZV1bbG9jYWxlXVtrZXldO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAvLyBSZXBsYWNlIGFsbCB3aWxkY2FyZHMgb24gdGhlIHRleHQgd2l0aCB0aGUgc3BlY2lmaWVkIHJlcGxhY2VtZW50cyBpZiBhbnlcclxuICAgICAgICAgICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHJlcGxhY2VtZW50c0NvdW50OyBpKyspIHtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdCA9IHRoaXMuX3JlcGxhY2UocmVzdWx0LCB0aGlzLl9yZXBsYWNlKHRoaXMuX3dpbGRDYXJkc0Zvcm1hdCwgJ04nLCBpLnRvU3RyaW5nKCkpLCByZXBsYWNlV2lsZGNhcmRzW2ldKTtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX2tleVZhbHVlc0NhY2hlW2NhY2hlS2V5XSA9IHJlc3VsdDtcclxuICAgICAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBDaGVjayBpZiBhbiBleGNlcHRpb24gbmVlZHMgdG8gYmUgdGhyb3duIGlmIHRoZSBzcGVjaWZpZWQga2V5IGlzIG5vdCBmb3VuZCBvbiB0aGlzIGJ1bmRsZVxyXG4gICAgICAgICAgICBpZiAodGhpcy5fbWlzc2luZ0tleUZvcm1hdC5pbmNsdWRlcygnJGV4Y2VwdGlvbicpKSB7XHJcbiAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihga2V5IDwke2tleX0+IG5vdCBmb3VuZCBvbiAke2J1bmRsZVBhdGh9YCk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIHRoaXMuX2tleVZhbHVlc0NhY2hlW2NhY2hlS2V5XSA9IHRoaXMuX3JlcGxhY2UodGhpcy5fbWlzc2luZ0tleUZvcm1hdCwgJyRrZXknLCBrZXkpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgcmV0dXJuIHRoaXMuX2tleVZhbHVlc0NhY2hlW2NhY2hlS2V5XTtcclxuICAgIH1cclxuICAgIFxyXG4gICAgXHJcbiAgICAvKipcclxuICAgICAqIEdldCB0aGUgdHJhbnNsYXRpb24gZm9yIHRoZSBnaXZlbiBrZXkgYW5kIGJ1bmRsZSBhcyBhIHN0cmluZyB3aXRoIGFsbCB3b3JkcyBmaXJzdCBjaGFyYWN0ZXIgY2FwaXRhbGl6ZWRcclxuICAgICAqIGFuZCBhbGwgdGhlIHJlc3Qgb2YgdGhlIHdvcmQgd2l0aCBsb3dlciBjYXNlXHJcbiAgICAgKlxyXG4gICAgICogQHNlZSB0KClcclxuICAgICAqXHJcbiAgICAgKiBAcmV0dXJucyBUaGUgbG9jYWxpemVkIGFuZCBjYXNlIGZvcm1hdHRlZCB0ZXh0XHJcbiAgICAgKi9cclxuICAgIHRTdGFydENhc2Uoa2V5OnN0cmluZywgYnVuZGxlUGF0aDpzdHJpbmcsIHJlcGxhY2VXaWxkY2FyZHM6c3RyaW5nW10gPSBbXSkge1xyXG5cclxuICAgICAgICByZXR1cm4gdGhpcy50KGtleSwgYnVuZGxlUGF0aCwgcmVwbGFjZVdpbGRjYXJkcykuc3BsaXQoJyAnKVxyXG4gICAgICAgICAgICAgICAgLm1hcCgod29yZDphbnkpID0+IHdvcmQgPyB3b3JkWzBdLnRvVXBwZXJDYXNlKCkgKyB3b3JkLnNsaWNlKDEpLnRvTG93ZXJDYXNlKCkgOiAnJykuam9pbignICcpO1xyXG4gICAgfVxyXG4gICAgXHJcbiAgICBcclxuICAgIC8qKlxyXG4gICAgICogR2V0IHRoZSB0cmFuc2xhdGlvbiBmb3IgdGhlIGdpdmVuIGtleSBhbmQgYnVuZGxlIGFzIGFuIGFsbCB1cHBlciBjYXNlIHN0cmluZ1xyXG4gICAgICpcclxuICAgICAqIEBzZWUgdCgpXHJcbiAgICAgKlxyXG4gICAgICogQHJldHVybnMgVGhlIGxvY2FsaXplZCBhbmQgY2FzZSBmb3JtYXR0ZWQgdGV4dFxyXG4gICAgICovXHJcbiAgICB0QWxsVXBwZXJDYXNlKGtleTpzdHJpbmcsIGJ1bmRsZVBhdGg6c3RyaW5nLCByZXBsYWNlV2lsZGNhcmRzOnN0cmluZ1tdID0gW10pIHtcclxuXHJcbiAgICAgICAgcmV0dXJuIHRoaXMudChrZXksIGJ1bmRsZVBhdGgsIHJlcGxhY2VXaWxkY2FyZHMpLnRvVXBwZXJDYXNlKCk7XHJcbiAgICB9XHJcbiAgICBcclxuICAgIFxyXG4gICAgLyoqXHJcbiAgICAgKiBHZXQgdGhlIHRyYW5zbGF0aW9uIGZvciB0aGUgZ2l2ZW4ga2V5IGFuZCBidW5kbGUgYXMgYW4gYWxsIGxvd2VyIGNhc2Ugc3RyaW5nXHJcbiAgICAgKlxyXG4gICAgICogQHNlZSB0KClcclxuICAgICAqXHJcbiAgICAgKiBAcmV0dXJucyBUaGUgbG9jYWxpemVkIGFuZCBjYXNlIGZvcm1hdHRlZCB0ZXh0XHJcbiAgICAgKi9cclxuICAgIHRBbGxMb3dlckNhc2Uoa2V5OnN0cmluZywgYnVuZGxlUGF0aDpzdHJpbmcsIHJlcGxhY2VXaWxkY2FyZHM6c3RyaW5nW10gPSBbXSkge1xyXG5cclxuICAgICAgICByZXR1cm4gdGhpcy50KGtleSwgYnVuZGxlUGF0aCwgcmVwbGFjZVdpbGRjYXJkcykudG9Mb3dlckNhc2UoKTtcclxuICAgIH1cclxuICAgIFxyXG4gICAgXHJcbiAgICAvKipcclxuICAgICAqIEdldCB0aGUgdHJhbnNsYXRpb24gZm9yIHRoZSBnaXZlbiBrZXkgYW5kIGJ1bmRsZSBhcyBhIHN0cmluZyB3aXRoIHRoZSBmaXJzdCBjaGFyYWN0ZXIgYXMgVXBwZXIgY2FzZVxyXG4gICAgICogYW5kIGFsbCB0aGUgcmVzdCBhcyBsb3dlciBjYXNlXHJcbiAgICAgKlxyXG4gICAgICogQHNlZSB0KClcclxuICAgICAqXHJcbiAgICAgKiBAcmV0dXJucyBUaGUgbG9jYWxpemVkIGFuZCBjYXNlIGZvcm1hdHRlZCB0ZXh0XHJcbiAgICAgKi9cclxuICAgIHRGaXJzdFVwcGVyUmVzdExvd2VyKGtleTpzdHJpbmcsIGJ1bmRsZVBhdGg6c3RyaW5nLCByZXBsYWNlV2lsZGNhcmRzOnN0cmluZ1tdID0gW10pe1xyXG5cclxuICAgICAgICBjb25zdCBzdHJpbmcgPSB0aGlzLnQoa2V5LCBidW5kbGVQYXRoLCByZXBsYWNlV2lsZGNhcmRzKTtcclxuICAgICAgICBcclxuICAgICAgICByZXR1cm4gc3RyaW5nLmNoYXJBdCgwKS50b1VwcGVyQ2FzZSgpICsgc3RyaW5nLnNsaWNlKDEpLnRvTG93ZXJDYXNlKCk7XHJcbiAgICB9XHJcbiAgICBcclxuICAgIFxyXG4gICAgLyoqXHJcbiAgICAgKiBBIGxpc3Qgb2Ygc3RyaW5ncyBjb250YWluaW5nIHRoZSBsb2NhbGVzIHRoYXQgYXJlIHVzZWQgYnkgdGhpcyBjbGFzcyB0byB0cmFuc2xhdGUgdGhlIGdpdmVuIGtleXMsIHNvcnRlZCBieSBwcmVmZXJlbmNlLlxyXG4gICAgICogRWFjaCBzdHJpbmcgaXMgZm9ybWF0dGVkIGFzIGEgc3RhbmRhcmQgbG9jYWxlIGNvZGUgd2l0aCBsYW5ndWFnZSBhbmQgY291bnRyeSBqb2luZWQgYnkgYW4gdW5kZXJzY29yZSwgbGlrZTogZW5fVVMsIGZyX0ZSXHJcbiAgICAgKlxyXG4gICAgICogV2hlbiBhIGtleSBhbmQgYnVuZGxlIGFyZSByZXF1ZXN0ZWQgZm9yIHRyYW5zbGF0aW9uLCB0aGUgY2xhc3Mgd2lsbCBjaGVjayBvbiB0aGUgZmlyc3QgbGFuZ3VhZ2Ugb2YgdGhpc1xyXG4gICAgICogbGlzdCBmb3IgYSB0cmFuc2xhdGVkIHRleHQuIElmIG1pc3NpbmcsIHRoZSBuZXh0IG9uZSB3aWxsIGJlIHVzZWQsIGFuZCBzby4gVGhpcyBsaXN0IGlzIGNvbnN0cnVjdGVkIGFmdGVyIGluaXRpYWxpemVcclxuICAgICAqIG1ldGhvZHMgaXMgY2FsbGVkLlxyXG4gICAgICpcclxuICAgICAqIEBleGFtcGxlOiBBZnRlciBsb2FkaW5nIHRoZSBmb2xsb3dpbmcgbGlzdCBvZiBsb2NhbGVzIFsnZW5fVVMnLCAnZXNfRVMnLCAnZnJfRlInXSBpZiB3ZSBjYWxsIExvY2FsZXNNYW5hZ2VyLnQoJ0hFTExPJywgJ2xpYjEvZ3JlZXRpbmdzJylcclxuICAgICAqIHRoZSBsb2NhbGl6YXRpb24gbWFuYWdlciB3aWxsIHRyeSB0byBsb2NhdGUgdGhlIGVuX1VTIHZhbHVlIGZvciB0aGUgSEVMTE8gdGFnIG9uIHRoZSBncmVldGluZ3MgYnVuZGxlIGZvciB0aGUgbGlicmFyeSBsaWIxLlxyXG4gICAgICogSWYgdGhlIHRhZyBpcyBub3QgZm91bmQgZm9yIHRoZSBzcGVjaWZpZWQgbG9jYWxlIGFuZCBidW5kbGUsIHRoZSBzYW1lIHNlYXJjaCB3aWxsIGJlIHBlcmZvcm1lZCBmb3IgdGhlIGVzX0VTIGxvY2FsZSwgYW5kIHNvLCB0aWxsIGFcclxuICAgICAqIHZhbHVlIGlzIGZvdW5kIG9yIG5vIG1vcmUgbG9jYWxlcyBhcmUgZGVmaW5lZC5cclxuICAgICAqL1xyXG4gICAgZ2V0TG9jYWxlcygpe1xyXG5cclxuICAgICAgICByZXR1cm4gdGhpcy5fbG9jYWxlcztcclxuICAgIH1cclxuICAgIFxyXG4gICAgXHJcbiAgICAvKipcclxuICAgICAqIEEgbGlzdCBvZiBzdHJpbmdzIGNvbnRhaW5pbmcgdGhlIGxhbmd1YWdlcyB0aGF0IGFyZSB1c2VkIGJ5IHRoaXMgY2xhc3MgdG8gdHJhbnNsYXRlIHRoZSBnaXZlbiBrZXlzLCBzb3J0ZWQgYnkgcHJlZmVyZW5jZS5cclxuICAgICAqIEVhY2ggc3RyaW5nIGlzIGZvcm1hdHRlZCBhcyBhIDIgZGlnaXQgbGFuZ3VhZ2UgY29kZSwgbGlrZTogZW4sIGZyXHJcbiAgICAgKlxyXG4gICAgICogVGhpcyBsaXN0IGlzIHRoZSBzYW1lIGFzIHRoZSBsb2NhbGVzKCkgb25lLCBidXQgY29udGFpbmluZyBvbmx5IHRoZSBsYW5ndWFnZSBwYXJ0IG9mIGVhY2ggbG9jYWxlICh0aGUgZmlyc3QgdHdvIGRpZ2l0cylcclxuICAgICAqXHJcbiAgICAgKiBAc2VlIGdldExvY2FsZXMoKVxyXG4gICAgICovXHJcbiAgICBnZXRMYW5ndWFnZXMoKXtcclxuXHJcbiAgICAgICAgcmV0dXJuIHRoaXMuX2xhbmd1YWdlcztcclxuICAgIH1cclxuICAgIFxyXG4gICAgXHJcbiAgICAvKipcclxuICAgICAqIEdldCB0aGUgZmlyc3QgbG9jYWxlIGZyb20gdGhlIGxpc3Qgb2YgbG9hZGVkIGxvY2FsZXMsIHdoaWNoIGlzIHRoZSBjdXJyZW50bHkgdXNlZCB0byBzZWFyY2ggZm9yIHRyYW5zbGF0ZWQgdGV4dHMuXHJcbiAgICAgKlxyXG4gICAgICogQHJldHVybnMgVGhlIGxvY2FsZSB0aGF0IGlzIGRlZmluZWQgYXMgdGhlIHByaW1hcnkgb25lLiBGb3IgZXhhbXBsZTogZW5fVVMsIGVzX0VTLCAuLlxyXG4gICAgICovXHJcbiAgICBnZXRQcmltYXJ5TG9jYWxlKCl7XHJcblxyXG4gICAgICAgIHRoaXMuX3ZhbGlkYXRlSW5pdGlhbGl6ZWQoKTtcclxuXHJcbiAgICAgICAgcmV0dXJuIHRoaXMuX2xvY2FsZXNbMF07XHJcbiAgICB9XHJcbiAgICBcclxuICAgIFxyXG4gICAgLyoqXHJcbiAgICAgKiBHZXQgdGhlIGZpcnN0IGxhbmd1YWdlIGZyb20gdGhlIGxpc3Qgb2YgbG9hZGVkIGxvY2FsZXMsIHdoaWNoIGlzIHRoZSBjdXJyZW50bHkgdXNlZCB0byBzZWFyY2ggZm9yIHRyYW5zbGF0ZWQgdGV4dHMuXHJcbiAgICAgKlxyXG4gICAgICogQHJldHVybnMgVGhlIDIgZGlnaXQgbGFuZ3VhZ2UgY29kZSB0aGF0IGlzIGRlZmluZWQgYXMgdGhlIHByaW1hcnkgb25lLiBGb3IgZXhhbXBsZTogZW4sIGVzLCAuLlxyXG4gICAgICovXHJcbiAgICBnZXRQcmltYXJ5TGFuZ3VhZ2UoKXtcclxuXHJcbiAgICAgICAgdGhpcy5fdmFsaWRhdGVJbml0aWFsaXplZCgpO1xyXG5cclxuICAgICAgICByZXR1cm4gdGhpcy5fbGFuZ3VhZ2VzWzBdO1xyXG4gICAgfVxyXG4gICAgXHJcbiAgICBcclxuICAgIC8qKlxyXG4gICAgICogRGVmaW5lIHRoZSBsb2NhbGUgdGhhdCB3aWxsIGJlIHBsYWNlZCBhdCB0aGUgZnJvbnQgb2YgdGhlIGN1cnJlbnRseSBsb2FkZWQgbG9jYWxlcyBsaXN0IChtb3ZpbmcgYWxsIHRoZSBvdGhlcnMgb25lIHBvc2l0aW9uIHRvIHRoZSByaWdodCkuXHJcbiAgICAgKlxyXG4gICAgICogVGhpcyB3aWxsIGJlIHRoZSBmaXJzdCBsb2NhbGUgdG8gdXNlIHdoZW4gdHJ5aW5nIHRvIGdldCBhIHRyYW5zbGF0aW9uLlxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSBsb2NhbGUgQSBjdXJyZW50bHkgbG9hZGVkIGxvY2FsZSB0aGF0IHdpbGwgYmUgbW92ZWQgdG8gdGhlIGZpcnN0IHBvc2l0aW9uIG9mIHRoZSBsb2FkZWQgbG9jYWxlcyBsaXN0LiBJZiB0aGUgc3BlY2lmaWVkIGxvY2FsZVxyXG4gICAgICogICAgICAgIGlzIG5vdCBjdXJyZW50bHkgbG9hZGVkLCBhbiBleGNlcHRpb24gd2lsbCBoYXBwZW4uXHJcbiAgICAgKlxyXG4gICAgICogQHJldHVybnMgdm9pZFxyXG4gICAgICovXHJcbiAgICBzZXRQcmltYXJ5TG9jYWxlKGxvY2FsZTpzdHJpbmcpe1xyXG5cclxuICAgICAgICB0aGlzLl92YWxpZGF0ZUluaXRpYWxpemVkKCk7XHJcblxyXG4gICAgICAgIGlmKCF0aGlzLmlzTG9jYWxlTG9hZGVkKGxvY2FsZSkpe1xyXG5cclxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGxvY2FsZSArICcgbm90IGxvYWRlZCcpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgbGV0IHJlc3VsdCA9IFtsb2NhbGVdO1xyXG5cclxuICAgICAgICBmb3IgKGxldCBsIG9mIHRoaXMuX2xvY2FsZXMpe1xyXG4gICAgICAgIFxyXG4gICAgICAgICAgICBpZihsICE9PSBsb2NhbGUpe1xyXG5cclxuICAgICAgICAgICAgICAgIHJlc3VsdC5wdXNoKGwpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICB0aGlzLl9sb2NhbGVzID0gcmVzdWx0O1xyXG4gICAgICAgIHRoaXMuX2xhbmd1YWdlcyA9IHRoaXMuX2xvY2FsZXMubWFwKChsOiBzdHJpbmcpID0+IGwuc3Vic3RyaW5nKDAsIDIpKTtcclxuICAgICAgICB0aGlzLl9jYWNoZUhhc2hCYXNlU3RyaW5nID0gdGhpcy5fd2lsZENhcmRzRm9ybWF0ICsgdGhpcy5fbWlzc2luZ0tleUZvcm1hdCArIHRoaXMuX2xvY2FsZXNbMF07XHJcbiAgICB9XHJcbiAgICBcclxuICAgIFxyXG4gICAgLyoqXHJcbiAgICAgKiBNb3ZlcyB0aGUgc3BlY2lmaWVkIGxvY2FsZXMgdG8gdGhlIGJlZ2lubmluZyBvZiB0aGUgbG9jYWxlcyBsaXN0LiBUaGlzIGFsc28gYWx0ZXJzIHRoZSB0cmFuc2xhdGlvbiBwcmlvcml0eSBieSBzZXR0aW5nIHRoZSBmaXJzdFxyXG4gICAgICogcHJvdmlkZWQgbG9jYWxlIGFzIHRoZSBtb3N0IHByaW9yaXRhcnksIHRoZSBzZWNvbmQgYXMgdGhlIG5leHQgb25lIGFuZCBzby5cclxuICAgICAqXHJcbiAgICAgKiBUaGlzIG1ldGhvZCBiYXNpY2FsbHkgd29ya3MgZXhhY3RseSB0aGUgc2FtZSB3YXkgYXMgc2V0UHJpbWFyeUxvY2FsZSBidXQgbGV0dGluZyB1cyBhZGQgbWFueSBsb2NhbGVzIGF0IG9uY2UuXHJcbiAgICAgKlxyXG4gICAgICogQHNlZSBzZXRQcmltYXJ5TG9jYWxlKClcclxuICAgICAqXHJcbiAgICAgKiBAcGFyYW0gbG9jYWxlcyBBIGxpc3Qgb2YgbG9jYWxlcyB0byBiZSBtb3ZlZCB0byB0aGUgYmVnaW5uaW5nIG9mIHRoZSB0cmFuc2xhdGlvbiBwcmlvcml0eS4gRmlyc3QgbG9jYWxlcyBpdGVtIHdpbGwgYmUgdGhlIHByZWZlcmVkXHJcbiAgICAgKiAgICAgICAgbG9jYWxlIGZvciB0cmFuc2xhdGlvbiwgc2Vjb25kIHdpbGwgYmUgdGhlIG5leHQgb25lIGluIGNhc2Ugc29tZSBrZXkgaXMgbm90IHRyYW5zbGF0ZWQgZm9yIHRoZSBmaXJzdCBvbmUgYW5kIHNvLiBJZiBhbnkgb2YgdGhlXHJcbiAgICAgKiAgICAgICAgc3BlY2lmaWVkIGxvY2FsZXMgaXMgbm90IGN1cnJlbnRseSBsb2FkZWQsIGFuIGV4Y2VwdGlvbiB3aWxsIGhhcHBlbi5cclxuICAgICAqXHJcbiAgICAgKiBAcmV0dXJucyB2b2lkXHJcbiAgICAgKi9cclxuICAgIHNldFByaW1hcnlMb2NhbGVzKGxvY2FsZXM6c3RyaW5nW10pe1xyXG5cclxuICAgICAgICBpZighQXJyYXkuaXNBcnJheShsb2NhbGVzKSB8fFxyXG4gICAgICAgICAgICAobmV3IFNldChsb2NhbGVzKS5zaXplICE9PSBsb2NhbGVzLmxlbmd0aCkgfHxcclxuICAgICAgICAgICAgbG9jYWxlcy5sZW5ndGggPT09IDApe1xyXG5cclxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignbG9jYWxlcyBtdXN0IGJlIG5vbiBlbXB0eSBzdHJpbmcgYXJyYXkgd2l0aCBubyBkdXBsaWNhdGUgZWxlbWVudHMnKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGZvciAobGV0IGkgPSBsb2NhbGVzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7XHJcblxyXG4gICAgICAgICAgICB0aGlzLnNldFByaW1hcnlMb2NhbGUobG9jYWxlc1tpXSk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG4gICAgXHJcbiAgICBcclxuICAgIC8qKlxyXG4gICAgICogRGVmaW5lIHRoZSAyIGRpZ2l0IGxhbmd1YWdlIHRoYXQgd2lsbCBiZSBwbGFjZWQgYXQgdGhlIGZyb250IG9mIHRoZSBjdXJyZW50bHkgbG9hZGVkIGxvY2FsZXMgbGlzdCAobW92aW5nIGFsbCB0aGUgb3RoZXJzIG9uZSBwb3NpdGlvbiB0byB0aGUgcmlnaHQpLlxyXG4gICAgICpcclxuICAgICAqIFRoaXMgd2lsbCBiZSB0aGUgZmlyc3QgbGFuZ3VhZ2UgdG8gdXNlIHdoZW4gdHJ5aW5nIHRvIGdldCBhIHRyYW5zbGF0aW9uLlxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSBsYW5ndWFnZSBBIDIgZGlnaXQgbGFuZ3VhZ2UgY29kZSB0aGF0IG1hdGNoZXMgd2l0aCBhbnkgb2YgdGhlIGN1cnJlbnRseSBsb2FkZWQgbG9jYWxlcywgd2hpY2ggd2lsbFxyXG4gICAgICogICAgICAgIGJlIG1vdmVkIHRvIHRoZSBmaXJzdCBwb3NpdGlvbiBvZiB0aGUgbG9hZGVkIGxvY2FsZXMgbGlzdC4gSWYgdGhlIHNwZWNpZmllZCBsYW5ndWFnZSBkb2VzIG5vdCBtYXRjaCB3aXRoXHJcbiAgICAgKiAgICAgICAgYSBsb2NhbGUgdGhhdCBpcyBjdXJyZW50bHkgbG9hZGVkLCBhbiBleGNlcHRpb24gd2lsbCBoYXBwZW4uXHJcbiAgICAgKlxyXG4gICAgICogQHJldHVybnMgdm9pZFxyXG4gICAgICovXHJcbiAgICBzZXRQcmltYXJ5TGFuZ3VhZ2UobGFuZ3VhZ2U6c3RyaW5nKXtcclxuXHJcbiAgICAgICAgZm9yKGxldCBsb2NhbGUgb2YgdGhpcy5fbG9jYWxlcyl7XHJcbiAgICAgICAgXHJcbiAgICAgICAgICAgIGlmKGxvY2FsZS5zdWJzdHJpbmcoMCwgMikgPT09IGxhbmd1YWdlKXtcclxuXHJcbiAgICAgICAgICAgICAgICB0aGlzLnNldFByaW1hcnlMb2NhbGUobG9jYWxlKTtcclxuXHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihsYW5ndWFnZSArICcgbm90IGxvYWRlZCcpO1xyXG4gICAgfVxyXG4gICAgXHJcbiAgICBcclxuICAgIC8qKlxyXG4gICAgICogTW92ZXMgdGhlIGxvY2FsZXMgdGhhdCBtYXRjaCB0aGUgc3BlY2lmaWVkIGxhbmd1YWdlcyB0byB0aGUgYmVnaW5uaW5nIG9mIHRoZSBsb2NhbGVzIGxpc3QuXHJcbiAgICAgKiBXb3JrcyB0aGUgc2FtZSBhcyBzZXRQcmltYXJ5TG9jYWxlcygpIGJ1dCB3aXRoIGEgbGlzdCBvZiB0aGUgMiBkaWdpdCBsYW5ndWFnZSBjb2RlcyB0aGF0IG1hdGNoIHRoZSByZXNwZWN0aXZlIGxvY2FsZXMuXHJcbiAgICAgKlxyXG4gICAgICogQHNlZSBzZXRQcmltYXJ5TG9jYWxlKClcclxuICAgICAqIEBzZWUgc2V0UHJpbWFyeUxhbmd1YWdlKClcclxuICAgICAqXHJcbiAgICAgKiBAcGFyYW0gbGFuZ3VhZ2VzIEEgbGlzdCBvZiAyIGRpZ2l0IGxhbmd1YWdlIGNvZGVzIHRvIGJlIG1vdmVkIHRvIHRoZSBiZWdpbm5pbmcgb2YgdGhlIHRyYW5zbGF0aW9uIHByaW9yaXR5LiBJZiBhbnkgb2YgdGhlXHJcbiAgICAgKiAgICAgICAgc3BlY2lmaWVkIGxhbmd1YWdlcyBkb2VzIG5vdCBtYXRjaCB3aXRoIGEgbG9jYWxlIHRoYXQgaXMgY3VycmVudGx5IGxvYWRlZCwgYW4gZXhjZXB0aW9uIHdpbGwgaGFwcGVuLlxyXG4gICAgICpcclxuICAgICAqIEByZXR1cm5zIHZvaWRcclxuICAgICAqL1xyXG4gICAgc2V0UHJpbWFyeUxhbmd1YWdlcyhsYW5ndWFnZXM6c3RyaW5nW10pe1xyXG5cclxuICAgICAgICBpZighQXJyYXkuaXNBcnJheShsYW5ndWFnZXMpIHx8XHJcbiAgICAgICAgICAgKG5ldyBTZXQobGFuZ3VhZ2VzKS5zaXplICE9PSBsYW5ndWFnZXMubGVuZ3RoKSB8fFxyXG4gICAgICAgICAgICBsYW5ndWFnZXMubGVuZ3RoID09PSAwKXtcclxuXHJcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignbGFuZ3VhZ2VzIG11c3QgYmUgbm9uIGVtcHR5IHN0cmluZyBhcnJheSB3aXRoIG5vIGR1cGxpY2F0ZSBlbGVtZW50cycpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgZm9yIChsZXQgaSA9IGxhbmd1YWdlcy5sZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xyXG5cclxuICAgICAgICAgICAgdGhpcy5zZXRQcmltYXJ5TGFuZ3VhZ2UobGFuZ3VhZ2VzW2ldKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICBcclxuICAgIFxyXG4gICAgLyoqXHJcbiAgICAgKiBDaGFuZ2UgdGhlIGxvYWRlZCBsb2NhbGVzIHRyYW5zbGF0aW9uIHByZWZlcmVuY2Ugb3JkZXIuIFRoZSBzYW1lIGxvY2FsZXMgdGhhdCBhcmUgY3VycmVudGx5IGxvYWRlZCBtdXN0IGJlIHBhc3NlZFxyXG4gICAgICogYnV0IHdpdGggYSBkaWZmZXJlbnQgb3JkZXIgdG8gY2hhbmdlIHRoZSB0cmFuc2xhdGlvbiBwcmlvcml0eS5cclxuICAgICAqXHJcbiAgICAgKiBAcGFyYW0gbG9jYWxlcyBBIGxpc3Qgd2l0aCB0aGUgbmV3IGxvY2FsZXMgdHJhbnNsYXRpb24gcHJpb3JpdHlcclxuICAgICAqXHJcbiAgICAgKiBAcmV0dXJucyB2b2lkXHJcbiAgICAgKi9cclxuICAgIHNldExvY2FsZXNPcmRlcihsb2NhbGVzOnN0cmluZ1tdKXtcclxuXHJcbiAgICAgICAgaWYobG9jYWxlcy5sZW5ndGggIT09IHRoaXMuX2xvY2FsZXMubGVuZ3RoKXtcclxuXHJcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignbG9jYWxlcyBtdXN0IGNvbnRhaW4gYWxsIHRoZSBjdXJyZW50bHkgbG9hZGVkIGxvY2FsZXMnKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHRoaXMuX3ZhbGlkYXRlSW5pdGlhbGl6ZWQoKTtcclxuXHJcbiAgICAgICAgZm9yKGxldCBsb2NhbGUgb2YgbG9jYWxlcyl7XHJcbiAgICAgICAgXHJcbiAgICAgICAgICAgIGlmKCF0aGlzLmlzTG9jYWxlTG9hZGVkKGxvY2FsZSkpe1xyXG5cclxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihsb2NhbGUgKyAnIG5vdCBsb2FkZWQnKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgdGhpcy5fbG9jYWxlcyA9IGxvY2FsZXM7XHJcbiAgICAgICAgdGhpcy5fbGFuZ3VhZ2VzID0gdGhpcy5fbG9jYWxlcy5tYXAoKGw6IHN0cmluZykgPT4gbC5zdWJzdHJpbmcoMCwgMikpO1xyXG4gICAgICAgIHRoaXMuX2NhY2hlSGFzaEJhc2VTdHJpbmcgPSB0aGlzLl93aWxkQ2FyZHNGb3JtYXQgKyB0aGlzLl9taXNzaW5nS2V5Rm9ybWF0ICsgdGhpcy5fbG9jYWxlc1swXTtcclxuICAgIH1cclxuICAgIFxyXG4gICAgXHJcbiAgICAvKipcclxuICAgICAqIFRoaXMgaXMgYW4gYXV4IG1ldGhvZCB0byBpbXBsZW1lbnQgdGhlIFR1cmJvQ29tbW9ucyBTdHJpbmdVdGlscyByZXBsYWNlIG1ldGhvZC5cclxuICAgICAqIEl0IGlzIGV4YWN0bHkgdGhlIHNhbWUgYXMgdGhlIG9uZSBvbiB0aGUgbGlicmFyeSwgYnV0IHdlIGltcGxlbWVudCBpdCBoZXJlIHRvIGF2b2lkIGhhdmluZyBhIGRlcGVuZGVuY3kgd2l0aCBUdXJib0NvbW1vbnNcclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSBfcmVwbGFjZShzdHJpbmc6IHN0cmluZywgc2VhcmNoOnN0cmluZywgcmVwbGFjZW1lbnQ6IHN0cmluZykge1xyXG4gICAgICAgIFxyXG4gICAgICAgIGNvbnN0IGVzY2FwZWRTZWFyY2ggPSBzZWFyY2gucmVwbGFjZSgvWy4qKz9eJHt9KCl8W1xcXVxcXFxdL2csICdcXFxcJCYnKTtcclxuICAgICAgICAgICBcclxuICAgICAgICByZXR1cm4gc3RyaW5nLnJlcGxhY2UobmV3IFJlZ0V4cChlc2NhcGVkU2VhcmNoLCAnZycpLCByZXBsYWNlbWVudCk7XHJcbiAgICB9XHJcbiAgICBcclxuICAgIFxyXG4gICAgLyoqXHJcbiAgICAgKiBUaGlzIGlzIGFuIGF1eCBtZXRob2QgdG8gaW1wbGVtZW50IHRoZSBUdXJib0NvbW1vbnMgU3RyaW5nVXRpbHMgaXNFbXB0eSBtZXRob2QuXHJcbiAgICAgKiBJdCBpcyBleGFjdGx5IHRoZSBzYW1lIGFzIHRoZSBvbmUgb24gdGhlIGxpYnJhcnksIGJ1dCB3ZSBpbXBsZW1lbnQgaXQgaGVyZSB0byBhdm9pZCBoYXZpbmcgYSBkZXBlbmRlbmN5IHdpdGggVHVyYm9Db21tb25zXHJcbiAgICAgKi9cclxuICAgIHByaXZhdGUgX2lzRW1wdHkoc3RyaW5nOnN0cmluZykge1xyXG4gICAgICAgIFxyXG4gICAgICAgIGxldCBpc1N0cmluZyA9ICh0eXBlb2Ygc3RyaW5nID09PSAnc3RyaW5nJyB8fCAoc3RyaW5nIGFzIGFueSkgaW5zdGFuY2VvZiBTdHJpbmcpO1xyXG4gICAgICAgICAgICAgICAgXHJcbiAgICAgICAgLy8gVGhyb3cgZXhjZXB0aW9uIGlmIG5vbiBzdHJpbmcgdmFsdWUgd2FzIHJlY2VpdmVkXHJcbiAgICAgICAgaWYoIWlzU3RyaW5nKXtcclxuXHJcbiAgICAgICAgICAgIC8vIEVtcHR5IG9yIG51bGwgdmFsdWUgaXMgY29uc2lkZXJlZCBlbXB0eVxyXG4gICAgICAgICAgICBpZihzdHJpbmcgPT0gbnVsbCB8fCBzdHJpbmcgPT0gJycpe1xyXG4gICAgXHJcbiAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICBcclxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwidmFsdWUgaXMgbm90IGEgc3RyaW5nXCIpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgcmV0dXJuIHN0cmluZy5yZXBsYWNlKC9bIFxcblxcclxcdF0vZywgJycpID09PSAnJztcclxuICAgIH1cclxuICAgIFxyXG4gICAgXHJcbiAgICAvKipcclxuICAgICAqIFRoaXMgaXMgYW4gYXV4IG1ldGhvZCB0byBpbXBsZW1lbnQgdGhlIFR1cmJvQ29tbW9ucyBTdHJpbmdVdGlscyBmb3JjZU5vbkVtcHR5U3RyaW5nIG1ldGhvZC5cclxuICAgICAqIEl0IGlzIGV4YWN0bHkgdGhlIHNhbWUgYXMgdGhlIG9uZSBvbiB0aGUgbGlicmFyeSwgYnV0IHdlIGltcGxlbWVudCBpdCBoZXJlIHRvIGF2b2lkIGhhdmluZyBhIGRlcGVuZGVuY3kgd2l0aCBUdXJib0NvbW1vbnNcclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSBfZm9yY2VOb25FbXB0eVN0cmluZyh2YWx1ZTphbnksIHZhbHVlTmFtZSA9ICcnLCBlcnJvck1lc3NhZ2UgPSAnbXVzdCBiZSBhIG5vbiBlbXB0eSBzdHJpbmcnKXtcclxuXHJcbiAgICAgICAgbGV0IGlzU3RyaW5nID0gKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgfHwgdmFsdWUgaW5zdGFuY2VvZiBTdHJpbmcpO1xyXG4gICAgICAgIFxyXG4gICAgICAgIGlmKCFpc1N0cmluZyB8fCB0aGlzLl9pc0VtcHR5KHZhbHVlKSl7XHJcblxyXG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IodmFsdWVOYW1lICsgJyAnICsgZXJyb3JNZXNzYWdlKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbn1cclxuIl19