ng-zorro-antd-mobile
Version:
An enterprise-class mobile UI components based on Ant Design and Angular
373 lines (372 loc) • 41.5 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
import { Models } from '../date/DataTypes';
import { formatDate } from '../util';
import defaultLocale from '../locale/zh_CN';
/**
* @record
*/
export function StateType() { }
/** @type {?} */
StateType.prototype.months;
export default class DatePicker {
constructor() {
this.props = /** @type {?} */ ({
prefixCls: 'rmc-calendar',
infinite: false,
infiniteOpt: false,
defaultDate: new Date(),
initalMonths: 6,
locale: defaultLocale
});
this.state = {
months: []
};
this.visibleMonth = [];
this.getDateWithoutTime = (date) => {
if (!date)
return 0;
return +new Date(date.getFullYear(), date.getMonth(), date.getDate());
};
this.genWeekData = (firstDate) => {
/** @type {?} */
const minDateTime = this.getDateWithoutTime(this.props.minDate);
/** @type {?} */
const maxDateTime = this.getDateWithoutTime(this.props.maxDate) || Number.POSITIVE_INFINITY;
/** @type {?} */
const weeks = [];
/** @type {?} */
const nextMonth = this.getMonthDate(firstDate, 1).firstDate;
/** @type {?} */
let currentDay = firstDate;
/** @type {?} */
let currentWeek = [];
weeks.push(currentWeek);
/** @type {?} */
let startWeekday = currentDay.getDay();
if (startWeekday > 0) {
for (let i = 0; i < startWeekday; i++) {
currentWeek.push(/** @type {?} */ ({}));
}
}
while (currentDay < nextMonth) {
if (currentWeek.length === 7) {
currentWeek = [];
weeks.push(currentWeek);
}
/** @type {?} */
const dayOfMonth = currentDay.getDate();
/** @type {?} */
const tick = +currentDay;
currentWeek.push({
tick,
dayOfMonth,
selected: Models.SelectType.None,
isFirstOfMonth: dayOfMonth === 1,
isLastOfMonth: false,
outOfDate: tick < minDateTime || tick > maxDateTime
});
currentDay = new Date(currentDay.getTime() + 3600 * 24 * 1000);
}
currentWeek[currentWeek.length - 1].isLastOfMonth = true;
return weeks;
};
this.selectDateRange = (startDate, endDate, clear = false) => {
const { getDateExtra, type, onSelectHasDisableDate } = this.props;
if (type === 'one') {
endDate = undefined;
}
/** @type {?} */
const time1 = this.getDateWithoutTime(startDate);
/** @type {?} */
const time2 = this.getDateWithoutTime(endDate);
/** @type {?} */
const startDateTick = !time2 || time1 < time2 ? time1 : time2;
/** @type {?} */
const endDateTick = time2 && time1 > time2 ? time1 : time2;
/** @type {?} */
const startMonthDate = this.getMonthDate(new Date(startDateTick)).firstDate;
/** @type {?} */
const endMonthDate = endDateTick ? new Date(endDateTick) : this.getMonthDate(new Date(startDateTick)).lastDate;
/** @type {?} */
let unuseable = [];
/** @type {?} */
let needUpdate = false;
this.state.months
.filter(m => {
return m.firstDate >= startMonthDate && m.firstDate <= endMonthDate;
})
.forEach(m => {
m.weeks.forEach(w => w
.filter(d => {
if (!endDateTick) {
return d.tick && this.inDate(startDateTick, d.tick);
}
else {
return d.tick && d.tick >= startDateTick && d.tick <= endDateTick;
}
})
.forEach(d => {
/** @type {?} */
const oldValue = d.selected;
if (clear) {
d.selected = Models.SelectType.None;
}
else {
/** @type {?} */
const info = (getDateExtra && getDateExtra(new Date(d.tick))) || {};
if (d.outOfDate || info.disable) {
unuseable.push(d.tick);
}
if (this.inDate(startDateTick, d.tick)) {
if (type === 'one') {
d.selected = Models.SelectType.Single;
}
else if (!endDateTick) {
d.selected = Models.SelectType.Only;
}
else if (startDateTick !== endDateTick) {
d.selected = Models.SelectType.Start;
}
else {
d.selected = Models.SelectType.All;
}
}
else if (this.inDate(endDateTick, d.tick)) {
d.selected = Models.SelectType.End;
}
else {
d.selected = Models.SelectType.Middle;
}
}
needUpdate = needUpdate || d.selected !== oldValue;
}));
if (needUpdate && m.componentRef) {
m.componentRef.updateWeeks();
}
});
if (unuseable.length > 0) {
if (onSelectHasDisableDate) {
onSelectHasDisableDate(unuseable.map(tick => new Date(tick)));
}
else {
console.warn('Unusable date. You can handle by onSelectHasDisableDate.', unuseable);
}
}
};
this.computeVisible = (clientHeight, scrollTop) => {
/** @type {?} */
let needUpdate = false;
/** @type {?} */
const MAX_VIEW_PORT = clientHeight * 2;
/** @type {?} */
const MIN_VIEW_PORT = clientHeight;
/** @type {?} */
const filterFunc = (vm) => vm.y &&
vm.height &&
(vm.y + vm.height > scrollTop - MAX_VIEW_PORT && vm.y < scrollTop + clientHeight + MAX_VIEW_PORT);
if (this.props.infiniteOpt && this.visibleMonth.length > 12) {
this.visibleMonth = this.visibleMonth.filter(filterFunc).sort((a, b) => +a.firstDate - +b.firstDate);
}
// 当小缓冲区不满时填充
if (this.visibleMonth.length > 0) {
/** @type {?} */
const last = this.visibleMonth[this.visibleMonth.length - 1];
if (last.y !== undefined && last.height && last.y + last.height < scrollTop + clientHeight + MIN_VIEW_PORT) {
/** @type {?} */
const lastIndex = this.state.months.indexOf(last);
for (let i = 1; i <= 2; i++) {
/** @type {?} */
const index = lastIndex + i;
if (index < this.state.months.length && this.visibleMonth.indexOf(this.state.months[index]) < 0) {
this.visibleMonth.push(this.state.months[index]);
}
else {
this.canLoadNext() && this.genMonthData(undefined, 1);
}
}
needUpdate = true;
}
/** @type {?} */
const first = this.visibleMonth[0];
if (first.y !== undefined && first.height && first.y > scrollTop - MIN_VIEW_PORT) {
/** @type {?} */
const firstIndex = this.state.months.indexOf(first);
for (let i = 1; i <= 2; i++) {
/** @type {?} */
const index = firstIndex - i;
if (index >= 0 && this.visibleMonth.indexOf(this.state.months[index]) < 0) {
this.visibleMonth.unshift(this.state.months[index]);
needUpdate = true;
}
}
}
}
else if (this.state.months.length > 0) {
this.visibleMonth = this.state.months.filter(filterFunc);
needUpdate = true;
}
return needUpdate;
};
this.createOnScroll = () => {
/** @type {?} */
let clientHeight = 0;
/** @type {?} */
let scrollTop = 0;
return (data) => {
const { client, top } = data;
clientHeight = client;
scrollTop = top;
this.computeVisible(clientHeight, scrollTop);
// 以上方法目前无问题,如果后续有性能问题,改用如下方法,但以下方法会导致刷新稍微延迟现象
// if (timer) {
// return;
// }
//
// timer = setTimeout(() => {
// timer = undefined;
//
// if (this.computeVisible(clientHeight, scrollTop)) {
// console.log('update dom');
// }
// }, 50);
};
};
this.baseOnCellClick = (day) => {
if (!day.tick)
return;
this.props.onCellClick && this.props.onCellClick(new Date(day.tick));
};
}
/**
* @return {?}
*/
init() {
const { initalMonths = 6, defaultDate } = this.props;
for (let i = 0; i < initalMonths; i++) {
this.canLoadNext() && this.genMonthData(defaultDate, i);
}
this.visibleMonth = [...this.state.months];
}
/**
* @param {?} oldValue
* @param {?} newValue
* @return {?}
*/
receiveProps(oldValue, newValue) {
if (oldValue && newValue) {
if (oldValue.startDate !== newValue.startDate || oldValue.endDate !== newValue.endDate) {
if (oldValue.startDate) {
this.selectDateRange(oldValue.startDate, oldValue.endDate, true);
}
if (newValue.startDate) {
this.selectDateRange(newValue.startDate, newValue.endDate);
}
}
}
}
/**
* @param {?=} date
* @param {?=} addMonth
* @return {?}
*/
getMonthDate(date = new Date(), addMonth = 0) {
/** @type {?} */
const y = date.getFullYear();
/** @type {?} */
const m = date.getMonth();
return {
firstDate: new Date(y, m + addMonth, 1),
lastDate: new Date(y, m + 1 + addMonth, 0)
};
}
/**
* @return {?}
*/
canLoadPrev() {
const { minDate } = this.props;
return (!minDate ||
this.state.months.length <= 0 ||
+this.getMonthDate(minDate).firstDate < +this.state.months[0].firstDate);
}
/**
* @return {?}
*/
canLoadNext() {
const { maxDate } = this.props;
return (!maxDate ||
this.state.months.length <= 0 ||
+this.getMonthDate(maxDate).firstDate > +this.state.months[this.state.months.length - 1].firstDate);
}
/**
* @param {?=} date
* @param {?=} addMonth
* @return {?}
*/
genMonthData(date, addMonth = 0) {
if (!date) {
date = addMonth >= 0 ? this.state.months[this.state.months.length - 1].firstDate : this.state.months[0].firstDate;
}
if (!date) {
date = new Date();
}
const { locale } = this.props;
const { firstDate, lastDate } = this.getMonthDate(date, addMonth);
/** @type {?} */
const weeks = this.genWeekData(firstDate);
/** @type {?} */
const title = formatDate(firstDate, locale ? locale.monthTitle : 'yyyy/MM', this.props.locale);
/** @type {?} */
const data = /** @type {?} */ ({
title,
firstDate,
lastDate,
weeks
});
data.component = this.genMonthComponent(data);
if (addMonth >= 0) {
this.state.months.push(data);
}
else {
this.state.months.unshift(data);
}
const { startDate, endDate } = this.props;
if (startDate) {
this.selectDateRange(startDate, endDate);
}
return data;
}
/**
* @param {?} date
* @param {?} tick
* @return {?}
*/
inDate(date, tick) {
return date <= tick && tick < date + 24 * 3600000;
}
}
if (false) {
/** @type {?} */
DatePicker.prototype.props;
/** @type {?} */
DatePicker.prototype.state;
/** @type {?} */
DatePicker.prototype.visibleMonth;
/** @type {?} */
DatePicker.prototype.genMonthComponent;
/** @type {?} */
DatePicker.prototype.getDateWithoutTime;
/** @type {?} */
DatePicker.prototype.genWeekData;
/** @type {?} */
DatePicker.prototype.selectDateRange;
/** @type {?} */
DatePicker.prototype.computeVisible;
/** @type {?} */
DatePicker.prototype.createOnScroll;
/** @type {?} */
DatePicker.prototype.baseOnCellClick;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0ZXBpY2tlci5iYXNlLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiJuZzovL25nLXpvcnJvLWFudGQtbW9iaWxlLyIsInNvdXJjZXMiOlsiY2FsZW5kYXIvZGF0ZXBpY2tlci9kYXRlcGlja2VyLmJhc2UuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7QUFBQSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFFM0MsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUNyQyxPQUFPLGFBQWEsTUFBTSxpQkFBaUIsQ0FBQzs7Ozs7OztBQU01QyxNQUFNLENBQUMsT0FBTztJQWlCWjt1Q0FoQlE7WUFDTixTQUFTLEVBQUUsY0FBYztZQUN6QixRQUFRLEVBQUUsS0FBSztZQUNmLFdBQVcsRUFBRSxLQUFLO1lBQ2xCLFdBQVcsRUFBRSxJQUFJLElBQUksRUFBRTtZQUN2QixZQUFZLEVBQUUsQ0FBQztZQUNmLE1BQU0sRUFBRSxhQUFhO1NBQ1Q7cUJBRUQ7WUFDWCxNQUFNLEVBQUUsRUFBRTtTQUNYOzRCQUVrQyxFQUFFO2tDQXFEaEIsQ0FBQyxJQUFXLEVBQUUsRUFBRTtZQUNuQyxJQUFJLENBQUMsSUFBSTtnQkFBRSxPQUFPLENBQUMsQ0FBQztZQUNwQixPQUFPLENBQUMsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxFQUFFLElBQUksQ0FBQyxRQUFRLEVBQUUsRUFBRSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztTQUN2RTsyQkFFYSxDQUFDLFNBQWUsRUFBRSxFQUFFOztZQUNoQyxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQzs7WUFDaEUsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLElBQUksTUFBTSxDQUFDLGlCQUFpQixDQUFDOztZQUU1RixNQUFNLEtBQUssR0FBd0IsRUFBRSxDQUFDOztZQUN0QyxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLFNBQVMsRUFBRSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7O1lBQzVELElBQUksVUFBVSxHQUFHLFNBQVMsQ0FBQzs7WUFDM0IsSUFBSSxXQUFXLEdBQXNCLEVBQUUsQ0FBQztZQUN4QyxLQUFLLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDOztZQUV4QixJQUFJLFlBQVksR0FBRyxVQUFVLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDdkMsSUFBSSxZQUFZLEdBQUcsQ0FBQyxFQUFFO2dCQUNwQixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsWUFBWSxFQUFFLENBQUMsRUFBRSxFQUFFO29CQUNyQyxXQUFXLENBQUMsSUFBSSxtQkFBQyxFQUFxQixFQUFDLENBQUM7aUJBQ3pDO2FBQ0Y7WUFDRCxPQUFPLFVBQVUsR0FBRyxTQUFTLEVBQUU7Z0JBQzdCLElBQUksV0FBVyxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUU7b0JBQzVCLFdBQVcsR0FBRyxFQUFFLENBQUM7b0JBQ2pCLEtBQUssQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7aUJBQ3pCOztnQkFDRCxNQUFNLFVBQVUsR0FBRyxVQUFVLENBQUMsT0FBTyxFQUFFLENBQUM7O2dCQUN4QyxNQUFNLElBQUksR0FBRyxDQUFDLFVBQVUsQ0FBQztnQkFDekIsV0FBVyxDQUFDLElBQUksQ0FBQztvQkFDZixJQUFJO29CQUNKLFVBQVU7b0JBQ1YsUUFBUSxFQUFFLE1BQU0sQ0FBQyxVQUFVLENBQUMsSUFBSTtvQkFDaEMsY0FBYyxFQUFFLFVBQVUsS0FBSyxDQUFDO29CQUNoQyxhQUFhLEVBQUUsS0FBSztvQkFDcEIsU0FBUyxFQUFFLElBQUksR0FBRyxXQUFXLElBQUksSUFBSSxHQUFHLFdBQVc7aUJBQ3BELENBQUMsQ0FBQztnQkFDSCxVQUFVLEdBQUcsSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxHQUFHLElBQUksR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDLENBQUM7YUFDaEU7WUFDRCxXQUFXLENBQUMsV0FBVyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxhQUFhLEdBQUcsSUFBSSxDQUFDO1lBQ3pELE9BQU8sS0FBSyxDQUFDO1NBQ2Q7K0JBb0NpQixDQUFDLFNBQWUsRUFBRSxPQUFjLEVBQUUsS0FBSyxHQUFHLEtBQUssRUFBRSxFQUFFO1lBQ25FLE1BQU0sRUFBRSxZQUFZLEVBQUUsSUFBSSxFQUFFLHNCQUFzQixFQUFFLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQztZQUNsRSxJQUFJLElBQUksS0FBSyxLQUFLLEVBQUU7Z0JBQ2xCLE9BQU8sR0FBRyxTQUFTLENBQUM7YUFDckI7O1lBQ0QsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLGtCQUFrQixDQUFDLFNBQVMsQ0FBQyxDQUNMOztZQUQzQyxNQUNFLEtBQUssR0FBRyxJQUFJLENBQUMsa0JBQWtCLENBQUMsT0FBTyxDQUFDLENBQUM7O1lBQzNDLE1BQU0sYUFBYSxHQUFHLENBQUMsS0FBSyxJQUFJLEtBQUssR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDOztZQUM5RCxNQUFNLFdBQVcsR0FBRyxLQUFLLElBQUksS0FBSyxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUM7O1lBRTNELE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7O1lBQzVFLE1BQU0sWUFBWSxHQUFHLFdBQVcsQ0FBQyxDQUFDLENBQUMsSUFBSSxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUM7O1lBRS9HLElBQUksU0FBUyxHQUFhLEVBQUUsQ0FDUDs7WUFEckIsSUFDRSxVQUFVLEdBQUcsS0FBSyxDQUFDO1lBQ3JCLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTTtpQkFDZCxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUU7Z0JBQ1YsT0FBTyxDQUFDLENBQUMsU0FBUyxJQUFJLGNBQWMsSUFBSSxDQUFDLENBQUMsU0FBUyxJQUFJLFlBQVksQ0FBQzthQUNyRSxDQUFDO2lCQUNELE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRTtnQkFDWCxDQUFDLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUNsQixDQUFDO3FCQUNFLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRTtvQkFDVixJQUFJLENBQUMsV0FBVyxFQUFFO3dCQUNoQixPQUFPLENBQUMsQ0FBQyxJQUFJLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxhQUFhLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDO3FCQUNyRDt5QkFBTTt3QkFDTCxPQUFPLENBQUMsQ0FBQyxJQUFJLElBQUksQ0FBQyxDQUFDLElBQUksSUFBSSxhQUFhLElBQUksQ0FBQyxDQUFDLElBQUksSUFBSSxXQUFXLENBQUM7cUJBQ25FO2lCQUNGLENBQUM7cUJBQ0QsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFOztvQkFDWCxNQUFNLFFBQVEsR0FBRyxDQUFDLENBQUMsUUFBUSxDQUFDO29CQUM1QixJQUFJLEtBQUssRUFBRTt3QkFDVCxDQUFDLENBQUMsUUFBUSxHQUFHLE1BQU0sQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDO3FCQUNyQzt5QkFBTTs7d0JBQ0wsTUFBTSxJQUFJLEdBQUcsQ0FBQyxZQUFZLElBQUksWUFBWSxDQUFDLElBQUksSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDO3dCQUNwRSxJQUFJLENBQUMsQ0FBQyxTQUFTLElBQUksSUFBSSxDQUFDLE9BQU8sRUFBRTs0QkFDL0IsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7eUJBQ3hCO3dCQUNELElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxhQUFhLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFOzRCQUN0QyxJQUFJLElBQUksS0FBSyxLQUFLLEVBQUU7Z0NBQ2xCLENBQUMsQ0FBQyxRQUFRLEdBQUcsTUFBTSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUM7NkJBQ3ZDO2lDQUFNLElBQUksQ0FBQyxXQUFXLEVBQUU7Z0NBQ3ZCLENBQUMsQ0FBQyxRQUFRLEdBQUcsTUFBTSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUM7NkJBQ3JDO2lDQUFNLElBQUksYUFBYSxLQUFLLFdBQVcsRUFBRTtnQ0FDeEMsQ0FBQyxDQUFDLFFBQVEsR0FBRyxNQUFNLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQzs2QkFDdEM7aUNBQU07Z0NBQ0wsQ0FBQyxDQUFDLFFBQVEsR0FBRyxNQUFNLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQzs2QkFDcEM7eUJBQ0Y7NkJBQU0sSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUU7NEJBQzNDLENBQUMsQ0FBQyxRQUFRLEdBQUcsTUFBTSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUM7eUJBQ3BDOzZCQUFNOzRCQUNMLENBQUMsQ0FBQyxRQUFRLEdBQUcsTUFBTSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUM7eUJBQ3ZDO3FCQUNGO29CQUNELFVBQVUsR0FBRyxVQUFVLElBQUksQ0FBQyxDQUFDLFFBQVEsS0FBSyxRQUFRLENBQUM7aUJBQ3BELENBQUMsQ0FDTCxDQUFDO2dCQUNGLElBQUksVUFBVSxJQUFJLENBQUMsQ0FBQyxZQUFZLEVBQUU7b0JBQ2hDLENBQUMsQ0FBQyxZQUFZLENBQUMsV0FBVyxFQUFFLENBQUM7aUJBQzlCO2FBQ0YsQ0FBQyxDQUFDO1lBQ0wsSUFBSSxTQUFTLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRTtnQkFDeEIsSUFBSSxzQkFBc0IsRUFBRTtvQkFDMUIsc0JBQXNCLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztpQkFDL0Q7cUJBQU07b0JBQ0wsT0FBTyxDQUFDLElBQUksQ0FBQywwREFBMEQsRUFBRSxTQUFTLENBQUMsQ0FBQztpQkFDckY7YUFDRjtTQUNGOzhCQUVnQixDQUFDLFlBQW9CLEVBQUUsU0FBaUIsRUFBRSxFQUFFOztZQUMzRCxJQUFJLFVBQVUsR0FBRyxLQUFLLENBQUM7O1lBQ3ZCLE1BQU0sYUFBYSxHQUFHLFlBQVksR0FBRyxDQUFDLENBQUM7O1lBQ3ZDLE1BQU0sYUFBYSxHQUFHLFlBQVksQ0FBQzs7WUFHbkMsTUFBTSxVQUFVLEdBQUcsQ0FBQyxFQUFvQixFQUFFLEVBQUUsQ0FDMUMsRUFBRSxDQUFDLENBQUM7Z0JBQ0osRUFBRSxDQUFDLE1BQU07Z0JBQ1QsQ0FBQyxFQUFFLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxNQUFNLEdBQUcsU0FBUyxHQUFHLGFBQWEsSUFBSSxFQUFFLENBQUMsQ0FBQyxHQUFHLFNBQVMsR0FBRyxZQUFZLEdBQUcsYUFBYSxDQUFDLENBQUM7WUFFcEcsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLFdBQVcsSUFBSSxJQUFJLENBQUMsWUFBWSxDQUFDLE1BQU0sR0FBRyxFQUFFLEVBQUU7Z0JBQzNELElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxHQUFHLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDO2FBQ3RHOztZQUdELElBQUksSUFBSSxDQUFDLFlBQVksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFOztnQkFDaEMsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQztnQkFDN0QsSUFBSSxJQUFJLENBQUMsQ0FBQyxLQUFLLFNBQVMsSUFBSSxJQUFJLENBQUMsTUFBTSxJQUFJLElBQUksQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLE1BQU0sR0FBRyxTQUFTLEdBQUcsWUFBWSxHQUFHLGFBQWEsRUFBRTs7b0JBQzFHLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztvQkFDbEQsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRTs7d0JBQzNCLE1BQU0sS0FBSyxHQUFHLFNBQVMsR0FBRyxDQUFDLENBQUM7d0JBQzVCLElBQUksS0FBSyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLE1BQU0sSUFBSSxJQUFJLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFBRTs0QkFDL0YsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQzt5QkFDbEQ7NkJBQU07NEJBQ0wsSUFBSSxDQUFDLFdBQVcsRUFBRSxJQUFJLElBQUksQ0FBQyxZQUFZLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQyxDQUFDO3lCQUN2RDtxQkFDRjtvQkFDRCxVQUFVLEdBQUcsSUFBSSxDQUFDO2lCQUNuQjs7Z0JBRUQsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQztnQkFDbkMsSUFBSSxLQUFLLENBQUMsQ0FBQyxLQUFLLFNBQVMsSUFBSSxLQUFLLENBQUMsTUFBTSxJQUFJLEtBQUssQ0FBQyxDQUFDLEdBQUcsU0FBUyxHQUFHLGFBQWEsRUFBRTs7b0JBQ2hGLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQztvQkFDcEQsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRTs7d0JBQzNCLE1BQU0sS0FBSyxHQUFHLFVBQVUsR0FBRyxDQUFDLENBQUM7d0JBQzdCLElBQUksS0FBSyxJQUFJLENBQUMsSUFBSSxJQUFJLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFBRTs0QkFDekUsSUFBSSxDQUFDLFlBQVksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQzs0QkFDcEQsVUFBVSxHQUFHLElBQUksQ0FBQzt5QkFDbkI7cUJBQ0Y7aUJBQ0Y7YUFDRjtpQkFBTSxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUU7Z0JBQ3ZDLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDO2dCQUN6RCxVQUFVLEdBQUcsSUFBSSxDQUFDO2FBQ25CO1lBRUQsT0FBTyxVQUFVLENBQUM7U0FDbkI7OEJBRWdCLEdBQUcsRUFBRTs7WUFFcEIsSUFBSSxZQUFZLEdBQUcsQ0FBQyxDQUNKOztZQURoQixJQUNFLFNBQVMsR0FBRyxDQUFDLENBQUM7WUFFaEIsT0FBTyxDQUFDLElBQW1ELEVBQUUsRUFBRTtnQkFDN0QsTUFBTSxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7Z0JBQzdCLFlBQVksR0FBRyxNQUFNLENBQUM7Z0JBQ3RCLFNBQVMsR0FBRyxHQUFHLENBQUM7Z0JBRWhCLElBQUksQ0FBQyxjQUFjLENBQUMsWUFBWSxFQUFFLFNBQVMsQ0FBQyxDQUFDOzs7Ozs7Ozs7Ozs7O2FBZTlDLENBQUM7U0FDSDsrQkFFaUIsQ0FBQyxHQUFvQixFQUFFLEVBQUU7WUFDekMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJO2dCQUFFLE9BQU87WUFDdEIsSUFBSSxDQUFDLEtBQUssQ0FBQyxXQUFXLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsSUFBSSxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7U0FDdEU7S0FyUmU7Ozs7SUFFaEIsSUFBSTtRQUNGLE1BQU0sRUFBRSxZQUFZLEdBQUcsQ0FBQyxFQUFFLFdBQVcsRUFBRSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUM7UUFDckQsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLFlBQVksRUFBRSxDQUFDLEVBQUUsRUFBRTtZQUNyQyxJQUFJLENBQUMsV0FBVyxFQUFFLElBQUksSUFBSSxDQUFDLFlBQVksQ0FBQyxXQUFXLEVBQUUsQ0FBQyxDQUFDLENBQUM7U0FDekQ7UUFDRCxJQUFJLENBQUMsWUFBWSxHQUFHLENBQUMsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0tBQzVDOzs7Ozs7SUFFRCxZQUFZLENBQUMsUUFBbUIsRUFBRSxRQUFtQjtRQUNuRCxJQUFJLFFBQVEsSUFBSSxRQUFRLEVBQUU7WUFDeEIsSUFBSSxRQUFRLENBQUMsU0FBUyxLQUFLLFFBQVEsQ0FBQyxTQUFTLElBQUksUUFBUSxDQUFDLE9BQU8sS0FBSyxRQUFRLENBQUMsT0FBTyxFQUFFO2dCQUN0RixJQUFJLFFBQVEsQ0FBQyxTQUFTLEVBQUU7b0JBQ3RCLElBQUksQ0FBQyxlQUFlLENBQUMsUUFBUSxDQUFDLFNBQVMsRUFBRSxRQUFRLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxDQUFDO2lCQUNsRTtnQkFDRCxJQUFJLFFBQVEsQ0FBQyxTQUFTLEVBQUU7b0JBQ3RCLElBQUksQ0FBQyxlQUFlLENBQUMsUUFBUSxDQUFDLFNBQVMsRUFBRSxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUM7aUJBQzVEO2FBQ0Y7U0FDRjtLQUNGOzs7Ozs7SUFFRCxZQUFZLENBQUMsSUFBSSxHQUFHLElBQUksSUFBSSxFQUFFLEVBQUUsUUFBUSxHQUFHLENBQUM7O1FBQzFDLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FDTjs7UUFEdEIsTUFDRSxDQUFDLEdBQUcsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQ3RCLE9BQU87WUFDTCxTQUFTLEVBQUUsSUFBSSxJQUFJLENBQUMsQ0FBQyxFQUFFLENBQUMsR0FBRyxRQUFRLEVBQUUsQ0FBQyxDQUFDO1lBQ3ZDLFFBQVEsRUFBRSxJQUFJLElBQUksQ0FBQyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxRQUFRLEVBQUUsQ0FBQyxDQUFDO1NBQzNDLENBQUM7S0FDSDs7OztJQUVELFdBQVc7UUFDVCxNQUFNLEVBQUUsT0FBTyxFQUFFLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQztRQUMvQixPQUFPLENBQ0wsQ0FBQyxPQUFPO1lBQ1IsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsTUFBTSxJQUFJLENBQUM7WUFDN0IsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxDQUFDLFNBQVMsR0FBRyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FDeEUsQ0FBQztLQUNIOzs7O0lBRUQsV0FBVztRQUNULE1BQU0sRUFBRSxPQUFPLEVBQUUsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDO1FBQy9CLE9BQU8sQ0FDTCxDQUFDLE9BQU87WUFDUixJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxNQUFNLElBQUksQ0FBQztZQUM3QixDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLENBQUMsU0FBUyxHQUFHLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FDbkcsQ0FBQztLQUNIOzs7Ozs7SUE0Q0QsWUFBWSxDQUFDLElBQVcsRUFBRSxXQUFtQixDQUFDO1FBQzVDLElBQUksQ0FBQyxJQUFJLEVBQUU7WUFDVCxJQUFJLEdBQUcsUUFBUSxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO1NBQ25IO1FBQ0QsSUFBSSxDQUFDLElBQUksRUFBRTtZQUNULElBQUksR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDO1NBQ25CO1FBQ0QsTUFBTSxFQUFFLE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUM7UUFDOUIsTUFBTSxFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksRUFBRSxRQUFRLENBQUMsQ0FBQzs7UUFDbEUsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxTQUFTLENBQUMsQ0FBQzs7UUFDMUMsTUFBTSxLQUFLLEdBQUcsVUFBVSxDQUFDLFNBQVMsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDOztRQUMvRixNQUFNLElBQUkscUJBQUc7WUFDWCxLQUFLO1lBQ0wsU0FBUztZQUNULFFBQVE7WUFDUixLQUFLO1NBQ2MsRUFBQztRQUN0QixJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUM5QyxJQUFJLFFBQVEsSUFBSSxDQUFDLEVBQUU7WUFDakIsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1NBQzlCO2FBQU07WUFDTCxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7U0FDakM7UUFDRCxNQUFNLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBRSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUM7UUFDMUMsSUFBSSxTQUFTLEVBQUU7WUFDYixJQUFJLENBQUMsZUFBZSxDQUFDLFNBQVMsRUFBRSxPQUFPLENBQUMsQ0FBQztTQUMxQztRQUNELE9BQU8sSUFBSSxDQUFDO0tBQ2I7Ozs7OztJQUVELE1BQU0sQ0FBQyxJQUFZLEVBQUUsSUFBWTtRQUMvQixPQUFPLElBQUksSUFBSSxJQUFJLElBQUksSUFBSSxHQUFHLElBQUksR0FBRyxFQUFFLEdBQUcsT0FBTyxDQUFDO0tBQ25EO0NBMkpGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgTW9kZWxzIH0gZnJvbSAnLi4vZGF0ZS9EYXRhVHlwZXMnO1xuaW1wb3J0IFByb3BzVHlwZSBmcm9tICcuL2RhdGVwaWNrZXIucHJvcHMuY29tcG9uZW50JztcbmltcG9ydCB7IGZvcm1hdERhdGUgfSBmcm9tICcuLi91dGlsJztcbmltcG9ydCBkZWZhdWx0TG9jYWxlIGZyb20gJy4uL2xvY2FsZS96aF9DTic7XG5cbmV4cG9ydCBpbnRlcmZhY2UgU3RhdGVUeXBlIHtcbiAgbW9udGhzOiBNb2RlbHMuTW9udGhEYXRhW107XG59XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIERhdGVQaWNrZXIge1xuICBwcm9wcyA9IHtcbiAgICBwcmVmaXhDbHM6ICdybWMtY2FsZW5kYXInLFxuICAgIGluZmluaXRlOiBmYWxzZSxcbiAgICBpbmZpbml0ZU9wdDogZmFsc2UsXG4gICAgZGVmYXVsdERhdGU6IG5ldyBEYXRlKCksXG4gICAgaW5pdGFsTW9udGhzOiA2LFxuICAgIGxvY2FsZTogZGVmYXVsdExvY2FsZVxuICB9IGFzIFByb3BzVHlwZTtcblxuICBzdGF0ZTogYW55ID0ge1xuICAgIG1vbnRoczogW11cbiAgfTtcblxuICB2aXNpYmxlTW9udGg6IE1vZGVscy5Nb250aERhdGFbXSA9IFtdO1xuICBnZW5Nb250aENvbXBvbmVudDogKGRhdGEpID0+IHt9O1xuXG4gIGNvbnN0cnVjdG9yKCkge31cblxuICBpbml0KCkge1xuICAgIGNvbnN0IHsgaW5pdGFsTW9udGhzID0gNiwgZGVmYXVsdERhdGUgfSA9IHRoaXMucHJvcHM7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBpbml0YWxNb250aHM7IGkrKykge1xuICAgICAgdGhpcy5jYW5Mb2FkTmV4dCgpICYmIHRoaXMuZ2VuTW9udGhEYXRhKGRlZmF1bHREYXRlLCBpKTtcbiAgICB9XG4gICAgdGhpcy52aXNpYmxlTW9udGggPSBbLi4udGhpcy5zdGF0ZS5tb250aHNdO1xuICB9XG5cbiAgcmVjZWl2ZVByb3BzKG9sZFZhbHVlOiBQcm9wc1R5cGUsIG5ld1ZhbHVlOiBQcm9wc1R5cGUpIHtcbiAgICBpZiAob2xkVmFsdWUgJiYgbmV3VmFsdWUpIHtcbiAgICAgIGlmIChvbGRWYWx1ZS5zdGFydERhdGUgIT09IG5ld1ZhbHVlLnN0YXJ0RGF0ZSB8fCBvbGRWYWx1ZS5lbmREYXRlICE9PSBuZXdWYWx1ZS5lbmREYXRlKSB7XG4gICAgICAgIGlmIChvbGRWYWx1ZS5zdGFydERhdGUpIHtcbiAgICAgICAgICB0aGlzLnNlbGVjdERhdGVSYW5nZShvbGRWYWx1ZS5zdGFydERhdGUsIG9sZFZhbHVlLmVuZERhdGUsIHRydWUpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChuZXdWYWx1ZS5zdGFydERhdGUpIHtcbiAgICAgICAgICB0aGlzLnNlbGVjdERhdGVSYW5nZShuZXdWYWx1ZS5zdGFydERhdGUsIG5ld1ZhbHVlLmVuZERhdGUpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgZ2V0TW9udGhEYXRlKGRhdGUgPSBuZXcgRGF0ZSgpLCBhZGRNb250aCA9IDApIHtcbiAgICBjb25zdCB5ID0gZGF0ZS5nZXRGdWxsWWVhcigpLFxuICAgICAgbSA9IGRhdGUuZ2V0TW9udGgoKTtcbiAgICByZXR1cm4ge1xuICAgICAgZmlyc3REYXRlOiBuZXcgRGF0ZSh5LCBtICsgYWRkTW9udGgsIDEpLFxuICAgICAgbGFzdERhdGU6IG5ldyBEYXRlKHksIG0gKyAxICsgYWRkTW9udGgsIDApXG4gICAgfTtcbiAgfVxuXG4gIGNhbkxvYWRQcmV2KCkge1xuICAgIGNvbnN0IHsgbWluRGF0ZSB9ID0gdGhpcy5wcm9wcztcbiAgICByZXR1cm4gKFxuICAgICAgIW1pbkRhdGUgfHxcbiAgICAgIHRoaXMuc3RhdGUubW9udGhzLmxlbmd0aCA8PSAwIHx8XG4gICAgICArdGhpcy5nZXRNb250aERhdGUobWluRGF0ZSkuZmlyc3REYXRlIDwgK3RoaXMuc3RhdGUubW9udGhzWzBdLmZpcnN0RGF0ZVxuICAgICk7XG4gIH1cblxuICBjYW5Mb2FkTmV4dCgpIHtcbiAgICBjb25zdCB7IG1heERhdGUgfSA9IHRoaXMucHJvcHM7XG4gICAgcmV0dXJuIChcbiAgICAgICFtYXhEYXRlIHx8XG4gICAgICB0aGlzLnN0YXRlLm1vbnRocy5sZW5ndGggPD0gMCB8fFxuICAgICAgK3RoaXMuZ2V0TW9udGhEYXRlKG1heERhdGUpLmZpcnN0RGF0ZSA+ICt0aGlzLnN0YXRlLm1vbnRoc1t0aGlzLnN0YXRlLm1vbnRocy5sZW5ndGggLSAxXS5maXJzdERhdGVcbiAgICApO1xuICB9XG5cbiAgZ2V0RGF0ZVdpdGhvdXRUaW1lID0gKGRhdGU/OiBEYXRlKSA9PiB7XG4gICAgaWYgKCFkYXRlKSByZXR1cm4gMDtcbiAgICByZXR1cm4gK25ldyBEYXRlKGRhdGUuZ2V0RnVsbFllYXIoKSwgZGF0ZS5nZXRNb250aCgpLCBkYXRlLmdldERhdGUoKSk7XG4gIH07XG5cbiAgZ2VuV2Vla0RhdGEgPSAoZmlyc3REYXRlOiBEYXRlKSA9PiB7XG4gICAgY29uc3QgbWluRGF0ZVRpbWUgPSB0aGlzLmdldERhdGVXaXRob3V0VGltZSh0aGlzLnByb3BzLm1pbkRhdGUpO1xuICAgIGNvbnN0IG1heERhdGVUaW1lID0gdGhpcy5nZXREYXRlV2l0aG91dFRpbWUodGhpcy5wcm9wcy5tYXhEYXRlKSB8fCBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFk7XG5cbiAgICBjb25zdCB3ZWVrczogTW9kZWxzLkNlbGxEYXRhW11bXSA9IFtdO1xuICAgIGNvbnN0IG5leHRNb250aCA9IHRoaXMuZ2V0TW9udGhEYXRlKGZpcnN0RGF0ZSwgMSkuZmlyc3REYXRlO1xuICAgIGxldCBjdXJyZW50RGF5ID0gZmlyc3REYXRlO1xuICAgIGxldCBjdXJyZW50V2VlazogTW9kZWxzLkNlbGxEYXRhW10gPSBbXTtcbiAgICB3ZWVrcy5wdXNoKGN1cnJlbnRXZWVrKTtcblxuICAgIGxldCBzdGFydFdlZWtkYXkgPSBjdXJyZW50RGF5LmdldERheSgpO1xuICAgIGlmIChzdGFydFdlZWtkYXkgPiAwKSB7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHN0YXJ0V2Vla2RheTsgaSsrKSB7XG4gICAgICAgIGN1cnJlbnRXZWVrLnB1c2goe30gYXMgTW9kZWxzLkNlbGxEYXRhKTtcbiAgICAgIH1cbiAgICB9XG4gICAgd2hpbGUgKGN1cnJlbnREYXkgPCBuZXh0TW9udGgpIHtcbiAgICAgIGlmIChjdXJyZW50V2Vlay5sZW5ndGggPT09IDcpIHtcbiAgICAgICAgY3VycmVudFdlZWsgPSBbXTtcbiAgICAgICAgd2Vla3MucHVzaChjdXJyZW50V2Vlayk7XG4gICAgICB9XG4gICAgICBjb25zdCBkYXlPZk1vbnRoID0gY3VycmVudERheS5nZXREYXRlKCk7XG4gICAgICBjb25zdCB0aWNrID0gK2N1cnJlbnREYXk7XG4gICAgICBjdXJyZW50V2Vlay5wdXNoKHtcbiAgICAgICAgdGljayxcbiAgICAgICAgZGF5T2ZNb250aCxcbiAgICAgICAgc2VsZWN0ZWQ6IE1vZGVscy5TZWxlY3RUeXBlLk5vbmUsXG4gICAgICAgIGlzRmlyc3RPZk1vbnRoOiBkYXlPZk1vbnRoID09PSAxLFxuICAgICAgICBpc0xhc3RPZk1vbnRoOiBmYWxzZSxcbiAgICAgICAgb3V0T2ZEYXRlOiB0aWNrIDwgbWluRGF0ZVRpbWUgfHwgdGljayA+IG1heERhdGVUaW1lXG4gICAgICB9KTtcbiAgICAgIGN1cnJlbnREYXkgPSBuZXcgRGF0ZShjdXJyZW50RGF5LmdldFRpbWUoKSArIDM2MDAgKiAyNCAqIDEwMDApO1xuICAgIH1cbiAgICBjdXJyZW50V2Vla1tjdXJyZW50V2Vlay5sZW5ndGggLSAxXS5pc0xhc3RPZk1vbnRoID0gdHJ1ZTtcbiAgICByZXR1cm4gd2Vla3M7XG4gIH07XG5cbiAgZ2VuTW9udGhEYXRhKGRhdGU/OiBEYXRlLCBhZGRNb250aDogbnVtYmVyID0gMCkge1xuICAgIGlmICghZGF0ZSkge1xuICAgICAgZGF0ZSA9IGFkZE1vbnRoID49IDAgPyB0aGlzLnN0YXRlLm1vbnRoc1t0aGlzLnN0YXRlLm1vbnRocy5sZW5ndGggLSAxXS5maXJzdERhdGUgOiB0aGlzLnN0YXRlLm1vbnRoc1swXS5maXJzdERhdGU7XG4gICAgfVxuICAgIGlmICghZGF0ZSkge1xuICAgICAgZGF0ZSA9IG5ldyBEYXRlKCk7XG4gICAgfVxuICAgIGNvbnN0IHsgbG9jYWxlIH0gPSB0aGlzLnByb3BzO1xuICAgIGNvbnN0IHsgZmlyc3REYXRlLCBsYXN0RGF0ZSB9ID0gdGhpcy5nZXRNb250aERhdGUoZGF0ZSwgYWRkTW9udGgpO1xuICAgIGNvbnN0IHdlZWtzID0gdGhpcy5nZW5XZWVrRGF0YShmaXJzdERhdGUpO1xuICAgIGNvbnN0IHRpdGxlID0gZm9ybWF0RGF0ZShmaXJzdERhdGUsIGxvY2FsZSA/IGxvY2FsZS5tb250aFRpdGxlIDogJ3l5eXkvTU0nLCB0aGlzLnByb3BzLmxvY2FsZSk7XG4gICAgY29uc3QgZGF0YSA9IHtcbiAgICAgIHRpdGxlLFxuICAgICAgZmlyc3REYXRlLFxuICAgICAgbGFzdERhdGUsXG4gICAgICB3ZWVrc1xuICAgIH0gYXMgTW9kZWxzLk1vbnRoRGF0YTtcbiAgICBkYXRhLmNvbXBvbmVudCA9IHRoaXMuZ2VuTW9udGhDb21wb25lbnQoZGF0YSk7XG4gICAgaWYgKGFkZE1vbnRoID49IDApIHtcbiAgICAgIHRoaXMuc3RhdGUubW9udGhzLnB1c2goZGF0YSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuc3RhdGUubW9udGhzLnVuc2hpZnQoZGF0YSk7XG4gICAgfVxuICAgIGNvbnN0IHsgc3RhcnREYXRlLCBlbmREYXRlIH0gPSB0aGlzLnByb3BzO1xuICAgIGlmIChzdGFydERhdGUpIHtcbiAgICAgIHRoaXMuc2VsZWN0RGF0ZVJhbmdlKHN0YXJ0RGF0ZSwgZW5kRGF0ZSk7XG4gICAgfVxuICAgIHJldHVybiBkYXRhO1xuICB9XG5cbiAgaW5EYXRlKGRhdGU6IG51bWJlciwgdGljazogbnVtYmVyKSB7XG4gICAgcmV0dXJuIGRhdGUgPD0gdGljayAmJiB0aWNrIDwgZGF0ZSArIDI0ICogMzYwMDAwMDtcbiAgfVxuXG4gIHNlbGVjdERhdGVSYW5nZSA9IChzdGFydERhdGU6IERhdGUsIGVuZERhdGU/OiBEYXRlLCBjbGVhciA9IGZhbHNlKSA9PiB7XG4gICAgY29uc3QgeyBnZXREYXRlRXh0cmEsIHR5cGUsIG9uU2VsZWN0SGFzRGlzYWJsZURhdGUgfSA9IHRoaXMucHJvcHM7XG4gICAgaWYgKHR5cGUgPT09ICdvbmUnKSB7XG4gICAgICBlbmREYXRlID0gdW5kZWZpbmVkO1xuICAgIH1cbiAgICBjb25zdCB0aW1lMSA9IHRoaXMuZ2V0RGF0ZVdpdGhvdXRUaW1lKHN0YXJ0RGF0ZSksXG4gICAgICB0aW1lMiA9IHRoaXMuZ2V0RGF0ZVdpdGhvdXRUaW1lKGVuZERhdGUpO1xuICAgIGNvbnN0IHN0YXJ0RGF0ZVRpY2sgPSAhdGltZTIgfHwgdGltZTEgPCB0aW1lMiA/IHRpbWUxIDogdGltZTI7XG4gICAgY29uc3QgZW5kRGF0ZVRpY2sgPSB0aW1lMiAmJiB0aW1lMSA+IHRpbWUyID8gdGltZTEgOiB0aW1lMjtcblxuICAgIGNvbnN0IHN0YXJ0TW9udGhEYXRlID0gdGhpcy5nZXRNb250aERhdGUobmV3IERhdGUoc3RhcnREYXRlVGljaykpLmZpcnN0RGF0ZTtcbiAgICBjb25zdCBlbmRNb250aERhdGUgPSBlbmREYXRlVGljayA/IG5ldyBEYXRlKGVuZERhdGVUaWNrKSA6IHRoaXMuZ2V0TW9udGhEYXRlKG5ldyBEYXRlKHN0YXJ0RGF0ZVRpY2spKS5sYXN0RGF0ZTtcblxuICAgIGxldCB1bnVzZWFibGU6IG51bWJlcltdID0gW10sXG4gICAgICBuZWVkVXBkYXRlID0gZmFsc2U7XG4gICAgdGhpcy5zdGF0ZS5tb250aHNcbiAgICAgIC5maWx0ZXIobSA9PiB7XG4gICAgICAgIHJldHVybiBtLmZpcnN0RGF0ZSA+PSBzdGFydE1vbnRoRGF0ZSAmJiBtLmZpcnN0RGF0ZSA8PSBlbmRNb250aERhdGU7XG4gICAgICB9KVxuICAgICAgLmZvckVhY2gobSA9PiB7XG4gICAgICAgIG0ud2Vla3MuZm9yRWFjaCh3ID0+XG4gICAgICAgICAgd1xuICAgICAgICAgICAgLmZpbHRlcihkID0+IHtcbiAgICAgICAgICAgICAgaWYgKCFlbmREYXRlVGljaykge1xuICAgICAgICAgICAgICAgIHJldHVybiBkLnRpY2sgJiYgdGhpcy5pbkRhdGUoc3RhcnREYXRlVGljaywgZC50aWNrKTtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZC50aWNrICYmIGQudGljayA+PSBzdGFydERhdGVUaWNrICYmIGQudGljayA8PSBlbmREYXRlVGljaztcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIC5mb3JFYWNoKGQgPT4ge1xuICAgICAgICAgICAgICBjb25zdCBvbGRWYWx1ZSA9IGQuc2VsZWN0ZWQ7XG4gICAgICAgICAgICAgIGlmIChjbGVhcikge1xuICAgICAgICAgICAgICAgIGQuc2VsZWN0ZWQgPSBNb2RlbHMuU2VsZWN0VHlwZS5Ob25lO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGNvbnN0IGluZm8gPSAoZ2V0RGF0ZUV4dHJhICYmIGdldERhdGVFeHRyYShuZXcgRGF0ZShkLnRpY2spKSkgfHwge307XG4gICAgICAgICAgICAgICAgaWYgKGQub3V0T2ZEYXRlIHx8IGluZm8uZGlzYWJsZSkge1xuICAgICAgICAgICAgICAgICAgdW51c2VhYmxlLnB1c2goZC50aWNrKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuaW5EYXRlKHN0YXJ0RGF0ZVRpY2ssIGQudGljaykpIHtcbiAgICAgICAgICAgICAgICAgIGlmICh0eXBlID09PSAnb25lJykge1xuICAgICAgICAgICAgICAgICAgICBkLnNlbGVjdGVkID0gTW9kZWxzLlNlbGVjdFR5cGUuU2luZ2xlO1xuICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmICghZW5kRGF0ZVRpY2spIHtcbiAgICAgICAgICAgICAgICAgICAgZC5zZWxlY3RlZCA9IE1vZGVscy5TZWxlY3RUeXBlLk9ubHk7XG4gICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHN0YXJ0RGF0ZVRpY2sgIT09IGVuZERhdGVUaWNrKSB7XG4gICAgICAgICAgICAgICAgICAgIGQuc2VsZWN0ZWQgPSBNb2RlbHMuU2VsZWN0VHlwZS5TdGFydDtcbiAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGQuc2VsZWN0ZWQgPSBNb2RlbHMuU2VsZWN0VHlwZS5BbGw7XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmICh0aGlzLmluRGF0ZShlbmREYXRlVGljaywgZC50aWNrKSkge1xuICAgICAgICAgICAgICAgICAgZC5zZWxlY3RlZCA9IE1vZGVscy5TZWxlY3RUeXBlLkVuZDtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgZC5zZWxlY3RlZCA9IE1vZGVscy5TZWxlY3RUeXBlLk1pZGRsZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgbmVlZFVwZGF0ZSA9IG5lZWRVcGRhdGUgfHwgZC5zZWxlY3RlZCAhPT0gb2xkVmFsdWU7XG4gICAgICAgICAgICB9KVxuICAgICAgICApO1xuICAgICAgICBpZiAobmVlZFVwZGF0ZSAmJiBtLmNvbXBvbmVudFJlZikge1xuICAgICAgICAgIG0uY29tcG9uZW50UmVmLnVwZGF0ZVdlZWtzKCk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIGlmICh1bnVzZWFibGUubGVuZ3RoID4gMCkge1xuICAgICAgaWYgKG9uU2VsZWN0SGFzRGlzYWJsZURhdGUpIHtcbiAgICAgICAgb25TZWxlY3RIYXNEaXNhYmxlRGF0ZSh1bnVzZWFibGUubWFwKHRpY2sgPT4gbmV3IERhdGUodGljaykpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnNvbGUud2FybignVW51c2FibGUgZGF0ZS4gWW91IGNhbiBoYW5kbGUgYnkgb25TZWxlY3RIYXNEaXNhYmxlRGF0ZS4nLCB1bnVzZWFibGUpO1xuICAgICAgfVxuICAgIH1cbiAgfTtcblxuICBjb21wdXRlVmlzaWJsZSA9IChjbGllbnRIZWlnaHQ6IG51bWJlciwgc2Nyb2xsVG9wOiBudW1iZXIpID0+IHtcbiAgICBsZXQgbmVlZFVwZGF0ZSA9IGZhbHNlO1xuICAgIGNvbnN0IE1BWF9WSUVXX1BPUlQgPSBjbGllbnRIZWlnaHQgKiAyO1xuICAgIGNvbnN0IE1JTl9WSUVXX1BPUlQgPSBjbGllbnRIZWlnaHQ7XG5cbiAgICAvLyDlpKfnvJPlhrLljLrlpJbov4fmu6Top4TliJlcbiAgICBjb25zdCBmaWx0ZXJGdW5jID0gKHZtOiBNb2RlbHMuTW9udGhEYXRhKSA9PlxuICAgICAgdm0ueSAmJlxuICAgICAgdm0uaGVpZ2h0ICYmXG4gICAgICAodm0ueSArIHZtLmhlaWdodCA+IHNjcm9sbFRvcCAtIE1BWF9WSUVXX1BPUlQgJiYgdm0ueSA8IHNjcm9sbFRvcCArIGNsaWVudEhlaWdodCArIE1BWF9WSUVXX1BPUlQpO1xuXG4gICAgaWYgKHRoaXMucHJvcHMuaW5maW5pdGVPcHQgJiYgdGhpcy52aXNpYmxlTW9udGgubGVuZ3RoID4gMTIpIHtcbiAgICAgIHRoaXMudmlzaWJsZU1vbnRoID0gdGhpcy52aXNpYmxlTW9udGguZmlsdGVyKGZpbHRlckZ1bmMpLnNvcnQoKGEsIGIpID0+ICthLmZpcnN0RGF0ZSAtICtiLmZpcnN0RGF0ZSk7XG4gICAgfVxuXG4gICAgLy8g5b2T5bCP57yT5Yay5Yy65LiN5ruh5pe25aGr5YWFXG4gICAgaWYgKHRoaXMudmlzaWJsZU1vbnRoLmxlbmd0aCA+IDApIHtcbiAgICAgIGNvbnN0IGxhc3QgPSB0aGlzLnZpc2libGVNb250aFt0aGlzLnZpc2libGVNb250aC5sZW5ndGggLSAxXTtcbiAgICAgIGlmIChsYXN0LnkgIT09IHVuZGVmaW5lZCAmJiBsYXN0LmhlaWdodCAmJiBsYXN0LnkgKyBsYXN0LmhlaWdodCA8IHNjcm9sbFRvcCArIGNsaWVudEhlaWdodCArIE1JTl9WSUVXX1BPUlQpIHtcbiAgICAgICAgY29uc3QgbGFzdEluZGV4ID0gdGhpcy5zdGF0ZS5tb250aHMuaW5kZXhPZihsYXN0KTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDE7IGkgPD0gMjsgaSsrKSB7XG4gICAgICAgICAgY29uc3QgaW5kZXggPSBsYXN0SW5kZXggKyBpO1xuICAgICAgICAgIGlmIChpbmRleCA8IHRoaXMuc3RhdGUubW9udGhzLmxlbmd0aCAmJiB0aGlzLnZpc2libGVNb250aC5pbmRleE9mKHRoaXMuc3RhdGUubW9udGhzW2luZGV4XSkgPCAwKSB7XG4gICAgICAgICAgICB0aGlzLnZpc2libGVNb250aC5wdXNoKHRoaXMuc3RhdGUubW9udGhzW2luZGV4XSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuY2FuTG9hZE5leHQoKSAmJiB0aGlzLmdlbk1vbnRoRGF0YSh1bmRlZmluZWQsIDEpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBuZWVkVXBkYXRlID0gdHJ1ZTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZmlyc3QgPSB0aGlzLnZpc2libGVNb250aFswXTtcbiAgICAgIGlmIChmaXJzdC55ICE9PSB1bmRlZmluZWQgJiYgZmlyc3QuaGVpZ2h0ICYmIGZpcnN0LnkgPiBzY3JvbGxUb3AgLSBNSU5fVklFV19QT1JUKSB7XG4gICAgICAgIGNvbnN0IGZpcnN0SW5kZXggPSB0aGlzLnN0YXRlLm1vbnRocy5pbmRleE9mKGZpcnN0KTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDE7IGkgPD0gMjsgaSsrKSB7XG4gICAgICAgICAgY29uc3QgaW5kZXggPSBmaXJzdEluZGV4IC0gaTtcbiAgICAgICAgICBpZiAoaW5kZXggPj0gMCAmJiB0aGlzLnZpc2libGVNb250aC5pbmRleE9mKHRoaXMuc3RhdGUubW9udGhzW2luZGV4XSkgPCAwKSB7XG4gICAgICAgICAgICB0aGlzLnZpc2libGVNb250aC51bnNoaWZ0KHRoaXMuc3RhdGUubW9udGhzW2luZGV4XSk7XG4gICAgICAgICAgICBuZWVkVXBkYXRlID0gdHJ1ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKHRoaXMuc3RhdGUubW9udGhzLmxlbmd0aCA+IDApIHtcbiAgICAgIHRoaXMudmlzaWJsZU1vbnRoID0gdGhpcy5zdGF0ZS5tb250aHMuZmlsdGVyKGZpbHRlckZ1bmMpO1xuICAgICAgbmVlZFVwZGF0ZSA9IHRydWU7XG4gICAgfVxuXG4gICAgcmV0dXJuIG5lZWRVcGRhdGU7XG4gIH07XG5cbiAgY3JlYXRlT25TY3JvbGwgPSAoKSA9PiB7XG4gICAgLy8gbGV0IHRpbWVyOiBhbnk7XG4gICAgbGV0IGNsaWVudEhlaWdodCA9IDAsXG4gICAgICBzY3JvbGxUb3AgPSAwO1xuXG4gICAgcmV0dXJuIChkYXRhOiB7IGZ1bGw6IG51bWJlcjsgY2xpZW50OiBudW1iZXI7IHRvcDogbnVtYmVyIH0pID0+IHtcbiAgICAgIGNvbnN0IHsgY2xpZW50LCB0b3AgfSA9IGRhdGE7XG4gICAgICBjbGllbnRIZWlnaHQgPSBjbGllbnQ7XG4gICAgICBzY3JvbGxUb3AgPSB0b3A7XG5cbiAgICAgIHRoaXMuY29tcHV0ZVZpc2libGUoY2xpZW50SGVpZ2h0LCBzY3JvbGxUb3ApO1xuXG4gICAgICAvLyDku6XkuIrmlrnms5Xnm67liY3ml6Dpl67popjvvIzlpoLmnpzlkI7nu63mnInmgKfog73pl67popjvvIzmlLnnlKjlpoLkuIvmlrnms5XvvIzkvYbku6XkuIvmlrnms5XkvJrlr7zoh7TliLfmlrDnqI3lvq7lu7bov5/njrDosaFcblxuICAgICAgLy8gaWYgKHRpbWVyKSB7XG4gICAgICAvLyAgIHJldHVybjtcbiAgICAgIC8vIH1cbiAgICAgIC8vXG4gICAgICAvLyB0aW1lciA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgLy8gICB0aW1lciA9IHVuZGVmaW5lZDtcbiAgICAgIC8vXG4gICAgICAvLyAgIGlmICh0aGlzLmNvbXB1dGVWaXNpYmxlKGNsaWVudEhlaWdodCwgc2Nyb2xsVG9wKSkge1xuICAgICAgLy8gICAgIGNvbnNvbGUubG9nKCd1cGRhdGUgZG9tJyk7XG4gICAgICAvLyAgIH1cbiAgICAgIC8vIH0sIDUwKTtcbiAgICB9O1xuICB9O1xuXG4gIGJhc2VPbkNlbGxDbGljayA9IChkYXk6IE1vZGVscy5DZWxsRGF0YSkgPT4ge1xuICAgIGlmICghZGF5LnRpY2spIHJldHVybjtcbiAgICB0aGlzLnByb3BzLm9uQ2VsbENsaWNrICYmIHRoaXMucHJvcHMub25DZWxsQ2xpY2sobmV3IERhdGUoZGF5LnRpY2spKTtcbiAgfTtcblxufVxuIl19