UNPKG

@dotglitch/ngx-common

Version:

Angular components and utilities that are commonly used.

143 lines 24.8 kB
import { Directive, Inject, InjectionToken, Input, Optional } from '@angular/core'; import { INDEXEDDB, createInstance } from 'localforage'; import * as i0 from "@angular/core"; const storage = createInstance({ name: "@dotglitch", storeName: "image-cache", driver: INDEXEDDB, version: 1 }); const imageCache = {}; const loadingSvg = `data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32px" height="32px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid"><circle cx="50" cy="50" fill="none" stroke="%2340c4ff" stroke-width="10" r="35" stroke-dasharray="164.93361431346415 56.97787143782138"><animateTransform attributeName="transform" type="rotate" repeatCount="indefinite" dur="1s" values="0 50 50;360 50 50" keyTimes="0;1"></animateTransform></circle><!-- [ldio] generated by https://loading.io/ --></svg>`; const brokenSvg = `data:image/svg+xml;utf8,<svg width="800" height="800" viewBox="0 0 24 24" version="1.1" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"><line x1="10.08" y1="8.29" x2="10.18" y2="8.29" style="fill:none;stroke:#000000;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round" /><path d="m 10.51,14.8 5.2,5.2 H 20 a 1,1 0 0 0 1,-1 V 15.73 L 15.29,10 Z M 3,16.71 V 19 a 1,1 0 0 0 1,1 h 11.71 l -8,-8 z M 21,5 v 14 a 1,1 0 0 1 -1,1 H 4 A 1,1 0 0 1 3,19 V 5 A 1,1 0 0 1 4,4 h 16 a 1,1 0 0 1 1,1 z" style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round" /><path d="M 21.193388,21.193388 2.8066108,2.8066108 m 18.3867772,0 L 2.8066108,21.193388" style="stroke:%23ff0000;stroke-width:2.62668;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" /></svg>`; export const NGX_IMAGE_CACHE_CONFIG = new InjectionToken('ngx-image-cache-config'); export class NgxImageCacheDirective { get el() { return this.element.nativeElement; } constructor(element, cacheConfig) { this.element = element; this.cacheConfig = cacheConfig; } ngOnChanges() { this.getCachedImage(); } async getCachedImage() { if (this.el.src?.trim() == this.url?.trim() || // Check that there's an actual change this.url?.trim().length == 0 // Check that there's an actual URL ) return; // Check if it's in the memory cache if (imageCache[this.url]) { const image = imageCache[this.url]; // If the image is currently loading, show the loader // and add it to the reflist if (image['_loading'] == true) { image['_refs'].push(this.el); this.el.setAttribute("loading", "true"); this.el.src = this.cacheConfig?.loadingPlaceholder || loadingSvg; } else { // The image is fully loaded, swap out the src with a data-uri this.el.setAttribute("loading", "false"); this.el.src = image.src; } // If it's already in the image cache, we're going to trust that it loads properly. return; } // Check if it's in indexedDB if (this.configuration?.cacheInIndexedDB != false) { const cached = await storage.getItem(this.url); if (cached) { // Attempt to load the base64 data from indexeddb. // If this fails, we'll fall back to attempting to download the image this.el.src = cached.data; const evt = await new Promise(res => { this.el.addEventListener('load', res); this.el.addEventListener('error', res); }); // If the event isn't an error if (evt.type == "load") { this.el.setAttribute("loading", "false"); if (this.configuration?.cacheInMemory != false) { // Successfully loaded into element // Create an entry in the memory cache const image = imageCache[this.url] = new Image(); image.src = cached.data; image['_createdAt'] = Date.now(); } return; } else { // Else, we try to load again. this.el.src = this.cacheConfig?.loadingPlaceholder || loadingSvg; } } } const image = (() => { if (this.configuration?.cacheInMemory != false) { return imageCache[this.url] = new Image(); } return new Image(); })(); // const clone = image.cloneNode(true) as HTMLImageElement; image['_refs'] = image['_refs'] ?? []; image['_refs'].push(this.el); image['_loading'] = true; image['_createdAt'] = Date.now(); // Show a loader while the image downloads. this.el.setAttribute("loading", "true"); this.el.src = this.cacheConfig?.loadingPlaceholder || loadingSvg; // Fetch the image via JS and cache it as base64 window.fetch(this.url) .then(response => response.blob()) .then(blob => new Promise((resolve, reject) => { const reader = new FileReader(); reader.onloadend = () => { image.src = reader.result; storage.setItem(this.url, { timestamp: Date.now(), data: reader.result }); image['_refs'].forEach((ref) => { ref.src = image.src; }); image['_loading'] = false; resolve(0); }; reader.onerror = reject; reader.readAsDataURL(blob); })) .catch(err => { // If a failure occurs, purge this entry from the cache // TODO: Render better "broken" image delete imageCache[this.url]; image['_refs'].forEach((ref) => { ref.src = this.cacheConfig?.brokenPlaceholder || brokenSvg; ref.setAttribute("loading", "failed"); }); }); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NgxImageCacheDirective, deps: [{ token: i0.ElementRef }, { token: NGX_IMAGE_CACHE_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: NgxImageCacheDirective, isStandalone: true, selector: "img[ngx-cache]", inputs: { url: ["source", "url"], configuration: ["ngx-cache-config", "configuration"] }, usesOnChanges: true, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NgxImageCacheDirective, decorators: [{ type: Directive, args: [{ selector: 'img[ngx-cache]', standalone: true }] }], ctorParameters: () => [{ type: i0.ElementRef }, { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [NGX_IMAGE_CACHE_CONFIG] }] }], propDecorators: { url: [{ type: Input, args: ["source"] }, { type: Input, args: ["ngx-cache"] }], configuration: [{ type: Input, args: ["ngx-cache-config"] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1hZ2UtY2FjaGUuZGlyZWN0aXZlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcGFja2FnZXMvY29tbW9uL2NvcmUvZGlyZWN0aXZlcy9pbWFnZS1jYWNoZS5kaXJlY3RpdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBYyxNQUFNLEVBQUUsY0FBYyxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDL0YsT0FBTyxFQUFFLFNBQVMsRUFBRSxjQUFjLEVBQUUsTUFBTSxhQUFhLENBQUM7O0FBRXhELE1BQU0sT0FBTyxHQUFHLGNBQWMsQ0FBQztJQUMzQixJQUFJLEVBQUUsWUFBWTtJQUNsQixTQUFTLEVBQUUsYUFBYTtJQUN4QixNQUFNLEVBQUUsU0FBUztJQUNqQixPQUFPLEVBQUUsQ0FBQztDQUNiLENBQUMsQ0FBQztBQUdILE1BQU0sVUFBVSxHQUVaLEVBQUUsQ0FBQztBQUVQLE1BQU0sVUFBVSxHQUFHLDZoQkFBNmhCLENBQUM7QUFDampCLE1BQU0sU0FBUyxHQUFHLHcwQkFBdzBCLENBQUM7QUFlMzFCLE1BQU0sQ0FBQyxNQUFNLHNCQUFzQixHQUFHLElBQUksY0FBYyxDQUFzQix3QkFBd0IsQ0FBQyxDQUFDO0FBMkJ4RyxNQUFNLE9BQU8sc0JBQXNCO0lBTy9CLElBQVksRUFBRSxLQUFLLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxhQUFpQyxDQUFBLENBQUMsQ0FBQztJQUUxRSxZQUNxQixPQUFtQixFQUN5QixXQUFnQztRQUQ1RSxZQUFPLEdBQVAsT0FBTyxDQUFZO1FBQ3lCLGdCQUFXLEdBQVgsV0FBVyxDQUFxQjtJQUM3RixDQUFDO0lBRUwsV0FBVztRQUNQLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztJQUMxQixDQUFDO0lBRUQsS0FBSyxDQUFDLGNBQWM7UUFDaEIsSUFDSSxJQUFJLENBQUMsRUFBRSxDQUFDLEdBQUcsRUFBRSxJQUFJ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Q25COzswQkFZUSxRQUFROzswQkFBSSxNQUFNOzJCQUFDLHNCQUFzQjt5Q0FSMUIsR0FBRztzQkFEdEIsS0FBSzt1QkFBQyxRQUFROztzQkFDZCxLQUFLO3VCQUFDLFdBQVc7Z0JBRVMsYUFBYTtzQkFBdkMsS0FBSzt1QkFBQyxrQkFBa0IiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBEaXJlY3RpdmUsIEVsZW1lbnRSZWYsIEluamVjdCwgSW5qZWN0aW9uVG9rZW4sIElucHV0LCBPcHRpb25hbCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgSU5ERVhFRERCLCBjcmVhdGVJbnN0YW5jZSB9IGZyb20gJ2xvY2FsZm9yYWdlJztcblxuY29uc3Qgc3RvcmFnZSA9IGNyZWF0ZUluc3RhbmNlKHtcbiAgICBuYW1lOiBcIkBkb3RnbGl0Y2hcIixcbiAgICBzdG9yZU5hbWU6IFwiaW1hZ2UtY2FjaGVcIixcbiAgICBkcml2ZXI6IElOREVYRUREQixcbiAgICB2ZXJzaW9uOiAxXG59KTtcblxuXG5jb25zdCBpbWFnZUNhY2hlOiB7XG4gICAgW2tleTogc3RyaW5nXTogSFRNTEltYWdlRWxlbWVudDtcbn0gPSB7fTtcblxuY29uc3QgbG9hZGluZ1N2ZyA9IGBkYXRhOmltYWdlL3N2Zyt4bWw7dXRmOCw8c3ZnIHhtbG5zPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmdcIiB4bWxuczp4bGluaz1cImh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmtcIiB3aWR0aD1cIjMycHhcIiBoZWlnaHQ9XCIzMnB4XCIgdmlld0JveD1cIjAgMCAxMDAgMTAwXCIgcHJlc2VydmVBc3BlY3RSYXRpbz1cInhNaWRZTWlkXCI+PGNpcmNsZSBjeD1cIjUwXCIgY3k9XCI1MFwiIGZpbGw9XCJub25lXCIgc3Ryb2tlPVwiJTIzNDBjNGZmXCIgc3Ryb2tlLXdpZHRoPVwiMTBcIiByPVwiMzVcIiBzdHJva2UtZGFzaGFycmF5PVwiMTY0LjkzMzYxNDMxMzQ2NDE1IDU2Ljk3Nzg3MTQzNzgyMTM4XCI+PGFuaW1hdGVUcmFuc2Zvcm0gYXR0cmlidXRlTmFtZT1cInRyYW5zZm9ybVwiIHR5cGU9XCJyb3RhdGVcIiByZXBlYXRDb3VudD1cImluZGVmaW5pdGVcIiBkdXI9XCIxc1wiIHZhbHVlcz1cIjAgNTAgNTA7MzYwIDUwIDUwXCIga2V5VGltZXM9XCIwOzFcIj48L2FuaW1hdGVUcmFuc2Zvcm0+PC9jaXJjbGU+PCEtLSBbbGRpb10gZ2VuZXJhdGVkIGJ5IGh0dHBzOi8vbG9hZGluZy5pby8gLS0+PC9zdmc+YDtcbmNvbnN0IGJyb2tlblN2ZyA9IGBkYXRhOmltYWdlL3N2Zyt4bWw7dXRmOCw8c3ZnIHdpZHRoPVwiODAwXCIgaGVpZ2h0PVwiODAwXCIgdmlld0JveD1cIjAgMCAyNCAyNFwiIHZlcnNpb249XCIxLjFcIiB4bWw6c3BhY2U9XCJwcmVzZXJ2ZVwiIHhtbG5zPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmdcIiB4bWxuczpzdmc9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiPjxsaW5lIHgxPVwiMTAuMDhcIiB5MT1cIjguMjlcIiB4Mj1cIjEwLjE4XCIgeTI9XCI4LjI5XCIgc3R5bGU9XCJmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjIuNTtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmRcIiAvPjxwYXRoIGQ9XCJtIDEwLjUxLDE0LjggNS4yLDUuMiBIIDIwIGEgMSwxIDAgMCAwIDEsLTEgViAxNS43MyBMIDE1LjI5LDEwIFogTSAzLDE2LjcxIFYgMTkgYSAxLDEgMCAwIDAgMSwxIGggMTEuNzEgbCAtOCwtOCB6IE0gMjEsNSB2IDE0IGEgMSwxIDAgMCAxIC0xLDEgSCA0IEEgMSwxIDAgMCAxIDMsMTkgViA1IEEgMSwxIDAgMCAxIDQsNCBoIDE2IGEgMSwxIDAgMCAxIDEsMSB6XCIgc3R5bGU9XCJmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kXCIgLz48cGF0aCBkPVwiTSAyMS4xOTMzODgsMjEuMTkzMzg4IDIuODA2NjEwOCwyLjgwNjYxMDggbSAxOC4zODY3NzcyLDAgTCAyLjgwNjYxMDgsMjEuMTkzMzg4XCIgc3R5bGU9XCJzdHJva2U6JTIzZmYwMDAwO3N0cm9rZS13aWR0aDoyLjYyNjY4O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2Utb3BhY2l0eToxXCIgLz48L3N2Zz5gO1xuXG5leHBvcnQgdHlwZSBOZ3hJbWFnZUNhY2hlQ29uZmlnID0ge1xuICAgIC8qKlxuICAgICAqIEltYWdlIHRvIHVzZSBhcyBhIHBsYWNlaG9sZGVyIHdoaWxlIGxvYWRpbmcgdGhlIG1haW4gaW1hZ2VcbiAgICAgKiBSZWNvbW1lbmRlZCB0byB1c2UgaW5saW5lZCBTVkcgb3IgYSBiYXNlNjQgZW5jb2RlZCBpbWFnZVxuICAgICAqL1xuICAgIGxvYWRpbmdQbGFjZWhvbGRlcj86IHN0cmluZyxcbiAgICAvKipcbiAgICAgKiBJbWFnZSB0byB1c2UgYXMgYSBwbGFjZWhvbGRlciB3aGVyZSBpbWFnZXMgZmFpbCB0byBsb2FkXG4gICAgICogUmVjb21tZW5kZWQgdG8gdXNlIGlubGluZWQgU1ZHIG9yIGEgYmFzZTY0IGVuY29kZWQgaW1hZ2VcbiAgICAgKi9cbiAgICBicm9rZW5QbGFjZWhvbGRlcj86IHN0cmluZ1xufVxuXG5leHBvcnQgY29uc3QgTkdYX0lNQUdFX0NBQ0hFX0NPTkZJRyA9IG5ldyBJbmplY3Rpb25Ub2tlbjxOZ3hJbWFnZUNhY2hlQ29uZmlnPignbmd4LWltYWdlLWNhY2hlLWNvbmZpZycpO1xuXG5cbmV4cG9ydCB0eXBlIE5neEltYWdlQ2FjaGVDb25maWd1cmF0aW9uID0ge1xuICAgIC8qKlxuICAgICAqIE1heCBhZ2UgdG8gY2FjaGUgYW4gaW1hZ2UgaW4gbWlsbGlzZWNvbmRzLlxuICAgICAqIElmIHNldCB0byBgMGAgb3IgYSBuZWdhdGl2ZSBudW1iZXIsIGltYWdlcyB3aWxsIG5ldmVyIGV4cGlyZS5cbiAgICAgKi9cbiAgICBtYXhBZ2U6IG51bWJlcixcbiAgICAvKipcbiAgICAgKiBTZXQgdG8gYGZhbHNlYCB0byBkaXNhYmxlIG1lbW9yeSBjYWNoaW5nIGZvciB0aGUgaW1hZ2VcbiAgICAgKiBJZiBib3RoIGBjYWNoZUluTWVtb3J5YCBhbmQgYGNhY2hlSW5JbmRleGVkREJgIGFyZSBmYWxzZSxcbiAgICAgKiBubyBjYWNoaW5nIHdpbGwgaGFwcGVuLiAoWW91J2xsIHN0aWxsIGdldCB0aGUgbG9hZGVyKVxuICAgICAqL1xuICAgIGNhY2hlSW5NZW1vcnk6IGJvb2xlYW4sXG4gICAgLyoqXG4gICAgICogU2V0IHRvIGBmYWxzZWAgdG8gZGlzYWJsZSBpbmRleGVkREIgY2FjaGluZyBmb3IgdGhlIGltYWdlXG4gICAgICogSWYgYm90aCBgY2FjaGVJbk1lbW9yeWAgYW5kIGBjYWNoZUluSW5kZXhlZERCYCBhcmUgZmFsc2UsXG4gICAgICogbm8gY2FjaGluZyB3aWxsIGhhcHBlbi4gKFlvdSdsbCBzdGlsbCBnZXQgdGhlIGxvYWRlcilcbiAgICAgKi9cbiAgICBjYWNoZUluSW5kZXhlZERCOiBib29sZWFuXG59XG5cbkBEaXJlY3RpdmUoe1xuICAgIHNlbGVjdG9yOiAnaW1nW25neC1jYWNoZV0nLFxuICAgIHN0YW5kYWxvbmU6IHRydWVcbn0pXG5leHBvcnQgY2xhc3MgTmd4SW1hZ2VDYWNoZURpcmVjdGl2ZSB7XG5cbiAgICBASW5wdXQoXCJzb3VyY2VcIilcbiAgICBASW5wdXQoXCJuZ3gtY2FjaGVcIikgdXJsOiBzdHJpbmc7XG5cbiAgICBASW5wdXQoXCJuZ3gtY2FjaGUtY29uZmlnXCIpIGNvbmZpZ3VyYXRpb246IE5neEltYWdlQ2FjaGVDb25maWd1cmF0aW9uO1xuXG4gICAgcHJpdmF0ZSBnZXQgZWwoKSB7IHJldHVybiB0aGlzLmVsZW1lbnQubmF0aXZlRWxlbWVudCBhcyBIVE1MSW1hZ2VFbGVtZW50IH1cblxuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgICBwcml2YXRlIHJlYWRvbmx5IGVsZW1lbnQ6IEVsZW1lbnRSZWYsXG4gICAgICAgIEBPcHRpb25hbCgpIEBJbmplY3QoTkdYX0lNQUdFX0NBQ0hFX0NPTkZJRykgcHJpdmF0ZSByZWFkb25seSBjYWNoZUNvbmZpZzogTmd4SW1hZ2VDYWNoZUNvbmZpZ1xuICAgICkgeyB9XG5cbiAgICBuZ09uQ2hhbmdlcygpIHtcbiAgICAgICAgdGhpcy5nZXRDYWNoZWRJbWFnZSgpO1xuICAgIH1cblxuICAgIGFzeW5jIGdldENhY2hlZEltYWdlKCkge1xuICAgICAgICBpZiAoXG4gICAgICAgICAgICB0aGlzLmVsLnNyYz8udHJpbSgpID09IHRoaXMudXJsPy50cmltKCkgfHwgLy8gQ2hlY2sgdGhhdCB0aGVyZSdzIGFuIGFjdHVhbCBjaGFuZ2VcbiAgICAgICAgICAgIHRoaXMudXJsPy50cmltKCkubGVuZ3RoID09IDAgLy8gQ2hlY2sgdGhhdCB0aGVyZSdzIGFuIGFjdHVhbCBVUkxcbiAgICAgICAgKSByZXR1cm47XG5cbiAgICAgICAgLy8gQ2hlY2sgaWYgaXQncyBpbiB0aGUgbWVtb3J5IGNhY2hlXG4gICAgICAgIGlmIChpbWFnZUNhY2hlW3RoaXMudXJsXSkge1xuICAgICAgICAgICAgY29uc3QgaW1hZ2UgPSBpbWFnZUNhY2hlW3RoaXMudXJsXTtcblxuICAgICAgICAgICAgLy8gSWYgdGhlIGltYWdlIGlzIGN1cnJlbnRseSBsb2FkaW5nLCBzaG93IHRoZSBsb2FkZXJcbiAgICAgICAgICAgIC8vIGFuZCBhZGQgaXQgdG8gdGhlIHJlZmxpc3RcbiAgICAgICAgICAgIGlmIChpbWFnZVsnX2xvYWRpbmcnXSA9PSB0cnVlKSB7XG4gICAgICAgICAgICAgICAgaW1hZ2VbJ19yZWZzJ10ucHVzaCh0aGlzLmVsKTtcblxuICAgICAgICAgICAgICAgIHRoaXMuZWwuc2V0QXR0cmlidXRlKFwibG9hZGluZ1wiLCBcInRydWVcIik7XG4gICAgICAgICAgICAgICAgdGhpcy5lbC5zcmMgPSB0aGlzLmNhY2hlQ29uZmlnPy5sb2FkaW5nUGxhY2Vob2xkZXIgfHwgbG9hZGluZ1N2ZztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIFRoZSBpbWFnZSBpcyBmdWxseSBsb2FkZWQsIHN3YXAgb3V0IHRoZSBzcmMgd2l0aCBhIGRhdGEtdXJpXG4gICAgICAgICAgICAgICAgdGhpcy5lbC5zZXRBdHRyaWJ1dGUoXCJsb2FkaW5nXCIsIFwiZmFsc2VcIik7XG4gICAgICAgICAgICAgICAgdGhpcy5lbC5zcmMgPSBpbWFnZS5zcmM7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIElmIGl0J3MgYWxyZWFkeSBpbiB0aGUgaW1hZ2UgY2FjaGUsIHdlJ3JlIGdvaW5nIHRvIHRydXN0IHRoYXQgaXQgbG9hZHMgcHJvcGVybHkuXG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBDaGVjayBpZiBpdCdzIGluIGluZGV4ZWREQlxuICAgICAgICBpZiAodGhpcy5jb25maWd1cmF0aW9uPy5jYWNoZUluSW5kZXhlZERCICE9IGZhbHNlKSB7XG4gICAgICAgICAgICBjb25zdCBjYWNoZWQgPSBhd2FpdCBzdG9yYWdlLmdldEl0ZW08YW55Pih0aGlzLnVybCk7XG4gICAgICAgICAgICBpZiAoY2FjaGVkKSB7XG4gICAgICAgICAgICAgICAgLy8gQXR0ZW1wdCB0byBsb2FkIHRoZSBiYXNlNjQgZGF0YSBmcm9tIGluZGV4ZWRkYi5cbiAgICAgICAgICAgICAgICAvLyBJZiB0aGlzIGZhaWxzLCB3ZSdsbCBmYWxsIGJhY2sgdG8gYXR0ZW1wdGluZyB0byBkb3dubG9hZCB0aGUgaW1hZ2VcbiAgICAgICAgICAgICAgICB0aGlzLmVsLnNyYyA9IGNhY2hlZC5kYXRhO1xuXG4gICAgICAgICAgICAgICAgY29uc3QgZXZ0OiBFdmVudCA9IGF3YWl0IG5ldyBQcm9taXNlKHJlcyA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZWwuYWRkRXZlbnRMaXN0ZW5lcignbG9hZCcsIHJlcyk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZWwuYWRkRXZlbnRMaXN0ZW5lcignZXJyb3InLCByZXMpO1xuICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgLy8gSWYgdGhlIGV2ZW50IGlzbid0IGFuIGVycm9yXG4gICAgICAgICAgICAgICAgaWYgKGV2dC50eXBlID09IFwibG9hZFwiKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZWwuc2V0QXR0cmlidXRlKFwibG9hZGluZ1wiLCBcImZhbHNlXCIpO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLmNvbmZpZ3VyYXRpb24/LmNhY2hlSW5NZW1vcnkgIT0gZmFsc2UpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFN1Y2Nlc3NmdWxseSBsb2FkZWQgaW50byBlbGVtZW50XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBDcmVhdGUgYW4gZW50cnkgaW4gdGhlIG1lbW9yeSBjYWNoZVxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgaW1hZ2UgPSBpbWFnZUNhY2hlW3RoaXMudXJsXSA9IG5ldyBJbWFnZSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgaW1hZ2Uuc3JjID0gY2FjaGVkLmRhdGE7XG4gICAgICAgICAgICAgICAgICAgICAgICBpbWFnZVsnX2NyZWF0ZWRBdCddID0gRGF0ZS5ub3coKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAvLyBFbHNlLCB3ZSB0cnkgdG8gbG9hZCBhZ2Fpbi5cbiAgICAgICAgICAgICAgICAgICAgdGhpcy5lbC5zcmMgPSB0aGlzLmNhY2hlQ29uZmlnPy5sb2FkaW5nUGxhY2Vob2xkZXIgfHwgbG9hZGluZ1N2ZztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBpbWFnZSA9ICgoKSA9PiB7XG4gICAgICAgICAgICBpZiAodGhpcy5jb25maWd1cmF0aW9uPy5jYWNoZUluTWVtb3J5ICE9IGZhbHNlKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGltYWdlQ2FjaGVbdGhpcy51cmxdID0gbmV3IEltYWdlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gbmV3IEltYWdlKCk7XG4gICAgICAgIH0pKCk7XG5cbiAgICAgICAgLy8gY29uc3QgY2xvbmUgPSBpbWFnZS5jbG9uZU5vZGUodHJ1ZSkgYXMgSFRNTEltYWdlRWxlbWVudDtcbiAgICAgICAgaW1hZ2VbJ19yZWZzJ10gPSBpbWFnZVsnX3JlZnMnXSA/PyBbXTtcbiAgICAgICAgaW1hZ2VbJ19yZWZzJ10ucHVzaCh0aGlzLmVsKTtcbiAgICAgICAgaW1hZ2VbJ19sb2FkaW5nJ10gPSB0cnVlO1xuICAgICAgICBpbWFnZVsnX2NyZWF0ZWRBdCddID0gRGF0ZS5ub3coKTtcblxuICAgICAgICAvLyBTaG93IGEgbG9hZGVyIHdoaWxlIHRoZSBpbWFnZSBkb3dubG9hZHMuXG4gICAgICAgIHRoaXMuZWwuc2V0QXR0cmlidXRlKFwibG9hZGluZ1wiLCBcInRydWVcIik7XG4gICAgICAgIHRoaXMuZWwuc3JjID0gdGhpcy5jYWNoZUNvbmZpZz8ubG9hZGluZ1BsYWNlaG9sZGVyIHx8IGxvYWRpbmdTdmc7XG5cbiAgICAgICAgLy8gRmV0Y2ggdGhlIGltYWdlIHZpYSBKUyBhbmQgY2FjaGUgaXQgYXMgYmFzZTY0XG4gICAgICAgIHdpbmRvdy5mZXRjaCh0aGlzLnVybClcbiAgICAgICAgICAgIC50aGVuKHJlc3BvbnNlID0+IHJlc3BvbnNlLmJsb2IoKSlcbiAgICAgICAgICAgIC50aGVuKGJsb2IgPT4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IHJlYWRlciA9IG5ldyBGaWxlUmVhZGVyKCk7XG4gICAgICAgICAgICAgICAgcmVhZGVyLm9ubG9hZGVuZCA9ICgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgaW1hZ2Uuc3JjID0gcmVhZGVyLnJlc3VsdCBhcyBzdHJpbmc7XG5cbiAgICAgICAgICAgICAgICAgICAgc3RvcmFnZS5zZXRJdGVtKHRoaXMudXJsLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aW1lc3RhbXA6IERhdGUubm93KCksXG4gICAgICAgICAgICAgICAgICAgICAgICBkYXRhOiByZWFkZXIucmVzdWx0XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgICAgIGltYWdlWydfcmVmcyddLmZvckVhY2goKHJlZjogSFRNTEltYWdlRWxlbWVudCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVmLnNyYyA9IGltYWdlLnNyYztcbiAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICAgICAgaW1hZ2VbJ19sb2FkaW5nJ10gPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgcmVzb2x2ZSgwKTtcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIHJlYWRlci5vbmVycm9yID0gcmVqZWN0O1xuICAgICAgICAgICAgICAgIHJlYWRlci5yZWFkQXNEYXRhVVJMKGJsb2IpO1xuICAgICAgICAgICAgfSkpXG4gICAgICAgICAgICAuY2F0Y2goZXJyID0+IHtcbiAgICAgICAgICAgICAgICAvLyBJZiBhIGZhaWx1cmUgb2NjdXJzLCBwdXJnZSB0aGlzIGVudHJ5IGZyb20gdGhlIGNhY2hlXG4gICAgICAgICAgICAgICAgLy8gVE9ETzogUmVuZGVyIGJldHRlciBcImJyb2tlblwiIGltYWdlXG4gICAgICAgICAgICAgICAgZGVsZXRlIGltYWdlQ2FjaGVbdGhpcy51cmxdO1xuICAgICAgICAgICAgICAgIGltYWdlWydfcmVmcyddLmZvckVhY2goKHJlZjogSFRNTEltYWdlRWxlbWVudCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICByZWYuc3JjID0gdGhpcy5jYWNoZUNvbmZpZz8uYnJva2VuUGxhY2Vob2xkZXIgfHwgYnJva2VuU3ZnO1xuICAgICAgICAgICAgICAgICAgICByZWYuc2V0QXR0cmlidXRlKFwibG9hZGluZ1wiLCBcImZhaWxlZFwiKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0pO1xuICAgIH1cbn1cbiJdfQ==