moh-common-lib
Version:
A library of Angular components, services, and styles for B.C. Government Ministry of Health (MoH).
472 lines (470 loc) • 48.2 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
import { Component, Input, Output, EventEmitter, Optional, Self, Inject } from '@angular/core';
import { NgControl, NG_VALIDATORS } from '@angular/forms';
import { LabelReplacementTag } from '../../models/error-message.interface';
import getDaysInMonth from 'date-fns/getDaysInMonth';
import isAfter from 'date-fns/isAfter';
import isBefore from 'date-fns/isBefore';
import startOfToday from 'date-fns/startOfToday';
import addYears from 'date-fns/addYears';
import subYears from 'date-fns/subYears';
import { MoHCommonLibraryError } from '../../../helpers/library-error';
import { AbstractFormControl } from '../../models/abstract-form-control';
import { compareAsc, startOfDay, addDays } from 'date-fns';
/**
* DateComponent
* You cannot use "[restrictDate]" in combination with either "[dateRangeEnd]" or "[dateRangeStart]".
* You must use either [restrictDate] or the [dateRange*] inputs.
*
* \@example
* To trigger 'no future dates allowed' using date ranges set the range end date to yesterday's date.
* <common-date name='effectiveDate'
* label="Effective Date"
* [dateRangeEnd]='yesterday'
* formControlName="effectiveDate"></common-date>
* '
* To trigger 'no past dates allowed' using date ranges set the range start date to today's date.
* <common-date name='effectiveDate'
* label="Effective Date"
* [dateRangeStart]="today"
* formControlName="effectiveDate"></common-date>
*
* To allow instructions under label.
* <common-date name='effectiveDate'
* label="Effective Date"
* [dateRangeEnd]='yesterday'
* formControlName="effectiveDate">
* <p>This is a test.</p>
* </common-date>
* @export
*
* @type {?}
*/
const MAX_YEAR_RANGE = 150;
/** @type {?} */
const distantFuture = addYears(startOfToday(), MAX_YEAR_RANGE);
/** @type {?} */
const distantPast = subYears(startOfToday(), MAX_YEAR_RANGE);
export class DateComponent extends AbstractFormControl {
// TODO: remove if not required - value does not get set when using Reactive forms
/**
* @param {?} controlDir
* @param {?} injectedValidators
*/
constructor(controlDir, injectedValidators) {
super();
this.controlDir = controlDir;
this.injectedValidators = injectedValidators;
this.dateChange = new EventEmitter();
this.label = 'Date';
/**
* Can be one of: "future", "past". "future" includes today, "past" does not.
*/
this.restrictDate = 'any';
this._month = 'null'; // this makes it so the blank option is selected in the input
// variables for date ranges
this._dateRangeStart = null;
this._dateRangeEnd = null;
this.monthList = [
'January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December'
];
this.monthLabelforId = 'month_' + this.objectId;
this.dayLabelforId = 'day_' + this.objectId;
this.yearLabelforId = 'year_' + this.objectId;
// Abstact variable defined
this._defaultErrMsg = {
required: `${LabelReplacementTag} is required.`,
dayOutOfRange: `Invalid ${LabelReplacementTag}.`,
yearDistantPast: `Invalid ${LabelReplacementTag}.`,
yearDistantFuture: `Invalid ${LabelReplacementTag}.`,
noPastDatesAllowed: `Invalid ${LabelReplacementTag}.`,
noFutureDatesAllowed: `Invalid ${LabelReplacementTag}.`,
invalidValue: `Invalid ${LabelReplacementTag}.`,
invalidRange: `Invalid ${LabelReplacementTag}.`
};
this.today = startOfToday();
this.tomorrow = addDays(this.today, 1);
if (controlDir) {
controlDir.valueAccessor = this;
}
}
/**
* The earliest valid date that can be used.
* Do NOT combine with restrictDates, as they set the same underlying values.
* @param {?} dt
* @return {?}
*/
set dateRangeStart(dt) {
// Set time on date to 00:00:00 for comparing later
this._dateRangeStart = dt ? startOfDay(dt) : null;
}
/**
* The latest valid date that can be used.
* Do NOT combine with restrictDates, as they set the same underlying values.
* @param {?} dt
* @return {?}
*/
set dateRangeEnd(dt) {
// Set time on date to 00:00:00 for comparing later
this._dateRangeEnd = dt ? startOfDay(dt) : null;
}
/**
* @param {?} changes
* @return {?}
*/
ngOnChanges(changes) {
/*
* Works, creates new object literall
* obj = {
* errorMessage: 'new'message';
* }
*
* Doesn't work, modifies existing object. Would have to manually call cd.detectChanges() afterwards.
* obj.errorMessage = 'newMessage';
*/
if (changes['errorMessage']) {
this.setErrorMsg();
}
}
/**
* @return {?}
*/
ngOnInit() {
this.setErrorMsg();
// Set to midnight, so we don't accidentally compare against hours/minutes/seconds
if (this.restrictDate !== 'any' && (this._dateRangeEnd || this._dateRangeStart)) {
/** @type {?} */
const msg = `<common-date> - Invalid option configuration.
You cannot use "[restrictDate]" in combination with either "[dateRangeEnd]" or "[dateRangeStart]".
You must use either [restrictDate] or the [dateRange*] inputs.
<common-date name='effectiveDate'
label="Effective Date"
[restrictDate]="'past'" <<< problem, choose one
[dateRangeEnd]='today' <<< problem, choose one
formControlName="effectiveDate"
></common-date>
`;
throw new MoHCommonLibraryError(msg);
}
// Initialize date range logic
if (this.restrictDate === 'past') {
// past does allow for today
this._dateRangeEnd = this.today;
this._dateRangeStart = null;
}
else if (this.restrictDate === 'future') {
// future does NOT allow for today
this._dateRangeEnd = null;
this._dateRangeStart = this.tomorrow;
}
this.registerValidation(this.controlDir, this.validateSelf)
.then((/**
* @param {?} _
* @return {?}
*/
_ => {
if (this.injectedValidators && this.injectedValidators.length) {
// TODO: Potentially move to AbstractFormControl
// Inspect the validator functions for one that has a {required: true}
// property. Importantly, we are inspecting the validator function
// itself and NOT the current state of the NgControl. -- Does not work for reactive forms
this.isRequired = this.injectedValidators
.filter((/**
* @param {?} x
* @return {?}
*/
x => x.required))
.length >= 1;
}
}));
}
/**
* @return {?}
*/
get month() {
if (this.date) {
return this.date.getMonth();
}
}
/**
* @return {?}
*/
get day() {
if (this.date) {
return this.date.getDate();
}
}
/**
* @return {?}
*/
get year() {
if (this.date) {
return this.date.getFullYear();
}
}
/**
* Handles creating / destroying date and emitting changes based on user behaviour.
* @private
* @return {?}
*/
processDate() {
if (this.canCreateDate()) {
/** @type {?} */
const year = this.getNumericValue(this._year);
/** @type {?} */
const month = this.getNumericValue(this._month);
/** @type {?} */
const day = this.getNumericValue(this._day);
// Date function appears to use setYear() so any year 0-99 results in year 1900 to 1999
// Set each field individually, use setFullYear() instead of setYear()
// Set time on date to 00:00:00 for comparing later
this.date = startOfDay(new Date(year, month, day));
this.date.setFullYear(year);
}
else {
// Trigger validator for emptying fields use case. This is to remove the 'Invalid date' error.
if (this.date ||
(!this._year && !this._day && this._month === 'null')) {
// Destroys the internal Date object.
this.date = null;
}
}
this._onChange(this.date);
this._onTouched(this.date);
this.dateChange.emit(this.date);
}
/**
* Returns true if and only if the day/month/year fields are all filled out.
* @private
* @return {?}
*/
canCreateDate() {
// special because "0" is valid (Jan)
/** @type {?} */
const monthCheck = (typeof this._month === 'string' && this._month !== 'null')
|| typeof this._month === 'number';
if (!!this._year && !!this._day && monthCheck) {
return true;
}
return false;
}
/**
* @private
* @param {?} dt
* @return {?}
*/
_triggerOnChange(dt) {
this._onChange(dt);
this.dateChange.emit(dt);
}
/**
* Convert string to numeric value or null if not
* @private
* @param {?} value
* @return {?}
*/
getNumericValue(value) {
/** @type {?} */
const parsed = parseInt(value, 10);
return (isNaN(parsed) ? null : parsed);
}
/**
* @private
* @return {?}
*/
setDisplayVariables() {
this._day = this.date.getDate().toString();
this._month = this.date.getMonth().toString();
this._year = this.date.getFullYear().toString();
}
/**
* @param {?} value
* @return {?}
*/
writeValue(value) {
if (value) {
this.date = value;
this.setDisplayVariables();
}
}
/**
* @param {?} value
* @return {?}
*/
onBlurDay(value) {
this._day = value;
this.processDate();
}
/**
* @param {?} value
* @return {?}
*/
onBlurYear(value) {
this._year = value;
this.processDate();
}
/**
* @param {?} value
* @return {?}
*/
onBlurMonth(value) {
this._month = value;
this.processDate();
}
/**
* Validates the DateComponent instance itself, using internal private variables.
*
* @private
* @return {?}
*/
validateSelf() {
/** @type {?} */
const year = parseInt(this._year, 10);
/** @type {?} */
const month = parseInt(this._month, 10);
/** @type {?} */
const day = parseInt(this._day, 10);
// Nothing empty fields - nothing to validate OR have required error
if (isNaN(year) && isNaN(month) && isNaN(day)) {
return null;
}
// Partially filled out is always invalid, if year is present it must be greater than zero
if (isNaN(year) || isNaN(month) || isNaN(day) || (!isNaN(year) && year <= 0)) {
return { invalidValue: true };
}
// We can hardcode the day, since we're only interested in total days for that month.
/** @type {?} */
const daysInMonth = getDaysInMonth(new Date(year, month, 1));
if (day > daysInMonth || day < 1) {
return { dayOutOfRange: true };
}
/** @type {?} */
const dateRangeResult = this.validateRange();
if (dateRangeResult) {
return dateRangeResult;
}
/** @type {?} */
const distantDatesResult = this.validateDistantDates();
if (distantDatesResult) {
return distantDatesResult;
}
return null;
}
// If you set restrictDate, it will return noFutureDatesAllowed / noPastDatesAllowed
// If you just set dateRangeStart / dateRangeEnd, you get invalidRange
/**
* @private
* @return {?}
*/
validateRange() {
/** @type {?} */
const _dt = startOfDay(this.date);
if (this._dateRangeEnd && isAfter(_dt, this._dateRangeEnd)) {
if (this.restrictDate === 'past' ||
compareAsc(this._dateRangeEnd, this.today) === 0) {
return { noFutureDatesAllowed: true };
}
return { invalidRange: true };
}
if (this._dateRangeStart && isBefore(_dt, this._dateRangeStart)) {
if (this.restrictDate === 'future' ||
compareAsc(this._dateRangeStart, this.tomorrow) === 0) {
return { noPastDatesAllowed: true };
}
return { invalidRange: true };
}
return null;
}
/**
* @private
* @return {?}
*/
validateDistantDates() {
// Null end range only allow 150 years in future
if (!this._dateRangeEnd && isAfter(this.date, distantFuture)) {
return { yearDistantFuture: true };
}
// Null start range only allow 150 years in past
if (!this._dateRangeStart && isBefore(this.date, distantPast)) {
return { yearDistantPast: true };
}
return null;
}
}
DateComponent.decorators = [
{ type: Component, args: [{
selector: 'common-date',
template: "<fieldset>\r\n <legend class=\"date--legend\">{{label}}</legend>\r\n <ng-container *ngTemplateOutlet=\"instructionText\"></ng-container>\r\n <div class=\"date-row\">\r\n <select class=\"form-control monthSelect\"\r\n id=\"{{monthLabelforId}}\"\r\n name=\"{{monthLabelforId}}\"\r\n [value]=\"_month\"\r\n (blur)=\"onBlurMonth($event.target.value)\"\r\n [disabled]='disabled'\r\n [required]=\"isRequired\"\r\n aria-label=\"Month\">\r\n <!-- We show the blank option so the user can clear out their data.-->\r\n <option value=\"null\" label=\"Month\" selected [disabled]='isRequired'></option>\r\n <option *ngFor=\"let month of monthList; let i = index;\" [value]=\"i\">{{month}}</option>\r\n </select>\r\n\r\n <input type=\"number\"\r\n class=\"form-control dayInput\"\r\n id=\"{{dayLabelforId}}\"\r\n name=\"{{dayLabelforId}}\"\r\n placeholder=\"Day\"\r\n [value]=\"_day\"\r\n (blur)=\"onBlurDay($event.target.value)\"\r\n commonDateFieldFormat\r\n [disabled]='disabled'\r\n [required]=\"isRequired\"\r\n maxlength=\"2\"\r\n step=\"any\"\r\n aria-label=\"Day\"\r\n autocomplete=\"off\"/>\r\n\r\n <input type=\"number\"\r\n class=\"form-control yearInput\"\r\n id=\"{{yearLabelforId}}\"\r\n name=\"{{yearLabelforId}}\"\r\n placeholder=\"Year\"\r\n [value]=\"_year\"\r\n (blur)=\"onBlurYear($event.target.value)\"\r\n commonDateFieldFormat\r\n [disabled]='disabled'\r\n [required]=\"isRequired\"\r\n maxlength=\"4\"\r\n step=\"any\"\r\n aria-label=\"Year\"\r\n autocomplete=\"off\"/>\r\n\r\n </div>\r\n</fieldset>\r\n\r\n<common-error-container\r\n [displayError]=\"!disabled && (controlDir?.touched || controlDir?.dirty) && controlDir.errors\">\r\n <div *ngIf=\"controlDir?.errors?.required; else ComponentErrors\">\r\n {{_defaultErrMsg.required}}\r\n </div>\r\n</common-error-container>\r\n\r\n<ng-template #instructionText>\r\n <ng-content></ng-content>\r\n</ng-template>\r\n\r\n<!--Errors triggered by self-validation within component-->\r\n<ng-template #ComponentErrors>\r\n <div *ngIf=\"controlDir?.errors?.dayOutOfRange\">\r\n {{_defaultErrMsg.dayOutOfRange}}\r\n </div>\r\n <div *ngIf=\"controlDir?.errors?.yearDistantPast\">\r\n {{_defaultErrMsg.yearDistantPast}}\r\n </div>\r\n <div *ngIf=\"controlDir?.errors?.yearDistantFuture\">\r\n {{_defaultErrMsg.yearDistantFuture}}\r\n </div>\r\n <div *ngIf=\"controlDir?.errors?.noPastDatesAllowed\">\r\n {{_defaultErrMsg.noPastDatesAllowed}}\r\n </div>\r\n <div *ngIf=\"controlDir?.errors?.noFutureDatesAllowed\">\r\n {{_defaultErrMsg.noFutureDatesAllowed}}\r\n </div>\r\n <div *ngIf=\"controlDir?.errors?.invalidRange\">\r\n {{_defaultErrMsg.invalidRange}}\r\n </div>\r\n\r\n <!-- Case should not happen until something is not formatted correctly-->\r\n <div *ngIf=\"controlDir?.errors?.invalidValue\">\r\n {{_defaultErrMsg.invalidValue}}\r\n </div>\r\n</ng-template>\r\n",
styles: [".date--legend{font-size:inherit;font-weight:700}.date-row{display:flex;flex-wrap:nowrap;justify-content:space-between}.monthSelect{max-width:50%;height:35px;margin-right:1em}.dayInput{max-width:25%;height:35px;margin-right:1em}.yearInput{max-width:25%;height:35px}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{-webkit-appearance:none;-moz-appearance:none;appearance:none;margin:0}select option[selected]{color:gray!important}"]
}] }
];
/** @nocollapse */
DateComponent.ctorParameters = () => [
{ type: NgControl, decorators: [{ type: Optional }, { type: Self }] },
{ type: Array, decorators: [{ type: Optional }, { type: Self }, { type: Inject, args: [NG_VALIDATORS,] }] }
];
DateComponent.propDecorators = {
date: [{ type: Input }],
dateChange: [{ type: Output }],
label: [{ type: Input }],
restrictDate: [{ type: Input }],
dateRangeStart: [{ type: Input }],
dateRangeEnd: [{ type: Input }]
};
if (false) {
/** @type {?} */
DateComponent.prototype.date;
/** @type {?} */
DateComponent.prototype.dateChange;
/** @type {?} */
DateComponent.prototype.label;
/**
* Can be one of: "future", "past". "future" includes today, "past" does not.
* @type {?}
*/
DateComponent.prototype.restrictDate;
/** @type {?} */
DateComponent.prototype._year;
/** @type {?} */
DateComponent.prototype._month;
/** @type {?} */
DateComponent.prototype._day;
/** @type {?} */
DateComponent.prototype._dateRangeStart;
/** @type {?} */
DateComponent.prototype._dateRangeEnd;
/** @type {?} */
DateComponent.prototype.monthList;
/** @type {?} */
DateComponent.prototype.monthLabelforId;
/** @type {?} */
DateComponent.prototype.dayLabelforId;
/** @type {?} */
DateComponent.prototype.yearLabelforId;
/** @type {?} */
DateComponent.prototype._defaultErrMsg;
/**
* @type {?}
* @private
*/
DateComponent.prototype.today;
/**
* @type {?}
* @private
*/
DateComponent.prototype.tomorrow;
/** @type {?} */
DateComponent.prototype.isRequired;
/** @type {?} */
DateComponent.prototype.controlDir;
/**
* @type {?}
* @private
*/
DateComponent.prototype.injectedValidators;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0ZS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9tb2gtY29tbW9uLWxpYi8iLCJzb3VyY2VzIjpbImxpYi9jb21wb25lbnRzL2RhdGUvZGF0ZS5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQUFBLE9BQU8sRUFDTCxTQUFTLEVBRVQsS0FBSyxFQUNMLE1BQU0sRUFDTixZQUFZLEVBQ1osUUFBUSxFQUFFLElBQUksRUFBNEIsTUFBTSxFQUNqRCxNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBRUwsU0FBUyxFQUVULGFBQWEsRUFBQyxNQUFNLGdCQUFnQixDQUFDO0FBQ3ZDLE9BQU8sRUFBZ0IsbUJBQW1CLEVBQUUsTUFBTSxzQ0FBc0MsQ0FBQztBQUN6RixPQUFPLGNBQWMsTUFBTSx5QkFBeUIsQ0FBQztBQUNyRCxPQUFPLE9BQU8sTUFBTSxrQkFBa0IsQ0FBQztBQUN2QyxPQUFPLFFBQVEsTUFBTSxtQkFBbUIsQ0FBQztBQUN6QyxPQUFPLFlBQVksTUFBTSx1QkFBdUIsQ0FBQztBQUNqRCxPQUFPLFFBQVEsTUFBTSxtQkFBbUIsQ0FBQztBQUN6QyxPQUFPLFFBQVEsTUFBTSxtQkFBbUIsQ0FBQztBQUN6QyxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUN2RSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUN6RSxPQUFPLEVBQUUsVUFBVSxFQUFFLFVBQVUsRUFBRSxPQUFPLEVBQUUsTUFBTSxVQUFVLENBQUM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztNQWdDckQsY0FBYyxHQUFHLEdBQUc7O01BQ3BCLGFBQWEsR0FBRyxRQUFRLENBQUMsWUFBWSxFQUFFLEVBQUUsY0FBYyxDQUFDOztNQUN4RCxXQUFXLEdBQUcsUUFBUSxDQUFDLFlBQVksRUFBRSxFQUFFLGNBQWMsQ0FBQztBQVE1RCxNQUFNLE9BQU8sYUFBYyxTQUFRLG1CQUFtQjs7Ozs7O0lBb0VwRCxZQUF3QyxVQUFxQixFQUNHLGtCQUF5QjtRQUN2RixLQUFLLEVBQUUsQ0FBQztRQUY4QixlQUFVLEdBQVYsVUFBVSxDQUFXO1FBQ0csdUJBQWtCLEdBQWxCLGtCQUFrQixDQUFPO1FBaEUvRSxlQUFVLEdBQXVCLElBQUksWUFBWSxFQUFRLENBQUM7UUFFM0QsVUFBSyxHQUFXLE1BQU0sQ0FBQzs7OztRQUV2QixpQkFBWSxHQUE4QixLQUFLLENBQUM7UUFNekQsV0FBTSxHQUFXLE1BQU0sQ0FBQyxDQUFDLDZEQUE2RDs7UUFLdEYsb0JBQWUsR0FBUyxJQUFJLENBQUM7UUFDN0Isa0JBQWEsR0FBUyxJQUFJLENBQUM7UUFzQnBCLGNBQVMsR0FBYTtZQUMzQixTQUFTLEVBQUUsVUFBVSxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU07WUFDdEQsTUFBTSxFQUFFLFFBQVEsRUFBRSxXQUFXLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxVQUFVO1NBQ2pFLENBQUM7UUFFRixvQkFBZSxHQUFXLFFBQVEsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDO1FBQ25ELGtCQUFhLEdBQVcsTUFBTSxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUM7UUFDL0MsbUJBQWMsR0FBVyxPQUFPLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQzs7UUFHakQsbUJBQWMsR0FBaUI7WUFDN0IsUUFBUSxFQUFFLEdBQUcsbUJBQW1CLGVBQWU7WUFDL0MsYUFBYSxFQUFFLFdBQVcsbUJBQW1CLEdBQUc7WUFDaEQsZUFBZSxFQUFFLFdBQVcsbUJBQW1CLEdBQUc7WUFDbEQsaUJBQWlCLEVBQUUsV0FBVyxtQkFBbUIsR0FBRztZQUNwRCxrQkFBa0IsRUFBRSxXQUFXLG1CQUFtQixHQUFHO1lBQ3JELG9CQUFvQixFQUFFLFdBQVcsbUJBQW1CLEdBQUc7WUFDdkQsWUFBWSxFQUFFLFdBQVcsbUJBQW1CLEdBQUc7WUFDL0MsWUFBWSxFQUFFLFdBQVcsbUJBQW1CLEdBQUc7U0FDaEQsQ0FBQztRQUVNLFVBQUssR0FBRyxZQUFZLEVBQUUsQ0FBQztRQUN2QixhQUFRLEdBQUcsT0FBTyxDQUFFLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFFLENBQUM7UUFNMUMsSUFBSSxVQUFVLEVBQUU7WUFDZCxVQUFVLENBQUMsYUFBYSxHQUFHLElBQUksQ0FBQztTQUNqQztJQUNILENBQUM7Ozs7Ozs7SUEvQ0QsSUFDSSxjQUFjLENBQUMsRUFBUTtRQUN6QixtREFBbUQ7UUFDbkQsSUFBSSxDQUFDLGVBQWUsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO0lBQ3BELENBQUM7Ozs7Ozs7SUFNRCxJQUNJLFlBQVksQ0FBQyxFQUFRO1FBQ3ZCLG1EQUFtRDtRQUNuRCxJQUFJLENBQUMsYUFBYSxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7SUFDbEQsQ0FBQzs7Ozs7SUFtQ0QsV0FBVyxDQUFDLE9BQXNCO1FBRWhDOzs7Ozs7OztXQVFHO1FBQ0gsSUFBSSxPQUFPLENBQUMsY0FBYyxDQUFDLEVBQUU7WUFDM0IsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1NBQ3BCO0lBQ0gsQ0FBQzs7OztJQUVELFFBQVE7UUFDTixJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7UUFFbkIsa0ZBQWtGO1FBRWxGLElBQUksSUFBSSxDQUFDLFlBQVksS0FBSyxLQUFLLElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYSxJQUFJLElBQUksQ0FBQyxlQUFlLENBQUMsRUFBRTs7a0JBQ3pFLEdBQUcsR0FBRzs7Ozs7Ozs7Ozs7R0FXZjtZQUNHLE1BQU0sSUFBSSxxQkFBcUIsQ0FBQyxHQUFHLENBQUMsQ0FBQztTQUN0QztRQUVELDhCQUE4QjtRQUM5QixJQUFJLElBQUksQ0FBQyxZQUFZLEtBQUssTUFBTSxFQUFFO1lBQ2hDLDRCQUE0QjtZQUM1QixJQUFJLENBQUMsYUFBYSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUM7WUFDaEMsSUFBSSxDQUFDLGVBQWUsR0FBRyxJQUFJLENBQUM7U0FDN0I7YUFBTSxJQUFJLElBQUksQ0FBQyxZQUFZLEtBQUssUUFBUSxFQUFFO1lBQ3pDLGtDQUFrQztZQUNsQyxJQUFJLENBQUMsYUFBYSxHQUFHLElBQUksQ0FBQztZQUMxQixJQUFJLENBQUMsZUFBZSxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUM7U0FDdEM7UUFFRCxJQUFJLENBQUMsa0JBQWtCLENBQUUsSUFBSSxDQUFDLFVBQVUsRUFBRSxJQUFJLENBQUMsWUFBWSxDQUFFO2FBQzFELElBQUk7Ozs7UUFBQyxDQUFDLENBQUMsRUFBRTtZQUNSLElBQUksSUFBSSxDQUFDLGtCQUFrQixJQUFJLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxNQUFNLEVBQUU7Z0JBQzdELGdEQUFnRDtnQkFDaEQsc0VBQXNFO2dCQUN0RSxrRUFBa0U7Z0JBQ2xFLHlGQUF5RjtnQkFDekYsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUMsa0JBQWtCO3FCQUN0QyxNQUFNOzs7O2dCQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLFFBQVEsRUFBQztxQkFDdkIsTUFBTSxJQUFJLENBQUMsQ0FBQzthQUNoQjtRQUNILENBQUMsRUFBQyxDQUFDO0lBQ1AsQ0FBQzs7OztJQUVELElBQUksS0FBSztRQUNQLElBQUksSUFBSSxDQUFDLElBQUksRUFBRTtZQUNiLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztTQUM3QjtJQUNILENBQUM7Ozs7SUFFRCxJQUFJLEdBQUc7UUFDTCxJQUFJLElBQUksQ0FBQyxJQUFJLEVBQUU7WUFDYixPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7U0FDNUI7SUFDSCxDQUFDOzs7O0lBRUQsSUFBSSxJQUFJO1FBQ04sSUFBSSxJQUFJLENBQUMsSUFBSSxFQUFFO1lBQ2IsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1NBQ2hDO0lBQ0gsQ0FBQzs7Ozs7O0lBS08sV0FBVztRQUVqQixJQUFJLElBQUksQ0FBQyxhQUFhLEVBQUUsRUFBRTs7a0JBQ2xCLElBQUksR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUM7O2tCQUN2QyxLQUFLLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDOztrQkFDekMsR0FBRyxHQUFHLElBQUksQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQztZQUUzQyx1RkFBdUY7WUFDdkYsc0VBQXNFO1lBQ3RFLG1EQUFtRDtZQUNuRCxJQUFJLENBQUMsSUFBSSxHQUFHLFVBQVUsQ0FBQyxJQUFJLElBQUksQ0FBQyxJQUFJLEVBQUUsS0FBSyxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUM7WUFDbkQsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUM7U0FFN0I7YUFBTTtZQUNMLDhGQUE4RjtZQUM5RixJQUFJLElBQUksQ0FBQyxJQUFJO2dCQUNYLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksSUFBSSxJQUFJLENBQUMsTUFBTSxLQUFLLE1BQU0sQ0FBQyxFQUFFO2dCQUV2RCxxQ0FBcUM7Z0JBQ3JDLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDO2FBQ2xCO1NBQ0Y7UUFFRCxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUMxQixJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUMzQixJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDbEMsQ0FBQzs7Ozs7O0lBS08sYUFBYTs7O2NBR2IsVUFBVSxHQUFHLENBQUMsT0FBTyxJQUFJLENBQUMsTUFBTSxLQUFLLFFBQVEsSUFBSSxJQUFJLENBQUMsTUFBTSxLQUFLLE1BQU0sQ0FBQztlQUN6RSxPQUFPLElBQUksQ0FBQyxNQUFNLEtBQUssUUFBUTtRQUVwQyxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxJQUFJLFVBQVUsRUFBRTtZQUM3QyxPQUFPLElBQUksQ0FBQztTQUNiO1FBQ0QsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDOzs7Ozs7SUFFTyxnQkFBZ0IsQ0FBRSxFQUFRO1FBQ2hDLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDbkIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDM0IsQ0FBQzs7Ozs7OztJQUdPLGVBQWUsQ0FBQyxLQUFhOztjQUM3QixNQUFNLEdBQUcsUUFBUSxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUM7UUFDbEMsT0FBTyxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUN6QyxDQUFDOzs7OztJQUdPLG1CQUFtQjtRQUN6QixJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDM0MsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQzlDLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQyxRQUFRLEVBQUUsQ0FBQztJQUNsRCxDQUFDOzs7OztJQUVELFVBQVUsQ0FBQyxLQUFXO1FBQ3BCLElBQUksS0FBSyxFQUFFO1lBQ1QsSUFBSSxDQUFDLElBQUksR0FBRyxLQUFLLENBQUM7WUFDbEIsSUFBSSxDQUFDLG1CQUFtQixFQUFFLENBQUM7U0FDNUI7SUFDSCxDQUFDOzs7OztJQUVELFNBQVMsQ0FBQyxLQUFhO1FBQ3JCLElBQUksQ0FBQyxJQUFJLEdBQUcsS0FBSyxDQUFDO1FBQ2xCLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUNyQixDQUFDOzs7OztJQUNELFVBQVUsQ0FBQyxLQUFhO1FBQ3RCLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO1FBQ25CLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUNyQixDQUFDOzs7OztJQUNELFdBQVcsQ0FBQyxLQUFhO1FBQ3ZCLElBQUksQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDO1FBQ3BCLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUNyQixDQUFDOzs7Ozs7O0lBTU8sWUFBWTs7Y0FDWixJQUFJLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDOztjQUMvQixLQUFLLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDOztjQUNqQyxHQUFHLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDO1FBRW5DLG9FQUFvRTtRQUNwRSxJQUFLLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxLQUFLLENBQUMsS0FBSyxDQUFDLElBQUksS0FBSyxDQUFDLEdBQUcsQ0FBQyxFQUFHO1lBQy9DLE9BQU8sSUFBSSxDQUFDO1NBQ2I7UUFFRCwwRkFBMEY7UUFDMUYsSUFBSyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksS0FBSyxDQUFDLEtBQUssQ0FBQyxJQUFJLEtBQUssQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUMsS0FBSyxDQUFFLElBQUksQ0FBQyxJQUFJLElBQUksSUFBSSxDQUFDLENBQUMsRUFBRztZQUMvRSxPQUFPLEVBQUMsWUFBWSxFQUFFLElBQUksRUFBQyxDQUFDO1NBQzdCOzs7Y0FHSyxXQUFXLEdBQUcsY0FBYyxDQUFDLElBQUksSUFBSSxDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDNUQsSUFBSSxHQUFHLEdBQUcsV0FBVyxJQUFJLEdBQUcsR0FBRyxDQUFDLEVBQUU7WUFDaEMsT0FBTyxFQUFFLGFBQWEsRUFBRSxJQUFJLEVBQUUsQ0FBQztTQUNoQzs7Y0FFSyxlQUFlLEdBQUcsSUFBSSxDQUFDLGFBQWEsRUFBRTtRQUM1QyxJQUFJLGVBQWUsRUFBRTtZQUNuQixPQUFPLGVBQWUsQ0FBQztTQUN4Qjs7Y0FFSyxrQkFBa0IsR0FBRyxJQUFJLENBQUMsb0JBQW9CLEVBQUU7UUFDdEQsSUFBSSxrQkFBa0IsRUFBRTtZQUN0QixPQUFPLGtCQUFrQixDQUFDO1NBQzNCO1FBRUQsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDOzs7Ozs7O0lBS08sYUFBYTs7Y0FFYixHQUFHLEdBQUcsVUFBVSxDQUFFLElBQUksQ0FBQyxJQUFJLENBQUU7UUFFbkMsSUFBSSxJQUFJLENBQUMsYUFBYSxJQUFJLE9BQU8sQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxFQUFFO1lBRTFELElBQUksSUFBSSxDQUFDLFlBQVksS0FBSyxNQUFNO2dCQUM1QixVQUFVLENBQUMsSUFBSSxDQUFDLGFBQWEsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxFQUFFO2dCQUNwRCxPQUFPLEVBQUMsb0JBQW9CLEVBQUUsSUFBSSxFQUFDLENBQUM7YUFDckM7WUFFRCxPQUFPLEVBQUMsWUFBWSxFQUFFLElBQUksRUFBQyxDQUFDO1NBQzdCO1FBRUQsSUFBSSxJQUFJLENBQUMsZUFBZSxJQUFJLFFBQVEsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLGVBQWUsQ0FBQyxFQUFFO1lBRS9ELElBQUksSUFBSSxDQUFDLFlBQVksS0FBSyxRQUFRO2dCQUM5QixVQUFVLENBQUMsSUFBSSxDQUFDLGVBQWUsRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxFQUFFO2dCQUN6RCxPQUFPLEVBQUMsa0JBQWtCLEVBQUUsSUFBSSxFQUFDLENBQUM7YUFDbkM7WUFFRCxPQUFPLEVBQUMsWUFBWSxFQUFFLElBQUksRUFBQyxDQUFDO1NBQzdCO1FBRUQsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDOzs7OztJQUVPLG9CQUFvQjtRQUUxQixnREFBZ0Q7UUFDaEQsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsYUFBYSxDQUFDLEVBQUU7WUFDNUQsT0FBTyxFQUFDLGlCQUFpQixFQUFFLElBQUksRUFBQyxDQUFDO1NBQ2xDO1FBRUQsZ0RBQWdEO1FBQ2hELElBQUksQ0FBQyxJQUFJLENBQUMsZUFBZSxJQUFJLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLFdBQVcsQ0FBQyxFQUFFO1lBQzdELE9BQU8sRUFBQyxlQUFlLEVBQUUsSUFBSSxFQUFDLENBQUM7U0FDaEM7UUFFRCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7OztZQXRVRixTQUFTLFNBQUM7Z0JBQ1QsUUFBUSxFQUFFLGFBQWE7Z0JBQ3ZCLGlyR0FBb0M7O2FBRXJDOzs7O1lBckRDLFNBQVMsdUJBMEhLLFFBQVEsWUFBSSxJQUFJO3dDQUNoQixRQUFRLFlBQUksSUFBSSxZQUFJLE1BQU0sU0FBQyxhQUFhOzs7bUJBakVyRCxLQUFLO3lCQUNMLE1BQU07b0JBRU4sS0FBSzsyQkFFTCxLQUFLOzZCQWtCTCxLQUFLOzJCQVVMLEtBQUs7Ozs7SUFqQ04sNkJBQW9COztJQUNwQixtQ0FBb0U7O0lBRXBFLDhCQUFnQzs7Ozs7SUFFaEMscUNBQXlEOztJQUt6RCw4QkFBYzs7SUFDZCwrQkFBd0I7O0lBQ3hCLDZCQUFhOztJQUliLHdDQUE2Qjs7SUFDN0Isc0NBQTJCOztJQXNCM0Isa0NBR0U7O0lBRUYsd0NBQW1EOztJQUNuRCxzQ0FBK0M7O0lBQy9DLHVDQUFpRDs7SUFHakQsdUNBU0U7Ozs7O0lBRUYsOEJBQStCOzs7OztJQUMvQixpQ0FBNEM7O0lBQzVDLG1DQUEyQjs7SUFFZCxtQ0FBZ0Q7Ozs7O0lBQ2hELDJDQUE0RSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XHJcbiAgQ29tcG9uZW50LFxyXG4gIE9uSW5pdCxcclxuICBJbnB1dCxcclxuICBPdXRwdXQsXHJcbiAgRXZlbnRFbWl0dGVyLFxyXG4gIE9wdGlvbmFsLCBTZWxmLCBTaW1wbGVDaGFuZ2VzLCBPbkNoYW5nZXMsIEluamVjdFxyXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQge1xyXG4gIENvbnRyb2xWYWx1ZUFjY2Vzc29yLFxyXG4gIE5nQ29udHJvbCxcclxuICBWYWxpZGF0aW9uRXJyb3JzLFxyXG4gIE5HX1ZBTElEQVRPUlN9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcclxuaW1wb3J0IHsgRXJyb3JNZXNzYWdlLCBMYWJlbFJlcGxhY2VtZW50VGFnIH0gZnJvbSAnLi4vLi4vbW9kZWxzL2Vycm9yLW1lc3NhZ2UuaW50ZXJmYWNlJztcclxuaW1wb3J0IGdldERheXNJbk1vbnRoIGZyb20gJ2RhdGUtZm5zL2dldERheXNJbk1vbnRoJztcclxuaW1wb3J0IGlzQWZ0ZXIgZnJvbSAnZGF0ZS1mbnMvaXNBZnRlcic7XHJcbmltcG9ydCBpc0JlZm9yZSBmcm9tICdkYXRlLWZucy9pc0JlZm9yZSc7XHJcbmltcG9ydCBzdGFydE9mVG9kYXkgZnJvbSAnZGF0ZS1mbnMvc3RhcnRPZlRvZGF5JztcclxuaW1wb3J0IGFkZFllYXJzIGZyb20gJ2RhdGUtZm5zL2FkZFllYXJzJztcclxuaW1wb3J0IHN1YlllYXJzIGZyb20gJ2RhdGUtZm5zL3N1YlllYXJzJztcclxuaW1wb3J0IHsgTW9IQ29tbW9uTGlicmFyeUVycm9yIH0gZnJvbSAnLi4vLi4vLi4vaGVscGVycy9saWJyYXJ5LWVycm9yJztcclxuaW1wb3J0IHsgQWJzdHJhY3RGb3JtQ29udHJvbCB9IGZyb20gJy4uLy4uL21vZGVscy9hYnN0cmFjdC1mb3JtLWNvbnRyb2wnO1xyXG5pbXBvcnQgeyBjb21wYXJlQXNjLCBzdGFydE9mRGF5LCBhZGREYXlzIH0gZnJvbSAnZGF0ZS1mbnMnO1xyXG5cclxuLyoqXHJcbiAqIERhdGVDb21wb25lbnRcclxuICogWW91IGNhbm5vdCB1c2UgXCJbcmVzdHJpY3REYXRlXVwiIGluIGNvbWJpbmF0aW9uIHdpdGggZWl0aGVyICBcIltkYXRlUmFuZ2VFbmRdXCIgb3IgXCJbZGF0ZVJhbmdlU3RhcnRdXCIuXHJcbiAqIFlvdSBtdXN0IHVzZSBlaXRoZXIgW3Jlc3RyaWN0RGF0ZV0gb3IgdGhlIFtkYXRlUmFuZ2UqXSBpbnB1dHMuXHJcbiAqXHJcbiAqIEBleGFtcGxlXHJcbiAqICBUbyB0cmlnZ2VyICdubyBmdXR1cmUgZGF0ZXMgYWxsb3dlZCcgdXNpbmcgZGF0ZSByYW5nZXMgc2V0IHRoZSByYW5nZSBlbmQgZGF0ZSB0byB5ZXN0ZXJkYXkncyBkYXRlLlxyXG4gKiAgICA8Y29tbW9uLWRhdGUgbmFtZT0nZWZmZWN0aXZlRGF0ZSdcclxuICogICAgICAgbGFiZWw9XCJFZmZlY3RpdmUgRGF0ZVwiXHJcbiAqICAgICAgIFtkYXRlUmFuZ2VFbmRdPSd5ZXN0ZXJkYXknXHJcbiAqICAgICAgIGZvcm1Db250cm9sTmFtZT1cImVmZmVjdGl2ZURhdGVcIj48L2NvbW1vbi1kYXRlPlxyXG4gKidcclxuICAqICBUbyB0cmlnZ2VyICdubyBwYXN0IGRhdGVzIGFsbG93ZWQnIHVzaW5nIGRhdGUgcmFuZ2VzIHNldCB0aGUgcmFuZ2Ugc3RhcnQgZGF0ZSB0byB0b2RheSdzIGRhdGUuXHJcbiAqICAgIDxjb21tb24tZGF0ZSBuYW1lPSdlZmZlY3RpdmVEYXRlJ1xyXG4gKiAgICAgICBsYWJlbD1cIkVmZmVjdGl2ZSBEYXRlXCJcclxuICogICAgICAgW2RhdGVSYW5nZVN0YXJ0XT1cInRvZGF5XCJcclxuICogICAgICAgZm9ybUNvbnRyb2xOYW1lPVwiZWZmZWN0aXZlRGF0ZVwiPjwvY29tbW9uLWRhdGU+XHJcbiAqXHJcbiAqICBUbyBhbGxvdyBpbnN0cnVjdGlvbnMgdW5kZXIgbGFiZWwuXHJcbiAqICAgIDxjb21tb24tZGF0ZSBuYW1lPSdlZmZlY3RpdmVEYXRlJ1xyXG4gKiAgICAgICBsYWJlbD1cIkVmZmVjdGl2ZSBEYXRlXCJcclxuICogICAgICAgW2RhdGVSYW5nZUVuZF09J3llc3RlcmRheSdcclxuICogICAgICAgZm9ybUNvbnRyb2xOYW1lPVwiZWZmZWN0aXZlRGF0ZVwiPlxyXG4gKiAgICAgIDxwPlRoaXMgaXMgYSB0ZXN0LjwvcD5cclxuICogICAgPC9jb21tb24tZGF0ZT5cclxuICogQGV4cG9ydFxyXG4gKlxyXG4gKi9cclxuXHJcblxyXG5jb25zdCBNQVhfWUVBUl9SQU5HRSA9IDE1MDtcclxuY29uc3QgZGlzdGFudEZ1dHVyZSA9IGFkZFllYXJzKHN0YXJ0T2ZUb2RheSgpLCBNQVhfWUVBUl9SQU5HRSk7XHJcbmNvbnN0IGRpc3RhbnRQYXN0ID0gc3ViWWVhcnMoc3RhcnRPZlRvZGF5KCksIE1BWF9ZRUFSX1JBTkdFKTtcclxuXHJcblxyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ2NvbW1vbi1kYXRlJyxcclxuICB0ZW1wbGF0ZVVybDogJy4vZGF0ZS5jb21wb25lbnQuaHRtbCcsXHJcbiAgc3R5bGVVcmxzOiBbJy4vZGF0ZS5jb21wb25lbnQuc2NzcyddLFxyXG59KVxyXG5leHBvcnQgY2xhc3MgRGF0ZUNvbXBvbmVudCBleHRlbmRzIEFic3RyYWN0Rm9ybUNvbnRyb2xcclxuICBpbXBsZW1lbnRzIE9uSW5pdCwgQ29udHJvbFZhbHVlQWNjZXNzb3IsIE9uQ2hhbmdlcyB7XHJcblxyXG4gIC8vIElucHV0cyBmb3IgZGlzYWJsZWQgJiBlcnJvck1lc3NhZ2UgYXJlIGZvdW5kIGluIHRoZSBBYnN0cmFjdEZvcm1Db250cm9sIGNsYXNzXHJcbiAgQElucHV0KCkgZGF0ZTogRGF0ZTtcclxuICBAT3V0cHV0KCkgZGF0ZUNoYW5nZTogRXZlbnRFbWl0dGVyPERhdGU+ID0gbmV3IEV2ZW50RW1pdHRlcjxEYXRlPigpO1xyXG5cclxuICBASW5wdXQoKSBsYWJlbDogc3RyaW5nID0gJ0RhdGUnO1xyXG4gIC8qKiBDYW4gYmUgb25lIG9mOiBcImZ1dHVyZVwiLCBcInBhc3RcIi4gXCJmdXR1cmVcIiBpbmNsdWRlcyB0b2RheSwgXCJwYXN0XCIgZG9lcyBub3QuICovXHJcbiAgQElucHV0KCkgcmVzdHJpY3REYXRlOiAnZnV0dXJlJyB8ICdwYXN0JyB8ICdhbnknID0gJ2FueSc7XHJcblxyXG4gIC8vIFRoZSBhY3R1YWwgdmFsdWVzIGRpc3BsYXllZCB0byB0aGUgdXNlci4gIE1heSBub3QgcHJlY2lzZWx5IG1hdGNoIERhdGVcclxuICAvLyBvYmplY3QsIGJlY2F1c2UgdGhlc2UgZmllbGRzIGNhbiBiZSBibGFuayB3aGVyZWFzIGEgRGF0ZSBjYW4gbmV2ZXIgaGF2ZSBhXHJcbiAgLy8gXCJibGFua1wiIHllYXIgZm9yIGV4YW1wbGUuIEFsbCBhcmUgbnVsbGFibGUgc3RpbmdzIG9mIG51bWJlcnMgXCIwXCIgb3IgXCIyXCIuXHJcbiAgX3llYXI6IHN0cmluZztcclxuICBfbW9udGg6IHN0cmluZyA9ICdudWxsJzsgLy8gdGhpcyBtYWtlcyBpdCBzbyB0aGUgYmxhbmsgb3B0aW9uIGlzIHNlbGVjdGVkIGluIHRoZSBpbnB1dFxyXG4gIF9kYXk6IHN0cmluZztcclxuXHJcblxyXG4gIC8vIHZhcmlhYmxlcyBmb3IgZGF0ZSByYW5nZXNcclxuICBfZGF0ZVJhbmdlU3RhcnQ6IERhdGUgPSBudWxsO1xyXG4gIF9kYXRlUmFuZ2VFbmQ6IERhdGUgPSBudWxsO1xyXG5cclxuICAvKipcclxuICAgKiBUaGUgZWFybGllc3QgdmFsaWQgZGF0ZSB0aGF0IGNhbiBiZSB1c2VkLlxyXG4gICAqIERvIE5PVCBjb21iaW5lIHdpdGggcmVzdHJpY3REYXRlcywgYXMgdGhleSBzZXQgdGhlIHNhbWUgdW5kZXJseWluZyB2YWx1ZXMuXHJcbiAgICovXHJcbiAgQElucHV0KClcclxuICBzZXQgZGF0ZVJhbmdlU3RhcnQoZHQ6IERhdGUpIHtcclxuICAgIC8vIFNldCB0aW1lIG9uIGRhdGUgdG8gMDA6MDA6MDAgZm9yIGNvbXBhcmluZyBsYXRlclxyXG4gICAgdGhpcy5fZGF0ZVJhbmdlU3RhcnQgPSBkdCA/IHN0YXJ0T2ZEYXkoZHQpIDogbnVsbDtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBsYXRlc3QgdmFsaWQgZGF0ZSB0aGF0IGNhbiBiZSB1c2VkLlxyXG4gICAqIERvIE5PVCBjb21iaW5lIHdpdGggcmVzdHJpY3REYXRlcywgYXMgdGhleSBzZXQgdGhlIHNhbWUgdW5kZXJseWluZyB2YWx1ZXMuXHJcbiAgICovXHJcbiAgQElucHV0KClcclxuICBzZXQgZGF0ZVJhbmdlRW5kKGR0OiBEYXRlKSB7XHJcbiAgICAvLyBTZXQgdGltZSBvbiBkYXRlIHRvIDAwOjAwOjAwIGZvciBjb21wYXJpbmcgbGF0ZXJcclxuICAgIHRoaXMuX2RhdGVSYW5nZUVuZCA9IGR0ID8gc3RhcnRPZkRheShkdCkgOiBudWxsO1xyXG4gIH1cclxuXHJcbiAgcHVibGljIG1vbnRoTGlzdDogc3RyaW5nW10gPSBbXHJcbiAgICAnSmFudWFyeScsICdGZWJydWFyeScsICdNYXJjaCcsICdBcHJpbCcsICdNYXknLCAnSnVuZScsXHJcbiAgICAnSnVseScsICdBdWd1c3QnLCAnU2VwdGVtYmVyJywgJ09jdG9iZXInLCAnTm92ZW1iZXInLCAnRGVjZW1iZXInXHJcbiAgXTtcclxuXHJcbiAgbW9udGhMYWJlbGZvcklkOiBzdHJpbmcgPSAnbW9udGhfJyArIHRoaXMub2JqZWN0SWQ7XHJcbiAgZGF5TGFiZWxmb3JJZDogc3RyaW5nID0gJ2RheV8nICsgdGhpcy5vYmplY3RJZDtcclxuICB5ZWFyTGFiZWxmb3JJZDogc3RyaW5nID0gJ3llYXJfJyArIHRoaXMub2JqZWN0SWQ7XHJcblxyXG4gIC8vIEFic3RhY3QgdmFyaWFibGUgZGVmaW5lZFxyXG4gIF9kZWZhdWx0RXJyTXNnOiBFcnJvck1lc3NhZ2UgPSB7XHJcbiAgICByZXF1aXJlZDogYCR7TGFiZWxSZXBsYWNlbWVudFRhZ30gaXMgcmVxdWlyZWQuYCxcclxuICAgIGRheU91dE9mUmFuZ2U6IGBJbnZhbGlkICR7TGFiZWxSZXBsYWNlbWVudFRhZ30uYCxcclxuICAgIHllYXJEaXN0YW50UGFzdDogYEludmFsaWQgJHtMYWJlbFJlcGxhY2VtZW50VGFnfS5gLFxyXG4gICAgeWVhckRpc3RhbnRGdXR1cmU6IGBJbnZhbGlkICR7TGFiZWxSZXBsYWNlbWVudFRhZ30uYCxcclxuICAgIG5vUGFzdERhdGVzQWxsb3dlZDogYEludmFsaWQgJHtMYWJlbFJlcGxhY2VtZW50VGFnfS5gLFxyXG4gICAgbm9GdXR1cmVEYXRlc0FsbG93ZWQ6IGBJbnZhbGlkICR7TGFiZWxSZXBsYWNlbWVudFRhZ30uYCxcclxuICAgIGludmFsaWRWYWx1ZTogYEludmFsaWQgJHtMYWJlbFJlcGxhY2VtZW50VGFnfS5gLFxyXG4gICAgaW52YWxpZFJhbmdlOiBgSW52YWxpZCAke0xhYmVsUmVwbGFjZW1lbnRUYWd9LmBcclxuICB9O1xyXG5cclxuICBwcml2YXRlIHRvZGF5ID0gc3RhcnRPZlRvZGF5KCk7XHJcbiAgcHJpdmF0ZSB0b21vcnJvdyA9IGFkZERheXMoIHRoaXMudG9kYXksIDEgKTtcclxuICBwdWJsaWMgaXNSZXF1aXJlZDogYm9vbGVhbjsgLy8gVE9ETzogcmVtb3ZlIGlmIG5vdCByZXF1aXJlZCAtIHZhbHVlIGRvZXMgbm90IGdldCBzZXQgd2hlbiB1c2luZyBSZWFjdGl2ZSBmb3Jtc1xyXG5cclxuICBjb25zdHJ1Y3RvciggQE9wdGlvbmFsKCkgQFNlbGYoKSBwdWJsaWMgY29udHJvbERpcjogTmdDb250cm9sLFxyXG4gICAgICAgICAgICAgICBAT3B0aW9uYWwoKSBAU2VsZigpIEBJbmplY3QoTkdfVkFMSURBVE9SUykgcHJpdmF0ZSBpbmplY3RlZFZhbGlkYXRvcnM6IGFueVtdICkge1xyXG4gICAgc3VwZXIoKTtcclxuICAgIGlmIChjb250cm9sRGlyKSB7XHJcbiAgICAgIGNvbnRyb2xEaXIudmFsdWVBY2Nlc3NvciA9IHRoaXM7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKSB7XHJcblxyXG4gICAgLypcclxuICAgICAqIFdvcmtzLCBjcmVhdGVzIG5ldyBvYmplY3QgbGl0ZXJhbGxcclxuICAgICAqIG9iaiA9IHtcclxuICAgICAqICAgZXJyb3JNZXNzYWdlOiAnbmV3J21lc3NhZ2UnO1xyXG4gICAgICogfVxyXG4gICAgICpcclxuICAgICAqIERvZXNuJ3Qgd29yaywgbW9kaWZpZXMgZXhpc3Rpbmcgb2JqZWN0LiAgV291bGQgaGF2ZSB0byBtYW51YWxseSBjYWxsIGNkLmRldGVjdENoYW5nZXMoKSBhZnRlcndhcmRzLlxyXG4gICAgICogb2JqLmVycm9yTWVzc2FnZSA9ICduZXdNZXNzYWdlJztcclxuICAgICAqL1xyXG4gICAgaWYgKGNoYW5nZXNbJ2Vycm9yTWVzc2FnZSddKSB7XHJcbiAgICAgIHRoaXMuc2V0RXJyb3JNc2coKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIG5nT25Jbml0KCkge1xyXG4gICAgdGhpcy5zZXRFcnJvck1zZygpO1xyXG5cclxuICAgIC8vIFNldCB0byBtaWRuaWdodCwgc28gd2UgZG9uJ3QgYWNjaWRlbnRhbGx5IGNvbXBhcmUgYWdhaW5zdCBob3Vycy9taW51dGVzL3NlY29uZHNcclxuXHJcbiAgICBpZiAodGhpcy5yZXN0cmljdERhdGUgIT09ICdhbnknICYmICh0aGlzLl9kYXRlUmFuZ2VFbmQgfHwgdGhpcy5fZGF0ZVJhbmdlU3RhcnQpKSB7XHJcbiAgICAgIGNvbnN0IG1zZyA9IGA8Y29tbW9uLWRhdGU+IC0gSW52YWxpZCBASW5wdXQoKSBvcHRpb24gY29uZmlndXJhdGlvbi5cclxuWW91IGNhbm5vdCB1c2UgXCJbcmVzdHJpY3REYXRlXVwiIGluIGNvbWJpbmF0aW9uIHdpdGggZWl0aGVyICBcIltkYXRlUmFuZ2VFbmRdXCIgb3IgXCJbZGF0ZVJhbmdlU3RhcnRdXCIuXHJcbllvdSBtdXN0IHVzZSBlaXRoZXIgW3Jlc3RyaWN0RGF0ZV0gb3IgdGhlIFtkYXRlUmFuZ2UqXSBpbnB1dHMuXHJcblxyXG4gICAgPGNvbW1vbi1kYXRlIG5hbWU9J2VmZmVjdGl2ZURhdGUnXHJcbiAgICAgICAgbGFiZWw9XCJFZmZlY3RpdmUgRGF0ZVwiXHJcbiAgICAgICAgW3Jlc3RyaWN0RGF0ZV09XCIncGFzdCdcIiAgIDw8PCBwcm9ibGVtLCBjaG9vc2Ugb25lXHJcbiAgICAgICAgW2RhdGVSYW5nZUVuZF09J3RvZGF5JyAgICA8PDwgcHJvYmxlbSwgY2hvb3NlIG9uZVxyXG4gICAgICAgIGZvcm1Db250cm9sTmFtZT1cImVmZmVjdGl2ZURhdGVcIlxyXG4gICAgPjwvY29tbW9uLWRhdGU+XHJcblxyXG4gIGA7XHJcbiAgICAgIHRocm93IG5ldyBNb0hDb21tb25MaWJyYXJ5RXJyb3IobXNnKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBJbml0aWFsaXplIGRhdGUgcmFuZ2UgbG9naWNcclxuICAgIGlmICh0aGlzLnJlc3RyaWN0RGF0ZSA9PT0gJ3Bhc3QnKSB7XHJcbiAgICAgIC8vIHBhc3QgZG9lcyBhbGxvdyBmb3IgdG9kYXlcclxuICAgICAgdGhpcy5fZGF0ZVJhbmdlRW5kID0gdGhpcy50b2RheTtcclxuICAgICAgdGhpcy5fZGF0ZVJhbmdlU3RhcnQgPSBudWxsO1xyXG4gICAgfSBlbHNlIGlmICh0aGlzLnJlc3RyaWN0RGF0ZSA9PT0gJ2Z1dHVyZScpIHtcclxuICAgICAgLy8gZnV0dXJlIGRvZXMgTk9UIGFsbG93IGZvciB0b2RheVxyXG4gICAgICB0aGlzLl9kYXRlUmFuZ2VFbmQgPSBudWxsO1xyXG4gICAgICB0aGlzLl9kYXRlUmFuZ2VTdGFydCA9IHRoaXMudG9tb3Jyb3c7XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy5yZWdpc3RlclZhbGlkYXRpb24oIHRoaXMuY29udHJvbERpciwgdGhpcy52YWxpZGF0ZVNlbGYgKVxyXG4gICAgICAudGhlbihfID0+IHtcclxuICAgICAgICBpZiAodGhpcy5pbmplY3RlZFZhbGlkYXRvcnMgJiYgdGhpcy5pbmplY3RlZFZhbGlkYXRvcnMubGVuZ3RoKSB7XHJcbiAgICAgICAgICAvLyBUT0RPOiBQb3RlbnRpYWxseSBtb3ZlIHRvIEFic3RyYWN0Rm9ybUNvbnRyb2xcclxuICAgICAgICAgIC8vIEluc3BlY3QgdGhlIHZhbGlkYXRvciBmdW5jdGlvbnMgZm9yIG9uZSB0aGF0IGhhcyBhIHtyZXF1aXJlZDogdHJ1ZX1cclxuICAgICAgICAgIC8vIHByb3BlcnR5LiBJbXBvcnRhbnRseSwgd2UgYXJlIGluc3BlY3RpbmcgdGhlIHZhbGlkYXRvciBmdW5jdGlvblxyXG4gICAgICAgICAgLy8gaXRzZWxmIGFuZCBOT1QgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIE5nQ29udHJvbC4gLS0gRG9lcyBub3Qgd29yayBmb3IgcmVhY3RpdmUgZm9ybXNcclxuICAgICAgICAgIHRoaXMuaXNSZXF1aXJlZCA9IHRoaXMuaW5qZWN0ZWRWYWxpZGF0b3JzXHJcbiAgICAgICAgICAgIC5maWx0ZXIoeCA9PiB4LnJlcXVpcmVkKVxyXG4gICAgICAgICAgICAubGVuZ3RoID49IDE7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICB9XHJcblxyXG4gIGdldCBtb250aCgpOiBudW1iZXIge1xyXG4gICAgaWYgKHRoaXMuZGF0ZSkge1xyXG4gICAgICByZXR1cm4gdGhpcy5kYXRlLmdldE1vbnRoKCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBnZXQgZGF5KCk6IG51bWJlciB7XHJcbiAgICBpZiAodGhpcy5kYXRlKSB7XHJcbiAgICAgIHJldHVybiB0aGlzLmRhdGUuZ2V0RGF0ZSgpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgZ2V0IHllYXIoKTogbnVtYmVyIHtcclxuICAgIGlmICh0aGlzLmRhdGUpIHtcclxuICAgICAgcmV0dXJuIHRoaXMuZGF0ZS5nZXRGdWxsWWVhcigpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogSGFuZGxlcyBjcmVhdGluZyAvIGRlc3Ryb3lpbmcgZGF0ZSBhbmQgZW1pdHRpbmcgY2hhbmdlcyBiYXNlZCBvbiB1c2VyIGJlaGF2aW91ci5cclxuICAgKi9cclxuICBwcml2YXRlIHByb2Nlc3NEYXRlKCkge1xyXG5cclxuICAgIGlmICh0aGlzLmNhbkNyZWF0ZURhdGUoKSkge1xyXG4gICAgICBjb25zdCB5ZWFyID0gdGhpcy5nZXROdW1lcmljVmFsdWUodGhpcy5feWVhcik7XHJcbiAgICAgIGNvbnN0IG1vbnRoID0gdGhpcy5nZXROdW1lcmljVmFsdWUodGhpcy5fbW9udGgpO1xyXG4gICAgICBjb25zdCBkYXkgPSB0aGlzLmdldE51bWVyaWNWYWx1ZSh0aGlzLl9kYXkpO1xyXG5cclxuICAgICAgLy8gRGF0ZSBmdW5jdGlvbiBhcHBlYXJzIHRvIHVzZSBzZXRZZWFyKCkgc28gYW55IHllYXIgMC05OSByZXN1bHRzIGluIHllYXIgMTkwMCB0byAxOTk5XHJcbiAgICAgIC8vIFNldCBlYWNoIGZpZWxkIGluZGl2aWR1YWxseSwgdXNlIHNldEZ1bGxZZWFyKCkgaW5zdGVhZCBvZiBzZXRZZWFyKClcclxuICAgICAgLy8gU2V0IHRpbWUgb24gZGF0ZSB0byAwMDowMDowMCBmb3IgY29tcGFyaW5nIGxhdGVyXHJcbiAgICAgIHRoaXMuZGF0ZSA9IHN0YXJ0T2ZEYXkobmV3IERhdGUoeWVhciwgbW9udGgsIGRheSkpO1xyXG4gICAgICB0aGlzLmRhdGUuc2V0RnVsbFllYXIoeWVhcik7XHJcblxyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gVHJpZ2dlciB2YWxpZGF0b3IgZm9yIGVtcHR5aW5nIGZpZWxkcyB1c2UgY2FzZS4gVGhpcyBpcyB0byByZW1vdmUgdGhlICdJbnZhbGlkIGRhdGUnIGVycm9yLlxyXG4gICAgICBpZiAodGhpcy5kYXRlIHx8XHJcbiAgICAgICAgKCF0aGlzLl95ZWFyICYmICF0aGlzLl9kYXkgJiYgdGhpcy5fbW9udGggPT09ICdudWxsJykpIHtcclxuXHJcbiAgICAgICAgLy8gRGVzdHJveXMgdGhlIGludGVybmFsIERhdGUgb2JqZWN0LlxyXG4gICAgICAgIHRoaXMuZGF0ZSA9IG51bGw7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICB0aGlzLl9vbkNoYW5nZSh0aGlzLmRhdGUpO1xyXG4gICAgdGhpcy5fb25Ub3VjaGVkKHRoaXMuZGF0ZSk7XHJcbiAgICB0aGlzLmRhdGVDaGFuZ2UuZW1pdCh0aGlzLmRhdGUpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogUmV0dXJucyB0cnVlIGlmIGFuZCBvbmx5IGlmIHRoZSBkYXkvbW9udGgveWVhciBmaWVsZHMgYXJlIGFsbCBmaWxsZWQgb3V0LlxyXG4gICAqL1xyXG4gIHByaXZhdGUgY2FuQ3JlYXRlRGF0ZSgpOiBib29sZWFuIHtcclxuXHJcbiAgICAvLyBzcGVjaWFsIGJlY2F1c2UgXCIwXCIgaXMgdmFsaWQgKEphbilcclxuICAgIGNvbnN0IG1vbnRoQ2hlY2sgPSAodHlwZW9mIHRoaXMuX21vbnRoID09PSAnc3RyaW5nJyAmJiB0aGlzLl9tb250aCAhPT0gJ251bGwnKVxyXG4gICAgICB8fCB0eXBlb2YgdGhpcy5fbW9udGggPT09ICdudW1iZXInO1xyXG5cclxuICAgIGlmICghIXRoaXMuX3llYXIgJiYgISF0aGlzLl9kYXkgJiYgbW9udGhDaGVjaykge1xyXG4gICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH1cclxuICAgIHJldHVybiBmYWxzZTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgX3RyaWdnZXJPbkNoYW5nZSggZHQ6IERhdGUgKSB7XHJcbiAgICB0aGlzLl9vbkNoYW5nZShkdCk7XHJcbiAgICB0aGlzLmRhdGVDaGFuZ2UuZW1pdChkdCk7XHJcbiAgfVxyXG5cclxuICAvKiogQ29udmVydCBzdHJpbmcgdG8gbnVtZXJpYyB2YWx1ZSBvciBudWxsIGlmIG5vdCAqL1xyXG4gIHByaXZhdGUgZ2V0TnVtZXJpY1ZhbHVlKHZhbHVlOiBzdHJpbmcpOiBudW1iZXIgfCBudWxsIHtcclxuICAgIGNvbnN0IHBhcnNlZCA9IHBhcnNlSW50KHZhbHVlLCAxMCk7XHJcbiAgICByZXR1cm4gKGlzTmFOKHBhcnNlZCkgPyBudWxsIDogcGFyc2VkKTtcclxuICB9XHJcblxyXG5cclxuICBwcml2YXRlIHNldERpc3BsYXlWYXJpYWJsZXMoKSB7XHJcbiAgICB0aGlzLl9kYXkgPSB0aGlzLmRhdGUuZ2V0RGF0ZSgpLnRvU3RyaW5nKCk7XHJcbiAgICB0aGlzLl9tb250aCA9IHRoaXMuZGF0ZS5nZXRNb250aCgpLnRvU3RyaW5nKCk7XHJcbiAgICB0aGlzLl95ZWFyID0gdGhpcy5kYXRlLmdldEZ1bGxZZWFyKCkudG9TdHJpbmcoKTtcclxuICB9XHJcblxyXG4gIHdyaXRlVmFsdWUodmFsdWU6IERhdGUpOiB2b2lkIHtcclxuICAgIGlmICh2YWx1ZSkge1xyXG4gICAgICB0aGlzLmRhdGUgPSB2YWx1ZTtcclxuICAgICAgdGhpcy5zZXREaXNwbGF5VmFyaWFibGVzKCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBvbkJsdXJEYXkodmFsdWU6IHN0cmluZykge1xyXG4gICAgdGhpcy5fZGF5ID0gdmFsdWU7XHJcbiAgICB0aGlzLnByb2Nlc3NEYXRlKCk7XHJcbiAgfVxyXG4gIG9uQmx1clllYXIodmFsdWU6IHN0cmluZykge1xyXG4gICAgdGhpcy5feWVhciA9IHZhbHVlO1xyXG4gICAgdGhpcy5wcm9jZXNzRGF0ZSgpO1xyXG4gIH1cclxuICBvbkJsdXJNb250aCh2YWx1ZTogc3RyaW5nKSB7XHJcbiAgICB0aGlzLl9tb250aCA9IHZhbHVlO1xyXG4gICAgdGhpcy5wcm9jZXNzRGF0ZSgpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogVmFsaWRhdGVzIHRoZSBEYXRlQ29tcG9uZW50IGluc3RhbmNlIGl0c2VsZiwgdXNpbmcgaW50ZXJuYWwgcHJpdmF0ZSB2YXJpYWJsZXMuXHJcbiAgICpcclxuICAgKi9cclxuICBwcml2YXRlIHZhbGlkYXRlU2VsZigpIHtcclxuICAgIGNvbnN0IHllYXIgPSBwYXJzZUludCh0aGlzLl95ZWFyLCAxMCk7XHJcbiAgICBjb25zdCBtb250aCA9IHBhcnNlSW50KHRoaXMuX21vbnRoLCAxMCk7XHJcbiAgICBjb25zdCBkYXkgPSBwYXJzZUludCh0aGlzLl9kYXksIDEwKTtcclxuXHJcbiAgICAvLyBOb3RoaW5nIGVtcHR5IGZpZWxkcyAtIG5vdGhpbmcgdG8gdmFsaWRhdGUgT1IgaGF2ZSByZXF1aXJlZCBlcnJvclxyXG4gICAgaWYgKCBpc05hTih5ZWFyKSAmJiBpc05hTihtb250aCkgJiYgaXNOYU4oZGF5KSApIHtcclxuICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUGFydGlhbGx5IGZpbGxlZCBvdXQgaXMgYWx3YXlzIGludmFsaWQsIGlmIHllYXIgaXMgcHJlc2VudCBpdCBtdXN0IGJlIGdyZWF0ZXIgdGhhbiB6ZXJvXHJcbiAgICBpZiAoIGlzTmFOKHllYXIpIHx8IGlzTmFOKG1vbnRoKSB8fCBpc05hTihkYXkpIHx8ICghaXNOYU4oIHllYXIpICYmIHllYXIgPD0gMCkgKSB7XHJcbiAgICAgIHJldHVybiB7aW52YWxpZFZhbHVlOiB0cnVlfTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBXZSBjYW4gaGFyZGNvZGUgdGhlIGRheSwgc2luY2Ugd2UncmUgb25seSBpbnRlcmVzdGVkIGluIHRvdGFsIGRheXMgZm9yIHRoYXQgbW9udGguXHJcbiAgICBjb25zdCBkYXlzSW5Nb250aCA9IGdldERheXNJbk1vbnRoKG5ldyBEYXRlKHllYXIsIG1vbnRoLCAxKSk7XHJcbiAgICBpZiAoZGF5ID4gZGF5c0luTW9udGggfHwgZGF5IDwgMSkge1xyXG4gICAgICByZXR1cm4geyBkYXlPdXRPZlJhbmdlOiB0cnVlIH07XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgZGF0ZVJhbmdlUmVzdWx0ID0gdGhpcy52YWxpZGF0ZVJhbmdlKCk7XHJcbiAgICBpZiAoZGF0ZVJhbmdlUmVzdWx0KSB7XHJcbiAgICAgIHJldHVybiBkYXRlUmFuZ2VSZXN1bHQ7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgZGlzdGFudERhdGVzUmVzdWx0ID0gdGhpcy52YWxpZGF0ZURpc3RhbnREYXRlcygpO1xyXG4gICAgaWYgKGRpc3RhbnREYXRlc1Jlc3VsdCkge1xyXG4gICAgICByZXR1cm4gZGlzdGFudERhdGVzUmVzdWx0O1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiBudWxsO1xyXG4gIH1cclxuXHJcblxyXG4gIC8vIElmIHlvdSBzZXQgcmVzdHJpY3REYXRlLCBpdCB3aWxsIHJldHVybiBub0Z1dHVyZURhdGVzQWxsb3dlZCAvIG5vUGFzdERhdGVzQWxsb3dlZFxyXG4gIC8vIElmIHlvdSBqdXN0IHNldCBkYXRlUmFuZ2VTdGFydCAvIGRhdGVSYW5nZUVuZCwgeW91IGdldCBpbnZhbGlkUmFuZ2VcclxuICBwcml2YXRlIHZhbGlkYXRlUmFuZ2UoKTogVmFsaWRhdGlvbkVycm9ycyB8IG51bGwge1xyXG5cclxuICAgIGNvbnN0IF9kdCA9IHN0YXJ0T2ZEYXkoIHRoaXMuZGF0ZSApO1xyXG5cclxuICAgIGlmICh0aGlzLl9kYXRlUmFuZ2VFbmQgJiYgaXNBZnRlcihfZHQsIHRoaXMuX2RhdGVSYW5nZUVuZCkpIHtcclxuXHJcbiAgICAgIGlmICh0aGlzLnJlc3RyaWN0RGF0ZSA9PT0gJ3Bhc3QnIHx8XHJcbiAgICAgICAgICBjb21wYXJlQXNjKHRoaXMuX2RhdGVSYW5nZUVuZCwgdGhpcy50b2RheSkgPT09IDApIHtcclxuICAgICAgICByZXR1cm4ge25vRnV0dXJlRGF0ZXNBbGxvd2VkOiB0cnVlfTtcclxuICAgICAgfVxyXG5cclxuICAgICAgcmV0dXJuIHtpbnZhbGlkUmFuZ2U6IHRydWV9O1xyXG4gICAgfVxyXG5cclxuICAgIGlmICh0aGlzLl9kYXRlUmFuZ2VTdGFydCAmJiBpc0JlZm9yZShfZHQsIHRoaXMuX2RhdGVSYW5nZVN0YXJ0KSkge1xyXG5cclxuICAgICAgaWYgKHRoaXMucmVzdHJpY3REYXRlID09PSAnZnV0dXJlJyAgfHxcclxuICAgICAgICAgIGNvbXBhcmVBc2ModGhpcy5fZGF0ZVJhbmdlU3RhcnQsIHRoaXMudG9tb3Jyb3cpID09PSAwKSB7XHJcbiAgICAgICAgcmV0dXJuIHtub1Bhc3REYXRlc0FsbG93ZWQ6IHRydWV9O1xyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm4ge2ludmFsaWRSYW5nZTogdHJ1ZX07XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIG51bGw7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHZhbGlkYXRlRGlzdGFudERhdGVzKCk6IFZhbGlkYXRpb25FcnJvcnMgfCBudWxsIHtcclxuXHJcbiAgICAvLyBOdWxsIGVuZCByYW5nZSBvbmx5IGFsbG93IDE1MCB5ZWFycyBpbiBmdXR1cmVcclxuICAgIGlmICghdGhpcy5fZGF0ZVJhbmdlRW5kICYmIGlzQWZ0ZXIodGhpcy5kYXRlLCBkaXN0YW50RnV0dXJlKSkge1xyXG4gICAgICByZXR1cm4ge3llYXJEaXN0YW50RnV0dXJlOiB0cnVlfTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBOdWxsIHN0YXJ0IHJhbmdlIG9ubHkgYWxsb3cgMTUwIHllYXJzIGluIHBhc3RcclxuICAgIGlmICghdGhpcy5fZGF0ZVJhbmdlU3RhcnQgJiYgaXNCZWZvcmUodGhpcy5kYXRlLCBkaXN0YW50UGFzdCkpIHtcclxuICAgICAgcmV0dXJuIHt5ZWFyRGlzdGFudFBhc3Q6IHRydWV9O1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiBudWxsO1xyXG4gIH1cclxuXHJcbn1cclxuIl19