UNPKG

@taiga-ui/cdk

Version:

Base library for creating Angular components and applications using Taiga UI principles regarding of actual visual appearance

292 lines • 38.3 kB
/// <reference types="@taiga-ui/tsconfig/ng-dev-mode" /> import { tuiInRange, tuiNormalizeToIntNumber } from '@taiga-ui/cdk/utils/math'; import { DATE_FILLER_LENGTH } from './date-fillers'; import { MIN_DAY, MONTHS_IN_YEAR } from './date-time'; import { TuiDayOfWeek } from './day-of-week'; import { TuiMonth } from './month'; import { TuiMonthNumber } from './month-number'; import { TuiYear } from './year'; /** * Immutable date object, consisting of day, month and year */ export class TuiDay extends TuiMonth { /** * @param year * @param month (starting with 0) * @param day */ constructor(year, month, day) { super(year, month); this.day = day; ngDevMode && console.assert(TuiDay.isValidDay(year, month, day)); } /** * Creates {@link TuiDay} from native {@link Date} based on local time zone */ static fromLocalNativeDate(date) { return new TuiDay(date.getFullYear(), date.getMonth(), date.getDate()); } /** * Creates {@link TuiDay} from native {@link Date} using UTC */ static fromUtcNativeDate(date) { return new TuiDay(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()); } /** * Check validity of year, month and day * * @param year * @param month * @param day * @return boolean validity */ static isValidDay(year, month, day) { return (TuiMonth.isValidMonth(year, month) && Number.isInteger(day) && tuiInRange(day, MIN_DAY, TuiMonth.getMonthDaysCount(month, TuiYear.isLeapYear(year)) + 1)); } /** * Current day based on local time zone */ static currentLocal() { const nativeDate = new Date(); const year = nativeDate.getFullYear(); const month = nativeDate.getMonth(); const day = nativeDate.getDate(); return new TuiDay(year, month, day); } /** * Returns current day based on UTC */ static currentUtc() { const nativeDate = new Date(); const year = nativeDate.getUTCFullYear(); const month = nativeDate.getUTCMonth(); const day = nativeDate.getUTCDate(); return new TuiDay(year, month, day); } /** * Calculates {@link TuiDay} normalizing year, month and day. {@link NaN} is turned into minimal value. * * @param year any year value, including invalid * @param month any month value, including invalid (months start with 0) * @param day any day value, including invalid * @return normalized date */ static normalizeOf(year, month, day) { const normalizedYear = TuiYear.normalizeYearPart(year); const normalizedMonth = TuiMonth.normalizeMonthPart(month); const normalizedDay = TuiDay.normalizeDayPart(day, normalizedMonth, normalizedYear); return new TuiDay(normalizedYear, normalizedMonth, normalizedDay); } static lengthBetween(from, to) { return Math.round((to.toLocalNativeDate().getTime() - from.toLocalNativeDate().getTime()) / (1000 * 60 * 60 * 24)); } static parseRawDateString(date, dateMode = 'DMY') { ngDevMode && console.assert(date.length === DATE_FILLER_LENGTH, '[parseRawDateString]: wrong date string length'); switch (dateMode) { case 'MDY': return { day: parseInt(date.slice(3, 5), 10), month: parseInt(date.slice(0, 2), 10) - 1, year: parseInt(date.slice(6, 10), 10), }; case 'YMD': return { day: parseInt(date.slice(8, 10), 10), month: parseInt(date.slice(5, 7), 10) - 1, year: parseInt(date.slice(0, 4), 10), }; case 'DMY': default: return { day: parseInt(date.slice(0, 2), 10), month: parseInt(date.slice(3, 5), 10) - 1, year: parseInt(date.slice(6, 10), 10), }; } } // TODO: Move month and year related code corresponding classes /** * Parsing a string with date with normalization * * @param rawDate date string * @param dateMode date format of the date string (DMY | MDY | YMD) * @return normalized date */ static normalizeParse(rawDate, dateMode = 'DMY') { const { day, month, year } = this.parseRawDateString(rawDate, dateMode); return TuiDay.normalizeOf(year, month, day); } /** * Parsing a date stringified in a toJSON format * @param yearMonthDayString date string in format of YYYY-MM-DD * @return date * @throws exceptions if any part of the date is invalid */ static jsonParse(yearMonthDayString) { const { day, month, year } = this.parseRawDateString(yearMonthDayString, 'YMD'); if (!TuiMonth.isValidMonth(year, month) || !Number.isInteger(day) || !tuiInRange(day, MIN_DAY, TuiMonth.getMonthDaysCount(month, TuiYear.isLeapYear(year)) + 1)) { throw new TuiInvalidDayException(year, month, day); } return new TuiDay(year, month, day); } static normalizeDayPart(day, month, year) { ngDevMode && console.assert(TuiMonth.isValidMonth(year, month)); const monthDaysCount = TuiMonth.getMonthDaysCount(month, TuiYear.isLeapYear(year)); return tuiNormalizeToIntNumber(day, 1, monthDaysCount); } get formattedDayPart() { return String(this.day).padStart(2, '0'); } get isWeekend() { const dayOfWeek = this.dayOfWeek(false); return dayOfWeek === TuiDayOfWeek.Saturday || dayOfWeek === TuiDayOfWeek.Sunday; } /** * Returns day of week * * @param startFromMonday whether week starts from Monday and not from Sunday * @return day of week (from 0 to 6) */ dayOfWeek(startFromMonday = true) { const dayOfWeek = startFromMonday ? this.toLocalNativeDate().getDay() - 1 : this.toLocalNativeDate().getDay(); return dayOfWeek < 0 ? 6 : dayOfWeek; } /** * Passed date is after current */ dayBefore(another) { return (this.monthBefore(another) || (this.monthSame(another) && this.day < another.day)); } /** * Passed date is after or equals to current */ daySameOrBefore(another) { return (this.monthBefore(another) || (this.monthSame(another) && this.day <= another.day)); } /** * Passed date is the same as current */ daySame(another) { return this.monthSame(another) && this.day === another.day; } /** * Passed date is either before or the same as current */ daySameOrAfter(another) { return (this.monthAfter(another) || (this.monthSame(another) && this.day >= another.day)); } /** * Passed date is before current */ dayAfter(another) { return (this.monthAfter(another) || (this.monthSame(another) && this.day > another.day)); } /** * Clamping date between two limits * * @param min * @param max * @return clamped date */ dayLimit(min, max) { if (min !== null && this.dayBefore(min)) { return min; } if (max !== null && this.dayAfter(max)) { return max; } return this; } /** * Immutably alters current day by passed offset * * If resulting month has more days than original one, date is rounded to the maximum day * in the resulting month. Offset of days will be calculated based on the resulted year and month * to not interfere with parent classes methods * * @param offset * @return new date object as a result of offsetting current */ append({ year = 0, month = 0, day = 0 }) { const totalMonths = (this.year + year) * MONTHS_IN_YEAR + this.month + month; let years = Math.floor(totalMonths / MONTHS_IN_YEAR); let months = totalMonths % MONTHS_IN_YEAR; let days = Math.min(this.day, TuiMonth.getMonthDaysCount(months, TuiYear.isLeapYear(years))) + day; while (days > TuiMonth.getMonthDaysCount(months, TuiYear.isLeapYear(years))) { days -= TuiMonth.getMonthDaysCount(months, TuiYear.isLeapYear(years)); if (months === TuiMonthNumber.December) { years++; months = TuiMonthNumber.January; } else { months++; } } while (days < MIN_DAY) { if (months === TuiMonthNumber.January) { years--; months = TuiMonthNumber.December; } else { months--; } days += TuiMonth.getMonthDaysCount(months, TuiYear.isLeapYear(years)); } return new TuiDay(years, months, days); } /** * Returns formatted whole date */ getFormattedDay(dateFormat, separator) { ngDevMode && console.assert(separator.length === 1, 'Separator should consist of only 1 symbol'); const dd = this.formattedDayPart; const mm = this.formattedMonthPart; const yyyy = this.formattedYear; switch (dateFormat) { case 'MDY': return `${mm}${separator}${dd}${separator}${yyyy}`; case 'YMD': return `${yyyy}${separator}${mm}${separator}${dd}`; case 'DMY': default: return `${dd}${separator}${mm}${separator}${yyyy}`; } } toString(dateFormat = 'DMY', separator = '.') { return this.getFormattedDay(dateFormat, separator); } toJSON() { return `${super.toJSON()}-${this.formattedDayPart}`; } /** * Returns native {@link Date} based on local time zone */ toLocalNativeDate() { return new Date(this.year, this.month, this.day); } /** * Returns native {@link Date} based on UTC */ toUtcNativeDate() { return new Date(Date.UTC(this.year, this.month, this.day)); } } export class TuiInvalidDayException extends Error { constructor(year, month, day) { super(ngDevMode ? `Invalid day: ${year}-${month}-${day}` : ''); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvY2RrL2RhdGUtdGltZS9kYXkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsd0RBQXdEO0FBRXhELE9BQU8sRUFBQyxVQUFVLEVBQUUsdUJBQXVCLEVBQUMsTUFBTSwwQkFBMEIsQ0FBQztBQUU3RSxPQUFPLEVBQUMsa0JBQWtCLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQztBQUNsRCxPQUFPLEVBQUMsT0FBTyxFQUFFLGNBQWMsRUFBQyxNQUFNLGFBQWEsQ0FBQztBQUNwRCxPQUFPLEVBQUMsWUFBWSxFQUFDLE1BQU0sZUFBZSxDQUFDO0FBQzNDLE9BQU8sRUFBQyxRQUFRLEVBQUMsTUFBTSxTQUFTLENBQUM7QUFDakMsT0FBTyxFQUFDLGNBQWMsRUFBQyxNQUFNLGdCQUFnQixDQUFDO0FBRTlDLE9BQU8sRUFBQyxPQUFPLEVBQUMsTUFBTSxRQUFRLENBQUM7QUFFL0I7O0dBRUc7QUFDSCxNQUFNLE9BQU8sTUFBTyxTQUFRLFFBQVE7SUFDaEM7Ozs7T0FJRztJQUNILFlBQ0ksSUFBWSxFQUNaLEtBQWEsRUFDRyxHQUFXO1FBRTNCLEtBQUssQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFGSCxRQUFHLEdBQUgsR0FBRyxDQUFRO1FBRzNCLFNBQVMsSUFBSSxPQUFPLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQ3JFLENBQUM7SUFFRDs7T0FFRztJQUNJLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxJQUFVO1FBQ3hDLE9BQU8sSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxFQUFFLElBQUksQ0FBQyxRQUFRLEVBQUUsRUFBRSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztJQUMzRSxDQUFDO0lBRUQ7O09BRUc7SUFDSSxNQUFNLENB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Q0FBQztJQUN4RCxDQUFDO0lBRUQ7O09BRUc7SUFDYSxpQkFBaUI7UUFDN0IsT0FBTyxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3JELENBQUM7SUFFRDs7T0FFRztJQUNhLGVBQWU7UUFDM0IsT0FBTyxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUMvRCxDQUFDO0NBQ0o7QUFFRCxNQUFNLE9BQU8sc0JBQXVCLFNBQVEsS0FBSztJQUM3QyxZQUFZLElBQVksRUFBRSxLQUFhLEVBQUUsR0FBVztRQUNoRCxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxnQkFBZ0IsSUFBSSxJQUFJLEtBQUssSUFBSSxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDbkUsQ0FBQztDQUNKIiwic291cmNlc0NvbnRlbnQiOlsiLy8vIDxyZWZlcmVuY2UgdHlwZXM9XCJAdGFpZ2EtdWkvdHNjb25maWcvbmctZGV2LW1vZGVcIiAvPlxuXG5pbXBvcnQge3R1aUluUmFuZ2UsIHR1aU5vcm1hbGl6ZVRvSW50TnVtYmVyfSBmcm9tICdAdGFpZ2EtdWkvY2RrL3V0aWxzL21hdGgnO1xuXG5pbXBvcnQge0RBVEVfRklMTEVSX0xFTkdUSH0gZnJvbSAnLi9kYXRlLWZpbGxlcnMnO1xuaW1wb3J0IHtNSU5fREFZLCBNT05USFNfSU5fWUVBUn0gZnJvbSAnLi9kYXRlLXRpbWUnO1xuaW1wb3J0IHtUdWlEYXlPZldlZWt9IGZyb20gJy4vZGF5LW9mLXdlZWsnO1xuaW1wb3J0IHtUdWlNb250aH0gZnJvbSAnLi9tb250aCc7XG5pbXBvcnQge1R1aU1vbnRoTnVtYmVyfSBmcm9tICcuL21vbnRoLW51bWJlcic7XG5pbXBvcnQgdHlwZSB7VHVpRGF0ZU1vZGUsIFR1aURheUxpa2V9IGZyb20gJy4vdHlwZXMnO1xuaW1wb3J0IHtUdWlZZWFyfSBmcm9tICcuL3llYXInO1xuXG4vKipcbiAqIEltbXV0YWJsZSBkYXRlIG9iamVjdCwgY29uc2lzdGluZyBvZiBkYXksIG1vbnRoIGFuZCB5ZWFyXG4gKi9cbmV4cG9ydCBjbGFzcyBUdWlEYXkgZXh0ZW5kcyBUdWlNb250aCB7XG4gICAgLyoqXG4gICAgICogQHBhcmFtIHllYXJcbiAgICAgKiBAcGFyYW0gbW9udGggKHN0YXJ0aW5nIHdpdGggMClcbiAgICAgKiBAcGFyYW0gZGF5XG4gICAgICovXG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIHllYXI6IG51bWJlcixcbiAgICAgICAgbW9udGg6IG51bWJlcixcbiAgICAgICAgcHVibGljIHJlYWRvbmx5IGRheTogbnVtYmVyLFxuICAgICkge1xuICAgICAgICBzdXBlcih5ZWFyLCBtb250aCk7XG4gICAgICAgIG5nRGV2TW9kZSAmJiBjb25zb2xlLmFzc2VydChUdWlEYXkuaXNWYWxpZERheSh5ZWFyLCBtb250aCwgZGF5KSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyB7QGxpbmsgVHVpRGF5fSBmcm9tIG5hdGl2ZSB7QGxpbmsgRGF0ZX0gYmFzZWQgb24gbG9jYWwgdGltZSB6b25lXG4gICAgICovXG4gICAgcHVibGljIHN0YXRpYyBmcm9tTG9jYWxOYXRpdmVEYXRlKGRhdGU6IERhdGUpOiBUdWlEYXkge1xuICAgICAgICByZXR1cm4gbmV3IFR1aURheShkYXRlLmdldEZ1bGxZZWFyKCksIGRhdGUuZ2V0TW9udGgoKSwgZGF0ZS5nZXREYXRlKCkpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMge0BsaW5rIFR1aURheX0gZnJvbSBuYXRpdmUge0BsaW5rIERhdGV9IHVzaW5nIFVUQ1xuICAgICAqL1xuICAgIHB1YmxpYyBzdGF0aWMgZnJvbVV0Y05hdGl2ZURhdGUoZGF0ZTogRGF0ZSk6IFR1aURheSB7XG4gICAgICAgIHJldHVybiBuZXcgVHVpRGF5KGRhdGUuZ2V0VVRDRnVsbFllYXIoKSwgZGF0ZS5nZXRVVENNb250aCgpLCBkYXRlLmdldFVUQ0RhdGUoKSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2hlY2sgdmFsaWRpdHkgb2YgeWVhciwgbW9udGggYW5kIGRheVxuICAgICAqXG4gICAgICogQHBhcmFtIHllYXJcbiAgICAgKiBAcGFyYW0gbW9udGhcbiAgICAgKiBAcGFyYW0gZGF5XG4gICAgICogQHJldHVybiBib29sZWFuIHZhbGlkaXR5XG4gICAgICovXG4gICAgcHVibGljIHN0YXRpYyBpc1ZhbGlkRGF5KHllYXI6IG51bWJlciwgbW9udGg6IG51bWJlciwgZGF5OiBudW1iZXIpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgIFR1aU1vbnRoLmlzVmFsaWRNb250aCh5ZWFyLCBtb250aCkgJiZcbiAgICAgICAgICAgIE51bWJlci5pc0ludGVnZXIoZGF5KSAmJlxuICAgICAgICAgICAgdHVpSW5SYW5nZShcbiAgICAgICAgICAgICAgICBkYXksXG4gICAgICAgICAgICAgICAgTUlOX0RBWSxcbiAgICAgICAgICAgICAgICBUdWlNb250aC5nZXRNb250aERheXNDb3VudChtb250aCwgVHVpWWVhci5pc0xlYXBZZWFyKHllYXIpKSArIDEsXG4gICAgICAgICAgICApXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3VycmVudCBkYXkgYmFzZWQgb24gbG9jYWwgdGltZSB6b25lXG4gICAgICovXG4gICAgcHVibGljIHN0YXRpYyBvdmVycmlkZSBjdXJyZW50TG9jYWwoKTogVHVpRGF5IHtcbiAgICAgICAgY29uc3QgbmF0aXZlRGF0ZSA9IG5ldyBEYXRlKCk7XG4gICAgICAgIGNvbnN0IHllYXIgPSBuYXRpdmVEYXRlLmdldEZ1bGxZZWFyKCk7XG4gICAgICAgIGNvbnN0IG1vbnRoID0gbmF0aXZlRGF0ZS5nZXRNb250aCgpO1xuICAgICAgICBjb25zdCBkYXkgPSBuYXRpdmVEYXRlLmdldERhdGUoKTtcblxuICAgICAgICByZXR1cm4gbmV3IFR1aURheSh5ZWFyLCBtb250aCwgZGF5KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIGN1cnJlbnQgZGF5IGJhc2VkIG9uIFVUQ1xuICAgICAqL1xuICAgIHB1YmxpYyBzdGF0aWMgb3ZlcnJpZGUgY3VycmVudFV0YygpOiBUdWlEYXkge1xuICAgICAgICBjb25zdCBuYXRpdmVEYXRlID0gbmV3IERhdGUoKTtcbiAgICAgICAgY29uc3QgeWVhciA9IG5hdGl2ZURhdGUuZ2V0VVRDRnVsbFllYXIoKTtcbiAgICAgICAgY29uc3QgbW9udGggPSBuYXRpdmVEYXRlLmdldFVUQ01vbnRoKCk7XG4gICAgICAgIGNvbnN0IGRheSA9IG5hdGl2ZURhdGUuZ2V0VVRDRGF0ZSgpO1xuXG4gICAgICAgIHJldHVybiBuZXcgVHVpRGF5KHllYXIsIG1vbnRoLCBkYXkpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENhbGN1bGF0ZXMge0BsaW5rIFR1aURheX0gbm9ybWFsaXppbmcgeWVhciwgbW9udGggYW5kIGRheS4ge0BsaW5rIE5hTn0gaXMgdHVybmVkIGludG8gbWluaW1hbCB2YWx1ZS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB5ZWFyIGFueSB5ZWFyIHZhbHVlLCBpbmNsdWRpbmcgaW52YWxpZFxuICAgICAqIEBwYXJhbSBtb250aCBhbnkgbW9udGggdmFsdWUsIGluY2x1ZGluZyBpbnZhbGlkIChtb250aHMgc3RhcnQgd2l0aCAwKVxuICAgICAqIEBwYXJhbSBkYXkgYW55IGRheSB2YWx1ZSwgaW5jbHVkaW5nIGludmFsaWRcbiAgICAgKiBAcmV0dXJuIG5vcm1hbGl6ZWQgZGF0ZVxuICAgICAqL1xuICAgIHB1YmxpYyBzdGF0aWMgbm9ybWFsaXplT2YoeWVhcjogbnVtYmVyLCBtb250aDogbnVtYmVyLCBkYXk6IG51bWJlcik6IFR1aURheSB7XG4gICAgICAgIGNvbnN0IG5vcm1hbGl6ZWRZZWFyID0gVHVpWWVhci5ub3JtYWxpemVZZWFyUGFydCh5ZWFyKTtcbiAgICAgICAgY29uc3Qgbm9ybWFsaXplZE1vbnRoID0gVHVpTW9udGgubm9ybWFsaXplTW9udGhQYXJ0KG1vbnRoKTtcbiAgICAgICAgY29uc3Qgbm9ybWFsaXplZERheSA9IFR1aURheS5ub3JtYWxpemVEYXlQYXJ0KFxuICAgICAgICAgICAgZGF5LFxuICAgICAgICAgICAgbm9ybWFsaXplZE1vbnRoLFxuICAgICAgICAgICAgbm9ybWFsaXplZFllYXIsXG4gICAgICAgICk7XG5cbiAgICAgICAgcmV0dXJuIG5ldyBUdWlEYXkobm9ybWFsaXplZFllYXIsIG5vcm1hbGl6ZWRNb250aCwgbm9ybWFsaXplZERheSk7XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyBvdmVycmlkZSBsZW5ndGhCZXR3ZWVuKGZyb206IFR1aURheSwgdG86IFR1aURheSk6IG51bWJlciB7XG4gICAgICAgIHJldHVybiBNYXRoLnJvdW5kKFxuICAgICAgICAgICAgKHRvLnRvTG9jYWxOYXRpdmVEYXRlKCkuZ2V0VGltZSgpIC0gZnJvbS50b0xvY2FsTmF0aXZlRGF0ZSgpLmdldFRpbWUoKSkgL1xuICAgICAgICAgICAgICAgICgxMDAwICogNjAgKiA2MCAqIDI0KSxcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc3RhdGljIHBhcnNlUmF3RGF0ZVN0cmluZyhcbiAgICAgICAgZGF0ZTogc3RyaW5nLFxuICAgICAgICBkYXRlTW9kZTogVHVpRGF0ZU1vZGUgPSAnRE1ZJyxcbiAgICApOiB7ZGF5OiBudW1iZXI7IG1vbnRoOiBudW1iZXI7IHllYXI6IG51bWJlcn0ge1xuICAgICAgICBuZ0Rldk1vZGUgJiZcbiAgICAgICAgICAgIGNvbnNvbGUuYXNzZXJ0KFxuICAgICAgICAgICAgICAgIGRhdGUubGVuZ3RoID09PSBEQVRFX0ZJTExFUl9MRU5HVEgsXG4gICAgICAgICAgICAgICAgJ1twYXJzZVJhd0RhdGVTdHJpbmddOiB3cm9uZyBkYXRlIHN0cmluZyBsZW5ndGgnLFxuICAgICAgICAgICAgKTtcblxuICAgICAgICBzd2l0Y2ggKGRhdGVNb2RlKSB7XG4gICAgICAgICAgICBjYXNlICdNRFknOlxuICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgIGRheTogcGFyc2VJbnQoZGF0ZS5zbGljZSgzLCA1KSwgMTApLFxuICAgICAgICAgICAgICAgICAgICBtb250aDogcGFyc2VJbnQoZGF0ZS5zbGljZSgwLCAyKSwgMTApIC0gMSxcbiAgICAgICAgICAgICAgICAgICAgeWVhcjogcGFyc2VJbnQoZGF0ZS5zbGljZSg2LCAxMCksIDEwKSxcbiAgICAgICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICBjYXNlICdZTUQnOlxuICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgIGRheTogcGFyc2VJbnQoZGF0ZS5zbGljZSg4LCAxMCksIDEwKSxcbiAgICAgICAgICAgICAgICAgICAgbW9udGg6IHBhcnNlSW50KGRhdGUuc2xpY2UoNSwgNyksIDEwKSAtIDEsXG4gICAgICAgICAgICAgICAgICAgIHllYXI6IHBhcnNlSW50KGRhdGUuc2xpY2UoMCwgNCksIDEwKSxcbiAgICAgICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICBjYXNlICdETVknOlxuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgICBkYXk6IHBhcnNlSW50KGRhdGUuc2xpY2UoMCwgMiksIDEwKSxcbiAgICAgICAgICAgICAgICAgICAgbW9udGg6IHBhcnNlSW50KGRhdGUuc2xpY2UoMywgNSksIDEwKSAtIDEsXG4gICAgICAgICAgICAgICAgICAgIHllYXI6IHBhcnNlSW50KGRhdGUuc2xpY2UoNiwgMTApLCAxMCksXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIFRPRE86IE1vdmUgbW9udGggYW5kIHllYXIgcmVsYXRlZCBjb2RlIGNvcnJlc3BvbmRpbmcgY2xhc3Nlc1xuICAgIC8qKlxuICAgICAqIFBhcnNpbmcgYSBzdHJpbmcgd2l0aCBkYXRlIHdpdGggbm9ybWFsaXphdGlvblxuICAgICAqXG4gICAgICogQHBhcmFtIHJhd0RhdGUgZGF0ZSBzdHJpbmdcbiAgICAgKiBAcGFyYW0gZGF0ZU1vZGUgZGF0ZSBmb3JtYXQgb2YgdGhlIGRhdGUgc3RyaW5nIChETVkgfCBNRFkgfCBZTUQpXG4gICAgICogQHJldHVybiBub3JtYWxpemVkIGRhdGVcbiAgICAgKi9cbiAgICBwdWJsaWMgc3RhdGljIG5vcm1hbGl6ZVBhcnNlKHJhd0RhdGU6IHN0cmluZywgZGF0ZU1vZGU6IFR1aURhdGVNb2RlID0gJ0RNWScpOiBUdWlEYXkge1xuICAgICAgICBjb25zdCB7ZGF5LCBtb250aCwgeWVhcn0gPSB0aGlzLnBhcnNlUmF3RGF0ZVN0cmluZyhyYXdEYXRlLCBkYXRlTW9kZSk7XG5cbiAgICAgICAgcmV0dXJuIFR1aURheS5ub3JtYWxpemVPZih5ZWFyLCBtb250aCwgZGF5KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBQYXJzaW5nIGEgZGF0ZSBzdHJpbmdpZmllZCBpbiBhIHRvSlNPTiBmb3JtYXRcbiAgICAgKiBAcGFyYW0geWVhck1vbnRoRGF5U3RyaW5nIGRhdGUgc3RyaW5nIGluIGZvcm1hdCBvZiBZWVlZLU1NLUREXG4gICAgICogQHJldHVybiBkYXRlXG4gICAgICogQHRocm93cyBleGNlcHRpb25zIGlmIGFueSBwYXJ0IG9mIHRoZSBkYXRlIGlzIGludmFsaWRcbiAgICAgKi9cbiAgICBwdWJsaWMgc3RhdGljIGpzb25QYXJzZSh5ZWFyTW9udGhEYXlTdHJpbmc6IHN0cmluZyk6IFR1aURheSB7XG4gICAgICAgIGNvbnN0IHtkYXksIG1vbnRoLCB5ZWFyfSA9IHRoaXMucGFyc2VSYXdEYXRlU3RyaW5nKHllYXJNb250aERheVN0cmluZywgJ1lNRCcpO1xuXG4gICAgICAgIGlmIChcbiAgICAgICAgICAgICFUdWlNb250aC5pc1ZhbGlkTW9udGgoeWVhciwgbW9udGgpIHx8XG4gICAgICAgICAgICAhTnVtYmVyLmlzSW50ZWdlcihkYXkpIHx8XG4gICAgICAgICAgICAhdHVpSW5SYW5nZShcbiAgICAgICAgICAgICAgICBkYXksXG4gICAgICAgICAgICAgICAgTUlOX0RBWSxcbiAgICAgICAgICAgICAgICBUdWlNb250aC5nZXRNb250aERheXNDb3VudChtb250aCwgVHVpWWVhci5pc0xlYXBZZWFyKHllYXIpKSArIDEsXG4gICAgICAgICAgICApXG4gICAgICAgICkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IFR1aUludmFsaWREYXlFeGNlcHRpb24oeWVhciwgbW9udGgsIGRheSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gbmV3IFR1aURheSh5ZWFyLCBtb250aCwgZGF5KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc3RhdGljIG5vcm1hbGl6ZURheVBhcnQoZGF5OiBudW1iZXIsIG1vbnRoOiBudW1iZXIsIHllYXI6IG51bWJlcik6IG51bWJlciB7XG4gICAgICAgIG5nRGV2TW9kZSAmJiBjb25zb2xlLmFzc2VydChUdWlNb250aC5pc1ZhbGlkTW9udGgoeWVhciwgbW9udGgpKTtcblxuICAgICAgICBjb25zdCBtb250aERheXNDb3VudCA9IFR1aU1vbnRoLmdldE1vbnRoRGF5c0NvdW50KFxuICAgICAgICAgICAgbW9udGgsXG4gICAgICAgICAgICBUdWlZZWFyLmlzTGVhcFllYXIoeWVhciksXG4gICAgICAgICk7XG5cbiAgICAgICAgcmV0dXJuIHR1aU5vcm1hbGl6ZVRvSW50TnVtYmVyKGRheSwgMSwgbW9udGhEYXlzQ291bnQpO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXQgZm9ybWF0dGVkRGF5UGFydCgpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gU3RyaW5nKHRoaXMuZGF5KS5wYWRTdGFydCgyLCAnMCcpO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXQgaXNXZWVrZW5kKCk6IGJvb2xlYW4ge1xuICAgICAgICBjb25zdCBkYXlPZldlZWsgPSB0aGlzLmRheU9mV2VlayhmYWxzZSk7XG5cbiAgICAgICAgcmV0dXJuIGRheU9mV2VlayA9PT0gVHVpRGF5T2ZXZWVrLlNhdHVyZGF5IHx8IGRheU9mV2VlayA9PT0gVHVpRGF5T2ZXZWVrLlN1bmRheTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIGRheSBvZiB3ZWVrXG4gICAgICpcbiAgICAgKiBAcGFyYW0gc3RhcnRGcm9tTW9uZGF5IHdoZXRoZXIgd2VlayBzdGFydHMgZnJvbSBNb25kYXkgYW5kIG5vdCBmcm9tIFN1bmRheVxuICAgICAqIEByZXR1cm4gZGF5IG9mIHdlZWsgKGZyb20gMCB0byA2KVxuICAgICAqL1xuICAgIHB1YmxpYyBkYXlPZldlZWsoc3RhcnRGcm9tTW9uZGF5ID0gdHJ1ZSk6IG51bWJlciB7XG4gICAgICAgIGNvbnN0IGRheU9mV2VlayA9IHN0YXJ0RnJvbU1vbmRheVxuICAgICAgICAgICAgPyB0aGlzLnRvTG9jYWxOYXRpdmVEYXRlKCkuZ2V0RGF5KCkgLSAxXG4gICAgICAgICAgICA6IHRoaXMudG9Mb2NhbE5hdGl2ZURhdGUoKS5nZXREYXkoKTtcblxuICAgICAgICByZXR1cm4gZGF5T2ZXZWVrIDwgMCA/IDYgOiBkYXlPZldlZWs7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUGFzc2VkIGRhdGUgaXMgYWZ0ZXIgY3VycmVudFxuICAgICAqL1xuICAgIHB1YmxpYyBkYXlCZWZvcmUoYW5vdGhlcjogVHVpRGF5KTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICB0aGlzLm1vbnRoQmVmb3JlKGFub3RoZXIpIHx8XG4gICAgICAgICAgICAodGhpcy5tb250aFNhbWUoYW5vdGhlcikgJiYgdGhpcy5kYXkgPCBhbm90aGVyLmRheSlcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBQYXNzZWQgZGF0ZSBpcyBhZnRlciBvciBlcXVhbHMgdG8gY3VycmVudFxuICAgICAqL1xuICAgIHB1YmxpYyBkYXlTYW1lT3JCZWZvcmUoYW5vdGhlcjogVHVpRGF5KTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICB0aGlzLm1vbnRoQmVmb3JlKGFub3RoZXIpIHx8XG4gICAgICAgICAgICAodGhpcy5tb250aFNhbWUoYW5vdGhlcikgJiYgdGhpcy5kYXkgPD0gYW5vdGhlci5kYXkpXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUGFzc2VkIGRhdGUgaXMgdGhlIHNhbWUgYXMgY3VycmVudFxuICAgICAqL1xuICAgIHB1YmxpYyBkYXlTYW1lKGFub3RoZXI6IFR1aURheSk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdGhpcy5tb250aFNhbWUoYW5vdGhlcikgJiYgdGhpcy5kYXkgPT09IGFub3RoZXIuZGF5O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFBhc3NlZCBkYXRlIGlzIGVpdGhlciBiZWZvcmUgb3IgdGhlIHNhbWUgYXMgY3VycmVudFxuICAgICAqL1xuICAgIHB1YmxpYyBkYXlTYW1lT3JBZnRlcihhbm90aGVyOiBUdWlEYXkpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgIHRoaXMubW9udGhBZnRlcihhbm90aGVyKSB8fFxuICAgICAgICAgICAgKHRoaXMubW9udGhTYW1lKGFub3RoZXIpICYmIHRoaXMuZGF5ID49IGFub3RoZXIuZGF5KVxuICAgICAgICApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFBhc3NlZCBkYXRlIGlzIGJlZm9yZSBjdXJyZW50XG4gICAgICovXG4gICAgcHVibGljIGRheUFmdGVyKGFub3RoZXI6IFR1aURheSk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgdGhpcy5tb250aEFmdGVyKGFub3RoZXIpIHx8XG4gICAgICAgICAgICAodGhpcy5tb250aFNhbWUoYW5vdGhlcikgJiYgdGhpcy5kYXkgPiBhbm90aGVyLmRheSlcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDbGFtcGluZyBkYXRlIGJldHdlZW4gdHdvIGxpbWl0c1xuICAgICAqXG4gICAgICogQHBhcmFtIG1pblxuICAgICAqIEBwYXJhbSBtYXhcbiAgICAgKiBAcmV0dXJuIGNsYW1wZWQgZGF0ZVxuICAgICAqL1xuICAgIHB1YmxpYyBkYXlMaW1pdChtaW46IFR1aURheSB8IG51bGwsIG1heDogVHVpRGF5IHwgbnVsbCk6IFR1aURheSB7XG4gICAgICAgIGlmIChtaW4gIT09IG51bGwgJiYgdGhpcy5kYXlCZWZvcmUobWluKSkge1xuICAgICAgICAgICAgcmV0dXJuIG1pbjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChtYXggIT09IG51bGwgJiYgdGhpcy5kYXlBZnRlcihtYXgpKSB7XG4gICAgICAgICAgICByZXR1cm4gbWF4O1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSW1tdXRhYmx5IGFsdGVycyBjdXJyZW50IGRheSBieSBwYXNzZWQgb2Zmc2V0XG4gICAgICpcbiAgICAgKiBJZiByZXN1bHRpbmcgbW9udGggaGFzIG1vcmUgZGF5cyB0aGFuIG9yaWdpbmFsIG9uZSwgZGF0ZSBpcyByb3VuZGVkIHRvIHRoZSBtYXhpbXVtIGRheVxuICAgICAqIGluIHRoZSByZXN1bHRpbmcgbW9udGguIE9mZnNldCBvZiBkYXlzIHdpbGwgYmUgY2FsY3VsYXRlZCBiYXNlZCBvbiB0aGUgcmVzdWx0ZWQgeWVhciBhbmQgbW9udGhcbiAgICAgKiB0byBub3QgaW50ZXJmZXJlIHdpdGggcGFyZW50IGNsYXNzZXMgbWV0aG9kc1xuICAgICAqXG4gICAgICogQHBhcmFtIG9mZnNldFxuICAgICAqIEByZXR1cm4gbmV3IGRhdGUgb2JqZWN0IGFzIGEgcmVzdWx0IG9mIG9mZnNldHRpbmcgY3VycmVudFxuICAgICAqL1xuICAgIHB1YmxpYyBvdmVycmlkZSBhcHBlbmQoe3llYXIgPSAwLCBtb250aCA9IDAsIGRheSA9IDB9OiBUdWlEYXlMaWtlKTogVHVpRGF5IHtcbiAgICAgICAgY29uc3QgdG90YWxNb250aHMgPSAodGhpcy55ZWFyICsgeWVhcikgKiBNT05USFNfSU5fWUVBUiArIHRoaXMubW9udGggKyBtb250aDtcbiAgICAgICAgbGV0IHllYXJzID0gTWF0aC5mbG9vcih0b3RhbE1vbnRocyAvIE1PTlRIU19JTl9ZRUFSKTtcbiAgICAgICAgbGV0IG1vbnRocyA9IHRvdGFsTW9udGhzICUgTU9OVEhTX0lOX1lFQVI7XG5cbiAgICAgICAgbGV0IGRheXMgPVxuICAgICAgICAgICAgTWF0aC5taW4oXG4gICAgICAgICAgICAgICAgdGhpcy5kYXksXG4gICAgICAgICAgICAgICAgVHVpTW9udGguZ2V0TW9udGhEYXlzQ291bnQobW9udGhzLCBUdWlZZWFyLmlzTGVhcFllYXIoeWVhcnMpKSxcbiAgICAgICAgICAgICkgKyBkYXk7XG5cbiAgICAgICAgd2hpbGUgKGRheXMgPiBUdWlNb250aC5nZXRNb250aERheXNDb3VudChtb250aHMsIFR1aVllYXIuaXNMZWFwWWVhcih5ZWFycykpKSB7XG4gICAgICAgICAgICBkYXlzIC09IFR1aU1vbnRoLmdldE1vbnRoRGF5c0NvdW50KG1vbnRocywgVHVpWWVhci5pc0xlYXBZZWFyKHllYXJzKSk7XG5cbiAgICAgICAgICAgIGlmIChtb250aHMgPT09IFR1aU1vbnRoTnVtYmVyLkRlY2VtYmVyKSB7XG4gICAgICAgICAgICAgICAgeWVhcnMrKztcbiAgICAgICAgICAgICAgICBtb250aHMgPSBUdWlNb250aE51bWJlci5KYW51YXJ5O1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBtb250aHMrKztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHdoaWxlIChkYXlzIDwgTUlOX0RBWSkge1xuICAgICAgICAgICAgaWYgKG1vbnRocyA9PT0gVHVpTW9udGhOdW1iZXIuSmFudWFyeSkge1xuICAgICAgICAgICAgICAgIHllYXJzLS07XG4gICAgICAgICAgICAgICAgbW9udGhzID0gVHVpTW9udGhOdW1iZXIuRGVjZW1iZXI7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIG1vbnRocy0tO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBkYXlzICs9IFR1aU1vbnRoLmdldE1vbnRoRGF5c0NvdW50KG1vbnRocywgVHVpWWVhci5pc0xlYXBZZWFyKHllYXJzKSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gbmV3IFR1aURheSh5ZWFycywgbW9udGhzLCBkYXlzKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIGZvcm1hdHRlZCB3aG9sZSBkYXRlXG4gICAgICovXG4gICAgcHVibGljIGdldEZvcm1hdHRlZERheShkYXRlRm9ybWF0OiBUdWlEYXRlTW9kZSwgc2VwYXJhdG9yOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgICAgICBuZ0Rldk1vZGUgJiZcbiAgICAgICAgICAgIGNvbnNvbGUuYXNzZXJ0KFxuICAgICAgICAgICAgICAgIHNlcGFyYXRvci5sZW5ndGggPT09IDEsXG4gICAgICAgICAgICAgICAgJ1NlcGFyYXRvciBzaG91bGQgY29uc2lzdCBvZiBvbmx5IDEgc3ltYm9sJyxcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgY29uc3QgZGQgPSB0aGlzLmZvcm1hdHRlZERheVBhcnQ7XG4gICAgICAgIGNvbnN0IG1tID0gdGhpcy5mb3JtYXR0ZWRNb250aFBhcnQ7XG4gICAgICAgIGNvbnN0IHl5eXkgPSB0aGlzLmZvcm1hdHRlZFllYXI7XG5cbiAgICAgICAgc3dpdGNoIChkYXRlRm9ybWF0KSB7XG4gICAgICAgICAgICBjYXNlICdNRFknOlxuICAgICAgICAgICAgICAgIHJldHVybiBgJHttbX0ke3NlcGFyYXRvcn0ke2RkfSR7c2VwYXJhdG9yfSR7eXl5eX1gO1xuICAgICAgICAgICAgY2FzZSAnWU1EJzpcbiAgICAgICAgICAgICAgICByZXR1cm4gYCR7eXl5eX0ke3NlcGFyYXRvcn0ke21tfSR7c2VwYXJhdG9yfSR7ZGR9YDtcbiAgICAgICAgICAgIGNhc2UgJ0RNWSc6XG4gICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgIHJldHVybiBgJHtkZH0ke3NlcGFyYXRvcn0ke21tfSR7c2VwYXJhdG9yfSR7eXl5eX1gO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGljIG92ZXJyaWRlIHRvU3RyaW5nKGRhdGVGb3JtYXQ6IFR1aURhdGVNb2RlID0gJ0RNWScsIHNlcGFyYXRvciA9ICcuJyk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldEZvcm1hdHRlZERheShkYXRlRm9ybWF0LCBzZXBhcmF0b3IpO1xuICAgIH1cblxuICAgIHB1YmxpYyBvdmVycmlkZSB0b0pTT04oKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIGAke3N1cGVyLnRvSlNPTigpfS0ke3RoaXMuZm9ybWF0dGVkRGF5UGFydH1gO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgbmF0aXZlIHtAbGluayBEYXRlfSBiYXNlZCBvbiBsb2NhbCB0aW1lIHpvbmVcbiAgICAgKi9cbiAgICBwdWJsaWMgb3ZlcnJpZGUgdG9Mb2NhbE5hdGl2ZURhdGUoKTogRGF0ZSB7XG4gICAgICAgIHJldHVybiBuZXcgRGF0ZSh0aGlzLnllYXIsIHRoaXMubW9udGgsIHRoaXMuZGF5KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIG5hdGl2ZSB7QGxpbmsgRGF0ZX0gYmFzZWQgb24gVVRDXG4gICAgICovXG4gICAgcHVibGljIG92ZXJyaWRlIHRvVXRjTmF0aXZlRGF0ZSgpOiBEYXRlIHtcbiAgICAgICAgcmV0dXJuIG5ldyBEYXRlKERhdGUuVVRDKHRoaXMueWVhciwgdGhpcy5tb250aCwgdGhpcy5kYXkpKTtcbiAgICB9XG59XG5cbmV4cG9ydCBjbGFzcyBUdWlJbnZhbGlkRGF5RXhjZXB0aW9uIGV4dGVuZHMgRXJyb3Ige1xuICAgIGNvbnN0cnVjdG9yKHllYXI6IG51bWJlciwgbW9udGg6IG51bWJlciwgZGF5OiBudW1iZXIpIHtcbiAgICAgICAgc3VwZXIobmdEZXZNb2RlID8gYEludmFsaWQgZGF5OiAke3llYXJ9LSR7bW9udGh9LSR7ZGF5fWAgOiAnJyk7XG4gICAgfVxufVxuIl19