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.
118 lines • 17 kB
JavaScript
import { Component, Input } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Observable, combineLatest, map } from 'rxjs';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
/**
* Screen Loading Component
*
* @description
* A screen-wide loading overlay component for blocking UI interactions during operations.
* Originally designed for backoffice applications to handle multiple loading states.
* Can combine multiple observables to show loading when any operation is in progress.
*
* @example
* ```html
* <!-- Single loading state -->
* <juvo-screen-loading
* [loading$]="dataLoading$"
* message="Loading data...">
* </juvo-screen-loading>
*
* <!-- Multiple loading states -->
* <juvo-screen-loading
* [loadingList$]="[saveLoading$, deleteLoading$, updateLoading$]"
* message="Processing operations..."
* [backdrop]="true">
* </juvo-screen-loading>
*
* <!-- Custom styled loading -->
* <juvo-screen-loading
* [loading$]="criticalOperation$"
* message="Critical operation in progress. Please do not refresh the page."
* color="#dc2626"
* size="large">
* </juvo-screen-loading>
* ```
*
* @selector juvo-screen-loading
* @since 2.1.0
* @author Juvo Rafa Team
*/
export class JuvoScreenLoadingComponent {
constructor() {
/** Array of loading observables to combine */
this.loadingList$ = [];
/** Loading message to display @default "Loading..." */
this.message = 'Loading...';
/** Size of the loading spinner @default "large" */
this.size = 'large';
/** Color of the spinner @default "#3b82f6" */
this.color = '#3b82f6';
/** Whether to show backdrop @default true */
this.backdrop = true;
/** Backdrop opacity @default 0.8 */
this.backdropOpacity = 0.8;
/** Whether to show the loading message @default true */
this.showMessage = true;
}
/**
* Gets the combined loading state from all sources
* @returns Observable<boolean> indicating if any loading is in progress
*/
get combinedLoading$() {
const observables = [];
if (this.loading$) {
observables.push(this.loading$);
}
if (this.loadingList$ && this.loadingList$.length > 0) {
observables.push(...this.loadingList$);
}
if (observables.length === 0) {
return new Observable(subscriber => subscriber.next(false));
}
if (observables.length === 1) {
return observables[0];
}
return combineLatest(observables).pipe(map(loadingStates => loadingStates.some(loading => loading)));
}
/**
* Gets the CSS class for the spinner size
* @returns CSS class name for the current size
*/
get sizeClass() {
return `spinner-${this.size}`;
}
/**
* Gets the backdrop style
* @returns CSS style object for backdrop
*/
get backdropStyle() {
return {
'background-color': `rgba(255, 255, 255, ${this.backdropOpacity})`
};
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: JuvoScreenLoadingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: JuvoScreenLoadingComponent, isStandalone: true, selector: "juvo-screen-loading", inputs: { loading$: "loading$", loadingList$: "loadingList$", message: "message", size: "size", color: "color", backdrop: "backdrop", backdropOpacity: "backdropOpacity", showMessage: "showMessage" }, ngImport: i0, template: "<div class=\"screen-loading-overlay\" \n *ngIf=\"combinedLoading$ | async\"\n [class.with-backdrop]=\"backdrop\"\n [ngStyle]=\"backdrop ? backdropStyle : null\">\n \n <div class=\"screen-loading-content\">\n <div class=\"spinner-container\">\n <div [class]=\"sizeClass\" \n class=\"loading-spinner\">\n <div class=\"spinner-circle\" \n [style.border-top-color]=\"color\"\n [style.border-right-color]=\"color\">\n </div>\n </div>\n </div>\n \n <div class=\"loading-message\" \n *ngIf=\"showMessage && message\">\n {{ message }}\n </div>\n </div>\n</div> ", styles: [".screen-loading-overlay{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;z-index:9999}.screen-loading-overlay.with-backdrop{background-color:#fffc;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.screen-loading-content{display:flex;flex-direction:column;align-items:center;gap:1.5rem;text-align:center;padding:2rem;border-radius:.5rem;background:#fffffff2;box-shadow:0 4px 12px #0000001a;min-width:200px}.spinner-container,.loading-spinner{display:flex;align-items:center;justify-content:center}.spinner-circle{border:4px solid #f3f4f6;border-top:4px solid #3b82f6;border-right:4px solid #3b82f6;border-radius:50%;animation:spin 1s linear infinite}.spinner-small .spinner-circle{width:2rem;height:2rem;border-width:3px}.spinner-medium .spinner-circle{width:3rem;height:3rem;border-width:4px}.spinner-large .spinner-circle{width:4rem;height:4rem;border-width:5px}.loading-message{color:#374151;font-size:1rem;font-weight:500;max-width:300px;line-height:1.5}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@media (max-width: 640px){.screen-loading-content{margin:1rem;padding:1.5rem;min-width:auto;max-width:calc(100vw - 2rem)}.loading-message{font-size:.875rem;max-width:250px}.spinner-large .spinner-circle{width:3rem;height:3rem;border-width:4px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: JuvoScreenLoadingComponent, decorators: [{
type: Component,
args: [{ selector: 'juvo-screen-loading', standalone: true, imports: [CommonModule], template: "<div class=\"screen-loading-overlay\" \n *ngIf=\"combinedLoading$ | async\"\n [class.with-backdrop]=\"backdrop\"\n [ngStyle]=\"backdrop ? backdropStyle : null\">\n \n <div class=\"screen-loading-content\">\n <div class=\"spinner-container\">\n <div [class]=\"sizeClass\" \n class=\"loading-spinner\">\n <div class=\"spinner-circle\" \n [style.border-top-color]=\"color\"\n [style.border-right-color]=\"color\">\n </div>\n </div>\n </div>\n \n <div class=\"loading-message\" \n *ngIf=\"showMessage && message\">\n {{ message }}\n </div>\n </div>\n</div> ", styles: [".screen-loading-overlay{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;z-index:9999}.screen-loading-overlay.with-backdrop{background-color:#fffc;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.screen-loading-content{display:flex;flex-direction:column;align-items:center;gap:1.5rem;text-align:center;padding:2rem;border-radius:.5rem;background:#fffffff2;box-shadow:0 4px 12px #0000001a;min-width:200px}.spinner-container,.loading-spinner{display:flex;align-items:center;justify-content:center}.spinner-circle{border:4px solid #f3f4f6;border-top:4px solid #3b82f6;border-right:4px solid #3b82f6;border-radius:50%;animation:spin 1s linear infinite}.spinner-small .spinner-circle{width:2rem;height:2rem;border-width:3px}.spinner-medium .spinner-circle{width:3rem;height:3rem;border-width:4px}.spinner-large .spinner-circle{width:4rem;height:4rem;border-width:5px}.loading-message{color:#374151;font-size:1rem;font-weight:500;max-width:300px;line-height:1.5}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@media (max-width: 640px){.screen-loading-content{margin:1rem;padding:1.5rem;min-width:auto;max-width:calc(100vw - 2rem)}.loading-message{font-size:.875rem;max-width:250px}.spinner-large .spinner-circle{width:3rem;height:3rem;border-width:4px}}\n"] }]
}], propDecorators: { loading$: [{
type: Input
}], loadingList$: [{
type: Input
}], message: [{
type: Input
}], size: [{
type: Input
}], color: [{
type: Input
}], backdrop: [{
type: Input
}], backdropOpacity: [{
type: Input
}], showMessage: [{
type: Input
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoianV2by1zY3JlZW4tbG9hZGluZy5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy91aS1jb21wb25lbnRzL3NyYy9saWIvanV2by1zY3JlZW4tbG9hZGluZy9qdXZvLXNjcmVlbi1sb2FkaW5nLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL3VpLWNvbXBvbmVudHMvc3JjL2xpYi9qdXZvLXNjcmVlbi1sb2FkaW5nL2p1dm8tc2NyZWVuLWxvYWRpbmcuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDakQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFBRSxVQUFVLEVBQUUsYUFBYSxFQUFFLEdBQUcsRUFBRSxNQUFNLE1BQU0sQ0FBQzs7O0FBRXREOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW1DRztBQVFILE1BQU0sT0FBTywwQkFBMEI7SUFQdkM7UUFXRSw4Q0FBOEM7UUFDckMsaUJBQVksR0FBMEIsRUFBRSxDQUFDO1FBRWxELHVEQUF1RDtRQUM5QyxZQUFPLEdBQVcsWUFBWSxDQUFDO1FBRXhDLG1EQUFtRDtRQUMxQyxTQUFJLEdBQWlDLE9BQU8sQ0FBQztRQUV0RCw4Q0FBOEM7UUFDckMsVUFBSyxHQUFXLFNBQVMsQ0FBQztRQUVuQyw2Q0FBNkM7UUFDcEMsYUFBUSxHQUFZLElBQUksQ0FBQztRQUVsQyxvQ0FBb0M7UUFDM0Isb0JBQWUsR0FBVyxHQUFHLENBQUM7UUFFdkMsd0RBQXdEO1FBQy9DLGdCQUFXLEdBQVksSUFBSSxDQUFDO0tBK0N0QztJQTdDQzs7O09BR0c7SUFDSCxJQUFJLGdCQUFnQjtRQUNsQixNQUFNLFdBQVcsR0FBMEIsRUFBRSxDQUFDO1FBRTlDLElBQUksSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ2xCLFdBQVcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ2xDLENBQUM7UUFFRCxJQUFJLElBQUksQ0FBQyxZQUFZLElBQUksSUFBSSxDQUFDLFlBQVksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDdEQsV0FBVyxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUN6QyxDQUFDO1FBRUQsSUFBSSxXQUFXLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQzdCLE9BQU8sSUFBSSxVQUFVLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7UUFDOUQsQ0FBQztRQUVELElBQUksV0FBVyxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUM3QixPQUFPLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN4QixDQUFDO1FBRUQsT0FBTyxhQUFhLENBQUMsV0FBVyxDQUFDLENBQUMsSUFBSSxDQUNwQyxHQUFHLENBQUMsYUFBYSxDQUFDLEVBQUUsQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FDN0QsQ0FBQztJQUNKLENBQUM7SUFFRDs7O09BR0c7SUFDSCxJQUFJLFNBQVM7UUFDWCxPQUFPLFdBQVcsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ2hDLENBQUM7SUFFRDs7O09BR0c7SUFDSCxJQUFJLGFBQWE7UUFDZixPQUFPO1lBQ0wsa0JBQWtCLEVBQUUsdUJBQXVCLElBQUksQ0FBQyxlQUFlLEdBQUc7U0FDbkUsQ0FBQztJQUNKLENBQUM7K0dBckVVLDBCQUEwQjttR0FBMUIsMEJBQTBCLHVSQy9DdkMsZ3BCQXFCTyx3MUNEc0JLLFlBQVk7OzRGQUlYLDBCQUEwQjtrQkFQdEMsU0FBUzsrQkFDRSxxQkFBcUIsY0FDbkIsSUFBSSxXQUNQLENBQUMsWUFBWSxDQUFDOzhCQU1kLFFBQVE7c0JBQWhCLEtBQUs7Z0JBR0csWUFBWTtzQkFBcEIsS0FBSztnQkFHRyxPQUFPO3NCQUFmLEtBQUs7Z0JBR0csSUFBSTtzQkFBWixLQUFLO2dCQUdHLEtBQUs7c0JBQWIsS0FBSztnQkFHRyxRQUFRO3NCQUFoQixLQUFLO2dCQUdHLGVBQWU7c0JBQXZCLEtBQUs7Z0JBR0csV0FBVztzQkFBbkIsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgSW5wdXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBPYnNlcnZhYmxlLCBjb21iaW5lTGF0ZXN0LCBtYXAgfSBmcm9tICdyeGpzJztcblxuLyoqXG4gKiBTY3JlZW4gTG9hZGluZyBDb21wb25lbnRcbiAqIFxuICogQGRlc2NyaXB0aW9uXG4gKiBBIHNjcmVlbi13aWRlIGxvYWRpbmcgb3ZlcmxheSBjb21wb25lbnQgZm9yIGJsb2NraW5nIFVJIGludGVyYWN0aW9ucyBkdXJpbmcgb3BlcmF0aW9ucy5cbiAqIE9yaWdpbmFsbHkgZGVzaWduZWQgZm9yIGJhY2tvZmZpY2UgYXBwbGljYXRpb25zIHRvIGhhbmRsZSBtdWx0aXBsZSBsb2FkaW5nIHN0YXRlcy5cbiAqIENhbiBjb21iaW5lIG11bHRpcGxlIG9ic2VydmFibGVzIHRvIHNob3cgbG9hZGluZyB3aGVuIGFueSBvcGVyYXRpb24gaXMgaW4gcHJvZ3Jlc3MuXG4gKiBcbiAqIEBleGFtcGxlXG4gKiBgYGBodG1sXG4gKiA8IS0tIFNpbmdsZSBsb2FkaW5nIHN0YXRlIC0tPlxuICogPGp1dm8tc2NyZWVuLWxvYWRpbmdcbiAqICAgW2xvYWRpbmckXT1cImRhdGFMb2FkaW5nJFwiXG4gKiAgIG1lc3NhZ2U9XCJMb2FkaW5nIGRhdGEuLi5cIj5cbiAqIDwvanV2by1zY3JlZW4tbG9hZGluZz5cbiAqIFxuICogPCEtLSBNdWx0aXBsZSBsb2FkaW5nIHN0YXRlcyAtLT5cbiAqIDxqdXZvLXNjcmVlbi1sb2FkaW5nXG4gKiAgIFtsb2FkaW5nTGlzdCRdPVwiW3NhdmVMb2FkaW5nJCwgZGVsZXRlTG9hZGluZyQsIHVwZGF0ZUxvYWRpbmckXVwiXG4gKiAgIG1lc3NhZ2U9XCJQcm9jZXNzaW5nIG9wZXJhdGlvbnMuLi5cIlxuICogICBbYmFja2Ryb3BdPVwidHJ1ZVwiPlxuICogPC9qdXZvLXNjcmVlbi1sb2FkaW5nPlxuICogXG4gKiA8IS0tIEN1c3RvbSBzdHlsZWQgbG9hZGluZyAtLT5cbiAqIDxqdXZvLXNjcmVlbi1sb2FkaW5nXG4gKiAgIFtsb2FkaW5nJF09XCJjcml0aWNhbE9wZXJhdGlvbiRcIlxuICogICBtZXNzYWdlPVwiQ3JpdGljYWwgb3BlcmF0aW9uIGluIHByb2dyZXNzLiBQbGVhc2UgZG8gbm90IHJlZnJlc2ggdGhlIHBhZ2UuXCJcbiAqICAgY29sb3I9XCIjZGMyNjI2XCJcbiAqICAgc2l6ZT1cImxhcmdlXCI+XG4gKiA8L2p1dm8tc2NyZWVuLWxvYWRpbmc+XG4gKiBgYGBcbiAqIFxuICogQHNlbGVjdG9yIGp1dm8tc2NyZWVuLWxvYWRpbmdcbiAqIEBzaW5jZSAyLjEuMFxuICogQGF1dGhvciBKdXZvIFJhZmEgVGVhbVxuICovXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdqdXZvLXNjcmVlbi1sb2FkaW5nJyxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW0NvbW1vbk1vZHVsZV0sXG4gIHRlbXBsYXRlVXJsOiAnLi9qdXZvLXNjcmVlbi1sb2FkaW5nLmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmw6ICcuL2p1dm8tc2NyZWVuLWxvYWRpbmcuY29tcG9uZW50LmNzcydcbn0pXG5leHBvcnQgY2xhc3MgSnV2b1NjcmVlbkxvYWRpbmdDb21wb25lbnQge1xuICAvKiogU2luZ2xlIGxvYWRpbmcgb2JzZXJ2YWJsZSAqL1xuICBASW5wdXQoKSBsb2FkaW5nJD86IE9ic2VydmFibGU8Ym9vbGVhbj47XG4gIFxuICAvKiogQXJyYXkgb2YgbG9hZGluZyBvYnNlcnZhYmxlcyB0byBjb21iaW5lICovXG4gIEBJbnB1dCgpIGxvYWRpbmdMaXN0JDogT2JzZXJ2YWJsZTxib29sZWFuPltdID0gW107XG4gIFxuICAvKiogTG9hZGluZyBtZXNzYWdlIHRvIGRpc3BsYXkgQGRlZmF1bHQgXCJMb2FkaW5nLi4uXCIgKi9cbiAgQElucHV0KCkgbWVzc2FnZTogc3RyaW5nID0gJ0xvYWRpbmcuLi4nO1xuICBcbiAgLyoqIFNpemUgb2YgdGhlIGxvYWRpbmcgc3Bpbm5lciBAZGVmYXVsdCBcImxhcmdlXCIgKi9cbiAgQElucHV0KCkgc2l6ZTogJ3NtYWxsJyB8ICdtZWRpdW0nIHwgJ2xhcmdlJyA9ICdsYXJnZSc7XG4gIFxuICAvKiogQ29sb3Igb2YgdGhlIHNwaW5uZXIgQGRlZmF1bHQgXCIjM2I4MmY2XCIgKi9cbiAgQElucHV0KCkgY29sb3I6IHN0cmluZyA9ICcjM2I4MmY2JztcbiAgXG4gIC8qKiBXaGV0aGVyIHRvIHNob3cgYmFja2Ryb3AgQGRlZmF1bHQgdHJ1ZSAqL1xuICBASW5wdXQoKSBiYWNrZHJvcDogYm9vbGVhbiA9IHRydWU7XG4gIFxuICAvKiogQmFja2Ryb3Agb3BhY2l0eSBAZGVmYXVsdCAwLjggKi9cbiAgQElucHV0KCkgYmFja2Ryb3BPcGFjaXR5OiBudW1iZXIgPSAwLjg7XG4gIFxuICAvKiogV2hldGhlciB0byBzaG93IHRoZSBsb2FkaW5nIG1lc3NhZ2UgQGRlZmF1bHQgdHJ1ZSAqL1xuICBASW5wdXQoKSBzaG93TWVzc2FnZTogYm9vbGVhbiA9IHRydWU7XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIGNvbWJpbmVkIGxvYWRpbmcgc3RhdGUgZnJvbSBhbGwgc291cmNlc1xuICAgKiBAcmV0dXJucyBPYnNlcnZhYmxlPGJvb2xlYW4+IGluZGljYXRpbmcgaWYgYW55IGxvYWRpbmcgaXMgaW4gcHJvZ3Jlc3NcbiAgICovXG4gIGdldCBjb21iaW5lZExvYWRpbmckKCk6IE9ic2VydmFibGU8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IG9ic2VydmFibGVzOiBPYnNlcnZhYmxlPGJvb2xlYW4+W10gPSBbXTtcbiAgICBcbiAgICBpZiAodGhpcy5sb2FkaW5nJCkge1xuICAgICAgb2JzZXJ2YWJsZXMucHVzaCh0aGlzLmxvYWRpbmckKTtcbiAgICB9XG4gICAgXG4gICAgaWYgKHRoaXMubG9hZGluZ0xpc3QkICYmIHRoaXMubG9hZGluZ0xpc3QkLmxlbmd0aCA+IDApIHtcbiAgICAgIG9ic2VydmFibGVzLnB1c2goLi4udGhpcy5sb2FkaW5nTGlzdCQpO1xuICAgIH1cbiAgICBcbiAgICBpZiAob2JzZXJ2YWJsZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gbmV3IE9ic2VydmFibGUoc3Vic2NyaWJlciA9PiBzdWJzY3JpYmVyLm5leHQoZmFsc2UpKTtcbiAgICB9XG4gICAgXG4gICAgaWYgKG9ic2VydmFibGVzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgcmV0dXJuIG9ic2VydmFibGVzWzBdO1xuICAgIH1cbiAgICBcbiAgICByZXR1cm4gY29tYmluZUxhdGVzdChvYnNlcnZhYmxlcykucGlwZShcbiAgICAgIG1hcChsb2FkaW5nU3RhdGVzID0+IGxvYWRpbmdTdGF0ZXMuc29tZShsb2FkaW5nID0+IGxvYWRpbmcpKVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogR2V0cyB0aGUgQ1NTIGNsYXNzIGZvciB0aGUgc3Bpbm5lciBzaXplXG4gICAqIEByZXR1cm5zIENTUyBjbGFzcyBuYW1lIGZvciB0aGUgY3VycmVudCBzaXplXG4gICAqL1xuICBnZXQgc2l6ZUNsYXNzKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIGBzcGlubmVyLSR7dGhpcy5zaXplfWA7XG4gIH1cblxuICAvKipcbiAgICogR2V0cyB0aGUgYmFja2Ryb3Agc3R5bGVcbiAgICogQHJldHVybnMgQ1NTIHN0eWxlIG9iamVjdCBmb3IgYmFja2Ryb3BcbiAgICovXG4gIGdldCBiYWNrZHJvcFN0eWxlKCk6IGFueSB7XG4gICAgcmV0dXJuIHtcbiAgICAgICdiYWNrZ3JvdW5kLWNvbG9yJzogYHJnYmEoMjU1LCAyNTUsIDI1NSwgJHt0aGlzLmJhY2tkcm9wT3BhY2l0eX0pYFxuICAgIH07XG4gIH1cbn0gIiwiPGRpdiBjbGFzcz1cInNjcmVlbi1sb2FkaW5nLW92ZXJsYXlcIiBcbiAgICAgKm5nSWY9XCJjb21iaW5lZExvYWRpbmckIHwgYXN5bmNcIlxuICAgICBbY2xhc3Mud2l0aC1iYWNrZHJvcF09XCJiYWNrZHJvcFwiXG4gICAgIFtuZ1N0eWxlXT1cImJhY2tkcm9wID8gYmFja2Ryb3BTdHlsZSA6IG51bGxcIj5cbiAgXG4gIDxkaXYgY2xhc3M9XCJzY3JlZW4tbG9hZGluZy1jb250ZW50XCI+XG4gICAgPGRpdiBjbGFzcz1cInNwaW5uZXItY29udGFpbmVyXCI+XG4gICAgICA8ZGl2IFtjbGFzc109XCJzaXplQ2xhc3NcIiBcbiAgICAgICAgICAgY2xhc3M9XCJsb2FkaW5nLXNwaW5uZXJcIj5cbiAgICAgICAgPGRpdiBjbGFzcz1cInNwaW5uZXItY2lyY2xlXCIgXG4gICAgICAgICAgICAgW3N0eWxlLmJvcmRlci10b3AtY29sb3JdPVwiY29sb3JcIlxuICAgICAgICAgICAgIFtzdHlsZS5ib3JkZXItcmlnaHQtY29sb3JdPVwiY29sb3JcIj5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgICBcbiAgICA8ZGl2IGNsYXNzPVwibG9hZGluZy1tZXNzYWdlXCIgXG4gICAgICAgICAqbmdJZj1cInNob3dNZXNzYWdlICYmIG1lc3NhZ2VcIj5cbiAgICAgIHt7IG1lc3NhZ2UgfX1cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG48L2Rpdj4gIl19