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
JavaScript
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=