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.1.2", 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.1.2", 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.1.2", 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1hZ2UtY2FjaGUuZGlyZWN0aXZlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcGFja2FnZXMvY29tbW9uL3NyYy9kaXJlY3RpdmVzL2ltYWdlLWNhY2hlLmRpcmVjdGl2ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFjLE1BQU0sRUFBRSxjQUFjLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMvRixPQUFPLEVBQUUsU0FBUyxFQUFFLGNBQWMsRUFBRSxNQUFNLGFBQWEsQ0FBQzs7QUFFeEQsTUFBTSxPQUFPLEdBQUcsY0FBYyxDQUFDO0lBQzNCLElBQUksRUFBRSxZQUFZO0lBQ2xCLFNBQVMsRUFBRSxhQUFhO0lBQ3hCLE1BQU0sRUFBRSxTQUFTO0lBQ2pCLE9BQU8sRUFBRSxDQUFDO0NBQ2IsQ0FBQyxDQUFDO0FBR0gsTUFBTSxVQUFVLEdBRVosRUFBRSxDQUFDO0FBRVAsTUFBTSxVQUFVLEdBQUcsNmhCQUE2aEIsQ0FBQztBQUNqakIsTUFBTSxTQUFTLEdBQUcsdzBCQUF3MEIsQ0FBQztBQWUzMUIsTUFBTSxDQUFDLE1BQU0sc0JBQXNCLEdBQUcsSUFBSSxjQUFjLENBQXNCLHdCQUF3QixDQUFDLENBQUM7QUEyQnhHLE1BQU0sT0FBTyxzQkFBc0I7SUFPL0IsSUFBWSxFQUFFLEtBQUssT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLGFBQWlDLENBQUEsQ0FBQyxDQUFDO0lBRTFFLFlBQ3FCLE9BQW1CLEVBQ3lCLFdBQWdDO1FBRDVFLFlBQU8sR0FBUCxPQUFPLENBQVk7UUFDeUIsZ0JBQVcsR0FBWCxXQUFXLENBQXFCO0lBQzdGLENBQUM7SUFFTCxXQUFXO1FBQ1AsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO0lBQzFCLENBQUM7SUFFRCxLQUFLLENBQUMsY0FBYztRQUNoQixJQUNJLElBQUksQ0FBQyxFQUFFLENBQUMsR0FBRyxFQUFFLElBQUks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bkI7OzBCQVlRLFFBQVE7OzBCQUFJLE1BQU07MkJBQUMsc0JBQXNCO3lDQVIxQixHQUFHO3NCQUR0QixLQUFLO3VCQUFDLFFBQVE7O3NCQUNkLEtBQUs7dUJBQUMsV0FBVztnQkFFUyxhQUFhO3NCQUF2QyxLQUFLO3VCQUFDLGtCQUFrQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IERpcmVjdGl2ZSwgRWxlbWVudFJlZiwgSW5qZWN0LCBJbmplY3Rpb25Ub2tlbiwgSW5wdXQsIE9wdGlvbmFsIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBJTkRFWEVEREIsIGNyZWF0ZUluc3RhbmNlIH0gZnJvbSAnbG9jYWxmb3JhZ2UnO1xuXG5jb25zdCBzdG9yYWdlID0gY3JlYXRlSW5zdGFuY2Uoe1xuICAgIG5hbWU6IFwiQGRvdGdsaXRjaFwiLFxuICAgIHN0b3JlTmFtZTogXCJpbWFnZS1jYWNoZVwiLFxuICAgIGRyaXZlcjogSU5ERVhFRERCLFxuICAgIHZlcnNpb246IDFcbn0pO1xuXG5cbmNvbnN0IGltYWdlQ2FjaGU6IHtcbiAgICBba2V5OiBzdHJpbmddOiBIVE1MSW1hZ2VFbGVtZW50O1xufSA9IHt9O1xuXG5jb25zdCBsb2FkaW5nU3ZnID0gYGRhdGE6aW1hZ2Uvc3ZnK3htbDt1dGY4LDxzdmcgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiIHhtbG5zOnhsaW5rPVwiaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGlua1wiIHdpZHRoPVwiMzJweFwiIGhlaWdodD1cIjMycHhcIiB2aWV3Qm94PVwiMCAwIDEwMCAxMDBcIiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPVwieE1pZFlNaWRcIj48Y2lyY2xlIGN4PVwiNTBcIiBjeT1cIjUwXCIgZmlsbD1cIm5vbmVcIiBzdHJva2U9XCIlMjM0MGM0ZmZcIiBzdHJva2Utd2lkdGg9XCIxMFwiIHI9XCIzNVwiIHN0cm9rZS1kYXNoYXJyYXk9XCIxNjQuOTMzNjE0MzEzNDY0MTUgNTYuOTc3ODcxNDM3ODIxMzhcIj48YW5pbWF0ZVRyYW5zZm9ybSBhdHRyaWJ1dGVOYW1lPVwidHJhbnNmb3JtXCIgdHlwZT1cInJvdGF0ZVwiIHJlcGVhdENvdW50PVwiaW5kZWZpbml0ZVwiIGR1cj1cIjFzXCIgdmFsdWVzPVwiMCA1MCA1MDszNjAgNTAgNTBcIiBrZXlUaW1lcz1cIjA7MVwiPjwvYW5pbWF0ZVRyYW5zZm9ybT48L2NpcmNsZT48IS0tIFtsZGlvXSBnZW5lcmF0ZWQgYnkgaHR0cHM6Ly9sb2FkaW5nLmlvLyAtLT48L3N2Zz5gO1xuY29uc3QgYnJva2VuU3ZnID0gYGRhdGE6aW1hZ2Uvc3ZnK3htbDt1dGY4LDxzdmcgd2lkdGg9XCI4MDBcIiBoZWlnaHQ9XCI4MDBcIiB2aWV3Qm94PVwiMCAwIDI0IDI0XCIgdmVyc2lvbj1cIjEuMVwiIHhtbDpzcGFjZT1cInByZXNlcnZlXCIgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiIHhtbG5zOnN2Zz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCI+PGxpbmUgeDE9XCIxMC4wOFwiIHkxPVwiOC4yOVwiIHgyPVwiMTAuMThcIiB5Mj1cIjguMjlcIiBzdHlsZT1cImZpbGw6bm9uZTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6Mi41O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZFwiIC8+PHBhdGggZD1cIm0gMTAuNTEsMTQuOCA1LjIsNS4yIEggMjAgYSAxLDEgMCAwIDAgMSwtMSBWIDE1LjczIEwgMTUuMjksMTAgWiBNIDMsMTYuNzEgViAxOSBhIDEsMSAwIDAgMCAxLDEgaCAxMS43MSBsIC04LC04IHogTSAyMSw1IHYgMTQgYSAxLDEgMCAwIDEgLTEsMSBIIDQgQSAxLDEgMCAwIDEgMywxOSBWIDUgQSAxLDEgMCAwIDEgNCw0IGggMTYgYSAxLDEgMCAwIDEgMSwxIHpcIiBzdHlsZT1cImZpbGw6bm9uZTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmRcIiAvPjxwYXRoIGQ9XCJNIDIxLjE5MzM4OCwyMS4xOTMzODggMi44MDY2MTA4LDIuODA2NjEwOCBtIDE4LjM4Njc3NzIsMCBMIDIuODA2NjEwOCwyMS4xOTMzODhcIiBzdHlsZT1cInN0cm9rZTolMjNmZjAwMDA7c3Ryb2tlLXdpZHRoOjIuNjI2Njg7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1vcGFjaXR5OjFcIiAvPjwvc3ZnPmA7XG5cbmV4cG9ydCB0eXBlIE5neEltYWdlQ2FjaGVDb25maWcgPSB7XG4gICAgLyoqXG4gICAgICogSW1hZ2UgdG8gdXNlIGFzIGEgcGxhY2Vob2xkZXIgd2hpbGUgbG9hZGluZyB0aGUgbWFpbiBpbWFnZVxuICAgICAqIFJlY29tbWVuZGVkIHRvIHVzZSBpbmxpbmVkIFNWRyBvciBhIGJhc2U2NCBlbmNvZGVkIGltYWdlXG4gICAgICovXG4gICAgbG9hZGluZ1BsYWNlaG9sZGVyPzogc3RyaW5nLFxuICAgIC8qKlxuICAgICAqIEltYWdlIHRvIHVzZSBhcyBhIHBsYWNlaG9sZGVyIHdoZXJlIGltYWdlcyBmYWlsIHRvIGxvYWRcbiAgICAgKiBSZWNvbW1lbmRlZCB0byB1c2UgaW5saW5lZCBTVkcgb3IgYSBiYXNlNjQgZW5jb2RlZCBpbWFnZVxuICAgICAqL1xuICAgIGJyb2tlblBsYWNlaG9sZGVyPzogc3RyaW5nXG59XG5cbmV4cG9ydCBjb25zdCBOR1hfSU1BR0VfQ0FDSEVfQ09ORklHID0gbmV3IEluamVjdGlvblRva2VuPE5neEltYWdlQ2FjaGVDb25maWc+KCduZ3gtaW1hZ2UtY2FjaGUtY29uZmlnJyk7XG5cblxuZXhwb3J0IHR5cGUgTmd4SW1hZ2VDYWNoZUNvbmZpZ3VyYXRpb24gPSB7XG4gICAgLyoqXG4gICAgICogTWF4IGFnZSB0byBjYWNoZSBhbiBpbWFnZSBpbiBtaWxsaXNlY29uZHMuXG4gICAgICogSWYgc2V0IHRvIGAwYCBvciBhIG5lZ2F0aXZlIG51bWJlciwgaW1hZ2VzIHdpbGwgbmV2ZXIgZXhwaXJlLlxuICAgICAqL1xuICAgIG1heEFnZTogbnVtYmVyLFxuICAgIC8qKlxuICAgICAqIFNldCB0byBgZmFsc2VgIHRvIGRpc2FibGUgbWVtb3J5IGNhY2hpbmcgZm9yIHRoZSBpbWFnZVxuICAgICAqIElmIGJvdGggYGNhY2hlSW5NZW1vcnlgIGFuZCBgY2FjaGVJbkluZGV4ZWREQmAgYXJlIGZhbHNlLFxuICAgICAqIG5vIGNhY2hpbmcgd2lsbCBoYXBwZW4uIChZb3UnbGwgc3RpbGwgZ2V0IHRoZSBsb2FkZXIpXG4gICAgICovXG4gICAgY2FjaGVJbk1lbW9yeTogYm9vbGVhbixcbiAgICAvKipcbiAgICAgKiBTZXQgdG8gYGZhbHNlYCB0byBkaXNhYmxlIGluZGV4ZWREQiBjYWNoaW5nIGZvciB0aGUgaW1hZ2VcbiAgICAgKiBJZiBib3RoIGBjYWNoZUluTWVtb3J5YCBhbmQgYGNhY2hlSW5JbmRleGVkREJgIGFyZSBmYWxzZSxcbiAgICAgKiBubyBjYWNoaW5nIHdpbGwgaGFwcGVuLiAoWW91J2xsIHN0aWxsIGdldCB0aGUgbG9hZGVyKVxuICAgICAqL1xuICAgIGNhY2hlSW5JbmRleGVkREI6IGJvb2xlYW5cbn1cblxuQERpcmVjdGl2ZSh7XG4gICAgc2VsZWN0b3I6ICdpbWdbbmd4LWNhY2hlXScsXG4gICAgc3RhbmRhbG9uZTogdHJ1ZVxufSlcbmV4cG9ydCBjbGFzcyBOZ3hJbWFnZUNhY2hlRGlyZWN0aXZlIHtcblxuICAgIEBJbnB1dChcInNvdXJjZVwiKVxuICAgIEBJbnB1dChcIm5neC1jYWNoZVwiKSB1cmw6IHN0cmluZztcblxuICAgIEBJbnB1dChcIm5neC1jYWNoZS1jb25maWdcIikgY29uZmlndXJhdGlvbjogTmd4SW1hZ2VDYWNoZUNvbmZpZ3VyYXRpb247XG5cbiAgICBwcml2YXRlIGdldCBlbCgpIHsgcmV0dXJuIHRoaXMuZWxlbWVudC5uYXRpdmVFbGVtZW50IGFzIEhUTUxJbWFnZUVsZW1lbnQgfVxuXG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIHByaXZhdGUgcmVhZG9ubHkgZWxlbWVudDogRWxlbWVudFJlZixcbiAgICAgICAgQE9wdGlvbmFsKCkgQEluamVjdChOR1hfSU1BR0VfQ0FDSEVfQ09ORklHKSBwcml2YXRlIHJlYWRvbmx5IGNhY2hlQ29uZmlnOiBOZ3hJbWFnZUNhY2hlQ29uZmlnXG4gICAgKSB7IH1cblxuICAgIG5nT25DaGFuZ2VzKCkge1xuICAgICAgICB0aGlzLmdldENhY2hlZEltYWdlKCk7XG4gICAgfVxuXG4gICAgYXN5bmMgZ2V0Q2FjaGVkSW1hZ2UoKSB7XG4gICAgICAgIGlmIChcbiAgICAgICAgICAgIHRoaXMuZWwuc3JjPy50cmltKCkgPT0gdGhpcy51cmw/LnRyaW0oKSB8fCAvLyBDaGVjayB0aGF0IHRoZXJlJ3MgYW4gYWN0dWFsIGNoYW5nZVxuICAgICAgICAgICAgdGhpcy51cmw/LnRyaW0oKS5sZW5ndGggPT0gMCAvLyBDaGVjayB0aGF0IHRoZXJlJ3MgYW4gYWN0dWFsIFVSTFxuICAgICAgICApIHJldHVybjtcblxuICAgICAgICAvLyBDaGVjayBpZiBpdCdzIGluIHRoZSBtZW1vcnkgY2FjaGVcbiAgICAgICAgaWYgKGltYWdlQ2FjaGVbdGhpcy51cmxdKSB7XG4gICAgICAgICAgICBjb25zdCBpbWFnZSA9IGltYWdlQ2FjaGVbdGhpcy51cmxdO1xuXG4gICAgICAgICAgICAvLyBJZiB0aGUgaW1hZ2UgaXMgY3VycmVudGx5IGxvYWRpbmcsIHNob3cgdGhlIGxvYWRlclxuICAgICAgICAgICAgLy8gYW5kIGFkZCBpdCB0byB0aGUgcmVmbGlzdFxuICAgICAgICAgICAgaWYgKGltYWdlWydfbG9hZGluZyddID09IHRydWUpIHtcbiAgICAgICAgICAgICAgICBpbWFnZVsnX3JlZnMnXS5wdXNoKHRoaXMuZWwpO1xuXG4gICAgICAgICAgICAgICAgdGhpcy5lbC5zZXRBdHRyaWJ1dGUoXCJsb2FkaW5nXCIsIFwidHJ1ZVwiKTtcbiAgICAgICAgICAgICAgICB0aGlzLmVsLnNyYyA9IHRoaXMuY2FjaGVDb25maWc/LmxvYWRpbmdQbGFjZWhvbGRlciB8fCBsb2FkaW5nU3ZnO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8gVGhlIGltYWdlIGlzIGZ1bGx5IGxvYWRlZCwgc3dhcCBvdXQgdGhlIHNyYyB3aXRoIGEgZGF0YS11cmlcbiAgICAgICAgICAgICAgICB0aGlzLmVsLnNldEF0dHJpYnV0ZShcImxvYWRpbmdcIiwgXCJmYWxzZVwiKTtcbiAgICAgICAgICAgICAgICB0aGlzLmVsLnNyYyA9IGltYWdlLnNyYztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gSWYgaXQncyBhbHJlYWR5IGluIHRoZSBpbWFnZSBjYWNoZSwgd2UncmUgZ29pbmcgdG8gdHJ1c3QgdGhhdCBpdCBsb2FkcyBwcm9wZXJseS5cbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIENoZWNrIGlmIGl0J3MgaW4gaW5kZXhlZERCXG4gICAgICAgIGlmICh0aGlzLmNvbmZpZ3VyYXRpb24/LmNhY2hlSW5JbmRleGVkREIgIT0gZmFsc2UpIHtcbiAgICAgICAgICAgIGNvbnN0IGNhY2hlZCA9IGF3YWl0IHN0b3JhZ2UuZ2V0SXRlbTxhbnk+KHRoaXMudXJsKTtcbiAgICAgICAgICAgIGlmIChjYWNoZWQpIHtcbiAgICAgICAgICAgICAgICAvLyBBdHRlbXB0IHRvIGxvYWQgdGhlIGJhc2U2NCBkYXRhIGZyb20gaW5kZXhlZGRiLlxuICAgICAgICAgICAgICAgIC8vIElmIHRoaXMgZmFpbHMsIHdlJ2xsIGZhbGwgYmFjayB0byBhdHRlbXB0aW5nIHRvIGRvd25sb2FkIHRoZSBpbWFnZVxuICAgICAgICAgICAgICAgIHRoaXMuZWwuc3JjID0gY2FjaGVkLmRhdGE7XG5cbiAgICAgICAgICAgICAgICBjb25zdCBldnQ6IEV2ZW50ID0gYXdhaXQgbmV3IFByb21pc2UocmVzID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5lbC5hZGRFdmVudExpc3RlbmVyKCdsb2FkJywgcmVzKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5lbC5hZGRFdmVudExpc3RlbmVyKCdlcnJvcicsIHJlcyk7XG4gICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICAvLyBJZiB0aGUgZXZlbnQgaXNuJ3QgYW4gZXJyb3JcbiAgICAgICAgICAgICAgICBpZiAoZXZ0LnR5cGUgPT0gXCJsb2FkXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5lbC5zZXRBdHRyaWJ1dGUoXCJsb2FkaW5nXCIsIFwiZmFsc2VcIik7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuY29uZmlndXJhdGlvbj8uY2FjaGVJbk1lbW9yeSAhPSBmYWxzZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gU3VjY2Vzc2Z1bGx5IGxvYWRlZCBpbnRvIGVsZW1lbnRcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIENyZWF0ZSBhbiBlbnRyeSBpbiB0aGUgbWVtb3J5IGNhY2hlXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBpbWFnZSA9IGltYWdlQ2FjaGVbdGhpcy51cmxdID0gbmV3IEltYWdlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBpbWFnZS5zcmMgPSBjYWNoZWQuZGF0YTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGltYWdlWydfY3JlYXRlZEF0J10gPSBEYXRlLm5vdygpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIEVsc2UsIHdlIHRyeSB0byBsb2FkIGFnYWluLlxuICAgICAgICAgICAgICAgICAgICB0aGlzLmVsLnNyYyA9IHRoaXMuY2FjaGVDb25maWc/LmxvYWRpbmdQbGFjZWhvbGRlciB8fCBsb2FkaW5nU3ZnO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGltYWdlID0gKCgpID0+IHtcbiAgICAgICAgICAgIGlmICh0aGlzLmNvbmZpZ3VyYXRpb24/LmNhY2hlSW5NZW1vcnkgIT0gZmFsc2UpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gaW1hZ2VDYWNoZVt0aGlzLnVybF0gPSBuZXcgSW1hZ2UoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBuZXcgSW1hZ2UoKTtcbiAgICAgICAgfSkoKTtcblxuICAgICAgICAvLyBjb25zdCBjbG9uZSA9IGltYWdlLmNsb25lTm9kZSh0cnVlKSBhcyBIVE1MSW1hZ2VFbGVtZW50O1xuICAgICAgICBpbWFnZVsnX3JlZnMnXSA9IGltYWdlWydfcmVmcyddID8/IFtdO1xuICAgICAgICBpbWFnZVsnX3JlZnMnXS5wdXNoKHRoaXMuZWwpO1xuICAgICAgICBpbWFnZVsnX2xvYWRpbmcnXSA9IHRydWU7XG4gICAgICAgIGltYWdlWydfY3JlYXRlZEF0J10gPSBEYXRlLm5vdygpO1xuXG4gICAgICAgIC8vIFNob3cgYSBsb2FkZXIgd2hpbGUgdGhlIGltYWdlIGRvd25sb2Fkcy5cbiAgICAgICAgdGhpcy5lbC5zZXRBdHRyaWJ1dGUoXCJsb2FkaW5nXCIsIFwidHJ1ZVwiKTtcbiAgICAgICAgdGhpcy5lbC5zcmMgPSB0aGlzLmNhY2hlQ29uZmlnPy5sb2FkaW5nUGxhY2Vob2xkZXIgfHwgbG9hZGluZ1N2ZztcblxuICAgICAgICAvLyBGZXRjaCB0aGUgaW1hZ2UgdmlhIEpTIGFuZCBjYWNoZSBpdCBhcyBiYXNlNjRcbiAgICAgICAgd2luZG93LmZldGNoKHRoaXMudXJsKVxuICAgICAgICAgICAgLnRoZW4ocmVzcG9uc2UgPT4gcmVzcG9uc2UuYmxvYigpKVxuICAgICAgICAgICAgLnRoZW4oYmxvYiA9PiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgcmVhZGVyID0gbmV3IEZpbGVSZWFkZXIoKTtcbiAgICAgICAgICAgICAgICByZWFkZXIub25sb2FkZW5kID0gKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBpbWFnZS5zcmMgPSByZWFkZXIucmVzdWx0IGFzIHN0cmluZztcblxuICAgICAgICAgICAgICAgICAgICBzdG9yYWdlLnNldEl0ZW0odGhpcy51cmwsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRpbWVzdGFtcDogRGF0ZS5ub3coKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE6IHJlYWRlci5yZXN1bHRcbiAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICAgICAgaW1hZ2VbJ19yZWZzJ10uZm9yRWFjaCgocmVmOiBIVE1MSW1hZ2VFbGVtZW50KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZWYuc3JjID0gaW1hZ2Uuc3JjO1xuICAgICAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICAgICAgICBpbWFnZVsnX2xvYWRpbmcnXSA9IGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICByZXNvbHZlKDApO1xuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgcmVhZGVyLm9uZXJyb3IgPSByZWplY3Q7XG4gICAgICAgICAgICAgICAgcmVhZGVyLnJlYWRBc0RhdGFVUkwoYmxvYik7XG4gICAgICAgICAgICB9KSlcbiAgICAgICAgICAgIC5jYXRjaChlcnIgPT4ge1xuICAgICAgICAgICAgICAgIC8vIElmIGEgZmFpbHVyZSBvY2N1cnMsIHB1cmdlIHRoaXMgZW50cnkgZnJvbSB0aGUgY2FjaGVcbiAgICAgICAgICAgICAgICAvLyBUT0RPOiBSZW5kZXIgYmV0dGVyIFwiYnJva2VuXCIgaW1hZ2VcbiAgICAgICAgICAgICAgICBkZWxldGUgaW1hZ2VDYWNoZVt0aGlzLnVybF07XG4gICAgICAgICAgICAgICAgaW1hZ2VbJ19yZWZzJ10uZm9yRWFjaCgocmVmOiBIVE1MSW1hZ2VFbGVtZW50KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHJlZi5zcmMgPSB0aGlzLmNhY2hlQ29uZmlnPy5icm9rZW5QbGFjZWhvbGRlciB8fCBicm9rZW5Tdmc7XG4gICAgICAgICAgICAgICAgICAgIHJlZi5zZXRBdHRyaWJ1dGUoXCJsb2FkaW5nXCIsIFwiZmFpbGVkXCIpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSk7XG4gICAgfVxufVxuIl19