@singleton-i18n/angular-client
Version:
Singleton client code for Angular 10.
399 lines • 62.7 kB
JavaScript
/*
* Copyright 2019-2021 VMware, Inc.
* SPDX-License-Identifier: EPL-2.0
*/
import { Decimal } from 'decimal.js-light';
import { NumberFormatTypes, RoundingMode, CurrenciesDataType } from './number.format.model';
import { isDefined, isEmptyObject, parseOption } from '../util';
import { Plural } from './plural/plural.formatter';
const DECIMAL_SEP = '.';
const ZERO_CHAR = '0';
const GROUP_SEP = ',';
const DIGIT_CHAR = '#';
const PATTERN_SEP = ';';
const MIN_INTEGER_RANGE = 1;
const MAX_INTEGER_RANGE = 21;
const MIN_FRACTION_RANGE = 0;
const MAX_FRACTION_RANGE = 20;
function getCompactData(data, display) {
const displayType = display === 'long' ? 'long' : 'short';
const compactData = data['decimalFormats-' + displayType].decimalFormat;
let compactMap;
let maxExponent = 0;
compactMap = Object.keys(compactData).reduce((newItem, compactKey) => {
const numberExponent = compactKey.split('0').length - 1;
const pluralForm = compactKey.split('-')[2];
newItem[numberExponent] = newItem[numberExponent] || {};
newItem[numberExponent][pluralForm] = compactData[compactKey];
maxExponent = Math.max(numberExponent, maxExponent);
return newItem;
}, {});
compactMap.maxExponent = maxExponent;
return compactMap;
}
class Formatter {
decimal(data, locale) {
const decimalFormats = data.numberFormats.decimalFormats;
const symbol = data.numberSymbols;
const formatsInfo = this.parseFormats(decimalFormats);
const formatsData = data.numberFormats;
return (value, formatOptions) => {
let currentFormats = formatsInfo;
let compactData;
if (!isEmptyObject(formatOptions)) {
currentFormats = this.resetFormats(formatsInfo, RoundingMode.ROUND_HALF_EVEN, formatOptions);
if (formatOptions.notation && formatOptions.notation === 'compact') {
compactData = getCompactData(formatsData, formatOptions.compactDisplay);
}
}
return this.resetString(currentFormats, symbol, value, compactData, locale);
};
}
currencies(data, locale) {
const formatsData = data.numberFormats;
const currencyFormats = data.currencyFormats;
const symbol = data.numberSymbols;
const formatsInfo = this.parseFormats(currencyFormats);
let nuDigits;
if (data.defaultNumberingSystem !== 'latn') {
nuDigits = data.numberingSystem._digits || undefined;
}
const currencySymbolFormatter = this.currencySymbol(data);
return (value, currencyCode, formatOptions) => {
const currentFormats = this.resetCurrencyFormatsInfo(formatsInfo, data, currencyCode, formatOptions);
let compactData;
if (!isEmptyObject(formatOptions) && formatOptions.notation === 'compact') {
compactData = getCompactData(formatsData, formatOptions.compactDisplay);
compactData.nuDigits = nuDigits;
}
const res = this.resetString(currentFormats, symbol, value, compactData, locale);
const currencySymbol = currencySymbolFormatter(currencyCode);
return res.replace(/\u00A4/g, currencySymbol);
};
}
currencySymbol(data) {
return (currencyCode) => {
const currencySymbol = data.currencySymbols[currencyCode] && data.currencySymbols[currencyCode].symbol
? data.currencySymbols[currencyCode].symbol
: currencyCode;
return currencySymbol;
};
}
percent(data) {
const percentFormats = data.numberFormats.percentFormats;
const symbol = data.numberSymbols;
const formatsInfo = this.parseFormats(percentFormats);
return (value, formatOptions) => {
let currentFormats = formatsInfo;
if (!isEmptyObject(formatOptions)) {
currentFormats = this.resetFormats(formatsInfo, RoundingMode.ROUND_HALF_EVEN, formatOptions);
}
value = +this.resetPercentNumber(value);
return this.resetString(currentFormats, symbol, value);
};
}
plural(data) {
const decimalFormats = data.numberFormats.decimalFormats;
let formatsInfo = this.parseFormats(decimalFormats);
return (value, min, max) => {
if (isDefined(max) || isDefined(min)) {
formatsInfo = this.resetFormats(formatsInfo, RoundingMode.ROUND_HALF_EVEN);
}
return this.roundingNumber(value, formatsInfo.minFrac, formatsInfo.maxFrac, formatsInfo.round);
};
}
resetFormats(formats, round, formatOptions) {
// assign the value type to a new object
const finalFormats = Object.assign({}, formats);
// in compact number formats, reset default digits
if (formatOptions.notation && formatOptions.compactDisplay) {
finalFormats.maxFrac = 0;
finalFormats.minFrac = 0;
finalFormats.minInt = 1;
}
if (isDefined(formatOptions.minFractionDigits)) {
finalFormats.minFrac = parseOption('minFractionDigits', [MIN_FRACTION_RANGE, MAX_FRACTION_RANGE], formatOptions.minFractionDigits);
}
if (isDefined(formatOptions.maxFractionDigits)) {
finalFormats.maxFrac = parseOption('maxFractionDigits', [MIN_FRACTION_RANGE, MAX_FRACTION_RANGE], formatOptions.maxFractionDigits);
}
else if (finalFormats.minFrac !== null && finalFormats.minFrac > finalFormats.maxFrac) {
// in the currency formatting, if the maximum fraction digit undefined in pattern, set the min as max
finalFormats.maxFrac = finalFormats.minFrac;
}
if (isDefined(formatOptions.minIntegerDigits)) {
finalFormats.minInt = parseOption('minIntegerDigits', [MIN_INTEGER_RANGE, MAX_INTEGER_RANGE], formatOptions.minIntegerDigits);
}
if (isDefined(round)) {
finalFormats.round = round;
}
return finalFormats;
}
/**
* Get info from the formats
* eg: ¤#,##0.00
* return: { gSize: 3, lgSize: 3, maxFrac: 2, minFrac: 2, minInt: 1, negPre: "-¤", posPre: "¤" }
*/
parseFormats(format, minusSign = '-') {
const patternInfo = {
'minInt': 1,
'minFrac': 0,
'maxFrac': 0,
'posPre': '',
'posSuf': '',
'negPre': '',
'negSuf': '',
'gSize': 0,
'lgSize': 0,
'round': RoundingMode.ROUND_HALF_EVEN
};
const patternParts = format.split(PATTERN_SEP);
const positive = patternParts[0];
const negative = patternParts[1];
const positiveParts = positive.indexOf(DECIMAL_SEP) !== -1
? positive.split(DECIMAL_SEP)
: [
positive.substring(0, positive.lastIndexOf(ZERO_CHAR) + 1),
positive.substring(positive.lastIndexOf(ZERO_CHAR) + 1)
];
const integer = positiveParts[0];
const fraction = positiveParts[1] || '';
patternInfo.posPre = integer.substr(0, integer.indexOf(DIGIT_CHAR));
for (let i = 0; i < fraction.length; i++) {
const ch = fraction.charAt(i);
if (ch === ZERO_CHAR) {
patternInfo.minFrac = patternInfo.maxFrac = i + 1;
}
else if (ch === DIGIT_CHAR) {
patternInfo.maxFrac = i + 1;
}
else {
patternInfo.posSuf += ch;
}
}
const groups = integer.split(GROUP_SEP);
patternInfo.gSize = groups[1] ? groups[1].length : 0;
patternInfo.lgSize = (groups[2] || groups[1]) ? (groups[2] || groups[1]).length : 0;
if (negative) {
const trunkLen = positive.length - patternInfo.posPre.length - patternInfo.posSuf.length;
const pos = negative.indexOf(DIGIT_CHAR);
patternInfo.negPre = negative.substr(0, pos).replace(/'/g, '');
patternInfo.negSuf = negative.substr(pos + trunkLen).replace(/'/g, '');
}
else {
patternInfo.negPre = minusSign + patternInfo.posPre;
patternInfo.negSuf = patternInfo.posSuf;
}
return patternInfo;
}
parseNumber(numStr) {
const digits = [];
let numberOfIntegerDigits;
let i;
// Decimal point?
if ((numberOfIntegerDigits = numStr.indexOf(DECIMAL_SEP)) > -1) {
numStr = numStr.replace(DECIMAL_SEP, '');
}
if (numberOfIntegerDigits < 0) {
// There was no decimal point or exponent so it is an integer.
numberOfIntegerDigits = numStr.length;
}
for (i = 0; i < numStr.length; i++) {
digits.push(+numStr.charAt(i));
}
return {
digits: digits,
integerLen: numberOfIntegerDigits
};
}
/**
* rounding number
*/
roundingNumber(number, minFrac, maxFrac, mode) {
// TODO exponent
const digists = number.toString().replace(DECIMAL_SEP, '').length;
const decimalIndex = number.toString().indexOf(DECIMAL_SEP);
const numberOfIntegerDigits = decimalIndex > -1 ? decimalIndex : digists;
const fractionLen = digists - numberOfIntegerDigits;
if (minFrac > maxFrac) {
throw new Error(`The minimum number of digits after fraction (${minFrac}) is higher than the maximum (${maxFrac}).`);
}
const newDecimal = new Decimal(number);
const fractionSize = Math.min(Math.max(minFrac, fractionLen), maxFrac);
const roundedNum = newDecimal.toFixed(fractionSize, mode);
return roundedNum;
}
resetCurrencyFormatsInfo(formatsInfo, data, currencyCode, formatOptions) {
if (!data.fractions[currencyCode] && isEmptyObject(formatOptions)) {
return formatsInfo;
}
// assign the value type to a new object
let finalFormats = Object.assign({}, formatsInfo);
if (data.fractions[currencyCode]) {
finalFormats.maxFrac = data.fractions[currencyCode][CurrenciesDataType.DIGIST];
finalFormats.minFrac = finalFormats.maxFrac;
}
const rounding = data.fractions[currencyCode] && data.fractions[currencyCode][CurrenciesDataType.ROUNDING];
finalFormats.round = !rounding || rounding === '0' ? formatsInfo.round : rounding;
if (!isEmptyObject(formatOptions)) {
finalFormats = this.resetFormats(finalFormats, finalFormats.round, formatOptions);
}
return finalFormats;
}
resetPercentNumber(num) {
return new Decimal(num).times(100).valueOf();
}
resetString(formatsInfo, symbol, value, compactData, locale) {
let formattedText;
const minFraction = formatsInfo.minFrac;
const maxFraction = formatsInfo.maxFrac;
const minInt = formatsInfo.minInt;
// compact
let numberExponent;
let compactPattern;
if (!isEmptyObject(compactData)) {
numberExponent = Math.abs(Math.floor(value)).toString().length - 1;
numberExponent = Math.min(numberExponent, compactData.maxExponent);
// Use default plural form to perform initial decimal shift
if (numberExponent >= 3) {
compactPattern = compactData[numberExponent] && compactData[numberExponent].other;
}
// if compactPattern is 0, output the number.
if (compactPattern === '0') {
compactPattern = null;
}
else if (compactPattern) {
const compactDigits = compactPattern.split('0').length - 1;
const divisor = numberExponent - (compactDigits - 1);
value = value / Math.pow(10, divisor);
}
}
// number rounding
let numberStr = this.roundingNumber(Math.abs(value), minFraction, maxFraction, formatsInfo.round);
// if no min fraction limit, remove meaningless 0
if (!minFraction) {
// if the number is >= 1e21
// use +numberStr will returns a string representing the number in exponential notation.
numberStr = +numberStr >= 1e21 ? numberStr : String(+numberStr);
}
let compactPrefix = '';
let compactSuffix = '';
if (compactData && compactPattern) {
// Get plural form after possible roundings
const pluralFunc = new Plural().getFunc(locale);
const pluralForm = pluralFunc && pluralFunc(+value) ? pluralFunc(+value) : 'other';
compactPattern = compactData[numberExponent][pluralForm] || compactPattern;
// if the compact pattern contains protected .
compactPattern = compactPattern.replace('\'.\'', '.');
const compactProperties = compactPattern.match(/^([^0]*)(0+)([^0]*)$/);
compactPrefix = compactProperties[1];
compactSuffix = compactProperties[3];
}
// parse the number string
const parsedNumber = this.parseNumber(numberStr);
let digits = parsedNumber.digits;
let integerLen = parsedNumber.integerLen;
let decimals = [];
// padding zero for integer if integerLen < minInt
for (; integerLen < minInt; integerLen++) {
digits.unshift(0);
}
// extract decimals digits
if (integerLen > 0) {
decimals = digits.splice(integerLen, digits.length);
}
else {
decimals = digits;
digits = [0];
}
if (compactData && compactData.nuDigits) {
digits.forEach((item, idx) => {
digits[idx] = compactData.nuDigits[+item];
});
decimals.forEach((item, idx) => {
decimals[idx] = compactData.nuDigits[+item];
});
}
// format the integer digits with grouping separators
const groups = [];
if (digits.length >= formatsInfo.lgSize) {
groups.unshift(digits.splice(-formatsInfo.lgSize, digits.length).join(''));
}
while (digits.length > formatsInfo.gSize) {
groups.unshift(digits.splice(-formatsInfo.gSize, digits.length).join(''));
}
if (digits.length) {
groups.unshift(digits.join(''));
}
formattedText = groups.join(symbol.group);
// append the decimal digits
if (decimals.length) {
formattedText += symbol.decimal + decimals.join('');
}
// append the compact infos
formattedText = compactPrefix + formattedText + compactSuffix;
if (value < 0) {
return formatsInfo.negPre + formattedText + formatsInfo.negSuf;
}
else {
return formatsInfo.posPre + formattedText + formatsInfo.posSuf;
}
}
}
export class FormatterFactory {
constructor() {
this.mapping = {};
this.formatter = new Formatter();
}
getFormatter(locale, type) {
if (!this.mapping[locale]) {
this.mapping[locale] = {};
}
let formatter;
if (this.mapping[locale] && this.mapping[locale][type]) {
formatter = this.mapping[locale] && this.mapping[locale][type];
}
return formatter;
}
currencies(data, locale) {
let formatter = this.getFormatter(locale, NumberFormatTypes.CURRENCIES);
if (!formatter) {
formatter = this.formatter.currencies(data, locale);
this.mapping[locale][NumberFormatTypes.CURRENCIES] = formatter;
}
return formatter;
}
currenySymbol(data, locale) {
let formatter = this.getFormatter(locale, NumberFormatTypes.CURRENCYSYMBOL);
if (!formatter) {
formatter = this.formatter.currencySymbol(data);
this.mapping[locale][NumberFormatTypes.CURRENCYSYMBOL] = formatter;
}
return formatter;
}
percent(data, locale) {
let formatter = this.getFormatter(locale, NumberFormatTypes.PERCENT);
if (!formatter) {
formatter = this.formatter.percent(data);
this.mapping[locale][NumberFormatTypes.PERCENT] = formatter;
}
return formatter;
}
decimal(data, locale) {
let formatter = this.getFormatter(locale, NumberFormatTypes.DECIMAL);
if (!formatter) {
formatter = this.formatter.decimal(data, locale);
this.mapping[locale][NumberFormatTypes.DECIMAL] = formatter;
}
return formatter;
}
roundNumberForPlural(data, locale) {
let formatter = this.getFormatter(locale, NumberFormatTypes.PLURAL);
if (!formatter) {
formatter = this.formatter.plural(data);
this.mapping[locale][NumberFormatTypes.PLURAL] = formatter;
}
return formatter;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibnVtYmVyLmZvcm1hdHRlci5qcyIsInNvdXJjZVJvb3QiOiIvaG9tZS9ybGlnZW5nL1Byb2plY3RzL0Rldm9wcy9DbGllbnRfQW5ndWxhcl9HaXRIdWJfTnBtanMvdmlwL2NpL3B1YjJvcmcvQ2xpZW50X0FuZ3VsYXJfR2l0SHViX05wbWpzL3NpbmdsZXRvbi9wcm9qZWN0cy9hbmd1bGFyLWNsaWVudC8iLCJzb3VyY2VzIjpbInNyYy9mb3JtYXR0ZXJzL251bWJlci5mb3JtYXR0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7OztHQUdHO0FBQ0gsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQzNDLE9BQU8sRUFDSCxpQkFBaUIsRUFHakIsWUFBWSxFQUNaLGtCQUFrQixFQUVyQixNQUFNLHVCQUF1QixDQUFDO0FBQy9CLE9BQU8sRUFBRSxTQUFTLEVBQUUsYUFBYSxFQUFFLFdBQVcsRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUNoRSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFbkQsTUFBTSxXQUFXLEdBQUcsR0FBRyxDQUFDO0FBQ3hCLE1BQU0sU0FBUyxHQUFHLEdBQUcsQ0FBQztBQUN0QixNQUFNLFNBQVMsR0FBRyxHQUFHLENBQUM7QUFDdEIsTUFBTSxVQUFVLEdBQUcsR0FBRyxDQUFDO0FBQ3ZCLE1BQU0sV0FBVyxHQUFHLEdBQUcsQ0FBQztBQUV4QixNQUFNLGlCQUFpQixHQUFHLENBQUMsQ0FBQztBQUM1QixNQUFNLGlCQUFpQixHQUFHLEVBQUUsQ0FBQztBQUM3QixNQUFNLGtCQUFrQixHQUFHLENBQUMsQ0FBQztBQUM3QixNQUFNLGtCQUFrQixHQUFHLEVBQUUsQ0FBQztBQVU5QixTQUFTLGNBQWMsQ0FBQyxJQUFTLEVBQUUsT0FBZTtJQUM5QyxNQUFNLFdBQVcsR0FBRyxPQUFPLEtBQUssTUFBTSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQztJQUMx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Q3JELElBQUksU0FBUyxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUUsTUFBTSxFQUFFLGlCQUFpQixDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3JFLElBQUksQ0FBQyxTQUFTLEVBQUU7WUFDWixTQUFTLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDeEMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxpQkFBaUIsQ0FBQyxNQUFNLENBQUMsR0FBRyxTQUFTLENBQUM7U0FDOUQ7UUFDRCxPQUFPLFNBQVMsQ0FBQztJQUNyQixDQUFDO0NBQ0oiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICogQ29weXJpZ2h0IDIwMTktMjAyMSBWTXdhcmUsIEluYy5cbiAqIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBFUEwtMi4wXG4gKi9cbmltcG9ydCB7IERlY2ltYWwgfSBmcm9tICdkZWNpbWFsLmpzLWxpZ2h0JztcbmltcG9ydCB7XG4gICAgTnVtYmVyRm9ybWF0VHlwZXMsXG4gICAgRGF0YUZvck51bWJlcixcbiAgICBEYXRhRm9yQ3VycmVuY3ksXG4gICAgUm91bmRpbmdNb2RlLFxuICAgIEN1cnJlbmNpZXNEYXRhVHlwZSxcbiAgICBOdW1iZXJGb3JtYXRPcHRpb25zXG59IGZyb20gJy4vbnVtYmVyLmZvcm1hdC5tb2RlbCc7XG5pbXBvcnQgeyBpc0RlZmluZWQsIGlzRW1wdHlPYmplY3QsIHBhcnNlT3B0aW9uIH0gZnJvbSAnLi4vdXRpbCc7XG5pbXBvcnQgeyBQbHVyYWwgfSBmcm9tICcuL3BsdXJhbC9wbHVyYWwuZm9ybWF0dGVyJztcblxuY29uc3QgREVDSU1BTF9TRVAgPSAnLic7XG5jb25zdCBaRVJPX0NIQVIgPSAnMCc7XG5jb25zdCBHUk9VUF9TRVAgPSAnLCc7XG5jb25zdCBESUdJVF9DSEFSID0gJyMnO1xuY29uc3QgUEFUVEVSTl9TRVAgPSAnOyc7XG5cbmNvbnN0IE1JTl9JTlRFR0VSX1JBTkdFID0gMTtcbmNvbnN0IE1BWF9JTlRFR0VSX1JBTkdFID0gMjE7XG5jb25zdCBNSU5fRlJBQ1RJT05fUkFOR0UgPSAwO1xuY29uc3QgTUFYX0ZSQUNUSU9OX1JBTkdFID0gMjA7XG5cblxuaW50ZXJmYWNlIFBhcnNlZE51bWJlciB7XG4gICAgLy8gYW4gYXJyYXkgb2YgZGlnaXRzIGNvbnRhaW5pbmcgbGVhZGluZyB6ZXJvcyBhcyBuZWNlc3NhcnlcbiAgICBkaWdpdHM6IG51bWJlcltdO1xuICAgIC8vIHRoZSBudW1iZXIgb2YgdGhlIGRpZ2l0cyBpbiBgZGlnaXRzYCB0aGF0IGFyZSB0byB0aGUgbGVmdCBvZiB0aGUgZGVjaW1hbCBwb2ludFxuICAgIGludGVnZXJMZW46IG51bWJlcjtcbn1cblxuZnVuY3Rpb24gZ2V0Q29tcGFjdERhdGEoZGF0YTogYW55LCBkaXNwbGF5OiBzdHJpbmcpIHtcbiAgICBjb25zdCBkaXNwbGF5VHlwZSA9IGRpc3BsYXkgPT09ICdsb25nJyA/ICdsb25nJyA6ICdzaG9ydCc7XG4gICAgY29uc3QgY29tcGFjdERhdGEgPSBkYXRhWydkZWNpbWFsRm9ybWF0cy0nICsgZGlzcGxheVR5cGVdLmRlY2ltYWxGb3JtYXQ7XG4gICAgbGV0IGNvbXBhY3RNYXA6IGFueTtcbiAgICBsZXQgbWF4RXhwb25lbnQgPSAwO1xuICAgIGNvbXBhY3RNYXAgPSBPYmplY3Qua2V5cyhjb21wYWN0RGF0YSkucmVkdWNlKChuZXdJdGVtLCBjb21wYWN0S2V5KSA9PiB7XG4gICAgICAgIGNvbnN0IG51bWJlckV4cG9uZW50ID0gY29tcGFjdEtleS5zcGxpdCgnMCcpLmxlbmd0aCAtIDE7XG4gICAgICAgIGNvbnN0IHBsdXJhbEZvcm0gPSBjb21wYWN0S2V5LnNwbGl0KCctJylbMl07XG4gICAgICAgIG5ld0l0ZW1bbnVtYmVyRXhwb25lbnRdID0gbmV3SXRlbVtudW1iZXJFeHBvbmVudF0gfHwge307XG4gICAgICAgIG5ld0l0ZW1bbnVtYmVyRXhwb25lbnRdW3BsdXJhbEZvcm1dID0gY29tcGFjdERhdGFbY29tcGFjdEtleV07XG4gICAgICAgIG1heEV4cG9uZW50ID0gTWF0aC5tYXgobnVtYmVyRXhwb25lbnQsIG1heEV4cG9uZW50KTtcbiAgICAgICAgcmV0dXJuIG5ld0l0ZW07XG4gICAgfSwge30pO1xuXG4gICAgY29tcGFjdE1hcC5tYXhFeHBvbmVudCA9IG1heEV4cG9uZW50O1xuICAgIHJldHVybiBjb21wYWN0TWFwO1xufVxuXG5jbGFzcyBGb3JtYXR0ZXIge1xuICAgIGRlY2ltYWwoZGF0YTogRGF0YUZvck51bWJlciwgbG9jYWxlOiBzdHJpbmcpIHtcbiAgICAgICAgY29uc3QgZGVjaW1hbEZvcm1hdHMgPSBkYXRhLm51bWJlckZvcm1hdHMuZGVjaW1hbEZvcm1hdHM7XG4gICAgICAgIGNvbnN0IHN5bWJvbCA9IGRhdGEubnVtYmVyU3ltYm9scztcbiAgICAgICAgY29uc3QgZm9ybWF0c0luZm8gPSB0aGlzLnBhcnNlRm9ybWF0cyhkZWNpbWFsRm9ybWF0cyk7XG4gICAgICAgIGNvbnN0IGZvcm1hdHNEYXRhID0gZGF0YS5udW1iZXJGb3JtYXRzO1xuICAgICAgICByZXR1cm4gKHZhbHVlOiBudW1iZXIsIGZvcm1hdE9wdGlvbnM/OiBOdW1iZXJGb3JtYXRPcHRpb25zKSA9PiB7XG4gICAgICAgICAgICBsZXQgY3VycmVudEZvcm1hdHMgPSBmb3JtYXRzSW5mbztcbiAgICAgICAgICAgIGxldCBjb21wYWN0RGF0YTtcbiAgICAgICAgICAgIGlmICggIWlzRW1wdHlPYmplY3QoZm9ybWF0T3B0aW9ucykgKSB7XG4gICAgICAgICAgICAgICAgY3VycmVudEZvcm1hdHMgPSB0aGlzLnJlc2V0Rm9ybWF0cyggZm9ybWF0c0luZm8sIFJvdW5kaW5nTW9kZS5ST1VORF9IQUxGX0VWRU4sIGZvcm1hdE9wdGlvbnMgKTtcbiAgICAgICAgICAgICAgICBpZiAoIGZvcm1hdE9wdGlvbnMubm90YXRpb24gJiYgZm9ybWF0T3B0aW9ucy5ub3RhdGlvbiA9PT0gJ2NvbXBhY3QnICkge1xuICAgICAgICAgICAgICAgICAgICBjb21wYWN0RGF0YSA9IGdldENvbXBhY3REYXRhKGZvcm1hdHNEYXRhLCBmb3JtYXRPcHRpb25zLmNvbXBhY3REaXNwbGF5KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5yZXNldFN0cmluZyhjdXJyZW50Rm9ybWF0cywgc3ltYm9sLCB2YWx1ZSwgY29tcGFjdERhdGEsIGxvY2FsZSk7XG4gICAgICAgIH07XG4gICAgfVxuICAgIGN1cnJlbmNpZXMoZGF0YTogRGF0YUZvckN1cnJlbmN5LCBsb2NhbGU6IHN0cmluZykge1xuICAgICAgICBjb25zdCBmb3JtYXRzRGF0YSA9IGRhdGEubnVtYmVyRm9ybWF0cztcbiAgICAgICAgY29uc3QgY3VycmVuY3lGb3JtYXRzID0gZGF0YS5jdXJyZW5jeUZvcm1hdHM7XG4gICAgICAgIGNvbnN0IHN5bWJvbCA9IGRhdGEubnVtYmVyU3ltYm9scztcbiAgICAgICAgY29uc3QgZm9ybWF0c0luZm8gPSB0aGlzLnBhcnNlRm9ybWF0cyhjdXJyZW5jeUZvcm1hdHMpO1xuICAgICAgICBsZXQgbnVEaWdpdHM6IHN0cmluZztcbiAgICAgICAgaWYgKCBkYXRhLmRlZmF1bHROdW1iZXJpbmdTeXN0ZW0gIT09ICdsYXRuJykge1xuICAgICAgICAgICAgbnVEaWdpdHMgPSBkYXRhLm51bWJlcmluZ1N5c3RlbS5fZGlnaXRzIHx8IHVuZGVmaW5lZDtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBjdXJyZW5jeVN5bWJvbEZvcm1hdHRlciA9IHRoaXMuY3VycmVuY3lTeW1ib2woZGF0YSk7XG4gICAgICAgIHJldHVybiAodmFsdWU6IG51bWJlciwgY3VycmVuY3lDb2RlOiBzdHJpbmcsIGZvcm1hdE9wdGlvbnM/OiBOdW1iZXJGb3JtYXRPcHRpb25zKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBjdXJyZW50Rm9ybWF0cyA9IHRoaXMucmVzZXRDdXJyZW5jeUZvcm1hdHNJbmZvKGZvcm1hdHNJbmZvLCBkYXRhLCBjdXJyZW5jeUNvZGUsIGZvcm1hdE9wdGlvbnMpO1xuICAgICAgICAgICAgbGV0IGNvbXBhY3REYXRhO1xuICAgICAgICAgICAgaWYgKCAhaXNFbXB0eU9iamVjdChmb3JtYXRPcHRpb25zKSAmJiBmb3JtYXRPcHRpb25zLm5vdGF0aW9uID09PSAnY29tcGFjdCcgKSB7XG4gICAgICAgICAgICAgICAgY29tcGFjdERhdGEgPSBnZXRDb21wYWN0RGF0YShmb3JtYXRzRGF0YSwgZm9ybWF0T3B0aW9ucy5jb21wYWN0RGlzcGxheSk7XG4gICAgICAgICAgICAgICAgY29tcGFjdERhdGEubnVEaWdpdHMgPSBudURpZ2l0cztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IHJlcyA9IHRoaXMucmVzZXRTdHJpbmcoY3VycmVudEZvcm1hdHMsIHN5bWJvbCwgdmFsdWUsIGNvbXBhY3REYXRhLCBsb2NhbGUpO1xuICAgICAgICAgICAgY29uc3QgY3VycmVuY3lTeW1ib2wgPSBjdXJyZW5jeVN5bWJvbEZvcm1hdHRlcihjdXJyZW5jeUNvZGUpO1xuICAgICAgICAgICAgcmV0dXJuIHJlcy5yZXBsYWNlKC9cXHUwMEE0L2csIGN1cnJlbmN5U3ltYm9sKTtcbiAgICAgICAgfTtcbiAgICB9XG4gICAgY3VycmVuY3lTeW1ib2woZGF0YTogRGF0YUZvckN1cnJlbmN5KSB7XG4gICAgICAgIHJldHVybiAoY3VycmVuY3lDb2RlOiBzdHJpbmcpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGN1cnJlbmN5U3ltYm9sID0gZGF0YS5jdXJyZW5jeVN5bWJvbHNbY3VycmVuY3lDb2RlXSAmJiBkYXRhLmN1cnJlbmN5U3ltYm9sc1tjdXJyZW5jeUNvZGVdLnN5bWJvbFxuICAgICAgICAgICAgPyBkYXRhLmN1cnJlbmN5U3ltYm9sc1tjdXJyZW5jeUNvZGVdLnN5bWJvbFxuICAgICAgICAgICAgOiBjdXJyZW5jeUNvZGU7XG4gICAgICAgICAgICByZXR1cm4gY3VycmVuY3lTeW1ib2w7XG4gICAgICAgIH07XG4gICAgfVxuICAgIHBlcmNlbnQoZGF0YTogRGF0YUZvck51bWJlcikge1xuICAgICAgICBjb25zdCBwZXJjZW50Rm9ybWF0cyA9IGRhdGEubnVtYmVyRm9ybWF0cy5wZXJjZW50Rm9ybWF0cztcbiAgICAgICAgY29uc3Qgc3ltYm9sID0gZGF0YS5udW1iZXJTeW1ib2xzO1xuICAgICAgICBjb25zdCBmb3JtYXRzSW5mbyA9IHRoaXMucGFyc2VGb3JtYXRzKHBlcmNlbnRGb3JtYXRzKTtcbiAgICAgICAgcmV0dXJuICh2YWx1ZTogbnVtYmVyLCBmb3JtYXRPcHRpb25zPzogTnVtYmVyRm9ybWF0T3B0aW9ucykgPT4ge1xuICAgICAgICAgICAgbGV0IGN1cnJlbnRGb3JtYXRzID0gZm9ybWF0c0luZm87XG4gICAgICAgICAgICBpZiAoICFpc0VtcHR5T2JqZWN0KGZvcm1hdE9wdGlvbnMpICkge1xuICAgICAgICAgICAgICAgIGN1cnJlbnRGb3JtYXRzID0gdGhpcy5yZXNldEZvcm1hdHMoIGZvcm1hdHNJbmZvLCBSb3VuZGluZ01vZGUuUk9VTkRfSEFMRl9FVkVOLCBmb3JtYXRPcHRpb25zICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YWx1ZSA9ICt0aGlzLnJlc2V0UGVyY2VudE51bWJlcih2YWx1ZSk7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5yZXNldFN0cmluZyhjdXJyZW50Rm9ybWF0cywgc3ltYm9sLCB2YWx1ZSk7XG4gICAgICAgIH07XG4gICAgfVxuICAgIHBsdXJhbCggZGF0YTogRGF0YUZvck51bWJlcikge1xuICAgICAgICBjb25zdCBkZWNpbWFsRm9ybWF0cyA9IGRhdGEubnVtYmVyRm9ybWF0cy5kZWNpbWFsRm9ybWF0cztcbiAgICAgICAgbGV0IGZvcm1hdHNJbmZvID0gdGhpcy5wYXJzZUZvcm1hdHMoZGVjaW1hbEZvcm1hdHMpO1xuICAgICAgICByZXR1cm4gKHZhbHVlOiBudW1iZXIsIG1pbj86IG51bWJlciwgbWF4PzogbnVtYmVyKSA9PiB7XG4gICAgICAgICAgICBpZiAoIGlzRGVmaW5lZChtYXgpIHx8IGlzRGVmaW5lZChtaW4pICkge1xuICAgICAgICAgICAgICAgIGZvcm1hdHNJbmZvID0gdGhpcy5yZXNldEZvcm1hdHMoIGZvcm1hdHNJbmZvLCBSb3VuZGluZ01vZGUuUk9VTkRfSEFMRl9FVkVOICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5yb3VuZGluZ051bWJlcih2YWx1ZSwgZm9ybWF0c0luZm8ubWluRnJhYywgZm9ybWF0c0luZm8ubWF4RnJhYywgZm9ybWF0c0luZm8ucm91bmQpO1xuICAgICAgICB9O1xuICAgIH1cbiAgICByZXNldEZvcm1hdHMoIGZvcm1hdHM6IGFueSwgcm91bmQ6IFJvdW5kaW5nTW9kZSwgZm9ybWF0T3B0aW9ucz86IE51bWJlckZvcm1hdE9wdGlvbnMgKSB7XG4gICAgICAgIC8vIGFzc2lnbiB0aGUgdmFsdWUgdHlwZSB0byBhIG5ldyBvYmplY3RcbiAgICAgICAgY29uc3QgZmluYWxGb3JtYXRzID0gT2JqZWN0LmFzc2lnbih7fSwgZm9ybWF0cyk7XG4gICAgICAgIC8vIGluIGNvbXBhY3QgbnVtYmVyIGZvcm1hdHMsIHJlc2V0IGRlZmF1bHQgZGlnaXRzXG4gICAgICAgIGlmICggZm9ybWF0T3B0aW9ucy5ub3RhdGlvbiAmJiBmb3JtYXRPcHRpb25zLmNvbXBhY3REaXNwbGF5ICkge1xuICAgICAgICAgICAgZmluYWxGb3JtYXRzLm1heEZyYWMgPSAwO1xuICAgICAgICAgICAgZmluYWxGb3JtYXRzLm1pbkZyYWMgPSAwO1xuICAgICAgICAgICAgZmluYWxGb3JtYXRzLm1pbkludCA9IDE7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGlzRGVmaW5lZChmb3JtYXRPcHRpb25zLm1pbkZyYWN0aW9uRGlnaXRzKSkge1xuICAgICAgICAgICAgZmluYWxGb3JtYXRzLm1pbkZyYWMgPSBwYXJzZU9wdGlvbignbWluRnJhY3Rpb25EaWdpdHMnLCBbTUlOX0ZSQUNUSU9OX1JBTkdFLCBNQVhfRlJBQ1RJT05fUkFOR0VdLCBmb3JtYXRPcHRpb25zLm1pbkZyYWN0aW9uRGlnaXRzKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoaXNEZWZpbmVkKGZvcm1hdE9wdGlvbnMubWF4RnJhY3Rpb25EaWdpdHMpKSB7XG4gICAgICAgICAgICBmaW5hbEZvcm1hdHMubWF4RnJhYyA9IHBhcnNlT3B0aW9uKCdtYXhGcmFjdGlvbkRpZ2l0cycsIFtNSU5fRlJBQ1RJT05fUkFOR0UsIE1BWF9GUkFDVElPTl9SQU5HRV0sIGZvcm1hdE9wdGlvbnMubWF4RnJhY3Rpb25EaWdpdHMpO1xuICAgICAgICB9IGVsc2UgaWYgKGZpbmFsRm9ybWF0cy5taW5GcmFjICE9PSBudWxsICYmIGZpbmFsRm9ybWF0cy5taW5GcmFjID4gZmluYWxGb3JtYXRzLm1heEZyYWMpIHtcbiAgICAgICAgICAgIC8vIGluIHRoZSBjdXJyZW5jeSBmb3JtYXR0aW5nLCBpZiB0aGUgbWF4aW11bSBmcmFjdGlvbiBkaWdpdCB1bmRlZmluZWQgaW4gcGF0dGVybiwgc2V0IHRoZSBtaW4gYXMgbWF4XG4gICAgICAgICAgICBmaW5hbEZvcm1hdHMubWF4RnJhYyA9IGZpbmFsRm9ybWF0cy5taW5GcmFjO1xuICAgICAgICB9XG4gICAgICAgIGlmICggaXNEZWZpbmVkKGZvcm1hdE9wdGlvbnMubWluSW50ZWdlckRpZ2l0cykgKSB7XG4gICAgICAgICAgICBmaW5hbEZvcm1hdHMubWluSW50ID0gcGFyc2VPcHRpb24oJ21pbkludGVnZXJEaWdpdHMnLCBbTUlOX0lOVEVHRVJfUkFOR0UsIE1BWF9JTlRFR0VSX1JBTkdFXSwgZm9ybWF0T3B0aW9ucy5taW5JbnRlZ2VyRGlnaXRzKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIGlzRGVmaW5lZChyb3VuZCkgKSB7XG4gICAgICAgICAgICBmaW5hbEZvcm1hdHMucm91bmQgPSByb3VuZDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZmluYWxGb3JtYXRzO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBHZXQgaW5mbyBmcm9tIHRoZSBmb3JtYXRzXG4gICAgICogZWc6IMKkIywjIzAuMDBcbiAgICAgKiByZXR1cm46IHsgZ1NpemU6IDMsIGxnU2l6ZTogMywgbWF4RnJhYzogMiwgbWluRnJhYzogMiwgbWluSW50OiAxLCBuZWdQcmU6IFwiLcKkXCIsIHBvc1ByZTogXCLCpFwiIH1cbiAgICAgKi9cbiAgICBwYXJzZUZvcm1hdHMoZm9ybWF0OiBzdHJpbmcsIG1pbnVzU2lnbiA9ICctJykge1xuICAgICAgICBjb25zdCBwYXR0ZXJuSW5mbyA9IHtcbiAgICAgICAgICAgICdtaW5JbnQnOiAxLFxuICAgICAgICAgICAgJ21pbkZyYWMnOiAwLFxuICAgICAgICAgICAgJ21heEZyYWMnOiAwLFxuICAgICAgICAgICAgJ3Bvc1ByZSc6ICcnLFxuICAgICAgICAgICAgJ3Bvc1N1Zic6ICcnLFxuICAgICAgICAgICAgJ25lZ1ByZSc6ICcnLFxuICAgICAgICAgICAgJ25lZ1N1Zic6ICcnLFxuICAgICAgICAgICAgJ2dTaXplJzogMCxcbiAgICAgICAgICAgICdsZ1NpemUnOiAwLFxuICAgICAgICAgICAgJ3JvdW5kJzogUm91bmRpbmdNb2RlLlJPVU5EX0hBTEZfRVZFTlxuICAgICAgICB9O1xuICAgICAgICBjb25zdCBwYXR0ZXJuUGFydHMgPSBmb3JtYXQuc3BsaXQoUEFUVEVSTl9TRVApO1xuICAgICAgICBjb25zdCBwb3NpdGl2ZSA9IHBhdHRlcm5QYXJ0c1swXTtcbiAgICAgICAgY29uc3QgbmVnYXRpdmUgPSBwYXR0ZXJuUGFydHNbMV07XG5cbiAgICAgICAgY29uc3QgcG9zaXRpdmVQYXJ0cyA9IHBvc2l0aXZlLmluZGV4T2YoREVDSU1BTF9TRVApICE9PSAtMVxuICAgICAgICAgICAgPyBwb3NpdGl2ZS5zcGxpdChERUNJTUFMX1NFUClcbiAgICAgICAgICAgIDogW1xuICAgICAgICAgICAgICAgIHBvc2l0aXZlLnN1YnN0cmluZygwLCBwb3NpdGl2ZS5sYXN0SW5kZXhPZihaRVJPX0NIQVIpICsgMSksXG4gICAgICAgICAgICAgICAgcG9zaXRpdmUuc3Vic3RyaW5nKHBvc2l0aXZlLmxhc3RJbmRleE9mKFpFUk9fQ0hBUikgKyAxKVxuICAgICAgICAgICAgXTtcbiAgICAgICAgY29uc3QgaW50ZWdlciA9IHBvc2l0aXZlUGFydHNbMF07XG4gICAgICAgIGNvbnN0IGZyYWN0aW9uID0gcG9zaXRpdmVQYXJ0c1sxXSB8fCAnJztcblxuICAgICAgICBwYXR0ZXJuSW5mby5wb3NQcmUgPSBpbnRlZ2VyLnN1YnN0cigwLCBpbnRlZ2VyLmluZGV4T2YoRElHSVRfQ0hBUikpO1xuXG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgZnJhY3Rpb24ubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGNvbnN0IGNoID0gZnJhY3Rpb24uY2hhckF0KGkpO1xuICAgICAgICAgICAgaWYgKGNoID09PSBaRVJPX0NIQVIpIHtcbiAgICAgICAgICAgICAgICBwYXR0ZXJuSW5mby5taW5GcmFjID0gcGF0dGVybkluZm8ubWF4RnJhYyA9IGkgKyAxO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChjaCA9PT0gRElHSVRfQ0hBUikge1xuICAgICAgICAgICAgICAgIHBhdHRlcm5JbmZvLm1heEZyYWMgPSBpICsgMTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcGF0dGVybkluZm8ucG9zU3VmICs9IGNoO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgZ3JvdXBzID0gaW50ZWdlci5zcGxpdChHUk9VUF9TRVApO1xuICAgICAgICBwYXR0ZXJuSW5mby5nU2l6ZSA9IGdyb3Vwc1sxXSA/IGdyb3Vwc1sxXS5sZW5ndGggOiAwO1xuICAgICAgICBwYXR0ZXJuSW5mby5sZ1NpemUgPSAoZ3JvdXBzWzJdIHx8IGdyb3Vwc1sxXSkgPyAoZ3JvdXBzWzJdIHx8IGdyb3Vwc1sxXSkubGVuZ3RoIDogMDtcblxuICAgICAgICBpZiAobmVnYXRpdmUpIHtcbiAgICAgICAgICAgIGNvbnN0IHRydW5rTGVuID0gcG9zaXRpdmUubGVuZ3RoIC0gcGF0dGVybkluZm8ucG9zUHJlLmxlbmd0aCAtIHBhdHRlcm5JbmZvLnBvc1N1Zi5sZW5ndGg7XG4gICAgICAgICAgICBjb25zdCBwb3MgPSBuZWdhdGl2ZS5pbmRleE9mKERJR0lUX0NIQVIpO1xuXG4gICAgICAgICAgICBwYXR0ZXJuSW5mby5uZWdQcmUgPSBuZWdhdGl2ZS5zdWJzdHIoMCwgcG9zKS5yZXBsYWNlKC8nL2csICcnKTtcbiAgICAgICAgICAgIHBhdHRlcm5JbmZvLm5lZ1N1ZiA9IG5lZ2F0aXZlLnN1YnN0cihwb3MgKyB0cnVua0xlbikucmVwbGFjZSgvJy9nLCAnJyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBwYXR0ZXJuSW5mby5uZWdQcmUgPSBtaW51c1NpZ24gKyBwYXR0ZXJuS