ngx-nested-data-table
Version:
angular master-detail table angular material style
318 lines (311 loc) • 31.5 kB
JavaScript
import { __extends, __spread } from 'tslib';
import { DataSource } from '@angular/cdk/collections';
import { map } from 'rxjs/operators';
import { of, merge, BehaviorSubject } from 'rxjs';
import { Component, ViewChild, Input, NgModule } from '@angular/core';
import { MatPaginator, MatSort, MatTableModule, MatPaginatorModule, MatSortModule, MatInputModule } from '@angular/material';
import { trigger, state, style, transition, animate } from '@angular/animations';
import { CommonModule } from '@angular/common';
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
/**
* Data source for the NgxDataTable view. This class should
* encapsulate all logic for fetching and manipulating the displayed data
* (including sorting, pagination, and filtering).
*/
var /**
* Data source for the NgxDataTable view. This class should
* encapsulate all logic for fetching and manipulating the displayed data
* (including sorting, pagination, and filtering).
*/
NgxDataTableDataSource = /** @class */ (function (_super) {
__extends(NgxDataTableDataSource, _super);
function NgxDataTableDataSource(paginator, _data, sort) {
var _this = _super.call(this) || this;
_this.paginator = paginator;
_this._data = _data;
_this.sort = sort;
_this._filterChange = new BehaviorSubject('');
_this.data = _data;
// Master detail table
var /** @type {?} */ rows = [];
_data.forEach(function (element) {
return element.details
? rows.push(element, { detailRow: true, element: element })
: rows.push(element);
});
_this.data = rows;
return _this;
}
Object.defineProperty(NgxDataTableDataSource.prototype, "filter", {
get: /**
* @return {?}
*/
function () {
return this._filterChange.value;
},
set: /**
* @param {?} filter
* @return {?}
*/
function (filter) {
this._filterChange.next(filter);
},
enumerable: true,
configurable: true
});
/**
* Connect this data source to the table. The table will only update when
* the returned stream emits new items.
* @returns A stream of the items to be rendered.
*/
/**
* Connect this data source to the table. The table will only update when
* the returned stream emits new items.
* @return {?} A stream of the items to be rendered.
*/
NgxDataTableDataSource.prototype.connect = /**
* Connect this data source to the table. The table will only update when
* the returned stream emits new items.
* @return {?} A stream of the items to be rendered.
*/
function () {
var _this = this;
// Combine everything that affects the rendered data into one update
// stream for the data-table to consume.
var /** @type {?} */ dataMutations = [
of(this.data),
this.paginator.page,
this.sort.sortChange,
this._filterChange,
];
// Set the paginator length
this.paginator.length = this.data.length;
return merge.apply(void 0, __spread(dataMutations)).pipe(map(function () {
var /** @type {?} */ filtered = _this._filterData(_this._data);
_this.data = _this._enrichData(filtered);
return _this.getPagedData(_this.getSortedData(__spread(_this.data)));
}));
};
/**
* @param {?} filtered
* @return {?}
*/
NgxDataTableDataSource.prototype._enrichData = /**
* @param {?} filtered
* @return {?}
*/
function (filtered) {
var /** @type {?} */ rows = [];
filtered.forEach(function (element) {
return element.details
? rows.push(element, { detailRow: true, element: element })
: rows.push(element);
});
return rows;
};
/**
* @param {?} data
* @return {?}
*/
NgxDataTableDataSource.prototype._filterData = /**
* @param {?} data
* @return {?}
*/
function (data) {
var _this = this;
this.filteredData =
!this.filter ? data : data.filter(function (obj) {
// Transform the data into a lowercase string of all property values.
var /** @type {?} */ accumulator = function (currentTerm, key) { return currentTerm + obj[key]; };
var /** @type {?} */ dataStr = Object.keys(obj).reduce(accumulator, '').toLowerCase();
// Transform the filter by converting it to lowercase and removing whitespace.
var /** @type {?} */ transformedFilter = _this.filter.trim().toLowerCase();
return dataStr.indexOf(transformedFilter) !== -1;
});
return this.filteredData;
};
/**
* Called when the table is being destroyed. Use this function, to clean up
* any open connections or free any held resources that were set up during connect.
*/
/**
* Called when the table is being destroyed. Use this function, to clean up
* any open connections or free any held resources that were set up during connect.
* @return {?}
*/
NgxDataTableDataSource.prototype.disconnect = /**
* Called when the table is being destroyed. Use this function, to clean up
* any open connections or free any held resources that were set up during connect.
* @return {?}
*/
function () { };
/**
* Paginate the data (client-side). If you're using server-side pagination,
* this would be replaced by requesting the appropriate data from the server.
* @param {?} data
* @return {?}
*/
NgxDataTableDataSource.prototype.getPagedData = /**
* Paginate the data (client-side). If you're using server-side pagination,
* this would be replaced by requesting the appropriate data from the server.
* @param {?} data
* @return {?}
*/
function (data) {
var /** @type {?} */ startIndex = this.paginator.pageIndex * this.paginator.pageSize;
return data.splice(startIndex, this.paginator.pageSize);
};
/**
* Sort the data (client-side). If you're using server-side sorting,
* this would be replaced by requesting the appropriate data from the server.
* @param {?} data
* @return {?}
*/
NgxDataTableDataSource.prototype.getSortedData = /**
* Sort the data (client-side). If you're using server-side sorting,
* this would be replaced by requesting the appropriate data from the server.
* @param {?} data
* @return {?}
*/
function (data) {
var _this = this;
if (!this.sort.active || this.sort.direction === '') {
return data;
}
return data.sort(function (a, b) {
var /** @type {?} */ isAsc = _this.sort.direction === 'asc';
if (isNaN(a[_this.sort.active])) {
return compare(a[_this.sort.active], b[_this.sort.active], isAsc);
}
else {
return compare(+a[_this.sort.active], +b[_this.sort.active], isAsc);
}
});
};
return NgxDataTableDataSource;
}(DataSource));
/**
* Simple sort comparator for example ID/Name columns (for client-side sorting).
* @param {?} a
* @param {?} b
* @param {?} isAsc
* @return {?}
*/
function compare(a, b, isAsc) {
return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
var NgxDataTableComponent = /** @class */ (function () {
function NgxDataTableComponent() {
this.isExpansionDetailRow = function (i, row) {
return row.hasOwnProperty('detailRow');
};
}
Object.defineProperty(NgxDataTableComponent.prototype, "data", {
set: /**
* @param {?} _data
* @return {?}
*/
function (_data) {
if (_data) {
this.dataSource = new NgxDataTableDataSource(this.paginator, _data, this.sort);
this.displayedColumns = Object.keys(_data[0]).filter(function (key) { return key !== 'details'; });
}
},
enumerable: true,
configurable: true
});
/**
* expand collapse a row
* @param row
*/
/**
* expand collapse a row
* @param {?} row
* @return {?}
*/
NgxDataTableComponent.prototype.toggleRow = /**
* expand collapse a row
* @param {?} row
* @return {?}
*/
function (row) {
if (this.expandedElement === row) {
this.expandedElement = null;
}
else {
this.expandedElement = row;
}
};
/**
* @param {?} filterValue
* @return {?}
*/
NgxDataTableComponent.prototype.applyFilter = /**
* @param {?} filterValue
* @return {?}
*/
function (filterValue) {
this.dataSource.filter = filterValue;
};
NgxDataTableComponent.decorators = [
{ type: Component, args: [{
selector: 'ngx-data-table',
template: "<div class=\"mat-elevation-z8\">\n <mat-form-field>\n <input matInput (keyup)=\"applyFilter($event.target.value)\" placeholder=\"Filter\" class=\"filter\">\n </mat-form-field>\n <mat-table #table [dataSource]=\"dataSource\" matSort aria-label=\"Elements\">\n <ng-container [matColumnDef]=\"cols\" *ngFor=\"let cols of displayedColumns; let i = index\">\n <mat-header-cell *matHeaderCellDef mat-sort-header>{{cols}}</mat-header-cell>\n <mat-cell *matCellDef=\"let element\" [ngClass]=\"{'col-value': element.details === undefined}\">\n <!-- expand caret -->\n <span *ngIf=\"i === 0 && element.details\">\n <span *ngIf=\"expandedElement && expandedElement[cols] === element[cols]; else plusIcon\" class=\"expand-icon\">▲</span>\n <ng-template #plusIcon><span class=\"expand-icon\">▼</span></ng-template>\n </span>\n <span>{{element[cols]}}</span>\n </mat-cell>\n </ng-container>\n\n <!-- Expanded Content Column - The detail row is made up of this one column -->\n <ng-container matColumnDef=\"expandedDetail\">\n <mat-cell *matCellDef=\"let detail\">\n <ngx-data-table [data]=\"detail.element.details\" class=\"detail-table\"></ngx-data-table>\n </mat-cell>\n </ng-container>\n\n <mat-header-row *matHeaderRowDef=\"displayedColumns\"></mat-header-row>\n <mat-row *matRowDef=\"let row; columns: displayedColumns;\"\n [class.expanded]=\"expandedElement == row\"\n (click)=\"toggleRow(row)\"></mat-row>\n <mat-row *matRowDef=\"let row; columns: ['expandedDetail']; when: isExpansionDetailRow\"\n [@detailExpand]=\"row.element == expandedElement ? 'expanded' : 'collapsed'\"\n style=\"overflow: hidden\"></mat-row>\n </mat-table>\n\n <mat-paginator #paginator\n\n [length]=\"dataSource?.data?.length\"\n [pageIndex]=\"0\"\n [pageSize]=\"25\"\n [pageSizeOptions]=\"[25, 50, 100, 250]\">\n </mat-paginator>\n</div>\n",
styles: [
".detail-table {display: flex;flex-direction: column;display: block;margin: 10px;width: 100%;}\n .expand-icon {color: rgba(0,0,0,.44);font-size: 12px; margin-right: 5px; cursor: pointer;}\n .col-value:first-child span{margin-left: 15px;}\n .mat-form-field {padding: 10px 10px 0 10px;width: calc(100% - 20px);}"
],
animations: [
trigger('detailExpand', [
state('collapsed', style({ height: '0px', minHeight: '0', visibility: 'hidden' })),
state('expanded', style({ height: '*', visibility: 'visible' })),
transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
]),
],
},] },
];
NgxDataTableComponent.propDecorators = {
data: [{ type: Input }],
paginator: [{ type: ViewChild, args: [MatPaginator,] }],
sort: [{ type: ViewChild, args: [MatSort,] }]
};
return NgxDataTableComponent;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
var NgxDataTableModule = /** @class */ (function () {
function NgxDataTableModule() {
}
NgxDataTableModule.decorators = [
{ type: NgModule, args: [{
imports: [
CommonModule,
MatTableModule,
MatPaginatorModule,
MatSortModule,
MatInputModule,
],
declarations: [NgxDataTableComponent],
exports: [NgxDataTableComponent],
},] },
];
return NgxDataTableModule;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
/**
* @fileoverview added by tsickle
* @suppress {checkTypes} checked by tsc
*/
export { NgxDataTableDataSource, NgxDataTableComponent, NgxDataTableModule };
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LW5lc3RlZC1kYXRhLXRhYmxlLmpzLm1hcCIsInNvdXJjZXMiOlsibmc6Ly9uZ3gtbmVzdGVkLWRhdGEtdGFibGUvbGliL25neC1kYXRhLXRhYmxlL25neC1kYXRhLXRhYmxlLWRhdGFzb3VyY2UudHMiLCJuZzovL25neC1uZXN0ZWQtZGF0YS10YWJsZS9saWIvbmd4LWRhdGEtdGFibGUvbmd4LWRhdGEtdGFibGUuY29tcG9uZW50LnRzIiwibmc6Ly9uZ3gtbmVzdGVkLWRhdGEtdGFibGUvbGliL25neC1kYXRhLXRhYmxlL25neC1kYXRhLXRhYmxlLm1vZHVsZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBEYXRhU291cmNlIH0gZnJvbSAnQGFuZ3VsYXIvY2RrL2NvbGxlY3Rpb25zJztcbmltcG9ydCB7IE1hdFBhZ2luYXRvciwgTWF0U29ydCB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsJztcbmltcG9ydCB7IG1hcCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7T2JzZXJ2YWJsZSwgb2YgYXMgb2JzZXJ2YWJsZU9mLCBtZXJnZSwgQmVoYXZpb3JTdWJqZWN0LCBjb21iaW5lTGF0ZXN0fSBmcm9tICdyeGpzJztcblxuLyoqXG4gKiBEYXRhIHNvdXJjZSBmb3IgdGhlIE5neERhdGFUYWJsZSB2aWV3LiBUaGlzIGNsYXNzIHNob3VsZFxuICogZW5jYXBzdWxhdGUgYWxsIGxvZ2ljIGZvciBmZXRjaGluZyBhbmQgbWFuaXB1bGF0aW5nIHRoZSBkaXNwbGF5ZWQgZGF0YVxuICogKGluY2x1ZGluZyBzb3J0aW5nLCBwYWdpbmF0aW9uLCBhbmQgZmlsdGVyaW5nKS5cbiAqL1xuZXhwb3J0IGNsYXNzIE5neERhdGFUYWJsZURhdGFTb3VyY2UgZXh0ZW5kcyBEYXRhU291cmNlPGFueT4ge1xuICBwdWJsaWMgZGF0YTogYW55W107XG4gIF9maWx0ZXJDaGFuZ2UgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PHN0cmluZz4oJycpO1xuICBmaWx0ZXJlZERhdGE6IGFueVtdO1xuXG4gIGdldCBmaWx0ZXIoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5fZmlsdGVyQ2hhbmdlLnZhbHVlO1xuICB9XG4gIHNldCBmaWx0ZXIoZmlsdGVyOiBzdHJpbmcpIHtcbiAgICB0aGlzLl9maWx0ZXJDaGFuZ2UubmV4dChmaWx0ZXIpO1xuICB9XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBwYWdpbmF0b3I6IE1hdFBhZ2luYXRvcixcbiAgICBwcml2YXRlIF9kYXRhOiBhbnlbXSxcbiAgICBwcml2YXRlIHNvcnQ6IE1hdFNvcnRcbiAgKSB7XG4gICAgc3VwZXIoKTtcbiAgICB0aGlzLmRhdGEgPSBfZGF0YTtcbiAgICAvLyBNYXN0ZXIgZGV0YWlsIHRhYmxlXG4gICAgY29uc3Qgcm93cyA9IFtdO1xuICAgIF9kYXRhLmZvckVhY2goXG4gICAgICBlbGVtZW50ID0+XG4gICAgICAgIGVsZW1lbnQuZGV0YWlsc1xuICAgICAgICAgID8gcm93cy5wdXNoKGVsZW1lbnQsIHsgZGV0YWlsUm93OiB0cnVlLCBlbGVtZW50IH0pXG4gICAgICAgICAgOiByb3dzLnB1c2goZWxlbWVudClcbiAgICApO1xuICAgIHRoaXMuZGF0YSA9IHJvd3M7XG4gIH1cblxuICAvKipcbiAgICogQ29ubmVjdCB0aGlzIGRhdGEgc291cmNlIHRvIHRoZSB0YWJsZS4gVGhlIHRhYmxlIHdpbGwgb25seSB1cGRhdGUgd2hlblxuICAgKiB0aGUgcmV0dXJuZWQgc3RyZWFtIGVtaXRzIG5ldyBpdGVtcy5cbiAgICogQHJldHVybnMgQSBzdHJlYW0gb2YgdGhlIGl0ZW1zIHRvIGJlIHJlbmRlcmVkLlxuICAgKi9cbiAgY29ubmVjdCgpOiBPYnNlcnZhYmxlPGFueVtdPiB7XG4gICAgLy8gQ29tYmluZSBldmVyeXRoaW5nIHRoYXQgYWZmZWN0cyB0aGUgcmVuZGVyZWQgZGF0YSBpbnRvIG9uZSB1cGRhdGVcbiAgICAvLyBzdHJlYW0gZm9yIHRoZSBkYXRhLXRhYmxlIHRvIGNvbnN1bWUuXG4gICAgY29uc3QgZGF0YU11dGF0aW9ucyA9IFtcbiAgICAgIG9ic2VydmFibGVPZih0aGlzLmRhdGEpLFxuICAgICAgdGhpcy5wYWdpbmF0b3IucGFnZSxcbiAgICAgIHRoaXMuc29ydC5zb3J0Q2hhbmdlLFxuICAgICAgdGhpcy5fZmlsdGVyQ2hhbmdlLFxuICAgIF07XG5cbiAgICAvLyBTZXQgdGhlIHBhZ2luYXRvciBsZW5ndGhcbiAgICB0aGlzLnBhZ2luYXRvci5sZW5ndGggPSB0aGlzLmRhdGEubGVuZ3RoO1xuXG4gICAgcmV0dXJuIG1lcmdlKC4uLmRhdGFNdXRhdGlvbnMpLnBpcGUoXG4gICAgICBtYXAoKCkgPT4ge1xuICAgICAgICBjb25zdCBmaWx0ZXJlZCA9IHRoaXMuX2ZpbHRlckRhdGEodGhpcy5fZGF0YSk7XG4gICAgICAgIHRoaXMuZGF0YSA9IHRoaXMuX2VucmljaERhdGEoZmlsdGVyZWQpO1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRQYWdlZERhdGEodGhpcy5nZXRTb3J0ZWREYXRhKFsuLi50aGlzLmRhdGFdKSk7XG4gICAgICB9KVxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIF9lbnJpY2hEYXRhKGZpbHRlcmVkKSB7XG4gICAgY29uc3Qgcm93cyA9IFtdO1xuICAgIGZpbHRlcmVkLmZvckVhY2goXG4gICAgICBlbGVtZW50ID0+XG4gICAgICAgIGVsZW1lbnQuZGV0YWlsc1xuICAgICAgICAgID8gcm93cy5wdXNoKGVsZW1lbnQsIHtkZXRhaWxSb3c6IHRydWUsIGVsZW1lbnR9KVxuICAgICAgICAgIDogcm93cy5wdXNoKGVsZW1lbnQpXG4gICAgKTtcbiAgICByZXR1cm4gcm93cztcbiAgfVxuXG4gIHByaXZhdGUgX2ZpbHRlckRhdGEoZGF0YTogYW55W10pIHtcbiAgICB0aGlzLmZpbHRlcmVkRGF0YSA9XG4gICAgICAhdGhpcy5maWx0ZXIgPyBkYXRhIDogZGF0YS5maWx0ZXIob2JqID0+IHtcbiAgICAgIC8vIFRyYW5zZm9ybSB0aGUgZGF0YSBpbnRvIGEgbG93ZXJjYXNlIHN0cmluZyBvZiBhbGwgcHJvcGVydHkgdmFsdWVzLlxuICAgICAgY29uc3QgYWNjdW11bGF0b3IgPSAoY3VycmVudFRlcm0sIGtleSkgPT4gY3VycmVudFRlcm0gKyBvYmpba2V5XTtcbiAgICAgIGNvbnN0IGRhdGFTdHIgPSBPYmplY3Qua2V5cyhvYmopLnJlZHVjZShhY2N1bXVsYXRvciwgJycpLnRvTG93ZXJDYXNlKCk7XG5cbiAgICAgIC8vIFRyYW5zZm9ybSB0aGUgZmlsdGVyIGJ5IGNvbnZlcnRpbmcgaXQgdG8gbG93ZXJjYXNlIGFuZCByZW1vdmluZyB3aGl0ZXNwYWNlLlxuICAgICAgY29uc3QgdHJhbnNmb3JtZWRGaWx0ZXIgPSB0aGlzLmZpbHRlci50cmltKCkudG9Mb3dlckNhc2UoKTtcblxuICAgICAgcmV0dXJuIGRhdGFTdHIuaW5kZXhPZih0cmFuc2Zvcm1lZEZpbHRlcikgIT09IC0xO1xuICAgIH0pO1xuICAgIHJldHVybiB0aGlzLmZpbHRlcmVkRGF0YTtcbiAgfVxuXG4gIC8qKlxuICAgKiAgQ2FsbGVkIHdoZW4gdGhlIHRhYmxlIGlzIGJlaW5nIGRlc3Ryb3llZC4gVXNlIHRoaXMgZnVuY3Rpb24sIHRvIGNsZWFuIHVwXG4gICAqIGFueSBvcGVuIGNvbm5lY3Rpb25zIG9yIGZyZWUgYW55IGhlbGQgcmVzb3VyY2VzIHRoYXQgd2VyZSBzZXQgdXAgZHVyaW5nIGNvbm5lY3QuXG4gICAqL1xuICBkaXNjb25uZWN0KCkge31cblxuICAvKipcbiAgICogUGFnaW5hdGUgdGhlIGRhdGEgKGNsaWVudC1zaWRlKS4gSWYgeW91J3JlIHVzaW5nIHNlcnZlci1zaWRlIHBhZ2luYXRpb24sXG4gICAqIHRoaXMgd291bGQgYmUgcmVwbGFjZWQgYnkgcmVxdWVzdGluZyB0aGUgYXBwcm9wcmlhdGUgZGF0YSBmcm9tIHRoZSBzZXJ2ZXIuXG4gICAqL1xuICBwcml2YXRlIGdldFBhZ2VkRGF0YShkYXRhOiBhbnlbXSkge1xuICAgIGNvbnN0IHN0YXJ0SW5kZXggPSB0aGlzLnBhZ2luYXRvci5wYWdlSW5kZXggKiB0aGlzLnBhZ2luYXRvci5wYWdlU2l6ZTtcbiAgICByZXR1cm4gZGF0YS5zcGxpY2Uoc3RhcnRJbmRleCwgdGhpcy5wYWdpbmF0b3IucGFnZVNpemUpO1xuICB9XG5cbiAgLyoqXG4gICAqIFNvcnQgdGhlIGRhdGEgKGNsaWVudC1zaWRlKS4gSWYgeW91J3JlIHVzaW5nIHNlcnZlci1zaWRlIHNvcnRpbmcsXG4gICAqIHRoaXMgd291bGQgYmUgcmVwbGFjZWQgYnkgcmVxdWVzdGluZyB0aGUgYXBwcm9wcmlhdGUgZGF0YSBmcm9tIHRoZSBzZXJ2ZXIuXG4gICAqL1xuICBwcml2YXRlIGdldFNvcnRlZERhdGEoZGF0YTogYW55W10pIHtcbiAgICBpZiAoIXRoaXMuc29ydC5hY3RpdmUgfHwgdGhpcy5zb3J0LmRpcmVjdGlvbiA9PT0gJycpIHtcbiAgICAgIHJldHVybiBkYXRhO1xuICAgIH1cblxuICAgIHJldHVybiBkYXRhLnNvcnQoKGEsIGIpID0+IHtcbiAgICAgIGNvbnN0IGlzQXNjID0gdGhpcy5zb3J0LmRpcmVjdGlvbiA9PT0gJ2FzYyc7XG4gICAgICBpZiAoaXNOYU4oYVt0aGlzLnNvcnQuYWN0aXZlXSkpIHtcbiAgICAgICAgcmV0dXJuIGNvbXBhcmUoYVt0aGlzLnNvcnQuYWN0aXZlXSwgYlt0aGlzLnNvcnQuYWN0aXZlXSwgaXNBc2MpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIGNvbXBhcmUoK2FbdGhpcy5zb3J0LmFjdGl2ZV0sICtiW3RoaXMuc29ydC5hY3RpdmVdLCBpc0FzYyk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cbn1cblxuLyoqIFNpbXBsZSBzb3J0IGNvbXBhcmF0b3IgZm9yIGV4YW1wbGUgSUQvTmFtZSBjb2x1bW5zIChmb3IgY2xpZW50LXNpZGUgc29ydGluZykuICovXG5mdW5jdGlvbiBjb21wYXJlKGEsIGIsIGlzQXNjKSB7XG4gIHJldHVybiAoYSA8IGIgPyAtMSA6IDEpICogKGlzQXNjID8gMSA6IC0xKTtcbn1cbiIsImltcG9ydCB7IENvbXBvbmVudCwgT25Jbml0LCBWaWV3Q2hpbGQsIElucHV0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBNYXRQYWdpbmF0b3IsIE1hdFNvcnQgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbCc7XG5pbXBvcnQgeyBOZ3hEYXRhVGFibGVEYXRhU291cmNlIH0gZnJvbSAnLi9uZ3gtZGF0YS10YWJsZS1kYXRhc291cmNlJztcbmltcG9ydCB7XG4gIHRyaWdnZXIsXG4gIHN0YXRlLFxuICBzdHlsZSxcbiAgdHJhbnNpdGlvbixcbiAgYW5pbWF0ZSxcbn0gZnJvbSAnQGFuZ3VsYXIvYW5pbWF0aW9ucyc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ25neC1kYXRhLXRhYmxlJyxcbiAgdGVtcGxhdGU6IGA8ZGl2IGNsYXNzPVwibWF0LWVsZXZhdGlvbi16OFwiPlxuICAgIDxtYXQtZm9ybS1maWVsZD5cbiAgICAgIDxpbnB1dCBtYXRJbnB1dCAoa2V5dXApPVwiYXBwbHlGaWx0ZXIoJGV2ZW50LnRhcmdldC52YWx1ZSlcIiBwbGFjZWhvbGRlcj1cIkZpbHRlclwiIGNsYXNzPVwiZmlsdGVyXCI+XG4gICAgPC9tYXQtZm9ybS1maWVsZD5cbiAgPG1hdC10YWJsZSAjdGFibGUgW2RhdGFTb3VyY2VdPVwiZGF0YVNvdXJjZVwiIG1hdFNvcnQgYXJpYS1sYWJlbD1cIkVsZW1lbnRzXCI+XG4gICAgPG5nLWNvbnRhaW5lciBbbWF0Q29sdW1uRGVmXT1cImNvbHNcIiAqbmdGb3I9XCJsZXQgY29scyBvZiBkaXNwbGF5ZWRDb2x1bW5zOyBsZXQgaSA9IGluZGV4XCI+XG4gICAgICA8bWF0LWhlYWRlci1jZWxsICptYXRIZWFkZXJDZWxsRGVmIG1hdC1zb3J0LWhlYWRlcj57e2NvbHN9fTwvbWF0LWhlYWRlci1jZWxsPlxuICAgICAgPG1hdC1jZWxsICptYXRDZWxsRGVmPVwibGV0IGVsZW1lbnRcIiBbbmdDbGFzc109XCJ7J2NvbC12YWx1ZSc6IGVsZW1lbnQuZGV0YWlscyA9PT0gdW5kZWZpbmVkfVwiPlxuICAgICAgICA8IS0tIGV4cGFuZCBjYXJldCAtLT5cbiAgICAgICAgPHNwYW4gKm5nSWY9XCJpID09PSAwICYmIGVsZW1lbnQuZGV0YWlsc1wiPlxuICAgICAgICAgIDxzcGFuICpuZ0lmPVwiZXhwYW5kZWRFbGVtZW50ICYmIGV4cGFuZGVkRWxlbWVudFtjb2xzXSA9PT0gZWxlbWVudFtjb2xzXTsgZWxzZSBwbHVzSWNvblwiIGNsYXNzPVwiZXhwYW5kLWljb25cIj4mIzk2NTA7PC9zcGFuPlxuICAgICAgICAgIDxuZy10ZW1wbGF0ZSAjcGx1c0ljb24+PHNwYW4gY2xhc3M9XCJleHBhbmQtaWNvblwiPiYjOTY2MDs8L3NwYW4+PC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgPC9zcGFuPlxuICAgICAgICA8c3Bhbj57e2VsZW1lbnRbY29sc119fTwvc3Bhbj5cbiAgICAgIDwvbWF0LWNlbGw+XG4gICAgPC9uZy1jb250YWluZXI+XG5cbiAgICA8IS0tIEV4cGFuZGVkIENvbnRlbnQgQ29sdW1uIC0gVGhlIGRldGFpbCByb3cgaXMgbWFkZSB1cCBvZiB0aGlzIG9uZSBjb2x1bW4gLS0+XG4gICAgPG5nLWNvbnRhaW5lciBtYXRDb2x1bW5EZWY9XCJleHBhbmRlZERldGFpbFwiPlxuICAgICAgPG1hdC1jZWxsICptYXRDZWxsRGVmPVwibGV0IGRldGFpbFwiPlxuICAgICAgICA8bmd4LWRhdGEtdGFibGUgW2RhdGFdPVwiZGV0YWlsLmVsZW1lbnQuZGV0YWlsc1wiIGNsYXNzPVwiZGV0YWlsLXRhYmxlXCI+PC9uZ3gtZGF0YS10YWJsZT5cbiAgICAgIDwvbWF0LWNlbGw+XG4gICAgPC9uZy1jb250YWluZXI+XG5cbiAgICA8bWF0LWhlYWRlci1yb3cgKm1hdEhlYWRlclJvd0RlZj1cImRpc3BsYXllZENvbHVtbnNcIj48L21hdC1oZWFkZXItcm93PlxuICAgIDxtYXQtcm93ICptYXRSb3dEZWY9XCJsZXQgcm93OyBjb2x1bW5zOiBkaXNwbGF5ZWRDb2x1bW5zO1wiXG4gICAgICAgICAgICAgIFtjbGFzcy5leHBhbmRlZF09XCJleHBhbmRlZEVsZW1lbnQgPT0gcm93XCJcbiAgICAgICAgICAgICAgKGNsaWNrKT1cInRvZ2dsZVJvdyhyb3cpXCI+PC9tYXQtcm93PlxuICAgIDxtYXQtcm93ICptYXRSb3dEZWY9XCJsZXQgcm93OyBjb2x1bW5zOiBbJ2V4cGFuZGVkRGV0YWlsJ107IHdoZW46IGlzRXhwYW5zaW9uRGV0YWlsUm93XCJcbiAgICBbQGRldGFpbEV4cGFuZF09XCJyb3cuZWxlbWVudCA9PSBleHBhbmRlZEVsZW1lbnQgPyAnZXhwYW5kZWQnIDogJ2NvbGxhcHNlZCdcIlxuICAgIHN0eWxlPVwib3ZlcmZsb3c6IGhpZGRlblwiPjwvbWF0LXJvdz5cbiAgPC9tYXQtdGFibGU+XG5cbiAgPG1hdC1wYWdpbmF0b3IgI3BhZ2luYXRvclxuXG4gICAgW2xlbmd0aF09XCJkYXRhU291cmNlPy5kYXRhPy5sZW5ndGhcIlxuICAgIFtwYWdlSW5kZXhdPVwiMFwiXG4gICAgW3BhZ2VTaXplXT1cIjI1XCJcbiAgICBbcGFnZVNpemVPcHRpb25zXT1cIlsyNSwgNTAsIDEwMCwgMjUwXVwiPlxuICA8L21hdC1wYWdpbmF0b3I+XG48L2Rpdj5cbmAsXG4gIHN0eWxlczogW1xuICAgIGAuZGV0YWlsLXRhYmxlIHtkaXNwbGF5OiBmbGV4O2ZsZXgtZGlyZWN0aW9uOiBjb2x1bW47ZGlzcGxheTogYmxvY2s7bWFyZ2luOiAxMHB4O3dpZHRoOiAxMDAlO31cbiAgICAuZXhwYW5kLWljb24ge2NvbG9yOiByZ2JhKDAsMCwwLC40NCk7Zm9udC1zaXplOiAxMnB4OyBtYXJnaW4tcmlnaHQ6IDVweDsgY3Vyc29yOiBwb2ludGVyO31cbiAgICAuY29sLXZhbHVlOmZpcnN0LWNoaWxkIHNwYW57bWFyZ2luLWxlZnQ6IDE1cHg7fVxuICAgIC5tYXQtZm9ybS1maWVsZCB7cGFkZGluZzogMTBweCAxMHB4IDAgMTBweDt3aWR0aDogY2FsYygxMDAlIC0gMjBweCk7fWBcbiAgXSxcbiAgYW5pbWF0aW9uczogW1xuICAgIHRyaWdnZXIoJ2RldGFpbEV4cGFuZCcsIFtcbiAgICAgIHN0YXRlKFxuICAgICAgICAnY29sbGFwc2VkJyxcbiAgICAgICAgc3R5bGUoeyBoZWlnaHQ6ICcwcHgnLCBtaW5IZWlnaHQ6ICcwJywgdmlzaWJpbGl0eTogJ2hpZGRlbicgfSlcbiAgICAgICksXG4gICAgICBzdGF0ZSgnZXhwYW5kZWQnLCBzdHlsZSh7IGhlaWdodDogJyonLCB2aXNpYmlsaXR5OiAndmlzaWJsZScgfSkpLFxuICAgICAgdHJhbnNpdGlvbihcbiAgICAgICAgJ2V4cGFuZGVkIDw9PiBjb2xsYXBzZWQnLFxuICAgICAgICBhbmltYXRlKCcyMjVtcyBjdWJpYy1iZXppZXIoMC40LCAwLjAsIDAuMiwgMSknKVxuICAgICAgKSxcbiAgICBdKSxcbiAgXSxcbn0pXG5leHBvcnQgY2xhc3MgTmd4RGF0YVRhYmxlQ29tcG9uZW50IHtcbiAgQElucHV0KClcbiAgc2V0IGRhdGEoX2RhdGE6IGFueVtdKSB7XG4gICAgaWYgKF9kYXRhKSB7XG4gICAgICB0aGlzLmRhdGFTb3VyY2UgPSBuZXcgTmd4RGF0YVRhYmxlRGF0YVNvdXJjZShcbiAgICAgICAgdGhpcy5wYWdpbmF0b3IsXG4gICAgICAgIF9kYXRhLFxuICAgICAgICB0aGlzLnNvcnRcbiAgICAgICk7XG4gICAgICB0aGlzLmRpc3BsYXllZENvbHVtbnMgPSBPYmplY3Qua2V5cyhfZGF0YVswXSkuZmlsdGVyKFxuICAgICAgICBrZXkgPT4ga2V5ICE9PSAnZGV0YWlscydcbiAgICAgICk7XG4gICAgfVxuICB9XG4gIEBWaWV3Q2hpbGQoTWF0UGFnaW5hdG9yKSBwYWdpbmF0b3I6IE1hdFBhZ2luYXRvcjtcbiAgQFZpZXdDaGlsZChNYXRTb3J0KSBzb3J0OiBNYXRTb3J0O1xuICBkYXRhU291cmNlOiBOZ3hEYXRhVGFibGVEYXRhU291cmNlO1xuXG4gIC8qKiBDb2x1bW5zIGRpc3BsYXllZCBpbiB0aGUgdGFibGUuIENvbHVtbnMgSURzIGNhbiBiZSBhZGRlZCwgcmVtb3ZlZCwgb3IgcmVvcmRlcmVkLiAqL1xuICBkaXNwbGF5ZWRDb2x1bW5zOiBBcnJheTxzdHJpbmc+O1xuICBleHBhbmRlZEVsZW1lbnQ6IEFycmF5PHN0cmluZz47XG4gIGlzRXhwYW5zaW9uRGV0YWlsUm93ID0gKGk6IG51bWJlciwgcm93OiBPYmplY3QpID0+XG4gICAgcm93Lmhhc093blByb3BlcnR5KCdkZXRhaWxSb3cnKTtcblxuICAvKipcbiAgICogZXhwYW5kIGNvbGxhcHNlIGEgcm93XG4gICAqIEBwYXJhbSByb3dcbiAgICovXG4gIHRvZ2dsZVJvdyhyb3cpIHtcbiAgICBpZiAodGhpcy5leHBhbmRlZEVsZW1lbnQgPT09IHJvdykge1xuICAgICAgdGhpcy5leHBhbmRlZEVsZW1lbnQgPSBudWxsO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmV4cGFuZGVkRWxlbWVudCA9IHJvdztcbiAgICB9XG4gIH1cblxuICBhcHBseUZpbHRlcihmaWx0ZXJWYWx1ZTogc3RyaW5nKSB7XG4gICAgdGhpcy5kYXRhU291cmNlLmZpbHRlciA9IGZpbHRlclZhbHVlO1xuICB9XG59XG4iLCJpbXBvcnQgeyBOZ01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7IE5neERhdGFUYWJsZUNvbXBvbmVudCB9IGZyb20gJy4vbmd4LWRhdGEtdGFibGUuY29tcG9uZW50JztcbmltcG9ydCB7XG4gIE1hdFRhYmxlTW9kdWxlLFxuICBNYXRQYWdpbmF0b3JNb2R1bGUsXG4gIE1hdFNvcnRNb2R1bGUsXG4gIE1hdElucHV0TW9kdWxlLFxufSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbCc7XG5cbkBOZ01vZHVsZSh7XG4gIGltcG9ydHM6IFtcbiAgICBDb21tb25Nb2R1bGUsXG4gICAgTWF0VGFibGVNb2R1bGUsXG4gICAgTWF0UGFnaW5hdG9yTW9kdWxlLFxuICAgIE1hdFNvcnRNb2R1bGUsXG4gICAgTWF0SW5wdXRNb2R1bGUsXG4gIF0sXG4gIGRlY2xhcmF0aW9uczogW05neERhdGFUYWJsZUNvbXBvbmVudF0sXG4gIGV4cG9ydHM6IFtOZ3hEYXRhVGFibGVDb21wb25lbnRdLFxufSlcbmV4cG9ydCBjbGFzcyBOZ3hEYXRhVGFibGVNb2R1bGUge31cbiJdLCJuYW1lcyI6WyJ0c2xpYl8xLl9fZXh0ZW5kcyIsIm9ic2VydmFibGVPZiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBVUE7Ozs7O0FBQUE7SUFBNENBLDBDQUFlO0lBWXpELGdDQUNVLFdBQ0EsT0FDQTtRQUhWLFlBS0UsaUJBQU8sU0FXUjtRQWZTLGVBQVMsR0FBVCxTQUFTO1FBQ1QsV0FBSyxHQUFMLEtBQUs7UUFDTCxVQUFJLEdBQUosSUFBSTs4QkFiRSxJQUFJLGVBQWUsQ0FBUyxFQUFFLENBQUM7UUFnQjdDLEtBQUksQ0FBQyxJQUFJLEdBQUcsS0FBSyxDQUFDOztRQUVsQixxQkFBTSxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBQ2hCLEtBQUssQ0FBQyxPQUFPLENBQ1gsVUFBQSxPQUFPO1lBQ0wsT0FBQSxPQUFPLENBQUMsT0FBTztrQkFDWCxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsT0FBTyxTQUFBLEVBQUUsQ0FBQztrQkFDaEQsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUM7U0FBQSxDQUN6QixDQUFDO1FBQ0YsS0FBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUM7O0tBQ2xCO0lBdkJELHNCQUFJLDBDQUFNOzs7O1FBQVY7WUFDRSxPQUFPLElBQUksQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDO1NBQ2pDOzs7OztRQUNELFVBQVcsTUFBYztZQUN2QixJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztTQUNqQzs7O09BSEE7Ozs7Ozs7Ozs7O0lBNEJELHdDQUFPOzs7OztJQUFQO1FBQUEsaUJBb0JDOzs7UUFqQkMs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