svogv
Version:
A decorator based approach for model driven forms, including an advanced DataGrid and a TreeView component.
199 lines • 31.1 kB
JavaScript
import { Component, Input, ViewChild, ContentChild, TemplateRef, EventEmitter, Output } from '@angular/core';
import { DataGridModel, Direction } from './models/datagrid.model';
/**
* A classic data grid. You provide a model to handle all features. The model is build from a
* simple array of objects with decorators.
*
* > See 'Documentation and Examples' tab for a complete documentation.
*
* ### Summary
*
* The datagrid provides basic functions for data tables:
*
* * sorting
* * filtering
* * pagination
* * editing
*
* Provide an decorator enhanced model and the grid appears driven by model meta data.
*
* There are many attributes and ways to change the appearance. Also some classes can be controlled by
* the host component:
*
* * `.col-borders`
* * `.col-last`
* * `.col-first`
*
* All these styles are applied to the <col> elements of the underlying table.
*
* The model used in the example is an array of objects, where the properties are decorated with
* various decorators used to control the grid's render behavior.
*
* ~~~typescript
* const data: UserViewModel[] = this.dataSource; // provide a simple array here
* this.model = new DataGridModel<UserViewModel>(data, UserViewModel);
* ~~~
*
* The class {@link DataGridModel} controls the grid. You must provide a viewmodel, this is mandatory. The viewmodel is being examined at runtime,
* so assure you provide a class and set all properties to a default to force creation of properties.
*
* ~~~typescript
* export class UserViewModel {
* email: string = ''; // the = '' is necessary!
* // more omitted for brevity
* }
* ~~~
*
* The grid can be extended with the {@link DataGridPaginationComponent} to page through huge data sets. The model
* handles the pagination, the additional {@link DataGridPaginationComponent} is only a predefined renderer that
* supports the used theme.
*
* <example-url>/#/widget/grid</example-url>
*
* @example
* <ac-datagrid
* [model]="model"
* [showActions]="false"
* [columnStyle]=""
* ></ac-datagrid>
*/
export class DataGridComponent {
constructor() {
/**
* @ignore
*/
this.directionEnumHelper = Direction;
this.externals = {};
/**
* Show the action column at all. Use {@link showDeleteButton and @see showEditButton to switch the}buttons
* on or off individually. Default is `true` (actions visible).
*/
this.showActions = true;
/**
* The text that appears on the Delete button. Default is 'Delete'.
*/
this.textDeleteButton = 'Delete';
/**
* The text that appears on the Edit button. Default is 'Edit'.
*/
this.textEditButton = 'Edit';
/**
* The column header of the column that shows the buttons. Default is 'Actions'.
*/
this.textButtonsHeader = 'Actions';
/**
* The text that appears if there are no items to show. Can also be overwritten by a more complex piece
* of code by adding a template like this:
*
* @example
* <ng-template #data-warning-noitems>
* <div class="alert alert-danger">The grid is empty</div>
* </ng-template>
*/
this.textNoItems = 'There are no items to show';
/**
* Event forwarded from model class and being fired after the model class's onEdit event.
* The event is invoked by the appropriate internal button via click.
*/
this.editItem = new EventEmitter();
/**
* Event forwarded from model class and being fired after the model class's onDelete event.
* The event is invoked by the appropriate internal button via click.
*/
this.deleteItem = new EventEmitter();
// tslint:disable-next-line:member-ordering
/**
* @ignore
*/
this.warnProp = {};
}
/**
* The filter value to filter the content. The data is of type `{ [prop: string]: any }`.
*
* @param value A dictionary with filter instructions as shown below. The filter logic applies one after another, like an __AND__ conjunction.
*
* @example
* {
* "email": "paul@sample.com"
* "name": "Paul"
* }
*
*/
set filter(value) {
if (this.model) {
this.model.searchValue = value;
}
}
ngAfterViewInit() {
if (this.model) {
this.model.onEdit.subscribe(item => this.editItem.emit(item));
this.model.onDelete.subscribe(item => this.deleteItem.emit(item));
}
}
ngOnDestroy() {
if (this.model) {
this.model.onEdit.unsubscribe();
this.model.onDelete.unsubscribe();
}
}
/**
* @ignore
* Controls the template used to display certain data types.
* If the host provides a template it's being used, otherwise a fallback is provided
* @param uiHint Property of {@link UiHint} decorator
*/
getActiveTemplate(uiHint, prop) {
if (this[uiHint]) {
// if provided by user via ContentChild and overwriting defaults (string == string etc.)
return this[uiHint];
}
if (this.externals[uiHint]) {
// if provided by user via ContentChild but completely replaced
return this.externals[uiHint];
}
if (this[`${uiHint}Fallback`]) {
// otherwise we take ours from ng-template via ViewChild
return this[`${uiHint}Fallback`];
}
// if we go here the model requested a custom template that didn't exists
if (this.warnProp[prop] !== uiHint) {
console.warn(`Property ${prop} requested the template ${uiHint}, but it wasn't provided. Falling back to "string".`);
this.warnProp[prop] = uiHint;
}
return this.stringFallback;
}
}
DataGridComponent.decorators = [
{ type: Component, args: [{
selector: 'ac-datagrid',
template: "<div class=\"row\" *ngIf=\"model && model.headers\">\n <div class=\"col-md-12\">\n <table class=\"table table-condensed\">\n <colgroup class=\"colborders\" [ngStyle]=\"columnStyle ? columnStyle.group : null\">\n <col class=\"first\" [ngStyle]=\"columnStyle ? columnStyle.first : null\" />\n <col class=\"middle\" [ngStyle]=\"columnStyle ? columnStyle.middle : null\" />\n <col class=\"middle\" [ngStyle]=\"columnStyle ? columnStyle.middle : null\" />\n <col class=\"middle\" [ngStyle]=\"columnStyle ? columnStyle.middle : null\" />\n <col class=\"last\" [ngStyle]=\"columnStyle ? columnStyle.last : null\" />\n </colgroup>\n <thead>\n <tr [ngStyle]=\"columnStyle ? columnStyle.header : null\" >\n <th *ngFor=\"let header of model.headers\"\n [ngClass]=\"{ 'sortableHeader': header.isSortable }\"\n [ngStyle]=\"header.uiHint || {}\"\n [title]=\"header.desc\"\n (click)=\"header.isSortable ? model.sortColumn(header.prop, null, header.sortCallback) : null\">\n <span class=\"headerText\">{{ header.text }}</span>\n <span class=\"sort\" [ngStyle]=\"columnStyle ? columnStyle.headerButton : null\" *ngIf=\"header.isSortable\">\n <button (click)=\"model.sortColumn(header.prop, directionEnumHelper.Ascending, header.sortCallback)\"\n class=\"up\"\n [hidden]=\"model.sortDirection[header.prop] === directionEnumHelper.Descending\"\n [ngStyle]=\"columnStyle ? columnStyle.headerSortButton : null\">\n <i class=\"fa fa-sort-asc\"></i>\n </button>\n <button (click)=\"model.sortColumn(header.prop, directionEnumHelper.Descending, header.sortCallback)\"\n class=\"down\"\n [hidden]=\"model.sortDirection[header.prop] === directionEnumHelper.Ascending\"\n [ngStyle]=\"columnStyle ? columnStyle.headerSortButton : null\">\n <i class=\"fa fa-sort-desc\"></i>\n </button>\n </span>\n </th>\n <th *ngIf=\"showActions\">\n {{ textButtonsHeader }}\n </th>\n </tr>\n </thead>\n <tbody>\n <tr *ngIf=\"!model.totalFilteredRows\">\n <td [attr.colspan]=\"model.headers.length\" class=\"text-center\">\n <div class=\"alert alert-warning\">\n <span #warningNoItems>\n <ng-content select=\"[data-warning-noitems]\"></ng-content>\n </span>\n <ng-container *ngIf=\"!warningNoItems.innerHTML.trim()\">{{ textNoItems }}</ng-container>\n </div>\n </td>\n </tr>\n <tr *ngFor=\"let item of model.itemsOnCurrentPage\">\n <td *ngFor=\"let header of model.headers\">\n <ng-container\n [ngTemplateOutlet]=\"getActiveTemplate(header.templateHint, header.prop)\"\n [ngTemplateOutletContext]=\"{ $implicit: item[header.prop], pipe: header.pipe, params: header.pipeParams }\"\n ></ng-container>\n </td>\n <td *ngIf=\"showActions\" [ngStyle]=\"columnStyle ? columnStyle.actionCell : null\" >\n <button class=\"btn btn-primary btn-sm\" type=\"button\" (click)=\"model.editItem(item)\">\n {{ textEditButton }}\n </button>\n <button class=\"btn btn-danger btn-sm\" type=\"button\" (click)=\"model.deleteItem(item)\">\n {{ textDeleteButton }}\n </button>\n </td>\n </tr>\n </tbody>\n <tfoot>\n <tr [ngStyle]=\"columnStyle ? columnStyle.footer : null\" >\n <td [attr.colspan]=\"model.headers.length + (showActions ? 1 : 0)\">\n <div #footerRef>\n <ng-content select=\"[data-footer]\"></ng-content>\n </div>\n <ng-container *ngIf=\"!footerRef.innerHTML.trim()\">©</ng-container>\n </td>\n </tr>\n </tfoot>\n </table>\n </div>\n</div>\n<ng-template #string let-data let-modelpipe=\"pipe\" let-params=\"params\">\n {{ data | formatData: modelpipe: params }}\n</ng-template>\n<ng-template #boolean let-data>\n <input type=\"checkbox\" disabled [checked]=\"data\" />\n</ng-template>\n<ng-template #date let-data let-modelpipe=\"pipe\" let-params=\"params\">\n {{ data | formatData: modelpipe: params }}\n</ng-template>\n<ng-template #enum let-data>\n {{ data }}\n</ng-template>\n<ng-template #number let-data let-modelpipe=\"pipe\" let-params=\"params\">\n {{ data | formatData: modelpipe: params }}\n</ng-template>\n",
styles: [".colborders col{border-right:1px solid azure}col.last{border-right:none!important}col.first{background-color:#eee}th{background:none}th.sortableHeader{cursor:pointer}.headerText{display:inline-block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sort{float:right}.sort button{background-color:transparent!important;border:0;border-radius:0;cursor:pointer;height:16px;padding:1px;width:16px}.sort button.up{left:0}.sort button.down{left:-16px}.rearrange{background-color:transparent;border:none;float:right;height:16px;margin:2px;width:16px}"]
},] }
];
DataGridComponent.propDecorators = {
stringFallback: [{ type: ViewChild, args: ['string', { static: true },] }],
string: [{ type: ContentChild, args: ['string', { static: true },] }],
booleanFallback: [{ type: ViewChild, args: ['boolean', { static: true },] }],
boolean: [{ type: ContentChild, args: ['boolean', { static: true },] }],
dateFallback: [{ type: ViewChild, args: ['date', { static: true },] }],
date: [{ type: ContentChild, args: ['date', { static: true },] }],
enumFallback: [{ type: ViewChild, args: ['enum', { static: true },] }],
enum: [{ type: ContentChild, args: ['enum', { static: true },] }],
numberFallback: [{ type: ViewChild, args: ['number', { static: true },] }],
number: [{ type: ContentChild, args: ['number', { static: true },] }],
externals: [{ type: Input }],
columnStyle: [{ type: Input }],
model: [{ type: Input }],
showDeleteButton: [{ type: Input }],
showEditButton: [{ type: Input }],
showActions: [{ type: Input }],
textDeleteButton: [{ type: Input }],
textEditButton: [{ type: Input }],
textButtonsHeader: [{ type: Input }],
textNoItems: [{ type: Input }],
filter: [{ type: Input }],
reArrangeColumns: [{ type: Input }],
editItem: [{ type: Output }],
deleteItem: [{ type: Output }]
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YWdyaWQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6Ii4uLy4uLy4uL3Byb2plY3RzL3N2b2d2L3NyYy8iLCJzb3VyY2VzIjpbImxpYi93aWRnZXRzL2RhdGFncmlkL2RhdGFncmlkLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFVLEtBQUssRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUNqRCxXQUFXLEVBQUUsWUFBWSxFQUFpQixNQUFNLEVBQWEsTUFBTSxlQUFlLENBQUM7QUFDNUYsT0FBTyxFQUFFLGFBQWEsRUFBRSxTQUFTLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUduRTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F3REc7QUFNSCxNQUFNLE9BQU8saUJBQWlCO0lBTDlCO1FBT0U7O1dBRUc7UUFDSSx3QkFBbUIsR0FBRyxTQUFTLENBQUM7UUFrR3ZCLGNBQVMsR0FBMkIsRUFBRSxDQUFDO1FBMkJ2RDs7O1dBR0c7UUFFSSxnQkFBVyxHQUFHLElBQUksQ0FBQztRQUUxQjs7V0FFRztRQUVJLHFCQUFnQixHQUFHLFFBQVEsQ0FBQztRQUNuQzs7V0FFRztRQUVJLG1CQUFjLEdBQUcsTUFBTSxDQUFDO1FBQy9COztXQUVHO1FBRUksc0JBQWlCLEdBQUcsU0FBUyxDQUFDO1FBRXJDOzs7Ozs7OztXQVFHO1FBRUksZ0JBQVcsR0FBRyw0QkFBNEIsQ0FBQztRQTJCbEQ7OztXQUdHO1FBRUksYUFBUSxHQUFzQixJQUFJLFlBQVksRUFBTyxDQUFDO1FBRTdEOzs7V0FHRztRQUVJLGVBQVUsR0FBc0IsSUFBSSxZQUFZLEVBQU8sQ0FBQztRQWdCL0QsMkNBQTJDO1FBQzNDOztXQUVHO1FBQ0ssYUFBUSxHQUErQixFQUFFLENBQUM7SUE0QnBELENBQUM7SUFyRkM7Ozs7Ozs7Ozs7O09BV0c7SUFDSCxJQUNXLE1BQU0sQ0FBQyxLQUE4QjtRQUM5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LEtBQUs7MEJBWUwsS0FBSztxQkFlTCxLQUFLOytCQVVMLEtBQUs7dUJBT0wsTUFBTTt5QkFPTixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBPbkluaXQsIElucHV0LCBWaWV3Q2hpbGQsIENvbnRlbnRDaGlsZCxcbiAgICAgICAgIFRlbXBsYXRlUmVmLCBFdmVudEVtaXR0ZXIsIEFmdGVyVmlld0luaXQsIE91dHB1dCwgT25EZXN0cm95IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBEYXRhR3JpZE1vZGVsLCBEaXJlY3Rpb24gfSBmcm9tICcuL21vZGVscy9kYXRhZ3JpZC5tb2RlbCc7XG5pbXBvcnQgeyBEYXRhZ3JpZFN0eWxlcyB9IGZyb20gJy4vbW9kZWxzL2RhdGFncmlkc3R5bGUubW9kZWwnO1xuXG4vKipcbiAqIEEgY2xhc3NpYyBkYXRhIGdyaWQuIFlvdSBwcm92aWRlIGEgbW9kZWwgdG8gaGFuZGxlIGFsbCBmZWF0dXJlcy4gVGhlIG1vZGVsIGlzIGJ1aWxkIGZyb20gYVxuICogc2ltcGxlIGFycmF5IG9mIG9iamVjdHMgd2l0aCBkZWNvcmF0b3JzLlxuICpcbiAqID4gU2VlICdEb2N1bWVudGF0aW9uIGFuZCBFeGFtcGxlcycgdGFiIGZvciBhIGNvbXBsZXRlIGRvY3VtZW50YXRpb24uXG4gKlxuICogIyMjIFN1bW1hcnlcbiAqXG4gKiBUaGUgZGF0YWdyaWQgcHJvdmlkZXMgYmFzaWMgZnVuY3Rpb25zIGZvciBkYXRhIHRhYmxlczpcbiAqXG4gKiAqIHNvcnRpbmdcbiAqICogZmlsdGVyaW5nXG4gKiAqIHBhZ2luYXRpb25cbiAqICogZWRpdGluZ1xuICpcbiAqIFByb3ZpZGUgYW4gZGVjb3JhdG9yIGVuaGFuY2VkIG1vZGVsIGFuZCB0aGUgZ3JpZCBhcHBlYXJzIGRyaXZlbiBieSBtb2RlbCBtZXRhIGRhdGEuXG4gKlxuICogVGhlcmUgYXJlIG1hbnkgYXR0cmlidXRlcyBhbmQgd2F5cyB0byBjaGFuZ2UgdGhlIGFwcGVhcmFuY2UuIEFsc28gc29tZSBjbGFzc2VzIGNhbiBiZSBjb250cm9sbGVkIGJ5XG4gKiB0aGUgaG9zdCBjb21wb25lbnQ6XG4gKlxuICogKiBgLmNvbC1ib3JkZXJzYFxuICogKiBgLmNvbC1sYXN0YFxuICogKiBgLmNvbC1maXJzdGBcbiAqXG4gKiBBbGwgdGhlc2Ugc3R5bGVzIGFyZSBhcHBsaWVkIHRvIHRoZSA8Y29sPiBlbGVtZW50cyBvZiB0aGUgdW5kZXJseWluZyB0YWJsZS5cbiAqXG4gKiBUaGUgbW9kZWwgdXNlZCBpbiB0aGUgZXhhbXBsZSBpcyBhbiBhcnJheSBvZiBvYmplY3RzLCB3aGVyZSB0aGUgcHJvcGVydGllcyBhcmUgZGVjb3JhdGVkIHdpdGhcbiAqIHZhcmlvdXMgZGVjb3JhdG9ycyB1c2VkIHRvIGNvbnRyb2wgdGhlIGdyaWQncyByZW5kZXIgYmVoYXZpb3IuXG4gKlxuICogfn5+dHlwZXNjcmlwdFxuICogY29uc3QgZGF0YTogVXNlclZpZXdNb2RlbFtdID0gdGhpcy5kYXRhU291cmNlOyAvLyBwcm92aWRlIGEgc2ltcGxlIGFycmF5IGhlcmVcbiAqICB0aGlzLm1vZGVsID0gbmV3IERhdGFHcmlkTW9kZWw8VXNlclZpZXdNb2RlbD4oZGF0YSwgVXNlclZpZXdNb2RlbCk7XG4gKiB+fn5cbiAqXG4gKiBUaGUgY2xhc3Mge0BsaW5rIERhdGFHcmlkTW9kZWx9IGNvbnRyb2xzIHRoZSBncmlkLiBZb3UgbXVzdCBwcm92aWRlIGEgdmlld21vZGVsLCB0aGlzIGlzIG1hbmRhdG9yeS4gVGhlIHZpZXdtb2RlbCBpcyBiZWluZyBleGFtaW5lZCBhdCBydW50aW1lLFxuICogc28gYXNzdXJlIHlvdSBwcm92aWRlIGEgY2xhc3MgYW5kIHNldCBhbGwgcHJvcGVydGllcyB0byBhIGRlZmF1bHQgdG8gZm9yY2UgY3JlYXRpb24gb2YgcHJvcGVydGllcy5cbiAqXG4gKiB+fn50eXBlc2NyaXB0XG4gKiBleHBvcnQgY2xhc3MgVXNlclZpZXdNb2RlbCB7XG4gKiAgZW1haWw6IHN0cmluZyA9ICcnOyAvLyB0aGUgPSAnJyBpcyBuZWNlc3NhcnkhXG4gKiAgLy8gbW9yZSBvbWl0dGVkIGZvciBicmV2aXR5XG4gKiB9XG4gKiB+fn5cbiAqXG4gKiBUaGUgZ3JpZCBjYW4gYmUgZXh0ZW5kZWQgd2l0aCB0aGUge0BsaW5rIERhdGFHcmlkUGFnaW5hdGlvbkNvbXBvbmVudH0gdG8gcGFnZSB0aHJvdWdoIGh1Z2UgZGF0YSBzZXRzLiBUaGUgbW9kZWxcbiAqIGhhbmRsZXMgdGhlIHBhZ2luYXRpb24sIHRoZSBhZGRpdGlvbmFsIHtAbGluayBEYXRhR3JpZFBhZ2luYXRpb25Db21wb25lbnR9IGlzIG9ubHkgYSBwcmVkZWZpbmVkIHJlbmRlcmVyIHRoYXRcbiAqIHN1cHBvcnRzIHRoZSB1c2VkIHRoZW1lLlxuICpcbiAqIDxleGFtcGxlLXVybD4vIy93aWRnZXQvZ3JpZDwvZXhhbXBsZS11cmw+XG4gKlxuICogQGV4YW1wbGVcbiAqICA8YWMtZGF0YWdyaWRcbiAqICAgICAgW21vZGVsXT1cIm1vZGVsXCJcbiAqICAgICAgW3Nob3dBY3Rpb25zXT1cImZhbHNlXCJcbiAqICAgICAgW2NvbHVtblN0eWxlXT1cIlwiXG4gKiAgPjwvYWMtZGF0YWdyaWQ+XG4gKi9cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2FjLWRhdGFncmlkJyxcbiAgdGVtcGxhdGVVcmw6ICcuL2RhdGFncmlkLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vZGF0YWdyaWQuY29tcG9uZW50LnNjc3MnXVxufSlcbmV4cG9ydCBjbGFzcyBEYXRhR3JpZENvbXBvbmVudCBpbXBsZW1lbnRzIEFmdGVyVmlld0luaXQsIE9uRGVzdHJveSB7XG5cbiAgLyoqXG4gICAqIEBpZ25vcmVcbiAgICovXG4gIHB1YmxpYyBkaXJlY3Rpb25FbnVtSGVscGVyID0gRGlyZWN0aW9uO1xuXG4gIC8qKlxuICAgKiBBY2Nlc3MgdG8gdGhlIHN0cmluZyByZW5kZXJlciBmYWxsYmFjayB0ZW1wbGF0ZS4gVGhlIHRlbXBsYXRlIHVzZWQgaW50ZXJuYWxseSBsb29rcyBsaWtlIHNob3duIGluIHRoZSBleGFtcGxlXG4gICAqIFRoYXQgbWVhbnMsIGl0IHJlbmRlcnMgZGF0YSBcImFzIGlzXCIsIGJ1dCBjYW4gYmUgbW9kaWZpZWQgYnkgaGFuZGxpbmcgYSBjdXN0b20gcGlwZS4gVG8gYXBwbHkgc3VjaFxuICAgKiBhIHBpcGUsIHlvdXIgdmlld21vZGVsJ3MgcHJvcGVydGllcyBtdXN0IGJlIGRlY29yYXRlZCB3aXRoIHRoZSB7QGxpbmsgRm9ybWF0UGlwZX0gZGVjb3JhdG9yLlxuICAgKlxuICAgKiBfX1RlbXBsYXRlIGNvZGU6X19cbiAgICogfn5+fn5+fn5cbiAgICogPG5nLXRlbXBsYXRlICNzdHJpbmcgbGV0LWRhdGEgbGV0LW1vZGVscGlwZT1cInBpcGVcIiBsZXQtcGFyYW1zPVwicGFyYW1zXCI+XG4gICAqICB7eyBkYXRhIHwgZm9ybWF0RGF0YTogbW9kZWxwaXBlOiBwYXJhbXMgfX1cbiAgICogPC9uZy10ZW1wbGF0ZT5cbiAgICogfn5+fn5+fn5cbiAgICpcbiAgICovXG4gIEBWaWV3Q2hpbGQoJ3N0cmluZycsIHsgc3RhdGljOiB0cnVlIH0pIHB1YmxpYyBzdHJpbmdGYWxsYmFjazogVGVtcGxhdGVSZWY8YW55PjtcblxuICAvKipcbiAgICogWW91IGNhbiBwcm92aWRlIGEgY3VzdG9tIHRlbXBsYXRlIHRvIG92ZXJyaWRlIHRoZSBmYWxsYmFjayBhbmQgcmVuZGVyIGEgZmllbGQncyBkYXRhIGNvbXBsZXRlbHkgb24geW91ciBvd24uXG4gICAqL1xuICBAQ29udGVudENoaWxkKCdzdHJpbmcnLCB7IHN0YXRpYzogdHJ1ZSB9KSBwdWJsaWMgc3RyaW5nOiBUZW1wbGF0ZVJlZjxhbnk+O1xuXG4gIC8qKlxuICAgKiBBY2Nlc3MgdG8gdGhlIGJvb2xlYW4gcmVuZGVyZXIgZmFsbGJhY2sgdGVtcGxhdGUuIFRoZSB0ZW1wbGF0ZSB1c2VkIGludGVybmFsbHkgbG9va3MgbGlrZSBzaG93biBpbiB0aGUgZXhhbXBsZS5cbiAgICpcbiAgICogX19UZW1wbGF0ZSBjb2RlOl9fXG4gICAqIH5+fn5+fn5+XG4gICAqIDxuZy10ZW1wbGF0ZSAjYm9vbGVhbiBsZXQtZGF0YT5cbiAgICogICA8aW5wdXQgdHlwZT1cImNoZWNrYm94XCIgZGlzYWJsZWQgW2NoZWNrZWRdPVwiZGF0YVwiIC8+XG4gICAqIDwvbmctdGVtcGxhdGU+XG4gICAqIH5+fn5+fn5+XG4gICAqXG4gICAqL1xuICBAVmlld0NoaWxkKCdib29sZWFuJywgeyBzdGF0aWM6IHRydWUgfSkgcHVibGljIGJvb2xlYW5GYWxsYmFjazogVGVtcGxhdGVSZWY8YW55PjtcblxuICAvKipcbiAgICogWW91IGNhbiBwcm92aWRlIGEgY3VzdG9tIHRlbXBsYXRlIHRvIG92ZXJyaWRlIHRoZSBmYWxsYmFjayBhbmQgcmVuZGVyIGEgZmllbGQncyBkYXRhIGNvbXBsZXRlbHkgb24geW91ciBvd24uXG4gICAqL1xuICBAQ29udGVudENoaWxkKCdib29sZWFuJywgeyBzdGF0aWM6IHRydWUgfSkgcHVibGljIGJvb2xlYW46IFRlbXBsYXRlUmVmPGFueT47XG5cbiAgLyoqXG4gICAqIEFjY2VzcyB0byB0aGUgZGF0ZSByZW5kZXJlciBmYWxsYmFjayB0ZW1wbGF0ZS4gVGhlIHRlbXBsYXRlIHVzZWQgaW50ZXJuYWxseSBsb29rcyBsaWtlIHNob3duIGluIHRoZSBleGFtcGxlXG4gICAqIFRoYXQgbWVhbnMsIGl0IHJlbmRlcnMgZGF0YSBcImFzIGlzXCIsIGJ1dCBjYW4gYmUgbW9kaWZpZWQgYnkgaGFuZGxpbmcgYSBjdXN0b20gcGlwZS4gVG8gYXBwbHkgc3VjaFxuICAgKiBhIHBpcGUsIHlvdXIgdmlld21vZGVsJ3MgcHJvcGVydGllcyBtdXN0IGJlIGRlY29yYXRlZCB3aXRoIHRoZSB7QGxpbmsgRm9ybWF0UGlwZX0gZGVjb3JhdG9yLlxuICAgKlxuICAgKiBfX1RlbXBsYXRlIGNvZGU6X19cbiAgICogfn5+fn5+fn5cbiAgICogPG5nLXRlbXBsYXRlICNkYXRlIGxldC1kYXRhIGxldC1tb2RlbHBpcGU9XCJwaXBlXCIgbGV0LXBhcmFtcz1cInBhcmFtc1wiPlxuICAgKiAge3sgZGF0YSB8IGZvcm1hdERhdGE6IG1vZGVscGlwZTogcGFyYW1zIH19XG4gICAqIDwvbmctdGVtcGxhdGU+XG4gICAqIH5+fn5+fn5+XG4gICAqXG4gICAqL1xuICBAVmlld0NoaWxkKCdkYXRlJywgeyBzdGF0aWM6IHRydWUgfSkgcHVibGljIGRhdGVGYWxsYmFjazogVGVtcGxhdGVSZWY8YW55PjtcblxuICAvKipcbiAgICogWW91IGNhbiBwcm92aWRlIGEgY3VzdG9tIHRlbXBsYXRlIHRvIG92ZXJyaWRlIHRoZSBmYWxsYmFjayBhbmQgcmVuZGVyIGEgZmllbGQncyBkYXRhIGNvbXBsZXRlbHkgb24geW91ciBvd24uXG4gICAqL1xuICBAQ29udGVudENoaWxkKCdkYXRlJywgeyBzdGF0aWM6IHRydWUgfSkgcHVibGljIGRhdGU6IFRlbXBsYXRlUmVmPGFueT47XG5cbiAgLyoqXG4gICAqIEFjY2VzcyB0byB0aGUgZW51bSByZW5kZXJlciBmYWxsYmFjayB0ZW1wbGF0ZS4gVGhlIHRlbXBsYXRlIHVzZWQgaW50ZXJuYWxseSBsb29rcyBsaWtlIHNob3duIGluIHRoZSBleGFtcGxlXG4gICAqXG4gICAqIF9fVGVtcGxhdGUgY29kZTpfX1xuICAgKiB+fn5+fn5+flxuICAgKiA8bmctdGVtcGxhdGUgI2VudW0gbGV0LWRhdGE+XG4gICAqICB7eyBkYXRhIH19XG4gICAqIDwvbmctdGVtcGxhdGU+XG4gICAqIH5+fn5+fn5+XG4gICAqXG4gICAqL1xuICBAVmlld0NoaWxkKCdlbnVtJywgeyBzdGF0aWM6IHRydWUgfSkgcHVibGljIGVudW1GYWxsYmFjazogVGVtcGxhdGVSZWY8YW55PjtcblxuICAvKipcbiAgICogWW91IGNhbiBwcm92aWRlIGEgY3VzdG9tIHRlbXBsYXRlIHRvIG92ZXJyaWRlIHRoZSBmYWxsYmFjayBhbmQgcmVuZGVyIGEgZmllbGQncyBkYXRhIGNvbXBsZXRlbHkgb24geW91ciBvd24uXG4gICAqL1xuICBAQ29udGVudENoaWxkKCdlbnVtJywgeyBzdGF0aWM6IHRydWUgfSkgcHVibGljIGVudW06IFRlbXBsYXRlUmVmPGFueT47XG5cbiAgLyoqXG4gICAqIEFjY2VzcyB0byB0aGUgbnVtYmVyIHJlbmRlcmVyIGZhbGxiYWNrIHRlbXBsYXRlLiBUaGUgdGVtcGxhdGUgdXNlZCBpbnRlcm5hbGx5IGxvb2tzIGxpa2Ugc2hvd24gaW4gdGhlIGV4YW1wbGVcbiAgICogVGhhdCBtZWFucywgaXQgcmVuZGVycyBkYXRhIFwiYXMgaXNcIiwgYnV0IGNhbiBiZSBtb2RpZmllZCBieSBoYW5kbGluZyBhIGN1c3RvbSBwaXBlLiBUbyBhcHBseSBzdWNoXG4gICAqIGEgcGlwZSwgeW91ciB2aWV3bW9kZWwncyBwcm9wZXJ0aWVzIG11c3QgYmUgZGVjb3JhdGVkIHdpdGggdGhlIHtAbGluayBGb3JtYXRQaXBlfSBkZWNvcmF0b3IuXG4gICAqXG4gICAqIF9fVGVtcGxhdGUgY29kZTpfX1xuICAgKiB+fn5+fn5+flxuICAgKiA8bmctdGVtcGxhdGUgI251bWJlciBsZXQtZGF0YSBsZXQtbW9kZWxwaXBlPVwicGlwZVwiIGxldC1wYXJhbXM9XCJwYXJhbXNcIj5cbiAgICogIHt7IGRhdGEgfCBmb3JtYXREYXRhOiBtb2RlbHBpcGU6IHBhcmFtcyB9fVxuICAgKiA8L25nLXRlbXBsYXRlPlxuICAgKiB+fn5+fn5+flxuICAgKlxuICAgKi9cbiAgQFZpZXdDaGlsZCgnbnVtYmVyJywgeyBzdGF0aWM6IHRydWUgfSkgcHVibGljIG51bWJlckZhbGxiYWNrOiBUZW1wbGF0ZVJlZjxhbnk+O1xuXG4gIC8qKlxuICAgKiBZb3UgY2FuIHByb3ZpZGUgYSBjdXN0b20gdGVtcGxhdGUgdG8gb3ZlcnJpZGUgdGhlIGZhbGxiYWNrIGFuZCByZW5kZXIgYSBmaWVsZCdzIGRhdGEgY29tcGxldGVseSBvbiB5b3VyIG93bi5cbiAgICovXG4gIEBDb250ZW50Q2hpbGQoJ251bWJlcicsIHsgc3RhdGljOiB0cnVlIH0pIHB1YmxpYyBudW1iZXI6IFRlbXBsYXRlUmVmPGFueT47XG5cbiAgQElucHV0KCkgcHVibGljIGV4dGVybmFsczogeyBba2V5OiBzdHJpbmddOiBhbnkgfSA9IHt9O1xuXG4gIC8vIEBWaWV3Q2hpbGQoVGVtcGxhdGVSZWYpIHRlbXBsYXRlOiBUZW1wbGF0ZVJlZjxhbnk+O1xuXG4gIC8qKlxuICAgKiBPdmVycmlkZSB0aGUgaW50ZXJuYWwgc3R5bGVzIGJ5IGdpdmluZyBkaXJlY3RseSBDU1MgcnVsZXMgYmFzZWQgb24gdGhlIGNvbHVtbiB0YWdzLlxuICAgKi9cbiAgQElucHV0KClcbiAgcHVibGljIGNvbHVtblN0eWxlOiBEYXRhZ3JpZFN0eWxlcztcblxuICAvKipcbiAgICogVGhlIG1vZGVsIHRoYXQgbWFrZXMgdXAgdGhlIGNvbnRlbnQuIFNoYWxsIHByb3ZpZGUgcHJvcGVydGllcyB3aXRoIGRlY29yYXRvcnMgdG8gY29udHJvbCBhcHBlYXJhbmNlLlxuICAgKi9cbiAgQElucHV0KClcbiAgcHVibGljIG1vZGVsOiBEYXRhR3JpZE1vZGVsPGFueT47XG5cbiAgLyoqXG4gICAqIFdoZWF0aGVyIHRvIHNob3cgYSBkZWxldGUgYnV0dG9uLiBDbGlja2luZyBpdCBmaXJlcyB0aGUge0BsaW5rIERhdGFHcmlkTW9kZWwuT25EZWxldGV9ZXZlbnQuXG4gICAqL1xuICBASW5wdXQoKVxuICBwdWJsaWMgc2hvd0RlbGV0ZUJ1dHRvbjogYm9vbGVhbjtcbiAgLyoqXG4gICAqIFdoZWF0aGVyIHRvIHNob3cgYW4gZWRpdCBidXR0b24uIENsaWNraW5nIGl0IGZpcmVzIHRoZSB7QGxpbmsgRGF0YUdyaWRNb2RlbC5PbkVkaXR9ZXZlbnQuXG4gICAqL1xuICBASW5wdXQoKVxuICBwdWJsaWMgc2hvd0VkaXRCdXR0b246IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFNob3cgdGhlIGFjdGlvbiBjb2x1bW4gYXQgYWxsLiBVc2Uge0BsaW5rIHNob3dEZWxldGVCdXR0b24gYW5kICBAc2VlIHNob3dFZGl0QnV0dG9uIHRvIHN3aXRjaCB0aGV9YnV0dG9uc1xuICAgKiBvbiBvciBvZmYgaW5kaXZpZHVhbGx5LiBEZWZhdWx0IGlzIGB0cnVlYCAoYWN0aW9ucyB2aXNpYmxlKS5cbiAgICovXG4gIEBJbnB1dCgpXG4gIHB1YmxpYyBzaG93QWN0aW9ucyA9IHRydWU7XG5cbiAgLyoqXG4gICAqIFRoZSB0ZXh0IHRoYXQgYXBwZWFycyBvbiB0aGUgRGVsZXRlIGJ1dHRvbi4gRGVmYXVsdCBpcyAnRGVsZXRlJy5cbiAgICovXG4gIEBJbnB1dCgpXG4gIHB1YmxpYyB0ZXh0RGVsZXRlQnV0dG9uID0gJ0RlbGV0ZSc7XG4gIC8qKlxuICAgKiBUaGUgdGV4dCB0aGF0IGFwcGVhcnMgb24gdGhlIEVkaXQgYnV0dG9uLiBEZWZhdWx0IGlzICdFZGl0Jy5cbiAgICovXG4gIEBJbnB1dCgpXG4gIHB1YmxpYyB0ZXh0RWRpdEJ1dHRvbiA9ICdFZGl0JztcbiAgLyoqXG4gICAqIFRoZSBjb2x1bW4gaGVhZGVyIG9mIHRoZSBjb2x1bW4gdGhhdCBzaG93cyB0aGUgYnV0dG9ucy4gRGVmYXVsdCBpcyAnQWN0aW9ucycuXG4gICAqL1xuICBASW5wdXQoKVxuICBwdWJsaWMgdGV4dEJ1dHRvbnNIZWFkZXIgPSAnQWN0aW9ucyc7XG5cbiAgLyoqXG4gICAqIFRoZSB0ZXh0IHRoYXQgYXBwZWFycyBpZiB0aGVyZSBhcmUgbm8gaXRlbXMgdG8gc2hvdy4gQ2FuIGFsc28gYmUgb3ZlcndyaXR0ZW4gYnkgYSBtb3JlIGNvbXBsZXggcGllY2VcbiAgICogb2YgY29kZSBieSBhZGRpbmcgYSB0ZW1wbGF0ZSBsaWtlIHRoaXM6XG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIDxuZy10ZW1wbGF0ZSAjZGF0YS13YXJuaW5nLW5vaXRlbXM+XG4gICAqICAgPGRpdiBjbGFzcz1cImFsZXJ0IGFsZXJ0LWRhbmdlclwiPlRoZSBncmlkIGlzIGVtcHR5PC9kaXY+XG4gICAqIDwvbmctdGVtcGxhdGU+XG4gICAqL1xuICBASW5wdXQoKVxuICBwdWJsaWMgdGV4dE5vSXRlbXMgPSAnVGhlcmUgYXJlIG5vIGl0ZW1zIHRvIHNob3cnO1xuXG4gIC8qKlxuICAgKiBUaGUgZmlsdGVyIHZhbHVlIHRvIGZpbHRlciB0aGUgY29udGVudC4gVGhlIGRhdGEgaXMgb2YgdHlwZSBgeyBbcHJvcDogc3RyaW5nXTogYW55IH1gLlxuICAgKlxuICAgKiBAcGFyYW0gdmFsdWUgQSBkaWN0aW9uYXJ5IHdpdGggZmlsdGVyIGluc3RydWN0aW9ucyBhcyBzaG93biBiZWxvdy4gVGhlIGZpbHRlciBsb2dpYyBhcHBsaWVzIG9uZSBhZnRlciBhbm90aGVyLCBsaWtlIGFuIF9fQU5EX18gY29uanVuY3Rpb24uXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIHtcbiAgICogICAgXCJlbWFpbFwiOiBcInBhdWxAc2FtcGxlLmNvbVwiXG4gICAqICAgIFwibmFtZVwiOiBcIlBhdWxcIlxuICAgKiB9XG4gICAqXG4gICAqL1xuICBASW5wdXQoKVxuICBwdWJsaWMgc2V0IGZpbHRlcih2YWx1ZTogeyBbcHJvcDogc3RyaW5nXTogYW55IH0pIHtcbiAgICBpZiAodGhpcy5tb2RlbCkge1xuICAgICAgdGhpcy5tb2RlbC5zZWFyY2hWYWx1ZSA9IHZhbHVlO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBJZiBgdHJ1ZWAgdGhlIGNvbHVtbnMgY2FuIGJlIHJlYXJyYW5nZWQgYnkgbW92aW5nIGFyb3VuZCB3aXRoIGRyYWcgJ24gZHJvcC5cbiAgICovXG4gIEBJbnB1dCgpXG4gIHB1YmxpYyByZUFycmFuZ2VDb2x1bW5zOiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBFdmVudCBmb3J3YXJkZWQgZnJvbSBtb2RlbCBjbGFzcyBhbmQgYmVpbmcgZmlyZWQgYWZ0ZXIgdGhlIG1vZGVsIGNsYXNzJ3Mgb25FZGl0IGV2ZW50LlxuICAgKiBUaGUgZXZlbnQgaXMgaW52b2tlZCBieSB0aGUgYXBwcm9wcmlhdGUgaW50ZXJuYWwgYnV0dG9uIHZpYSBjbGljay5cbiAgICovXG4gIEBPdXRwdXQoKVxuICBwdWJsaWMgZWRpdEl0ZW06IEV2ZW50RW1pdHRlcjxhbnk+ID0gbmV3IEV2ZW50RW1pdHRlcjxhbnk+KCk7XG5cbiAgLyoqXG4gICAqIEV2ZW50IGZvcndhcmRlZCBmcm9tIG1vZGVsIGNsYXNzIGFuZCBiZWluZyBmaXJlZCBhZnRlciB0aGUgbW9kZWwgY2xhc3MncyBvbkRlbGV0ZSBldmVudC5cbiAgICogVGhlIGV2ZW50IGlzIGludm9rZWQgYnkgdGhlIGFwcHJvcHJpYXRlIGludGVybmFsIGJ1dHRvbiB2aWEgY2xpY2suXG4gICAqL1xuICBAT3V0cHV0KClcbiAgcHVibGljIGRlbGV0ZUl0ZW06IEV2ZW50RW1pdHRlcjxhbnk+ID0gbmV3IEV2ZW50RW1pdHRlcjxhbnk+KCk7XG5cbiAgcHVibGljIG5nQWZ0ZXJWaWV3SW5pdCgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5tb2RlbCkge1xuICAgICAgdGhpcy5tb2RlbC5vbkVkaXQuc3Vic2NyaWJlKGl0ZW0gPT4gdGhpcy5lZGl0SXRlbS5lbWl0KGl0ZW0pKTtcbiAgICAgIHRoaXMubW9kZWwub25EZWxldGUuc3Vic2NyaWJlKGl0ZW0gPT4gdGhpcy5kZWxldGVJdGVtLmVtaXQoaXRlbSkpO1xuICAgIH1cbiAgfVxuXG4gIHB1YmxpYyBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5tb2RlbCkge1xuICAgICAgdGhpcy5tb2RlbC5vbkVkaXQudW5zdWJzY3JpYmUoKTtcbiAgICAgIHRoaXMubW9kZWwub25EZWxldGUudW5zdWJzY3JpYmUoKTtcbiAgICB9XG4gIH1cblxuICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6bWVtYmVyLW9yZGVyaW5nXG4gIC8qKlxuICAgKiBAaWdub3JlXG4gICAqL1xuICBwcml2YXRlIHdhcm5Qcm9wOiB7IFtwcm9wOiBzdHJpbmddOiBzdHJpbmcgfSA9IHt9O1xuXG4gIC8qKlxuICAgKiBAaWdub3JlXG4gICAqIENvbnRyb2xzIHRoZSB0ZW1wbGF0ZSB1c2VkIHRvIGRpc3BsYXkgY2VydGFpbiBkYXRhIHR5cGVzLlxuICAgKiBJZiB0aGUgaG9zdCBwcm92aWRlcyBhIHRlbXBsYXRlIGl0J3MgYmVpbmcgdXNlZCwgb3RoZXJ3aXNlIGEgZmFsbGJhY2sgaXMgcHJvdmlkZWRcbiAgICogQHBhcmFtIHVpSGludCBQcm9wZXJ0eSBvZiB7QGxpbmsgVWlIaW50fSBkZWNvcmF0b3JcbiAgICovXG4gIHB1YmxpYyBnZXRBY3RpdmVUZW1wbGF0ZSh1aUhpbnQ6IHN0cmluZywgcHJvcD86IHN0cmluZyk6IFRlbXBsYXRlUmVmPGFueT4ge1xuICAgIGlmICh0aGlzW3VpSGludF0pIHtcbiAgICAgIC8vIGlmIHByb3ZpZGVkIGJ5IHVzZXIgdmlhIENvbnRlbnRDaGlsZCBhbmQgb3ZlcndyaXRpbmcgZGVmYXVsdHMgKHN0cmluZyA9PSBzdHJpbmcgZXRjLilcbiAgICAgIHJldHVybiB0aGlzW3VpSGludF07XG4gICAgfVxuICAgIGlmICh0aGlzLmV4dGVybmFsc1t1aUhpbnRdKSB7XG4gICAgICAvLyBpZiBwcm92aWRlZCBieSB1c2VyIHZpYSBDb250ZW50Q2hpbGQgYnV0IGNvbXBsZXRlbHkgcmVwbGFjZWRcbiAgICAgIHJldHVybiB0aGlzLmV4dGVybmFsc1t1aUhpbnRdO1xuICAgIH1cbiAgICBpZiAodGhpc1tgJHt1aUhpbnR9RmFsbGJhY2tgXSkge1xuICAgICAgLy8gb3RoZXJ3aXNlIHdlIHRha2Ugb3VycyBmcm9tIG5nLXRlbXBsYXRlIHZpYSBWaWV3Q2hpbGRcbiAgICAgIHJldHVybiB0aGlzW2Ake3VpSGludH1GYWxsYmFja2BdO1xuICAgIH1cbiAgICAvLyBpZiB3ZSBnbyBoZXJlIHRoZSBtb2RlbCByZXF1ZXN0ZWQgYSBjdXN0b20gdGVtcGxhdGUgdGhhdCBkaWRuJ3QgZXhpc3RzXG4gICAgaWYgKHRoaXMud2FyblByb3BbcHJvcF0gIT09IHVpSGludCkge1xuICAgICAgY29uc29sZS53YXJuKGBQcm9wZXJ0eSAke3Byb3B9IHJlcXVlc3RlZCB0aGUgdGVtcGxhdGUgJHt1aUhpbnR9LCBidXQgaXQgd2Fzbid0IHByb3ZpZGVkLiBGYWxsaW5nIGJhY2sgdG8gXCJzdHJpbmdcIi5gKTtcbiAgICAgIHRoaXMud2FyblByb3BbcHJvcF0gPSB1aUhpbnQ7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLnN0cmluZ0ZhbGxiYWNrO1xuICB9XG59XG4iXX0=