UNPKG

svogv

Version:

A decorator based approach for model driven forms, including an advanced DataGrid and a TreeView component.

199 lines 31.1 kB
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()\">&copy;</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=