UNPKG

@bespunky/angular-zen

Version:

The Angular tools you always wished were there.

162 lines 26.1 kB
import { Observable, of } from 'rxjs'; import { Injectable } from '@angular/core'; import { HeadService } from '@bespunky/angular-zen/core'; import { UniversalService } from '@bespunky/angular-zen/universal'; import * as i0 from "@angular/core"; import * as i1 from "@bespunky/angular-zen/core"; import * as i2 from "@bespunky/angular-zen/universal"; /** * Provides methods for lazy loading scripts and styles programatically. * The service keeps track of loaded files to skip reloading unless specified otherwise in the options of `loadScript()` or `loadStyle()`. */ export class LazyLoaderService { constructor(head, universal) { this.head = head; this.universal = universal; /** * Defines the default options when calling the `LazyLoaderService.loadScript()` method. */ this.defaultScriptOptions = { async: true, defer: true, alreadyLoaded: (url) => this.isCached(url) || this.isScriptPresent(url), force: false }; /** * Defines the default options when calling the `LazyLoaderService.loadStyle()` method. */ this.defaultStyleOptions = { alreadyLoaded: (url) => this.isCached(url) || this.isStylePresent(url), force: false }; this.cache = {}; } /** * Checks whether the file from the specified url has already been cached. * @param url The url for the file to check. * @returns A value indicating whether the file from the specified url has already been cached. */ isCached(url) { return !!this.cache[url]; } /** * Checks whether a script element is already present in `<head>` for the given url. * This doesn't guarantee that the script has been loaded. * * @param {string} url The url of the loaded script. * @returns {boolean} `true` if an element matching the url is present in `<head>`; otherwise `false. */ isScriptPresent(url) { return this.head.contains('script', { src: url }); } /** * Checks whether a link element is already present in `<head>` for the given style url. * This doesn't guarantee that the style has been loaded. * * @param {string} url The url of the loaded link. * @returns {boolean} `true` if an element matching the url is present in `<head>`; otherwise `false. */ isStylePresent(url) { return this.head.contains('link', { rel: 'stylesheet', href: url }); } /** * Loads a script programatically. * * @param url The full url of the script to load. * @param options (Optional) Specifies custom options to override default behaviour. * @returns An observable object which allows subscribers to know when the script has been loaded and access its associated `<script>` element. * The observable will complete immediately in case the script was already previously loaded. * If the script was already loaded outside of the service, the observable will stream `undefined`. */ loadScript(url, options = this.defaultScriptOptions) { // Set default options if not specified by caller options.async = options.async === undefined ? this.defaultScriptOptions.async : options.async; options.defer = options.defer === undefined ? this.defaultScriptOptions.defer : options.defer; options.alreadyLoaded = options.alreadyLoaded === undefined ? this.defaultScriptOptions.alreadyLoaded : options.alreadyLoaded; options.force = options.force === undefined ? this.defaultScriptOptions.force : options.force; return this.loadFile(url, 'script', options, this.createScriptElement.bind(this)); } /** * Loads a style programatically. * * @param url The full url of the style to load. * @param options (Optional) Specifies custom options to override default behaviour. * @returns An observable object which allows subscribers to know when the style has been loaded and access its associated `<link>` element. * The observable will complete immediately in case the style was already previously loaded. * If the style was already loaded outside of the service, the observable will stream `undefined`. */ loadStyle(url, options = this.defaultStyleOptions) { // Set default options if not specified by caller options.alreadyLoaded = options.alreadyLoaded === undefined ? this.defaultStyleOptions.alreadyLoaded : options.alreadyLoaded; options.force = options.force === undefined ? this.defaultStyleOptions.force : options.force; return this.loadFile(url, 'style', options, this.createLinkElement.bind(this)); } loadFile(url, type, options, createElement) { if (!this.universal.isPlatformBrowser) return of(null); // If the script should be loaded, load it if (!options.alreadyLoaded(url) || options.force) { // Initialize a base object to store the data later const lazyFile = { url, type, completed: false, element: null }; // Create an observable that waits until the script has been loaded and executed const observable = new Observable(observer => { // Create the callback that will mark the script as completed and notify the subscriber const onLoad = () => { lazyFile.completed = true; observer.next(lazyFile); observer.complete(); }; // Create the actual file tag, start downloading and store the element reference lazyFile.element = createElement(url, onLoad, observer.error.bind(observer), options); }); // Cache the file and the observable for later use this.cache[url] = { lazyFile: lazyFile, observable }; return observable; } // If the file was already loaded and it shouldn't be downloaded again, complete immediately with the previous link data. // If the file was already loaded outside of the service, the observable will stream `undefined` as there is nothing cached. return of(this.cache[url]?.lazyFile); } /** * Creates a `<script>` tag for the given url and adds it to the `<head>` tag to start downloading the script. * * @param url The url for the script to download. * @param onLoad The callback to execute when the script has been downloaded and executed. * @param onError The callback to execute when script download or execution has failed. * @param options The options to add to the script. * @returns A reference to the `<script>` element that was added to the DOM. */ createScriptElement(url, onLoad, onError, options) { return this.head.addScriptElement('text/javascript', url, { async: options.async, defer: options.defer, onload: onLoad, onerror: onError }); } /** * Creates a `<link>` tag for the given url and adds it to the `<head>` tag to start downloading the link. * * @param url The url for the link to download. * @param onLoad The callback to execute when the script has been downloaded and executed. * @param onError The callback to execute when script download or execution has failed. * @returns A reference to the `<link>` element that was added to the DOM. */ createLinkElement(url, onLoad, onError) { return this.head.addLinkElement('stylesheet', { type: 'text/css', href: url, onload: onLoad, onerror: onError }); } } LazyLoaderService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: LazyLoaderService, deps: [{ token: i1.HeadService }, { token: i2.UniversalService }], target: i0.ɵɵFactoryTarget.Injectable }); LazyLoaderService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: LazyLoaderService, providedIn: 'root' }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: LazyLoaderService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: function () { return [{ type: i1.HeadService }, { type: i2.UniversalService }]; } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGF6eS1sb2FkZXIuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL2xpYnMvYW5ndWxhci16ZW4vYXN5bmMvc3JjL2xhenktbG9hZGVyL2xhenktbG9hZGVyLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxFQUFFLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDdEMsT0FBTyxFQUFFLFVBQVUsRUFBYyxNQUFNLGVBQWUsQ0FBQztBQUV2RCxPQUFPLEVBQUUsV0FBVyxFQUFRLE1BQU0sNEJBQTRCLENBQUM7QUFDL0QsT0FBTyxFQUFFLGdCQUFnQixFQUFHLE1BQU0saUNBQWlDLENBQUM7Ozs7QUFPcEU7OztHQUdHO0FBSUgsTUFBTSxPQUFPLGlCQUFpQjtJQXlCMUIsWUFBb0IsSUFBaUIsRUFBVSxTQUEyQjtRQUF0RCxTQUFJLEdBQUosSUFBSSxDQUFhO1FBQVUsY0FBUyxHQUFULFNBQVMsQ0FBa0I7UUF2QjFFOztXQUVHO1FBQ0sseUJBQW9CLEdBQXNCO1lBQzlDLEtBQUssRUFBRSxJQUFJO1lBQ1gsS0FBSyxFQUFFLElBQUk7WUFDWCxhQUFhLEVBQUUsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLElBQUksSUFBSSxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUM7WUFDdkUsS0FBSyxFQUFFLEtBQUs7U0FDZixDQUFDO1FBRUQ7O1VBRUU7UUFDSyx3QkFBbUIsR0FBZ0I7WUFDdkMsYUFBYSxFQUFFLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxJQUFJLElBQUksQ0FBQyxjQUFjLENBQUMsR0FBRyxDQUFDO1lBQ3RFLEtBQUssRUFBRSxLQUFLO1NBQ2YsQ0FBQztRQVNFLElBQUksQ0FBQyxLQUFLLEdBQUcsRUFBRSxDQUFDO0lBQ3BCLENBQUM7SUFF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TSxFQUFFLE1BQU07WUFDZCxPQUFPLEVBQUUsT0FBTztTQUNuQixDQUFDLENBQUM7SUFDWCxDQUFDO0lBRUQ7Ozs7Ozs7T0FPRztJQUNLLGlCQUFpQixDQUFDLEdBQVcsRUFBRSxNQUFrQixFQUFFLE9BQTZCO1FBRXBGLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsWUFBWSxFQUN4QztZQUNJLElBQUksRUFBRSxVQUFVO1lBQ2hCLElBQUksRUFBRSxHQUFHO1lBQ1QsTUFBTSxFQUFFLE1BQU07WUFDZCxPQUFPLEVBQUUsT0FBTztTQUNuQixDQUFDLENBQUM7SUFDWCxDQUFDOzsrR0EvS1EsaUJBQWlCO21IQUFqQixpQkFBaUIsY0FGZCxNQUFNOzRGQUVULGlCQUFpQjtrQkFIN0IsVUFBVTttQkFBQztvQkFDUixVQUFVLEVBQUUsTUFBTTtpQkFDckIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBPYnNlcnZhYmxlLCBvZiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgSW5qZWN0YWJsZSwgRWxlbWVudFJlZiB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuXG5pbXBvcnQgeyBIZWFkU2VydmljZSAgICAgICB9IGZyb20gJ0BiZXNwdW5reS9hbmd1bGFyLXplbi9jb3JlJztcbmltcG9ydCB7IFVuaXZlcnNhbFNlcnZpY2UgIH0gZnJvbSAnQGJlc3B1bmt5L2FuZ3VsYXItemVuL3VuaXZlcnNhbCc7XG5pbXBvcnQgeyBTY3JpcHRMb2FkT3B0aW9ucyB9IGZyb20gJy4vc2NyaXB0LWxvYWQtb3B0aW9ucyc7XG5pbXBvcnQgeyBMb2FkT3B0aW9ucyAgICAgICB9IGZyb20gJy4vbG9hZC1vcHRpb25zJztcbmltcG9ydCB7IExhenlMb2FkZWRGaWxlICAgIH0gZnJvbSAnLi9sYXp5LWxvYWRlZC1maWxlJztcblxudHlwZSBFbGVtZW50Q3JlYXRvciA9ICh1cmw6IHN0cmluZywgb25Mb2FkOiAoKSA9PiB2b2lkLCBvbkVycm9yOiAoZXJyb3I6IGFueSkgPT4gdm9pZCwgb3B0aW9uczogTG9hZE9wdGlvbnMpID0+IEVsZW1lbnRSZWY7XG5cbi8qKlxuICogUHJvdmlkZXMgbWV0aG9kcyBmb3IgbGF6eSBsb2FkaW5nIHNjcmlwdHMgYW5kIHN0eWxlcyBwcm9ncmFtYXRpY2FsbHkuXG4gKiBUaGUgc2VydmljZSBrZWVwcyB0cmFjayBvZiBsb2FkZWQgZmlsZXMgdG8gc2tpcCByZWxvYWRpbmcgdW5sZXNzIHNwZWNpZmllZCBvdGhlcndpc2UgaW4gdGhlIG9wdGlvbnMgb2YgYGxvYWRTY3JpcHQoKWAgb3IgYGxvYWRTdHlsZSgpYC5cbiAqL1xuQEluamVjdGFibGUoe1xuICAgIHByb3ZpZGVkSW46ICdyb290J1xufSlcbmV4cG9ydCBjbGFzcyBMYXp5TG9hZGVyU2VydmljZVxue1xuICAgIC8qKlxuICAgICAqIERlZmluZXMgdGhlIGRlZmF1bHQgb3B0aW9ucyB3aGVuIGNhbGxpbmcgdGhlIGBMYXp5TG9hZGVyU2VydmljZS5sb2FkU2NyaXB0KClgIG1ldGhvZC5cbiAgICAgKi9cbiAgICBwcml2YXRlIGRlZmF1bHRTY3JpcHRPcHRpb25zOiBTY3JpcHRMb2FkT3B0aW9ucyA9IHtcbiAgICAgICAgYXN5bmM6IHRydWUsXG4gICAgICAgIGRlZmVyOiB0cnVlLFxuICAgICAgICBhbHJlYWR5TG9hZGVkOiAodXJsKSA9PiB0aGlzLmlzQ2FjaGVkKHVybCkgfHwgdGhpcy5pc1NjcmlwdFByZXNlbnQodXJsKSxcbiAgICAgICAgZm9yY2U6IGZhbHNlXG4gICAgfTtcblxuICAgICAvKipcbiAgICAgKiBEZWZpbmVzIHRoZSBkZWZhdWx0IG9wdGlvbnMgd2hlbiBjYWxsaW5nIHRoZSBgTGF6eUxvYWRlclNlcnZpY2UubG9hZFN0eWxlKClgIG1ldGhvZC5cbiAgICAgKi9cbiAgICBwcml2YXRlIGRlZmF1bHRTdHlsZU9wdGlvbnM6IExvYWRPcHRpb25zID0ge1xuICAgICAgICBhbHJlYWR5TG9hZGVkOiAodXJsKSA9PiB0aGlzLmlzQ2FjaGVkKHVybCkgfHwgdGhpcy5pc1N0eWxlUHJlc2VudCh1cmwpLFxuICAgICAgICBmb3JjZTogZmFsc2VcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogS2VlcHMgdHJhY2sgb2YgbG9hZGVkIGxhenkgZmlsZXMgc3RhdHVzIGFuZCByZWZlcmVuY2VzXG4gICAgICovXG4gICAgcHJpdmF0ZSBjYWNoZTogeyBbdXJsOiBzdHJpbmddOiB7IGxhenlGaWxlOiBMYXp5TG9hZGVkRmlsZSwgb2JzZXJ2YWJsZTogT2JzZXJ2YWJsZTxMYXp5TG9hZGVkRmlsZT4gfSB9O1xuXG4gICAgY29uc3RydWN0b3IocHJpdmF0ZSBoZWFkOiBIZWFkU2VydmljZSwgcHJpdmF0ZSB1bml2ZXJzYWw6IFVuaXZlcnNhbFNlcnZpY2UpXG4gICAge1xuICAgICAgICB0aGlzLmNhY2hlID0ge307XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2hlY2tzIHdoZXRoZXIgdGhlIGZpbGUgZnJvbSB0aGUgc3BlY2lmaWVkIHVybCBoYXMgYWxyZWFkeSBiZWVuIGNhY2hlZC5cbiAgICAgKiBAcGFyYW0gdXJsIFRoZSB1cmwgZm9yIHRoZSBmaWxlIHRvIGNoZWNrLlxuICAgICAqIEByZXR1cm5zIEEgdmFsdWUgaW5kaWNhdGluZyB3aGV0aGVyIHRoZSBmaWxlIGZyb20gdGhlIHNwZWNpZmllZCB1cmwgaGFzIGFscmVhZHkgYmVlbiBjYWNoZWQuXG4gICAgICovXG4gICAgcHVibGljIGlzQ2FjaGVkKHVybDogc3RyaW5nKTogYm9vbGVhblxuICAgIHtcbiAgICAgICAgcmV0dXJuICEhdGhpcy5jYWNoZVt1cmxdO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENoZWNrcyB3aGV0aGVyIGEgc2NyaXB0IGVsZW1lbnQgaXMgYWxyZWFkeSBwcmVzZW50IGluIGA8aGVhZD5gIGZvciB0aGUgZ2l2ZW4gdXJsLlxuICAgICAqIFRoaXMgZG9lc24ndCBndWFyYW50ZWUgdGhhdCB0aGUgc2NyaXB0IGhhcyBiZWVuIGxvYWRlZC5cbiAgICAgKiBcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gdXJsIFRoZSB1cmwgb2YgdGhlIGxvYWRlZCBzY3JpcHQuXG4gICAgICogQHJldHVybnMge2Jvb2xlYW59IGB0cnVlYCBpZiBhbiBlbGVtZW50IG1hdGNoaW5nIHRoZSB1cmwgaXMgcHJlc2VudCBpbiBgPGhlYWQ+YDsgb3RoZXJ3aXNlIGBmYWxzZS5cbiAgICAgKi9cbiAgICBwdWJsaWMgaXNTY3JpcHRQcmVzZW50KHVybDogc3RyaW5nKTogYm9vbGVhblxuICAgIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuaGVhZC5jb250YWlucygnc2NyaXB0JywgeyBzcmM6IHVybCB9KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDaGVja3Mgd2hldGhlciBhIGxpbmsgZWxlbWVudCBpcyBhbHJlYWR5IHByZXNlbnQgaW4gYDxoZWFkPmAgZm9yIHRoZSBnaXZlbiBzdHlsZSB1cmwuXG4gICAgICogVGhpcyBkb2Vzbid0IGd1YXJhbnRlZSB0aGF0IHRoZSBzdHlsZSBoYXMgYmVlbiBsb2FkZWQuXG4gICAgICogXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHVybCBUaGUgdXJsIG9mIHRoZSBsb2FkZWQgbGluay5cbiAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gYHRydWVgIGlmIGFuIGVsZW1lbnQgbWF0Y2hpbmcgdGhlIHVybCBpcyBwcmVzZW50IGluIGA8aGVhZD5gOyBvdGhlcndpc2UgYGZhbHNlLlxuICAgICAqL1xuICAgIHB1YmxpYyBpc1N0eWxlUHJlc2VudCh1cmw6IHN0cmluZyk6IGJvb2xlYW5cbiAgICB7XG4gICAgICAgIHJldHVybiB0aGlzLmhlYWQuY29udGFpbnMoJ2xpbmsnLCB7IHJlbDogJ3N0eWxlc2hlZXQnLCBocmVmOiB1cmwgfSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogTG9hZHMgYSBzY3JpcHQgcHJvZ3JhbWF0aWNhbGx5LlxuICAgICAqXG4gICAgICogQHBhcmFtIHVybCBUaGUgZnVsbCB1cmwgb2YgdGhlIHNjcmlwdCB0byBsb2FkLlxuICAgICAqIEBwYXJhbSBvcHRpb25zIChPcHRpb25hbCkgU3BlY2lmaWVzIGN1c3RvbSBvcHRpb25zIHRvIG92ZXJyaWRlIGRlZmF1bHQgYmVoYXZpb3VyLlxuICAgICAqIEByZXR1cm5zIEFuIG9ic2VydmFibGUgb2JqZWN0IHdoaWNoIGFsbG93cyBzdWJzY3JpYmVycyB0byBrbm93IHdoZW4gdGhlIHNjcmlwdCBoYXMgYmVlbiBsb2FkZWQgYW5kIGFjY2VzcyBpdHMgYXNzb2NpYXRlZCBgPHNjcmlwdD5gIGVsZW1lbnQuXG4gICAgICogICAgICAgICAgVGhlIG9ic2VydmFibGUgd2lsbCBjb21wbGV0ZSBpbW1lZGlhdGVseSBpbiBjYXNlIHRoZSBzY3JpcHQgd2FzIGFscmVhZHkgcHJldmlvdXNseSBsb2FkZWQuXG4gICAgICogICAgICAgICAgSWYgdGhlIHNjcmlwdCB3YXMgYWxyZWFkeSBsb2FkZWQgb3V0c2lkZSBvZiB0aGUgc2VydmljZSwgdGhlIG9ic2VydmFibGUgd2lsbCBzdHJlYW0gYHVuZGVmaW5lZGAuXG4gICAgICovXG4gICAgcHVibGljIGxvYWRTY3JpcHQodXJsOiBzdHJpbmcsIG9wdGlvbnM6IFNjcmlwdExvYWRPcHRpb25zID0gdGhpcy5kZWZhdWx0U2NyaXB0T3B0aW9ucyk6IE9ic2VydmFibGU8TGF6eUxvYWRlZEZpbGUgfCBudWxsPlxuICAgIHtcbiAgICAgICAgLy8gU2V0IGRlZmF1bHQgb3B0aW9ucyBpZiBub3Qgc3BlY2lmaWVkIGJ5IGNhbGxlclxuICAgICAgICBvcHRpb25zLmFzeW5jICAgICAgICAgPSBvcHRpb25zLmFzeW5jICAgICAgICAgPT09IHVuZGVmaW5lZCA/IHRoaXMuZGVmYXVsdFNjcmlwdE9wdGlvbnMuYXN5bmMgOiBvcHRpb25zLmFzeW5jO1xuICAgICAgICBvcHRpb25zLmRlZmVyICAgICAgICAgPSBvcHRpb25zLmRlZmVyICAgICAgICAgPT09IHVuZGVmaW5lZCA/IHRoaXMuZGVmYXVsdFNjcmlwdE9wdGlvbnMuZGVmZXIgOiBvcHRpb25zLmRlZmVyO1xuICAgICAgICBvcHRpb25zLmFscmVhZHlMb2FkZWQgPSBvcHRpb25zLmFscmVhZHlMb2FkZWQgPT09IHVuZGVmaW5lZCA/IHRoaXMuZGVmYXVsdFNjcmlwdE9wdGlvbnMuYWxyZWFkeUxvYWRlZCA6IG9wdGlvbnMuYWxyZWFkeUxvYWRlZDtcbiAgICAgICAgb3B0aW9ucy5mb3JjZSAgICAgICAgID0gb3B0aW9ucy5mb3JjZSAgICAgICAgID09PSB1bmRlZmluZWQgPyB0aGlzLmRlZmF1bHRTY3JpcHRPcHRpb25zLmZvcmNlIDogb3B0aW9ucy5mb3JjZTsgICAgICAgICAgXG5cbiAgICAgICAgcmV0dXJuIHRoaXMubG9hZEZpbGUodXJsLCAnc2NyaXB0Jywgb3B0aW9ucyBhcyBSZXF1aXJlZDxTY3JpcHRMb2FkT3B0aW9ucz4sIHRoaXMuY3JlYXRlU2NyaXB0RWxlbWVudC5iaW5kKHRoaXMpKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBMb2FkcyBhIHN0eWxlIHByb2dyYW1hdGljYWxseS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB1cmwgVGhlIGZ1bGwgdXJsIG9mIHRoZSBzdHlsZSB0byBsb2FkLlxuICAgICAqIEBwYXJhbSBvcHRpb25zIChPcHRpb25hbCkgU3BlY2lmaWVzIGN1c3RvbSBvcHRpb25zIHRvIG92ZXJyaWRlIGRlZmF1bHQgYmVoYXZpb3VyLlxuICAgICAqIEByZXR1cm5zIEFuIG9ic2VydmFibGUgb2JqZWN0IHdoaWNoIGFsbG93cyBzdWJzY3JpYmVycyB0byBrbm93IHdoZW4gdGhlIHN0eWxlIGhhcyBiZWVuIGxvYWRlZCBhbmQgYWNjZXNzIGl0cyBhc3NvY2lhdGVkIGA8bGluaz5gIGVsZW1lbnQuXG4gICAgICogICAgICAgICAgVGhlIG9ic2VydmFibGUgd2lsbCBjb21wbGV0ZSBpbW1lZGlhdGVseSBpbiBjYXNlIHRoZSBzdHlsZSB3YXMgYWxyZWFkeSBwcmV2aW91c2x5IGxvYWRlZC5cbiAgICAgKiAgICAgICAgICBJZiB0aGUgc3R5bGUgd2FzIGFscmVhZHkgbG9hZGVkIG91dHNpZGUgb2YgdGhlIHNlcnZpY2UsIHRoZSBvYnNlcnZhYmxlIHdpbGwgc3RyZWFtIGB1bmRlZmluZWRgLlxuICAgICAqL1xuICAgIHB1YmxpYyBsb2FkU3R5bGUodXJsOiBzdHJpbmcsIG9wdGlvbnM6IExvYWRPcHRpb25zID0gdGhpcy5kZWZhdWx0U3R5bGVPcHRpb25zKTogT2JzZXJ2YWJsZTxMYXp5TG9hZGVkRmlsZSB8IG51bGw+XG4gICAge1xuICAgICAgICAvLyBTZXQgZGVmYXVsdCBvcHRpb25zIGlmIG5vdCBzcGVjaWZpZWQgYnkgY2FsbGVyXG4gICAgICAgIG9wdGlvbnMuYWxyZWFkeUxvYWRlZCA9IG9wdGlvbnMuYWxyZWFkeUxvYWRlZCA9PT0gdW5kZWZpbmVkID8gdGhpcy5kZWZhdWx0U3R5bGVPcHRpb25zLmFscmVhZHlMb2FkZWQgOiBvcHRpb25zLmFscmVhZHlMb2FkZWQ7XG4gICAgICAgIG9wdGlvbnMuZm9yY2UgICAgICAgICA9IG9wdGlvbnMuZm9yY2UgICAgICAgICA9PT0gdW5kZWZpbmVkID8gdGhpcy5kZWZhdWx0U3R5bGVPcHRpb25zLmZvcmNlIDogb3B0aW9ucy5mb3JjZTtcblxuICAgICAgICByZXR1cm4gdGhpcy5sb2FkRmlsZSh1cmwsICdzdHlsZScsIG9wdGlvbnMgYXMgUmVxdWlyZWQ8TG9hZE9wdGlvbnM+LCB0aGlzLmNyZWF0ZUxpbmtFbGVtZW50LmJpbmQodGhpcykpO1xuICAgIH1cblxuICAgIHByaXZhdGUgbG9hZEZpbGUodXJsOiBzdHJpbmcsIHR5cGU6ICdzY3JpcHQnIHwgJ3N0eWxlJywgb3B0aW9uczogUmVxdWlyZWQ8TG9hZE9wdGlvbnM+LCBjcmVhdGVFbGVtZW50OiBFbGVtZW50Q3JlYXRvcik6IE9ic2VydmFibGU8TGF6eUxvYWRlZEZpbGUgfCBudWxsPlxuICAgIHtcbiAgICAgICAgaWYgKCF0aGlzLnVuaXZlcnNhbC5pc1BsYXRmb3JtQnJvd3NlcikgcmV0dXJuIG9mKG51bGwpO1xuXG4gICAgICAgIC8vIElmIHRoZSBzY3JpcHQgc2hvdWxkIGJlIGxvYWRlZCwgbG9hZCBpdFxuICAgICAgICBpZiAoIW9wdGlvbnMuYWxyZWFkeUxvYWRlZCh1cmwpIHx8IG9wdGlvbnMuZm9yY2UpXG4gICAgICAgIHtcbiAgICAgICAgICAgIC8vIEluaXRpYWxpemUgYSBiYXNlIG9iamVjdCB0byBzdG9yZSB0aGUgZGF0YSBsYXRlclxuICAgICAgICAgICAgY29uc3QgbGF6eUZpbGU6IExhenlMb2FkZWRGaWxlID0geyB1cmwsIHR5cGUsIGNvbXBsZXRlZDogZmFsc2UsIGVsZW1lbnQ6IG51bGwgfTtcbiAgICAgICAgICAgIC8vIENyZWF0ZSBhbiBvYnNlcnZhYmxlIHRoYXQgd2FpdHMgdW50aWwgdGhlIHNjcmlwdCBoYXMgYmVlbiBsb2FkZWQgYW5kIGV4ZWN1dGVkXG4gICAgICAgICAgICBjb25zdCBvYnNlcnZhYmxlID0gbmV3IE9ic2VydmFibGU8TGF6eUxvYWRlZEZpbGU+KG9ic2VydmVyID0+XG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgLy8gQ3JlYXRlIHRoZSBjYWxsYmFjayB0aGF0IHdpbGwgbWFyayB0aGUgc2NyaXB0IGFzIGNvbXBsZXRlZCBhbmQgbm90aWZ5IHRoZSBzdWJzY3JpYmVyXG4gICAgICAgICAgICAgICAgY29uc3Qgb25Mb2FkID0gKCkgPT5cbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGxhenlGaWxlLmNvbXBsZXRlZCA9IHRydWU7XG5cbiAgICAgICAgICAgICAgICAgICAgb2JzZXJ2ZXIubmV4dChsYXp5RmlsZSk7XG4gICAgICAgICAgICAgICAgICAgIG9ic2VydmVyLmNvbXBsZXRlKCk7XG4gICAgICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgICAgIC8vIENyZWF0ZSB0aGUgYWN0dWFsIGZpbGUgdGFnLCBzdGFydCBkb3dubG9hZGluZyBhbmQgc3RvcmUgdGhlIGVsZW1lbnQgcmVmZXJlbmNlXG4gICAgICAgICAgICAgICAgbGF6eUZpbGUuZWxlbWVudCA9IGNyZWF0ZUVsZW1lbnQodXJsLCBvbkxvYWQsIG9ic2VydmVyLmVycm9yLmJpbmQob2JzZXJ2ZXIpLCBvcHRpb25zKTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAvLyBDYWNoZSB0aGUgZmlsZSBhbmQgdGhlIG9ic2VydmFibGUgZm9yIGxhdGVyIHVzZVxuICAgICAgICAgICAgdGhpcy5jYWNoZVt1cmxdID0geyBsYXp5RmlsZTogbGF6eUZpbGUsIG9ic2VydmFibGUgfTtcblxuICAgICAgICAgICAgcmV0dXJuIG9ic2VydmFibGU7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBJZiB0aGUgZmlsZSB3YXMgYWxyZWFkeSBsb2FkZWQgYW5kIGl0IHNob3VsZG4ndCBiZSBkb3dubG9hZGVkIGFnYWluLCBjb21wbGV0ZSBpbW1lZGlhdGVseSB3aXRoIHRoZSBwcmV2aW91cyBsaW5rIGRhdGEuXG4gICAgICAgIC8vIElmIHRoZSBmaWxlIHdhcyBhbHJlYWR5IGxvYWRlZCBvdXRzaWRlIG9mIHRoZSBzZXJ2aWNlLCB0aGUgb2JzZXJ2YWJsZSB3aWxsIHN0cmVhbSBgdW5kZWZpbmVkYCBhcyB0aGVyZSBpcyBub3RoaW5nIGNhY2hlZC5cbiAgICAgICAgcmV0dXJuIG9mKHRoaXMuY2FjaGVbdXJsXT8ubGF6eUZpbGUpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYSBgPHNjcmlwdD5gIHRhZyBmb3IgdGhlIGdpdmVuIHVybCBhbmQgYWRkcyBpdCB0byB0aGUgYDxoZWFkPmAgdGFnIHRvIHN0YXJ0IGRvd25sb2FkaW5nIHRoZSBzY3JpcHQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gdXJsICAgICAgIFRoZSB1cmwgZm9yIHRoZSBzY3JpcHQgdG8gZG93bmxvYWQuXG4gICAgICogQHBhcmFtIG9uTG9hZCAgICBUaGUgY2FsbGJhY2sgdG8gZXhlY3V0ZSB3aGVuIHRoZSBzY3JpcHQgaGFzIGJlZW4gZG93bmxvYWRlZCBhbmQgZXhlY3V0ZWQuXG4gICAgICogQHBhcmFtIG9uRXJyb3IgICBUaGUgY2FsbGJhY2sgdG8gZXhlY3V0ZSB3aGVuIHNjcmlwdCBkb3dubG9hZCBvciBleGVjdXRpb24gaGFzIGZhaWxlZC5cbiAgICAgKiBAcGFyYW0gb3B0aW9ucyAgIFRoZSBvcHRpb25zIHRvIGFkZCB0byB0aGUgc2NyaXB0LlxuICAgICAqIEByZXR1cm5zIEEgcmVmZXJlbmNlIHRvIHRoZSBgPHNjcmlwdD5gIGVsZW1lbnQgdGhhdCB3YXMgYWRkZWQgdG8gdGhlIERPTS5cbiAgICAgKi9cbiAgICBwcml2YXRlIGNyZWF0ZVNjcmlwdEVsZW1lbnQodXJsOiBzdHJpbmcsIG9uTG9hZDogKCkgPT4gdm9pZCwgb25FcnJvcjogKGVycm9yOiBhbnkpID0+IHZvaWQsIG9wdGlvbnM6IFNjcmlwdExvYWRPcHRpb25zKTogRWxlbWVudFJlZjxIVE1MU2NyaXB0RWxlbWVudD5cbiAgICB7XG4gICAgICAgIHJldHVybiB0aGlzLmhlYWQuYWRkU2NyaXB0RWxlbWVudCgndGV4dC9qYXZhc2NyaXB0JywgdXJsLFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGFzeW5jOiBvcHRpb25zLmFzeW5jLFxuICAgICAgICAgICAgICAgIGRlZmVyOiBvcHRpb25zLmRlZmVyLFxuICAgICAgICAgICAgICAgIG9ubG9hZDogb25Mb2FkLFxuICAgICAgICAgICAgICAgIG9uZXJyb3I6IG9uRXJyb3JcbiAgICAgICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYSBgPGxpbms+YCB0YWcgZm9yIHRoZSBnaXZlbiB1cmwgYW5kIGFkZHMgaXQgdG8gdGhlIGA8aGVhZD5gIHRhZyB0byBzdGFydCBkb3dubG9hZGluZyB0aGUgbGluay5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB1cmwgICAgICAgVGhlIHVybCBmb3IgdGhlIGxpbmsgdG8gZG93bmxvYWQuXG4gICAgICogQHBhcmFtIG9uTG9hZCAgICBUaGUgY2FsbGJhY2sgdG8gZXhlY3V0ZSB3aGVuIHRoZSBzY3JpcHQgaGFzIGJlZW4gZG93bmxvYWRlZCBhbmQgZXhlY3V0ZWQuXG4gICAgICogQHBhcmFtIG9uRXJyb3IgICBUaGUgY2FsbGJhY2sgdG8gZXhlY3V0ZSB3aGVuIHNjcmlwdCBkb3dubG9hZCBvciBleGVjdXRpb24gaGFzIGZhaWxlZC5cbiAgICAgKiBAcmV0dXJucyBBIHJlZmVyZW5jZSB0byB0aGUgYDxsaW5rPmAgZWxlbWVudCB0aGF0IHdhcyBhZGRlZCB0byB0aGUgRE9NLlxuICAgICAqL1xuICAgIHByaXZhdGUgY3JlYXRlTGlua0VsZW1lbnQodXJsOiBzdHJpbmcsIG9uTG9hZDogKCkgPT4gdm9pZCwgb25FcnJvcjogKGVycm9yOiBhbnkpID0+IHZvaWQpOiBFbGVtZW50UmVmPEhUTUxMaW5rRWxlbWVudD5cbiAgICB7XG4gICAgICAgIHJldHVybiB0aGlzLmhlYWQuYWRkTGlua0VsZW1lbnQoJ3N0eWxlc2hlZXQnLFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHR5cGU6ICd0ZXh0L2NzcycsXG4gICAgICAgICAgICAgICAgaHJlZjogdXJsLFxuICAgICAgICAgICAgICAgIG9ubG9hZDogb25Mb2FkLFxuICAgICAgICAgICAgICAgIG9uZXJyb3I6IG9uRXJyb3JcbiAgICAgICAgICAgIH0pO1xuICAgIH1cbn1cbiJdfQ==