UNPKG

@alauda-fe/common

Version:

Alauda frontend team common codes.

293 lines 32.9 kB
/** * @packageDocumentation * @module translate */ import { ChangeDetectorRef, inject, Injectable, Pipe, } from '@angular/core'; import { Subject, takeUntil } from 'rxjs'; import { FIELD_NOT_AVAILABLE_PLACEHOLDER } from '../core/public-api'; import { RelativeTimeManagerService } from './relative-time-manager.service'; import { TranslateService } from './translate.service'; import * as i0 from "@angular/core"; /** * 基础国际化格式化 Pipe 抽象类 * 提供响应式的 locale 变化监听功能 */ class BaseIntlPipe { constructor() { this.destroy$$ = new Subject(); this.cdr = inject(ChangeDetectorRef); this.translate = inject(TranslateService); // 监听 locale 变化 this.translate.locale$.pipe(takeUntil(this.destroy$$)).subscribe(() => { this.cdr.markForCheck(); }); } ngOnDestroy() { this.destroy$$.next(); this.destroy$$.complete(); } static { this.ɵfac = function BaseIntlPipe_Factory(t) { return new (t || BaseIntlPipe)(); }; } static { this.ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: BaseIntlPipe, factory: BaseIntlPipe.ɵfac }); } } (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(BaseIntlPipe, [{ type: Injectable }], () => [], null); })(); /** * 数字格式化 Pipe * @example * {{ 1234.56 | aclIntlNumber }} // "1,234.56" * {{ 0.85 | aclIntlNumber:{ style: 'percent' } }} // "85%" * {{ 1234.56 | aclIntlNumber:{ minimumFractionDigits: 2 } }} // "1,234.56" */ export class IntlNumberPipe extends BaseIntlPipe { transform(value, options) { if (value == null || isNaN(value)) { return FIELD_NOT_AVAILABLE_PLACEHOLDER; } return this.translate.formatNumber(value, options || {}); } static { this.ɵfac = /*@__PURE__*/ (() => { let ɵIntlNumberPipe_BaseFactory; return function IntlNumberPipe_Factory(t) { return (ɵIntlNumberPipe_BaseFactory || (ɵIntlNumberPipe_BaseFactory = i0.ɵɵgetInheritedFactory(IntlNumberPipe)))(t || IntlNumberPipe); }; })(); } static { this.ɵpipe = /*@__PURE__*/ i0.ɵɵdefinePipe({ name: "aclIntlNumber", type: IntlNumberPipe, pure: false, standalone: true }); } } (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(IntlNumberPipe, [{ type: Pipe, args: [{ name: 'aclIntlNumber', pure: false, standalone: true, }] }], null, null); })(); /** * 货币格式化 Pipe * @example * {{ 1234.56 | aclIntlCurrency }} // "¥1,234.56" * {{ 1234.56 | aclIntlCurrency:'USD' }} // "$1,234.56" * {{ 1234.56 | aclIntlCurrency:'EUR':{ minimumFractionDigits: 2 } }} // "€1,234.56" */ export class IntlCurrencyPipe extends BaseIntlPipe { transform(value, currency, options) { if (value == null || isNaN(value)) { return FIELD_NOT_AVAILABLE_PLACEHOLDER; } return this.translate.formatCurrency(value, currency, options); } static { this.ɵfac = /*@__PURE__*/ (() => { let ɵIntlCurrencyPipe_BaseFactory; return function IntlCurrencyPipe_Factory(t) { return (ɵIntlCurrencyPipe_BaseFactory || (ɵIntlCurrencyPipe_BaseFactory = i0.ɵɵgetInheritedFactory(IntlCurrencyPipe)))(t || IntlCurrencyPipe); }; })(); } static { this.ɵpipe = /*@__PURE__*/ i0.ɵɵdefinePipe({ name: "aclIntlCurrency", type: IntlCurrencyPipe, pure: false, standalone: true }); } } (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(IntlCurrencyPipe, [{ type: Pipe, args: [{ name: 'aclIntlCurrency', pure: false, standalone: true, }] }], null, null); })(); /** * 百分比格式化 Pipe * @example * {{ 0.85 | aclIntlPercent }} // "85%" * {{ 0.8567 | aclIntlPercent:{ minimumFractionDigits: 2 } }} // "85.67%" */ export class IntlPercentPipe extends BaseIntlPipe { transform(value, options) { if (value == null || isNaN(value)) { return FIELD_NOT_AVAILABLE_PLACEHOLDER; } return this.translate.formatPercent(value, options || {}); } static { this.ɵfac = /*@__PURE__*/ (() => { let ɵIntlPercentPipe_BaseFactory; return function IntlPercentPipe_Factory(t) { return (ɵIntlPercentPipe_BaseFactory || (ɵIntlPercentPipe_BaseFactory = i0.ɵɵgetInheritedFactory(IntlPercentPipe)))(t || IntlPercentPipe); }; })(); } static { this.ɵpipe = /*@__PURE__*/ i0.ɵɵdefinePipe({ name: "aclIntlPercent", type: IntlPercentPipe, pure: false, standalone: true }); } } (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(IntlPercentPipe, [{ type: Pipe, args: [{ name: 'aclIntlPercent', pure: false, standalone: true, }] }], null, null); })(); /** * 日期格式化 Pipe * @example * {{ date | aclIntlDate }} // "2025/01/01" * {{ date | aclIntlDate:{ dateStyle: 'long' } }} // "2025年1月1日" * {{ date | aclIntlDate:{ year: 'numeric', month: 'long' } }} // "2025年1月" */ export class IntlDatePipe extends BaseIntlPipe { transform(value, options) { if (value == null) { return FIELD_NOT_AVAILABLE_PLACEHOLDER; } // 检查日期是否有效 const date = value instanceof Date ? value : new Date(value); if (isNaN(date.getTime())) { return FIELD_NOT_AVAILABLE_PLACEHOLDER; } return this.translate.formatDate(value, options); } static { this.ɵfac = /*@__PURE__*/ (() => { let ɵIntlDatePipe_BaseFactory; return function IntlDatePipe_Factory(t) { return (ɵIntlDatePipe_BaseFactory || (ɵIntlDatePipe_BaseFactory = i0.ɵɵgetInheritedFactory(IntlDatePipe)))(t || IntlDatePipe); }; })(); } static { this.ɵpipe = /*@__PURE__*/ i0.ɵɵdefinePipe({ name: "aclIntlDate", type: IntlDatePipe, pure: false, standalone: true }); } } (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(IntlDatePipe, [{ type: Pipe, args: [{ name: 'aclIntlDate', pure: false, standalone: true, }] }], null, null); })(); /** * 日期时间格式化 Pipe * @example * {{ date | aclIntlDateTime }} // "2025/01/01 14:30:00" * {{ date | aclIntlDateTime:{ dateStyle: 'medium', timeStyle: 'short' } }} // "2025年1月1日 14:30" */ export class IntlDateTimePipe extends BaseIntlPipe { transform(value, options) { if (value == null) { return FIELD_NOT_AVAILABLE_PLACEHOLDER; } // 检查日期是否有效 const date = value instanceof Date ? value : new Date(value); if (isNaN(date.getTime())) { return FIELD_NOT_AVAILABLE_PLACEHOLDER; } return this.translate.formatDateTime(value, options); } static { this.ɵfac = /*@__PURE__*/ (() => { let ɵIntlDateTimePipe_BaseFactory; return function IntlDateTimePipe_Factory(t) { return (ɵIntlDateTimePipe_BaseFactory || (ɵIntlDateTimePipe_BaseFactory = i0.ɵɵgetInheritedFactory(IntlDateTimePipe)))(t || IntlDateTimePipe); }; })(); } static { this.ɵpipe = /*@__PURE__*/ i0.ɵɵdefinePipe({ name: "aclIntlDateTime", type: IntlDateTimePipe, pure: false, standalone: true }); } } (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(IntlDateTimePipe, [{ type: Pipe, args: [{ name: 'aclIntlDateTime', pure: false, standalone: true, }] }], null, null); })(); // 时间间隔常量 (毫秒) const MILLISECONDS_SECOND = 1000; const MILLISECONDS_MINUTE = MILLISECONDS_SECOND * 60; const MILLISECONDS_HOUR = MILLISECONDS_MINUTE * 60; const MILLISECONDS_DAY = MILLISECONDS_HOUR * 24; /** * 相对时间格式化 Pipe * 支持两种使用方式: * 1. 传入 Date 对象,自动计算相对时间 * 2. 传入数值和单位,手动指定相对时间 * * 特性: * - 自动刷新UI:根据时间距离智能调整刷新频率 * - 性能优化:共享定时器,避免大量单独计时器 * - 响应式设计:监听语言变化自动更新 * * @example * // 自动计算 * {{ pastDate | aclIntlRelativeTime }} // "2 hours ago" * {{ futureDate | aclIntlRelativeTime:{ numeric: 'always' } }} // "in 2 hours" * * // 手动指定 * {{ -1 | aclIntlRelativeTime:'day' }} // "yesterday" * {{ 2 | aclIntlRelativeTime:'hour':{ numeric: 'always' } }} // "in 2 hours" * {{ -30 | aclIntlRelativeTime:'minute':{ numeric: 'always' } }} // "30 minutes ago" */ export class IntlRelativeTimePipe extends BaseIntlPipe { constructor() { super(...arguments); this.relativeTimeManager = inject(RelativeTimeManagerService); } ngOnDestroy() { super.ngOnDestroy(); this.cleanupRefresh(); } transform(value, unitOrOptions, options) { if (value == null) { return FIELD_NOT_AVAILABLE_PLACEHOLDER; } // 情况1: 传入 Date 对象,自动计算相对时间(支持自动刷新) if (value instanceof Date) { this.currentValue = value; this.setupAutoRefresh(value); const relativeOptions = unitOrOptions; return this.translate.formatRelativeTime(value, relativeOptions); } // 情况2: 传入数字,需要手动指定单位(不需要自动刷新) if (typeof value === 'number') { this.cleanupRefresh(); // 清除可能存在的刷新订阅 if (isNaN(value)) { return FIELD_NOT_AVAILABLE_PLACEHOLDER; } const unit = unitOrOptions; if (!unit) { return FIELD_NOT_AVAILABLE_PLACEHOLDER; } // 对于手动指定单位的情况,直接调用翻译服务 return this.translate.formatRelativeTime(value, unit, options); } return FIELD_NOT_AVAILABLE_PLACEHOLDER; } /** * 设置自动刷新机制 * 使用共享的计时器管理器,提高多实例场景下的性能 * 时间间隔大于一天时不设置自动刷新 */ setupAutoRefresh(date) { const distance = Math.abs(Date.now() - date.getTime()); // 时间间隔大于一天时,不需要自动刷新 if (distance >= MILLISECONDS_DAY) { this.cleanupRefresh(); return; } let interval; if (distance < MILLISECONDS_MINUTE) { interval = MILLISECONDS_SECOND; } else if (distance < MILLISECONDS_HOUR) { interval = MILLISECONDS_MINUTE; } else { interval = MILLISECONDS_HOUR; } // 如果刷新间隔没有变化,无需重新订阅 if (this.currentInterval === interval && this.refreshSubscription) { return; } this.cleanupRefresh(); this.currentInterval = interval; // 订阅共享的刷新事件 this.refreshSubscription = this.relativeTimeManager .getRefreshSubject(interval) .pipe(takeUntil(this.destroy$$)) .subscribe(() => { this.cdr.markForCheck(); // 重新计算刷新间隔,适应时间变化 if (this.currentValue) { this.setupAutoRefresh(this.currentValue); } }); } /** * 清理刷新相关资源 */ cleanupRefresh() { if (this.refreshSubscription) { this.refreshSubscription.unsubscribe(); this.refreshSubscription = undefined; } if (this.currentInterval !== undefined) { this.relativeTimeManager.releaseRefreshSubject(this.currentInterval); this.currentInterval = undefined; } } static { this.ɵfac = /*@__PURE__*/ (() => { let ɵIntlRelativeTimePipe_BaseFactory; return function IntlRelativeTimePipe_Factory(t) { return (ɵIntlRelativeTimePipe_BaseFactory || (ɵIntlRelativeTimePipe_BaseFactory = i0.ɵɵgetInheritedFactory(IntlRelativeTimePipe)))(t || IntlRelativeTimePipe); }; })(); } static { this.ɵpipe = /*@__PURE__*/ i0.ɵɵdefinePipe({ name: "aclIntlRelativeTime", type: IntlRelativeTimePipe, pure: false, standalone: true }); } } (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(IntlRelativeTimePipe, [{ type: Pipe, args: [{ name: 'aclIntlRelativeTime', pure: false, standalone: true, }] }], null, null); })(); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW50bC1mb3JtYXQucGlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9saWJzL2NvbW1vbi9zcmMvdHJhbnNsYXRlL2ludGwtZm9ybWF0LnBpcGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7R0FHRztBQUVILE9BQU8sRUFDTCxpQkFBaUIsRUFDakIsTUFBTSxFQUNOLFVBQVUsRUFFVixJQUFJLEdBRUwsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLE9BQU8sRUFBZ0IsU0FBUyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBRXhELE9BQU8sRUFBRSwrQkFBK0IsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBRXJFLE9BQU8sRUFBRSwwQkFBMEIsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQzdFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHFCQUFxQixDQUFDOztBQUV2RDs7O0dBR0c7QUFDSCxNQUNlLFlBQVk7SUFPekI7UUFObUIsY0FBUyxHQUFHLElBQUksT0FBTyxFQUFRLENBQUM7UUFFaEMsUUFBRyxHQUFHLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1FBRWhDLGNBQVMsR0FBRyxNQUFNLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztRQUd0RCxlQUFlO1FBQ2YsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsR0FBRyxFQUFFO1lBQ3BFLElBQUksQ0FBQyxHQUFHLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDMUIsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQsV0FBVztRQUNULElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDdEIsSUFBSSxDQUFDLFNBQVMsQ0FBQyxRQUFRLEVBQUUsQ0FBQztJQUM1QixDQUFDOzZFQWpCWSxZQUFZO3VFQUFaLFlBQVks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QUMsbUJBQW1CLEVBQUUsQ0FBQztZQUM3QixJQUFJLENBQUMsbUJBQW1CLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDdkMsSUFBSSxDQUFDLG1CQUFtQixHQUFHLFNBQVMsQ0FBQztRQUN2QyxDQUFDO1FBRUQsSUFBSSxJQUFJLENBQUMsZUFBZSxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ3ZDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxxQkFBcUIsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLENBQUM7WUFDckUsSUFBSSxDQUFDLGVBQWUsR0FBRyxTQUFTLENBQUM7UUFDbkMsQ0FBQztJQUNILENBQUM7b1BBbkhVLG9CQUFvQixTQUFwQixvQkFBb0I7NkZBQXBCLG9CQUFvQjs7aUZBQXBCLG9CQUFvQjtjQUxoQyxJQUFJO2VBQUM7Z0JBQ0osSUFBSSxFQUFFLHFCQUFxQjtnQkFDM0IsSUFBSSxFQUFFLEtBQUs7Z0JBQ1gsVUFBVSxFQUFFLElBQUk7YUFDakIiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBwYWNrYWdlRG9jdW1lbnRhdGlvblxuICogQG1vZHVsZSB0cmFuc2xhdGVcbiAqL1xuXG5pbXBvcnQge1xuICBDaGFuZ2VEZXRlY3RvclJlZixcbiAgaW5qZWN0LFxuICBJbmplY3RhYmxlLFxuICBPbkRlc3Ryb3ksXG4gIFBpcGUsXG4gIFBpcGVUcmFuc2Zvcm0sXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgU3ViamVjdCwgU3Vic2NyaXB0aW9uLCB0YWtlVW50aWwgfSBmcm9tICdyeGpzJztcblxuaW1wb3J0IHsgRklFTERfTk9UX0FWQUlMQUJMRV9QTEFDRUhPTERFUiB9IGZyb20gJy4uL2NvcmUvcHVibGljLWFwaSc7XG5cbmltcG9ydCB7IFJlbGF0aXZlVGltZU1hbmFnZXJTZXJ2aWNlIH0gZnJvbSAnLi9yZWxhdGl2ZS10aW1lLW1hbmFnZXIuc2VydmljZSc7XG5pbXBvcnQgeyBUcmFuc2xhdGVTZXJ2aWNlIH0gZnJvbSAnLi90cmFuc2xhdGUuc2VydmljZSc7XG5cbi8qKlxuICog5Z+656GA5Zu96ZmF5YyW5qC85byP5YyWIFBpcGUg5oq96LGh57G7XG4gKiDmj5Dkvpvlk43lupTlvI/nmoQgbG9jYWxlIOWPmOWMluebkeWQrOWKn+iDvVxuICovXG5ASW5qZWN0YWJsZSgpXG5hYnN0cmFjdCBjbGFzcyBCYXNlSW50bFBpcGUgaW1wbGVtZW50cyBQaXBlVHJhbnNmb3JtLCBPbkRlc3Ryb3kge1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgZGVzdHJveSQkID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcblxuICBwcm90ZWN0ZWQgcmVhZG9ubHkgY2RyID0gaW5qZWN0KENoYW5nZURldGVjdG9yUmVmKTtcblxuICBwcm90ZWN0ZWQgcmVhZG9ubHkgdHJhbnNsYXRlID0gaW5qZWN0KFRyYW5zbGF0ZVNlcnZpY2UpO1xuXG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIC8vIOebkeWQrCBsb2NhbGUg5Y+Y5YyWXG4gICAgdGhpcy50cmFuc2xhdGUubG9jYWxlJC5waXBlKHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkJCkpLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICB0aGlzLmNkci5tYXJrRm9yQ2hlY2soKTtcbiAgICB9KTtcbiAgfVxuXG4gIG5nT25EZXN0cm95KCkge1xuICAgIHRoaXMuZGVzdHJveSQkLm5leHQoKTtcbiAgICB0aGlzLmRlc3Ryb3kkJC5jb21wbGV0ZSgpO1xuICB9XG5cbiAgYWJzdHJhY3QgdHJhbnNmb3JtKHZhbHVlOiBhbnksIC4uLmFyZ3M6IGFueVtdKTogc3RyaW5nO1xufVxuXG4vKipcbiAqIOaVsOWtl+agvOW8j+WMliBQaXBlXG4gKiBAZXhhbXBsZVxuICoge3sgMTIzNC41NiB8IGFjbEludGxOdW1iZXIgfX0gLy8gXCIxLDIzNC41NlwiXG4gKiB7eyAwLjg1IHwgYWNsSW50bE51bWJlcjp7IHN0eWxlOiAncGVyY2VudCcgfSB9fSAvLyBcIjg1JVwiXG4gKiB7eyAxMjM0LjU2IHwgYWNsSW50bE51bWJlcjp7IG1pbmltdW1GcmFjdGlvbkRpZ2l0czogMiB9IH19IC8vIFwiMSwyMzQuNTZcIlxuICovXG5AUGlwZSh7XG4gIG5hbWU6ICdhY2xJbnRsTnVtYmVyJyxcbiAgcHVyZTogZmFsc2UsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG59KVxuZXhwb3J0IGNsYXNzIEludGxOdW1iZXJQaXBlIGV4dGVuZHMgQmFzZUludGxQaXBlIGltcGxlbWVudHMgUGlwZVRyYW5zZm9ybSB7XG4gIHRyYW5zZm9ybSh2YWx1ZTogbnVtYmVyLCBvcHRpb25zPzogSW50bC5OdW1iZXJGb3JtYXRPcHRpb25zKTogc3RyaW5nIHtcbiAgICBpZiAodmFsdWUgPT0gbnVsbCB8fCBpc05hTih2YWx1ZSkpIHtcbiAgICAgIHJldHVybiBGSUVMRF9OT1RfQVZBSUxBQkxFX1BMQUNFSE9MREVSO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLnRyYW5zbGF0ZS5mb3JtYXROdW1iZXIodmFsdWUsIG9wdGlvbnMgfHwge30pO1xuICB9XG59XG5cbi8qKlxuICog6LSn5biB5qC85byP5YyWIFBpcGVcbiAqIEBleGFtcGxlXG4gKiB7eyAxMjM0LjU2IHwgYWNsSW50bEN1cnJlbmN5IH19IC8vIFwiwqUxLDIzNC41NlwiXG4gKiB7eyAxMjM0LjU2IHwgYWNsSW50bEN1cnJlbmN5OidVU0QnIH19IC8vIFwiJDEsMjM0LjU2XCJcbiAqIHt7IDEyMzQuNTYgfCBhY2xJbnRsQ3VycmVuY3k6J0VVUic6eyBtaW5pbXVtRnJhY3Rpb25EaWdpdHM6IDIgfSB9fSAvLyBcIuKCrDEsMjM0LjU2XCJcbiAqL1xuQFBpcGUoe1xuICBuYW1lOiAnYWNsSW50bEN1cnJlbmN5JyxcbiAgcHVyZTogZmFsc2UsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG59KVxuZXhwb3J0IGNsYXNzIEludGxDdXJyZW5jeVBpcGUgZXh0ZW5kcyBCYXNlSW50bFBpcGUgaW1wbGVtZW50cyBQaXBlVHJhbnNmb3JtIHtcbiAgdHJhbnNmb3JtKFxuICAgIHZhbHVlOiBudW1iZXIsXG4gICAgY3VycmVuY3k/OiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IEludGwuTnVtYmVyRm9ybWF0T3B0aW9ucyxcbiAgKTogc3RyaW5nIHtcbiAgICBpZiAodmFsdWUgPT0gbnVsbCB8fCBpc05hTih2YWx1ZSkpIHtcbiAgICAgIHJldHVybiBGSUVMRF9OT1RfQVZBSUxBQkxFX1BMQUNFSE9MREVSO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLnRyYW5zbGF0ZS5mb3JtYXRDdXJyZW5jeSh2YWx1ZSwgY3VycmVuY3ksIG9wdGlvbnMpO1xuICB9XG59XG5cbi8qKlxuICog55m+5YiG5q+U5qC85byP5YyWIFBpcGVcbiAqIEBleGFtcGxlXG4gKiB7eyAwLjg1IHwgYWNsSW50bFBlcmNlbnQgfX0gLy8gXCI4NSVcIlxuICoge3sgMC44NTY3IHwgYWNsSW50bFBlcmNlbnQ6eyBtaW5pbXVtRnJhY3Rpb25EaWdpdHM6IDIgfSB9fSAvLyBcIjg1LjY3JVwiXG4gKi9cbkBQaXBlKHtcbiAgbmFtZTogJ2FjbEludGxQZXJjZW50JyxcbiAgcHVyZTogZmFsc2UsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG59KVxuZXhwb3J0IGNsYXNzIEludGxQZXJjZW50UGlwZSBleHRlbmRzIEJhc2VJbnRsUGlwZSBpbXBsZW1lbnRzIFBpcGVUcmFuc2Zvcm0ge1xuICB0cmFuc2Zvcm0oXG4gICAgdmFsdWU6IG51bWJlcixcbiAgICBvcHRpb25zPzogT21pdDxJbnRsLk51bWJlckZvcm1hdE9wdGlvbnMsICdzdHlsZSc+LFxuICApOiBzdHJpbmcge1xuICAgIGlmICh2YWx1ZSA9PSBudWxsIHx8IGlzTmFOKHZhbHVlKSkge1xuICAgICAgcmV0dXJuIEZJRUxEX05PVF9BVkFJTEFCTEVfUExBQ0VIT0xERVI7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMudHJhbnNsYXRlLmZvcm1hdFBlcmNlbnQodmFsdWUsIG9wdGlvbnMgfHwge30pO1xuICB9XG59XG5cbi8qKlxuICog5pel5pyf5qC85byP5YyWIFBpcGVcbiAqIEBleGFtcGxlXG4gKiB7eyBkYXRlIHwgYWNsSW50bERhdGUgfX0gLy8gXCIyMDI1LzAxLzAxXCJcbiAqIHt7IGRhdGUgfCBhY2xJbnRsRGF0ZTp7IGRhdGVTdHlsZTogJ2xvbmcnIH0gfX0gLy8gXCIyMDI15bm0MeaciDHml6VcIlxuICoge3sgZGF0ZSB8IGFjbEludGxEYXRlOnsgeWVhcjogJ251bWVyaWMnLCBtb250aDogJ2xvbmcnIH0gfX0gLy8gXCIyMDI15bm0MeaciFwiXG4gKi9cbkBQaXBlKHtcbiAgbmFtZTogJ2FjbEludGxEYXRlJyxcbiAgcHVyZTogZmFsc2UsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG59KVxuZXhwb3J0IGNsYXNzIEludGxEYXRlUGlwZSBleHRlbmRzIEJhc2VJbnRsUGlwZSBpbXBsZW1lbnRzIFBpcGVUcmFuc2Zvcm0ge1xuICB0cmFuc2Zvcm0oXG4gICAgdmFsdWU6IERhdGUgfCBzdHJpbmcgfCBudW1iZXIsXG4gICAgb3B0aW9ucz86IEludGwuRGF0ZVRpbWVGb3JtYXRPcHRpb25zLFxuICApOiBzdHJpbmcge1xuICAgIGlmICh2YWx1ZSA9PSBudWxsKSB7XG4gICAgICByZXR1cm4gRklFTERfTk9UX0FWQUlMQUJMRV9QTEFDRUhPTERFUjtcbiAgICB9XG5cbiAgICAvLyDmo4Dmn6Xml6XmnJ/mmK/lkKbmnInmlYhcbiAgICBjb25zdCBkYXRlID0gdmFsdWUgaW5zdGFuY2VvZiBEYXRlID8gdmFsdWUgOiBuZXcgRGF0ZSh2YWx1ZSk7XG4gICAgaWYgKGlzTmFOKGRhdGUuZ2V0VGltZSgpKSkge1xuICAgICAgcmV0dXJuIEZJRUxEX05PVF9BVkFJTEFCTEVfUExBQ0VIT0xERVI7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMudHJhbnNsYXRlLmZvcm1hdERhdGUodmFsdWUsIG9wdGlvbnMpO1xuICB9XG59XG5cbi8qKlxuICog5pel5pyf5pe26Ze05qC85byP5YyWIFBpcGVcbiAqIEBleGFtcGxlXG4gKiB7eyBkYXRlIHwgYWNsSW50bERhdGVUaW1lIH19IC8vIFwiMjAyNS8wMS8wMSAxNDozMDowMFwiXG4gKiB7eyBkYXRlIHwgYWNsSW50bERhdGVUaW1lOnsgZGF0ZVN0eWxlOiAnbWVkaXVtJywgdGltZVN0eWxlOiAnc2hvcnQnIH0gfX0gLy8gXCIyMDI15bm0MeaciDHml6UgMTQ6MzBcIlxuICovXG5AUGlwZSh7XG4gIG5hbWU6ICdhY2xJbnRsRGF0ZVRpbWUnLFxuICBwdXJlOiBmYWxzZSxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbn0pXG5leHBvcnQgY2xhc3MgSW50bERhdGVUaW1lUGlwZSBleHRlbmRzIEJhc2VJbnRsUGlwZSBpbXBsZW1lbnRzIFBpcGVUcmFuc2Zvcm0ge1xuICB0cmFuc2Zvcm0oXG4gICAgdmFsdWU6IERhdGUgfCBzdHJpbmcgfCBudW1iZXIsXG4gICAgb3B0aW9ucz86IEludGwuRGF0ZVRpbWVGb3JtYXRPcHRpb25zLFxuICApOiBzdHJpbmcge1xuICAgIGlmICh2YWx1ZSA9PSBudWxsKSB7XG4gICAgICByZXR1cm4gRklFTERfTk9UX0FWQUlMQUJMRV9QTEFDRUhPTERFUjtcbiAgICB9XG5cbiAgICAvLyDmo4Dmn6Xml6XmnJ/mmK/lkKbmnInmlYhcbiAgICBjb25zdCBkYXRlID0gdmFsdWUgaW5zdGFuY2VvZiBEYXRlID8gdmFsdWUgOiBuZXcgRGF0ZSh2YWx1ZSk7XG4gICAgaWYgKGlzTmFOKGRhdGUuZ2V0VGltZSgpKSkge1xuICAgICAgcmV0dXJuIEZJRUxEX05PVF9BVkFJTEFCTEVfUExBQ0VIT0xERVI7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMudHJhbnNsYXRlLmZvcm1hdERhdGVUaW1lKHZhbHVlLCBvcHRpb25zKTtcbiAgfVxufVxuXG4vLyDml7bpl7Tpl7TpmpTluLjph48gKOavq+enkilcbmNvbnN0IE1JTExJU0VDT05EU19TRUNPTkQgPSAxMDAwO1xuY29uc3QgTUlMTElTRUNPTkRTX01JTlVURSA9IE1JTExJU0VDT05EU19TRUNPTkQgKiA2MDtcbmNvbnN0IE1JTExJU0VDT05EU19IT1VSID0gTUlMTElTRUNPTkRTX01JTlVURSAqIDYwO1xuY29uc3QgTUlMTElTRUNPTkRTX0RBWSA9IE1JTExJU0VDT05EU19IT1VSICogMjQ7XG5cbi8qKlxuICog55u45a+55pe26Ze05qC85byP5YyWIFBpcGVcbiAqIOaUr+aMgeS4pOenjeS9v+eUqOaWueW8j++8mlxuICogMS4g5Lyg5YWlIERhdGUg5a+56LGh77yM6Ieq5Yqo6K6h566X55u45a+55pe26Ze0XG4gKiAyLiDkvKDlhaXmlbDlgLzlkozljZXkvY3vvIzmiYvliqjmjIflrprnm7jlr7nml7bpl7RcbiAqXG4gKiDnibnmgKfvvJpcbiAqIC0g6Ieq5Yqo5Yi35pawVUnvvJrmoLnmja7ml7bpl7Tot53nprvmmbrog73osIPmlbTliLfmlrDpopHnjodcbiAqIC0g5oCn6IO95LyY5YyW77ya5YWx5Lqr5a6a5pe25Zmo77yM6YG/5YWN5aSn6YeP5Y2V54us6K6h5pe25ZmoXG4gKiAtIOWTjeW6lOW8j+iuvuiuoe+8muebkeWQrOivreiogOWPmOWMluiHquWKqOabtOaWsFxuICpcbiAqIEBleGFtcGxlXG4gKiAvLyDoh6rliqjorqHnrpdcbiAqIHt7IHBhc3REYXRlIHwgYWNsSW50bFJlbGF0aXZlVGltZSB9fSAvLyBcIjIgaG91cnMgYWdvXCJcbiAqIHt7IGZ1dHVyZURhdGUgfCBhY2xJbnRsUmVsYXRpdmVUaW1lOnsgbnVtZXJpYzogJ2Fsd2F5cycgfSB9fSAvLyBcImluIDIgaG91cnNcIlxuICpcbiAqIC8vIOaJi+WKqOaMh+WumlxuICoge3sgLTEgfCBhY2xJbnRsUmVsYXRpdmVUaW1lOidkYXknIH19IC8vIFwieWVzdGVyZGF5XCJcbiAqIHt7IDIgfCBhY2xJbnRsUmVsYXRpdmVUaW1lOidob3VyJzp7IG51bWVyaWM6ICdhbHdheXMnIH0gfX0gLy8gXCJpbiAyIGhvdXJzXCJcbiAqIHt7IC0zMCB8IGFjbEludGxSZWxhdGl2ZVRpbWU6J21pbnV0ZSc6eyBudW1lcmljOiAnYWx3YXlzJyB9IH19IC8vIFwiMzAgbWludXRlcyBhZ29cIlxuICovXG5AUGlwZSh7XG4gIG5hbWU6ICdhY2xJbnRsUmVsYXRpdmVUaW1lJyxcbiAgcHVyZTogZmFsc2UsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG59KVxuZXhwb3J0IGNsYXNzIEludGxSZWxhdGl2ZVRpbWVQaXBlXG4gIGV4dGVuZHMgQmFzZUludGxQaXBlXG4gIGltcGxlbWVudHMgUGlwZVRyYW5zZm9ybSwgT25EZXN0cm95XG57XG4gIHByaXZhdGUgcmVhZG9ubHkgcmVsYXRpdmVUaW1lTWFuYWdlciA9IGluamVjdChSZWxhdGl2ZVRpbWVNYW5hZ2VyU2VydmljZSk7XG5cbiAgcHJpdmF0ZSBjdXJyZW50SW50ZXJ2YWw/OiBudW1iZXI7XG4gIHByaXZhdGUgcmVmcmVzaFN1YnNjcmlwdGlvbj86IFN1YnNjcmlwdGlvbjtcbiAgcHJpdmF0ZSBjdXJyZW50VmFsdWU/OiBEYXRlO1xuXG4gIG92ZXJyaWRlIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgIHN1cGVyLm5nT25EZXN0cm95KCk7XG4gICAgdGhpcy5jbGVhbnVwUmVmcmVzaCgpO1xuICB9XG5cbiAgdHJhbnNmb3JtKFxuICAgIHZhbHVlOiBEYXRlIHwgbnVtYmVyLFxuICAgIHVuaXRPck9wdGlvbnM/OlxuICAgICAgfCBJbnRsLlJlbGF0aXZlVGltZUZvcm1hdFVuaXRcbiAgICAgIHwgSW50bC5SZWxhdGl2ZVRpbWVGb3JtYXRPcHRpb25zLFxuICAgIG9wdGlvbnM/OiBJbnRsLlJlbGF0aXZlVGltZUZvcm1hdE9wdGlvbnMsXG4gICk6IHN0cmluZyB7XG4gICAgaWYgKHZhbHVlID09IG51bGwpIHtcbiAgICAgIHJldHVybiBGSUVMRF9OT1RfQVZBSUxBQkxFX1BMQUNFSE9MREVSO1xuICAgIH1cblxuICAgIC8vIOaDheWGtTE6IOS8oOWFpSBEYXRlIOWvueixoe+8jOiHquWKqOiuoeeul+ebuOWvueaXtumXtO+8iOaUr+aMgeiHquWKqOWIt+aWsO+8iVxuICAgIGlmICh2YWx1ZSBpbnN0YW5jZW9mIERhdGUpIHtcbiAgICAgIHRoaXMuY3VycmVudFZhbHVlID0gdmFsdWU7XG4gICAgICB0aGlzLnNldHVwQXV0b1JlZnJlc2godmFsdWUpO1xuXG4gICAgICBjb25zdCByZWxhdGl2ZU9wdGlvbnMgPSB1bml0T3JPcHRpb25zIGFzXG4gICAgICAgIHwgSW50bC5SZWxhdGl2ZVRpbWVGb3JtYXRPcHRpb25zXG4gICAgICAgIHwgdW5kZWZpbmVkO1xuXG4gICAgICByZXR1cm4gdGhpcy50cmFuc2xhdGUuZm9ybWF0UmVsYXRpdmVUaW1lKHZhbHVlLCByZWxhdGl2ZU9wdGlvbnMpO1xuICAgIH1cblxuICAgIC8vIOaDheWGtTI6IOS8oOWFpeaVsOWtl++8jOmcgOimgeaJi+WKqOaMh+WumuWNleS9je+8iOS4jemcgOimgeiHquWKqOWIt+aWsO+8iVxuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInKSB7XG4gICAgICB0aGlzLmNsZWFudXBSZWZyZXNoKCk7IC8vIOa4hemZpOWPr+iDveWtmOWcqOeahOWIt+aWsOiuoumYhVxuXG4gICAgICBpZiAoaXNOYU4odmFsdWUpKSB7XG4gICAgICAgIHJldHVybiBGSUVMRF9OT1RfQVZBSUxBQkxFX1BMQUNFSE9MREVSO1xuICAgICAgfVxuXG4gICAgICBjb25zdCB1bml0ID0gdW5pdE9yT3B0aW9ucyBhcyBJbnRsLlJlbGF0aXZlVGltZUZvcm1hdFVuaXQ7XG4gICAgICBpZiAoIXVuaXQpIHtcbiAgICAgICAgcmV0dXJuIEZJRUxEX05PVF9BVkFJTEFCTEVfUExBQ0VIT0xERVI7XG4gICAgICB9XG5cbiAgICAgIC8vIOWvueS6juaJi+WKqOaMh+WumuWNleS9jeeahOaDheWGte+8jOebtOaOpeiwg+eUqOe/u+ivkeacjeWKoVxuICAgICAgcmV0dXJuIHRoaXMudHJhbnNsYXRlLmZvcm1hdFJlbGF0aXZlVGltZSh2YWx1ZSwgdW5pdCwgb3B0aW9ucyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIEZJRUxEX05PVF9BVkFJTEFCTEVfUExBQ0VIT0xERVI7XG4gIH1cblxuICAvKipcbiAgICog6K6+572u6Ieq5Yqo5Yi35paw5py65Yi2XG4gICAqIOS9v+eUqOWFseS6q+eahOiuoeaXtuWZqOeuoeeQhuWZqO+8jOaPkOmrmOWkmuWunuS+i+WcuuaZr+S4i+eahOaAp+iDvVxuICAgKiDml7bpl7Tpl7TpmpTlpKfkuo7kuIDlpKnml7bkuI3orr7nva7oh6rliqjliLfmlrBcbiAgICovXG4gIHByaXZhdGUgc2V0dXBBdXRvUmVmcmVzaChkYXRlOiBEYXRlKTogdm9pZCB7XG4gICAgY29uc3QgZGlzdGFuY2UgPSBNYXRoLmFicyhEYXRlLm5vdygpIC0gZGF0ZS5nZXRUaW1lKCkpO1xuXG4gICAgLy8g5pe26Ze06Ze06ZqU5aSn5LqO5LiA5aSp5pe277yM5LiN6ZyA6KaB6Ieq5Yqo5Yi35pawXG4gICAgaWYgKGRpc3RhbmNlID49IE1JTExJU0VDT05EU19EQVkpIHtcbiAgICAgIHRoaXMuY2xlYW51cFJlZnJlc2goKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBsZXQgaW50ZXJ2YWw6IG51bWJlcjtcbiAgICBpZiAoZGlzdGFuY2UgPCBNSUxMSVNFQ09ORFNfTUlOVVRFKSB7XG4gICAgICBpbnRlcnZhbCA9IE1JTExJU0VDT05EU19TRUNPTkQ7XG4gICAgfSBlbHNlIGlmIChkaXN0YW5jZSA8IE1JTExJU0VDT05EU19IT1VSKSB7XG4gICAgICBpbnRlcnZhbCA9IE1JTExJU0VDT05EU19NSU5VVEU7XG4gICAgfSBlbHNlIHtcbiAgICAgIGludGVydmFsID0gTUlMTElTRUNPTkRTX0hPVVI7XG4gICAgfVxuXG4gICAgLy8g5aaC5p6c5Yi35paw6Ze06ZqU5rKh5pyJ5Y+Y5YyW77yM5peg6ZyA6YeN5paw6K6i6ZiFXG4gICAgaWYgKHRoaXMuY3VycmVudEludGVydmFsID09PSBpbnRlcnZhbCAmJiB0aGlzLnJlZnJlc2hTdWJzY3JpcHRpb24pIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLmNsZWFudXBSZWZyZXNoKCk7XG4gICAgdGhpcy5jdXJyZW50SW50ZXJ2YWwgPSBpbnRlcnZhbDtcblxuICAgIC8vIOiuoumYheWFseS6q+eahOWIt+aWsOS6i+S7tlxuICAgIHRoaXMucmVmcmVzaFN1YnNjcmlwdGlvbiA9IHRoaXMucmVsYXRpdmVUaW1lTWFuYWdlclxuICAgICAgLmdldFJlZnJlc2hTdWJqZWN0KGludGVydmFsKVxuICAgICAgLnBpcGUodGFrZVVudGlsKHRoaXMuZGVzdHJveSQkKSlcbiAgICAgIC5zdWJzY3JpYmUoKCkgPT4ge1xuICAgICAgICB0aGlzLmNkci5tYXJrRm9yQ2hlY2soKTtcbiAgICAgICAgLy8g6YeN5paw6K6h566X5Yi35paw6Ze06ZqU77yM6YCC5bqU5pe26Ze05Y+Y5YyWXG4gICAgICAgIGlmICh0aGlzLmN1cnJlbnRWYWx1ZSkge1xuICAgICAgICAgIHRoaXMuc2V0dXBBdXRvUmVmcmVzaCh0aGlzLmN1cnJlbnRWYWx1ZSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIOa4heeQhuWIt+aWsOebuOWFs+i1hOa6kFxuICAgKi9cbiAgcHJpdmF0ZSBjbGVhbnVwUmVmcmVzaCgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5yZWZyZXNoU3Vic2NyaXB0aW9uKSB7XG4gICAgICB0aGlzLnJlZnJlc2hTdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcbiAgICAgIHRoaXMucmVmcmVzaFN1YnNjcmlwdGlvbiA9IHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5jdXJyZW50SW50ZXJ2YWwgIT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhpcy5yZWxhdGl2ZVRpbWVNYW5hZ2VyLnJlbGVhc2VSZWZyZXNoU3ViamVjdCh0aGlzLmN1cnJlbnRJbnRlcnZhbCk7XG4gICAgICB0aGlzLmN1cnJlbnRJbnRlcnZhbCA9IHVuZGVmaW5lZDtcbiAgICB9XG4gIH1cbn1cbiJdfQ==