UNPKG

juvo-rafa-library

Version:

A comprehensive Angular component library featuring real-world components and validators extracted from the Juvo Rafa backoffice application. Now with improved select components and bug fixes.

192 lines 31.1 kB
import { Component, Input, Output, EventEmitter } from '@angular/core'; import { CommonModule } from '@angular/common'; import { of } from 'rxjs'; import * as i0 from "@angular/core"; import * as i1 from "@angular/common"; /** * List Component * * @description * A simple list component for displaying tabular data with basic functionality. * Originally designed for backoffice applications requiring data presentation. * Supports sorting, custom columns, and item selection. * * @example * ```html * <!-- Basic list --> * <juvo-list * [data$]="listData$" * [columns]="[ * { key: 'name', label: 'Name', sortable: true }, * { key: 'email', label: 'Email' }, * { key: 'status', label: 'Status', type: 'boolean' } * ]" * (itemSelected)="onItemSelected($event)"> * </juvo-list> * * <!-- List with loading state --> * <juvo-list * [data$]="userData$" * [columns]="userColumns" * [loading$]="userLoading$" * [selectable]="true" * (itemSelected)="handleSelection($event)"> * </juvo-list> * ``` * * @selector juvo-list * @since 2.1.0 * @author Juvo Rafa Team */ export class JuvoListComponent { constructor() { /** Observable data source */ this.data$ = of([]); /** Column configuration */ this.columns = []; /** Loading state observable */ this.loading$ = of(false); /** Whether items are selectable @default false */ this.selectable = false; /** Whether to show header @default true */ this.showHeader = true; /** Empty state message */ this.emptyMessage = 'No data available'; /** Loading message */ this.loadingMessage = 'Loading...'; /** List size variant @default "medium" */ this.size = 'medium'; /** Whether to show borders @default true */ this.bordered = true; /** Whether to show striped rows @default true */ this.striped = true; /** Emitted when an item is selected */ this.itemSelected = new EventEmitter(); /** Emitted when an item is clicked */ this.itemClicked = new EventEmitter(); /** Emitted when column header is clicked for sorting */ this.columnSort = new EventEmitter(); this.selectedItems = []; this.sortDirection = 'asc'; } /** * Gets CSS classes for the list container * @returns Combined CSS classes */ get containerClasses() { let classes = `juvo-list juvo-list-${this.size}`; if (this.bordered) classes += ' bordered'; if (this.striped) classes += ' striped'; return classes; } /** * Handles item selection */ onItemSelect(item) { if (!this.selectable) return; const index = this.selectedItems.findIndex(selected => selected === item); if (index > -1) { this.selectedItems.splice(index, 1); } else { this.selectedItems.push(item); } this.itemSelected.emit(item); } /** * Handles item click */ onItemClick(item) { this.itemClicked.emit(item); } /** * Handles column header click for sorting */ onColumnHeaderClick(column) { if (!column.sortable) return; if (this.sortColumn === column.key) { this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc'; } else { this.sortColumn = column.key; this.sortDirection = 'asc'; } this.columnSort.emit({ column, direction: this.sortDirection }); } /** * Checks if an item is selected */ isSelected(item) { return this.selectedItems.includes(item); } /** * Gets the display value for a cell */ getCellValue(item, column) { const value = item[column.key]; switch (column.type) { case 'boolean': return value ? '' : ''; case 'date': return value ? new Date(value).toLocaleDateString() : ''; case 'number': return typeof value === 'number' ? value.toLocaleString() : ''; default: return value?.toString() || ''; } } /** * Gets CSS classes for column header */ getHeaderClasses(column) { let classes = 'list-header-cell'; if (column.sortable) classes += ' sortable'; if (this.sortColumn === column.key) classes += ` sorted-${this.sortDirection}`; return classes; } /** * Track by function for ngFor performance */ trackByFn(index, item) { return item.id || index; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: JuvoListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: JuvoListComponent, isStandalone: true, selector: "juvo-list", inputs: { data$: "data$", columns: "columns", loading$: "loading$", selectable: "selectable", showHeader: "showHeader", emptyMessage: "emptyMessage", loadingMessage: "loadingMessage", size: "size", bordered: "bordered", striped: "striped" }, outputs: { itemSelected: "itemSelected", itemClicked: "itemClicked", columnSort: "columnSort" }, ngImport: i0, template: "<div [class]=\"containerClasses\">\n <!-- Loading State -->\n <div class=\"list-loading\" *ngIf=\"loading$ | async\">\n <div class=\"loading-spinner\"></div>\n <div class=\"loading-text\">{{ loadingMessage }}</div>\n </div>\n\n <!-- List Content -->\n <div class=\"list-content\" *ngIf=\"!(loading$ | async)\">\n <!-- Header -->\n <div class=\"list-header\" *ngIf=\"showHeader && columns.length > 0\">\n <div class=\"list-header-row\">\n <div \n *ngIf=\"selectable\" \n class=\"list-header-cell checkbox-cell\">\n <!-- Checkbox for select all could go here -->\n </div>\n <div\n *ngFor=\"let column of columns\"\n [class]=\"getHeaderClasses(column)\"\n [style.width]=\"column.width\"\n (click)=\"onColumnHeaderClick(column)\">\n {{ column.label }}\n <span class=\"sort-indicator\" *ngIf=\"column.sortable && sortColumn === column.key\">\n {{ sortDirection === 'asc' ? '\u2191' : '\u2193' }}\n </span>\n </div>\n </div>\n </div>\n\n <!-- Body -->\n <div class=\"list-body\">\n <!-- Data Rows -->\n <div \n class=\"list-row\"\n *ngFor=\"let item of data$ | async; trackBy: trackByFn\"\n [class.selected]=\"isSelected(item)\"\n (click)=\"onItemClick(item)\">\n \n <!-- Selection checkbox -->\n <div \n *ngIf=\"selectable\" \n class=\"list-cell checkbox-cell\"\n (click)=\"onItemSelect(item); $event.stopPropagation()\">\n <input \n type=\"checkbox\" \n [checked]=\"isSelected(item)\"\n (change)=\"onItemSelect(item)\">\n </div>\n\n <!-- Data cells -->\n <div\n *ngFor=\"let column of columns\"\n class=\"list-cell\"\n [style.width]=\"column.width\">\n {{ getCellValue(item, column) }}\n </div>\n </div>\n\n <!-- Empty State -->\n <div class=\"list-empty\" *ngIf=\"(data$ | async)?.length === 0\">\n <div class=\"empty-icon\">\uD83D\uDCCB</div>\n <div class=\"empty-text\">{{ emptyMessage }}</div>\n </div>\n </div>\n </div>\n</div> ", styles: [".juvo-list{width:100%;background:#fff;border-radius:.5rem;overflow:hidden}.juvo-list.bordered{border:1px solid #e5e7eb}.list-loading{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:3rem;gap:1rem}.loading-spinner{width:2rem;height:2rem;border:2px solid #f3f4f6;border-top:2px solid #3b82f6;border-radius:50%;animation:spin 1s linear infinite}.loading-text{color:#6b7280;font-size:.875rem}@keyframes spin{to{transform:rotate(360deg)}}.list-content{width:100%}.list-header{background:#f9fafb;border-bottom:1px solid #e5e7eb}.list-header-row{display:flex;align-items:center}.list-header-cell{display:flex;align-items:center;gap:.5rem;font-weight:600;color:#374151;font-size:.875rem;border-right:1px solid #e5e7eb}.list-header-cell:last-child{border-right:none}.list-header-cell.sortable{cursor:pointer;transition:background-color .15s}.list-header-cell.sortable:hover{background:#f3f4f6}.sort-indicator{font-size:.75rem;color:#3b82f6}.list-body{max-height:400px;overflow-y:auto}.list-row{display:flex;align-items:center;border-bottom:1px solid #f3f4f6;cursor:pointer;transition:all .15s}.list-row:hover{background:#f9fafb}.list-row.selected{background:#eff6ff;border-color:#bfdbfe}.list-row:last-child{border-bottom:none}.juvo-list.striped .list-row:nth-child(2n){background:#fafafa}.juvo-list.striped .list-row:nth-child(2n):hover{background:#f3f4f6}.list-cell{flex:1;color:#374151;font-size:.875rem;border-right:1px solid #f3f4f6;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.list-cell:last-child{border-right:none}.checkbox-cell{flex:0 0 auto;width:3rem;display:flex;justify-content:center}.checkbox-cell input[type=checkbox]{margin:0}.juvo-list-small .list-header-cell,.juvo-list-small .list-cell{padding:.5rem;font-size:.8125rem}.juvo-list-medium .list-header-cell,.juvo-list-medium .list-cell{padding:.75rem;font-size:.875rem}.juvo-list-large .list-header-cell,.juvo-list-large .list-cell{padding:1rem;font-size:1rem}.list-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:3rem 2rem;gap:1rem}.empty-icon{font-size:3rem;opacity:.4}.empty-text{color:#9ca3af;font-size:.875rem;text-align:center}@media (max-width: 768px){.list-body{max-height:300px}.list-header-cell,.list-cell{min-width:100px;padding:.5rem .25rem}.juvo-list-large .list-header-cell,.juvo-list-large .list-cell{padding:.75rem .5rem;font-size:.875rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: JuvoListComponent, decorators: [{ type: Component, args: [{ selector: 'juvo-list', standalone: true, imports: [CommonModule], template: "<div [class]=\"containerClasses\">\n <!-- Loading State -->\n <div class=\"list-loading\" *ngIf=\"loading$ | async\">\n <div class=\"loading-spinner\"></div>\n <div class=\"loading-text\">{{ loadingMessage }}</div>\n </div>\n\n <!-- List Content -->\n <div class=\"list-content\" *ngIf=\"!(loading$ | async)\">\n <!-- Header -->\n <div class=\"list-header\" *ngIf=\"showHeader && columns.length > 0\">\n <div class=\"list-header-row\">\n <div \n *ngIf=\"selectable\" \n class=\"list-header-cell checkbox-cell\">\n <!-- Checkbox for select all could go here -->\n </div>\n <div\n *ngFor=\"let column of columns\"\n [class]=\"getHeaderClasses(column)\"\n [style.width]=\"column.width\"\n (click)=\"onColumnHeaderClick(column)\">\n {{ column.label }}\n <span class=\"sort-indicator\" *ngIf=\"column.sortable && sortColumn === column.key\">\n {{ sortDirection === 'asc' ? '\u2191' : '\u2193' }}\n </span>\n </div>\n </div>\n </div>\n\n <!-- Body -->\n <div class=\"list-body\">\n <!-- Data Rows -->\n <div \n class=\"list-row\"\n *ngFor=\"let item of data$ | async; trackBy: trackByFn\"\n [class.selected]=\"isSelected(item)\"\n (click)=\"onItemClick(item)\">\n \n <!-- Selection checkbox -->\n <div \n *ngIf=\"selectable\" \n class=\"list-cell checkbox-cell\"\n (click)=\"onItemSelect(item); $event.stopPropagation()\">\n <input \n type=\"checkbox\" \n [checked]=\"isSelected(item)\"\n (change)=\"onItemSelect(item)\">\n </div>\n\n <!-- Data cells -->\n <div\n *ngFor=\"let column of columns\"\n class=\"list-cell\"\n [style.width]=\"column.width\">\n {{ getCellValue(item, column) }}\n </div>\n </div>\n\n <!-- Empty State -->\n <div class=\"list-empty\" *ngIf=\"(data$ | async)?.length === 0\">\n <div class=\"empty-icon\">\uD83D\uDCCB</div>\n <div class=\"empty-text\">{{ emptyMessage }}</div>\n </div>\n </div>\n </div>\n</div> ", styles: [".juvo-list{width:100%;background:#fff;border-radius:.5rem;overflow:hidden}.juvo-list.bordered{border:1px solid #e5e7eb}.list-loading{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:3rem;gap:1rem}.loading-spinner{width:2rem;height:2rem;border:2px solid #f3f4f6;border-top:2px solid #3b82f6;border-radius:50%;animation:spin 1s linear infinite}.loading-text{color:#6b7280;font-size:.875rem}@keyframes spin{to{transform:rotate(360deg)}}.list-content{width:100%}.list-header{background:#f9fafb;border-bottom:1px solid #e5e7eb}.list-header-row{display:flex;align-items:center}.list-header-cell{display:flex;align-items:center;gap:.5rem;font-weight:600;color:#374151;font-size:.875rem;border-right:1px solid #e5e7eb}.list-header-cell:last-child{border-right:none}.list-header-cell.sortable{cursor:pointer;transition:background-color .15s}.list-header-cell.sortable:hover{background:#f3f4f6}.sort-indicator{font-size:.75rem;color:#3b82f6}.list-body{max-height:400px;overflow-y:auto}.list-row{display:flex;align-items:center;border-bottom:1px solid #f3f4f6;cursor:pointer;transition:all .15s}.list-row:hover{background:#f9fafb}.list-row.selected{background:#eff6ff;border-color:#bfdbfe}.list-row:last-child{border-bottom:none}.juvo-list.striped .list-row:nth-child(2n){background:#fafafa}.juvo-list.striped .list-row:nth-child(2n):hover{background:#f3f4f6}.list-cell{flex:1;color:#374151;font-size:.875rem;border-right:1px solid #f3f4f6;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.list-cell:last-child{border-right:none}.checkbox-cell{flex:0 0 auto;width:3rem;display:flex;justify-content:center}.checkbox-cell input[type=checkbox]{margin:0}.juvo-list-small .list-header-cell,.juvo-list-small .list-cell{padding:.5rem;font-size:.8125rem}.juvo-list-medium .list-header-cell,.juvo-list-medium .list-cell{padding:.75rem;font-size:.875rem}.juvo-list-large .list-header-cell,.juvo-list-large .list-cell{padding:1rem;font-size:1rem}.list-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:3rem 2rem;gap:1rem}.empty-icon{font-size:3rem;opacity:.4}.empty-text{color:#9ca3af;font-size:.875rem;text-align:center}@media (max-width: 768px){.list-body{max-height:300px}.list-header-cell,.list-cell{min-width:100px;padding:.5rem .25rem}.juvo-list-large .list-header-cell,.juvo-list-large .list-cell{padding:.75rem .5rem;font-size:.875rem}}\n"] }] }], propDecorators: { data$: [{ type: Input }], columns: [{ type: Input }], loading$: [{ type: Input }], selectable: [{ type: Input }], showHeader: [{ type: Input }], emptyMessage: [{ type: Input }], loadingMessage: [{ type: Input }], size: [{ type: Input }], bordered: [{ type: Input }], striped: [{ type: Input }], itemSelected: [{ type: Output }], itemClicked: [{ type: Output }], columnSort: [{ type: Output }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoianV2by1saXN0LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL3VpLWNvbXBvbmVudHMvc3JjL2xpYi9qdXZvLWxpc3QvanV2by1saXN0LmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL3VpLWNvbXBvbmVudHMvc3JjL2xpYi9qdXZvLWxpc3QvanV2by1saXN0LmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDdkUsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFBYyxFQUFFLEVBQUUsTUFBTSxNQUFNLENBQUM7OztBQWV0Qzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWtDRztBQVFILE1BQU0sT0FBTyxpQkFBaUI7SUFQOUI7UUFRRSw2QkFBNkI7UUFDcEIsVUFBSyxHQUFzQixFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7UUFFM0MsMkJBQTJCO1FBQ2xCLFlBQU8sR0FBaUIsRUFBRSxDQUFDO1FBRXBDLCtCQUErQjtRQUN0QixhQUFRLEdBQXdCLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUVuRCxrREFBa0Q7UUFDekMsZUFBVSxHQUFZLEtBQUssQ0FBQztRQUVyQywyQ0FBMkM7UUFDbEMsZUFBVSxHQUFZLElBQUksQ0FBQztRQUVwQywwQkFBMEI7UUFDakIsaUJBQVksR0FBVyxtQkFBbUIsQ0FBQztRQUVwRCxzQkFBc0I7UUFDYixtQkFBYyxHQUFXLFlBQVksQ0FBQztRQUUvQywwQ0FBMEM7UUFDakMsU0FBSSxHQUFpQyxRQUFRLENBQUM7UUFFdkQsNENBQTRDO1FBQ25DLGFBQVEsR0FBWSxJQUFJLENBQUM7UUFFbEMsaURBQWlEO1FBQ3hDLFlBQU8s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QkFHRyxXQUFXO3NCQUFwQixNQUFNO2dCQUdHLFVBQVU7c0JBQW5CLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIElucHV0LCBPdXRwdXQsIEV2ZW50RW1pdHRlciB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7IE9ic2VydmFibGUsIG9mIH0gZnJvbSAncnhqcyc7XG5cbi8qKlxuICogTGlzdCBjb2x1bW4gY29uZmlndXJhdGlvbiBpbnRlcmZhY2VcbiAqIEBpbnRlcmZhY2UgTGlzdENvbHVtblxuICogQHNpbmNlIDIuMS4wXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTGlzdENvbHVtbiB7XG4gIGtleTogc3RyaW5nO1xuICBsYWJlbDogc3RyaW5nO1xuICBzb3J0YWJsZT86IGJvb2xlYW47XG4gIHdpZHRoPzogc3RyaW5nO1xuICB0eXBlPzogJ3RleHQnIHwgJ251bWJlcicgfCAnZGF0ZScgfCAnYm9vbGVhbicgfCAnY3VzdG9tJztcbn1cblxuLyoqXG4gKiBMaXN0IENvbXBvbmVudFxuICogXG4gKiBAZGVzY3JpcHRpb25cbiAqIEEgc2ltcGxlIGxpc3QgY29tcG9uZW50IGZvciBkaXNwbGF5aW5nIHRhYnVsYXIgZGF0YSB3aXRoIGJhc2ljIGZ1bmN0aW9uYWxpdHkuXG4gKiBPcmlnaW5hbGx5IGRlc2lnbmVkIGZvciBiYWNrb2ZmaWNlIGFwcGxpY2F0aW9ucyByZXF1aXJpbmcgZGF0YSBwcmVzZW50YXRpb24uXG4gKiBTdXBwb3J0cyBzb3J0aW5nLCBjdXN0b20gY29sdW1ucywgYW5kIGl0ZW0gc2VsZWN0aW9uLlxuICogXG4gKiBAZXhhbXBsZVxuICogYGBgaHRtbFxuICogPCEtLSBCYXNpYyBsaXN0IC0tPlxuICogPGp1dm8tbGlzdFxuICogICBbZGF0YSRdPVwibGlzdERhdGEkXCJcbiAqICAgW2NvbHVtbnNdPVwiW1xuICogICAgIHsga2V5OiAnbmFtZScsIGxhYmVsOiAnTmFtZScsIHNvcnRhYmxlOiB0cnVlIH0sXG4gKiAgICAgeyBrZXk6ICdlbWFpbCcsIGxhYmVsOiAnRW1haWwnIH0sXG4gKiAgICAgeyBrZXk6ICdzdGF0dXMnLCBsYWJlbDogJ1N0YXR1cycsIHR5cGU6ICdib29sZWFuJyB9XG4gKiAgIF1cIlxuICogICAoaXRlbVNlbGVjdGVkKT1cIm9uSXRlbVNlbGVjdGVkKCRldmVudClcIj5cbiAqIDwvanV2by1saXN0PlxuICogXG4gKiA8IS0tIExpc3Qgd2l0aCBsb2FkaW5nIHN0YXRlIC0tPlxuICogPGp1dm8tbGlzdFxuICogICBbZGF0YSRdPVwidXNlckRhdGEkXCJcbiAqICAgW2NvbHVtbnNdPVwidXNlckNvbHVtbnNcIlxuICogICBbbG9hZGluZyRdPVwidXNlckxvYWRpbmckXCJcbiAqICAgW3NlbGVjdGFibGVdPVwidHJ1ZVwiXG4gKiAgIChpdGVtU2VsZWN0ZWQpPVwiaGFuZGxlU2VsZWN0aW9uKCRldmVudClcIj5cbiAqIDwvanV2by1saXN0PlxuICogYGBgXG4gKiBcbiAqIEBzZWxlY3RvciBqdXZvLWxpc3RcbiAqIEBzaW5jZSAyLjEuMFxuICogQGF1dGhvciBKdXZvIFJhZmEgVGVhbVxuICovXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdqdXZvLWxpc3QnLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbQ29tbW9uTW9kdWxlXSxcbiAgdGVtcGxhdGVVcmw6ICcuL2p1dm8tbGlzdC5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsOiAnLi9qdXZvLWxpc3QuY29tcG9uZW50LmNzcydcbn0pXG5leHBvcnQgY2xhc3MgSnV2b0xpc3RDb21wb25lbnQge1xuICAvKiogT2JzZXJ2YWJsZSBkYXRhIHNvdXJjZSAqL1xuICBASW5wdXQoKSBkYXRhJDogT2JzZXJ2YWJsZTxhbnlbXT4gPSBvZihbXSk7XG4gIFxuICAvKiogQ29sdW1uIGNvbmZpZ3VyYXRpb24gKi9cbiAgQElucHV0KCkgY29sdW1uczogTGlzdENvbHVtbltdID0gW107XG4gIFxuICAvKiogTG9hZGluZyBzdGF0ZSBvYnNlcnZhYmxlICovXG4gIEBJbnB1dCgpIGxvYWRpbmckOiBPYnNlcnZhYmxlPGJvb2xlYW4+ID0gb2YoZmFsc2UpO1xuICBcbiAgLyoqIFdoZXRoZXIgaXRlbXMgYXJlIHNlbGVjdGFibGUgQGRlZmF1bHQgZmFsc2UgKi9cbiAgQElucHV0KCkgc2VsZWN0YWJsZTogYm9vbGVhbiA9IGZhbHNlO1xuICBcbiAgLyoqIFdoZXRoZXIgdG8gc2hvdyBoZWFkZXIgQGRlZmF1bHQgdHJ1ZSAqL1xuICBASW5wdXQoKSBzaG93SGVhZGVyOiBib29sZWFuID0gdHJ1ZTtcbiAgXG4gIC8qKiBFbXB0eSBzdGF0ZSBtZXNzYWdlICovXG4gIEBJbnB1dCgpIGVtcHR5TWVzc2FnZTogc3RyaW5nID0gJ05vIGRhdGEgYXZhaWxhYmxlJztcbiAgXG4gIC8qKiBMb2FkaW5nIG1lc3NhZ2UgKi9cbiAgQElucHV0KCkgbG9hZGluZ01lc3NhZ2U6IHN0cmluZyA9ICdMb2FkaW5nLi4uJztcbiAgXG4gIC8qKiBMaXN0IHNpemUgdmFyaWFudCBAZGVmYXVsdCBcIm1lZGl1bVwiICovXG4gIEBJbnB1dCgpIHNpemU6ICdzbWFsbCcgfCAnbWVkaXVtJyB8ICdsYXJnZScgPSAnbWVkaXVtJztcbiAgXG4gIC8qKiBXaGV0aGVyIHRvIHNob3cgYm9yZGVycyBAZGVmYXVsdCB0cnVlICovXG4gIEBJbnB1dCgpIGJvcmRlcmVkOiBib29sZWFuID0gdHJ1ZTtcbiAgXG4gIC8qKiBXaGV0aGVyIHRvIHNob3cgc3RyaXBlZCByb3dzIEBkZWZhdWx0IHRydWUgKi9cbiAgQElucHV0KCkgc3RyaXBlZDogYm9vbGVhbiA9IHRydWU7XG4gIFxuICAvKiogRW1pdHRlZCB3aGVuIGFuIGl0ZW0gaXMgc2VsZWN0ZWQgKi9cbiAgQE91dHB1dCgpIGl0ZW1TZWxlY3RlZCA9IG5ldyBFdmVudEVtaXR0ZXI8YW55PigpO1xuICBcbiAgLyoqIEVtaXR0ZWQgd2hlbiBhbiBpdGVtIGlzIGNsaWNrZWQgKi9cbiAgQE91dHB1dCgpIGl0ZW1DbGlja2VkID0gbmV3IEV2ZW50RW1pdHRlcjxhbnk+KCk7XG4gIFxuICAvKiogRW1pdHRlZCB3aGVuIGNvbHVtbiBoZWFkZXIgaXMgY2xpY2tlZCBmb3Igc29ydGluZyAqL1xuICBAT3V0cHV0KCkgY29sdW1uU29ydCA9IG5ldyBFdmVudEVtaXR0ZXI8eyBjb2x1bW46IExpc3RDb2x1bW4sIGRpcmVjdGlvbjogJ2FzYycgfCAnZGVzYycgfT4oKTtcblxuICBzZWxlY3RlZEl0ZW1zOiBhbnlbXSA9IFtdO1xuICBzb3J0Q29sdW1uPzogc3RyaW5nO1xuICBzb3J0RGlyZWN0aW9uOiAnYXNjJyB8ICdkZXNjJyA9ICdhc2MnO1xuXG4gIC8qKlxuICAgKiBHZXRzIENTUyBjbGFzc2VzIGZvciB0aGUgbGlzdCBjb250YWluZXJcbiAgICogQHJldHVybnMgQ29tYmluZWQgQ1NTIGNsYXNzZXNcbiAgICovXG4gIGdldCBjb250YWluZXJDbGFzc2VzKCk6IHN0cmluZyB7XG4gICAgbGV0IGNsYXNzZXMgPSBganV2by1saXN0IGp1dm8tbGlzdC0ke3RoaXMuc2l6ZX1gO1xuICAgIGlmICh0aGlzLmJvcmRlcmVkKSBjbGFzc2VzICs9ICcgYm9yZGVyZWQnO1xuICAgIGlmICh0aGlzLnN0cmlwZWQpIGNsYXNzZXMgKz0gJyBzdHJpcGVkJztcbiAgICByZXR1cm4gY2xhc3NlcztcbiAgfVxuXG4gIC8qKlxuICAgKiBIYW5kbGVzIGl0ZW0gc2VsZWN0aW9uXG4gICAqL1xuICBvbkl0ZW1TZWxlY3QoaXRlbTogYW55KTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLnNlbGVjdGFibGUpIHJldHVybjtcbiAgICBcbiAgICBjb25zdCBpbmRleCA9IHRoaXMuc2VsZWN0ZWRJdGVtcy5maW5kSW5kZXgoc2VsZWN0ZWQgPT4gc2VsZWN0ZWQgPT09IGl0ZW0pO1xuICAgIGlmIChpbmRleCA+IC0xKSB7XG4gICAgICB0aGlzLnNlbGVjdGVkSXRlbXMuc3BsaWNlKGluZGV4LCAxKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5zZWxlY3RlZEl0ZW1zLnB1c2goaXRlbSk7XG4gICAgfVxuICAgIFxuICAgIHRoaXMuaXRlbVNlbGVjdGVkLmVtaXQoaXRlbSk7XG4gIH1cblxuICAvKipcbiAgICogSGFuZGxlcyBpdGVtIGNsaWNrXG4gICAqL1xuICBvbkl0ZW1DbGljayhpdGVtOiBhbnkpOiB2b2lkIHtcbiAgICB0aGlzLml0ZW1DbGlja2VkLmVtaXQoaXRlbSk7XG4gIH1cblxuICAvKipcbiAgICogSGFuZGxlcyBjb2x1bW4gaGVhZGVyIGNsaWNrIGZvciBzb3J0aW5nXG4gICAqL1xuICBvbkNvbHVtbkhlYWRlckNsaWNrKGNvbHVtbjogTGlzdENvbHVtbik6IHZvaWQge1xuICAgIGlmICghY29sdW1uLnNvcnRhYmxlKSByZXR1cm47XG4gICAgXG4gICAgaWYgKHRoaXMuc29ydENvbHVtbiA9PT0gY29sdW1uLmtleSkge1xuICAgICAgdGhpcy5zb3J0RGlyZWN0aW9uID0gdGhpcy5zb3J0RGlyZWN0aW9uID09PSAnYXNjJyA/ICdkZXNjJyA6ICdhc2MnO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnNvcnRDb2x1bW4gPSBjb2x1bW4ua2V5O1xuICAgICAgdGhpcy5zb3J0RGlyZWN0aW9uID0gJ2FzYyc7XG4gICAgfVxuICAgIFxuICAgIHRoaXMuY29sdW1uU29ydC5lbWl0KHsgY29sdW1uLCBkaXJlY3Rpb246IHRoaXMuc29ydERpcmVjdGlvbiB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVja3MgaWYgYW4gaXRlbSBpcyBzZWxlY3RlZFxuICAgKi9cbiAgaXNTZWxlY3RlZChpdGVtOiBhbnkpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5zZWxlY3RlZEl0ZW1zLmluY2x1ZGVzKGl0ZW0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIGRpc3BsYXkgdmFsdWUgZm9yIGEgY2VsbFxuICAgKi9cbiAgZ2V0Q2VsbFZhbHVlKGl0ZW06IGFueSwgY29sdW1uOiBMaXN0Q29sdW1uKTogc3RyaW5nIHtcbiAgICBjb25zdCB2YWx1ZSA9IGl0ZW1bY29sdW1uLmtleV07XG4gICAgXG4gICAgc3dpdGNoIChjb2x1bW4udHlwZSkge1xuICAgICAgY2FzZSAnYm9vbGVhbic6XG4gICAgICAgIHJldHVybiB2YWx1ZSA/ICfinIUnIDogJ+KdjCc7XG4gICAgICBjYXNlICdkYXRlJzpcbiAgICAgICAgcmV0dXJuIHZhbHVlID8gbmV3IERhdGUodmFsdWUpLnRvTG9jYWxlRGF0ZVN0cmluZygpIDogJyc7XG4gICAgICBjYXNlICdudW1iZXInOlxuICAgICAgICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSAnbnVtYmVyJyA/IHZhbHVlLnRvTG9jYWxlU3RyaW5nKCkgOiAnJztcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiB2YWx1ZT8udG9TdHJpbmcoKSB8fCAnJztcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogR2V0cyBDU1MgY2xhc3NlcyBmb3IgY29sdW1uIGhlYWRlclxuICAgKi9cbiAgZ2V0SGVhZGVyQ2xhc3Nlcyhjb2x1bW46IExpc3RDb2x1bW4pOiBzdHJpbmcge1xuICAgIGxldCBjbGFzc2VzID0gJ2xpc3QtaGVhZGVyLWNlbGwnO1xuICAgIGlmIChjb2x1bW4uc29ydGFibGUpIGNsYXNzZXMgKz0gJyBzb3J0YWJsZSc7XG4gICAgaWYgKHRoaXMuc29ydENvbHVtbiA9PT0gY29sdW1uLmtleSkgY2xhc3NlcyArPSBgIHNvcnRlZC0ke3RoaXMuc29ydERpcmVjdGlvbn1gO1xuICAgIHJldHVybiBjbGFzc2VzO1xuICB9XG5cbiAgLyoqXG4gICAqIFRyYWNrIGJ5IGZ1bmN0aW9uIGZvciBuZ0ZvciBwZXJmb3JtYW5jZVxuICAgKi9cbiAgdHJhY2tCeUZuKGluZGV4OiBudW1iZXIsIGl0ZW06IGFueSk6IGFueSB7XG4gICAgcmV0dXJuIGl0ZW0uaWQgfHwgaW5kZXg7XG4gIH1cbn0gIiwiPGRpdiBbY2xhc3NdPVwiY29udGFpbmVyQ2xhc3Nlc1wiPlxuICA8IS0tIExvYWRpbmcgU3RhdGUgLS0+XG4gIDxkaXYgY2xhc3M9XCJsaXN0LWxvYWRpbmdcIiAqbmdJZj1cImxvYWRpbmckIHwgYXN5bmNcIj5cbiAgICA8ZGl2IGNsYXNzPVwibG9hZGluZy1zcGlubmVyXCI+PC9kaXY+XG4gICAgPGRpdiBjbGFzcz1cImxvYWRpbmctdGV4dFwiPnt7IGxvYWRpbmdNZXNzYWdlIH19PC9kaXY+XG4gIDwvZGl2PlxuXG4gIDwhLS0gTGlzdCBDb250ZW50IC0tPlxuICA8ZGl2IGNsYXNzPVwibGlzdC1jb250ZW50XCIgKm5nSWY9XCIhKGxvYWRpbmckIHwgYXN5bmMpXCI+XG4gICAgPCEtLSBIZWFkZXIgLS0+XG4gICAgPGRpdiBjbGFzcz1cImxpc3QtaGVhZGVyXCIgKm5nSWY9XCJzaG93SGVhZGVyICYmIGNvbHVtbnMubGVuZ3RoID4gMFwiPlxuICAgICAgPGRpdiBjbGFzcz1cImxpc3QtaGVhZGVyLXJvd1wiPlxuICAgICAgICA8ZGl2IFxuICAgICAgICAgICpuZ0lmPVwic2VsZWN0YWJsZVwiIFxuICAgICAgICAgIGNsYXNzPVwibGlzdC1oZWFkZXItY2VsbCBjaGVja2JveC1jZWxsXCI+XG4gICAgICAgICAgPCEtLSBDaGVja2JveCBmb3Igc2VsZWN0IGFsbCBjb3VsZCBnbyBoZXJlIC0tPlxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgPGRpdlxuICAgICAgICAgICpuZ0Zvcj1cImxldCBjb2x1bW4gb2YgY29sdW1uc1wiXG4gICAgICAgICAgW2NsYXNzXT1cImdldEhlYWRlckNsYXNzZXMoY29sdW1uKVwiXG4gICAgICAgICAgW3N0eWxlLndpZHRoXT1cImNvbHVtbi53aWR0aFwiXG4gICAgICAgICAgKGNsaWNrKT1cIm9uQ29sdW1uSGVhZGVyQ2xpY2soY29sdW1uKVwiPlxuICAgICAgICAgIHt7IGNvbHVtbi5sYWJlbCB9fVxuICAgICAgICAgIDxzcGFuIGNsYXNzPVwic29ydC1pbmRpY2F0b3JcIiAqbmdJZj1cImNvbHVtbi5zb3J0YWJsZSAmJiBzb3J0Q29sdW1uID09PSBjb2x1bW4ua2V5XCI+XG4gICAgICAgICAgICB7eyBzb3J0RGlyZWN0aW9uID09PSAnYXNjJyA/ICfihpEnIDogJ+KGkycgfX1cbiAgICAgICAgICA8L3NwYW4+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG5cbiAgICA8IS0tIEJvZHkgLS0+XG4gICAgPGRpdiBjbGFzcz1cImxpc3QtYm9keVwiPlxuICAgICAgPCEtLSBEYXRhIFJvd3MgLS0+XG4gICAgICA8ZGl2IFxuICAgICAgICBjbGFzcz1cImxpc3Qtcm93XCJcbiAgICAgICAgKm5nRm9yPVwibGV0IGl0ZW0gb2YgZGF0YSQgfCBhc3luYzsgdHJhY2tCeTogdHJhY2tCeUZuXCJcbiAgICAgICAgW2NsYXNzLnNlbGVjdGVkXT1cImlzU2VsZWN0ZWQoaXRlbSlcIlxuICAgICAgICAoY2xpY2spPVwib25JdGVtQ2xpY2soaXRlbSlcIj5cbiAgICAgICAgXG4gICAgICAgIDwhLS0gU2VsZWN0aW9uIGNoZWNrYm94IC0tPlxuICAgICAgICA8ZGl2IFxuICAgICAgICAgICpuZ0lmPVwic2VsZWN0YWJsZVwiIFxuICAgICAgICAgIGNsYXNzPVwibGlzdC1jZWxsIGNoZWNrYm94LWNlbGxcIlxuICAgICAgICAgIChjbGljayk9XCJvbkl0ZW1TZWxlY3QoaXRlbSk7ICRldmVudC5zdG9wUHJvcGFnYXRpb24oKVwiPlxuICAgICAgICAgIDxpbnB1dCBcbiAgICAgICAgICAgIHR5cGU9XCJjaGVja2JveFwiIFxuICAgICAgICAgICAgW2NoZWNrZWRdPVwiaXNTZWxlY3RlZChpdGVtKVwiXG4gICAgICAgICAgICAoY2hhbmdlKT1cIm9uSXRlbVNlbGVjdChpdGVtKVwiPlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICA8IS0tIERhdGEgY2VsbHMgLS0+XG4gICAgICAgIDxkaXZcbiAgICAgICAgICAqbmdGb3I9XCJsZXQgY29sdW1uIG9mIGNvbHVtbnNcIlxuICAgICAgICAgIGNsYXNzPVwibGlzdC1jZWxsXCJcbiAgICAgICAgICBbc3R5bGUud2lkdGhdPVwiY29sdW1uLndpZHRoXCI+XG4gICAgICAgICAge3sgZ2V0Q2VsbFZhbHVlKGl0ZW0sIGNvbHVtbikgfX1cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L2Rpdj5cblxuICAgICAgPCEtLSBFbXB0eSBTdGF0ZSAtLT5cbiAgICAgIDxkaXYgY2xhc3M9XCJsaXN0LWVtcHR5XCIgKm5nSWY9XCIoZGF0YSQgfCBhc3luYyk/Lmxlbmd0aCA9PT0gMFwiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwiZW1wdHktaWNvblwiPvCfk4s8L2Rpdj5cbiAgICAgICAgPGRpdiBjbGFzcz1cImVtcHR5LXRleHRcIj57eyBlbXB0eU1lc3NhZ2UgfX08L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuICA8L2Rpdj5cbjwvZGl2PiAiXX0=