UNPKG

@singleton-i18n/angular-client

Version:

Singleton client code for Angular 10.

366 lines 57.2 kB
import { __awaiter } from "tslib"; /* * Copyright 2019-2021 VMware, Inc. * SPDX-License-Identifier: EPL-2.0 */ import { Injectable } from '@angular/core'; import { DateFormatter } from '../formatters/date.formatter'; import { FormatterFactory } from '../formatters/number.formatter'; import { Plural } from '../formatters/plural/plural.formatter'; import { isDefined } from '../util'; import { LocaleService } from './locale.service'; import { I18nLoader } from '../loader'; import { PatternCategories } from '../config'; import { SOURCE_LOCALE_DATA } from '../data/locale_en'; import { BaseService } from './base.service'; import { VIPService } from './vip.service'; import { RelativeTimeFormatter } from '../formatters/relative.time'; import { format, deprecatedWarn } from '../util'; import { VIPServiceConstants } from '../constants'; export class I18nService extends BaseService { constructor(dateFormatter, localeService, vipService, currentLoader) { super(vipService, localeService); this.dateFormatter = dateFormatter; this.localeService = localeService; this.vipService = vipService; this.currentLoader = currentLoader; this.initSourcePatterns(); this.formatter = new FormatterFactory(); this.relativeFormat = new RelativeTimeFormatter(); this.plural = new Plural(); } resolveLocaleData(locale) { let patterns; let localeData; const currentLocale = locale ? locale : this.currentLocale; localeData = this.vipService.localeData[currentLocale]; patterns = localeData && localeData.categories ? localeData.categories : undefined; return patterns; } initSourcePatterns() { this.sourceLocaleData = SOURCE_LOCALE_DATA; this.sourceLocaleData.categories[PatternCategories.CURRENCIES] = this.getCurrencyData(this.sourceLocaleData.categories); } validateNumber(value) { let number; if (typeof value === 'string' && !isNaN(+value - parseFloat(value))) { number = +value; } else if (typeof value !== 'number') { throw new Error(`'${value}' is not a number`); } else { number = value; } return number; } getFormattedDateTime(value, pattern, timezone) { deprecatedWarn('getFormattedDateTime in I18nService', 'v9', 'formatDate'); return this.formatDate(value, pattern, undefined, timezone); } formatDate(value, pattern, locale, timezone) { pattern = isDefined(pattern) ? pattern : 'mediumDate'; locale = isDefined(locale) ? locale : this.currentLocale; const date = this.dateFormatter.getStandardTime(value); this.validateDate(date); const dataForDate = this.getPattern(PatternCategories.DATE, locale) || this.getSourcePattern(PatternCategories.DATE); return this.dateFormatter.getformattedString(date, pattern, dataForDate, '-', timezone); } /** * Get localized pattern by predefined pattern and locale. * The default locale is the locale current in use. * If no exist date formatting data of the locale, fallback to source locale 'en'. * If the pattern is not predefined pattern, return origin pattern directly. */ getLocalizedPattern(pattern, locale) { locale = isDefined(locale) ? locale : this.currentLocale; const dataForDate = this.getPattern(PatternCategories.DATE, locale) || this.getSourcePattern(PatternCategories.DATE); const localizedPattern = this.dateFormatter.getRulesByPattern(pattern, dataForDate); return localizedPattern; } /** * Get number related formatter from FormatterFactory * @param type currencies, currencySymbol, percent or number * @param categories PatternCategories * @returns formatter */ getFormatter(type, categories, locale) { let data = this.getPattern(categories, locale); let formatter; if (data) { formatter = this.formatter[type](data, locale); } else { // fallback to source locale data = this.getSourcePattern(categories); formatter = this.formatter[type](data, VIPServiceConstants.ENGLISH.languageCode); } return formatter; } /** * Get the localized currency symbol by currency code and locale, * return the currency symbol of the currency code. * The default locale is the locale current in use. * If the currency code invalid, return the currency code. */ getLocalizedCurrencySymbol(currencyCode, locale) { locale = isDefined(locale) ? locale : this.currentLocale; const formatter = this.getFormatter('currenySymbol', PatternCategories.CURRENCIES, locale); const localizedCurrencySymbol = formatter(currencyCode); return localizedCurrencySymbol; } validateDate(date) { const type = Object.prototype.toString.call(date); if (!(type === '[object Date]') || !isFinite(date.getTime())) { throw new Error(`${date} is not an available date`); } } /** * Formats simple relative dates. * @param from The starting time of relative time calculation. * @param to The ending time of relative time calculation. * @param locale The locale to determine which patters need to use. * @param options The formatting style. */ formatRelativeTime(from, to, locale, options) { locale = isDefined(locale) ? locale : this.currentLocale; const timeOffset = this.getRelativeTimeOffset(from, to); const res = this.relativeTimeFormat(timeOffset.offset, timeOffset.unit, locale, options); return res; } /** * Calculate the most suitable unit and the corresponding offset according to the input time * @param from The starting time of relative time calculation. * @param to The ending time of relative time calculation. */ getRelativeTimeOffset(from, to) { // Verify the input time this.validateDate(from); this.validateDate(to); const offset = this.relativeFormat.getOffset(from, to); return offset; } /** * Get formatted message reaponseable * @param offset The offset of time * @param unit The unit of offset * @param locale The locale to determine which patters need to use. * @param options The formatting style. */ relativeTimeFormat(offset, unit, locale, options) { const format_numeric = options && options.numeric === 'auto' ? 'auto' : 'always'; // Get the data of `unit` in the fields node in the date pattern data. const dateFields = this.getPattern(PatternCategories.DATEFIELDS, locale) || this.getSourcePattern(PatternCategories.DATEFIELDS); const dataOfUnit = dateFields[unit]; // Get the message corresponding to the offset. let messages; // If `numeric` is automatic, Match the message corresponding to the offset value first. if (format_numeric === 'auto') { messages = dataOfUnit["relative-type-" /* AUTO */ + offset]; } // According to the plural type of offset, obtain the message. if (!messages) { const pluralType = this.getPluralCategory(Math.abs(offset), locale); const direction = offset > 0 ? 'future' : 'past'; messages = dataOfUnit["relativeTime-type-" /* ALWAYS */ + direction]["relativeTimePattern-count-" /* PLURALTYPE */ + pluralType] || dataOfUnit["relativeTime-type-" /* ALWAYS */ + direction]["relativeTimePattern-count-" /* PLURALTYPE */ + 'other']; } const res = format(messages, [Math.abs(offset)]); return res; } getFormattedDecimal(value, locale) { deprecatedWarn('getFormattedDecimal in I18nService', 'v9', 'formatNumber'); return this.formatNumber(value, locale); } formatNumber(value, locale, formatOptions) { locale = isDefined(locale) ? locale : this.currentLocale; value = this.validateNumber(value); const formatter = this.getFormatter('decimal', PatternCategories.NUMBER, locale); const text = formatter(value, formatOptions); return text; } getFormattedPercent(value) { deprecatedWarn('getFormattedPercent in I18nService', 'v9', 'formatPercent'); return this.formatPercent(value); } formatPercent(value, locale, formatOptions) { locale = isDefined(locale) ? locale : this.currentLocale; value = this.validateNumber(value); const formatter = this.getFormatter('percent', PatternCategories.NUMBER, locale); const text = formatter(value, formatOptions); return text; } getFormattedCurrency(value, currencyCode) { deprecatedWarn('getFormattedCurrency in I18nService', 'v9', 'formatCurrency'); return this.formatCurrency(value, currencyCode); } formatCurrency(value, currencyCode, locale, formatOptions) { currencyCode = isDefined(currencyCode) ? currencyCode : 'USD'; locale = isDefined(locale) ? locale : this.currentLocale; value = this.validateNumber(value); const formatter = this.getFormatter('currencies', PatternCategories.CURRENCIES, locale); const text = formatter(value, currencyCode, formatOptions); return text; } /** * This APIs will be call by l10n service when render plural message * @param value Numerals that need to be dealt with * @param locale Locale from l10n service */ getPluralCategory(value, locale) { locale = isDefined(locale) ? locale : this.currentLocale; value = this.validateNumber(value); value = Math.abs(value); // try to round number with default number formatting rules // if data isn't exist, use origin number. // getPattern will use validateScope to validate is correct formatting data exist. try { const dataForNumber = this.getPattern(PatternCategories.NUMBER, locale); const formatter = this.formatter.roundNumberForPlural(dataForNumber, locale); value = Number(formatter(value)); } catch (error) { } const pluraFunction = this.getPluralFunction(locale); const type = pluraFunction ? pluraFunction(value) : undefined; return type; } getPluralCategoryType(value, locale) { deprecatedWarn('getPluralCategoryType in I18nService', 'v9', 'getPluralCategory'); return this.getPluralCategory(value, locale); } getPluralFunction(locale) { return this.plural.getFunc(locale); } validateScope(type) { if (!this.localeService.isSourceLocale && this.vipService.i18nScope.indexOf(type) === -1) { throw new Error(`You should add '${type}' to 'i18nScope' in initialize configuration`); } return true; } getSourcePattern(type) { return this.sourceLocaleData.categories[type]; } getPattern(type, locale) { if (this.localeService.shouldSourceLocale(locale)) { return this.getSourcePattern(type); } this.validateScope(type); const localeData = this.resolveLocaleData(locale); if (localeData && type === PatternCategories.CURRENCIES) { // number formatting is part of currency format. localeData[PatternCategories.CURRENCIES] = this.getCurrencyData(localeData); } return localeData && localeData[type]; } getCurrencyData(data) { // TODO: data sharing. Avoid duplicate processing. if (data[PatternCategories.CURRENCIES].currencyFormats) { return data[PatternCategories.CURRENCIES]; } const defaultNumberingSystem = data[PatternCategories.NUMBER].defaultNumberingSystem; const supplementalData = data.supplemental; return data[PatternCategories.NUMBER] ? { currencyFormats: data[PatternCategories.NUMBER].numberFormats.currencyFormats, numberSymbols: data[PatternCategories.NUMBER].numberSymbols, currencySymbols: data[PatternCategories.CURRENCIES], fractions: supplementalData.currencies.fractions, numberFormats: { 'decimalFormats-long': data[PatternCategories.NUMBER].numberFormats['decimalFormats-long'], 'decimalFormats-short': data[PatternCategories.NUMBER].numberFormats['decimalFormats-short'] }, defaultNumberingSystem: defaultNumberingSystem, numberingSystem: supplementalData.numbers ? supplementalData.numbers.numberingSystems[defaultNumberingSystem] : undefined } : undefined; } getSupportedLanguages() { return __awaiter(this, void 0, void 0, function* () { if (!this.vipService.mainConfig) { console.error('No main component to get supported languages'); return Promise.resolve(undefined); } let supportedLanguages = yield this.currentLoader .getSupportedLanguages(this.vipService.mainConfig) .toPromise() .then((res) => { if (isDefined(res)) { return res; } }).catch((error) => { console.error('Failed to get supported languages from VIP service.', error); }); supportedLanguages = supportedLanguages ? supportedLanguages : [{ languageTag: this.localeService.defaultLocale.languageCode, displayName: this.localeService.defaultLocale.languageName }]; return supportedLanguages; }); } getSupportedRegions(language) { return __awaiter(this, void 0, void 0, function* () { if (!this.vipService.mainConfig) { console.error('No main component to get supported regions'); return Promise.resolve(undefined); } let supportedRegions = yield this.currentLoader .getSupportedRegions(language || this.localeService.getCurrentLanguage(), this.vipService.mainConfig) .toPromise() .catch((error) => { console.error('Failed to get supported regions from VIP service.', error); }); const defaultRegion = [[this.localeService.defaultLocale.regionCode, this.localeService.defaultLocale.regionName]]; if (supportedRegions) { supportedRegions = this.convertObjectToArray(supportedRegions); } supportedRegions = supportedRegions ? supportedRegions : defaultRegion; return supportedRegions; }); } getCities(region, language) { return __awaiter(this, void 0, void 0, function* () { if (!region || !language) { return; } let localizedCities = yield this.currentLoader .getLocalizedCities(language, region, this.vipService.mainConfig) .toPromise() .then((res) => { if (isDefined(res) && isDefined(res.cities)) { return res.cities[region]; } }) .catch((error) => { console.error('Failed to get localized cities from VIP service.', error); }); return localizedCities; }); } convertObjectToArray(obj) { if (!obj || !obj.territories) { return undefined; } const defaultRegion = obj.defaultRegionCode; const territories = obj.territories; if (!obj) { return []; } const result = []; for (const key in territories) { if (key) { const item = [key, territories[key]]; // convert region object to array if (key === defaultRegion) { // put default region at top of the dropdown list result.unshift(item); } else { result.push(item); } } } return result; } } I18nService.decorators = [ { type: Injectable } ]; I18nService.ctorParameters = () => [ { type: DateFormatter }, { type: LocaleService }, { type: VIPService }, { type: I18nLoader } ]; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaTE4bi5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6Ii9ob21lL3JsaWdlbmcvUHJvamVjdHMvRGV2b3BzL0NsaWVudF9Bbmd1bGFyX0dpdEh1Yl9OcG1qcy92aXAvY2kvcHViMm9yZy9DbGllbnRfQW5ndWxhcl9HaXRIdWJfTnBtanMvc2luZ2xldG9uL3Byb2plY3RzL2FuZ3VsYXItY2xpZW50LyIsInNvdXJjZXMiOlsic3JjL3NlcnZpY2VzL2kxOG4uc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7OztHQUdHO0FBQ0gsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzQyxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDN0QsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDbEUsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLHVDQUF1QyxDQUFDO0FBQy9ELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDcEMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2pELE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFFdkMsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQzlDLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM3QyxPQUFPLEVBQUUsVUFBVSxFQUFjLE1BQU0sZUFBZSxDQUFDO0FBQ3ZELE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQ3BFLE9BQU8sRUFBRSxNQUFNLEVBQUUsY0FBYyxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQ2pELE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQWNuRCxNQUFNLE9BQU8sV0FBWSxTQUFR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LElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztpQkFDckI7YUFDSjtTQUNKO1FBQ0QsT0FBTyxNQUFNLENBQUM7SUFDbEIsQ0FBQzs7O1lBeldKLFVBQVU7OztZQTFCRixhQUFhO1lBSWIsYUFBYTtZQU1iLFVBQVU7WUFMVixVQUFVIiwic291cmNlc0NvbnRlbnQiOlsiLypcbiAqIENvcHlyaWdodCAyMDE5LTIwMjEgVk13YXJlLCBJbmMuXG4gKiBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogRVBMLTIuMFxuICovXG5pbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBEYXRlRm9ybWF0dGVyIH0gZnJvbSAnLi4vZm9ybWF0dGVycy9kYXRlLmZvcm1hdHRlcic7XG5pbXBvcnQgeyBGb3JtYXR0ZXJGYWN0b3J5IH0gZnJvbSAnLi4vZm9ybWF0dGVycy9udW1iZXIuZm9ybWF0dGVyJztcbmltcG9ydCB7IFBsdXJhbCB9IGZyb20gJy4uL2Zvcm1hdHRlcnMvcGx1cmFsL3BsdXJhbC5mb3JtYXR0ZXInO1xuaW1wb3J0IHsgaXNEZWZpbmVkIH0gZnJvbSAnLi4vdXRpbCc7XG5pbXBvcnQgeyBMb2NhbGVTZXJ2aWNlIH0gZnJvbSAnLi9sb2NhbGUuc2VydmljZSc7XG5pbXBvcnQgeyBJMThuTG9hZGVyIH0gZnJvbSAnLi4vbG9hZGVyJztcbmltcG9ydCB7IERhdGFGb3JDdXJyZW5jeSwgTnVtYmVyRm9ybWF0T3B0aW9ucyB9IGZyb20gJy4uL2Zvcm1hdHRlcnMvbnVtYmVyLmZvcm1hdC5tb2RlbCc7XG5pbXBvcnQgeyBQYXR0ZXJuQ2F0ZWdvcmllcyB9IGZyb20gJy4uL2NvbmZpZyc7XG5pbXBvcnQgeyBTT1VSQ0VfTE9DQUxFX0RBVEEgfSBmcm9tICcuLi9kYXRhL2xvY2FsZV9lbic7XG5pbXBvcnQgeyBCYXNlU2VydmljZSB9IGZyb20gJy4vYmFzZS5zZXJ2aWNlJztcbmltcG9ydCB7IFZJUFNlcnZpY2UsIExvY2FsZURhdGEgfSBmcm9tICcuL3ZpcC5zZXJ2aWNlJztcbmltcG9ydCB7IFJlbGF0aXZlVGltZUZvcm1hdHRlciB9IGZyb20gJy4uL2Zvcm1hdHRlcnMvcmVsYXRpdmUudGltZSc7XG5pbXBvcnQgeyBmb3JtYXQsIGRlcHJlY2F0ZWRXYXJuIH0gZnJvbSAnLi4vdXRpbCc7XG5pbXBvcnQgeyBWSVBTZXJ2aWNlQ29uc3RhbnRzIH0gZnJvbSAnLi4vY29uc3RhbnRzJztcblxuZXhwb3J0IGludGVyZmFjZSBGb3JtYXRPcHRpb24ge1xuICAgIG51bWVyaWM/OiBzdHJpbmc7XG4gICAgZm9ybXM/OiBzdHJpbmc7XG59XG5cbmNvbnN0IGVudW0gTWVzc2FnZVByZWZpeCB7XG4gICAgQUxXQVlTID0gJ3JlbGF0aXZlVGltZS10eXBlLScsXG4gICAgQVVUTyA9ICdyZWxhdGl2ZS10eXBlLScsXG4gICAgUExVUkFMVFlQRSA9ICdyZWxhdGl2ZVRpbWVQYXR0ZXJuLWNvdW50LScsXG59XG5cbkBJbmplY3RhYmxlKClcbmV4cG9ydCBjbGFzcyBJMThuU2VydmljZSBleHRlbmRzIEJhc2VTZXJ2aWNlIHtcbiAgICBwcml2YXRlIHNvdXJjZUxvY2FsZURhdGE6IGFueTtcbiAgICBwcml2YXRlIHBsdXJhbDogUGx1cmFsO1xuICAgIHByaXZhdGUgZm9ybWF0dGVyOiBGb3JtYXR0ZXJGYWN0b3J5O1xuICAgIHByaXZhdGUgcmVsYXRpdmVGb3JtYXQ6IFJlbGF0aXZlVGltZUZvcm1hdHRlcjtcbiAgICBjb25zdHJ1Y3RvcihcbiAgICAgICAgcHJpdmF0ZSBkYXRlRm9ybWF0dGVyOiBEYXRlRm9ybWF0dGVyLFxuICAgICAgICBwcm90ZWN0ZWQgbG9jYWxlU2VydmljZTogTG9jYWxlU2VydmljZSxcbiAgICAgICAgcHJvdGVjdGVkIHZpcFNlcnZpY2U6IFZJUFNlcnZpY2UsXG4gICAgICAgIHB1YmxpYyBjdXJyZW50TG9hZGVyOiBJMThuTG9hZGVyXG4gICAgKSB7XG4gICAgICAgIHN1cGVyKHZpcFNlcnZpY2UsIGxvY2FsZVNlcnZpY2UpO1xuICAgICAgICB0aGlzLmluaXRTb3VyY2VQYXR0ZXJucygpO1xuICAgICAgICB0aGlzLmZvcm1hdHRlciA9IG5ldyBGb3JtYXR0ZXJGYWN0b3J5KCk7XG4gICAgICAgIHRoaXMucmVsYXRpdmVGb3JtYXQgPSBuZXcgUmVsYXRpdmVUaW1lRm9ybWF0dGVyKCk7XG4gICAgICAgIHRoaXMucGx1cmFsID0gbmV3IFBsdXJhbCgpO1xuICAgIH1cblxuICAgIHB1YmxpYyByZXNvbHZlTG9jYWxlRGF0YShsb2NhbGU6IHN0cmluZykge1xuICAgICAgICBsZXQgcGF0dGVybnM6IGFueTtcbiAgICAgICAgbGV0IGxvY2FsZURhdGE6IExvY2FsZURhdGE7XG4gICAgICAgIGNvbnN0IGN1cnJlbnRMb2NhbGUgPSBsb2NhbGUgPyBsb2NhbGUgOiB0aGlzLmN1cnJlbnRMb2NhbGU7XG4gICAgICAgIGxvY2FsZURhdGEgPSB0aGlzLnZpcFNlcnZpY2UubG9jYWxlRGF0YVtjdXJyZW50TG9jYWxlXTtcbiAgICAgICAgcGF0dGVybnMgPSBsb2NhbGVEYXRhICYmIGxvY2FsZURhdGEuY2F0ZWdvcmllcyA/IGxvY2FsZURhdGEuY2F0ZWdvcmllcyA6IHVuZGVmaW5lZDtcbiAgICAgICAgcmV0dXJuIHBhdHRlcm5zO1xuICAgIH1cblxuICAgIHByaXZhdGUgaW5pdFNvdXJjZVBhdHRlcm5zKCkge1xuICAgICAgICB0aGlzLnNvdXJjZUxvY2FsZURhdGEgPSBTT1VSQ0VfTE9DQUxFX0RBVEE7XG4gICAgICAgIHRoaXMuc291cmNlTG9jYWxlRGF0YS5jYXRlZ29yaWVzW1BhdHRlcm5DYXRlZ29yaWVzLkNVUlJFTkNJRVNdID0gdGhpcy5nZXRDdXJyZW5jeURhdGEodGhpcy5zb3VyY2VMb2NhbGVEYXRhLmNhdGVnb3JpZXMpO1xuICAgIH1cblxuICAgIHByaXZhdGUgdmFsaWRhdGVOdW1iZXIodmFsdWU6IG51bWJlciB8IHN0cmluZyk6IG51bWJlciB7XG4gICAgICAgIGxldCBudW1iZXI6IGFueTtcbiAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgJiYgIWlzTmFOKCt2YWx1ZSAtIHBhcnNlRmxvYXQodmFsdWUpKSkge1xuICAgICAgICAgICAgbnVtYmVyID0gK3ZhbHVlO1xuICAgICAgICB9IGVsc2UgaWYgKHR5cGVvZiB2YWx1ZSAhPT0gJ251bWJlcicpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgJyR7dmFsdWV9JyBpcyBub3QgYSBudW1iZXJgKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIG51bWJlciA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBudW1iZXI7XG4gICAgfVxuXG4gICAgcHVibGljIGdldEZvcm1hdHRlZERhdGVUaW1lKHZhbHVlOiBhbnksIHBhdHRlcm46IHN0cmluZywgdGltZXpvbmU/OiBzdHJpbmcpOiBhbnkge1xuICAgICAgICBkZXByZWNhdGVkV2FybignZ2V0Rm9ybWF0dGVkRGF0ZVRpbWUgaW4gSTE4blNlcnZpY2UnLCAndjknLCAnZm9ybWF0RGF0ZScpO1xuICAgICAgICByZXR1cm4gdGhpcy5mb3JtYXREYXRlKHZhbHVlLCBwYXR0ZXJuLCB1bmRlZmluZWQsIHRpbWV6b25lKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZm9ybWF0RGF0ZSh2YWx1ZTogYW55LCBwYXR0ZXJuOiBzdHJpbmcsIGxvY2FsZT86IHN0cmluZywgdGltZXpvbmU/OiBzdHJpbmcgKTogYW55IHtcbiAgICAgICAgcGF0dGVybiA9IGlzRGVmaW5lZChwYXR0ZXJuKSA/IHBhdHRlcm4gOiAnbWVkaXVtRGF0ZSc7XG4gICAgICAgIGxvY2FsZSA9IGlzRGVmaW5lZChsb2NhbGUpID8gbG9jYWxlIDogdGhpcy5jdXJyZW50TG9jYWxlO1xuICAgICAgICBjb25zdCBkYXRlID0gdGhpcy5kYXRlRm9ybWF0dGVyLmdldFN0YW5kYXJkVGltZSh2YWx1ZSk7XG4gICAgICAgIHRoaXMudmFsaWRhdGVEYXRlKGRhdGUpO1xuICAgICAgICBjb25zdCBkYXRhRm9yRGF0ZSA9IHRoaXMuZ2V0UGF0dGVybihQYXR0ZXJuQ2F0ZWdvcmllcy5EQVRFLCBsb2NhbGUpIHx8IHRoaXMuZ2V0U291cmNlUGF0dGVybihQYXR0ZXJuQ2F0ZWdvcmllcy5EQVRFKTtcbiAgICAgICAgcmV0dXJuIHRoaXMuZGF0ZUZvcm1hdHRlci5nZXRmb3JtYXR0ZWRTdHJpbmcoZGF0ZSwgcGF0dGVybiwgZGF0YUZvckRhdGUsICctJywgdGltZXpvbmUpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCBsb2NhbGl6ZWQgcGF0dGVybiBieSBwcmVkZWZpbmVkIHBhdHRlcm4gYW5kIGxvY2FsZS5cbiAgICAgKiBUaGUgZGVmYXVsdCBsb2NhbGUgaXMgdGhlIGxvY2FsZSBjdXJyZW50IGluIHVzZS5cbiAgICAgKiBJZiBubyBleGlzdCBkYXRlIGZvcm1hdHRpbmcgZGF0YSBvZiB0aGUgbG9jYWxlLCBmYWxsYmFjayB0byBzb3VyY2UgbG9jYWxlICdlbicuXG4gICAgICogSWYgdGhlIHBhdHRlcm4gaXMgbm90IHByZWRlZmluZWQgcGF0dGVybiwgcmV0dXJuIG9yaWdpbiBwYXR0ZXJuIGRpcmVjdGx5LlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXRMb2NhbGl6ZWRQYXR0ZXJuKCBwYXR0ZXJuOiBzdHJpbmcsIGxvY2FsZT86IHN0cmluZyApOiBzdHJpbmcge1xuICAgICAgICBsb2NhbGUgPSBpc0RlZmluZWQobG9jYWxlKSA/IGxvY2FsZSA6IHRoaXMuY3VycmVudExvY2FsZTtcbiAgICAgICAgY29uc3QgZGF0YUZvckRhdGUgPSB0aGlzLmdldFBhdHRlcm4oUGF0dGVybkNhdGVnb3JpZXMuREFURSwgbG9jYWxlKSB8fCB0aGlzLmdldFNvdXJjZVBhdHRlcm4oUGF0dGVybkNhdGVnb3JpZXMuREFURSk7XG4gICAgICAgIGNvbnN0IGxvY2FsaXplZFBhdHRlcm4gPSB0aGlzLmRhdGVGb3JtYXR0ZXIuZ2V0UnVsZXNCeVBhdHRlcm4ocGF0dGVybiwgZGF0YUZvckRhdGUpO1xuICAgICAgICByZXR1cm4gbG9jYWxpemVkUGF0dGVybjtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgbnVtYmVyIHJlbGF0ZWQgZm9ybWF0dGVyIGZyb20gRm9ybWF0dGVyRmFjdG9yeVxuICAgICAqIEBwYXJhbSB0eXBlIGN1cnJlbmNpZXMsIGN1cnJlbmN5U3ltYm9sLCBwZXJjZW50IG9yIG51bWJlclxuICAgICAqIEBwYXJhbSBjYXRlZ29yaWVzIFBhdHRlcm5DYXRlZ29yaWVzXG4gICAgICogQHJldHVybnMgZm9ybWF0dGVyXG4gICAgICovXG4gICAgIHByaXZhdGUgZ2V0Rm9ybWF0dGVyKHR5cGU6IHN0cmluZywgY2F0ZWdvcmllczogUGF0dGVybkNhdGVnb3JpZXMsIGxvY2FsZTogc3RyaW5nKSB7XG4gICAgICAgIGxldCBkYXRhID0gdGhpcy5nZXRQYXR0ZXJuKGNhdGVnb3JpZXMsIGxvY2FsZSk7XG4gICAgICAgIGxldCBmb3JtYXR0ZXI6IGFueTtcbiAgICAgICAgaWYgKGRhdGEpIHtcbiAgICAgICAgICAgIGZvcm1hdHRlciA9IHRoaXMuZm9ybWF0dGVyW3R5cGVdKGRhdGEsIGxvY2FsZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBmYWxsYmFjayB0byBzb3VyY2UgbG9jYWxlXG4gICAgICAgICAgICBkYXRhID0gdGhpcy5nZXRTb3VyY2VQYXR0ZXJuKGNhdGVnb3JpZXMpO1xuICAgICAgICAgICAgZm9ybWF0dGVyID0gdGhpcy5mb3JtYXR0ZXJbdHlwZV0oZGF0YSwgVklQU2VydmljZUNvbnN0YW50cy5FTkdMSVNILmxhbmd1YWdlQ29kZSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZvcm1hdHRlcjtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgdGhlIGxvY2FsaXplZCBjdXJyZW5jeSBzeW1ib2wgYnkgY3VycmVuY3kgY29kZSBhbmQgbG9jYWxlLFxuICAgICAqIHJldHVybiB0aGUgY3VycmVuY3kgc3ltYm9sIG9mIHRoZSBjdXJyZW5jeSBjb2RlLlxuICAgICAqIFRoZSBkZWZhdWx0IGxvY2FsZSBpcyB0aGUgbG9jYWxlIGN1cnJlbnQgaW4gdXNlLlxuICAgICAqIElmIHRoZSBjdXJyZW5jeSBjb2RlIGludmFsaWQsIHJldHVybiB0aGUgY3VycmVuY3kgY29kZS5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0TG9jYWxpemVkQ3VycmVuY3lTeW1ib2woY3VycmVuY3lDb2RlOiBzdHJpbmcsIGxvY2FsZT86IHN0cmluZykge1xuICAgICAgICBsb2NhbGUgPSBpc0RlZmluZWQobG9jYWxlKSA/IGxvY2FsZSA6IHRoaXMuY3VycmVudExvY2FsZTtcbiAgICAgICAgY29uc3QgZm9ybWF0dGVyID0gdGhpcy5nZXRGb3JtYXR0ZXIoJ2N1cnJlbnlTeW1ib2wnLCBQYXR0ZXJuQ2F0ZWdvcmllcy5DVVJSRU5DSUVTLCBsb2NhbGUpO1xuICAgICAgICBjb25zdCBsb2NhbGl6ZWRDdXJyZW5jeVN5bWJvbCA9IGZvcm1hdHRlcihjdXJyZW5jeUNvZGUpO1xuICAgICAgICByZXR1cm4gbG9jYWxpemVkQ3VycmVuY3lTeW1ib2w7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSB2YWxpZGF0ZURhdGUoZGF0ZTogYW55KSB7XG4gICAgICAgIGNvbnN0IHR5cGUgPSBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoZGF0ZSk7XG4gICAgICAgIGlmICghKHR5cGUgPT09ICdbb2JqZWN0IERhdGVdJykgfHwgIWlzRmluaXRlKGRhdGUuZ2V0VGltZSgpKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGAke2RhdGV9IGlzIG5vdCBhbiBhdmFpbGFibGUgZGF0ZWApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRm9ybWF0cyBzaW1wbGUgcmVsYXRpdmUgZGF0ZXMuXG4gICAgICogQHBhcmFtIGZyb20gVGhlIHN0YXJ0aW5nIHRpbWUgb2YgcmVsYXRpdmUgdGltZSBjYWxjdWxhdGlvbi5cbiAgICAgKiBAcGFyYW0gdG8gVGhlIGVuZGluZyB0aW1lIG9mIHJlbGF0aXZlIHRpbWUgY2FsY3VsYXRpb24uXG4gICAgICogQHBhcmFtIGxvY2FsZSBUaGUgbG9jYWxlIHRvIGRldGVybWluZSB3aGljaCBwYXR0ZXJzIG5lZWQgdG8gdXNlLlxuICAgICAqIEBwYXJhbSBvcHRpb25zIFRoZSBmb3JtYXR0aW5nIHN0eWxlLlxuICAgICAqL1xuICAgIHB1YmxpYyBmb3JtYXRSZWxhdGl2ZVRpbWUoIGZyb206IERhdGUsIHRvOiBEYXRlLCBsb2NhbGU/OiBzdHJpbmcsIG9wdGlvbnM/OiBGb3JtYXRPcHRpb24gKSB7XG4gICAgICAgIGxvY2FsZSA9IGlzRGVmaW5lZChsb2NhbGUpID8gbG9jYWxlIDogdGhpcy5jdXJyZW50TG9jYWxlO1xuICAgICAgICBjb25zdCB0aW1lT2Zmc2V0ID0gdGhpcy5nZXRSZWxhdGl2ZVRpbWVPZmZzZXQoZnJvbSwgdG8pO1xuICAgICAgICBjb25zdCByZXMgPSB0aGlzLnJlbGF0aXZlVGltZUZvcm1hdCggdGltZU9mZnNldC5vZmZzZXQsIHRpbWVPZmZzZXQudW5pdCwgbG9jYWxlLCBvcHRpb25zKTtcbiAgICAgICAgcmV0dXJuIHJlcztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDYWxjdWxhdGUgdGhlIG1vc3Qgc3VpdGFibGUgdW5pdCBhbmQgdGhlIGNvcnJlc3BvbmRpbmcgb2Zmc2V0IGFjY29yZGluZyB0byB0aGUgaW5wdXQgdGltZVxuICAgICAqIEBwYXJhbSBmcm9tIFRoZSBzdGFydGluZyB0aW1lIG9mIHJlbGF0aXZlIHRpbWUgY2FsY3VsYXRpb24uXG4gICAgICogQHBhcmFtIHRvIFRoZSBlbmRpbmcgdGltZSBvZiByZWxhdGl2ZSB0aW1lIGNhbGN1bGF0aW9uLlxuICAgICAqL1xuICAgIHByaXZhdGUgZ2V0UmVsYXRpdmVUaW1lT2Zmc2V0KGZyb206IERhdGUsIHRvOiBEYXRlKSB7XG4gICAgICAgIC8vIFZlcmlmeSB0aGUgaW5wdXQgdGltZVxuICAgICAgICB0aGlzLnZhbGlkYXRlRGF0ZShmcm9tKTtcbiAgICAgICAgdGhpcy52YWxpZGF0ZURhdGUodG8pO1xuICAgICAgICBjb25zdCBvZmZzZXQgPSB0aGlzLnJlbGF0aXZlRm9ybWF0LmdldE9mZnNldChmcm9tLCB0byk7XG4gICAgICAgIHJldHVybiBvZmZzZXQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IGZvcm1hdHRlZCBtZXNzYWdlIHJlYXBvbnNlYWJsZVxuICAgICAqIEBwYXJhbSBvZmZzZXQgVGhlIG9mZnNldCBvZiB0aW1lXG4gICAgICogQHBhcmFtIHVuaXQgVGhlIHVuaXQgb2Ygb2Zmc2V0XG4gICAgICogQHBhcmFtIGxvY2FsZSBUaGUgbG9jYWxlIHRvIGRldGVybWluZSB3aGljaCBwYXR0ZXJzIG5lZWQgdG8gdXNlLlxuICAgICAqIEBwYXJhbSBvcHRpb25zIFRoZSBmb3JtYXR0aW5nIHN0eWxlLlxuICAgICAqL1xuICAgIHByaXZhdGUgcmVsYXRpdmVUaW1lRm9ybWF0KG9mZnNldDogbnVtYmVyLCB1bml0OiBzdHJpbmcsIGxvY2FsZTogc3RyaW5nLCBvcHRpb25zOiBGb3JtYXRPcHRpb24gKTogc3RyaW5nIHtcbiAgICAgICAgY29uc3QgZm9ybWF0X251bWVyaWMgPSBvcHRpb25zICYmIG9wdGlvbnMubnVtZXJpYyA9PT0gJ2F1dG8nID8gJ2F1dG8nIDogJ2Fsd2F5cyc7XG5cbiAgICAgICAgLy8gR2V0IHRoZSBkYXRhIG9mIGB1bml0YCBpbiB0aGUgZmllbGRzIG5vZGUgaW4gdGhlIGRhdGUgcGF0dGVybiBkYXRhLlxuICAgICAgICBjb25zdCBkYXRlRmllbGRzID0gdGhpcy5nZXRQYXR0ZXJuKFBhdHRlcm5DYXRlZ29yaWVzLkRBVEVGSUVMRFMsIGxvY2FsZSkgfHwgdGhpcy5nZXRTb3VyY2VQYXR0ZXJuKFBhdHRlcm5DYXRlZ29yaWVzLkRBVEVGSUVMRFMpO1xuICAgICAgICBjb25zdCBkYXRhT2ZVbml0ID0gZGF0ZUZpZWxkc1t1bml0XTtcblxuICAgICAgICAvLyBHZXQgdGhlIG1lc3NhZ2UgY29ycmVzcG9uZGluZyB0byB0aGUgb2Zmc2V0LlxuICAgICAgICBsZXQgbWVzc2FnZXM6IHN0cmluZztcbiAgICAgICAgLy8gSWYgYG51bWVyaWNgIGlzIGF1dG9tYXRpYywgTWF0Y2ggdGhlIG1lc3NhZ2UgY29ycmVzcG9uZGluZyB0byB0aGUgb2Zmc2V0IHZhbHVlIGZpcnN0LlxuICAgICAgICBpZiAoIGZvcm1hdF9udW1lcmljID09PSAnYXV0bycgKSB7XG4gICAgICAgICAgICBtZXNzYWdlcyA9ICBkYXRhT2ZVbml0IFsgTWVzc2FnZVByZWZpeC5BVVRPICsgb2Zmc2V0IF07XG4gICAgICAgIH1cbiAgICAgICAgLy8gQWNjb3JkaW5nIHRvIHRoZSBwbHVyYWwgdHlwZSBvZiBvZmZzZXQsIG9idGFpbiB0aGUgbWVzc2FnZS5cbiAgICAgICAgaWYgKCAhbWVzc2FnZXMgKSB7XG4gICAgICAgICAgICBjb25zdCBwbHVyYWxUeXBlID0gdGhpcy5nZXRQbHVyYWxDYXRlZ29yeShNYXRoLmFicyhvZmZzZXQpLCBsb2NhbGUpO1xuICAgICAgICAgICAgY29uc3QgZGlyZWN0aW9uID0gb2Zmc2V0ID4gMCA/ICdmdXR1cmUnIDogJ3Bhc3QnO1xuICAgICAgICAgICAgbWVzc2FnZXMgPSBkYXRhT2ZVbml0W01lc3NhZ2VQcmVmaXguQUxXQVlTICsgZGlyZWN0aW9uXVtNZXNzYWdlUHJlZml4LlBMVVJBTFRZUEUgKyBwbHVyYWxUeXBlXVxuICAgICAgICAgICAgICAgICAgICB8fCBkYXRhT2ZVbml0W01lc3NhZ2VQcmVmaXguQUxXQVlTICsgZGlyZWN0aW9uXVtNZXNzYWdlUHJlZml4LlBMVVJBTFRZUEUgKyAnb3RoZXInXTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCByZXMgPSBmb3JtYXQobWVzc2FnZXMsIFtNYXRoLmFicyhvZmZzZXQpXSk7XG4gICAgICAgIHJldHVybiByZXM7XG4gICAgfVxuXG4gICAgcHVibGljIGdldEZvcm1hdHRlZERlY2ltYWwodmFsdWU6IGFueSwgbG9jYWxlPzogc3RyaW5nKSB7XG4gICAgICAgIGRlcHJlY2F0ZWRXYXJuKCdnZXRGb3JtYXR0ZWREZWNpbWFsIGluIEkxOG5TZXJ2aWNlJywgJ3Y5JywgJ2Zvcm1hdE51bWJlcicpO1xuICAgICAgICByZXR1cm4gdGhpcy5mb3JtYXROdW1iZXIodmFsdWUsIGxvY2FsZSk7XG4gICAgfVxuICAgIHB1YmxpYyBmb3JtYXROdW1iZXIodmFsdWU6IGFueSwgbG9jYWxlPzogc3RyaW5nLCBmb3JtYXRPcHRpb25zPzogTnVtYmVyRm9ybWF0T3B0aW9ucyk6IHN0cmluZyB7XG4gICAgICAgIGxvY2FsZSA9IGlzRGVmaW5lZChsb2NhbGUpID8gbG9jYWxlIDogdGhpcy5jdXJyZW50TG9jYWxlO1xuICAgICAgICB2YWx1ZSA9IHRoaXMudmFsaWRhdGVOdW1iZXIodmFsdWUpO1xuICAgICAgICBjb25zdCBmb3JtYXR0ZXIgPSB0aGlzLmdldEZvcm1hdHRlcignZGVjaW1hbCcsIFBhdHRlcm5DYXRlZ29yaWVzLk5VTUJFUiwgbG9jYWxlKTtcbiAgICAgICAgY29uc3QgdGV4dCA9IGZvcm1hdHRlcih2YWx1ZSwgZm9ybWF0T3B0aW9ucyk7XG4gICAgICAgIHJldHVybiB0ZXh0O1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRGb3JtYXR0ZWRQZXJjZW50KHZhbHVlOiBhbnkpIHtcbiAgICAgICAgZGVwcmVjYXRlZFdhcm4oJ2dldEZvcm1hdHRlZFBlcmNlbnQgaW4gSTE4blNlcnZpY2UnLCAndjknLCAnZm9ybWF0UGVyY2VudCcpO1xuICAgICAgICByZXR1cm4gdGhpcy5mb3JtYXRQZXJjZW50KHZhbHVlKTtcbiAgICB9XG4gICAgcHVibGljIGZvcm1hdFBlcmNlbnQodmFsdWU6IGFueSwgbG9jYWxlPzogc3RyaW5nLCBmb3JtYXRPcHRpb25zPzogTnVtYmVyRm9ybWF0T3B0aW9ucyk6IHN0cmluZyB7XG4gICAgICAgIGxvY2FsZSA9IGlzRGVmaW5lZChsb2NhbGUpID8gbG9jYWxlIDogdGhpcy5jdXJyZW50TG9jYWxlO1xuICAgICAgICB2YWx1ZSA9IHRoaXMudmFsaWRhdGVOdW1iZXIodmFsdWUpO1xuICAgICAgICBjb25zdCBmb3JtYXR0ZXIgPSB0aGlzLmdldEZvcm1hdHRlcigncGVyY2VudCcsIFBhdHRlcm5DYXRlZ29yaWVzLk5VTUJFUiwgbG9jYWxlKTtcbiAgICAgICAgY29uc3QgdGV4dCA9IGZvcm1hdHRlcih2YWx1ZSwgZm9ybWF0T3B0aW9ucyk7XG4gICAgICAgIHJldHVybiB0ZXh0O1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRGb3JtYXR0ZWRDdXJyZW5jeSh2YWx1ZTogYW55LCBjdXJyZW5jeUNvZGU6IHN0cmluZyk6IGFueSB7XG4gICAgICAgIGRlcHJlY2F0ZWRXYXJuKCdnZXRGb3JtYXR0ZWRDdXJyZW5jeSBpbiBJMThuU2VydmljZScsICd2OScsICdmb3JtYXRDdXJyZW5jeScpO1xuICAgICAgICByZXR1cm4gdGhpcy5mb3JtYXRDdXJyZW5jeSh2YWx1ZSwgY3VycmVuY3lDb2RlKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZm9ybWF0Q3VycmVuY3kodmFsdWU6IGFueSwgY3VycmVuY3lDb2RlPzogc3RyaW5nLCBsb2NhbGU/OiBzdHJpbmcsIGZvcm1hdE9wdGlvbnM/OiBOdW1iZXJGb3JtYXRPcHRpb25zKTogYW55IHtcbiAgICAgICAgY3VycmVuY3lDb2RlID0gaXNEZWZpbmVkKGN1cnJlbmN5Q29kZSkgPyBjdXJyZW5jeUNvZGUgOiAnVVNEJztcbiAgICAgICAgbG9jYWxlID0gaXNEZWZpbmVkKGxvY2FsZSkgPyBsb2NhbGUgOiB0aGlzLmN1cnJlbnRMb2NhbGU7XG4gICAgICAgIHZhbHVlID0gdGhpcy52YWxpZGF0ZU51bWJlcih2YWx1ZSk7XG4gICAgICAgIGNvbnN0IGZvcm1hdHRlciA9IHRoaXMuZ2V0Rm9ybWF0dGVyKCdjdXJyZW5jaWVzJywgUGF0dGVybkNhdGVnb3JpZXMuQ1VSUkVOQ0lFUywgbG9jYWxlKTtcbiAgICAgICAgY29uc3QgdGV4dCA9IGZvcm1hdHRlcih2YWx1ZSwgY3VycmVuY3lDb2RlLCBmb3JtYXRPcHRpb25zKTtcbiAgICAgICAgcmV0dXJuIHRleHQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVGhpcyBBUElzIHdpbGwgYmUgY2FsbCBieSBsMTBuIHNlcnZpY2Ugd2hlbiByZW5kZXIgcGx1cmFsIG1lc3NhZ2VcbiAgICAgKiBAcGFyYW0gdmFsdWUgTnVtZXJhbHMgdGhhdCBuZWVkIHRvIGJlIGRlYWx0IHdpdGhcbiAgICAgKiBAcGFyYW0gbG9jYWxlIExvY2FsZSAgZnJvbSBsMTBuIHNlcnZpY2VcbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0UGx1cmFsQ2F0ZWdvcnkodmFsdWU6IG51bWJlciwgbG9jYWxlPzogc3RyaW5nKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICAgICAgbG9jYWxlID0gaXNEZWZpbmVkKGxvY2FsZSkgPyBsb2NhbGUgOiB0aGlzLmN1cnJlbnRMb2NhbGU7XG4gICAgICAgIHZhbHVlID0gdGhpcy52YWxpZGF0ZU51bWJlcih2YWx1ZSk7XG4gICAgICAgIHZhbHVlID0gTWF0aC5hYnModmFsdWUpO1xuICAgICAgICAvLyB0cnkgdG8gcm91bmQgbnVtYmVyIHdpdGggZGVmYXVsdCBudW1iZXIgZm9ybWF0dGluZyBydWxlc1xuICAgICAgICAvLyBpZiBkYXRhIGlzbid0IGV4aXN0LCB1c2Ugb3JpZ2luIG51bWJlci5cbiAgICAgICAgLy8gZ2V0UGF0dGVybiB3aWxsIHVzZSB2YWxpZGF0ZVNjb3BlIHRvIHZhbGlkYXRlIGlzIGNvcnJlY3QgZm9ybWF0dGluZyBkYXRhIGV4aXN0LlxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgY29uc3QgZGF0YUZvck51bWJlciA9IHRoaXMuZ2V0UGF0dGVybihQYXR0ZXJuQ2F0ZWdvcmllcy5OVU1CRVIsIGxvY2FsZSk7XG4gICAgICAgICAgICBjb25zdCBmb3JtYXR0ZXIgPSB0aGlzLmZvcm1hdHRlci5yb3VuZE51bWJlckZvclBsdXJhbChkYXRhRm9yTnVtYmVyLCBsb2NhbGUpO1xuICAgICAgICAgICAgdmFsdWUgPSBOdW1iZXIoZm9ybWF0dGVyKHZhbHVlKSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7IH1cbiAgICAgICAgY29uc3QgcGx1cmFGdW5jdGlvbiA9IHRoaXMuZ2V0UGx1cmFsRnVuY3Rpb24obG9jYWxlKTtcbiAgICAgICAgY29uc3QgdHlwZSA9IHBsdXJhRnVuY3Rpb24gPyBwbHVyYUZ1bmN0aW9uKHZhbHVlKSA6IHVuZGVmaW5lZDtcbiAgICAgICAgcmV0dXJuIHR5cGU7XG4gICAgfVxuICAgIHB1YmxpYyBnZXRQbHVyYWxDYXRlZ29yeVR5cGUodmFsdWU6IG51bWJlciwgbG9jYWxlPzogc3RyaW5nKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICAgICAgZGVwcmVjYXRlZFdhcm4oJ2dldFBsdXJhbENhdGVnb3J5VHlwZSBpbiBJMThuU2VydmljZScsICd2OScsICdnZXRQbHVyYWxDYXRlZ29yeScpO1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRQbHVyYWxDYXRlZ29yeSh2YWx1ZSwgbG9jYWxlKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGdldFBsdXJhbEZ1bmN0aW9uKGxvY2FsZTogc3RyaW5nKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnBsdXJhbC5nZXRGdW5jKGxvY2FsZSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSB2YWxpZGF0ZVNjb3BlKHR5cGU6IFBhdHRlcm5DYXRlZ29yaWVzKTogYm9vbGVhbiB7XG4gICAgICAgIGlmICghdGhpcy5sb2NhbGVTZXJ2aWNlLmlzU291cmNlTG9jYWxlICYmIHRoaXMudmlwU2VydmljZS5pMThuU2NvcGUuaW5kZXhPZih0eXBlKSA9PT0gLTEpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgWW91IHNob3VsZCBhZGQgJyR7dHlwZX0nIHRvICdpMThuU2NvcGUnIGluIGluaXRpYWxpemUgY29uZmlndXJhdGlvbmApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0cnV