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.

282 lines 38.9 kB
import { Component, Input, Output, EventEmitter, forwardRef } from '@angular/core'; import { CommonModule } from '@angular/common'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import * as i0 from "@angular/core"; import * as i1 from "@angular/common"; /** * Image Picker Component * * @description * A drag-and-drop image picker component for file uploads. * Supports multiple file selection, preview, and validation. * Originally designed for backoffice applications with image management needs. * * @example * ```html * <!-- Basic image picker --> * <juvo-image-picker * [multiple]="false" * [maxSize]="5242880" * (filesSelected)="onFilesSelected($event)" * (fileRemoved)="onFileRemoved($event)"> * </juvo-image-picker> * * <!-- Multiple images with preview --> * <juvo-image-picker * [multiple]="true" * [maxFiles]="5" * [showPreview]="true" * acceptedTypes="image/*" * [(ngModel)]="selectedFiles"> * </juvo-image-picker> * ``` * * @selector juvo-image-picker * @since 2.1.0 * @author Juvo Rafa Team */ export class JuvoImagePickerComponent { constructor() { /** Whether multiple files can be selected @default false */ this.multiple = false; /** Maximum file size in bytes @default 5MB */ this.maxSize = 5 * 1024 * 1024; /** Maximum number of files (for multiple mode) @default 10 */ this.maxFiles = 10; /** Accepted file types @default "image/*" */ this.acceptedTypes = 'image/*'; /** Whether to show file preview @default true */ this.showPreview = true; /** Whether component is disabled @default false */ this.disabled = false; /** Placeholder text */ this.placeholder = 'Drop images here or click to browse'; /** Upload button text */ this.buttonText = 'Choose Files'; /** Whether to show file details @default true */ this.showFileDetails = true; /** Emitted when files are selected */ this.filesSelected = new EventEmitter(); /** Emitted when a file is removed */ this.fileRemoved = new EventEmitter(); /** Emitted when validation errors occur */ this.validationError = new EventEmitter(); this.files = []; this.isDragOver = false; this._onChange = (value) => { }; this._onTouched = () => { }; } /** * Gets CSS classes for the drop zone * @returns Combined CSS classes */ get dropZoneClasses() { let classes = 'drop-zone'; if (this.isDragOver) classes += ' drag-over'; if (this.disabled) classes += ' disabled'; if (this.files.length > 0) classes += ' has-files'; return classes; } /** * Handles drag over event */ onDragOver(event) { if (this.disabled) return; event.preventDefault(); event.stopPropagation(); this.isDragOver = true; } /** * Handles drag leave event */ onDragLeave(event) { if (this.disabled) return; event.preventDefault(); event.stopPropagation(); this.isDragOver = false; } /** * Handles file drop event */ onDrop(event) { if (this.disabled) return; event.preventDefault(); event.stopPropagation(); this.isDragOver = false; const files = Array.from(event.dataTransfer?.files || []); this.handleFiles(files); } /** * Handles file input change */ onFileInputChange(event) { const input = event.target; const files = Array.from(input.files || []); this.handleFiles(files); // Reset input value input.value = ''; } /** * Processes selected files */ handleFiles(selectedFiles) { const validFiles = []; for (const file of selectedFiles) { // Validate file type if (!this.isValidFileType(file)) { this.validationError.emit(`Invalid file type: ${file.name}`); continue; } // Validate file size if (file.size > this.maxSize) { this.validationError.emit(`File too large: ${file.name}`); continue; } const uploadedFile = { name: file.name, size: file.size, type: file.type, file: file, url: URL.createObjectURL(file) }; validFiles.push(uploadedFile); } if (this.multiple) { // Check max files limit const totalFiles = this.files.length + validFiles.length; if (totalFiles > this.maxFiles) { this.validationError.emit(`Maximum ${this.maxFiles} files allowed`); return; } this.files = [...this.files, ...validFiles]; } else { // Single file mode - replace existing if (this.files.length > 0) { this.files.forEach(file => { if (file.url) URL.revokeObjectURL(file.url); }); } this.files = validFiles.slice(0, 1); } this.updateValue(); this.filesSelected.emit(this.files); } /** * Validates file type */ isValidFileType(file) { if (this.acceptedTypes === '*') return true; const types = this.acceptedTypes.split(',').map(t => t.trim()); return types.some(type => { if (type.endsWith('/*')) { return file.type.startsWith(type.slice(0, -1)); } return file.type === type; }); } /** * Removes a file */ removeFile(file) { if (this.disabled) return; const index = this.files.findIndex(f => f === file); if (index > -1) { if (file.url) URL.revokeObjectURL(file.url); this.files.splice(index, 1); this.updateValue(); this.fileRemoved.emit(file); } } /** * Formats file size for display */ formatFileSize(size) { if (size === 0) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(size) / Math.log(k)); return parseFloat((size / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i]; } /** * Updates form control value */ updateValue() { this._onChange(this.files); this._onTouched(); } // ControlValueAccessor implementation writeValue(value) { this.files = value || []; } registerOnChange(fn) { this._onChange = fn; } registerOnTouched(fn) { this._onTouched = fn; } setDisabledState(isDisabled) { this.disabled = isDisabled; } ngOnDestroy() { // Clean up object URLs this.files.forEach(file => { if (file.url) URL.revokeObjectURL(file.url); }); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: JuvoImagePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: JuvoImagePickerComponent, isStandalone: true, selector: "juvo-image-picker", inputs: { multiple: "multiple", maxSize: "maxSize", maxFiles: "maxFiles", acceptedTypes: "acceptedTypes", showPreview: "showPreview", disabled: "disabled", placeholder: "placeholder", buttonText: "buttonText", showFileDetails: "showFileDetails" }, outputs: { filesSelected: "filesSelected", fileRemoved: "fileRemoved", validationError: "validationError" }, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => JuvoImagePickerComponent), multi: true } ], ngImport: i0, template: "<div class=\"image-picker-container\">\n <!-- Drop Zone -->\n <div \n [class]=\"dropZoneClasses\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n (click)=\"fileInput.click()\">\n \n <div class=\"drop-zone-content\">\n <div class=\"drop-zone-icon\">\uD83D\uDCC1</div>\n <div class=\"drop-zone-text\">{{ placeholder }}</div>\n <button type=\"button\" class=\"upload-button\" [disabled]=\"disabled\">\n {{ buttonText }}\n </button>\n </div>\n\n <!-- Hidden file input -->\n <input\n #fileInput\n type=\"file\"\n [accept]=\"acceptedTypes\"\n [multiple]=\"multiple\"\n [disabled]=\"disabled\"\n (change)=\"onFileInputChange($event)\"\n style=\"display: none;\">\n </div>\n\n <!-- File Preview -->\n <div class=\"file-list\" *ngIf=\"files.length > 0\">\n <div class=\"file-item\" *ngFor=\"let file of files\">\n <!-- Image Preview -->\n <div class=\"file-preview\" *ngIf=\"showPreview && file.url\">\n <img [src]=\"file.url\" [alt]=\"file.name\" />\n </div>\n\n <!-- File Details -->\n <div class=\"file-details\" *ngIf=\"showFileDetails\">\n <div class=\"file-name\">{{ file.name }}</div>\n <div class=\"file-info\">\n <span class=\"file-size\">{{ formatFileSize(file.size) }}</span>\n <span class=\"file-type\">{{ file.type }}</span>\n </div>\n </div>\n\n <!-- Remove Button -->\n <button \n type=\"button\" \n class=\"remove-button\"\n [disabled]=\"disabled\"\n (click)=\"removeFile(file)\"\n aria-label=\"Remove file\">\n \u2715\n </button>\n </div>\n </div>\n</div> ", styles: [".image-picker-container{width:100%}.drop-zone{border:2px dashed #d1d5db;border-radius:.5rem;padding:2rem;text-align:center;cursor:pointer;transition:all .15s;background:#fafafa}.drop-zone:hover:not(.disabled){border-color:#3b82f6;background:#f8fafc}.drop-zone.drag-over{border-color:#3b82f6;background:#eff6ff}.drop-zone.disabled{opacity:.6;cursor:not-allowed;background:#f3f4f6}.drop-zone.has-files{border-style:solid;border-color:#10b981;background:#f0fdf4}.drop-zone-content{display:flex;flex-direction:column;align-items:center;gap:1rem}.drop-zone-icon{font-size:3rem;opacity:.6}.drop-zone-text{color:#6b7280;font-size:.875rem}.upload-button{background:#3b82f6;color:#fff;border:none;padding:.5rem 1rem;border-radius:.375rem;font-size:.875rem;font-weight:500;cursor:pointer;transition:all .15s}.upload-button:hover:not(:disabled){background:#2563eb}.upload-button:disabled{opacity:.6;cursor:not-allowed}.file-list{margin-top:1rem;display:flex;flex-direction:column;gap:.75rem}.file-item{display:flex;align-items:center;gap:1rem;padding:1rem;background:#fff;border:1px solid #e5e7eb;border-radius:.5rem;transition:all .15s}.file-item:hover{border-color:#d1d5db;box-shadow:0 1px 3px #0000001a}.file-preview{flex-shrink:0;width:4rem;height:4rem;border-radius:.375rem;overflow:hidden;background:#f3f4f6;display:flex;align-items:center;justify-content:center}.file-preview img{width:100%;height:100%;object-fit:cover}.file-details{flex:1;min-width:0}.file-name{font-weight:500;color:#374151;font-size:.875rem;margin-bottom:.25rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-info{display:flex;gap:1rem;font-size:.75rem;color:#6b7280}.file-size,.file-type{flex-shrink:0}.remove-button{background:none;border:none;color:#9ca3af;cursor:pointer;padding:.5rem;border-radius:.25rem;transition:all .15s;font-size:1rem;flex-shrink:0}.remove-button:hover:not(:disabled){background:#fee2e2;color:#ef4444}.remove-button:disabled{opacity:.5;cursor:not-allowed}@media (max-width: 640px){.drop-zone{padding:1.5rem 1rem}.drop-zone-icon{font-size:2rem}.file-item{padding:.75rem}.file-preview{width:3rem;height:3rem}.file-info{flex-direction:column;gap:.25rem}}\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"] }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: JuvoImagePickerComponent, decorators: [{ type: Component, args: [{ selector: 'juvo-image-picker', standalone: true, imports: [CommonModule], providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => JuvoImagePickerComponent), multi: true } ], template: "<div class=\"image-picker-container\">\n <!-- Drop Zone -->\n <div \n [class]=\"dropZoneClasses\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n (click)=\"fileInput.click()\">\n \n <div class=\"drop-zone-content\">\n <div class=\"drop-zone-icon\">\uD83D\uDCC1</div>\n <div class=\"drop-zone-text\">{{ placeholder }}</div>\n <button type=\"button\" class=\"upload-button\" [disabled]=\"disabled\">\n {{ buttonText }}\n </button>\n </div>\n\n <!-- Hidden file input -->\n <input\n #fileInput\n type=\"file\"\n [accept]=\"acceptedTypes\"\n [multiple]=\"multiple\"\n [disabled]=\"disabled\"\n (change)=\"onFileInputChange($event)\"\n style=\"display: none;\">\n </div>\n\n <!-- File Preview -->\n <div class=\"file-list\" *ngIf=\"files.length > 0\">\n <div class=\"file-item\" *ngFor=\"let file of files\">\n <!-- Image Preview -->\n <div class=\"file-preview\" *ngIf=\"showPreview && file.url\">\n <img [src]=\"file.url\" [alt]=\"file.name\" />\n </div>\n\n <!-- File Details -->\n <div class=\"file-details\" *ngIf=\"showFileDetails\">\n <div class=\"file-name\">{{ file.name }}</div>\n <div class=\"file-info\">\n <span class=\"file-size\">{{ formatFileSize(file.size) }}</span>\n <span class=\"file-type\">{{ file.type }}</span>\n </div>\n </div>\n\n <!-- Remove Button -->\n <button \n type=\"button\" \n class=\"remove-button\"\n [disabled]=\"disabled\"\n (click)=\"removeFile(file)\"\n aria-label=\"Remove file\">\n \u2715\n </button>\n </div>\n </div>\n</div> ", styles: [".image-picker-container{width:100%}.drop-zone{border:2px dashed #d1d5db;border-radius:.5rem;padding:2rem;text-align:center;cursor:pointer;transition:all .15s;background:#fafafa}.drop-zone:hover:not(.disabled){border-color:#3b82f6;background:#f8fafc}.drop-zone.drag-over{border-color:#3b82f6;background:#eff6ff}.drop-zone.disabled{opacity:.6;cursor:not-allowed;background:#f3f4f6}.drop-zone.has-files{border-style:solid;border-color:#10b981;background:#f0fdf4}.drop-zone-content{display:flex;flex-direction:column;align-items:center;gap:1rem}.drop-zone-icon{font-size:3rem;opacity:.6}.drop-zone-text{color:#6b7280;font-size:.875rem}.upload-button{background:#3b82f6;color:#fff;border:none;padding:.5rem 1rem;border-radius:.375rem;font-size:.875rem;font-weight:500;cursor:pointer;transition:all .15s}.upload-button:hover:not(:disabled){background:#2563eb}.upload-button:disabled{opacity:.6;cursor:not-allowed}.file-list{margin-top:1rem;display:flex;flex-direction:column;gap:.75rem}.file-item{display:flex;align-items:center;gap:1rem;padding:1rem;background:#fff;border:1px solid #e5e7eb;border-radius:.5rem;transition:all .15s}.file-item:hover{border-color:#d1d5db;box-shadow:0 1px 3px #0000001a}.file-preview{flex-shrink:0;width:4rem;height:4rem;border-radius:.375rem;overflow:hidden;background:#f3f4f6;display:flex;align-items:center;justify-content:center}.file-preview img{width:100%;height:100%;object-fit:cover}.file-details{flex:1;min-width:0}.file-name{font-weight:500;color:#374151;font-size:.875rem;margin-bottom:.25rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-info{display:flex;gap:1rem;font-size:.75rem;color:#6b7280}.file-size,.file-type{flex-shrink:0}.remove-button{background:none;border:none;color:#9ca3af;cursor:pointer;padding:.5rem;border-radius:.25rem;transition:all .15s;font-size:1rem;flex-shrink:0}.remove-button:hover:not(:disabled){background:#fee2e2;color:#ef4444}.remove-button:disabled{opacity:.5;cursor:not-allowed}@media (max-width: 640px){.drop-zone{padding:1.5rem 1rem}.drop-zone-icon{font-size:2rem}.file-item{padding:.75rem}.file-preview{width:3rem;height:3rem}.file-info{flex-direction:column;gap:.25rem}}\n"] }] }], propDecorators: { multiple: [{ type: Input }], maxSize: [{ type: Input }], maxFiles: [{ type: Input }], acceptedTypes: [{ type: Input }], showPreview: [{ type: Input }], disabled: [{ type: Input }], placeholder: [{ type: Input }], buttonText: [{ type: Input }], showFileDetails: [{ type: Input }], filesSelected: [{ type: Output }], fileRemoved: [{ type: Output }], validationError: [{ type: Output }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoianV2by1pbWFnZS1waWNrZXIuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvdWktY29tcG9uZW50cy9zcmMvbGliL2p1dm8taW1hZ2UtcGlja2VyL2p1dm8taW1hZ2UtcGlja2VyLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL3VpLWNvbXBvbmVudHMvc3JjL2xpYi9qdXZvLWltYWdlLXBpY2tlci9qdXZvLWltYWdlLXBpY2tlci5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsWUFBWSxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNuRixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUF3QixpQkFBaUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDOzs7QUFlekU7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0ErQkc7QUFlSCxNQUFNLE9BQU8sd0JBQXdCO0lBZHJDO1FBZUUsNERBQTREO1FBQ25ELGFBQVEsR0FBWSxLQUFLLENBQUM7UUFFbkMsOENBQThDO1FBQ3JDLFlBQU8sR0FBVyxDQUFDLEdBQUcsSUFBSSxHQUFHLElBQUksQ0FBQztRQUUzQyw4REFBOEQ7UUFDckQsYUFBUSxHQUFXLEVBQUUsQ0FBQztRQUUvQiw2Q0FBNkM7UUFDcEMsa0JBQWEsR0FBVyxTQUFTLENBQUM7UUFFM0MsaURBQWlEO1FBQ3hDLGdCQUFXLEdBQVksSUFBSSxDQUFDO1FBRXJDLG1EQUFtRDtRQUMxQyxhQUFRLEdBQVksS0FBSyxDQUFDO1FBRW5DLHVCQUF1QjtRQUNkLGdCQUFXLEdBQVcscUNBQXFDLENBQUM7UUFFckUseUJBQXlCO1FBQ2hCLGVBQVUsR0FBVyxjQUFjLENBQUM7UUFFN0MsaURBQWlEO1FBQ3hDLG9CQUFl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QUFLO2dCQUdHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBR0csV0FBVztzQkFBbkIsS0FBSztnQkFHRyxVQUFVO3NCQUFsQixLQUFLO2dCQUdHLGVBQWU7c0JBQXZCLEtBQUs7Z0JBR0ksYUFBYTtzQkFBdEIsTUFBTTtnQkFHRyxXQUFXO3NCQUFwQixNQUFNO2dCQUdHLGVBQWU7c0JBQXhCLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIElucHV0LCBPdXRwdXQsIEV2ZW50RW1pdHRlciwgZm9yd2FyZFJlZiB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7IENvbnRyb2xWYWx1ZUFjY2Vzc29yLCBOR19WQUxVRV9BQ0NFU1NPUiB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcblxuLyoqXG4gKiBGaWxlIHVwbG9hZCBpbnRlcmZhY2VcbiAqIEBpbnRlcmZhY2UgVXBsb2FkZWRGaWxlXG4gKiBAc2luY2UgMi4xLjBcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBVcGxvYWRlZEZpbGUge1xuICBuYW1lOiBzdHJpbmc7XG4gIHNpemU6IG51bWJlcjtcbiAgdHlwZTogc3RyaW5nO1xuICB1cmw/OiBzdHJpbmc7XG4gIGZpbGU/OiBGaWxlO1xufVxuXG4vKipcbiAqIEltYWdlIFBpY2tlciBDb21wb25lbnRcbiAqIFxuICogQGRlc2NyaXB0aW9uXG4gKiBBIGRyYWctYW5kLWRyb3AgaW1hZ2UgcGlja2VyIGNvbXBvbmVudCBmb3IgZmlsZSB1cGxvYWRzLlxuICogU3VwcG9ydHMgbXVsdGlwbGUgZmlsZSBzZWxlY3Rpb24sIHByZXZpZXcsIGFuZCB2YWxpZGF0aW9uLlxuICogT3JpZ2luYWxseSBkZXNpZ25lZCBmb3IgYmFja29mZmljZSBhcHBsaWNhdGlvbnMgd2l0aCBpbWFnZSBtYW5hZ2VtZW50IG5lZWRzLlxuICogXG4gKiBAZXhhbXBsZVxuICogYGBgaHRtbFxuICogPCEtLSBCYXNpYyBpbWFnZSBwaWNrZXIgLS0+XG4gKiA8anV2by1pbWFnZS1waWNrZXJcbiAqICAgW211bHRpcGxlXT1cImZhbHNlXCJcbiAqICAgW21heFNpemVdPVwiNTI0Mjg4MFwiXG4gKiAgIChmaWxlc1NlbGVjdGVkKT1cIm9uRmlsZXNTZWxlY3RlZCgkZXZlbnQpXCJcbiAqICAgKGZpbGVSZW1vdmVkKT1cIm9uRmlsZVJlbW92ZWQoJGV2ZW50KVwiPlxuICogPC9qdXZvLWltYWdlLXBpY2tlcj5cbiAqIFxuICogPCEtLSBNdWx0aXBsZSBpbWFnZXMgd2l0aCBwcmV2aWV3IC0tPlxuICogPGp1dm8taW1hZ2UtcGlja2VyXG4gKiAgIFttdWx0aXBsZV09XCJ0cnVlXCJcbiAqICAgW21heEZpbGVzXT1cIjVcIlxuICogICBbc2hvd1ByZXZpZXddPVwidHJ1ZVwiXG4gKiAgIGFjY2VwdGVkVHlwZXM9XCJpbWFnZS8qXCJcbiAqICAgWyhuZ01vZGVsKV09XCJzZWxlY3RlZEZpbGVzXCI+XG4gKiA8L2p1dm8taW1hZ2UtcGlja2VyPlxuICogYGBgXG4gKiBcbiAqIEBzZWxlY3RvciBqdXZvLWltYWdlLXBpY2tlclxuICogQHNpbmNlIDIuMS4wXG4gKiBAYXV0aG9yIEp1dm8gUmFmYSBUZWFtXG4gKi9cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2p1dm8taW1hZ2UtcGlja2VyJyxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW0NvbW1vbk1vZHVsZV0sXG4gIHRlbXBsYXRlVXJsOiAnLi9qdXZvLWltYWdlLXBpY2tlci5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsOiAnLi9qdXZvLWltYWdlLXBpY2tlci5jb21wb25lbnQuY3NzJyxcbiAgcHJvdmlkZXJzOiBbXG4gICAge1xuICAgICAgcHJvdmlkZTogTkdfVkFMVUVfQUNDRVNTT1IsXG4gICAgICB1c2VFeGlzdGluZzogZm9yd2FyZFJlZigoKSA9PiBKdXZvSW1hZ2VQaWNrZXJDb21wb25lbnQpLFxuICAgICAgbXVsdGk6IHRydWVcbiAgICB9XG4gIF1cbn0pXG5leHBvcnQgY2xhc3MgSnV2b0ltYWdlUGlja2VyQ29tcG9uZW50IGltcGxlbWVudHMgQ29udHJvbFZhbHVlQWNjZXNzb3Ige1xuICAvKiogV2hldGhlciBtdWx0aXBsZSBmaWxlcyBjYW4gYmUgc2VsZWN0ZWQgQGRlZmF1bHQgZmFsc2UgKi9cbiAgQElucHV0KCkgbXVsdGlwbGU6IGJvb2xlYW4gPSBmYWxzZTtcbiAgXG4gIC8qKiBNYXhpbXVtIGZpbGUgc2l6ZSBpbiBieXRlcyBAZGVmYXVsdCA1TUIgKi9cbiAgQElucHV0KCkgbWF4U2l6ZTogbnVtYmVyID0gNSAqIDEwMjQgKiAxMDI0O1xuICBcbiAgLyoqIE1heGltdW0gbnVtYmVyIG9mIGZpbGVzIChmb3IgbXVsdGlwbGUgbW9kZSkgQGRlZmF1bHQgMTAgKi9cbiAgQElucHV0KCkgbWF4RmlsZXM6IG51bWJlciA9IDEwO1xuICBcbiAgLyoqIEFjY2VwdGVkIGZpbGUgdHlwZXMgQGRlZmF1bHQgXCJpbWFnZS8qXCIgKi9cbiAgQElucHV0KCkgYWNjZXB0ZWRUeXBlczogc3RyaW5nID0gJ2ltYWdlLyonO1xuICBcbiAgLyoqIFdoZXRoZXIgdG8gc2hvdyBmaWxlIHByZXZpZXcgQGRlZmF1bHQgdHJ1ZSAqL1xuICBASW5wdXQoKSBzaG93UHJldmlldzogYm9vbGVhbiA9IHRydWU7XG4gIFxuICAvKiogV2hldGhlciBjb21wb25lbnQgaXMgZGlzYWJsZWQgQGRlZmF1bHQgZmFsc2UgKi9cbiAgQElucHV0KCkgZGlzYWJsZWQ6IGJvb2xlYW4gPSBmYWxzZTtcbiAgXG4gIC8qKiBQbGFjZWhvbGRlciB0ZXh0ICovXG4gIEBJbnB1dCgpIHBsYWNlaG9sZGVyOiBzdHJpbmcgPSAnRHJvcCBpbWFnZXMgaGVyZSBvciBjbGljayB0byBicm93c2UnO1xuICBcbiAgLyoqIFVwbG9hZCBidXR0b24gdGV4dCAqL1xuICBASW5wdXQoKSBidXR0b25UZXh0OiBzdHJpbmcgPSAnQ2hvb3NlIEZpbGVzJztcbiAgXG4gIC8qKiBXaGV0aGVyIHRvIHNob3cgZmlsZSBkZXRhaWxzIEBkZWZhdWx0IHRydWUgKi9cbiAgQElucHV0KCkgc2hvd0ZpbGVEZXRhaWxzOiBib29sZWFuID0gdHJ1ZTtcbiAgXG4gIC8qKiBFbWl0dGVkIHdoZW4gZmlsZXMgYXJlIHNlbGVjdGVkICovXG4gIEBPdXRwdXQoKSBmaWxlc1NlbGVjdGVkID0gbmV3IEV2ZW50RW1pdHRlcjxVcGxvYWRlZEZpbGVbXT4oKTtcbiAgXG4gIC8qKiBFbWl0dGVkIHdoZW4gYSBmaWxlIGlzIHJlbW92ZWQgKi9cbiAgQE91dHB1dCgpIGZpbGVSZW1vdmVkID0gbmV3IEV2ZW50RW1pdHRlcjxVcGxvYWRlZEZpbGU+KCk7XG4gIFxuICAvKiogRW1pdHRlZCB3aGVuIHZhbGlkYXRpb24gZXJyb3JzIG9jY3VyICovXG4gIEBPdXRwdXQoKSB2YWxpZGF0aW9uRXJyb3IgPSBuZXcgRXZlbnRFbWl0dGVyPHN0cmluZz4oKTtcblxuICBmaWxlczogVXBsb2FkZWRGaWxlW10gPSBbXTtcbiAgaXNEcmFnT3ZlciA9IGZhbHNlO1xuXG4gIHByaXZhdGUgX29uQ2hhbmdlID0gKHZhbHVlOiBVcGxvYWRlZEZpbGVbXSkgPT4ge307XG4gIHByaXZhdGUgX29uVG91Y2hlZCA9ICgpID0+IHt9O1xuXG4gIC8qKlxuICAgKiBHZXRzIENTUyBjbGFzc2VzIGZvciB0aGUgZHJvcCB6b25lXG4gICAqIEByZXR1cm5zIENvbWJpbmVkIENTUyBjbGFzc2VzXG4gICAqL1xuICBnZXQgZHJvcFpvbmVDbGFzc2VzKCk6IHN0cmluZyB7XG4gICAgbGV0IGNsYXNzZXMgPSAnZHJvcC16b25lJztcbiAgICBpZiAodGhpcy5pc0RyYWdPdmVyKSBjbGFzc2VzICs9ICcgZHJhZy1vdmVyJztcbiAgICBpZiAodGhpcy5kaXNhYmxlZCkgY2xhc3NlcyArPSAnIGRpc2FibGVkJztcbiAgICBpZiAodGhpcy5maWxlcy5sZW5ndGggPiAwKSBjbGFzc2VzICs9ICcgaGFzLWZpbGVzJztcbiAgICByZXR1cm4gY2xhc3NlcztcbiAgfVxuXG4gIC8qKlxuICAgKiBIYW5kbGVzIGRyYWcgb3ZlciBldmVudFxuICAgKi9cbiAgb25EcmFnT3ZlcihldmVudDogRHJhZ0V2ZW50KTogdm9pZCB7XG4gICAgaWYgKHRoaXMuZGlzYWJsZWQpIHJldHVybjtcbiAgICBcbiAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgIHRoaXMuaXNEcmFnT3ZlciA9IHRydWU7XG4gIH1cblxuICAvKipcbiAgICogSGFuZGxlcyBkcmFnIGxlYXZlIGV2ZW50XG4gICAqL1xuICBvbkRyYWdMZWF2ZShldmVudDogRHJhZ0V2ZW50KTogdm9pZCB7XG4gICAgaWYgKHRoaXMuZGlzYWJsZWQpIHJldHVybjtcbiAgICBcbiAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgIHRoaXMuaXNEcmFnT3ZlciA9IGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIEhhbmRsZXMgZmlsZSBkcm9wIGV2ZW50XG4gICAqL1xuICBvbkRyb3AoZXZlbnQ6IERyYWdFdmVudCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmRpc2FibGVkKSByZXR1cm47XG4gICAgXG4gICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICB0aGlzLmlzRHJhZ092ZXIgPSBmYWxzZTtcblxuICAgIGNvbnN0IGZpbGVzID0gQXJyYXkuZnJvbShldmVudC5kYXRhVHJhbnNmZXI/LmZpbGVzIHx8IFtdKTtcbiAgICB0aGlzLmhhbmRsZUZpbGVzKGZpbGVzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBIYW5kbGVzIGZpbGUgaW5wdXQgY2hhbmdlXG4gICAqL1xuICBvbkZpbGVJbnB1dENoYW5nZShldmVudDogRXZlbnQpOiB2b2lkIHtcbiAgICBjb25zdCBpbnB1dCA9IGV2ZW50LnRhcmdldCBhcyBIVE1MSW5wdXRFbGVtZW50O1xuICAgIGNvbnN0IGZpbGVzID0gQXJyYXkuZnJvbShpbnB1dC5maWxlcyB8fCBbXSk7XG4gICAgdGhpcy5oYW5kbGVGaWxlcyhmaWxlcyk7XG4gICAgXG4gICAgLy8gUmVzZXQgaW5wdXQgdmFsdWVcbiAgICBpbnB1dC52YWx1ZSA9ICcnO1xuICB9XG5cbiAgLyoqXG4gICAqIFByb2Nlc3NlcyBzZWxlY3RlZCBmaWxlc1xuICAgKi9cbiAgcHJpdmF0ZSBoYW5kbGVGaWxlcyhzZWxlY3RlZEZpbGVzOiBGaWxlW10pOiB2b2lkIHtcbiAgICBjb25zdCB2YWxpZEZpbGVzOiBVcGxvYWRlZEZpbGVbXSA9IFtdO1xuXG4gICAgZm9yIChjb25zdCBmaWxlIG9mIHNlbGVjdGVkRmlsZXMpIHtcbiAgICAgIC8vIFZhbGlkYXRlIGZpbGUgdHlwZVxuICAgICAgaWYgKCF0aGlzLmlzVmFsaWRGaWxlVHlwZShmaWxlKSkge1xuICAgICAgICB0aGlzLnZhbGlkYXRpb25FcnJvci5lbWl0KGBJbnZhbGlkIGZpbGUgdHlwZTogJHtmaWxlLm5hbWV9YCk7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICAvLyBWYWxpZGF0ZSBmaWxlIHNpemVcbiAgICAgIGlmIChmaWxlLnNpemUgPiB0aGlzLm1heFNpemUpIHtcbiAgICAgICAgdGhpcy52YWxpZGF0aW9uRXJyb3IuZW1pdChgRmlsZSB0b28gbGFyZ2U6ICR7ZmlsZS5uYW1lfWApO1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgdXBsb2FkZWRGaWxlOiBVcGxvYWRlZEZpbGUgPSB7XG4gICAgICAgIG5hbWU6IGZpbGUubmFtZSxcbiAgICAgICAgc2l6ZTogZmlsZS5zaXplLFxuICAgICAgICB0eXBlOiBmaWxlLnR5cGUsXG4gICAgICAgIGZpbGU6IGZpbGUsXG4gICAgICAgIHVybDogVVJMLmNyZWF0ZU9iamVjdFVSTChmaWxlKVxuICAgICAgfTtcblxuICAgICAgdmFsaWRGaWxlcy5wdXNoKHVwbG9hZGVkRmlsZSk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMubXVsdGlwbGUpIHtcbiAgICAgIC8vIENoZWNrIG1heCBmaWxlcyBsaW1pdFxuICAgICAgY29uc3QgdG90YWxGaWxlcyA9IHRoaXMuZmlsZXMubGVuZ3RoICsgdmFsaWRGaWxlcy5sZW5ndGg7XG4gICAgICBpZiAodG90YWxGaWxlcyA+IHRoaXMubWF4RmlsZXMpIHtcbiAgICAgICAgdGhpcy52YWxpZGF0aW9uRXJyb3IuZW1pdChgTWF4aW11bSAke3RoaXMubWF4RmlsZXN9IGZpbGVzIGFsbG93ZWRgKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgXG4gICAgICB0aGlzLmZpbGVzID0gWy4uLnRoaXMuZmlsZXMsIC4uLnZhbGlkRmlsZXNdO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBTaW5nbGUgZmlsZSBtb2RlIC0gcmVwbGFjZSBleGlzdGluZ1xuICAgICAgaWYgKHRoaXMuZmlsZXMubGVuZ3RoID4gMCkge1xuICAgICAgICB0aGlzLmZpbGVzLmZvckVhY2goZmlsZSA9PiB7XG4gICAgICAgICAgaWYgKGZpbGUudXJsKSBVUkwucmV2b2tlT2JqZWN0VVJMKGZpbGUudXJsKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICB0aGlzLmZpbGVzID0gdmFsaWRGaWxlcy5zbGljZSgwLCAxKTtcbiAgICB9XG5cbiAgICB0aGlzLnVwZGF0ZVZhbHVlKCk7XG4gICAgdGhpcy5maWxlc1NlbGVjdGVkLmVtaXQodGhpcy5maWxlcyk7XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGVzIGZpbGUgdHlwZVxuICAgKi9cbiAgcHJpdmF0ZSBpc1ZhbGlkRmlsZVR5cGUoZmlsZTogRmlsZSk6IGJvb2xlYW4ge1xuICAgIGlmICh0aGlzLmFjY2VwdGVkVHlwZXMgPT09ICcqJykgcmV0dXJuIHRydWU7XG4gICAgXG4gICAgY29uc3QgdHlwZXMgPSB0aGlzLmFjY2VwdGVkVHlwZXMuc3BsaXQoJywnKS5tYXAodCA9PiB0LnRyaW0oKSk7XG4gICAgcmV0dXJuIHR5cGVzLnNvbWUodHlwZSA9PiB7XG4gICAgICBpZiAodHlwZS5lbmRzV2l0aCgnLyonKSkge1xuICAgICAgICByZXR1cm4gZmlsZS50eXBlLnN0YXJ0c1dpdGgodHlwZS5zbGljZSgwLCAtMSkpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGZpbGUudHlwZSA9PT0gdHlwZTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmVzIGEgZmlsZVxuICAgKi9cbiAgcmVtb3ZlRmlsZShmaWxlOiBVcGxvYWRlZEZpbGUpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5kaXNhYmxlZCkgcmV0dXJuO1xuICAgIFxuICAgIGNvbnN0IGluZGV4ID0gdGhpcy5maWxlcy5maW5kSW5kZXgoZiA9PiBmID09PSBmaWxlKTtcbiAgICBpZiAoaW5kZXggPiAtMSkge1xuICAgICAgaWYgKGZpbGUudXJsKSBVUkwucmV2b2tlT2JqZWN0VVJMKGZpbGUudXJsKTtcbiAgICAgIHRoaXMuZmlsZXMuc3BsaWNlKGluZGV4LCAxKTtcbiAgICAgIHRoaXMudXBkYXRlVmFsdWUoKTtcbiAgICAgIHRoaXMuZmlsZVJlbW92ZWQuZW1pdChmaWxlKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRm9ybWF0cyBmaWxlIHNpemUgZm9yIGRpc3BsYXlcbiAgICovXG4gIGZvcm1hdEZpbGVTaXplKHNpemU6IG51bWJlcik6IHN0cmluZyB7XG4gICAgaWYgKHNpemUgPT09IDApIHJldHVybiAnMCBCJztcbiAgICBcbiAgICBjb25zdCBrID0gMTAyNDtcbiAgICBjb25zdCBzaXplcyA9IFsnQicsICdLQicsICdNQicsICdHQiddO1xuICAgIGNvbnN0IGkgPSBNYXRoLmZsb29yKE1hdGgubG9nKHNpemUpIC8gTWF0aC5sb2coaykpO1xuICAgIFxuICAgIHJldHVybiBwYXJzZUZsb2F0KChzaXplIC8gTWF0aC5wb3coaywgaSkpLnRvRml4ZWQoMSkpICsgJyAnICsgc2l6ZXNbaV07XG4gIH1cblxuICAvKipcbiAgICogVXBkYXRlcyBmb3JtIGNvbnRyb2wgdmFsdWVcbiAgICovXG4gIHByaXZhdGUgdXBkYXRlVmFsdWUoKTogdm9pZCB7XG4gICAgdGhpcy5fb25DaGFuZ2UodGhpcy5maWxlcyk7XG4gICAgdGhpcy5fb25Ub3VjaGVkKCk7XG4gIH1cblxuICAvLyBDb250cm9sVmFsdWVBY2Nlc3NvciBpbXBsZW1lbnRhdGlvblxuICB3cml0ZVZhbHVlKHZhbHVlOiBVcGxvYWRlZEZpbGVbXSk6IHZvaWQge1xuICAgIHRoaXMuZmlsZXMgPSB2YWx1ZSB8fCBbXTtcbiAgfVxuXG4gIHJlZ2lzdGVyT25DaGFuZ2UoZm46ICh2YWx1ZTogVXBsb2FkZWRGaWxlW10pID0+IHZvaWQpOiB2b2lkIHtcbiAgICB0aGlzLl9vbkNoYW5nZSA9IGZuO1xuICB9XG5cbiAgcmVnaXN0ZXJPblRvdWNoZWQoZm46ICgpID0+IHZvaWQpOiB2b2lkIHtcbiAgICB0aGlzLl9vblRvdWNoZWQgPSBmbjtcbiAgfVxuXG4gIHNldERpc2FibGVkU3RhdGUoaXNEaXNhYmxlZDogYm9vbGVhbik6IHZvaWQge1xuICAgIHRoaXMuZGlzYWJsZWQgPSBpc0Rpc2FibGVkO1xuICB9XG5cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgLy8gQ2xlYW4gdXAgb2JqZWN0IFVSTHNcbiAgICB0aGlzLmZpbGVzLmZvckVhY2goZmlsZSA9PiB7XG4gICAgICBpZiAoZmlsZS51cmwpIFVSTC5yZXZva2VPYmplY3RVUkwoZmlsZS51cmwpO1xuICAgIH0pO1xuICB9XG59ICIsIjxkaXYgY2xhc3M9XCJpbWFnZS1waWNrZXItY29udGFpbmVyXCI+XG4gIDwhLS0gRHJvcCBab25lIC0tPlxuICA8ZGl2IFxuICAgIFtjbGFzc109XCJkcm9wWm9uZUNsYXNzZXNcIlxuICAgIChkcmFnb3Zlcik9XCJvbkRyYWdPdmVyKCRldmVudClcIlxuICAgIChkcmFnbGVhdmUpPVwib25EcmFnTGVhdmUoJGV2ZW50KVwiXG4gICAgKGRyb3ApPVwib25Ecm9wKCRldmVudClcIlxuICAgIChjbGljayk9XCJmaWxlSW5wdXQuY2xpY2soKVwiPlxuICAgIFxuICAgIDxkaXYgY2xhc3M9XCJkcm9wLXpvbmUtY29udGVudFwiPlxuICAgICAgPGRpdiBjbGFzcz1cImRyb3Atem9uZS1pY29uXCI+8J+TgTwvZGl2PlxuICAgICAgPGRpdiBjbGFzcz1cImRyb3Atem9uZS10ZXh0XCI+e3sgcGxhY2Vob2xkZXIgfX08L2Rpdj5cbiAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwidXBsb2FkLWJ1dHRvblwiIFtkaXNhYmxlZF09XCJkaXNhYmxlZFwiPlxuICAgICAgICB7eyBidXR0b25UZXh0IH19XG4gICAgICA8L2J1dHRvbj5cbiAgICA8L2Rpdj5cblxuICAgIDwhLS0gSGlkZGVuIGZpbGUgaW5wdXQgLS0+XG4gICAgPGlucHV0XG4gICAgICAjZmlsZUlucHV0XG4gICAgICB0eXBlPVwiZmlsZVwiXG4gICAgICBbYWNjZXB0XT1cImFjY2VwdGVkVHlwZXNcIlxuICAgICAgW211bHRpcGxlXT1cIm11bHRpcGxlXCJcbiAgICAgIFtkaXNhYmxlZF09XCJkaXNhYmxlZFwiXG4gICAgICAoY2hhbmdlKT1cIm9uRmlsZUlucHV0Q2hhbmdlKCRldmVudClcIlxuICAgICAgc3R5bGU9XCJkaXNwbGF5OiBub25lO1wiPlxuICA8L2Rpdj5cblxuICA8IS0tIEZpbGUgUHJldmlldyAtLT5cbiAgPGRpdiBjbGFzcz1cImZpbGUtbGlzdFwiICpuZ0lmPVwiZmlsZXMubGVuZ3RoID4gMFwiPlxuICAgIDxkaXYgY2xhc3M9XCJmaWxlLWl0ZW1cIiAqbmdGb3I9XCJsZXQgZmlsZSBvZiBmaWxlc1wiPlxuICAgICAgPCEtLSBJbWFnZSBQcmV2aWV3IC0tPlxuICAgICAgPGRpdiBjbGFzcz1cImZpbGUtcHJldmlld1wiICpuZ0lmPVwic2hvd1ByZXZpZXcgJiYgZmlsZS51cmxcIj5cbiAgICAgICAgPGltZyBbc3JjXT1cImZpbGUudXJsXCIgW2FsdF09XCJmaWxlLm5hbWVcIiAvPlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDwhLS0gRmlsZSBEZXRhaWxzIC0tPlxuICAgICAgPGRpdiBjbGFzcz1cImZpbGUtZGV0YWlsc1wiICpuZ0lmPVwic2hvd0ZpbGVEZXRhaWxzXCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJmaWxlLW5hbWVcIj57eyBmaWxlLm5hbWUgfX08L2Rpdj5cbiAgICAgICAgPGRpdiBjbGFzcz1cImZpbGUtaW5mb1wiPlxuICAgICAgICAgIDxzcGFuIGNsYXNzPVwiZmlsZS1zaXplXCI+e3sgZm9ybWF0RmlsZVNpemUoZmlsZS5zaXplKSB9fTwvc3Bhbj5cbiAgICAgICAgICA8c3BhbiBjbGFzcz1cImZpbGUtdHlwZVwiPnt7IGZpbGUudHlwZSB9fTwvc3Bhbj5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L2Rpdj5cblxuICAgICAgPCEtLSBSZW1vdmUgQnV0dG9uIC0tPlxuICAgICAgPGJ1dHRvbiBcbiAgICAgICAgdHlwZT1cImJ1dHRvblwiIFxuICAgICAgICBjbGFzcz1cInJlbW92ZS1idXR0b25cIlxuICAgICAgICBbZGlzYWJsZWRdPVwiZGlzYWJsZWRcIlxuICAgICAgICAoY2xpY2spPVwicmVtb3ZlRmlsZShmaWxlKVwiXG4gICAgICAgIGFyaWEtbGFiZWw9XCJSZW1vdmUgZmlsZVwiPlxuICAgICAgICDinJVcbiAgICAgIDwvYnV0dG9uPlxuICAgIDwvZGl2PlxuICA8L2Rpdj5cbjwvZGl2PiAiXX0=