@data-cafe/datagrid
Version:
A very generic datagrid component for data-café applications
126 lines • 23.1 kB
JavaScript
import { __decorate } from "tslib";
/*
* data·café
* Copyright (c) 2021-2022 Data Terrae
* This program is under the terms of the GNU Affero General Public License version 3
* The full license information can be found in LICENSE in the root directory of this project.
*/
import { Component, EventEmitter, Input, Output, } from '@angular/core';
import { FormControl } from '@angular/forms';
import { UntilDestroy } from '@ngneat/until-destroy';
import { ICONS } from '../constant';
import * as i0 from "@angular/core";
import * as i1 from "@ngneat/edit-in-place";
import * as i2 from "@angular/common";
import * as i3 from "@angular/forms";
import * as i4 from "@clr/angular";
let CellEditableComponent = class CellEditableComponent {
constructor(renderer, element) {
this.renderer = renderer;
this.element = element;
this.ICON = ICONS;
/**
* Main item to edit.
* It could be null, meaning no value.
* The `undefined` value is not allowed here; please use `null` instead.
*/
this.item = null;
/**
* Allow edition
*/
this.enable = true;
/**
* Specify some extra validators
*/
this.validators = [];
/**
* call on save:
* - button validate
* - enter key
*/
this.save = new EventEmitter();
/**
* Dispatch a event indicating whenever this component is in edition mode.
*/
this.editing$ = new EventEmitter();
this.formControl = new FormControl();
}
ngOnInit() {
// Styling parent cell <td>
const cellElement = this.element.nativeElement.closest('clr-dg-cell');
this.renderer.addClass(cellElement, 'has-edit');
}
getLabel(value) {
if (!value) {
return undefined;
}
else if (['string', 'number'].includes(typeof value)) {
return `${value}`;
}
else if (this.itemToLabel) {
return this.itemToLabel(value);
}
else if ('label' in value) {
return value.label;
}
else if ('name' in value) {
return value.name;
}
else if ('title' in value) {
return value.title;
}
else {
return '' + value;
}
}
onEditableChange(mode) {
if (mode === 'edit') {
this.formControl.setValidators(this.validators);
this.formControl.setValue(this.item);
}
this.editing$.emit(mode === 'edit');
}
trim(value) {
if (typeof value === 'string') {
return value.trim();
}
else {
return value;
}
}
onEdit() {
if (this.formControl.valid) {
this.save.emit({
previous: this.item ?? null,
current: this.trim(this.formControl.value) ?? null,
});
}
}
};
CellEditableComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: CellEditableComponent, deps: [{ token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
CellEditableComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.1.1", type: CellEditableComponent, selector: "dt-cell-editable", inputs: { item: "item", fallbackLabel: "fallbackLabel", altValues: "altValues", itemToLabel: "itemToLabel", enable: "enable", validators: "validators" }, outputs: { save: "save", editing$: "editing$" }, ngImport: i0, template: "<!--\n ~ data\u00B7caf\u00E9\n ~ Copyright (c) 2021-2022 Data Terrae\n ~ This program is under the terms of the GNU Affero General Public License version 3\n ~ The full license information can be found in LICENSE in the root directory of this project.\n -->\n\n<editable (modeChange)=\"onEditableChange($event)\"\n (save)=\"onEdit()\"\n [class.can-edit]=\"enable\"\n [class.is-editing]=\"editing$ | async\"\n [enabled]=\"enable\">\n <ng-template viewMode>\n <span [class.missing]=\"!item && fallbackLabel\"\n [innerText]=\"getLabel(item) ?? fallbackLabel ?? ''\"></span>\n </ng-template>\n <ng-template editMode>\n\n <input *ngIf=\"!altValues\"\n [formControl]=\"formControl\"\n clrInput\n editableFocusable editableOnEnter editableOnEscape trim=\"blur\"/>\n\n <select *ngIf=\"altValues\"\n [formControl]=\"formControl\"\n clrSelect\n editableFocusable editableOnEnter editableOnEscape>\n <option [label]=\"fallbackLabel\" [ngValue]=\"null\" class=\"missing\"></option>\n <option *ngFor=\"let alt of altValues\" [label]=\"getLabel(alt)\" [ngValue]=\"alt\"></option>\n </select>\n\n <div class=\"btn-group btn-sm btn-icon\">\n <button class=\"btn btn-success\" editableOnSave>\n <cds-icon [attr.shape]=\"ICON.VALID\"></cds-icon>\n </button>\n <button class=\"btn btn-danger\" editableOnCancel>\n <cds-icon [attr.shape]=\"ICON.CANCEL\"></cds-icon>\n </button>\n </div>\n </ng-template>\n</editable>\n", styles: ["@charset \"UTF-8\";/*!\n * data\u00B7caf\u00E9\n * Copyright (c) 2021-2022 Data Terrae\n * This program is under the terms of the GNU Affero General Public License version 3\n * The full license information can be found in LICENSE in the root directory of this project.\n */:host{display:contents}:host editable{height:2rem;display:flex;flex-direction:row;align-items:center;justify-content:space-between}:host editable.can-edit{cursor:pointer}:host editable:not(.is-editing){flex-flow:wrap;padding:0 .6rem;overflow-wrap:break-word}:host editable.is-editing{flex-flow:nowrap;padding:0 .3rem}:host editable ::ng-deep .clr-form-control{display:contents}:host editable ::ng-deep .clr-form-control .clr-control-container{display:contents;margin:0}:host editable ::ng-deep .clr-form-control .clr-control-container .clr-input-wrapper,:host editable ::ng-deep .clr-form-control .clr-control-container .clr-select-wrapper{display:contents}:host editable ::ng-deep .clr-form-control .clr-control-container .clr-input-wrapper input,:host editable ::ng-deep .clr-form-control .clr-control-container .clr-input-wrapper select,:host editable ::ng-deep .clr-form-control .clr-control-container .clr-select-wrapper input,:host editable ::ng-deep .clr-form-control .clr-control-container .clr-select-wrapper select{width:calc(100% - 4.2rem);min-width:unset;max-width:unset;flex-grow:1;flex-shrink:1}:host editable ::ng-deep .btn-group{min-width:3.8rem;flex-grow:0;flex-shrink:0}:host editable ::ng-deep *+.btn-group{margin:0 0 0 .4rem}\n"], components: [{ type: i1.EditableComponent, selector: "editable", inputs: ["enabled", "openBindingEvent", "closeBindingEvent"], outputs: ["save", "cancel", "modeChange"] }], directives: [{ type: i1.ViewModeDirective, selector: "[viewMode]" }, { type: i1.EditModeDirective, selector: "[editMode]" }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i4.ClrInput, selector: "[clrInput]" }, { type: i1.EditableFocusDirective, selector: "[editableFocusable]" }, { type: i1.EditableOnEnterDirective, selector: "[editableOnEnter]" }, { type: i1.EditableOnEscapeDirective, selector: "[editableOnEscape]" }, { type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i3.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i3.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { type: i4.ClrSelect, selector: "[clrSelect]" }, { type: i3.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { type: i3.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i1.EditableSaveDirective, selector: "[editableOnSave]", inputs: ["saveEvent"] }, { type: i4.CdsIconCustomTag, selector: "cds-icon" }, { type: i1.EditableCancelDirective, selector: "[editableOnCancel]", inputs: ["cancelEvent"] }], pipes: { "async": i2.AsyncPipe } });
CellEditableComponent = __decorate([
UntilDestroy()
], CellEditableComponent);
export { CellEditableComponent };
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: CellEditableComponent, decorators: [{
type: Component,
args: [{ selector: 'dt-cell-editable', template: "<!--\n ~ data\u00B7caf\u00E9\n ~ Copyright (c) 2021-2022 Data Terrae\n ~ This program is under the terms of the GNU Affero General Public License version 3\n ~ The full license information can be found in LICENSE in the root directory of this project.\n -->\n\n<editable (modeChange)=\"onEditableChange($event)\"\n (save)=\"onEdit()\"\n [class.can-edit]=\"enable\"\n [class.is-editing]=\"editing$ | async\"\n [enabled]=\"enable\">\n <ng-template viewMode>\n <span [class.missing]=\"!item && fallbackLabel\"\n [innerText]=\"getLabel(item) ?? fallbackLabel ?? ''\"></span>\n </ng-template>\n <ng-template editMode>\n\n <input *ngIf=\"!altValues\"\n [formControl]=\"formControl\"\n clrInput\n editableFocusable editableOnEnter editableOnEscape trim=\"blur\"/>\n\n <select *ngIf=\"altValues\"\n [formControl]=\"formControl\"\n clrSelect\n editableFocusable editableOnEnter editableOnEscape>\n <option [label]=\"fallbackLabel\" [ngValue]=\"null\" class=\"missing\"></option>\n <option *ngFor=\"let alt of altValues\" [label]=\"getLabel(alt)\" [ngValue]=\"alt\"></option>\n </select>\n\n <div class=\"btn-group btn-sm btn-icon\">\n <button class=\"btn btn-success\" editableOnSave>\n <cds-icon [attr.shape]=\"ICON.VALID\"></cds-icon>\n </button>\n <button class=\"btn btn-danger\" editableOnCancel>\n <cds-icon [attr.shape]=\"ICON.CANCEL\"></cds-icon>\n </button>\n </div>\n </ng-template>\n</editable>\n", styles: ["@charset \"UTF-8\";/*!\n * data\u00B7caf\u00E9\n * Copyright (c) 2021-2022 Data Terrae\n * This program is under the terms of the GNU Affero General Public License version 3\n * The full license information can be found in LICENSE in the root directory of this project.\n */:host{display:contents}:host editable{height:2rem;display:flex;flex-direction:row;align-items:center;justify-content:space-between}:host editable.can-edit{cursor:pointer}:host editable:not(.is-editing){flex-flow:wrap;padding:0 .6rem;overflow-wrap:break-word}:host editable.is-editing{flex-flow:nowrap;padding:0 .3rem}:host editable ::ng-deep .clr-form-control{display:contents}:host editable ::ng-deep .clr-form-control .clr-control-container{display:contents;margin:0}:host editable ::ng-deep .clr-form-control .clr-control-container .clr-input-wrapper,:host editable ::ng-deep .clr-form-control .clr-control-container .clr-select-wrapper{display:contents}:host editable ::ng-deep .clr-form-control .clr-control-container .clr-input-wrapper input,:host editable ::ng-deep .clr-form-control .clr-control-container .clr-input-wrapper select,:host editable ::ng-deep .clr-form-control .clr-control-container .clr-select-wrapper input,:host editable ::ng-deep .clr-form-control .clr-control-container .clr-select-wrapper select{width:calc(100% - 4.2rem);min-width:unset;max-width:unset;flex-grow:1;flex-shrink:1}:host editable ::ng-deep .btn-group{min-width:3.8rem;flex-grow:0;flex-shrink:0}:host editable ::ng-deep *+.btn-group{margin:0 0 0 .4rem}\n"] }]
}], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.ElementRef }]; }, propDecorators: { item: [{
type: Input
}], fallbackLabel: [{
type: Input
}], altValues: [{
type: Input
}], itemToLabel: [{
type: Input
}], enable: [{
type: Input
}], validators: [{
type: Input
}], save: [{
type: Output
}], editing$: [{
type: Output
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2VsbC1lZGl0YWJsZS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9kYXRhZ3JpZC9zcmMvbGliL2NlbGwtZWRpdGFibGUvY2VsbC1lZGl0YWJsZS5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9kYXRhZ3JpZC9zcmMvbGliL2NlbGwtZWRpdGFibGUvY2VsbC1lZGl0YWJsZS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7O0dBS0c7QUFFSCxPQUFPLEVBQ0wsU0FBUyxFQUVULFlBQVksRUFDWixLQUFLLEVBRUwsTUFBTSxHQUVQLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxXQUFXLEVBQWUsTUFBTSxnQkFBZ0IsQ0FBQztBQUMxRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDckQsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLGFBQWEsQ0FBQzs7Ozs7O0lBYXZCLHFCQUFxQixTQUFyQixxQkFBcUI7SUF3RGhDLFlBQXFCLFFBQW1CLEVBQ25CLE9BQW1CO1FBRG5CLGFBQVEsR0FBUixRQUFRLENBQVc7UUFDbkIsWUFBTyxHQUFQLE9BQU8sQ0FBWTtRQXZEL0IsU0FBSSxHQUFHLEtBQUssQ0FBQztRQUV0Qjs7OztXQUlHO1FBQ00sU0FBSSxHQUFhLElBQUksQ0FBQztRQXVCL0I7O1dBRUc7UUFDTSxXQUFNLEdBQUcsSUFBSSxDQUFDO1FBRXZCOztXQUVHO1FBQ00sZUFBVSxHQUF1QixFQUFFLENBQUM7UUFFN0M7Ozs7V0FJRztRQUNPLFNBQUksR0FBNEIsSUFBSSxZQUFZLEVBQWEsQ0FBQztRQUV4RTs7V0FFRztRQUNPLGFBQVEsR0FBMEIsSUFBSSxZQUFZLEVBQVcsQ0FBQztRQUV4RSxnQkFBVyxHQUFHLElBQUksV0FBVyxFQUFFLENBQUM7SUFJaEMsQ0FBQztJQUVELFFBQVE7UUFDTiwyQkFBMkI7UUFDM0IsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsT0FBTyxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBQ3RFLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLFdBQVcsRUFBRSxVQUFVLENBQUMsQ0FBQztJQUNsRCxDQUFDO0lBRUQsUUFBUSxDQUFDLEtBQWU7UUFDdEIsSUFBSSxDQUFDLEtBQUssRUFBRTtZQUNWLE9BQU8sU0FBUyxDQUFDO1NBQ2xCO2FBQU0sSUFBSSxDQUFDLFFBQVEsRUFBRSxRQUFRLENBQUMsQ0FBQyxRQUFRLENBQUMsT0FBTyxLQUFLLENBQUMsRUFBRTtZQUN0RCxPQUFPLEdBQUcsS0FBSyxFQUFFLENBQUM7U0FDbkI7YUFBTSxJQUFJLElBQUksQ0FBQyxXQUFXLEVBQUU7WUFDM0IsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxDQUFDO1NBQ2hDO2FBQU0sSUFBSSxPQUFPLElBQUksS0FBSyxFQUFFO1lBQzNCLE9BQVEsS0FBc0MsQ0FBQyxLQUFLLENBQUM7U0FDdEQ7YUFBTSxJQUFJLE1BQU0sSUFBSSxLQUFLLEVBQUU7WUFDMUIsT0FBUSxLQUFxQyxDQUFDLElBQUksQ0FBQztTQUNwRDthQUFNLElBQUksT0FBTyxJQUFJLEtBQUssRUFBRTtZQUMzQixPQUFRLEtBQXNDLENBQUMsS0FBSyxDQUFDO1NBQ3REO2FBQU07WUFDTCxPQUFPLEVBQUUsR0FBRyxLQUFLLENBQUM7U0FDbkI7SUFDSCxDQUFDO0lBRUQsZ0JBQWdCLENBQUMsSUFBcUI7UUFDcEMsSUFBSSxJQUFJLEtBQUssTUFBTSxFQUFFO1lBQ25CLElBQUksQ0FBQyxXQUFXLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztZQUNoRCxJQUFJLENBQUMsV0FBVyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7U0FDdEM7UUFDRCxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLEtBQUssTUFBTSxDQUFDLENBQUM7SUFDdEMsQ0FBQztJQUVELElBQUksQ0FBQyxLQUFlO1FBQ2xCLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxFQUFFO1lBQzdCLE9BQU8sS0FBSyxDQUFDLElBQUksRUFBa0IsQ0FBQztTQUNyQzthQUFNO1lBQ0wsT0FBTyxLQUFLLENBQUM7U0FDZDtJQUNILENBQUM7SUFFRCxNQUFNO1FBQ0osSUFBSSxJQUFJLENBQUMsV0FBVyxDQUFDLEtBQUssRUFBRTtZQUMxQixJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQztnQkFDYixRQUFRLEVBQUUsSUFBSSxDQUFDLElBQUksSUFBSSxJQUFJO2dCQUMzQixPQUFPLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxJQUFJLElBQUk7YUFDbkQsQ0FBQyxDQUFDO1NBQ0o7SUFDSCxDQUFDO0NBQ0YsQ0FBQTtrSEE1R1kscUJBQXFCO3NHQUFyQixxQkFBcUIsbVFDL0JsQywyaURBeUNBO0FEVmEscUJBQXFCO0lBTmpDLFlBQVksRUFBRTtHQU1GLHFCQUFxQixDQTRHakM7U0E1R1kscUJBQXFCOzJGQUFyQixxQkFBcUI7a0JBTGpDLFNBQVM7K0JBQ0Usa0JBQWtCO3lIQWFuQixJQUFJO3NCQUFaLEtBQUs7Z0JBTUcsYUFBYTtzQkFBckIsS0FBSztnQkFPRyxTQUFTO3NCQUFqQixLQUFLO2dCQVFHLFdBQVc7c0JBQW5CLEtBQUs7Z0JBS0csTUFBTTtzQkFBZCxLQUFLO2dCQUtHLFVBQVU7c0JBQWxCLEtBQUs7Z0JBT0ksSUFBSTtzQkFBYixNQUFNO2dCQUtHLFFBQVE7c0JBQWpCLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICogZGF0YcK3Y2Fmw6lcbiAqIENvcHlyaWdodCAoYykgMjAyMS0yMDIyIERhdGEgVGVycmFlXG4gKiBUaGlzIHByb2dyYW0gaXMgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgQWZmZXJvIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgdmVyc2lvbiAzXG4gKiBUaGUgZnVsbCBsaWNlbnNlIGluZm9ybWF0aW9uIGNhbiBiZSBmb3VuZCBpbiBMSUNFTlNFIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHByb2plY3QuXG4gKi9cblxuaW1wb3J0IHtcbiAgQ29tcG9uZW50LFxuICBFbGVtZW50UmVmLFxuICBFdmVudEVtaXR0ZXIsXG4gIElucHV0LFxuICBPbkluaXQsXG4gIE91dHB1dCxcbiAgUmVuZGVyZXIyLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEZvcm1Db250cm9sLCBWYWxpZGF0b3JGbiB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IFVudGlsRGVzdHJveSB9IGZyb20gJ0BuZ25lYXQvdW50aWwtZGVzdHJveSc7XG5pbXBvcnQgeyBJQ09OUyB9IGZyb20gJy4uL2NvbnN0YW50JztcblxuZXhwb3J0IGludGVyZmFjZSBSZXN1bHQ8VD4ge1xuICBwcmV2aW91czogVCB8IG51bGwsXG4gIGN1cnJlbnQ6IFQgfCBudWxsLFxufVxuXG5AVW50aWxEZXN0cm95KClcbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2R0LWNlbGwtZWRpdGFibGUnLFxuICB0ZW1wbGF0ZVVybDogJy4vY2VsbC1lZGl0YWJsZS5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL2NlbGwtZWRpdGFibGUuY29tcG9uZW50LnNjc3MnXVxufSlcbmV4cG9ydCBjbGFzcyBDZWxsRWRpdGFibGVDb21wb25lbnQ8VD4gaW1wbGVtZW50cyBPbkluaXQge1xuXG4gIHJlYWRvbmx5IElDT04gPSBJQ09OUztcblxuICAvKipcbiAgICogTWFpbiBpdGVtIHRvIGVkaXQuXG4gICAqIEl0IGNvdWxkIGJlIG51bGwsIG1lYW5pbmcgbm8gdmFsdWUuXG4gICAqIFRoZSBgdW5kZWZpbmVkYCB2YWx1ZSBpcyBub3QgYWxsb3dlZCBoZXJlOyBwbGVhc2UgdXNlIGBudWxsYCBpbnN0ZWFkLlxuICAgKi9cbiAgQElucHV0KCkgaXRlbTogVCB8IG51bGwgPSBudWxsO1xuICAvKipcbiAgICogRmFsbGJhY2sgbGFiZWwgdXNlZCB3aGVuIGl0ZW0gaXMgbnVsbCBvciBmYWxzeSwgb3IgdGhlIHByb3BlcnR5IGlzIG1pc3NpbmcuXG4gICAqXG4gICAqIFRoaXMgaXMgb3B0aW9uYWwuXG4gICAqL1xuICBASW5wdXQoKSBmYWxsYmFja0xhYmVsPzogc3RyaW5nO1xuICAvKipcbiAgICogVGhpcyBsaXN0IGlzIGEgcmFuZ2Ugb2YgYWxsb3dlZCB2YWx1ZXMuXG4gICAqIEl0IGRpc3BsYXlzIGEgc2VsZWN0IGVsZW1lbnQgaW5zdGVhZCBvZiBhIHNpbXBsZSBpbnB1dC5cbiAgICpcbiAgICogVGhpcyBpcyBvcHRpb25hbC5cbiAgICovXG4gIEBJbnB1dCgpIGFsdFZhbHVlcz86IEFycmF5PFQ+O1xuICAvKipcbiAgICogQ29udmVydGVyIG1ldGhvZC5cbiAgICpcbiAgICogVGhpcyBpcyBvcHRpb25hbCBvbmx5IGlmOlxuICAgKiAtIHRoZSBpdGVtIGlzIGEgc3RyaW5nXG4gICAqIC0gdGhlIGl0ZW0gY29udGFpbnMgYSBwcm9wZXJ0eSBgbGFiZWxgLCBgbmFtZWAgb3IgYHRpdGxlYFxuICAgKi9cbiAgQElucHV0KCkgaXRlbVRvTGFiZWw/OiAodDogVCkgPT4gc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBBbGxvdyBlZGl0aW9uXG4gICAqL1xuICBASW5wdXQoKSBlbmFibGUgPSB0cnVlO1xuXG4gIC8qKlxuICAgKiBTcGVjaWZ5IHNvbWUgZXh0cmEgdmFsaWRhdG9yc1xuICAgKi9cbiAgQElucHV0KCkgdmFsaWRhdG9yczogQXJyYXk8VmFsaWRhdG9yRm4+ID0gW107XG5cbiAgLyoqXG4gICAqIGNhbGwgb24gc2F2ZTpcbiAgICogLSBidXR0b24gdmFsaWRhdGVcbiAgICogLSBlbnRlciBrZXlcbiAgICovXG4gIEBPdXRwdXQoKSBzYXZlOiBFdmVudEVtaXR0ZXI8UmVzdWx0PFQ+PiA9IG5ldyBFdmVudEVtaXR0ZXI8UmVzdWx0PFQ+PigpO1xuXG4gIC8qKlxuICAgKiBEaXNwYXRjaCBhIGV2ZW50IGluZGljYXRpbmcgd2hlbmV2ZXIgdGhpcyBjb21wb25lbnQgaXMgaW4gZWRpdGlvbiBtb2RlLlxuICAgKi9cbiAgQE91dHB1dCgpIGVkaXRpbmckOiBFdmVudEVtaXR0ZXI8Ym9vbGVhbj4gPSBuZXcgRXZlbnRFbWl0dGVyPGJvb2xlYW4+KCk7XG5cbiAgZm9ybUNvbnRyb2wgPSBuZXcgRm9ybUNvbnRyb2woKTtcblxuICBjb25zdHJ1Y3RvcihyZWFkb25seSByZW5kZXJlcjogUmVuZGVyZXIyLFxuICAgICAgICAgICAgICByZWFkb25seSBlbGVtZW50OiBFbGVtZW50UmVmKSB7XG4gIH1cblxuICBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICAvLyBTdHlsaW5nIHBhcmVudCBjZWxsIDx0ZD5cbiAgICBjb25zdCBjZWxsRWxlbWVudCA9IHRoaXMuZWxlbWVudC5uYXRpdmVFbGVtZW50LmNsb3Nlc3QoJ2Nsci1kZy1jZWxsJyk7XG4gICAgdGhpcy5yZW5kZXJlci5hZGRDbGFzcyhjZWxsRWxlbWVudCwgJ2hhcy1lZGl0Jyk7XG4gIH1cblxuICBnZXRMYWJlbCh2YWx1ZTogVCB8IG51bGwpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgIGlmICghdmFsdWUpIHtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfSBlbHNlIGlmIChbJ3N0cmluZycsICdudW1iZXInXS5pbmNsdWRlcyh0eXBlb2YgdmFsdWUpKSB7XG4gICAgICByZXR1cm4gYCR7dmFsdWV9YDtcbiAgICB9IGVsc2UgaWYgKHRoaXMuaXRlbVRvTGFiZWwpIHtcbiAgICAgIHJldHVybiB0aGlzLml0ZW1Ub0xhYmVsKHZhbHVlKTtcbiAgICB9IGVsc2UgaWYgKCdsYWJlbCcgaW4gdmFsdWUpIHtcbiAgICAgIHJldHVybiAodmFsdWUgYXMgdW5rbm93biBhcyB7IGxhYmVsOiBzdHJpbmcgfSkubGFiZWw7XG4gICAgfSBlbHNlIGlmICgnbmFtZScgaW4gdmFsdWUpIHtcbiAgICAgIHJldHVybiAodmFsdWUgYXMgdW5rbm93biBhcyB7IG5hbWU6IHN0cmluZyB9KS5uYW1lO1xuICAgIH0gZWxzZSBpZiAoJ3RpdGxlJyBpbiB2YWx1ZSkge1xuICAgICAgcmV0dXJuICh2YWx1ZSBhcyB1bmtub3duIGFzIHsgdGl0bGU6IHN0cmluZyB9KS50aXRsZTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuICcnICsgdmFsdWU7XG4gICAgfVxuICB9XG5cbiAgb25FZGl0YWJsZUNoYW5nZShtb2RlOiAndmlldycgfCAnZWRpdCcpOiB2b2lkIHtcbiAgICBpZiAobW9kZSA9PT0gJ2VkaXQnKSB7XG4gICAgICB0aGlzLmZvcm1Db250cm9sLnNldFZhbGlkYXRvcnModGhpcy52YWxpZGF0b3JzKTtcbiAgICAgIHRoaXMuZm9ybUNvbnRyb2wuc2V0VmFsdWUodGhpcy5pdGVtKTtcbiAgICB9XG4gICAgdGhpcy5lZGl0aW5nJC5lbWl0KG1vZGUgPT09ICdlZGl0Jyk7XG4gIH1cblxuICB0cmltKHZhbHVlOiBUIHwgbnVsbCk6IFQgfCBudWxsIHtcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJykge1xuICAgICAgcmV0dXJuIHZhbHVlLnRyaW0oKSBhcyB1bmtub3duIGFzIFQ7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiB2YWx1ZTtcbiAgICB9XG4gIH1cblxuICBvbkVkaXQoKSB7XG4gICAgaWYgKHRoaXMuZm9ybUNvbnRyb2wudmFsaWQpIHtcbiAgICAgIHRoaXMuc2F2ZS5lbWl0KHtcbiAgICAgICAgcHJldmlvdXM6IHRoaXMuaXRlbSA/PyBudWxsLFxuICAgICAgICBjdXJyZW50OiB0aGlzLnRyaW0odGhpcy5mb3JtQ29udHJvbC52YWx1ZSkgPz8gbnVsbCxcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxufVxuIiwiPCEtLVxuICB+IGRhdGHCt2NhZsOpXG4gIH4gQ29weXJpZ2h0IChjKSAyMDIxLTIwMjIgRGF0YSBUZXJyYWVcbiAgfiBUaGlzIHByb2dyYW0gaXMgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgQWZmZXJvIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgdmVyc2lvbiAzXG4gIH4gVGhlIGZ1bGwgbGljZW5zZSBpbmZvcm1hdGlvbiBjYW4gYmUgZm91bmQgaW4gTElDRU5TRSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBwcm9qZWN0LlxuICAtLT5cblxuPGVkaXRhYmxlIChtb2RlQ2hhbmdlKT1cIm9uRWRpdGFibGVDaGFuZ2UoJGV2ZW50KVwiXG4gICAgICAgICAgKHNhdmUpPVwib25FZGl0KClcIlxuICAgICAgICAgIFtjbGFzcy5jYW4tZWRpdF09XCJlbmFibGVcIlxuICAgICAgICAgIFtjbGFzcy5pcy1lZGl0aW5nXT1cImVkaXRpbmckIHwgYXN5bmNcIlxuICAgICAgICAgIFtlbmFibGVkXT1cImVuYWJsZVwiPlxuICA8bmctdGVtcGxhdGUgdmlld01vZGU+XG4gICAgPHNwYW4gW2NsYXNzLm1pc3NpbmddPVwiIWl0ZW0gJiYgZmFsbGJhY2tMYWJlbFwiXG4gICAgICAgICAgW2lubmVyVGV4dF09XCJnZXRMYWJlbChpdGVtKSA/PyBmYWxsYmFja0xhYmVsID8/ICcnXCI+PC9zcGFuPlxuICA8L25nLXRlbXBsYXRlPlxuICA8bmctdGVtcGxhdGUgZWRpdE1vZGU+XG5cbiAgICA8aW5wdXQgKm5nSWY9XCIhYWx0VmFsdWVzXCJcbiAgICAgICAgICAgW2Zvcm1Db250cm9sXT1cImZvcm1Db250cm9sXCJcbiAgICAgICAgICAgY2xySW5wdXRcbiAgICAgICAgICAgZWRpdGFibGVGb2N1c2FibGUgZWRpdGFibGVPbkVudGVyIGVkaXRhYmxlT25Fc2NhcGUgdHJpbT1cImJsdXJcIi8+XG5cbiAgICA8c2VsZWN0ICpuZ0lmPVwiYWx0VmFsdWVzXCJcbiAgICAgICAgICAgIFtmb3JtQ29udHJvbF09XCJmb3JtQ29udHJvbFwiXG4gICAgICAgICAgICBjbHJTZWxlY3RcbiAgICAgICAgICAgIGVkaXRhYmxlRm9jdXNhYmxlIGVkaXRhYmxlT25FbnRlciBlZGl0YWJsZU9uRXNjYXBlPlxuICAgICAgPG9wdGlvbiBbbGFiZWxdPVwiZmFsbGJhY2tMYWJlbFwiIFtuZ1ZhbHVlXT1cIm51bGxcIiBjbGFzcz1cIm1pc3NpbmdcIj48L29wdGlvbj5cbiAgICAgIDxvcHRpb24gKm5nRm9yPVwibGV0IGFsdCBvZiBhbHRWYWx1ZXNcIiBbbGFiZWxdPVwiZ2V0TGFiZWwoYWx0KVwiIFtuZ1ZhbHVlXT1cImFsdFwiPjwvb3B0aW9uPlxuICAgIDwvc2VsZWN0PlxuXG4gICAgPGRpdiBjbGFzcz1cImJ0bi1ncm91cCBidG4tc20gYnRuLWljb25cIj5cbiAgICAgIDxidXR0b24gY2xhc3M9XCJidG4gYnRuLXN1Y2Nlc3NcIiBlZGl0YWJsZU9uU2F2ZT5cbiAgICAgICAgPGNkcy1pY29uIFthdHRyLnNoYXBlXT1cIklDT04uVkFMSURcIj48L2Nkcy1pY29uPlxuICAgICAgPC9idXR0b24+XG4gICAgICA8YnV0dG9uIGNsYXNzPVwiYnRuIGJ0bi1kYW5nZXJcIiBlZGl0YWJsZU9uQ2FuY2VsPlxuICAgICAgICA8Y2RzLWljb24gW2F0dHIuc2hhcGVdPVwiSUNPTi5DQU5DRUxcIj48L2Nkcy1pY29uPlxuICAgICAgPC9idXR0b24+XG4gICAgPC9kaXY+XG4gIDwvbmctdGVtcGxhdGU+XG48L2VkaXRhYmxlPlxuIl19