UNPKG

@angular/common

Version:

Angular - commonly needed directives and services

634 lines 59.9 kB
/** * @fileoverview added by tsickle * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * @license * Copyright Google Inc. All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ import { ɵLocaleDataIndex as LocaleDataIndex, ɵfindLocaleData as findLocaleData, ɵgetLocalePluralCase } from '@angular/core'; import { CURRENCIES_EN } from './currencies'; /** @enum {number} */ const NumberFormatStyle = { Decimal: 0, Percent: 1, Currency: 2, Scientific: 3, }; export { NumberFormatStyle }; NumberFormatStyle[NumberFormatStyle.Decimal] = 'Decimal'; NumberFormatStyle[NumberFormatStyle.Percent] = 'Percent'; NumberFormatStyle[NumberFormatStyle.Currency] = 'Currency'; NumberFormatStyle[NumberFormatStyle.Scientific] = 'Scientific'; /** @enum {number} */ const Plural = { Zero: 0, One: 1, Two: 2, Few: 3, Many: 4, Other: 5, }; export { Plural }; Plural[Plural.Zero] = 'Zero'; Plural[Plural.One] = 'One'; Plural[Plural.Two] = 'Two'; Plural[Plural.Few] = 'Few'; Plural[Plural.Many] = 'Many'; Plural[Plural.Other] = 'Other'; /** @enum {number} */ const FormStyle = { Format: 0, Standalone: 1, }; export { FormStyle }; FormStyle[FormStyle.Format] = 'Format'; FormStyle[FormStyle.Standalone] = 'Standalone'; /** @enum {number} */ const TranslationWidth = { /** 1 character for `en-US`. For example: 'S' */ Narrow: 0, /** 3 characters for `en-US`. For example: 'Sun' */ Abbreviated: 1, /** Full length for `en-US`. For example: "Sunday" */ Wide: 2, /** 2 characters for `en-US`, For example: "Su" */ Short: 3, }; export { TranslationWidth }; TranslationWidth[TranslationWidth.Narrow] = 'Narrow'; TranslationWidth[TranslationWidth.Abbreviated] = 'Abbreviated'; TranslationWidth[TranslationWidth.Wide] = 'Wide'; TranslationWidth[TranslationWidth.Short] = 'Short'; /** @enum {number} */ const FormatWidth = { /** * For `en-US`, 'M/d/yy, h:mm a'` * (Example: `6/15/15, 9:03 AM`) */ Short: 0, /** * For `en-US`, `'MMM d, y, h:mm:ss a'` * (Example: `Jun 15, 2015, 9:03:01 AM`) */ Medium: 1, /** * For `en-US`, `'MMMM d, y, h:mm:ss a z'` * (Example: `June 15, 2015 at 9:03:01 AM GMT+1`) */ Long: 2, /** * For `en-US`, `'EEEE, MMMM d, y, h:mm:ss a zzzz'` * (Example: `Monday, June 15, 2015 at 9:03:01 AM GMT+01:00`) */ Full: 3, }; export { FormatWidth }; FormatWidth[FormatWidth.Short] = 'Short'; FormatWidth[FormatWidth.Medium] = 'Medium'; FormatWidth[FormatWidth.Long] = 'Long'; FormatWidth[FormatWidth.Full] = 'Full'; /** @enum {number} */ const NumberSymbol = { /** * Decimal separator. * For `en-US`, the dot character. * Example : 2,345`.`67 */ Decimal: 0, /** * Grouping separator, typically for thousands. * For `en-US`, the comma character. * Example: 2`,`345.67 */ Group: 1, /** * List-item separator. * Example: "one, two, and three" */ List: 2, /** * Sign for percentage (out of 100). * Example: 23.4% */ PercentSign: 3, /** * Sign for positive numbers. * Example: +23 */ PlusSign: 4, /** * Sign for negative numbers. * Example: -23 */ MinusSign: 5, /** * Computer notation for exponential value (n times a power of 10). * Example: 1.2E3 */ Exponential: 6, /** * Human-readable format of exponential. * Example: 1.2x103 */ SuperscriptingExponent: 7, /** * Sign for permille (out of 1000). * Example: 23.4‰ */ PerMille: 8, /** * Infinity, can be used with plus and minus. * Example: ∞, +∞, -∞ */ Infinity: 9, /** * Not a number. * Example: NaN */ NaN: 10, /** * Symbol used between time units. * Example: 10:52 */ TimeSeparator: 11, /** * Decimal separator for currency values (fallback to `Decimal`). * Example: $2,345.67 */ CurrencyDecimal: 12, /** * Group separator for currency values (fallback to `Group`). * Example: $2,345.67 */ CurrencyGroup: 13, }; export { NumberSymbol }; NumberSymbol[NumberSymbol.Decimal] = 'Decimal'; NumberSymbol[NumberSymbol.Group] = 'Group'; NumberSymbol[NumberSymbol.List] = 'List'; NumberSymbol[NumberSymbol.PercentSign] = 'PercentSign'; NumberSymbol[NumberSymbol.PlusSign] = 'PlusSign'; NumberSymbol[NumberSymbol.MinusSign] = 'MinusSign'; NumberSymbol[NumberSymbol.Exponential] = 'Exponential'; NumberSymbol[NumberSymbol.SuperscriptingExponent] = 'SuperscriptingExponent'; NumberSymbol[NumberSymbol.PerMille] = 'PerMille'; NumberSymbol[NumberSymbol.Infinity] = 'Infinity'; NumberSymbol[NumberSymbol.NaN] = 'NaN'; NumberSymbol[NumberSymbol.TimeSeparator] = 'TimeSeparator'; NumberSymbol[NumberSymbol.CurrencyDecimal] = 'CurrencyDecimal'; NumberSymbol[NumberSymbol.CurrencyGroup] = 'CurrencyGroup'; /** @enum {number} */ const WeekDay = { Sunday: 0, Monday: 1, Tuesday: 2, Wednesday: 3, Thursday: 4, Friday: 5, Saturday: 6, }; export { WeekDay }; WeekDay[WeekDay.Sunday] = 'Sunday'; WeekDay[WeekDay.Monday] = 'Monday'; WeekDay[WeekDay.Tuesday] = 'Tuesday'; WeekDay[WeekDay.Wednesday] = 'Wednesday'; WeekDay[WeekDay.Thursday] = 'Thursday'; WeekDay[WeekDay.Friday] = 'Friday'; WeekDay[WeekDay.Saturday] = 'Saturday'; /** * Retrieves the locale ID from the currently loaded locale. * The loaded locale could be, for example, a global one rather than a regional one. * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n) * * \@publicApi * @param {?} locale A locale code, such as `fr-FR`. * @return {?} The locale code. For example, `fr`. */ export function getLocaleId(locale) { return findLocaleData(locale)[LocaleDataIndex.LocaleId]; } /** * Retrieves day period strings for the given locale. * * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n) * * \@publicApi * @param {?} locale A locale code for the locale format rules to use. * @param {?} formStyle The required grammatical form. * @param {?} width The required character width. * @return {?} An array of localized period strings. For example, `[AM, PM]` for `en-US`. */ export function getLocaleDayPeriods(locale, formStyle, width) { /** @type {?} */ const data = findLocaleData(locale); /** @type {?} */ const amPmData = (/** @type {?} */ ([data[LocaleDataIndex.DayPeriodsFormat], data[LocaleDataIndex.DayPeriodsStandalone]])); /** @type {?} */ const amPm = getLastDefinedValue(amPmData, formStyle); return getLastDefinedValue(amPm, width); } /** * Retrieves days of the week for the given locale, using the Gregorian calendar. * * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n) * * \@publicApi * @param {?} locale A locale code for the locale format rules to use. * @param {?} formStyle The required grammatical form. * @param {?} width The required character width. * @return {?} An array of localized name strings. * For example,`[Sunday, Monday, ... Saturday]` for `en-US`. */ export function getLocaleDayNames(locale, formStyle, width) { /** @type {?} */ const data = findLocaleData(locale); /** @type {?} */ const daysData = (/** @type {?} */ ([data[LocaleDataIndex.DaysFormat], data[LocaleDataIndex.DaysStandalone]])); /** @type {?} */ const days = getLastDefinedValue(daysData, formStyle); return getLastDefinedValue(days, width); } /** * Retrieves months of the year for the given locale, using the Gregorian calendar. * * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n) * * \@publicApi * @param {?} locale A locale code for the locale format rules to use. * @param {?} formStyle The required grammatical form. * @param {?} width The required character width. * @return {?} An array of localized name strings. * For example, `[January, February, ...]` for `en-US`. */ export function getLocaleMonthNames(locale, formStyle, width) { /** @type {?} */ const data = findLocaleData(locale); /** @type {?} */ const monthsData = (/** @type {?} */ ([data[LocaleDataIndex.MonthsFormat], data[LocaleDataIndex.MonthsStandalone]])); /** @type {?} */ const months = getLastDefinedValue(monthsData, formStyle); return getLastDefinedValue(months, width); } /** * Retrieves Gregorian-calendar eras for the given locale. * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n) * * \@publicApi * @param {?} locale A locale code for the locale format rules to use. * @param {?} width The required character width. * @return {?} An array of localized era strings. * For example, `[AD, BC]` for `en-US`. */ export function getLocaleEraNames(locale, width) { /** @type {?} */ const data = findLocaleData(locale); /** @type {?} */ const erasData = (/** @type {?} */ (data[LocaleDataIndex.Eras])); return getLastDefinedValue(erasData, width); } /** * Retrieves the first day of the week for the given locale. * * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n) * * \@publicApi * @param {?} locale A locale code for the locale format rules to use. * @return {?} A day index number, using the 0-based week-day index for `en-US` * (Sunday = 0, Monday = 1, ...). * For example, for `fr-FR`, returns 1 to indicate that the first day is Monday. */ export function getLocaleFirstDayOfWeek(locale) { /** @type {?} */ const data = findLocaleData(locale); return data[LocaleDataIndex.FirstDayOfWeek]; } /** * Range of week days that are considered the week-end for the given locale. * * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n) * * \@publicApi * @param {?} locale A locale code for the locale format rules to use. * @return {?} The range of day values, `[startDay, endDay]`. */ export function getLocaleWeekEndRange(locale) { /** @type {?} */ const data = findLocaleData(locale); return data[LocaleDataIndex.WeekendRange]; } /** * Retrieves a localized date-value formating string. * * @see `FormatWidth` / [Internationalization (i18n) Guide](https://angular.io/guide/i18n) * * \@publicApi * @param {?} locale A locale code for the locale format rules to use. * @param {?} width The format type. * @return {?} The localized formating string. */ export function getLocaleDateFormat(locale, width) { /** @type {?} */ const data = findLocaleData(locale); return getLastDefinedValue(data[LocaleDataIndex.DateFormat], width); } /** * Retrieves a localized time-value formatting string. * * @see `FormatWidth` / [Internationalization (i18n) Guide](https://angular.io/guide/i18n) * \@publicApi * @param {?} locale A locale code for the locale format rules to use. * @param {?} width The format type. * @return {?} The localized formatting string. */ export function getLocaleTimeFormat(locale, width) { /** @type {?} */ const data = findLocaleData(locale); return getLastDefinedValue(data[LocaleDataIndex.TimeFormat], width); } /** * Retrieves a localized date-time formatting string. * * @see `FormatWidth` / [Internationalization (i18n) Guide](https://angular.io/guide/i18n) * * \@publicApi * @param {?} locale A locale code for the locale format rules to use. * @param {?} width The format type. * @return {?} The localized formatting string. */ export function getLocaleDateTimeFormat(locale, width) { /** @type {?} */ const data = findLocaleData(locale); /** @type {?} */ const dateTimeFormatData = (/** @type {?} */ (data[LocaleDataIndex.DateTimeFormat])); return getLastDefinedValue(dateTimeFormatData, width); } /** * Retrieves a localized number symbol that can be used to replace placeholders in number formats. * @see `NumberSymbol` / [Internationalization (i18n) Guide](https://angular.io/guide/i18n) * * \@publicApi * @param {?} locale The locale code. * @param {?} symbol The symbol to localize. * @return {?} The character for the localized symbol. */ export function getLocaleNumberSymbol(locale, symbol) { /** @type {?} */ const data = findLocaleData(locale); /** @type {?} */ const res = data[LocaleDataIndex.NumberSymbols][symbol]; if (typeof res === 'undefined') { if (symbol === NumberSymbol.CurrencyDecimal) { return data[LocaleDataIndex.NumberSymbols][NumberSymbol.Decimal]; } else if (symbol === NumberSymbol.CurrencyGroup) { return data[LocaleDataIndex.NumberSymbols][NumberSymbol.Group]; } } return res; } /** * Retrieves a number format for a given locale. * * Numbers are formatted using patterns, like `#,###.00`. For example, the pattern `#,###.00` * when used to format the number 12345.678 could result in "12'345,678". That would happen if the * grouping separator for your language is an apostrophe, and the decimal separator is a comma. * * <b>Important:</b> The characters `.` `,` `0` `#` (and others below) are special placeholders * that stand for the decimal separator, and so on, and are NOT real characters. * You must NOT "translate" the placeholders. For example, don't change `.` to `,` even though in * your language the decimal point is written with a comma. The symbols should be replaced by the * local equivalents, using the appropriate `NumberSymbol` for your language. * * Here are the special characters used in number patterns: * * | Symbol | Meaning | * |--------|---------| * | . | Replaced automatically by the character used for the decimal point. | * | , | Replaced by the "grouping" (thousands) separator. | * | 0 | Replaced by a digit (or zero if there aren't enough digits). | * | # | Replaced by a digit (or nothing if there aren't enough). | * | ¤ | Replaced by a currency symbol, such as $ or USD. | * | % | Marks a percent format. The % symbol may change position, but must be retained. | * | E | Marks a scientific format. The E symbol may change position, but must be retained. | * | ' | Special characters used as literal characters are quoted with ASCII single quotes. | * * @see `NumberFormatStyle` / [CLDR website](http://cldr.unicode.org/translation/number-patterns) / [Internationalization (i18n) Guide](https://angular.io/guide/i18n) * * \@publicApi * @param {?} locale A locale code for the locale format rules to use. * @param {?} type The type of numeric value to be formatted (such as `Decimal` or `Currency`.) * @return {?} The localized format string. */ export function getLocaleNumberFormat(locale, type) { /** @type {?} */ const data = findLocaleData(locale); return data[LocaleDataIndex.NumberFormats][type]; } /** * Retrieves the symbol used to represent the currency for the main country * corresponding to a given locale. For example, '$' for `en-US`. * * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n) * * \@publicApi * @param {?} locale A locale code for the locale format rules to use. * @return {?} The localized symbol character, * or `null` if the main country cannot be determined. */ export function getLocaleCurrencySymbol(locale) { /** @type {?} */ const data = findLocaleData(locale); return data[LocaleDataIndex.CurrencySymbol] || null; } /** * Retrieves the name of the currency for the main country corresponding * to a given locale. For example, 'US Dollar' for `en-US`. * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n) * * \@publicApi * @param {?} locale A locale code for the locale format rules to use. * @return {?} The currency name, * or `null` if the main country cannot be determined. */ export function getLocaleCurrencyName(locale) { /** @type {?} */ const data = findLocaleData(locale); return data[LocaleDataIndex.CurrencyName] || null; } /** * Retrieves the currency values for a given locale. * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n) * @param {?} locale A locale code for the locale format rules to use. * @return {?} The currency values. */ function getLocaleCurrencies(locale) { /** @type {?} */ const data = findLocaleData(locale); return data[LocaleDataIndex.Currencies]; } /** * \@alias core/ɵgetLocalePluralCase * \@publicApi * @type {?} */ export const getLocalePluralCase = ɵgetLocalePluralCase; /** * @param {?} data * @return {?} */ function checkFullData(data) { if (!data[LocaleDataIndex.ExtraData]) { throw new Error(`Missing extra locale data for the locale "${data[LocaleDataIndex.LocaleId]}". Use "registerLocaleData" to load new data. See the "I18n guide" on angular.io to know more.`); } } /** * Retrieves locale-specific rules used to determine which day period to use * when more than one period is defined for a locale. * * There is a rule for each defined day period. The * first rule is applied to the first day period and so on. * Fall back to AM/PM when no rules are available. * * A rule can specify a period as time range, or as a single time value. * * This functionality is only available when you have loaded the full locale data. * See the ["I18n guide"](guide/i18n#i18n-pipes). * * @see `getLocaleExtraDayPeriods()` / [Internationalization (i18n) Guide](https://angular.io/guide/i18n) * * \@publicApi * @param {?} locale A locale code for the locale format rules to use. * @return {?} The rules for the locale, a single time value or array of *from-time, to-time*, * or null if no periods are available. * */ export function getLocaleExtraDayPeriodRules(locale) { /** @type {?} */ const data = findLocaleData(locale); checkFullData(data); /** @type {?} */ const rules = data[LocaleDataIndex.ExtraData][2 /* ExtraDayPeriodsRules */] || []; return rules.map((/** * @param {?} rule * @return {?} */ (rule) => { if (typeof rule === 'string') { return extractTime(rule); } return [extractTime(rule[0]), extractTime(rule[1])]; })); } /** * Retrieves locale-specific day periods, which indicate roughly how a day is broken up * in different languages. * For example, for `en-US`, periods are morning, noon, afternoon, evening, and midnight. * * This functionality is only available when you have loaded the full locale data. * See the ["I18n guide"](guide/i18n#i18n-pipes). * * @see `getLocaleExtraDayPeriodRules()` / [Internationalization (i18n) Guide](https://angular.io/guide/i18n) * * \@publicApi * @param {?} locale A locale code for the locale format rules to use. * @param {?} formStyle The required grammatical form. * @param {?} width The required character width. * @return {?} The translated day-period strings. */ export function getLocaleExtraDayPeriods(locale, formStyle, width) { /** @type {?} */ const data = findLocaleData(locale); checkFullData(data); /** @type {?} */ const dayPeriodsData = (/** @type {?} */ ([ data[LocaleDataIndex.ExtraData][0 /* ExtraDayPeriodFormats */], data[LocaleDataIndex.ExtraData][1 /* ExtraDayPeriodStandalone */] ])); /** @type {?} */ const dayPeriods = getLastDefinedValue(dayPeriodsData, formStyle) || []; return getLastDefinedValue(dayPeriods, width) || []; } /** * Retrieves the first value that is defined in an array, going backwards from an index position. * * To avoid repeating the same data (as when the "format" and "standalone" forms are the same) * add the first value to the locale data arrays, and add other values only if they are different. * * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n) * * \@publicApi * @template T * @param {?} data The data array to retrieve from. * @param {?} index A 0-based index into the array to start from. * @return {?} The value immediately before the given index position. */ function getLastDefinedValue(data, index) { for (let i = index; i > -1; i--) { if (typeof data[i] !== 'undefined') { return data[i]; } } throw new Error('Locale data API: locale data undefined'); } /** * Extracts the hours and minutes from a string like "15:45" * @param {?} time * @return {?} */ function extractTime(time) { const [h, m] = time.split(':'); return { hours: +h, minutes: +m }; } /** * Retrieves the currency symbol for a given currency code. * * For example, for the default `en-US` locale, the code `USD` can * be represented by the narrow symbol `$` or the wide symbol `US$`. * * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n) * * \@publicApi * @param {?} code The currency code. * @param {?} format The format, `wide` or `narrow`. * @param {?=} locale A locale code for the locale format rules to use. * * @return {?} The symbol, or the currency code if no symbol is available.0 */ export function getCurrencySymbol(code, format, locale = 'en') { /** @type {?} */ const currency = getLocaleCurrencies(locale)[code] || CURRENCIES_EN[code] || []; /** @type {?} */ const symbolNarrow = currency[1 /* SymbolNarrow */]; if (format === 'narrow' && typeof symbolNarrow === 'string') { return symbolNarrow; } return currency[0 /* Symbol */] || code; } // Most currencies have cents, that's why the default is 2 /** @type {?} */ const DEFAULT_NB_OF_CURRENCY_DIGITS = 2; /** * Reports the number of decimal digits for a given currency. * The value depends upon the presence of cents in that particular currency. * * @see [Internationalization (i18n) Guide](https://angular.io/guide/i18n) * * \@publicApi * @param {?} code The currency code. * @return {?} The number of decimal digits, typically 0 or 2. */ export function getNumberOfCurrencyDigits(code) { /** @type {?} */ let digits; /** @type {?} */ const currency = CURRENCIES_EN[code]; if (currency) { digits = currency[2 /* NbOfDigits */]; } return typeof digits === 'number' ? digits : DEFAULT_NB_OF_CURRENCY_DIGITS; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9jYWxlX2RhdGFfYXBpLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvY29tbW9uL3NyYy9pMThuL2xvY2FsZV9kYXRhX2FwaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQVFBLE9BQU8sRUFBQyxnQkFBZ0IsSUFBSSxlQUFlLEVBQUUsZUFBZSxJQUFJLGNBQWMsRUFBRSxvQkFBb0IsRUFBQyxNQUFNLGVBQWUsQ0FBQztBQUMzSCxPQUFPLEVBQUMsYUFBYSxFQUFvQixNQUFNLGNBQWMsQ0FBQzs7O0lBVzVELFVBQU87SUFDUCxVQUFPO0lBQ1AsV0FBUTtJQUNSLGFBQVU7Ozs7Ozs7OztJQWFWLE9BQVE7SUFDUixNQUFPO0lBQ1AsTUFBTztJQUNQLE1BQU87SUFDUCxPQUFRO0lBQ1IsUUFBUzs7Ozs7Ozs7Ozs7SUFhVCxTQUFNO0lBQ04sYUFBVTs7Ozs7OztJQVdWLGdEQUFnRDtJQUNoRCxTQUFNO0lBQ04sbURBQW1EO0lBQ25ELGNBQVc7SUFDWCxxREFBcUQ7SUFDckQsT0FBSTtJQUNKLGtEQUFrRDtJQUNsRCxRQUFLOzs7Ozs7Ozs7SUFlTDs7O09BR0c7SUFDSCxRQUFLO0lBQ0w7OztPQUdHO0lBQ0gsU0FBTTtJQUNOOzs7T0FHRztJQUNILE9BQUk7SUFDSjs7O09BR0c7SUFDSCxPQUFJOzs7Ozs7Ozs7SUFhSjs7OztPQUlHO0lBQ0gsVUFBTztJQUNQOzs7O09BSUc7SUFDSCxRQUFLO0lBQ0w7OztPQUdHO0lBQ0gsT0FBSTtJQUNKOzs7T0FHRztJQUNILGNBQVc7SUFDWDs7O09BR0c7SUFDSCxXQUFRO0lBQ1I7OztPQUdHO0lBQ0gsWUFBUztJQUNUOzs7T0FHRztJQUNILGNBQVc7SUFDWDs7O09BR0c7SUFDSCx5QkFBc0I7SUFDdEI7OztPQUdHO0lBQ0gsV0FBUTtJQUNSOzs7T0FHRztJQUNILFdBQVE7SUFDUjs7O09BR0c7SUFDSCxPQUFHO0lBQ0g7OztPQUdHO0lBQ0gsaUJBQWE7SUFDYjs7O09BR0c7SUFDSCxtQkFBZTtJQUNmOzs7T0FHRztJQUNILGlCQUFhOzs7Ozs7Ozs7Ozs7Ozs7Ozs7O0lBU2IsU0FBVTtJQUNWLFNBQU07SUFDTixVQUFPO0lBQ1AsWUFBUztJQUNULFdBQVE7SUFDUixTQUFNO0lBQ04sV0FBUTs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQVlWLE1BQU0sVUFBVSxXQUFXLENBQUMsTUFBYztJQUN4QyxPQUFPLGNBQWMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxlQUFlLENBQUMsUUFBUSxDQUFDLENBQUM7QUFDMUQsQ0FBQzs7Ozs7Ozs7Ozs7O0FBYUQsTUFBTSxVQUFVLG1CQUFtQixDQUMvQixNQUFjLEVBQUUsU0FBb0IsRUFBRSxLQUF1Qjs7VUFDekQsSUFBSSxHQUFHLGNBQWMsQ0FBQyxNQUFNLENBQUM7O1VBQzdCLFFBQVEsR0FBRyxtQkFFWCxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsZ0JBQWdCLENBQUMsRUFBRSxJQUFJLENBQUMsZUFBZSxDQUFDLG9CQUFvQixDQUFDLENBQUMsRUFBQTs7VUFDcEYsSUFBSSxHQUFHLG1CQUFtQixDQUFDLFFBQVEsRUFBRSxTQUFTLENBQUM7SUFDckQsT0FBTyxtQkFBbUIsQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUM7QUFDMUMsQ0FBQzs7Ozs7Ozs7Ozs7OztBQWNELE1BQU0sVUFBVSxpQkFBaUIsQ0FDN0IsTUFBYyxFQUFFLFNBQW9CLEVBQUUsS0FBdUI7O1VBQ3pELElBQUksR0FBRyxjQUFjLENBQUMsTUFBTSxDQUFDOztVQUM3QixRQUFRLEdBQ1YsbUJBQWMsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLFVBQVUsQ0FBQyxFQUFFLElBQUksQ0FBQyxlQUFlLENBQUMsY0FBYyxDQUFDLENBQUMsRUFBQTs7VUFDcEYsSUFBSSxHQUFHLG1CQUFtQixDQUFDLFFBQVEsRUFBRSxTQUFTLENBQUM7SUFDckQsT0FBTyxtQkFBbUIsQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUM7QUFDMUMsQ0FBQzs7Ozs7Ozs7Ozs7OztBQWNELE1BQU0sVUFBVSxtQkFBbUIsQ0FDL0IsTUFBYyxFQUFFLFNBQW9CLEVBQUUsS0FBdUI7O1VBQ3pELElBQUksR0FBRyxjQUFjLENBQUMsTUFBTSxDQUFDOztVQUM3QixVQUFVLEdBQ1osbUJBQWMsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLFlBQVksQ0FBQyxFQUFFLElBQUksQ0FBQyxlQUFlLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxFQUFBOztVQUN4RixNQUFNLEdBQUcsbUJBQW1CLENBQUMsVUFBVSxFQUFFLFNBQVMsQ0FBQztJQUN6RCxPQUFPLG1CQUFtQixDQUFDLE1BQU0sRUFBRSxLQUFLLENBQUMsQ0FBQztBQUM1QyxDQUFDOzs7Ozs7Ozs7OztBQWNELE1BQU0sVUFBVSxpQkFBaUIsQ0FBQyxNQUFjLEVBQUUsS0FBdUI7O1VBQ2pFLElBQUksR0FBRyxjQUFjLENBQUMsTUFBTSxDQUFDOztVQUM3QixRQUFRLEdBQUcsbUJBQW9CLElBQUksQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLEVBQUE7SUFDL0QsT0FBTyxtQkFBbUIsQ0FBQyxRQUFRLEVBQUUsS0FBSyxDQUFDLENBQUM7QUFDOUMsQ0FBQzs7Ozs7Ozs7Ozs7O0FBYUQsTUFBTSxVQUFVLHVCQUF1QixDQUFDLE1BQWM7O1VBQzlDLElBQUksR0FBRyxjQUFjLENBQUMsTUFBTSxDQUFDO0lBQ25DLE9BQU8sSUFBSSxDQUFDLGVBQWUsQ0FBQyxjQUFjLENBQUMsQ0FBQztBQUM5QyxDQUFDOzs7Ozs7Ozs7O0FBV0QsTUFBTSxVQUFVLHFCQUFxQixDQUFDLE1BQWM7O1VBQzVDLElBQUksR0FBRyxjQUFjLENBQUMsTUFBTSxDQUFDO0lBQ25DLE9BQU8sSUFBSSxDQUFDLGVBQWUsQ0FBQyxZQUFZLENBQUMsQ0FBQztBQUM1QyxDQUFDOzs7Ozs7Ozs7OztBQWFELE1BQU0sVUFBVSxtQkFBbUIsQ0FBQyxNQUFjLEVBQUUsS0FBa0I7O1VBQzlELElBQUksR0FBRyxjQUFjLENBQUMsTUFBTSxDQUFDO0lBQ25DLE9BQU8sbUJBQW1CLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxVQUFVLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQztBQUN0RSxDQUFDOzs7Ozs7Ozs7O0FBYUQsTUFBTSxVQUFVLG1CQUFtQixDQUFDLE1BQWMsRUFBRSxLQUFrQjs7VUFDOUQsSUFBSSxHQUFHLGNBQWMsQ0FBQyxNQUFNLENBQUM7SUFDbkMsT0FBTyxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLFVBQVUsQ0FBQyxFQUFFLEtBQUssQ0FBQyxDQUFDO0FBQ3RFLENBQUM7Ozs7Ozs7Ozs7O0FBYUQsTUFBTSxVQUFVLHVCQUF1QixDQUFDLE1BQWMsRUFBRSxLQUFrQjs7VUFDbEUsSUFBSSxHQUFHLGNBQWMsQ0FBQyxNQUFNLENBQUM7O1VBQzdCLGtCQUFrQixHQUFHLG1CQUFVLElBQUksQ0FBQyxlQUFlLENBQUMsY0FBYyxDQUFDLEVBQUE7SUFDekUsT0FBTyxtQkFBbUIsQ0FBQyxrQkFBa0IsRUFBRSxLQUFLLENBQUMsQ0FBQztBQUN4RCxDQUFDOzs7Ozs7Ozs7O0FBWUQsTUFBTSxVQUFVLHFCQUFxQixDQUFDLE1BQWMsRUFBRSxNQUFvQjs7VUFDbEUsSUFBSSxHQUFHLGNBQWMsQ0FBQyxNQUFNLENBQUM7O1VBQzdCLEdBQUcsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLGFBQWEsQ0FBQyxDQUFDLE1BQU0sQ0FBQztJQUN2RCxJQUFJLE9BQU8sR0FBRyxLQUFLLFdBQVcsRUFBRTtRQUM5QixJQUFJLE1BQU0sS0FBSyxZQUFZLENBQUMsZUFBZSxFQUFFO1lBQzNDLE9BQU8sSUFBSSxDQUFDLGVBQWUsQ0FBQyxhQUFhLENBQUMsQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLENBQUM7U0FDbEU7YUFBTSxJQUFJLE1BQU0sS0FBSyxZQUFZLENBQUMsYUFBYSxFQUFFO1lBQ2hELE9BQU8sSUFBSSxDQUFDLGVBQWUsQ0FBQyxhQUFhLENBQUMsQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLENBQUM7U0FDaEU7S0FDRjtJQUNELE9BQU8sR0FBRyxDQUFDO0FBQ2IsQ0FBQzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQXFDRCxNQUFNLFVBQVUscUJBQXFCLENBQUMsTUFBYyxFQUFFLElBQXVCOztVQUNyRSxJQUFJLEdBQUcsY0FBYyxDQUFDLE1BQU0sQ0FBQztJQUNuQyxPQUFPLElBQUksQ0FBQyxlQUFlLENBQUMsYUFBYSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7QUFDbkQsQ0FBQzs7Ozs7Ozs7Ozs7O0FBYUQsTUFBTSxVQUFVLHVCQUF1QixDQUFDLE1BQWM7O1VBQzlDLElBQUksR0FBRyxjQUFjLENBQUMsTUFBTSxDQUFDO0lBQ25DLE9BQU8sSUFBSSxDQUFDLGVBQWUsQ0FBQyxjQUFjLENBQUMsSUFBSSxJQUFJLENBQUM7QUFDdEQsQ0FBQzs7Ozs7Ozs7Ozs7QUFZRCxNQUFNLFVBQVUscUJBQXFCLENBQUMsTUFBYzs7VUFDNUMsSUFBSSxHQUFHLGNBQWMsQ0FBQyxNQUFNLENBQUM7SUFDbkMsT0FBTyxJQUFJLENBQUMsZUFBZSxDQUFDLFlBQVksQ0FBQyxJQUFJLElBQUksQ0FBQztBQUNwRCxDQUFDOzs7Ozs7O0FBUUQsU0FBUyxtQkFBbUIsQ0FBQyxNQUFjOztVQUNuQyxJQUFJLEdBQUcsY0FBYyxDQUFDLE1BQU0sQ0FBQztJQUNuQyxPQUFPLElBQUksQ0FBQyxlQUFlLENBQUMsVUFBVSxDQUFDLENBQUM7QUFDMUMsQ0FBQzs7Ozs7O0FBTUQsTUFBTSxPQUFPLG1CQUFtQixHQUM1QixvQkFBb0I7Ozs7O0FBRXhCLFNBQVMsYUFBYSxDQUFDLElBQVM7SUFDOUIsSUFBSSxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsU0FBUyxDQUFDLEVBQUU7UUFDcEMsTUFBTSxJQUFJLEtBQUssQ0FDWCw2Q0FBNkMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxRQUFRLENBQUMsZ0dBQWdHLENBQUMsQ0FBQztLQUNsTDtBQUNILENBQUM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUF3QkQsTUFBTSxVQUFVLDRCQUE0QixDQUFDLE1BQWM7O1VBQ25ELElBQUksR0FBRyxjQUFjLENBQUMsTUFBTSxDQUFDO0lBQ25DLGFBQWEsQ0FBQyxJQUFJLENBQUMsQ0FBQzs7VUFDZCxLQUFLLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxTQUFTLENBQUMsOEJBQTJDLElBQUksRUFBRTtJQUM5RixPQUFPLEtBQUssQ0FBQyxHQUFHOzs7O0lBQUMsQ0FBQyxJQUErQixFQUFFLEVBQUU7UUFDbkQsSUFBSSxPQUFPLElBQUksS0FBSyxRQUFRLEVBQUU7WUFDNUIsT0FBTyxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUM7U0FDMUI7UUFDRCxPQUFPLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLFdBQVcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3RELENBQUMsRUFBQyxDQUFDO0FBQ0wsQ0FBQzs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFtQkQsTUFBTSxVQUFVLHdCQUF3QixDQUNwQyxNQUFjLEVBQUUsU0FBb0IsRUFBRSxLQUF1Qjs7VUFDekQsSUFBSSxHQUFHLGNBQWMsQ0FBQyxNQUFNLENBQUM7SUFDbkMsYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDOztVQUNkLGNBQWMsR0FBRyxtQkFBYztRQUNuQyxJQUFJLENBQUMsZUFBZSxDQUFDLFNBQVMsQ0FBQywrQkFBNEM7UUFDM0UsSUFBSSxDQUFDLGVBQWUsQ0FBQyxTQUFTLENBQUMsa0NBQStDO0tBQy9FLEVBQUE7O1VBQ0ssVUFBVSxHQUFHLG1CQUFtQixDQUFDLGNBQWMsRUFBRSxTQUFTLENBQUMsSUFBSSxFQUFFO0lBQ3ZFLE9BQU8sbUJBQW1CLENBQUMsVUFBVSxFQUFFLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztBQUN0RCxDQUFDOzs7Ozs7Ozs7Ozs7Ozs7QUFlRCxTQUFTLG1CQUFtQixDQUFJLElBQVMsRUFBRSxLQUFhO0lBQ3RELEtBQUssSUFBSSxDQUFDLEdBQUcsS0FBSyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRTtRQUMvQixJQUFJLE9BQU8sSUFBSSxDQUFDLENBQUMsQ0FBQyxLQUFLLFdBQVcsRUFBRTtZQUNsQyxPQUFPLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztTQUNoQjtLQUNGO0lBQ0QsTUFBTSxJQUFJLEtBQUssQ0FBQyx3Q0FBd0MsQ0FBQyxDQUFDO0FBQzVELENBQUM7Ozs7OztBQWVELFNBQVMsV0FBVyxDQUFDLElBQVk7VUFDekIsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUM7SUFDOUIsT0FBTyxFQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDLEVBQUMsQ0FBQztBQUNsQyxDQUFDOzs7Ozs7Ozs7Ozs7Ozs7O0FBbUJELE1BQU0sVUFBVSxpQkFBaUIsQ0FBQyxJQUFZLEVBQUUsTUFBeUIsRUFBRSxNQUFNLEdBQUcsSUFBSTs7VUFDaEYsUUFBUSxHQUFHLG1CQUFtQixDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLGFBQWEsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFOztVQUN6RSxZQUFZLEdBQUcsUUFBUSxzQkFBNEI7SUFFekQsSUFBSSxNQUFNLEtBQUssUUFBUSxJQUFJLE9BQU8sWUFBWSxLQUFLLFFBQVEsRUFBRTtRQUMzRCxPQUFPLFlBQVksQ0FBQztLQUNyQjtJQUVELE9BQU8sUUFBUSxnQkFBc0IsSUFBSSxJQUFJLENBQUM7QUFDaEQsQ0FBQzs7O01BR0ssNkJBQTZCLEdBQUcsQ0FBQzs7Ozs7Ozs7Ozs7QUFZdkMsTUFBTSxVQUFVLHlCQUF5QixDQUFDLElBQVk7O1FBQ2hELE1BQU07O1VBQ0osUUFBUSxHQUFHLGFBQWEsQ0FBQyxJQUFJLENBQUM7SUFDcEMsSUFBSSxRQUFRLEVBQUU7UUFDWixNQUFNLEdBQUcsUUFBUSxvQkFBMEIsQ0FBQztLQUM3QztJQUNELE9BQU8sT0FBTyxNQUFNLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLDZCQUE2QixDQUFDO0FBQzdFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgR29vZ2xlIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5cbmltcG9ydCB7ybVMb2NhbGVEYXRhSW5kZXggYXMgTG9jYWxlRGF0YUluZGV4LCDJtWZpbmRMb2NhbGVEYXRhIGFzIGZpbmRMb2NhbGVEYXRhLCDJtWdldExvY2FsZVBsdXJhbENhc2V9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtDVVJSRU5DSUVTX0VOLCBDdXJyZW5jaWVzU3ltYm9sc30gZnJvbSAnLi9jdXJyZW5jaWVzJztcbmltcG9ydCB7Q3VycmVuY3lJbmRleCwgRXh0cmFMb2NhbGVEYXRhSW5kZXh9IGZyb20gJy4vbG9jYWxlX2RhdGEnO1xuXG4vKipcbiAqIEZvcm1hdCBzdHlsZXMgdGhhdCBjYW4gYmUgdXNlZCB0byByZXByZXNlbnQgbnVtYmVycy5cbiAqIEBzZWUgYGdldExvY2FsZU51bWJlckZvcm1hdCgpYC5cbiAqIEBzZWUgW0ludGVybmF0aW9uYWxpemF0aW9uIChpMThuKSBHdWlkZV0oaHR0cHM6Ly9hbmd1bGFyLmlvL2d1aWRlL2kxOG4pXG4gKlxuICogQHB1YmxpY0FwaVxuICovXG5leHBvcnQgZW51bSBOdW1iZXJGb3JtYXRTdHlsZSB7XG4gIERlY2ltYWwsXG4gIFBlcmNlbnQsXG4gIEN1cnJlbmN5LFxuICBTY2llbnRpZmljXG59XG5cbi8qKlxuICogUGx1cmFsaXR5IGNhc2VzIHVzZWQgZm9yIHRyYW5zbGF0aW5nIHBsdXJhbHMgdG8gZGlmZmVyZW50IGxhbmd1YWdlcy5cbiAqXG4gKiBAc2VlIGBOZ1BsdXJhbGBcbiAqIEBzZWUgYE5nUGx1cmFsQ2FzZWBcbiAqIEBzZWUgW0ludGVybmF0aW9uYWxpemF0aW9uIChpMThuKSBHdWlkZV0oaHR0cHM6Ly9hbmd1bGFyLmlvL2d1aWRlL2kxOG4pXG4gKlxuICogQHB1YmxpY0FwaVxuICovXG5leHBvcnQgZW51bSBQbHVyYWwge1xuICBaZXJvID0gMCxcbiAgT25lID0gMSxcbiAgVHdvID0gMixcbiAgRmV3ID0gMyxcbiAgTWFueSA9IDQsXG4gIE90aGVyID0gNSxcbn1cblxuLyoqXG4gKiBDb250ZXh0LWRlcGVuZGFudCB0cmFuc2xhdGlvbiBmb3JtcyBmb3Igc3RyaW5ncy5cbiAqIFR5cGljYWxseSB0aGUgc3RhbmRhbG9uZSB2ZXJzaW9uIGlzIGZvciB0aGUgbm9taW5hdGl2ZSBmb3JtIG9mIHRoZSB3b3JkLFxuICogYW5kIHRoZSBmb3JtYXQgdmVyc2lvbiBpcyB1c2VkIGZvciB0aGUgZ2VuaXRpdmUgY2FzZS5cbiAqIEBzZWUgW0NMRFIgd2Vic2l0ZV0oaHR0cDovL2NsZHIudW5pY29kZS5vcmcvdHJhbnNsYXRpb24vZGF0ZS10aW1lI1RPQy1TdGFuZC1BbG9uZS12cy4tRm9ybWF0LVN0eWxlcylcbiAqIEBzZWUgW0ludGVybmF0aW9uYWxpemF0aW9uIChpMThuKSBHdWlkZV0oaHR0cHM6Ly9hbmd1bGFyLmlvL2d1aWRlL2kxOG4pXG4gKlxuICogQHB1YmxpY0FwaVxuICovXG5leHBvcnQgZW51bSBGb3JtU3R5bGUge1xuICBGb3JtYXQsXG4gIFN0YW5kYWxvbmVcbn1cblxuLyoqXG4gKiBTdHJpbmcgd2lkdGhzIGF2YWlsYWJsZSBmb3IgdHJhbnNsYXRpb25zLlxuICogVGhlIHNwZWNpZmljIGNoYXJhY3RlciB3aWR0aHMgYXJlIGxvY2FsZS1zcGVjaWZpYy5cbiAqIEV4YW1wbGVzIGFyZSBnaXZlbiBmb3IgdGhlIHdvcmQgXCJTdW5kYXlcIiBpbiBFbmdsaXNoLlxuICpcbiAqIEBwdWJsaWNBcGlcbiAqL1xuZXhwb3J0IGVudW0gVHJhbnNsYXRpb25XaWR0aCB7XG4gIC8qKiAxIGNoYXJhY3RlciBmb3IgYGVuLVVTYC4gRm9yIGV4YW1wbGU6ICdTJyAqL1xuICBOYXJyb3csXG4gIC8qKiAzIGNoYXJhY3RlcnMgZm9yIGBlbi1VU2AuIEZvciBleGFtcGxlOiAnU3VuJyAqL1xuICBBYmJyZXZpYXRlZCxcbiAgLyoqIEZ1bGwgbGVuZ3RoIGZvciBgZW4tVVNgLiBGb3IgZXhhbXBsZTogXCJTdW5kYXlcIiAqL1xuICBXaWRlLFxuICAvKiogMiBjaGFyYWN0ZXJzIGZvciBgZW4tVVNgLCBGb3IgZXhhbXBsZTogXCJTdVwiICovXG4gIFNob3J0XG59XG5cbi8qKlxuICogU3RyaW5nIHdpZHRocyBhdmFpbGFibGUgZm9yIGRhdGUtdGltZSBmb3JtYXRzLlxuICogVGhlIHNwZWNpZmljIGNoYXJhY3RlciB3aWR0aHMgYXJlIGxvY2FsZS1zcGVjaWZpYy5cbiAqIEV4YW1wbGVzIGFyZSBnaXZlbiBmb3IgYGVuLVVTYC5cbiAqXG4gKiBAc2VlIGBnZXRMb2NhbGVEYXRlRm9ybWF0KClgXG4gKiBAc2VlIGBnZXRMb2NhbGVUaW1lRm9ybWF0KClgYFxuICogQHNlZSBgZ2V0TG9jYWxlRGF0ZVRpbWVGb3JtYXQoKWBcbiAqIEBzZWUgW0ludGVybmF0aW9uYWxpemF0aW9uIChpMThuKSBHdWlkZV0oaHR0cHM6Ly9hbmd1bGFyLmlvL2d1aWRlL2kxOG4pXG4gKiBAcHVibGljQXBpXG4gKi9cbmV4cG9ydCBlbnVtIEZvcm1hdFdpZHRoIHtcbiAgLyoqXG4gICAqIEZvciBgZW4tVVNgLCAnTS9kL3l5LCBoOm1tIGEnYFxuICAgKiAoRXhhbXBsZTogYDYvMTUvMTUsIDk6MDMgQU1gKVxuICAgKi9cbiAgU2hvcnQsXG4gIC8qKlxuICAgKiBGb3IgYGVuLVVTYCwgYCdNTU0gZCwgeSwgaDptbTpzcyBhJ2BcbiAgICogKEV4YW1wbGU6IGBKdW4gMTUsIDIwMTUsIDk6MDM6MDEgQU1gKVxuICAgKi9cbiAgTWVkaXVtLFxuICAvKipcbiAgICogRm9yIGBlbi1VU2AsIGAnTU1NTSBkLCB5LCBoOm1tOnNzIGEgeidgXG4gICAqIChFeGFtcGxlOiBgSnVuZSAxNSwgMjAxNSBhdCA5OjAzOjAxIEFNIEdNVCsxYClcbiAgICovXG4gIExvbmcsXG4gIC8qKlxuICAgKiBGb3IgYGVuLVVTYCwgYCdFRUVFLCBNTU1NIGQsIHksIGg6bW06c3MgYSB6enp6J2BcbiAgICogKEV4YW1wbGU6IGBNb25kYXksIEp1bmUgMTUsIDIwMTUgYXQgOTowMzowMSBBTSBHTVQrMDE6MDBgKVxuICAgKi9cbiAgRnVsbFxufVxuXG4vKipcbiAqIFN5bWJvbHMgdGhhdCBjYW4gYmUgdXNlZCB0byByZXBsYWNlIHBsYWNlaG9sZGVycyBpbiBudW1iZXIgcGF0dGVybnMuXG4gKiBFeGFtcGxlcyBhcmUgYmFzZWQgb24gYGVuLVVTYCB2YWx1ZXMuXG4gKlxuICogQHNlZSBgZ2V0TG9jYWxlTnVtYmVyU3ltYm9sKClgXG4gKiBAc2VlIFtJbnRlcm5hdGlvbmFsaXphdGlvbiAoaTE4bikgR3VpZGVdKGh0dHBzOi8vYW5ndWxhci5pby9ndWlkZS9pMThuKVxuICpcbiAqIEBwdWJsaWNBcGlcbiAqL1xuZXhwb3J0IGVudW0gTnVtYmVyU3ltYm9sIHtcbiAgLyoqXG4gICAqIERlY2ltYWwgc2VwYXJhdG9yLlxuICAgKiBGb3IgYGVuLVVTYCwgdGhlIGRvdCBjaGFyYWN0ZXIuXG4gICAqIEV4YW1wbGUgOiAyLDM0NWAuYDY3XG4gICAqL1xuICBEZWNpbWFsLFxuICAvKipcbiAgICogR3JvdXBpbmcgc2VwYXJhdG9yLCB0eXBpY2FsbHkgZm9yIHRob3VzYW5kcy5cbiAgICogRm9yIGBlbi1VU2AsIHRoZSBjb21tYSBjaGFyYWN0ZXIuXG4gICAqIEV4YW1wbGU6IDJgLGAzNDUuNjdcbiAgICovXG4gIEdyb3VwLFxuICAvKipcbiAgICogTGlzdC1pdGVtIHNlcGFyYXRvci5cbiAgICogRXhhbXBsZTogXCJvbmUsIHR3bywgYW5kIHRocmVlXCJcbiAgICovXG4gIExpc3QsXG4gIC8qKlxuICAgKiBTaWduIGZvciBwZXJjZW50YWdlIChvdXQgb2YgMTAwKS5cbiAgICogRXhhbXBsZTogMjMuNCVcbiAgICovXG4gIFBlcmNlbnRTaWduLFxuICAvKipcbiAgICogU2lnbiBmb3IgcG9zaXRpdmUgbnVtYmVycy5cbiAgICogRXhhbXBsZTogKzIzXG4gICAqL1xuICBQbHVzU2lnbixcbiAgLyoqXG4gICAqIFNpZ24gZm9yIG5lZ2F0aXZlIG51bWJlcnMuXG4gICAqIEV4YW1wbGU6IC0yM1xuICAgKi9cbiAgTWludXNTaWduLFxuICAvKipcbiAgICogQ29tcHV0ZXIgbm90YXRpb24gZm9yIGV4cG9uZW50aWFsIHZhbHVlIChuIHRpbWVzIGEgcG93ZXIgb2YgMTApLlxuICAgKiBFeGFtcGxlOiAxLjJFM1xuICAgKi9cbiAgRXhwb25lbnRpYWwsXG4gIC8qKlxuICAgKiBIdW1hbi1yZWFkYWJsZSBmb3JtYXQgb2YgZXhwb25lbnRpYWwuXG4gICAqIEV4YW1wbGU6IDEuMngxMDNcbiAgICovXG4gIFN1cGVyc2NyaXB0aW5nRXhwb25lbnQsXG4gIC8qKlxuICAgKiBTaWduIGZvciBwZXJtaWxsZSAob3V0IG9mIDEwMDApLlxuICAgKiBFeGFtcGxlOiAyMy404oCwXG4gICAqL1xuICBQZXJNaWxsZSxcbiAgLyoqXG4gICAqIEluZmluaXR5LCBjYW4gYmUgdXNlZCB3aXRoIHBsdXMgYW5kIG1pbnVzLlxuICAgKiBFeGFtcGxlOiDiiJ4sICviiJ4sIC3iiJ5cbiAgICovXG4gIEluZmluaXR5LFxuICAvKipcbiAgICogTm90IGEgbnVtYmVyLlxuICAgKiBFeGFtcGxlOiBOYU5cbiAgICovXG4gIE5hTixcbiAgLyoqXG4gICAqIFN5bWJvbCB1c2VkIGJldHdlZW4gdGltZSB1bml0cy5cbiAgICogRXhhbXBsZTogMTA6NTJcbiAgICovXG4gIFRpbWVTZXBhcmF0b3IsXG4gIC8qKlxuICAgKiBEZWNpbWFsIHNlcGFyYXRvciBmb3IgY3VycmVuY3kgdmFsdWVzIChmYWxsYmFjayB0byBgRGVjaW1hbGApLlxuICAgKiBFeGFtcGxlOiAkMiwzNDUuNjdcbiAgICovXG4gIEN1cnJlbmN5RGVjaW1hbCxcbiAgLyoqXG4gICAqIEdyb3VwIHNlcGFyYXRvciBmb3IgY3VycmVuY3kgdmFsdWVzIChmYWxsYmFjayB0byBgR3JvdXBgKS5cbiAgICogRXhhbXBsZTogJDIsMzQ1LjY3XG4gICAqL1xuICBDdXJyZW5jeUdyb3VwXG59XG5cbi8qKlxuICogVGhlIHZhbHVlIGZvciBlYWNoIGRheSBvZiB0aGUgd2VlaywgYmFzZWQgb24gdGhlIGBlbi1VU2AgbG9jYWxlXG4gKlxuICogQHB1YmxpY0FwaVxuICovXG5leHBvcnQgZW51bSBXZWVrRGF5IHtcbiAgU3VuZGF5ID0gMCxcbiAgTW9uZGF5LFxuICBUdWVzZGF5LFxuICBXZWRuZXNkYXksXG4gIFRodXJzZGF5LFxuICBGcmlkYXksXG4gIFNhdHVyZGF5XG59XG5cbi8qKlxuICogUmV0cmlldmVzIHRoZSBsb2NhbGUgSUQgZnJvbSB0aGUgY3VycmVudGx5IGxvYWRlZCBsb2NhbGUuXG4gKiBUaGUgbG9hZGVkIGxvY2FsZSBjb3VsZCBiZSwgZm9yIGV4YW1wbGUsIGEgZ2xvYmFsIG9uZSByYXRoZXIgdGhhbiBhIHJlZ2lvbmFsIG9uZS5cbiAqIEBwYXJhbSBsb2NhbGUgQSBsb2NhbGUgY29kZSwgc3VjaCBhcyBgZnItRlJgLlxuICogQHJldHVybnMgVGhlIGxvY2FsZSBjb2RlLiBGb3IgZXhhbXBsZSwgYGZyYC5cbiAqIEBzZWUgW0ludGVybmF0aW9uYWxpemF0aW9uIChpMThuKSBHdWlkZV0oaHR0cHM6Ly9hbmd1bGFyLmlvL2d1aWRlL2kxOG4pXG4gKlxuICogQHB1YmxpY0FwaVxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0TG9jYWxlSWQobG9jYWxlOiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gZmluZExvY2FsZURhdGEobG9jYWxlKVtMb2NhbGVEYXRhSW5kZXguTG9jYWxlSWRdO1xufVxuXG4vKipcbiAqIFJldHJpZXZlcyBkYXkgcGVyaW9kIHN0cmluZ3MgZm9yIHRoZSBnaXZlbiBsb2NhbGUuXG4gKlxuICogQHBhcmFtIGxvY2FsZSBBIGxvY2FsZSBjb2RlIGZvciB0aGUgbG9jYWxlIGZvcm1hdCBydWxlcyB0byB1c2UuXG4gKiBAcGFyYW0gZm9ybVN0eWxlIFRoZSByZXF1aXJlZCBncmFtbWF0aWNhbCBmb3JtLlxuICogQHBhcmFtIHdpZHRoIFRoZSByZXF1aXJlZCBjaGFyYWN0ZXIgd2lkdGguXG4gKiBAcmV0dXJucyBBbiBhcnJheSBvZiBsb2NhbGl6ZWQgcGVyaW9kIHN0cmluZ3MuIEZvciBleGFtcGxlLCBgW0FNLCBQTV1gIGZvciBgZW4tVVNgLlxuICogQHNlZSBbSW50ZXJuYXRpb25hbGl6YXRpb24gKGkxOG4pIEd1aWRlXShodHRwczovL2FuZ3VsYXIuaW8vZ3VpZGUvaTE4bilcbiAqXG4gKiBAcHVibGljQXBpXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRMb2NhbGVEYXlQZXJpb2RzKFxuICAgIGxvY2FsZTogc3RyaW5nLCBmb3JtU3R5bGU6IEZvcm1TdHlsZSwgd2lkdGg6IFRyYW5zbGF0aW9uV2lkdGgpOiBbc3RyaW5nLCBzdHJpbmddIHtcbiAgY29uc3QgZGF0YSA9IGZpbmRMb2NhbGVEYXRhKGxvY2FsZSk7XG4gIGNvbnN0IGFtUG1EYXRhID0gPFtcbiAgICBzdHJpbmcsIHN0cmluZ1xuICBdW11bXT5bZGF0YVtMb2NhbGVEYXRhSW5kZXguRGF5UGVyaW9kc0Zvcm1hdF0sIGRhdGFbTG9jYWxlRGF0YUluZGV4LkRheVBlcmlvZHNTdGFuZGFsb25lXV07XG4gIGNvbnN0IGFtUG0gPSBnZXRMYXN0RGVmaW5lZFZhbHVlKGFtUG1EYXRhLCBmb3JtU3R5bGUpO1xuICByZXR1cm4gZ2V0TGFzdERlZmluZWRWYWx1ZShhbVBtLCB3aWR0aCk7XG59XG5cbi8qKlxuICogUmV0cmlldmVzIGRheXMgb2YgdGhlIHdlZWsgZm9yIHRoZSBnaXZlbiBsb2NhbGUsIHVzaW5nIHRoZSBHcmVnb3JpYW4gY2FsZW5kYXIuXG4gKlxuICogQHBhcmFtIGxvY2FsZSBBIGxvY2FsZSBjb2RlIGZvciB0aGUgbG9jYWxlIGZvcm1hdCBydWxlcyB0byB1c2UuXG4gKiBAcGFyYW0gZm9ybVN0eWxlIFRoZSByZXF1aXJlZCBncmFtbWF0aWNhbCBmb3JtLlxuICogQHBhcmFtIHdpZHRoIFRoZSByZXF1aXJlZCBjaGFyYWN0ZXIgd2lkdGguXG4gKiBAcmV0dXJucyBBbiBhcnJheSBvZiBsb2NhbGl6ZWQgbmFtZSBzdHJpbmdzLlxuICogRm9yIGV4YW1wbGUsYFtTdW5kYXksIE1vbmRheSwgLi4uIFNhdHVyZGF5XWAgZm9yIGBlbi1VU2AuXG4gKiBAc2VlIFtJbnRlcm5hdGlvbmFsaXphdGlvbiAoaTE4bikgR3VpZGVdKGh0dHBzOi8vYW5ndWxhci5pby9ndWlkZS9pMThuKVxuICpcbiAqIEBwdWJsaWNBcGlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldExvY2FsZURheU5hbWVzKFxuICAgIGxvY2FsZTogc3RyaW5nLCBmb3JtU3R5bGU6IEZvcm1TdHlsZSwgd2lkdGg6IFRyYW5zbGF0aW9uV2lkdGgpOiBzdHJpbmdbXSB7XG4gIGNvbnN0IGRhdGEgPSBmaW5kTG9jYWxlRGF0YShsb2NhbGUpO1xuICBjb25zdCBkYXlzRGF0YSA9XG4gICAgICA8c3RyaW5nW11bXVtdPltkYXRhW0xvY2FsZURhdGFJbmRleC5EYXlzRm9ybWF0XSwgZGF0YVtMb2NhbGVEYXRhSW5kZXguRGF5c1N0YW5kYWxvbmVdXTtcbiAgY29uc3QgZGF5cyA9IGdldExhc3REZWZpbmVkVmFsdWUoZGF5c0RhdGEsIGZvcm1TdHlsZSk7XG4gIHJldHVybiBnZXRMYXN0RGVmaW5lZFZhbHVlKGRheXMsIHdpZHRoKTtcbn1cblxuLyoqXG4gKiBSZXRyaWV2ZXMgbW9udGhzIG9mIHRoZSB5ZWFyIGZvciB0aGUgZ2l2ZW4gbG9jYWxlLCB1c2luZyB0aGUgR3JlZ29yaWFuIGNhbGVuZGFyLlxuICpcbiAqIEBwYXJhbSBsb2NhbGUgQSBsb2NhbGUgY29kZSBmb3IgdGhlIGxvY2FsZSBmb3JtYXQgcnVsZXMgdG8gdXNlLlxuICogQHBhcmFtIGZvcm1TdHlsZSBUaGUgcmVxdWlyZWQgZ3JhbW1hdGljYWwgZm9ybS5cbiAqIEBwYXJhbSB3aWR0aCBUaGUgcmVxdWlyZWQgY2hhcmFjdGVyIHdpZHRoLlxuICogQHJldHVybnMgQW4gYXJyYXkgb2YgbG9jYWxpemVkIG5hbWUgc3RyaW5ncy5cbiAqIEZvciBleGFtcGxlLCAgYFtKYW51YXJ5LCBGZWJydWFyeSwgLi4uXWAgZm9yIGBlbi1VU2AuXG4gKiBAc2VlIFtJbnRlcm5hdGlvbmFsaXphdGlvbiAoaTE4bikgR3VpZGVdKGh0dHBzOi8vYW5ndWxhci5pby9ndWlkZS9pMThuKVxuICpcbiAqIEBwdWJsaWNBcGlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldExvY2FsZU1vbnRoTmFtZXMoXG4gICAgbG9jYWxlOiBzdHJpbmcsIGZvcm1TdHlsZTogRm9ybVN0eWxlLCB3aWR0aDogVHJhbnNsYXRpb25XaWR0aCk6IHN0cmluZ1tdIHtcbiAgY29uc3QgZGF0YSA9IGZpbmRMb2NhbGVEYXRhKGxvY2FsZSk7XG4gIGNvbnN0IG1vbnRoc0RhdGEgPVxuICAgICAgPHN0cmluZ1tdW11bXT5bZGF0YVtMb2NhbGVEYXRhSW5kZXguTW9udGhzRm9ybWF0XSwgZGF0YVtMb2NhbGVEYXRhSW5kZXguTW9udGhzU3RhbmRhbG9uZV1dO1xuICBjb25zdCBtb250aHMgPSBnZXRMYXN0RGVmaW5lZFZhbHVlKG1vbnRoc0RhdGEsIGZvcm1TdHlsZSk7XG4gIHJldHVybiBnZXRMYXN0RGVmaW5lZFZhbHVlKG1vbnRocywgd2lkdGgpO1xufVxuXG4vKipcbiAqIFJldHJpZXZlcyBHcmVnb3JpYW4tY2FsZW5kYXIgZXJhcyBmb3IgdGhlIGdpdmVuIGxvY2FsZS5cbiAqIEBwYXJhbSBsb2NhbGUgQSBsb2NhbGUgY29kZSBmb3IgdGhlIGxvY2FsZSBmb3JtYXQgcnVsZXMgdG8gdXNlLlxuICogQHBhcmFtIGZvcm1TdHlsZSBUaGUgcmVxdWlyZWQgZ3JhbW1hdGljYWwgZm9ybS5cbiAqIEBwYXJhbSB3aWR0aCBUaGUgcmVxdWlyZWQgY2hhcmFjdGVyIHdpZHRoLlxuXG4gKiBAcmV0dXJucyBBbiBhcnJheSBvZiBsb2NhbGl6ZWQgZXJhIHN0cmluZ3MuXG4gKiBGb3IgZXhhbXBsZSwgYFtBRCwgQkNdYCBmb3IgYGVuLVVTYC5cbiAqIEBzZWUgW0ludGVybmF0aW9uYWxpemF0aW9uIChpMThuKSBHdWlkZV0oaHR0cHM6Ly9hbmd1bGFyLmlvL2d1aWRlL2kxOG4pXG4gKlxuICogQHB1YmxpY0FwaVxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0TG9jYWxlRXJhTmFtZXMobG9jYWxlOiBzdHJpbmcsIHdpZHRoOiBUcmFuc2xhdGlvbldpZHRoKTogW3N0cmluZywgc3RyaW5nXSB7XG4gIGNvbnN0IGRhdGEgPSBmaW5kTG9jYWxlRGF0YShsb2NhbGUpO1xuICBjb25zdCBlcmFzRGF0YSA9IDxbc3RyaW5nLCBzdHJpbmddW10+ZGF0YVtMb2NhbGVEYXRhSW5kZXguRXJhc107XG4gIHJldHVybiBnZXRMYXN0RGVmaW5lZFZhbHVlKGVyYXNEYXRhLCB3aWR0aCk7XG59XG5cbi8qKlxuICogUmV0cmlldmVzIHRoZSBmaXJzdCBkYXkgb2YgdGhlIHdlZWsgZm9yIHRoZSBnaXZlbiBsb2NhbGUuXG4gKlxuICogQHBhcmFtIGxvY2FsZSBBIGxvY2FsZSBjb2RlIGZvciB0aGUgbG9jYWxlIGZvcm1hdCBydWxlcyB0byB1c2UuXG4gKiBAcmV0dXJucyBBIGRheSBpbmRleCBudW1iZXIsIHVzaW5nIHRoZSAwLWJhc2VkIHdlZWstZGF5IGluZGV4IGZvciBgZW4tVVNgXG4gKiAoU3VuZGF5ID0gMCwgTW9uZGF5ID0gMSwgLi4uKS5cbiAqIEZvciBleGFtcGxlLCBmb3IgYGZyLUZSYCwgcmV0dXJucyAxIHRvIGluZGljYXRlIHRoYXQgdGhlIGZpcnN0IGRheSBpcyBNb25kYXkuXG4gKiBAc2VlIFtJbnRlcm5hdGlvbmFsaXphdGlvbiAoaTE4bikgR3VpZGVdKGh0dHBzOi8vYW5ndWxhci5pby9ndWlkZS9pMThuKVxuICpcbiAqIEBwdWJsaWNBcGlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldExvY2FsZUZpcnN0RGF5T2ZXZWVrKGxvY2FsZTogc3RyaW5nKTogV2Vla0RheSB7XG4gIGNvbnN0IGRhdGEgPSBmaW5kTG9jYWxlRGF0YShsb2NhbGUpO1xuICByZXR1cm4gZGF0YVtMb2NhbGVEYXRhSW5kZXguRmlyc3REYXlPZldlZWtdO1xufVxuXG4vKipcbiAqIFJhbmdlIG9mIHdlZWsgZGF5cyB0aGF0IGFyZSBjb25zaWRlcmVkIHRoZSB3ZWVrLWVuZCBmb3IgdGhlIGdpdmVuIGxvY2FsZS5cbiAqXG4gKiBAcGFyYW0gbG9jYWxlIEEgbG9jYWxlIGNvZGUgZm9yIHRoZSBsb2NhbGUgZm9ybWF0IHJ1bGVzIHRvIHVzZS5cbiAqIEByZXR1cm5zIFRoZSByYW5nZSBvZiBkYXkgdmFsdWVzLCBgW3N0YXJ0RGF5LCBlbmREYXldYC5cbiAqIEBzZWUgW0ludGVybmF0aW9uYWxpemF0aW9uIChpMThuKSBHdWlkZV0oaHR0cHM6Ly9hbmd1bGFyLmlvL2d1aWRlL2kxOG4pXG4gKlxuICogQHB1YmxpY0FwaVxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0TG9jYWxlV2Vla0VuZFJhbmdlKGxvY2FsZTogc3RyaW5nKTogW1dlZWtEYXksIFdlZWtEYXldIHtcbiAgY29uc3QgZGF0YSA9IGZpbmRMb2NhbGVEYXRhKGxvY2FsZSk7XG4gIHJldHVybiBkYXRhW0xvY2FsZURhdGFJbmRleC5XZWVrZW5kUmFuZ2VdO1xufVxuXG4vKipcbiAqIFJldHJpZXZlcyBhIGxvY2FsaXplZCBkYXRlLXZhbHVlIGZvcm1hdGluZyBzdHJpbmcuXG4gKlxuICogQHBhcmFtIGxvY2FsZSBBIGxvY2FsZSBjb2RlIGZvciB0aGUgbG9jYWxlIGZvcm1hdCBydWxlcyB0byB1c2UuXG4gKiBAcGFyYW0gd2lkdGggVGhlIGZvcm1hdCB0eXBlLlxuICogQHJldHVybnMgVGhlIGxvY2FsaXplZCBmb3JtYXRpbmcgc3RyaW5nLlxuICogQHNlZSBgRm9ybWF0V2lkdGhgXG4gKiBAc2VlIFtJbnRlcm5hdGlvbmFsaXphdGlvbiAoaTE4bikgR3VpZGVdKGh0dHBzOi8vYW5ndWxhci5pby9ndWlkZS9pMThuKVxuICpcbiAqIEBwdWJsaWNBcGlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldExvY2FsZURhdGVGb3JtYXQobG9jYWxlOiBzdHJpbmcsIHdpZHRoOiBGb3JtYXRXaWR0aCk6IHN0cmluZyB7XG4gIGNvbnN0IGRhdGEgPSBmaW5kTG9jYWxlRGF0YShsb2NhbGUpO1xuICByZXR1cm4gZ2V0TGFzdERlZmluZWRWYWx1ZShkYXRhW0xvY2FsZURhdGFJbmRleC5EYXRlRm9ybWF0XSwgd2lkdGgpO1xufVxuXG4vKipcbiAqIFJldHJpZXZlcyBhIGxvY2FsaXplZCB0aW1lLXZhbHVlIGZvcm1hdHRpbmcgc3RyaW5nLlxuICpcbiAqIEBwYXJhbSBsb2NhbGUgQSBsb2NhbGUgY29kZSBmb3IgdGhlIGxvY2FsZSBmb3JtYXQgcnVsZXMgdG8gdXNlLlxuICogQHBhcmFtIHdpZHRoIFRoZSBmb3JtYXQgdHlwZS5cbiAqIEByZXR1cm5zIFRoZSBsb2NhbGl6ZWQgZm9ybWF0dGluZyBzdHJpbmcuXG4gKiBAc2VlIGBGb3JtYXRXaWR0aGBcbiAqIEBzZWUgW0ludGVybmF0aW9uYWxpemF0aW9uIChpMThuKSBHdWlkZV0oaHR0cHM6Ly9hbmd1bGFyLmlvL2d1aWRlL2kxOG4pXG5cbiAqIEBwdWJsaWNBcGlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldExvY2FsZVRpbWVGb3JtYXQobG9jYWxlOiBzdHJpbmcsIHdpZHRoOiBGb3JtYXRXaWR0aCk6IHN0cmluZyB7XG4gIGNvbnN0IGRhdGEgPSBmaW5kTG9jYWxlRGF0YShsb2NhbGUpO1xuICByZXR1cm4gZ2V0TGFzdERlZmluZWRWYWx1ZShkYXRhW0xvY2FsZURhdGFJbmRleC5UaW1lRm9ybWF0XSwgd2lkdGgpO1xufVxuXG4vKipcbiAqIFJldHJpZXZlcyBhIGxvY2FsaXplZCBkYXRlLXRpbWUgZm9ybWF0dGluZyBzdHJpbmcuXG4gKlxuICogQHBhcmFtIGxvY2FsZSBBIGxvY2FsZSBjb2RlIGZvciB0aGUgbG9jYWxlIGZvcm1hdCBydWxlcyB0byB1c2UuXG4gKiBAcGFyYW0gd2lkdGggVGhlIGZvcm1hdCB0eXBlLlxuICogQHJldHVybnMgVGhlIGxvY2FsaXplZCBmb3JtYXR0aW5nIHN0cmluZy5cbiAqIEBzZWUgYEZvcm1hdFdpZHRoYFxuICogQHNlZSBbSW50ZXJuYXRpb25hbGl6YXRpb24gKGkxOG4pIEd1aWRlXShodHRwczovL2FuZ3VsYXIuaW8vZ3VpZGUvaTE4bilcbiAqXG4gKiBAcHVibGljQXBpXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRMb2NhbGVEYXRlVGltZUZvcm1hdChsb2NhbGU6IHN0cmluZywgd2lkdGg6IEZvcm1hdFdpZHRoKTogc3RyaW5nIHtcbiAgY29uc3QgZGF0YSA9IGZpbmRMb2NhbGVEYXRhKGxvY2FsZSk7XG4gIGNvbnN0IGRhdGVUaW1lRm9ybWF0RGF0YSA9IDxzdHJpbmdbXT5kYXRhW0xvY2FsZURhdGFJbmRleC5EYXRlVGltZUZvcm1hdF07XG4gIHJldHVybiBnZXRMYXN0RGVmaW5lZFZhbHVlKGRhdGVUaW1lRm9ybWF0RGF0YSwgd2lkdGgpO1xufVxuXG4vKipcbiAqIFJldHJpZXZlcyBhIGxvY2FsaXplZCBudW1iZXIgc3ltYm9sIHRoYXQgY2FuIGJlIHVzZWQgdG8gcmVwbGFjZSBwbGFjZWhvbGRlcnMgaW4gbnVtYmVyIGZvcm1hdHMuXG4gKiBAcGFyYW0gbG9jYWxlIFRoZSBsb2NhbGUgY29kZS5cbiAqIEBwYXJhbSBzeW1ib2wgVGhlIHN5bWJvbCB0byBsb2NhbGl6ZS5cbiAqIEByZXR1cm5zIFRoZSBjaGFyYWN0ZXIgZm9yIHRoZSBsb2NhbGl6ZWQgc3ltYm9sLlxuICogQHNlZSBgTnVtYmVyU3ltYm9sYFxuICogQHNlZSBbSW50ZXJuYXRpb25hbGl6YXRpb24gKGkxOG4pIEd1aWRlXShodHRwczovL2FuZ3VsYXIuaW8vZ3VpZGUvaTE4bilcbiAqXG4gKiBAcHVibGljQXBpXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRMb2NhbGVOdW1iZXJTeW1ib2wobG9jYWxlOiBzdHJpbmcsIHN5bWJvbDogTnVtYmVyU3ltYm9sKTogc3RyaW5nIHtcbiAgY29uc3QgZGF0YSA9IGZpbmRMb2NhbGVEYXRhKGxvY2FsZSk7XG4gIGNvbnN0IHJlcyA9IGRhdGFbTG9jYWxlRGF0YUluZGV4Lk51bWJlclN5bWJvbHNdW3N5bWJvbF07XG4gIGlmICh0eXBlb2YgcmVzID09PSAndW5kZWZpbmVkJykge1xuICAgIGlmIChzeW1ib2wgPT09IE51bWJlclN5bWJvbC5DdXJyZW5jeURlY2ltYWwpIHtcbiAgICAgIHJldHVybiBkYXRhW0xvY2FsZURhdGFJbmRleC5OdW1iZXJTeW1ib2xzXVtOdW1iZXJTeW1ib2wuRGVjaW1hbF07XG4gICAgfSBlbHNlIGlmIChzeW1ib2wgPT09IE51bWJlclN5bWJvbC5DdXJyZW5jeUdyb3VwKSB7XG4gICAgICByZXR1cm4gZGF0YVtMb2NhbGVEYXRhSW5kZXguTnVtYmVyU3ltYm9sc11bTnVtYmVyU3ltYm9sLkdyb3VwXTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHJlcztcbn1cblxuLyoqXG4gKiBSZXRyaWV2ZXMgYSBudW1iZXIgZm9ybWF0IGZvciBhIGdpdmVuIGxvY2FsZS5cbiAqXG4gKiBOdW1iZXJzIGFyZSBmb3JtYXR0ZWQgdXNpbmcgcGF0dGVybnMsIGxpa2UgYCMsIyMjLjAwYC4gRm9yIGV4YW1wbGUsIHRoZSBwYXR0ZXJuIGAjLCMjIy4wMGBcbiAqIHdoZW4gdXNlZCB0byBmb3JtYXQgdGhlIG51bWJlciAxMjM0NS42NzggY291bGQgcmVzdWx0IGluIFwiMTInMzQ1LDY3OFwiLiBUaGF0IHdvdWxkIGhhcHBlbiBpZiB0aGVcbiAqIGdyb3VwaW5nIHNlcGFyYXRvciBmb3IgeW91ciBsYW5ndWFnZSBpcyBhbiBhcG9zdHJvcGhlLCBhbmQgdGhlIGRlY2ltYWwgc2VwYXJhdG9yIGlzIGEgY29tbWEuXG4gKlxuICogPGI+SW1wb3J0YW50OjwvYj4gVGhlIGNoYXJhY3RlcnMgYC5gIGAsYCBgMGAgYCNgIChhbmQgb3RoZXJzIGJlbG93KSBhcmUgc3BlY2lhbCBwbGFjZWhvbGRlcnNcbiAqIHRoYXQgc3RhbmQgZm9yIHRoZSBkZWNpbWFsIHNlcGFyYXRvciwgYW5kIHNvIG9uLCBhbmQgYXJlIE5PVCByZWFsIGNoYXJhY3RlcnMuXG4gKiBZb3UgbXVzdCBOT1QgXCJ0cmFuc2xhdGVcIiB0aGUgcGxhY2Vob2xkZXJzLiBGb3IgZXhhbXBsZSwgZG9uJ3QgY2hhbmdlIGAuYCB0byBgLGAgZXZlbiB0aG91Z2ggaW5cbiAqIHlvdXIgbGFuZ3VhZ2UgdGhlIGRlY2ltYWwgcG9pbnQgaXMgd3JpdHRlbiB3aXRoIGEgY29tbWEuIFRoZSBzeW1ib2xzIHNob3VsZCBiZSByZXBsYWNlZCBieSB0aGVcbiAqIGxvY2FsIGVxdWl2YWxlbnRzLCB1c2luZyB0aGUgYXBwcm9wcmlhdGUgYE51bWJlclN5bWJvbGAgZm9yIHlvdXIgbGFuZ3VhZ2UuXG4gKlxuICogSGVyZSBhcmUgdGhlIHNwZWNpYWwgY2hhcmFjdGVycyB1c2VkIGluIG51bWJlciBwYXR0ZXJuczpcbiAqXG4gKiB8IFN5bWJvbCB8IE1lYW5pbmcgfFxuICogfC0tLS0tLS0tfC0tLS0tLS0tLXxcbiAqIHwgLiB8IFJlcGxhY2VkIGF1dG9tYXRpY2FsbHkgYnkgdGhlIGNoYXJhY3RlciB1c2VkIGZvciB0aGUgZGVjaW1hbCBwb2ludC4gfFxuICogfCAsIHwgUmVwbGFjZWQgYnkgdGhlIFwiZ3JvdXBpbmdcIiAodGhvdXNhbmRzKSBzZXBhcmF0b3IuIHxcbiAqIHwgMCB8IFJlcGxhY2VkIGJ5IGEgZGlnaXQgKG9yIHplcm8gaWYgdGhlcmUgYXJlbid0IGVub3VnaCBkaWdpdHMpLiB8XG4gKiB8ICMgfCBSZXBsYWNlZCBieSBhIGRpZ2l0IChvciBub3RoaW5nIGlmIHRoZXJlIGFyZW4ndCBlbm91Z2gpLiB8XG4gKiB8IMKkIHwgUmVwbGFjZWQgYnkgYSBjdXJyZW5jeSBzeW1ib2wsIHN1Y2ggYXMgJCBvciBVU0QuIHxcbiAqIHwgJSB8IE1hcmtzIGEgcGVyY2VudCBmb3JtYXQuIFRoZSAlIHN5bWJvbCBtYXkgY2hhbmdlIHBvc2l0aW9uLCBidXQgbXVzdCBiZSByZXRhaW5lZC4gfFxuICogfCBFIHwgTWFya3MgYSBzY2llbnRpZmljIGZvcm1hdC4gVGhlIEUgc3ltYm9sIG1heSBjaGFuZ2UgcG9zaXRpb24sIGJ1dCBtdXN0IGJlIHJldGFpbmVkLiB8XG4gKiB8ICcgfCBTcGVjaWFsIGNoYXJhY3RlcnMgdXNlZCBhcyBsaXRlcmFsIGNoYXJhY3RlcnMgYXJlIHF1b3RlZCB3aXRoIEFTQ0lJIHNpbmdsZSBxdW90ZXMuIHxcbiAqXG4gKiBAcGFyYW0gbG9jYWxlIEEgbG9jYWxlIGNvZGUgZm9yIHRoZSBsb2NhbGUgZm9ybWF0IHJ1bGVzIHRvIHVzZS5cbiAqIEBwYXJhbSB0eXBlIFRoZSB0eXBlIG9mIG51bWVyaWMgdmFsdWUgdG8gYmUgZm9ybWF0dGVkIChzdWNoIGFzIGBEZWNpbWFsYCBvciBgQ3VycmVuY3lgLilcbiAqIEByZXR1cm5zIFRoZSBsb2NhbGl6ZWQgZm9ybWF0IHN0cmluZy5cbiAqIEBzZWUgYE51bWJlckZvcm1hdFN0eWxlYFxuICogQHNlZSBbQ0xEUiB3ZWJzaXRlXShodHRwOi8vY2xkci51bmljb2RlLm9yZy90cmFuc2xhdGlvbi9udW1iZXItcGF0dGVybnMpXG4gKiBAc2VlIFtJbnRlcm5hdGlvbmFsaXphdGlvbiAoaTE4bikgR3VpZGVdKGh0dHBzOi8vYW5ndWxhci5pby9ndWlkZS9pMThuKVxuICpcbiAqIEBwdWJsaWNBcGlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldExvY2FsZU51bWJlckZvcm1hdChsb2NhbGU6IHN0cmluZywgdHlwZTogTnVtYmVyRm9ybWF0U3R5bGUpOiBzdHJpbmcge1xuICBjb25zdCBkYXRhID0gZmluZExvY2FsZURhdGEobG9jYWxlKTtcbiAgcmV0dXJuIGRhdGFbTG9jYWxlRGF0YUluZGV4Lk51bWJlckZvcm1hdHNdW3R5cGVdO1xufVxuXG4vKipcbiAqIFJldHJpZXZlcyB0aGUgc3ltYm9sIHVzZWQgdG8gcmVwcmVzZW50IHRoZSBjdXJyZW5jeSBmb3IgdGhlIG1haW4gY291bnRyeVxuICogY29ycmVzcG9uZGluZyB0byBhIGdpdmVuIGxvY2Fs