moh-common-lib
Version:
A library of Angular components, services, and styles for B.C. Government Ministry of Health (MoH).
346 lines • 30.7 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
import { Component, Input, Output, EventEmitter, ViewChild, forwardRef } from '@angular/core';
import { NgxMyDatePickerDirective } from 'ngx-mydatepicker';
import { NgForm, ControlContainer, NG_VALUE_ACCESSOR } from '@angular/forms';
import { Base } from '../../models/base';
/**
* Component NPM package dependencies:
* a) moment
*
* This component reports the following errors.
* required
* dayOutOfRange
* yearDistantPast
* yearDistantFuture
* noFutureDatesAllowed
* invalidValue
*
* These messages can be changed by updated messages using the errorMessages interface/
* Ex. { required: 'This field is required', invalidValue: '{label} is invalid' }
* @record
*/
export function DateErrorMsg() { }
if (false) {
/** @type {?|undefined} */
DateErrorMsg.prototype.required;
/** @type {?|undefined} */
DateErrorMsg.prototype.dayOutOfRange;
/** @type {?|undefined} */
DateErrorMsg.prototype.yearDistantPast;
/** @type {?|undefined} */
DateErrorMsg.prototype.yearDistantFuture;
/** @type {?|undefined} */
DateErrorMsg.prototype.noPastDatesAllowed;
/** @type {?|undefined} */
DateErrorMsg.prototype.noFutureDatesAllowed;
/** @type {?|undefined} */
DateErrorMsg.prototype.invalidValue;
}
/**
* PRIME datepicker component. Largely a wrapper for ngx-mydatepicker
* https://github.com/kekeh/ngx-mydatepicker
*
* NOTE - YOU MUST INCLUDE NGX-MYDATEPICKER IN YOUR PARENT APPLICATION TO USE
* THIS COMPONENT! This is due to some poor implementation in ngx-mydatepicker.
* Make sure to use the same version that this library uses.
*/
export class DatepickerComponent extends Base {
constructor() {
super();
/**
* Component size can be reduced, see Datepickersizes for options
*/
this.size = DatepickerSizes.DEFAULT;
this.dateChange = new EventEmitter();
this.required = false;
/**
* Control visibility of the clear 'x' button on the mini datepicker.
*
* **'visible'** is default, button exists
*
* **'none'** means the element does not exist
*
* **'invisible'** means the element takes up space but is not visible / cannot be
* used.
*
* Invisible is useful when you want to make sure a datepicker is the same
* size as a visible one.
*/
this.clearButton = 'visible';
/**
* Format for how to display the date to the user.
*/
this.dateFormat = 'yyyy/mm/dd';
// Make enum accessible in HTML
this.DatepickerSizes = DatepickerSizes;
this._onChange = (/**
* @param {?} _
* @return {?}
*/
(_) => { });
this._onTouched = (/**
* @return {?}
*/
() => { });
}
/**
* @param {?} date
* @return {?}
*/
convertDateToSimpleDate(date) {
if (date === null || date === undefined) {
return null;
}
return {
year: date.getFullYear(),
month: date.getMonth() + 1,
day: date.getDate(),
};
}
/**
* @param {?} date
* @return {?}
*/
convertSimpleDateToDate(date) {
// When ngx-mydatepicker is cleared, it returns {year: 0, month: 0, day: 0}
if (date.year === 0) {
return null;
}
return new Date(date.year, date.month - 1, date.day);
}
/**
* @param {?} x
* @return {?}
*/
isDate(x) {
if (!x) {
return false;
}
return x.getDate !== undefined;
}
/**
* @return {?}
*/
ngOnInit() {
if (!this.errorMessages) {
this.errorMessages = {
required: this.labelText + ' is required.',
dayOutOfRange: 'Invalid ' + this.labelText + '.',
yearDistantPast: 'Invalid ' + this.labelText + '.',
yearDistantFuture: 'Invalid ' + this.labelText + '.',
noFutureDatesAllowed: 'Invalid ' + this.labelText + '.',
invalidValue: 'Invalid ' + this.labelText + '.'
};
}
this.datepickerOptions = {
dateFormat: this.dateFormat,
sunHighlight: false,
appendSelectorToBody: true,
};
if (this.size === DatepickerSizes.MINI) {
// Set width/height to 4/5 of default
this.datepickerOptions.selectorHeight = '185px';
this.datepickerOptions.selectorWidth = '201px';
}
if (this.isDate(this.disableSince)) {
this.datepickerOptions.disableSince = this.convertDateToSimpleDate(this.disableSince);
}
if (this.isDate(this.disableUntil)) {
this.datepickerOptions.disableUntil = this.convertDateToSimpleDate(this.disableSince);
}
if (this.onlyFutureDates) {
/** @type {?} */
const today = new Date();
this.datepickerOptions.disableUntil = this.convertDateToSimpleDate(today);
}
if (this.date) {
// Even if jsdate winds up being undefined, even defining this.model will
// set the input as non-empty and it'll satisfy the 'required' validation.
// So, we only add the model if there's actual data.
this.model = {
jsdate: this.date
};
}
}
/**
* @param {?} changes
* @return {?}
*/
ngOnChanges(changes) {
// Parent component has passed in null, so we have to manually clear the input. This leads to 2 change detection cycles.
// We could refactor it down to one, but the performance hit is minimal for such a simple component.
if (this.date === null) {
this.clearDate();
this._onChange(null);
this._onTouched();
}
}
/**
* @param {?} event
* @return {?}
*/
onDateChanged(event) {
if (event.jsdate || event.jsdate === null) {
// Always emit a Date (or null)
this.dateChange.emit(event.jsdate);
this._onChange(event.jsdate);
this._onTouched();
}
}
/**
* @return {?}
*/
clearDate() {
if (this.ngxdp) {
// We don't need to emit here, because by changing date we'll trigger onDateChanged automatically.
this.date = null;
this.ngxdp.clearDate();
}
}
/**
* @param {?} fn
* @return {?}
*/
registerOnChange(fn) {
this._onChange = fn;
}
/**
* @param {?} fn
* @return {?}
*/
registerOnTouched(fn) {
this._onTouched = fn;
}
/**
* @param {?} obj
* @return {?}
*/
writeValue(obj) {
this.model = {
jsdate: obj
};
}
}
DatepickerComponent.decorators = [
{ type: Component, args: [{
selector: 'common-datepicker',
template: "<div>\r\n <label><span>{{labelText}}</span>\r\n <div class=\"input-group\">\r\n\r\n <input class=\"form-control\" placeholder=\"YYYY/MM/DD\"\r\n ngx-mydatepicker name=\"datepicker-{{labelText}}-{{objectId}}\"\r\n [(ngModel)]=\"model\"\r\n [options]=\"datepickerOptions\"\r\n #dp=\"ngx-mydatepicker\"\r\n #dateEl='ngModel'\r\n (dateChanged)=\"onDateChanged($event)\"\r\n [required]='required'\r\n [disabled]=\"disabled\"\r\n autocomplete=\"off\"/>\r\n\r\n <span class=\"input-group-append float-label-append\">\r\n <button type=\"button\" class=\"btn btn-default\" (click)=\"dp.toggleCalendar()\">\r\n <i class=\"fa fa-calendar\"></i>\r\n </button>\r\n </span>\r\n </div>\r\n </label>\r\n</div>\r\n\r\n<!-- InvalidDateFormat comes from ngxmydatepicker, so we have a little less control over it. -->\r\n<div *ngIf=\"!disabled && dateEl.touched\"\r\n role=\"alert\"\r\n class='error-container'\r\n aria-live=\"assertive\">\r\n <div class=\"text-danger\"\r\n *ngIf=\"(dateEl?.errors?.required) && errorMessages?.required && !dateEl?.errors?.invalidDateFormat\">\r\n {{errorMessages.required}}\r\n </div>\r\n <!-- ngx-mydatepicker has it's own errors and we can't easily add our own, so we have reduced error messages. -->\r\n <!-- <div class=\"text-danger\"\r\n *ngIf=\"dateEl?.errors?.dayOutOfRange && errorMessages?.dayOutOfRange\">\r\n {{errorMessages.dayOutOfRange}}\r\n </div>\r\n <div class=\"text-danger\"\r\n *ngIf=\"dateEl?.errors?.yearDistantPast && errorMessages?.yearDistantPast\">\r\n {{errorMessages.yearDistantPast}}\r\n </div>\r\n <div class=\"text-danger\"\r\n *ngIf=\"dateEl?.errors?.yearDistantFuture && errorMessages?.yearDistantFuture\">\r\n {{errorMessages.yearDistantFuture}}\r\n </div>\r\n <div class=\"text-danger\"\r\n *ngIf=\"dateEl?.errors?.noPastDatesAllowed && errorMessages?.noPastDatesAllowed\">\r\n {{errorMessages.noPastDatesAllowed}}\r\n </div>\r\n\r\n <div class=\"text-danger\"\r\n *ngIf=\"dateEl?.errors?.noFutureDatesAllowed && errorMessages?.noFutureDatesAllowed\">\r\n {{errorMessages.noFutureDatesAllowed}}\r\n </div> -->\r\n <div class=\"text-danger\"\r\n *ngIf=\"(dateEl?.errors?.invalidValue || dateEl?.errors?.invalidDateFormat) && errorMessages?.invalidValue\">\r\n {{errorMessages.invalidValue}}\r\n </div>\r\n</div>\r\n",
/* Re-use the same ngForm that it's parent is using. The component will show
* up in its parents `this.form`, and will auto-update `this.form.valid`
*/
viewProviders: [{ provide: ControlContainer, useExisting: forwardRef((/**
* @return {?}
*/
() => NgForm)) }],
providers: [
{
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: forwardRef((/**
* @return {?}
*/
() => DatepickerComponent))
}
],
styles: [".datepicker--mini{display:flex;flex-wrap:nowrap}.datepicker--mini:not(.hide-clear)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.datepicker--mini .input-group-append .btn{padding:0 .5rem}.input-group-append{z-index:0}.float-label-append{margin-bottom:calc(.5rem + 2px)}.has-float-label{flex-basis:calc(100% - 36px)}input::-ms-clear{display:none}"]
}] }
];
/** @nocollapse */
DatepickerComponent.ctorParameters = () => [];
DatepickerComponent.propDecorators = {
size: [{ type: Input }],
date: [{ type: Input }],
dateChange: [{ type: Output }],
disabled: [{ type: Input }],
labelText: [{ type: Input }],
required: [{ type: Input }],
disableUntil: [{ type: Input }],
disableSince: [{ type: Input }],
onlyFutureDates: [{ type: Input }],
clearButton: [{ type: Input }],
dateFormat: [{ type: Input }],
errorMessages: [{ type: Input }],
ngxdp: [{ type: ViewChild, args: ['dp',] }]
};
if (false) {
/**
* Component size can be reduced, see Datepickersizes for options
* @type {?}
*/
DatepickerComponent.prototype.size;
/** @type {?} */
DatepickerComponent.prototype.date;
/** @type {?} */
DatepickerComponent.prototype.dateChange;
/** @type {?} */
DatepickerComponent.prototype.disabled;
/** @type {?} */
DatepickerComponent.prototype.labelText;
/** @type {?} */
DatepickerComponent.prototype.required;
/**
* Dates **before** disableUntil will not be valid selections. Maps to a ngx-mydatepicker option, but we convert IMyDate to Date
* @type {?}
*/
DatepickerComponent.prototype.disableUntil;
/**
* Dates **after** disableSince will not be valid selections. Maps to a ngx-mydatepicker option, but we convert IMyDate to Date
* @type {?}
*/
DatepickerComponent.prototype.disableSince;
/**
* Equivalent to setting disableBefore to tomorrow.
* @type {?}
*/
DatepickerComponent.prototype.onlyFutureDates;
/**
* Control visibility of the clear 'x' button on the mini datepicker.
*
* **'visible'** is default, button exists
*
* **'none'** means the element does not exist
*
* **'invisible'** means the element takes up space but is not visible / cannot be
* used.
*
* Invisible is useful when you want to make sure a datepicker is the same
* size as a visible one.
* @type {?}
*/
DatepickerComponent.prototype.clearButton;
/**
* Format for how to display the date to the user.
* @type {?}
*/
DatepickerComponent.prototype.dateFormat;
/** @type {?} */
DatepickerComponent.prototype.errorMessages;
/**
* Datetime model used to interface with ngx-datepicker.
* @type {?}
*/
DatepickerComponent.prototype.model;
/** @type {?} */
DatepickerComponent.prototype.DatepickerSizes;
/** @type {?} */
DatepickerComponent.prototype.ngxdp;
/**
* Default options for wrapped ngx-datepicker.
* @type {?}
*/
DatepickerComponent.prototype.datepickerOptions;
/** @type {?} */
DatepickerComponent.prototype._onChange;
/** @type {?} */
DatepickerComponent.prototype._onTouched;
}
/** @enum {string} */
const DatepickerSizes = {
MINI: 'mini',
DEFAULT: 'default',
};
export { DatepickerSizes };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0ZXBpY2tlci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9tb2gtY29tbW9uLWxpYi8iLCJzb3VyY2VzIjpbImxpYi9jb21wb25lbnRzL2RhdGVwaWNrZXIvZGF0ZXBpY2tlci5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQVUsS0FBSyxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQWlCLFNBQVMsRUFBYSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDaEksT0FBTyxFQUE0Qix3QkFBd0IsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ3RGLE9BQU8sRUFBRSxNQUFNLEVBQUUsZ0JBQWdCLEVBQUUsaUJBQWlCLEVBQXdCLE1BQU0sZ0JBQWdCLENBQUM7QUFDbkcsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLG1CQUFtQixDQUFDOzs7Ozs7Ozs7Ozs7Ozs7OztBQWtCekMsa0NBUUM7OztJQVBDLGdDQUFrQjs7SUFDbEIscUNBQXVCOztJQUN2Qix1Q0FBeUI7O0lBQ3pCLHlDQUEyQjs7SUFDM0IsMENBQTRCOztJQUM1Qiw0Q0FBOEI7O0lBQzlCLG9DQUFzQjs7Ozs7Ozs7OztBQTRCeEIsTUFBTSxPQUFPLG1CQUFvQixTQUFRLElBQUk7SUF5RDNDO1FBQ0UsS0FBSyxFQUFFLENBQUM7Ozs7UUF4REQsU0FBSSxHQUFvQixlQUFlLENBQUMsT0FBTyxDQUFDO1FBRS9DLGVBQVUsR0FBRyxJQUFJLFlBQVksRUFBUSxDQUFDO1FBSXZDLGFBQVEsR0FBWSxLQUFLLENBQUM7Ozs7Ozs7Ozs7Ozs7O1FBeUIxQixnQkFBVyxHQUFxQyxTQUFTLENBQUM7Ozs7UUFLMUQsZUFBVSxHQUFXLFlBQVksQ0FBQzs7UUFTM0Msb0JBQWUsR0FBMkIsZUFBZSxDQUFDO1FBT25ELGNBQVM7Ozs7UUFBRyxDQUFDLENBQU0sRUFBRSxFQUFFLEdBQUUsQ0FBQyxFQUFDO1FBQzNCLGVBQVU7OztRQUFHLEdBQUcsRUFB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TUFBTSxFQUFFLEdBQUc7U0FDWixDQUFDO0lBQ0osQ0FBQzs7O1lBN0xGLFNBQVMsU0FBQztnQkFDVCxRQUFRLEVBQUUsbUJBQW1CO2dCQUM3Qixra0ZBQTBDOzs7O2dCQUsxQyxhQUFhLEVBQUUsQ0FBRSxFQUFFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxXQUFXLEVBQUUsVUFBVTs7O3dCQUFDLEdBQUcsRUFBRSxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUU7Z0JBQ3hGLFNBQVMsRUFBRTtvQkFDVDt3QkFDRSxPQUFPLEVBQUUsaUJBQWlCO3dCQUMxQixLQUFLLEVBQUUsSUFBSTt3QkFDWCxXQUFXLEVBQUUsVUFBVTs7O3dCQUFDLEdBQUcsRUFBRSxDQUFDLG1CQUFtQixFQUFDO3FCQUNuRDtpQkFDRjs7YUFDRjs7Ozs7bUJBR0UsS0FBSzttQkFDTCxLQUFLO3lCQUNMLE1BQU07dUJBQ04sS0FBSzt3QkFDTCxLQUFLO3VCQUVMLEtBQUs7MkJBSUwsS0FBSzsyQkFHTCxLQUFLOzhCQUdMLEtBQUs7MEJBZUwsS0FBSzt5QkFLTCxLQUFLOzRCQUVMLEtBQUs7b0JBU0wsU0FBUyxTQUFDLElBQUk7Ozs7Ozs7SUEvQ2YsbUNBQXlEOztJQUN6RCxtQ0FBb0I7O0lBQ3BCLHlDQUFnRDs7SUFDaEQsdUNBQTJCOztJQUMzQix3Q0FBMkI7O0lBRTNCLHVDQUFtQzs7Ozs7SUFJbkMsMkNBQTRCOzs7OztJQUc1QiwyQ0FBNEI7Ozs7O0lBRzVCLDhDQUFrQzs7Ozs7Ozs7Ozs7Ozs7O0lBZWxDLDBDQUFtRTs7Ozs7SUFLbkUseUNBQTJDOztJQUUzQyw0Q0FBcUM7Ozs7O0lBSXJDLG9DQUFXOztJQUdYLDhDQUEwRDs7SUFFMUQsb0NBQWlEOzs7OztJQUdqRCxnREFBbUM7O0lBRW5DLHdDQUFrQzs7SUFDbEMseUNBQTZCOzs7O0lBMEg3QixNQUFPLE1BQU07SUFDYixTQUFVLFNBQVMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIE9uSW5pdCwgSW5wdXQsIE91dHB1dCwgRXZlbnRFbWl0dGVyLCBTaW1wbGVDaGFuZ2VzLCBWaWV3Q2hpbGQsIE9uQ2hhbmdlcywgZm9yd2FyZFJlZiB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBJTmd4TXlEcE9wdGlvbnMsIElNeURhdGUsIE5neE15RGF0ZVBpY2tlckRpcmVjdGl2ZSB9IGZyb20gJ25neC1teWRhdGVwaWNrZXInO1xyXG5pbXBvcnQgeyBOZ0Zvcm0sIENvbnRyb2xDb250YWluZXIsIE5HX1ZBTFVFX0FDQ0VTU09SLCBDb250cm9sVmFsdWVBY2Nlc3NvciB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcclxuaW1wb3J0IHsgQmFzZSB9IGZyb20gJy4uLy4uL21vZGVscy9iYXNlJztcclxuXHJcbi8qKlxyXG4gKiBDb21wb25lbnQgTlBNIHBhY2thZ2UgZGVwZW5kZW5jaWVzOlxyXG4gKiBhKSBtb21lbnRcclxuICpcclxuICogVGhpcyBjb21wb25lbnQgcmVwb3J0cyB0aGUgZm9sbG93aW5nIGVycm9ycy5cclxuICogICAgcmVxdWlyZWRcclxuICogICAgZGF5T3V0T2ZSYW5nZVxyXG4gKiAgICB5ZWFyRGlzdGFudFBhc3RcclxuICogICAgeWVhckRpc3RhbnRGdXR1cmVcclxuICogICAgbm9GdXR1cmVEYXRlc0FsbG93ZWRcclxuICogICAgaW52YWxpZFZhbHVlXHJcbiAqXHJcbiAqICBUaGVzZSBtZXNzYWdlcyBjYW4gYmUgY2hhbmdlZCBieSB1cGRhdGVkIG1lc3NhZ2VzIHVzaW5nIHRoZSBlcnJvck1lc3NhZ2VzIGludGVyZmFjZS9cclxuICogIEV4LiB7IHJlcXVpcmVkOiAnVGhpcyBmaWVsZCBpcyByZXF1aXJlZCcsIGludmFsaWRWYWx1ZTogJ3tsYWJlbH0gaXMgaW52YWxpZCcgfVxyXG4gKi9cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgRGF0ZUVycm9yTXNnIHsgLy8gVE9ETzogUmVtb3ZlIC0gcG9zc2libGUgYnJlYWtpbmcgY2hhbmdlIC0gY3VycmVudGx5IGRhdGVwaWNrZXIgdXNlcyBpdFxyXG4gIHJlcXVpcmVkPzogc3RyaW5nO1xyXG4gIGRheU91dE9mUmFuZ2U/OiBzdHJpbmc7XHJcbiAgeWVhckRpc3RhbnRQYXN0Pzogc3RyaW5nO1xyXG4gIHllYXJEaXN0YW50RnV0dXJlPzogc3RyaW5nO1xyXG4gIG5vUGFzdERhdGVzQWxsb3dlZD86IHN0cmluZztcclxuICBub0Z1dHVyZURhdGVzQWxsb3dlZD86IHN0cmluZztcclxuICBpbnZhbGlkVmFsdWU/OiBzdHJpbmc7XHJcbn1cclxuXHJcblxyXG4vKipcclxuICogUFJJTUUgZGF0ZXBpY2tlciBjb21wb25lbnQuIExhcmdlbHkgYSB3cmFwcGVyIGZvciBuZ3gtbXlkYXRlcGlja2VyXHJcbiAqIGh0dHBzOi8vZ2l0aHViLmNvbS9rZWtlaC9uZ3gtbXlkYXRlcGlja2VyXHJcbiAqXHJcbiAqIE5PVEUgLSBZT1UgTVVTVCBJTkNMVURFIE5HWC1NWURBVEVQSUNLRVIgSU4gWU9VUiBQQVJFTlQgQVBQTElDQVRJT04gVE8gVVNFXHJcbiAqIFRISVMgQ09NUE9ORU5UISAgVGhpcyBpcyBkdWUgdG8gc29tZSBwb29yIGltcGxlbWVudGF0aW9uIGluIG5neC1teWRhdGVwaWNrZXIuXHJcbiAqIE1ha2Ugc3VyZSB0byB1c2UgdGhlIHNhbWUgdmVyc2lvbiB0aGF0IHRoaXMgbGlicmFyeSB1c2VzLlxyXG4gKi9cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICdjb21tb24tZGF0ZXBpY2tlcicsXHJcbiAgdGVtcGxhdGVVcmw6ICcuL2RhdGVwaWNrZXIuY29tcG9uZW50Lmh0bWwnLFxyXG4gIHN0eWxlVXJsczogWycuL2RhdGVwaWNrZXIuY29tcG9uZW50LnNjc3MnXSxcclxuICAvKiBSZS11c2UgdGhlIHNhbWUgbmdGb3JtIHRoYXQgaXQncyBwYXJlbnQgaXMgdXNpbmcuIFRoZSBjb21wb25lbnQgd2lsbCBzaG93XHJcbiAgICogdXAgaW4gaXRzIHBhcmVudHMgYHRoaXMuZm9ybWAsIGFuZCB3aWxsIGF1dG8tdXBkYXRlIGB0aGlzLmZvcm0udmFsaWRgXHJcbiAgICovXHJcbiAgdmlld1Byb3ZpZGVyczogWyB7IHByb3ZpZGU6IENvbnRyb2xDb250YWluZXIsIHVzZUV4aXN0aW5nOiBmb3J3YXJkUmVmKCgpID0+IE5nRm9ybSApIH0gXSxcclxuICBwcm92aWRlcnM6IFtcclxuICAgIHtcclxuICAgICAgcHJvdmlkZTogTkdfVkFMVUVfQUNDRVNTT1IsXHJcbiAgICAgIG11bHRpOiB0cnVlLFxyXG4gICAgICB1c2VFeGlzdGluZzogZm9yd2FyZFJlZigoKSA9PiBEYXRlcGlja2VyQ29tcG9uZW50KVxyXG4gICAgfVxyXG4gIF1cclxufSlcclxuZXhwb3J0IGNsYXNzIERhdGVwaWNrZXJDb21wb25lbnQgZXh0ZW5kcyBCYXNlIGltcGxlbWVudHMgT25Jbml0LCBPbkNoYW5nZXMsIENvbnRyb2xWYWx1ZUFjY2Vzc29yIHtcclxuICAvKiogQ29tcG9uZW50IHNpemUgY2FuIGJlIHJlZHVjZWQsIHNlZSBEYXRlcGlja2Vyc2l6ZXMgZm9yIG9wdGlvbnMgKi9cclxuICBASW5wdXQoKSBzaXplOiBEYXRlcGlja2VyU2l6ZXMgPSBEYXRlcGlja2VyU2l6ZXMuREVGQVVMVDtcclxuICBASW5wdXQoKSBkYXRlOiBEYXRlO1xyXG4gIEBPdXRwdXQoKSBkYXRlQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxEYXRlPigpO1xyXG4gIEBJbnB1dCgpIGRpc2FibGVkOiBib29sZWFuO1xyXG4gIEBJbnB1dCgpIGxhYmVsVGV4dDogc3RyaW5nO1xyXG5cclxuICBASW5wdXQoKSByZXF1aXJlZDogYm9vbGVhbiA9IGZhbHNlO1xyXG5cclxuXHJcbiAgLyoqIERhdGVzICoqYmVmb3JlKiogZGlzYWJsZVVudGlsIHdpbGwgbm90IGJlIHZhbGlkIHNlbGVjdGlvbnMuICBNYXBzIHRvIGEgbmd4LW15ZGF0ZXBpY2tlciBvcHRpb24sIGJ1dCB3ZSBjb252ZXJ0IElNeURhdGUgdG8gRGF0ZSAgKi9cclxuICBASW5wdXQoKSBkaXNhYmxlVW50aWw6IERhdGU7XHJcblxyXG4gIC8qKiBEYXRlcyAqKmFmdGVyKiogZGlzYWJsZVNpbmNlIHdpbGwgbm90IGJlIHZhbGlkIHNlbGVjdGlvbnMuICBNYXBzIHRvIGEgbmd4LW15ZGF0ZXBpY2tlciBvcHRpb24sIGJ1dCB3ZSBjb252ZXJ0IElNeURhdGUgdG8gRGF0ZSAqL1xyXG4gIEBJbnB1dCgpIGRpc2FibGVTaW5jZTogRGF0ZTtcclxuXHJcbiAgLyoqIEVxdWl2YWxlbnQgdG8gc2V0dGluZyBkaXNhYmxlQmVmb3JlIHRvIHRvbW9ycm93LiAqL1xyXG4gIEBJbnB1dCgpIG9ubHlGdXR1cmVEYXRlczogYm9vbGVhbjtcclxuXHJcbiAgLyoqXHJcbiAgICogQ29udHJvbCB2aXNpYmlsaXR5IG9mIHRoZSBjbGVhciAneCcgYnV0dG9uIG9uIHRoZSBtaW5pIGRhdGVwaWNrZXIuXHJcbiAgICpcclxuICAgKiAqKid2aXNpYmxlJyoqIGlzIGRlZmF1bHQsIGJ1dHRvbiBleGlzdHNcclxuICAgKlxyXG4gICAqICoqJ25vbmUnKiogbWVhbnMgdGhlIGVsZW1lbnQgZG9lcyBub3QgZXhpc3RcclxuICAgKlxyXG4gICAqICoqJ2ludmlzaWJsZScqKiBtZWFucyB0aGUgZWxlbWVudCB0YWtlcyB1cCBzcGFjZSBidXQgaXMgbm90IHZpc2libGUgLyBjYW5ub3QgYmVcclxuICAgKiB1c2VkLlxyXG4gICAqXHJcbiAgICogSW52aXNpYmxlIGlzIHVzZWZ1bCB3aGVuIHlvdSB3YW50IHRvIG1ha2Ugc3VyZSBhIGRhdGVwaWNrZXIgaXMgdGhlIHNhbWVcclxuICAgKiBzaXplIGFzIGEgdmlzaWJsZSBvbmUuXHJcbiAgICovXHJcbiAgQElucHV0KCkgY2xlYXJCdXR0b246ICd2aXNpYmxlJyB8ICdpbnZpc2libGUnIHwgJ25vbmUnID0gJ3Zpc2libGUnO1xyXG5cclxuXHJcblxyXG4gIC8qKiBGb3JtYXQgZm9yIGhvdyB0byBkaXNwbGF5IHRoZSBkYXRlIHRvIHRoZSB1c2VyLiAqL1xyXG4gIEBJbnB1dCgpIGRhdGVGb3JtYXQ6IHN0cmluZyA9ICd5eXl5L21tL2RkJztcclxuXHJcbiAgQElucHV0KCkgZXJyb3JNZXNzYWdlczogRGF0ZUVycm9yTXNnO1xyXG5cclxuICAvKiogRGF0ZXRpbWUgbW9kZWwgdXNlZCB0byBpbnRlcmZhY2Ugd2l0aCBuZ3gtZGF0ZXBpY2tlci4gKi9cclxuICAvLyBtb2RlbDogYW55O1xyXG4gIG1vZGVsOiBhbnk7XHJcblxyXG4gIC8vIE1ha2UgZW51bSBhY2Nlc3NpYmxlIGluIEhUTUxcclxuICBEYXRlcGlja2VyU2l6ZXM6IHR5cGVvZiBEYXRlcGlja2VyU2l6ZXMgPSBEYXRlcGlja2VyU2l6ZXM7XHJcblxyXG4gIEBWaWV3Q2hpbGQoJ2RwJykgbmd4ZHA6IE5neE15RGF0ZVBpY2tlckRpcmVjdGl2ZTtcclxuXHJcbiAgLyoqIERlZmF1bHQgb3B0aW9ucyBmb3Igd3JhcHBlZCBuZ3gtZGF0ZXBpY2tlci4gKi9cclxuICBkYXRlcGlja2VyT3B0aW9uczogSU5neE15RHBPcHRpb25zO1xyXG5cclxuICBwdWJsaWMgX29uQ2hhbmdlID0gKF86IGFueSkgPT4ge307XHJcbiAgcHVibGljIF9vblRvdWNoZWQgPSAoKSA9PiB7fTtcclxuXHJcbiAgY29uc3RydWN0b3IoKSB7XHJcbiAgICBzdXBlcigpO1xyXG4gICB9XHJcblxyXG4gIGNvbnZlcnREYXRlVG9TaW1wbGVEYXRlKGRhdGU6IERhdGUpOiBJTXlEYXRlIHtcclxuICAgIGlmIChkYXRlID09PSBudWxsIHx8IGRhdGUgPT09IHVuZGVmaW5lZCkgeyByZXR1cm4gbnVsbDsgfVxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgeWVhcjogZGF0ZS5nZXRGdWxsWWVhcigpLFxyXG4gICAgICBtb250aDogZGF0ZS5nZXRNb250aCgpICsgMSxcclxuICAgICAgZGF5OiBkYXRlLmdldERhdGUoKSxcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICBjb252ZXJ0U2ltcGxlRGF0ZVRvRGF0ZShkYXRlOiBJTXlEYXRlKTogRGF0ZSB7XHJcbiAgICAvLyBXaGVuIG5neC1teWRhdGVwaWNrZXIgaXMgY2xlYXJlZCwgaXQgcmV0dXJucyB7eWVhcjogMCwgbW9udGg6IDAsIGRheTogMH1cclxuICAgIGlmIChkYXRlLnllYXIgPT09IDApIHtcclxuICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gbmV3IERhdGUoZGF0ZS55ZWFyLCBkYXRlLm1vbnRoIC0gMSwgZGF0ZS5kYXkpO1xyXG4gIH1cclxuXHJcbiAgaXNEYXRlKHg6IGFueSk6IHggaXMgRGF0ZSB7XHJcbiAgICBpZiAoIXgpIHsgcmV0dXJuIGZhbHNlOyB9XHJcbiAgICByZXR1cm4geC5nZXREYXRlICE9PSB1bmRlZmluZWQ7XHJcbiAgfVxyXG5cclxuICBuZ09uSW5pdCgpIHtcclxuICAgIGlmICghdGhpcy5lcnJvck1lc3NhZ2VzKSB7XHJcbiAgICAgIHRoaXMuZXJyb3JNZXNzYWdlcyA9IHtcclxuICAgICAgICByZXF1aXJlZDogdGhpcy5sYWJlbFRleHQgKyAnIGlzIHJlcXVpcmVkLicsXHJcbiAgICAgICAgZGF5T3V0T2ZSYW5nZTogJ0ludmFsaWQgJyArIHRoaXMubGFiZWxUZXh0ICsgJy4nLFxyXG4gICAgICAgIHllYXJEaXN0YW50UGFzdDogJ0ludmFsaWQgJyArIHRoaXMubGFiZWxUZXh0ICsgJy4nLFxyXG4gICAgICAgIHllYXJEaXN0YW50RnV0dXJlOiAnSW52YWxpZCAnICsgdGhpcy5sYWJlbFRleHQgKyAnLicsXHJcbiAgICAgICAgbm9GdXR1cmVEYXRlc0FsbG93ZWQ6ICdJbnZhbGlkICcgKyB0aGlzLmxhYmVsVGV4dCArICcuJyxcclxuICAgICAgICBpbnZhbGlkVmFsdWU6ICdJbnZhbGlkICcgKyB0aGlzLmxhYmVsVGV4dCArICcuJ1xyXG4gICAgICB9O1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuZGF0ZXBpY2tlck9wdGlvbnMgPSB7XHJcbiAgICAgIGRhdGVGb3JtYXQ6IHRoaXMuZGF0ZUZvcm1hdCxcclxuICAgICAgc3VuSGlnaGxpZ2h0OiBmYWxzZSxcclxuICAgICAgYXBwZW5kU2VsZWN0b3JUb0JvZHk6IHRydWUsXHJcbiAgICB9O1xyXG5cclxuICAgIGlmICh0aGlzLnNpemUgPT09IERhdGVwaWNrZXJTaXplcy5NSU5JKSB7XHJcbiAgICAgIC8vIFNldCB3aWR0aC9oZWlnaHQgdG8gNC81IG9mIGRlZmF1bHRcclxuICAgICAgdGhpcy5kYXRlcGlja2VyT3B0aW9ucy5zZWxlY3RvckhlaWdodCA9ICcxODVweCc7XHJcbiAgICAgIHRoaXMuZGF0ZXBpY2tlck9wdGlvbnMuc2VsZWN0b3JXaWR0aCA9ICcyMDFweCc7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHRoaXMuaXNEYXRlKHRoaXMuZGlzYWJsZVNpbmNlKSkge1xyXG4gICAgICB0aGlzLmRhdGVwaWNrZXJPcHRpb25zLmRpc2FibGVTaW5jZSA9IHRoaXMuY29udmVydERhdGVUb1NpbXBsZURhdGUodGhpcy5kaXNhYmxlU2luY2UpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICh0aGlzLmlzRGF0ZSh0aGlzLmRpc2FibGVVbnRpbCkpIHtcclxuICAgICAgdGhpcy5kYXRlcGlja2VyT3B0aW9ucy5kaXNhYmxlVW50aWwgPSB0aGlzLmNvbnZlcnREYXRlVG9TaW1wbGVEYXRlKHRoaXMuZGlzYWJsZVNpbmNlKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAodGhpcy5vbmx5RnV0dXJlRGF0ZXMpIHtcclxuICAgICAgY29uc3QgdG9kYXkgPSBuZXcgRGF0ZSgpO1xyXG4gICAgICB0aGlzLmRhdGVwaWNrZXJPcHRpb25zLmRpc2FibGVVbnRpbCA9IHRoaXMuY29udmVydERhdGVUb1NpbXBsZURhdGUodG9kYXkpO1xyXG4gICAgfVxyXG5cclxuXHJcbiAgICBpZiAodGhpcy5kYXRlKSB7XHJcbiAgICAgIC8vIEV2ZW4gaWYganNkYXRlIHdpbmRzIHVwIGJlaW5nIHVuZGVmaW5lZCwgZXZlbiBkZWZpbmluZyB0aGlzLm1vZGVsIHdpbGxcclxuICAgICAgLy8gc2V0IHRoZSBpbnB1dCBhcyBub24tZW1wdHkgYW5kIGl0J2xsIHNhdGlzZnkgdGhlICdyZXF1aXJlZCcgdmFsaWRhdGlvbi5cclxuICAgICAgLy8gU28sIHdlIG9ubHkgYWRkIHRoZSBtb2RlbCBpZiB0aGVyZSdzIGFjdHVhbCBkYXRhLlxyXG4gICAgICB0aGlzLm1vZGVsID0ge1xyXG4gICAgICAgIGpzZGF0ZTogdGhpcy5kYXRlXHJcbiAgICAgIH07XHJcbiAgICB9XHJcblxyXG5cclxuICB9XHJcblxyXG5cclxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKSB7XHJcbiAgICAvLyBQYXJlbnQgY29tcG9uZW50IGhhcyBwYXNzZWQgaW4gbnVsbCwgc28gd2UgaGF2ZSB0byBtYW51YWxseSBjbGVhciB0aGUgaW5wdXQuIFRoaXMgbGVhZHMgdG8gMiBjaGFuZ2UgZGV0ZWN0aW9uIGN5Y2xlcy5cclxuICAgIC8vIFdlIGNvdWxkIHJlZmFjdG9yIGl0IGRvd24gdG8gb25lLCBidXQgdGhlIHBlcmZvcm1hbmNlIGhpdCBpcyBtaW5pbWFsIGZvciBzdWNoIGEgc2ltcGxlIGNvbXBvbmVudC5cclxuICAgIGlmICh0aGlzLmRhdGUgPT09IG51bGwpIHtcclxuICAgICAgdGhpcy5jbGVhckRhdGUoKTtcclxuICAgICAgdGhpcy5fb25DaGFuZ2UobnVsbCk7XHJcbiAgICAgIHRoaXMuX29uVG91Y2hlZCgpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgb25EYXRlQ2hhbmdlZChldmVudCk6IHZvaWQge1xyXG4gICAgaWYgKGV2ZW50LmpzZGF0ZSB8fCBldmVudC5qc2RhdGUgPT09IG51bGwpIHtcclxuICAgICAgLy8gQWx3YXlzIGVtaXQgYSBEYXRlIChvciBudWxsKVxyXG4gICAgICB0aGlzLmRhdGVDaGFuZ2UuZW1pdChldmVudC5qc2RhdGUpO1xyXG4gICAgICB0aGlzLl9vbkNoYW5nZShldmVudC5qc2RhdGUpO1xyXG4gICAgICB0aGlzLl9vblRvdWNoZWQoKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGNsZWFyRGF0ZSgpIHtcclxuICAgIGlmICh0aGlzLm5neGRwKSB7XHJcbiAgICAgIC8vIFdlIGRvbid0IG5lZWQgdG8gZW1pdCBoZXJlLCBiZWNhdXNlIGJ5IGNoYW5naW5nIGRhdGUgd2UnbGwgdHJpZ2dlciBvbkRhdGVDaGFuZ2VkIGF1dG9tYXRpY2FsbHkuXHJcbiAgICAgIHRoaXMuZGF0ZSA9IG51bGw7XHJcbiAgICAgIHRoaXMubmd4ZHAuY2xlYXJEYXRlKCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICByZWdpc3Rlck9uQ2hhbmdlKGZuOiBhbnkpOiB2b2lkIHtcclxuICAgIHRoaXMuX29uQ2hhbmdlID0gZm47XHJcbiAgfVxyXG5cclxuICByZWdpc3Rlck9uVG91Y2hlZChmbjogYW55KTogdm9pZCB7XHJcbiAgICB0aGlzLl9vblRvdWNoZWQgPSBmbjtcclxuICB9XHJcblxyXG4gIHdyaXRlVmFsdWUob2JqOiBhbnkpOiB2b2lkIHtcclxuICAgIHRoaXMubW9kZWwgPSB7XHJcbiAgICAgIGpzZGF0ZTogb2JqXHJcbiAgICB9O1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGVudW0gRGF0ZXBpY2tlclNpemVzIHtcclxuICBNSU5JID0gJ21pbmknLFxyXG4gIERFRkFVTFQgPSAnZGVmYXVsdCdcclxufVxyXG4iXX0=