UNPKG

@angulogic/ng-sidebar

Version:

angular sidebar - standalone components

440 lines 58 kB
import { Injectable } from '@angular/core'; import { NavigationEnd } from '@angular/router'; import { BehaviorSubject } from 'rxjs'; import * as i0 from "@angular/core"; import * as i1 from "@angular/router"; import * as i2 from "@angular/common/http"; /** * Service responsible for managing sidebar state, configurations, and behaviors. * It handles sidebar initialization, resizing, menu interactions, and theme changes. * * @export * @class NgSidebarService */ export class NgSidebarService { /** * Initializes the sidebar service and listens for route changes. * * @param {Router} router - Angular Router for detecting navigation events. * @param {HttpClient} http - Angular HttpClient for loading assets (e.g., SVG icons). */ constructor(router, http) { this.router = router; this.http = http; /** * Tracks whether auto-positioning is enabled. * @default false */ this.autoPositionActive = false; /** * Indicates whether the sidebar is currently being resized. * @default false */ this.isResizing = false; /** * Sidebar genişliğini tutan observable. */ this.sidebarWidth$ = new BehaviorSubject(0); router.events.subscribe(route => { if (route instanceof NavigationEnd && this.sidebarData && this.sidebarData.sidebarData) { this.sidebarData.sidebarData.forEach(data => { this.updateActiveState(data.data, route.url); }); } }); } /** * Initializes the sidebar configuration with default values if not provided. * * @param {Partial<SidebarModel> & { sidebarData: SidebarData[] }} data - Sidebar data with optional configurations. * @returns {SidebarModel} - The complete SidebarModel with default values applied. */ initilazeSidebarData(data) { // Banner options data.bannerOptions = data.bannerOptions ? { logo: data.bannerOptions.logo ?? 'assets/icons/angular-logo.png', title: data.bannerOptions.title ?? 'Angulogic', onClick: data.bannerOptions.onClick, } : undefined; // User options data.userOptions = data.userOptions ? { avatar: data.userOptions.avatar ?? 'assets/icons/avatar.svg', name: data.userOptions.name, position: data.userOptions.position ?? 'bottom', onClick: data.userOptions.onClick, } : undefined; // Search options data.searchOptions = data.searchOptions ? { placeholder: data.searchOptions.placeholder, caseSensitive: data.searchOptions.caseSensitive ?? false, strategy: data.searchOptions.strategy ?? 'contains', cssClass: data.searchOptions.cssClass, localCompare: data.searchOptions.localCompare ?? 'en', onSearchStart: data.searchOptions.onSearchStart, onSearchEnd: data.searchOptions.onSearchEnd, } : undefined; // Sidebar data initialization data.sidebarData = data.sidebarData.map(item => ({ title: item.title, cssClass: item.cssClass, visible: item.visible ?? true, data: this.initializeMenuData(item.data), })); // Sidebar options initialization data.options = data.options ? { resize: data.options.resize ?? true, expand: data.options.expand ?? true, favorites: data.options.favorites ?? true, favoritesTitle: data.options.favoritesTitle ?? 'Favorites', search: data.options.search ?? true, cssClass: data.options.cssClass ?? '', viewMode: data.options.viewMode ?? 'toggle', theme: data.options.theme ?? 'light', themePicker: data.options.themePicker ?? true, minWidth: data.options.minWidth ?? 300, maxWidth: data.options.maxWidth ?? 500, width: data.options.width ?? 300, themeText: data.options.themeText ?? { light: 'Light', dark: 'Dark' }, autoPosition: data.options.autoPosition ?? true, toggleCollapseIcon: data.options.toggleCollapseIcon ?? 'assets/icons/collapse.svg', toggleExpandIcon: data.options.toggleExpandIcon ?? 'assets/icons/expand.svg', pinIcon: data.options.pinIcon ?? 'assets/icons/pin.svg', unpinIcon: data.options.unpinIcon ?? 'assets/icons/unpin.svg', closeIcon: data.options.closeIcon ?? 'assets/icons/cancel.svg', pinned: data.options.pinned ?? (data.options.expand && data.options.viewMode === 'hover') ?? false, onThemeChange: data.options.onThemeChange, onResizeStart: data.options.onResizeStart, onResizing: data.options.onResizing, onResizeEnd: data.options.onResizeEnd, onExpand: data.options.onExpand, onCollapse: data.options.onCollapse, onMenuNodeClick: data.options.onMenuNodeClick, } : { resize: true, expand: true, favorites: true, search: true, viewMode: 'toggle', theme: 'light', }; this.sidebarData = data; return data; } /** * Enables automatic positioning of the sidebar. * It observes the sidebar's width and updates the CSS variable `--sidebar-width` dynamically. */ setAutoPosition() { const divElement = document.getElementById('ng-sidebar'); if (!divElement) { return; } if (!document.body.classList.contains('auto-position')) { document.body.classList.add('auto-position'); } const duration = 300; this.observer = new MutationObserver(() => { const width = divElement.offsetWidth; this.updateWidth(divElement, performance.now(), duration); document.documentElement.style.setProperty('--sidebar-width', `${width}px`); }); this.observer.observe(divElement, { attributeFilter: ['style'], }); this.autoPositionActive = true; console.log('Auto position enabled'); } /** * Animates the width update of the sidebar. * * @param {HTMLElement} divElement - The sidebar element whose width is being updated. * @param {number} startTime - The start time of the animation. * @param {number} duration - The duration of the width animation in milliseconds. */ updateWidth(divElement, startTime, duration) { const animateWidth = (timestamp) => { let progress = (timestamp - startTime) / duration; const currentWidth = divElement.offsetWidth; document.documentElement.style.setProperty('--sidebar-width', `${currentWidth}px`); if (progress < 1) { requestAnimationFrame(animateWidth); } }; requestAnimationFrame(animateWidth); } /** * Disables automatic positioning of the sidebar. * Stops observing style changes and resets CSS modifications. */ destroyAutoPosition() { this.observer.disconnect(); if (document.body.classList.contains('auto-position')) { document.body.classList.remove('auto-position'); } this.autoPositionActive = false; console.log('Auto position disabled'); } /** * Handles sidebar resizing using mouse events. * * @param {SidebarModel} sidebarData - The sidebar configuration object. */ resize(sidebarData) { // Check if sidebarData and options are initialized if (!sidebarData || !sidebarData.options) { return; } this.isResizing = true; const initialPin = sidebarData.options.pinned; sidebarData.options.pinned = true; const divElement = document.getElementById('ng-sidebar'); const startEvent = { cancel: false, sidebarOptions: sidebarData, nativeElement: divElement, }; if (sidebarData.options.onResizeStart) { sidebarData.options.onResizeStart(startEvent); if (startEvent.cancel) { this.isResizing = false; return; } } document.body.classList.add('no-select'); /** * Handles mouse movement during resizing. * * @param {MouseEvent} e - The mouse movement event. */ const mouseMoveListener = (e) => { const resizeEvent = { cancel: false, sidebarOptions: sidebarData, mouseEvent: e, nativeElement: divElement, }; if (sidebarData.options.onResizing) { sidebarData.options.onResizing(resizeEvent); if (resizeEvent.cancel) { return; } } if (sidebarData.options.minWidth && e.clientX < sidebarData.options.minWidth) { sidebarData.options.width = sidebarData.options.minWidth; } else if (sidebarData.options.maxWidth && e.clientX > sidebarData.options.maxWidth) { sidebarData.options.width = sidebarData.options.maxWidth; } else { sidebarData.options.width = e.clientX; } }; document.addEventListener('mousemove', mouseMoveListener); /** * Handles mouse release after resizing. * * @param {MouseEvent} e - The mouse up event. */ const mouseUpListener = (e) => { document.body.classList.remove('no-select'); document.removeEventListener('mousemove', mouseMoveListener); document.removeEventListener('mouseup', mouseUpListener); this.isResizing = false; sidebarData.options.pinned = initialPin; const endEvent = { sidebarOptions: sidebarData, mouseEvent: e, nativeElement: divElement, }; if (sidebarData.options.onResizeEnd) { sidebarData.options.onResizeEnd(endEvent); } }; document.addEventListener('mouseup', mouseUpListener); } /** * Initializes menu data by assigning default values if not provided. * * @param {MenuData[]} menuData - The menu data array to initialize. * @returns {MenuData[]} - The processed menu data with default values applied. */ initializeMenuData(menuData) { return menuData.map(item => { item['name'] = item['name']; item['icon'] = item['icon']; item['route'] = item['route']; item['visible'] = item['visible'] ?? true; item['disabled'] = item['disabled'] ?? false; item['isExpanded'] = item['isExpanded'] ?? false; item['isFavorited'] = item['isFavorited'] ?? false; item['cssClass'] = item['cssClass']; item['active'] = item['active'] ?? false; item['children'] = item['children'] ? this.initializeMenuData(item['children']) : undefined; item['onClick'] = item['onClick']; return item; }); } /** * Searches for menu items by name within the sidebar data. * * @param {SidebarModel} data - The sidebar configuration containing menu data. * @param {string} searchValue - The search query entered by the user. * @returns {MenuData[]} - An array of matching menu items. */ searchByName(data, searchValue) { const { searchOptions, sidebarData } = data; /** * Compares two strings based on the configured search options. * * @param {string} source - The original menu item name. * @param {string} target - The search query entered by the user. * @returns {boolean} - True if the search criteria match, false otherwise. */ const compareStrings = (source, target) => { if (!searchOptions?.caseSensitive) { source = source.toLocaleLowerCase(searchOptions?.localCompare); target = target.toLocaleLowerCase(searchOptions?.localCompare); } switch (searchOptions?.strategy) { case 'contains': return source.includes(target); case 'startsWith': return source.startsWith(target); case 'endsWith': return source.endsWith(target); case 'equal': return source === target; default: return false; } }; /** * Recursively searches menu items and their children. * * @param {MenuData[]} data - The menu items to search in. * @returns {MenuData[]} - The filtered menu items. */ const searchInMenuData = (data) => { const resultSet = new Set(); data.forEach(item => { if (compareStrings(item.name, searchValue)) { resultSet.add(item); } if (item.children && item.children.length > 0) { const childResults = searchInMenuData(item.children); if (childResults.length > 0) { item.children = childResults; resultSet.add(item); } } }); return Array.from(resultSet); }; return sidebarData.flatMap(sidebarItem => searchInMenuData(sidebarItem.data)); } /** * Updates the active state of menu items based on the current route. * * @param {MenuData[]} menuData - The menu data array to update. * @param {string} currentRoute - The current active route. */ updateActiveState(menuData, currentRoute) { menuData.forEach(item => { if (item.route?.startsWith('/')) { item.active = item.route === currentRoute; } else { item.active = `/${item.route}` === currentRoute; } if (item.children) { this.updateActiveState(item.children, currentRoute); } }); } /** * Toggles the sidebar theme between 'light' and 'dark'. * Updates the `theme` property in `sidebarData.options`. */ changeTheme() { // Check if sidebarData and options are initialized if (!this.sidebarData || !this.sidebarData.options) { return; } if (this.sidebarData.options.theme === 'light') { this.sidebarData.options.theme = 'dark'; } else { this.sidebarData.options.theme = 'light'; } // Trigger theme change event if provided if (this.sidebarData.options.onThemeChange) { this.sidebarData.options.onThemeChange(this.sidebarData.options.theme); } } /** * Loads an SVG file from the given path. * * @param {string} path - The file path of the SVG to load. * @returns {Promise<string>} - A promise resolving to the SVG content. */ loadSvg(path) { return new Promise((resolve, reject) => { this.http.get(path, { responseType: 'text' }).subscribe({ next: svgContent => resolve(svgContent), error: err => reject(new Error(`Failed to load SVG: ${path}. Error: ${err.message}`)), }); }); } /** * Toggles the sidebar's expanded or collapsed state. * Triggers the appropriate expand/collapse event if provided. */ async toggleSidebar() { // Check if sidebarData and options are initialized if (!this.sidebarData || !this.sidebarData.options) { return; } const divElement = document.getElementById('ng-sidebar'); let event = { cancel: false, click: true, nativeElement: divElement, }; // Trigger collapse event if sidebar is currently expanded if (this.sidebarData.options.expand) { await Promise.resolve(this.sidebarData.options.onCollapse?.(event)); } // Trigger expand event if sidebar is currently collapsed else { await Promise.resolve(this.sidebarData.options.onExpand?.(event)); } // If the event was canceled, do not toggle if (event.cancel) return; // Toggle expand/collapse state this.sidebarData.options.expand = !this.sidebarData.options.expand; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NgSidebarService, deps: [{ token: i1.Router }, { token: i2.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NgSidebarService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NgSidebarService, decorators: [{ type: Injectable, args: [{ providedIn: 'root', }] }], ctorParameters: () => [{ type: i1.Router }, { type: i2.HttpClient }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmctc2lkZWJhci5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvbmctc2lkZWJhci9zcmMvbGliL25nLXNpZGViYXIuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBUTNDLE9BQU8sRUFBRSxhQUFhLEVBQVUsTUFBTSxpQkFBaUIsQ0FBQztBQUV4RCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sTUFBTSxDQUFDOzs7O0FBRXZDOzs7Ozs7R0FNRztBQUlILE1BQU0sT0FBTyxnQkFBZ0I7SUE4QjNCOzs7OztPQUtHO0lBQ0gsWUFDUyxNQUFjLEVBQ2IsSUFBZ0I7UUFEakIsV0FBTSxHQUFOLE1BQU0sQ0FBUTtRQUNiLFNBQUksR0FBSixJQUFJLENBQVk7UUFyQzFCOzs7V0FHRztRQUNILHVCQUFrQixHQUFZLEtBQUssQ0FBQztRQUVwQzs7O1dBR0c7UUFDSCxlQUFVLEdBQVksS0FBSyxDQUFDO1FBWTVCOztXQUVHO1FBQ0ksa0JBQWEsR0FBNEIsSUFBSSxlQUFlLENBQ2pFLENBQUMsQ0FDRixDQUFDO1FBWUEsTUFBTSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLEVBQUU7WUFDOUIsSUFBSSxLQUFLLFlBQVksYUFBYSxJQUFJLElBQUksQ0FBQyxXQUFXLElBQUksSUFBSSxDQUFDLFdBQVcsQ0FBQyxXQUFXLEVBQUUsQ0FBQztnQkFDdkYsSUFBSSxDQUFDLFdBQVcsQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxFQUFFO29CQUMxQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7Z0JBQy9DLENBQUMsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVEOzs7OztP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TyxDQUFDLFFBQVEsRUFBRSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7UUFDcEUsQ0FBQztRQUVELDJDQUEyQztRQUMzQyxJQUFJLEtBQUssQ0FBQyxNQUFNO1lBQUUsT0FBTztRQUV6QiwrQkFBK0I7UUFDL0IsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDO0lBQ3JFLENBQUM7K0dBamZVLGdCQUFnQjttSEFBaEIsZ0JBQWdCLGNBRmYsTUFBTTs7NEZBRVAsZ0JBQWdCO2tCQUg1QixVQUFVO21CQUFDO29CQUNWLFVBQVUsRUFBRSxNQUFNO2lCQUNuQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHtcclxuICBFeHBhbmRDbGlja0V2ZW50LFxyXG4gIE1lbnVEYXRhLFxyXG4gIFJlc2l6ZUV2ZW50LFxyXG4gIFNpZGViYXJEYXRhLFxyXG4gIFNpZGViYXJNb2RlbCxcclxufSBmcm9tICcuL3NpZGViYXIubW9kZWwnO1xyXG5pbXBvcnQgeyBOYXZpZ2F0aW9uRW5kLCBSb3V0ZXIgfSBmcm9tICdAYW5ndWxhci9yb3V0ZXInO1xyXG5pbXBvcnQgeyBIdHRwQ2xpZW50IH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnO1xyXG5pbXBvcnQgeyBCZWhhdmlvclN1YmplY3QgfSBmcm9tICdyeGpzJztcclxuXHJcbi8qKlxyXG4gKiBTZXJ2aWNlIHJlc3BvbnNpYmxlIGZvciBtYW5hZ2luZyBzaWRlYmFyIHN0YXRlLCBjb25maWd1cmF0aW9ucywgYW5kIGJlaGF2aW9ycy5cclxuICogSXQgaGFuZGxlcyBzaWRlYmFyIGluaXRpYWxpemF0aW9uLCByZXNpemluZywgbWVudSBpbnRlcmFjdGlvbnMsIGFuZCB0aGVtZSBjaGFuZ2VzLlxyXG4gKlxyXG4gKiBAZXhwb3J0XHJcbiAqIEBjbGFzcyBOZ1NpZGViYXJTZXJ2aWNlXHJcbiAqL1xyXG5ASW5qZWN0YWJsZSh7XHJcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnLFxyXG59KVxyXG5leHBvcnQgY2xhc3MgTmdTaWRlYmFyU2VydmljZSB7XHJcbiAgLyoqXHJcbiAgICogVHJhY2tzIHdoZXRoZXIgYXV0by1wb3NpdGlvbmluZyBpcyBlbmFibGVkLlxyXG4gICAqIEBkZWZhdWx0IGZhbHNlXHJcbiAgICovXHJcbiAgYXV0b1Bvc2l0aW9uQWN0aXZlOiBib29sZWFuID0gZmFsc2U7XHJcblxyXG4gIC8qKlxyXG4gICAqIEluZGljYXRlcyB3aGV0aGVyIHRoZSBzaWRlYmFyIGlzIGN1cnJlbnRseSBiZWluZyByZXNpemVkLlxyXG4gICAqIEBkZWZhdWx0IGZhbHNlXHJcbiAgICovXHJcbiAgaXNSZXNpemluZzogYm9vbGVhbiA9IGZhbHNlO1xyXG5cclxuICAvKipcclxuICAgKiBTdG9yZXMgdGhlIGNvbXBsZXRlIHNpZGViYXIgY29uZmlndXJhdGlvbiBhbmQgZGF0YS5cclxuICAgKi9cclxuICBzaWRlYmFyRGF0YSE6IFNpZGViYXJNb2RlbDtcclxuXHJcbiAgLyoqXHJcbiAgICogTXV0YXRpb25PYnNlcnZlciB0byBtb25pdG9yIHNpZGViYXIgc3R5bGUgY2hhbmdlcyBmb3IgYXV0by1wb3NpdGlvbmluZy5cclxuICAgKi9cclxuICBwcml2YXRlIG9ic2VydmVyITogTXV0YXRpb25PYnNlcnZlcjtcclxuXHJcbiAgLyoqXHJcbiAgICogU2lkZWJhciBnZW5pxZ9sacSfaW5pIHR1dGFuIG9ic2VydmFibGUuXHJcbiAgICovXHJcbiAgcHVibGljIHNpZGViYXJXaWR0aCQ6IEJlaGF2aW9yU3ViamVjdDxudW1iZXI+ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxudW1iZXI+KFxyXG4gICAgMFxyXG4gICk7XHJcblxyXG4gIC8qKlxyXG4gICAqIEluaXRpYWxpemVzIHRoZSBzaWRlYmFyIHNlcnZpY2UgYW5kIGxpc3RlbnMgZm9yIHJvdXRlIGNoYW5nZXMuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge1JvdXRlcn0gcm91dGVyIC0gQW5ndWxhciBSb3V0ZXIgZm9yIGRldGVjdGluZyBuYXZpZ2F0aW9uIGV2ZW50cy5cclxuICAgKiBAcGFyYW0ge0h0dHBDbGllbnR9IGh0dHAgLSBBbmd1bGFyIEh0dHBDbGllbnQgZm9yIGxvYWRpbmcgYXNzZXRzIChlLmcuLCBTVkcgaWNvbnMpLlxyXG4gICAqL1xyXG4gIGNvbnN0cnVjdG9yKFxyXG4gICAgcHVibGljIHJvdXRlcjogUm91dGVyLFxyXG4gICAgcHJpdmF0ZSBodHRwOiBIdHRwQ2xpZW50XHJcbiAgKSB7XHJcbiAgICByb3V0ZXIuZXZlbnRzLnN1YnNjcmliZShyb3V0ZSA9PiB7XHJcbiAgICAgIGlmIChyb3V0ZSBpbnN0YW5jZW9mIE5hdmlnYXRpb25FbmQgJiYgdGhpcy5zaWRlYmFyRGF0YSAmJiB0aGlzLnNpZGViYXJEYXRhLnNpZGViYXJEYXRhKSB7XHJcbiAgICAgICAgdGhpcy5zaWRlYmFyRGF0YS5zaWRlYmFyRGF0YS5mb3JFYWNoKGRhdGEgPT4ge1xyXG4gICAgICAgICAgdGhpcy51cGRhdGVBY3RpdmVTdGF0ZShkYXRhLmRhdGEsIHJvdXRlLnVybCk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogSW5pdGlhbGl6ZXMgdGhlIHNpZGViYXIgY29uZmlndXJhdGlvbiB3aXRoIGRlZmF1bHQgdmFsdWVzIGlmIG5vdCBwcm92aWRlZC5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7UGFydGlhbDxTaWRlYmFyTW9kZWw+ICYgeyBzaWRlYmFyRGF0YTogU2lkZWJhckRhdGFbXSB9fSBkYXRhIC0gU2lkZWJhciBkYXRhIHdpdGggb3B0aW9uYWwgY29uZmlndXJhdGlvbnMuXHJcbiAgICogQHJldHVybnMge1NpZGViYXJNb2RlbH0gLSBUaGUgY29tcGxldGUgU2lkZWJhck1vZGVsIHdpdGggZGVmYXVsdCB2YWx1ZXMgYXBwbGllZC5cclxuICAgKi9cclxuICBpbml0aWxhemVTaWRlYmFyRGF0YShcclxuICAgIGRhdGE6IFBhcnRpYWw8U2lkZWJhck1vZGVsPiAmIHsgc2lkZWJhckRhdGE6IFNpZGViYXJEYXRhW10gfVxyXG4gICk6IFNpZGViYXJNb2RlbCB7XHJcbiAgICAvLyBCYW5uZXIgb3B0aW9uc1xyXG4gICAgZGF0YS5iYW5uZXJPcHRpb25zID0gZGF0YS5iYW5uZXJPcHRpb25zXHJcbiAgICAgID8ge1xyXG4gICAgICAgICAgbG9nbzogZGF0YS5iYW5uZXJPcHRpb25zLmxvZ28gPz8gJ2Fzc2V0cy9pY29ucy9hbmd1bGFyLWxvZ28ucG5nJyxcclxuICAgICAgICAgIHRpdGxlOiBkYXRhLmJhbm5lck9wdGlvbnMudGl0bGUgPz8gJ0FuZ3Vsb2dpYycsXHJcbiAgICAgICAgICBvbkNsaWNrOiBkYXRhLmJhbm5lck9wdGlvbnMub25DbGljayxcclxuICAgICAgICB9XHJcbiAgICAgIDogdW5kZWZpbmVkO1xyXG5cclxuICAgIC8vIFVzZXIgb3B0aW9uc1xyXG4gICAgZGF0YS51c2VyT3B0aW9ucyA9IGRhdGEudXNlck9wdGlvbnNcclxuICAgICAgPyB7XHJcbiAgICAgICAgICBhdmF0YXI6IGRhdGEudXNlck9wdGlvbnMuYXZhdGFyID8/ICdhc3NldHMvaWNvbnMvYXZhdGFyLnN2ZycsXHJcbiAgICAgICAgICBuYW1lOiBkYXRhLnVzZXJPcHRpb25zLm5hbWUsXHJcbiAgICAgICAgICBwb3NpdGlvbjogZGF0YS51c2VyT3B0aW9ucy5wb3NpdGlvbiA/PyAnYm90dG9tJyxcclxuICAgICAgICAgIG9uQ2xpY2s6IGRhdGEudXNlck9wdGlvbnMub25DbGljayxcclxuICAgICAgICB9XHJcbiAgICAgIDogdW5kZWZpbmVkO1xyXG5cclxuICAgIC8vIFNlYXJjaCBvcHRpb25zXHJcbiAgICBkYXRhLnNlYXJjaE9wdGlvbnMgPSBkYXRhLnNlYXJjaE9wdGlvbnNcclxuICAgICAgPyB7XHJcbiAgICAgICAgICBwbGFjZWhvbGRlcjogZGF0YS5zZWFyY2hPcHRpb25zLnBsYWNlaG9sZGVyLFxyXG4gICAgICAgICAgY2FzZVNlbnNpdGl2ZTogZGF0YS5zZWFyY2hPcHRpb25zLmNhc2VTZW5zaXRpdmUgPz8gZmFsc2UsXHJcbiAgICAgICAgICBzdHJhdGVneTogZGF0YS5zZWFyY2hPcHRpb25zLnN0cmF0ZWd5ID8/ICdjb250YWlucycsXHJcbiAgICAgICAgICBjc3NDbGFzczogZGF0YS5zZWFyY2hPcHRpb25zLmNzc0NsYXNzLFxyXG4gICAgICAgICAgbG9jYWxDb21wYXJlOiBkYXRhLnNlYXJjaE9wdGlvbnMubG9jYWxDb21wYXJlID8/ICdlbicsXHJcbiAgICAgICAgICBvblNlYXJjaFN0YXJ0OiBkYXRhLnNlYXJjaE9wdGlvbnMub25TZWFyY2hTdGFydCxcclxuICAgICAgICAgIG9uU2VhcmNoRW5kOiBkYXRhLnNlYXJjaE9wdGlvbnMub25TZWFyY2hFbmQsXHJcbiAgICAgICAgfVxyXG4gICAgICA6IHVuZGVmaW5lZDtcclxuXHJcbiAgICAvLyBTaWRlYmFyIGRhdGEgaW5pdGlhbGl6YXRpb25cclxuICAgIGRhdGEuc2lkZWJhckRhdGEgPSBkYXRhLnNpZGViYXJEYXRhLm1hcChpdGVtID0+ICh7XHJcbiAgICAgIHRpdGxlOiBpdGVtLnRpdGxlLFxyXG4gICAgICBjc3NDbGFzczogaXRlbS5jc3NDbGFzcyxcclxuICAgICAgdmlzaWJsZTogaXRlbS52aXNpYmxlID8/IHRydWUsXHJcbiAgICAgIGRhdGE6IHRoaXMuaW5pdGlhbGl6ZU1lbnVEYXRhKGl0ZW0uZGF0YSksXHJcbiAgICB9KSk7XHJcblxyXG4gICAgLy8gU2lkZWJhciBvcHRpb25zIGluaXRpYWxpemF0aW9uXHJcbiAgICBkYXRhLm9wdGlvbnMgPSBkYXRhLm9wdGlvbnNcclxuICAgICAgPyB7XHJcbiAgICAgICAgICByZXNpemU6IGRhdGEub3B0aW9ucy5yZXNpemUgPz8gdHJ1ZSxcclxuICAgICAgICAgIGV4cGFuZDogZGF0YS5vcHRpb25zLmV4cGFuZCA/PyB0cnVlLFxyXG4gICAgICAgICAgZmF2b3JpdGVzOiBkYXRhLm9wdGlvbnMuZmF2b3JpdGVzID8/IHRydWUsXHJcbiAgICAgICAgICBmYXZvcml0ZXNUaXRsZTogZGF0YS5vcHRpb25zLmZhdm9yaXRlc1RpdGxlID8/ICdGYXZvcml0ZXMnLFxyXG4gICAgICAgICAgc2VhcmNoOiBkYXRhLm9wdGlvbnMuc2VhcmNoID8/IHRydWUsXHJcbiAgICAgICAgICBjc3NDbGFzczogZGF0YS5vcHRpb25zLmNzc0NsYXNzID8/ICcnLFxyXG4gICAgICAgICAgdmlld01vZGU6IGRhdGEub3B0aW9ucy52aWV3TW9kZSA/PyAndG9nZ2xlJyxcclxuICAgICAgICAgIHRoZW1lOiBkYXRhLm9wdGlvbnMudGhlbWUgPz8gJ2xpZ2h0JyxcclxuICAgICAgICAgIHRoZW1lUGlja2VyOiBkYXRhLm9wdGlvbnMudGhlbWVQaWNrZXIgPz8gdHJ1ZSxcclxuICAgICAgICAgIG1pbldpZHRoOiBkYXRhLm9wdGlvbnMubWluV2lkdGggPz8gMzAwLFxyXG4gICAgICAgICAgbWF4V2lkdGg6IGRhdGEub3B0aW9ucy5tYXhXaWR0aCA/PyA1MDAsXHJcbiAgICAgICAgICB3aWR0aDogZGF0YS5vcHRpb25zLndpZHRoID8/IDMwMCxcclxuICAgICAgICAgIHRoZW1lVGV4dDogZGF0YS5vcHRpb25zLnRoZW1lVGV4dCA/PyB7IGxpZ2h0OiAnTGlnaHQnLCBkYXJrOiAnRGFyaycgfSxcclxuICAgICAgICAgIGF1dG9Qb3NpdGlvbjogZGF0YS5vcHRpb25zLmF1dG9Qb3NpdGlvbiA/PyB0cnVlLFxyXG4gICAgICAgICAgdG9nZ2xlQ29sbGFwc2VJY29uOlxyXG4gICAgICAgICAgICBkYXRhLm9wdGlvbnMudG9nZ2xlQ29sbGFwc2VJY29uID8/ICdhc3NldHMvaWNvbnMvY29sbGFwc2Uuc3ZnJyxcclxuICAgICAgICAgIHRvZ2dsZUV4cGFuZEljb246XHJcbiAgICAgICAgICAgIGRhdGEub3B0aW9ucy50b2dnbGVFeHBhbmRJY29uID8/ICdhc3NldHMvaWNvbnMvZXhwYW5kLnN2ZycsXHJcbiAgICAgICAgICBwaW5JY29uOiBkYXRhLm9wdGlvbnMucGluSWNvbiA/PyAnYXNzZXRzL2ljb25zL3Bpbi5zdmcnLFxyXG4gICAgICAgICAgdW5waW5JY29uOiBkYXRhLm9wdGlvbnMudW5waW5JY29uID8/ICdhc3NldHMvaWNvbnMvdW5waW4uc3ZnJyxcclxuICAgICAgICAgIGNsb3NlSWNvbjogZGF0YS5vcHRpb25zLmNsb3NlSWNvbiA/PyAnYXNzZXRzL2ljb25zL2NhbmNlbC5zdmcnLFxyXG4gICAgICAgICAgcGlubmVkOlxyXG4gICAgICAgICAgICBkYXRhLm9wdGlvbnMucGlubmVkID8/XHJcbiAgICAgICAgICAgIChkYXRhLm9wdGlvbnMuZXhwYW5kICYmIGRhdGEub3B0aW9ucy52aWV3TW9kZSA9PT0gJ2hvdmVyJykgPz9cclxuICAgICAgICAgICAgZmFsc2UsXHJcbiAgICAgICAgICBvblRoZW1lQ2hhbmdlOiBkYXRhLm9wdGlvbnMub25UaGVtZUNoYW5nZSxcclxuICAgICAgICAgIG9uUmVzaXplU3RhcnQ6IGRhdGEub3B0aW9ucy5vblJlc2l6ZVN0YXJ0LFxyXG4gICAgICAgICAgb25SZXNpemluZzogZGF0YS5vcHRpb25zLm9uUmVzaXppbmcsXHJcbiAgICAgICAgICBvblJlc2l6ZUVuZDogZGF0YS5vcHRpb25zLm9uUmVzaXplRW5kLFxyXG4gICAgICAgICAgb25FeHBhbmQ6IGRhdGEub3B0aW9ucy5vbkV4cGFuZCxcclxuICAgICAgICAgIG9uQ29sbGFwc2U6IGRhdGEub3B0aW9ucy5vbkNvbGxhcHNlLFxyXG4gICAgICAgICAgb25NZW51Tm9kZUNsaWNrOiBkYXRhLm9wdGlvbnMub25NZW51Tm9kZUNsaWNrLFxyXG4gICAgICAgIH1cclxuICAgICAgOiB7XHJcbiAgICAgICAgICByZXNpemU6IHRydWUsXHJcbiAgICAgICAgICBleHBhbmQ6IHRydWUsXHJcbiAgICAgICAgICBmYXZvcml0ZXM6IHRydWUsXHJcbiAgICAgICAgICBzZWFyY2g6IHRydWUsXHJcbiAgICAgICAgICB2aWV3TW9kZTogJ3RvZ2dsZScsXHJcbiAgICAgICAgICB0aGVtZTogJ2xpZ2h0JyxcclxuICAgICAgICB9O1xyXG5cclxuICAgIHRoaXMuc2lkZWJhckRhdGEgPSBkYXRhIGFzIFNpZGViYXJNb2RlbDtcclxuICAgIHJldHVybiBkYXRhIGFzIFNpZGViYXJNb2RlbDtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEVuYWJsZXMgYXV0b21hdGljIHBvc2l0aW9uaW5nIG9mIHRoZSBzaWRlYmFyLlxyXG4gICAqIEl0IG9ic2VydmVzIHRoZSBzaWRlYmFyJ3Mgd2lkdGggYW5kIHVwZGF0ZXMgdGhlIENTUyB2YXJpYWJsZSBgLS1zaWRlYmFyLXdpZHRoYCBkeW5hbWljYWxseS5cclxuICAgKi9cclxuICBzZXRBdXRvUG9zaXRpb24oKTogdm9pZCB7XHJcbiAgICBjb25zdCBkaXZFbGVtZW50ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ25nLXNpZGViYXInKTtcclxuICAgIGlmICghZGl2RWxlbWVudCkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFkb2N1bWVudC5ib2R5LmNsYXNzTGlzdC5jb250YWlucygnYXV0by1wb3NpdGlvbicpKSB7XHJcbiAgICAgIGRvY3VtZW50LmJvZHkuY2xhc3NMaXN0LmFkZCgnYXV0by1wb3NpdGlvbicpO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IGR1cmF0aW9uID0gMzAwO1xyXG4gICAgdGhpcy5vYnNlcnZlciA9IG5ldyBNdXRhdGlvbk9ic2VydmVyKCgpID0+IHtcclxuICAgICAgY29uc3Qgd2lkdGggPSBkaXZFbGVtZW50Lm9mZnNldFdpZHRoO1xyXG4gICAgICB0aGlzLnVwZGF0ZVdpZHRoKGRpdkVsZW1lbnQsIHBlcmZvcm1hbmNlLm5vdygpLCBkdXJhdGlvbik7XHJcbiAgICAgIGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5zdHlsZS5zZXRQcm9wZXJ0eShcclxuICAgICAgICAnLS1zaWRlYmFyLXdpZHRoJyxcclxuICAgICAgICBgJHt3aWR0aH1weGBcclxuICAgICAgKTtcclxuICAgIH0pO1xyXG5cclxuICAgIHRoaXMub2JzZXJ2ZXIub2JzZXJ2ZShkaXZFbGVtZW50LCB7XHJcbiAgICAgIGF0dHJpYnV0ZUZpbHRlcjogWydzdHlsZSddLFxyXG4gICAgfSk7XHJcblxyXG4gICAgdGhpcy5hdXRvUG9zaXRpb25BY3RpdmUgPSB0cnVlO1xyXG4gICAgY29uc29sZS5sb2coJ0F1dG8gcG9zaXRpb24gZW5hYmxlZCcpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogQW5pbWF0ZXMgdGhlIHdpZHRoIHVwZGF0ZSBvZiB0aGUgc2lkZWJhci5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7SFRNTEVsZW1lbnR9IGRpdkVsZW1lbnQgLSBUaGUgc2lkZWJhciBlbGVtZW50IHdob3NlIHdpZHRoIGlzIGJlaW5nIHVwZGF0ZWQuXHJcbiAgICogQHBhcmFtIHtudW1iZXJ9IHN0YXJ0VGltZSAtIFRoZSBzdGFydCB0aW1lIG9mIHRoZSBhbmltYXRpb24uXHJcbiAgICogQHBhcmFtIHtudW1iZXJ9IGR1cmF0aW9uIC0gVGhlIGR1cmF0aW9uIG9mIHRoZSB3aWR0aCBhbmltYXRpb24gaW4gbWlsbGlzZWNvbmRzLlxyXG4gICAqL1xyXG4gIHVwZGF0ZVdpZHRoKFxyXG4gICAgZGl2RWxlbWVudDogSFRNTEVsZW1lbnQsXHJcbiAgICBzdGFydFRpbWU6IG51bWJlcixcclxuICAgIGR1cmF0aW9uOiBudW1iZXJcclxuICApOiB2b2lkIHtcclxuICAgIGNvbnN0IGFuaW1hdGVXaWR0aCA9ICh0aW1lc3RhbXA6IG51bWJlcikgPT4ge1xyXG4gICAgICBsZXQgcHJvZ3Jlc3MgPSAodGltZXN0YW1wIC0gc3RhcnRUaW1lKSAvIGR1cmF0aW9uO1xyXG4gICAgICBjb25zdCBjdXJyZW50V2lkdGggPSBkaXZFbGVtZW50Lm9mZnNldFdpZHRoO1xyXG4gICAgICBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuc3R5bGUuc2V0UHJvcGVydHkoXHJcbiAgICAgICAgJy0tc2lkZWJhci13aWR0aCcsXHJcbiAgICAgICAgYCR7Y3VycmVudFdpZHRofXB4YFxyXG4gICAgICApO1xyXG4gICAgICBpZiAocHJvZ3Jlc3MgPCAxKSB7XHJcbiAgICAgICAgcmVxdWVzdEFuaW1hdGlvbkZyYW1lKGFuaW1hdGVXaWR0aCk7XHJcbiAgICAgIH1cclxuICAgIH07XHJcbiAgICByZXF1ZXN0QW5pbWF0aW9uRnJhbWUoYW5pbWF0ZVdpZHRoKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIERpc2FibGVzIGF1dG9tYXRpYyBwb3NpdGlvbmluZyBvZiB0aGUgc2lkZWJhci5cclxuICAgKiBTdG9wcyBvYnNlcnZpbmcgc3R5bGUgY2hhbmdlcyBhbmQgcmVzZXRzIENTUyBtb2RpZmljYXRpb25zLlxyXG4gICAqL1xyXG4gIGRlc3Ryb3lBdXRvUG9zaXRpb24oKTogdm9pZCB7XHJcbiAgICB0aGlzLm9ic2VydmVyLmRpc2Nvbm5lY3QoKTtcclxuICAgIGlmIChkb2N1bWVudC5ib2R5LmNsYXNzTGlzdC5jb250YWlucygnYXV0by1wb3NpdGlvbicpKSB7XHJcbiAgICAgIGRvY3VtZW50LmJvZHkuY2xhc3NMaXN0LnJlbW92ZSgnYXV0by1wb3NpdGlvbicpO1xyXG4gICAgfVxyXG4gICAgdGhpcy5hdXRvUG9zaXRpb25BY3RpdmUgPSBmYWxzZTtcclxuICAgIGNvbnNvbGUubG9nKCdBdXRvIHBvc2l0aW9uIGRpc2FibGVkJyk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBIYW5kbGVzIHNpZGViYXIgcmVzaXppbmcgdXNpbmcgbW91c2UgZXZlbnRzLlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtTaWRlYmFyTW9kZWx9IHNpZGViYXJEYXRhIC0gVGhlIHNpZGViYXIgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAgICovXHJcbiAgcmVzaXplKHNpZGViYXJEYXRhOiBTaWRlYmFyTW9kZWwpOiB2b2lkIHtcclxuICAgIC8vIENoZWNrIGlmIHNpZGViYXJEYXRhIGFuZCBvcHRpb25zIGFyZSBpbml0aWFsaXplZFxyXG4gICAgaWYgKCFzaWRlYmFyRGF0YSB8fCAhc2lkZWJhckRhdGEub3B0aW9ucykge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy5pc1Jlc2l6aW5nID0gdHJ1ZTtcclxuICAgIGNvbnN0IGluaXRpYWxQaW4gPSBzaWRlYmFyRGF0YS5vcHRpb25zLnBpbm5lZDtcclxuICAgIHNpZGViYXJEYXRhLm9wdGlvbnMucGlubmVkID0gdHJ1ZTtcclxuXHJcbiAgICBjb25zdCBkaXZFbGVtZW50ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ25nLXNpZGViYXInKSBhcyBIVE1MRWxlbWVudDtcclxuXHJcbiAgICBjb25zdCBzdGFydEV2ZW50OiBSZXNpemVFdmVudCA9IHtcclxuICAgICAgY2FuY2VsOiBmYWxzZSxcclxuICAgICAgc2lkZWJhck9wdGlvbnM6IHNpZGViYXJEYXRhLFxyXG4gICAgICBuYXRpdmVFbGVtZW50OiBkaXZFbGVtZW50LFxyXG4gICAgfTtcclxuXHJcbiAgICBpZiAoc2lkZWJhckRhdGEub3B0aW9ucy5vblJlc2l6ZVN0YXJ0KSB7XHJcbiAgICAgIHNpZGViYXJEYXRhLm9wdGlvbnMub25SZXNpemVTdGFydChzdGFydEV2ZW50KTtcclxuICAgICAgaWYgKHN0YXJ0RXZlbnQuY2FuY2VsKSB7XHJcbiAgICAgICAgdGhpcy5pc1Jlc2l6aW5nID0gZmFsc2U7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgZG9jdW1lbnQuYm9keS5jbGFzc0xpc3QuYWRkKCduby1zZWxlY3QnKTtcclxuXHJcbiAgICAvKipcclxuICAgICAqIEhhbmRsZXMgbW91c2UgbW92ZW1lbnQgZHVyaW5nIHJlc2l6aW5nLlxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSB7TW91c2VFdmVudH0gZSAtIFRoZSBtb3VzZSBtb3ZlbWVudCBldmVudC5cclxuICAgICAqL1xyXG4gICAgY29uc3QgbW91c2VNb3ZlTGlzdGVuZXIgPSAoZTogTW91c2VFdmVudCkgPT4ge1xyXG4gICAgICBjb25zdCByZXNpemVFdmVudDogUmVzaXplRXZlbnQgPSB7XHJcbiAgICAgICAgY2FuY2VsOiBmYWxzZSxcclxuICAgICAgICBzaWRlYmFyT3B0aW9uczogc2lkZWJhckRhdGEsXHJcbiAgICAgICAgbW91c2VFdmVudDogZSxcclxuICAgICAgICBuYXRpdmVFbGVtZW50OiBkaXZFbGVtZW50LFxyXG4gICAgICB9O1xyXG5cclxuICAgICAgaWYgKHNpZGViYXJEYXRhLm9wdGlvbnMub25SZXNpemluZykge1xyXG4gICAgICAgIHNpZGViYXJEYXRhLm9wdGlvbnMub25SZXNpemluZyhyZXNpemVFdmVudCk7XHJcbiAgICAgICAgaWYgKHJlc2l6ZUV2ZW50LmNhbmNlbCkge1xyXG4gICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKFxyXG4gICAgICAgIHNpZGViYXJEYXRhLm9wdGlvbnMubWluV2lkdGggJiZcclxuICAgICAgICBlLmNsaWVudFggPCBzaWRlYmFyRGF0YS5vcHRpb25zLm1pbldpZHRoXHJcbiAgICAgICkge1xyXG4gICAgICAgIHNpZGViYXJEYXRhLm9wdGlvbnMud2lkdGggPSBzaWRlYmFyRGF0YS5vcHRpb25zLm1pbldpZHRoO1xyXG4gICAgICB9IGVsc2UgaWYgKFxyXG4gICAgICAgIHNpZGViYXJEYXRhLm9wdGlvbnMubWF4V2lkdGggJiZcclxuICAgICAgICBlLmNsaWVudFggPiBzaWRlYmFyRGF0YS5vcHRpb25zLm1heFdpZHRoXHJcbiAgICAgICkge1xyXG4gICAgICAgIHNpZGViYXJEYXRhLm9wdGlvbnMud2lkdGggPSBzaWRlYmFyRGF0YS5vcHRpb25zLm1heFdpZHRoO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHNpZGViYXJEYXRhLm9wdGlvbnMud2lkdGggPSBlLmNsaWVudFg7XHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignbW91c2Vtb3ZlJywgbW91c2VNb3ZlTGlzdGVuZXIpO1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogSGFuZGxlcyBtb3VzZSByZWxlYXNlIGFmdGVyIHJlc2l6aW5nLlxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSB7TW91c2VFdmVudH0gZSAtIFRoZSBtb3VzZSB1cCBldmVudC5cclxuICAgICAqL1xyXG4gICAgY29uc3QgbW91c2VVcExpc3RlbmVyID0gKGU6IE1vdXNlRXZlbnQpID0+IHtcclxuICAgICAgZG9jdW1lbnQuYm9keS5jbGFzc0xpc3QucmVtb3ZlKCduby1zZWxlY3QnKTtcclxuICAgICAgZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2Vtb3ZlJywgbW91c2VNb3ZlTGlzdGVuZXIpO1xyXG4gICAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCdtb3VzZXVwJywgbW91c2VVcExpc3RlbmVyKTtcclxuXHJcbiAgICAgIHRoaXMuaXNSZXNpemluZyA9IGZhbHNlO1xyXG4gICAgICBzaWRlYmFyRGF0YS5vcHRpb25zLnBpbm5lZCA9IGluaXRpYWxQaW47XHJcblxyXG4gICAgICBjb25zdCBlbmRFdmVudDogUmVzaXplRXZlbnQgPSB7XHJcbiAgICAgICAgc2lkZWJhck9wdGlvbnM6IHNpZGViYXJEYXRhLFxyXG4gICAgICAgIG1vdXNlRXZlbnQ6IGUsXHJcbiAgICAgICAgbmF0aXZlRWxlbWVudDogZGl2RWxlbWVudCxcclxuICAgICAgfTtcclxuXHJcbiAgICAgIGlmIChzaWRlYmFyRGF0YS5vcHRpb25zLm9uUmVzaXplRW5kKSB7XHJcbiAgICAgICAgc2lkZWJhckRhdGEub3B0aW9ucy5vblJlc2l6ZUVuZChlbmRFdmVudCk7XHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignbW91c2V1cCcsIG1vdXNlVXBMaXN0ZW5lcik7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBJbml0aWFsaXplcyBtZW51IGRhdGEgYnkgYXNzaWduaW5nIGRlZmF1bHQgdmFsdWVzIGlmIG5vdCBwcm92aWRlZC5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7TWVudURhdGFbXX0gbWVudURhdGEgLSBUaGUgbWVudSBkYXRhIGFycmF5IHRvIGluaXRpYWxpemUuXHJcbiAgICogQHJldHVybnMge01lbnVEYXRhW119IC0gVGhlIHByb2Nlc3NlZCBtZW51IGRhdGEgd2l0aCBkZWZhdWx0IHZhbHVlcyBhcHBsaWVkLlxyXG4gICAqL1xyXG4gIHByaXZhdGUgaW5pdGlhbGl6ZU1lbnVEYXRhKG1lbnVEYXRhOiBNZW51RGF0YVtdKTogTWVudURhdGFbXSB7XHJcbiAgICByZXR1cm4gbWVudURhdGEubWFwKGl0ZW0gPT4ge1xyXG4gICAgICBpdGVtWyduYW1lJ10gPSBpdGVtWyduYW1lJ107XHJcbiAgICAgIGl0ZW1bJ2ljb24nXSA9IGl0ZW1bJ2ljb24nXTtcclxuICAgICAgaXRlbVsncm91dGUnXSA9IGl0ZW1bJ3JvdXRlJ107XHJcbiAgICAgIGl0ZW1bJ3Zpc2libGUnXSA9IGl0ZW1bJ3Zpc2libGUnXSA/PyB0cnVlO1xyXG4gICAgICBpdGVtWydka