@angulogic/ng-sidebar
Version:
angular sidebar - standalone components
440 lines • 58 kB
JavaScript
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