@nlabs/arkhamjs
Version:
Javascript Flux Library
410 lines (409 loc) • 54.3 kB
JavaScript
function _define_property(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
/**
* Copyright (c) 2018-Present, Nitrogen Labs, Inc.
* Copyrights licensed under the MIT License. See the accompanying LICENSE file for terms.
*/ import { cloneDeep } from '@nlabs/utils/objects/clone';
import { debounceCompact } from '@nlabs/utils/objects/debounce-compact';
import { get } from '@nlabs/utils/objects/get';
import { merge } from '@nlabs/utils/objects/merge';
import { set } from '@nlabs/utils/objects/set';
import { parseStack } from '@nlabs/utils/objects/stack-parser';
import { EventEmitter } from 'events';
import { ArkhamConstants } from '../constants/ArkhamConstants.js';
const STACK_CACHE = new Map();
const STACK_CACHE_SIZE = 100;
export class FluxFramework extends EventEmitter {
addMiddleware(middleware) {
middleware.forEach((middleObj)=>{
if (!middleObj || typeof middleObj !== 'function' && typeof middleObj !== 'object') {
throw Error('Unknown middleware is not configured properly. Cannot add to Flux.');
}
const middleName = middleObj.name || '';
if (!middleName) {
throw Error('Unknown middleware is not configured properly. Requires name property. Cannot add to Flux.');
}
const existingMiddleware = this.middleware.preDispatchList?.find((m)=>m.name === middleName) || this.middleware.postDispatchList?.find((m)=>m.name === middleName);
if (existingMiddleware) {
// eslint-disable-next-line no-console
console.warn(`Middleware "${middleName}" already exists. Skipping duplicate.`);
return;
}
this.pluginTypes.forEach((type)=>{
const method = middleObj[type];
if (method && typeof method === 'function') {
const plugin = {
method,
name: middleName
};
this.middleware[`${type}List`] = this.addPlugin(type, plugin);
}
});
});
}
clearAppData() {
Object.keys(this.storeActions).forEach((storeName)=>{
const storeFn = this.storeActions[storeName];
if (storeFn) {
this.state[storeFn.name] = storeFn.initialState;
}
});
this.stateCache.clear();
this.stateChanged = true;
const { name, storage } = this.options;
if (storage?.setStorageData) {
return storage.setStorageData(name ?? 'arkhamjs', this.state);
}
return Promise.resolve(true);
}
clearMiddleware() {
Object.keys(this.middleware).forEach((pluginType)=>{
this.middleware[pluginType] = [];
});
return true;
}
removeStores(storeNames) {
storeNames.forEach((name)=>this.deregister(name));
}
async dispatch(action, silent = false) {
if (!action) {
throw new Error('ArkhamJS Error: Flux.dispatch requires an action.');
}
const startTime = Date.now();
let clonedAction = cloneDeep(action);
let stack = [];
if (this.options.debug) {
stack = this.getCachedStack();
}
const appInfo = {
duration: 0,
options: this.options,
stack
};
const { postDispatchList = [], preDispatchList = [] } = this.middleware;
if (preDispatchList.length) {
clonedAction = await this.processMiddleware(preDispatchList, clonedAction, appInfo);
}
const { type, ...data } = clonedAction;
if (!type || type === '') {
// eslint-disable-next-line no-console
console.warn('ArkhamJS Warning: Flux.dispatch is missing an action type for the payload:', data);
return Promise.resolve(clonedAction);
}
this.updateStoresState(type, data);
if (this.stateChanged && this.options.storage && this.updateStorage) {
try {
await this.updateStorage();
this.stateChanged = false;
} catch (error) {
// eslint-disable-next-line no-console
console.error('Storage update failed:', error);
}
}
const duration = Date.now() - startTime;
appInfo.duration = duration;
if (postDispatchList.length) {
clonedAction = await this.processMiddleware(postDispatchList, clonedAction, appInfo);
}
if (!silent) {
this.emit(type, clonedAction);
this.emit('arkhamjs', this.state);
}
return Promise.resolve(clonedAction);
}
getOptions() {
return this.options;
}
getState(path = '', defaultValue) {
const pathKey = Array.isArray(path) ? path.join('.') : path;
if (this.stateCache.has(pathKey)) {
return this.stateCache.get(pathKey);
}
let storeValue;
if (!path) {
storeValue = this.state || {};
} else {
storeValue = get(this.state, path);
}
const value = storeValue ? cloneDeep(storeValue) : storeValue;
const result = value === undefined ? defaultValue : value;
this.stateCache.set(pathKey, result);
return result;
}
getStore(name = '') {
return this.storeActions[name];
}
async init(options = {}, reset = false) {
if (reset) {
this.isInit = false;
await this.reset(false);
}
const updatedOptions = {
...options
};
if (this.isInit && this.options.name) {
updatedOptions.name = this.options.name;
}
this.options = {
...this.defaultOptions,
...updatedOptions
};
const { debug, middleware, name, stores } = this.options;
try {
await this.useStorage(name ?? 'arkhamjs');
} catch (error) {
// eslint-disable-next-line no-console
console.error('Arkham Error: There was an error while using storage.', name);
throw error;
}
if (stores?.length) {
try {
await this.addStores(stores);
} catch (error) {
// eslint-disable-next-line no-console
console.error('Arkham Error: There was an error while adding stores.', stores);
throw error;
}
}
if (middleware?.length) {
this.addMiddleware(middleware);
}
const windowProperty = 'arkhamjs';
if (debug) {
window[windowProperty] = this;
} else {
delete window[windowProperty];
}
this.isInit = true;
this.emit(ArkhamConstants.INIT);
return this;
}
onInit(listener) {
this.on(ArkhamConstants.INIT, listener);
if (this.isInit) {
listener();
}
}
offInit(listener) {
this.off(ArkhamConstants.INIT, listener);
}
off(eventType, listener) {
return this.removeListener(eventType, listener);
}
on(eventType, listener) {
return this.addListener(eventType, listener);
}
async addStores(stores) {
const registeredStores = stores.map((store)=>this.register(store));
const { name, storage } = this.options;
if (storage?.setStorageData) {
try {
await storage.setStorageData(name ?? 'arkhamjs', this.state);
} catch (error) {
throw error;
}
}
return registeredStores;
}
removeMiddleware(names) {
names.forEach((name)=>{
this.pluginTypes.forEach((type)=>{
this.middleware[`${type}List`] = this.removePlugin(type, name);
});
});
}
async reset(clearStorage = true) {
const { name, storage } = this.options;
if (storage && clearStorage) {
try {
await storage.setStorageData?.(name ?? 'arkhamjs', {});
} catch (error) {
throw error;
}
}
this.middleware = {};
this.options = {
...this.defaultOptions
};
this.state = {};
this.storeActions = {};
this.stateCache.clear();
this.stateChanged = false;
this.isInit = false;
this.pluginTypes.forEach((type)=>this.middleware[`${type}List`] = []);
}
setState(path = '', value) {
if (path) {
this.state = set(this.state, path, cloneDeep(value));
this.stateChanged = true;
const pathKey = Array.isArray(path) ? path.join('.') : path;
this.stateCache.delete(pathKey);
}
if (this.options.storage && this.updateStorage) {
return this.updateStorage();
}
return Promise.resolve(false);
}
async processMiddleware(middlewareList, action, appInfo) {
return Promise.all(middlewareList.map((plugin)=>plugin.method(cloneDeep(action), cloneDeep(this.state), appInfo))).then((actions)=>actions.reduce((updatedAction, action)=>merge(updatedAction, action), action)).catch((error)=>{
throw error;
});
}
updateStoresState(type, data) {
Object.keys(this.storeActions).forEach((storeName)=>{
const storeFn = this.storeActions[storeName];
if (storeFn) {
const currentState = this.state[storeName] || storeFn.initialState || {};
const newState = storeFn.action(type, data, currentState);
if (newState !== currentState) {
this.state[storeName] = cloneDeep(newState) || currentState;
this.stateChanged = true;
}
}
});
}
getCachedStack() {
const cacheKey = new Error().stack?.split('\n')[2] || '';
if (STACK_CACHE.has(cacheKey)) {
return STACK_CACHE.get(cacheKey);
}
let stack = [];
try {
const stackProperty = 'stackTraceLimit';
const originalLimit = Error.stackTraceLimit;
Error[stackProperty] = Infinity;
stack = parseStack(new Error());
Error[stackProperty] = originalLimit;
if (STACK_CACHE.size >= STACK_CACHE_SIZE) {
const firstKey = STACK_CACHE.keys().next().value;
if (firstKey) {
STACK_CACHE.delete(firstKey);
}
}
STACK_CACHE.set(cacheKey, stack);
} catch (error) {}
return stack;
}
addPlugin(type, plugin) {
const list = this.middleware[`${type}List`] || [];
const { method, name } = plugin;
if (method && typeof method === 'function') {
const exists = list.some((obj)=>obj.name === name);
if (!exists) {
list.push({
method,
name
});
}
} else if (method !== undefined) {
throw Error(`${plugin.name} middleware is not configured properly. Method is not a function.`);
}
return list;
}
deregister(name = '') {
delete this.storeActions[name];
delete this.state[name];
this.stateCache.clear(); // Clear cache when stores change
}
register(store) {
if (!store) {
throw Error('Store is undefined. Cannot register with Flux.');
}
let storeName;
let storeAction;
let initialState;
if (typeof store === 'function') {
// Function store - extract name from function.name
storeName = store.name || 'anonymous';
storeAction = store;
initialState = store();
} else if (typeof store?.action === 'function') {
// Object store with action method
storeName = store.name || 'anonymous';
storeAction = store.action;
initialState = store.initialState || store.action();
} else {
throw Error(`${store} is not a valid store. Must be a function or object with action method.`);
}
if (!storeName || storeName === 'anonymous') {
// Silently ignore anonymous stores - return undefined
return undefined;
}
const fluxStore = {
action: storeAction,
initialState,
name: storeName
};
if (!this.storeActions[storeName]) {
this.storeActions[storeName] = fluxStore;
if (!this.state[storeName]) {
this.state[storeName] = cloneDeep(initialState || {});
}
}
return this.storeActions[storeName];
}
removePlugin(type, name) {
const list = this.middleware[`${type}List`] || [];
return list.filter((obj)=>obj.name !== name);
}
async useStorage(name) {
const { storage, state, storageWait } = this.options;
if (storage) {
try {
this.state = state || await storage?.getStorageData?.(name) || {};
this.updateStorage = debounceCompact(()=>storage?.setStorageData?.(name, this.state), storageWait ?? 300);
} catch (error) {
// eslint-disable-next-line no-console
console.error(`ArkhamJS Error: Using storage, "${name}".`);
throw error;
}
} else {
this.state = state || {};
}
}
constructor(){
super(), _define_property(this, "isInit", false), _define_property(this, "pluginTypes", [
'preDispatch',
'postDispatch'
]), _define_property(this, "state", {}), _define_property(this, "storeActions", {}), _define_property(this, "defaultOptions", {
name: 'arkhamjs',
routerType: 'browser',
scrollToTop: true,
storageWait: 300,
stores: [],
title: 'ArkhamJS'
}), _define_property(this, "middleware", {}), _define_property(this, "options", this.defaultOptions), _define_property(this, "stateCache", new Map()), _define_property(this, "stateChanged", false), _define_property(this, "updateStorage", ()=>Promise.resolve(false));
// Bind methods once in constructor for better performance
this.addMiddleware = this.addMiddleware.bind(this);
this.addStores = this.addStores.bind(this);
this.clearAppData = this.clearAppData.bind(this);
this.clearMiddleware = this.clearMiddleware.bind(this);
this.deregister = this.deregister.bind(this);
this.dispatch = this.dispatch.bind(this);
this.getOptions = this.getOptions.bind(this);
this.getState = this.getState.bind(this);
this.getStore = this.getStore.bind(this);
this.init = this.init.bind(this);
this.off = this.off.bind(this);
this.register = this.register.bind(this);
this.removeMiddleware = this.removeMiddleware.bind(this);
this.removeStores = this.removeStores.bind(this);
this.reset = this.reset.bind(this);
this.setState = this.setState.bind(this);
this.pluginTypes.forEach((type)=>this.middleware[`${type}List`] = []);
}
}
_define_property(FluxFramework, "initFlux", false);
export const Flux = new FluxFramework();
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9Vc2Vycy9uaXRyb2c3L0RldmVsb3BtZW50L2Fya2hhbWpzL3BhY2thZ2VzL2Fya2hhbWpzL3NyYy9GbHV4L0ZsdXgudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDb3B5cmlnaHQgKGMpIDIwMTgtUHJlc2VudCwgTml0cm9nZW4gTGFicywgSW5jLlxuICogQ29weXJpZ2h0cyBsaWNlbnNlZCB1bmRlciB0aGUgTUlUIExpY2Vuc2UuIFNlZSB0aGUgYWNjb21wYW55aW5nIExJQ0VOU0UgZmlsZSBmb3IgdGVybXMuXG4gKi9cbmltcG9ydCB7Y2xvbmVEZWVwfSBmcm9tICdAbmxhYnMvdXRpbHMvb2JqZWN0cy9jbG9uZSc7XG5pbXBvcnQge2RlYm91bmNlQ29tcGFjdH0gZnJvbSAnQG5sYWJzL3V0aWxzL29iamVjdHMvZGVib3VuY2UtY29tcGFjdCc7XG5pbXBvcnQge2dldH0gZnJvbSAnQG5sYWJzL3V0aWxzL29iamVjdHMvZ2V0JztcbmltcG9ydCB7bWVyZ2V9IGZyb20gJ0BubGFicy91dGlscy9vYmplY3RzL21lcmdlJztcbmltcG9ydCB7c2V0fSBmcm9tICdAbmxhYnMvdXRpbHMvb2JqZWN0cy9zZXQnO1xuaW1wb3J0IHtwYXJzZVN0YWNrfSBmcm9tICdAbmxhYnMvdXRpbHMvb2JqZWN0cy9zdGFjay1wYXJzZXInO1xuaW1wb3J0IHtFdmVudEVtaXR0ZXJ9IGZyb20gJ2V2ZW50cyc7XG5cbmltcG9ydCB7QXJraGFtQ29uc3RhbnRzfSBmcm9tICcuLi9jb25zdGFudHMvQXJraGFtQ29uc3RhbnRzLmpzJztcblxuaW1wb3J0IHR5cGUge0ZsdXhBY3Rpb24sIEZsdXhNaWRkbGV3YXJlVHlwZSwgRmx1eE9wdGlvbnMsIEZsdXhQbHVnaW5UeXBlLCBGbHV4U3RvcmV9IGZyb20gJy4vRmx1eC50eXBlcy5qcyc7XG5cbmNvbnN0IFNUQUNLX0NBQ0hFID0gbmV3IE1hcDxzdHJpbmcsIGFueVtdPigpO1xuY29uc3QgU1RBQ0tfQ0FDSEVfU0laRSA9IDEwMDtcblxuZXhwb3J0IGNsYXNzIEZsdXhGcmFtZXdvcmsgZXh0ZW5kcyBFdmVudEVtaXR0ZXIge1xuICBzdGF0aWMgaW5pdEZsdXg6IGJvb2xlYW4gPSBmYWxzZTtcbiAgaXNJbml0OiBib29sZWFuID0gZmFsc2U7XG5cbiAgcmVhZG9ubHkgcGx1Z2luVHlwZXM6IHJlYWRvbmx5IHN0cmluZ1tdID0gWydwcmVEaXNwYXRjaCcsICdwb3N0RGlzcGF0Y2gnXSBhcyBjb25zdDtcblxuICBwcml2YXRlIHN0YXRlOiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0ge307XG4gIHByaXZhdGUgc3RvcmVBY3Rpb25zOiBSZWNvcmQ8c3RyaW5nLCBGbHV4U3RvcmU+ID0ge307XG4gIHByaXZhdGUgcmVhZG9ubHkgZGVmYXVsdE9wdGlvbnM6IEZsdXhPcHRpb25zID0ge1xuICAgIG5hbWU6ICdhcmtoYW1qcycsXG4gICAgcm91dGVyVHlwZTogJ2Jyb3dzZXInLFxuICAgIHNjcm9sbFRvVG9wOiB0cnVlLFxuICAgIHN0b3JhZ2VXYWl0OiAzMDAsXG4gICAgc3RvcmVzOiBbXSxcbiAgICB0aXRsZTogJ0Fya2hhbUpTJ1xuICB9O1xuICBwcml2YXRlIG1pZGRsZXdhcmU6IFJlY29yZDxzdHJpbmcsIEZsdXhQbHVnaW5UeXBlW10+ID0ge307XG4gIHByaXZhdGUgb3B0aW9uczogRmx1eE9wdGlvbnMgPSB0aGlzLmRlZmF1bHRPcHRpb25zO1xuICBwcml2YXRlIHN0YXRlQ2FjaGU6IE1hcDxzdHJpbmcsIGFueT4gPSBuZXcgTWFwKCk7XG4gIHByaXZhdGUgc3RhdGVDaGFuZ2VkOiBib29sZWFuID0gZmFsc2U7XG5cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgc3VwZXIoKTtcblxuICAgIC8vIEJpbmQgbWV0aG9kcyBvbmNlIGluIGNvbnN0cnVjdG9yIGZvciBiZXR0ZXIgcGVyZm9ybWFuY2VcbiAgICB0aGlzLmFkZE1pZGRsZXdhcmUgPSB0aGlzLmFkZE1pZGRsZXdhcmUuYmluZCh0aGlzKTtcbiAgICB0aGlzLmFkZFN0b3JlcyA9IHRoaXMuYWRkU3RvcmVzLmJpbmQodGhpcyk7XG4gICAgdGhpcy5jbGVhckFwcERhdGEgPSB0aGlzLmNsZWFyQXBwRGF0YS5iaW5kKHRoaXMpO1xuICAgIHRoaXMuY2xlYXJNaWRkbGV3YXJlID0gdGhpcy5jbGVhck1pZGRsZXdhcmUuYmluZCh0aGlzKTtcbiAgICB0aGlzLmRlcmVnaXN0ZXIgPSB0aGlzLmRlcmVnaXN0ZXIuYmluZCh0aGlzKTtcbiAgICB0aGlzLmRpc3BhdGNoID0gdGhpcy5kaXNwYXRjaC5iaW5kKHRoaXMpO1xuICAgIHRoaXMuZ2V0T3B0aW9ucyA9IHRoaXMuZ2V0T3B0aW9ucy5iaW5kKHRoaXMpO1xuICAgIHRoaXMuZ2V0U3RhdGUgPSB0aGlzLmdldFN0YXRlLmJpbmQodGhpcyk7XG4gICAgdGhpcy5nZXRTdG9yZSA9IHRoaXMuZ2V0U3RvcmUuYmluZCh0aGlzKTtcbiAgICB0aGlzLmluaXQgPSB0aGlzLmluaXQuYmluZCh0aGlzKTtcbiAgICB0aGlzLm9mZiA9IHRoaXMub2ZmLmJpbmQodGhpcyk7XG4gICAgdGhpcy5yZWdpc3RlciA9IHRoaXMucmVnaXN0ZXIuYmluZCh0aGlzKTtcbiAgICB0aGlzLnJlbW92ZU1pZGRsZXdhcmUgPSB0aGlzLnJlbW92ZU1pZGRsZXdhcmUuYmluZCh0aGlzKTtcbiAgICB0aGlzLnJlbW92ZVN0b3JlcyA9IHRoaXMucmVtb3ZlU3RvcmVzLmJpbmQodGhpcyk7XG4gICAgdGhpcy5yZXNldCA9IHRoaXMucmVzZXQuYmluZCh0aGlzKTtcbiAgICB0aGlzLnNldFN0YXRlID0gdGhpcy5zZXRTdGF0ZS5iaW5kKHRoaXMpO1xuXG4gICAgdGhpcy5wbHVnaW5UeXBlcy5mb3JFYWNoKCh0eXBlOiBzdHJpbmcpID0+IHRoaXMubWlkZGxld2FyZVtgJHt0eXBlfUxpc3RgXSA9IFtdKTtcbiAgfVxuXG4gIGFkZE1pZGRsZXdhcmUobWlkZGxld2FyZTogRmx1eE1pZGRsZXdhcmVUeXBlW10pOiB2b2lkIHtcbiAgICBtaWRkbGV3YXJlLmZvckVhY2goKG1pZGRsZU9iajogRmx1eE1pZGRsZXdhcmVUeXBlKSA9PiB7XG4gICAgICBpZighbWlkZGxlT2JqIHx8ICh0eXBlb2YgbWlkZGxlT2JqICE9PSAnZnVuY3Rpb24nICYmIHR5cGVvZiBtaWRkbGVPYmogIT09ICdvYmplY3QnKSkge1xuICAgICAgICB0aHJvdyBFcnJvcignVW5rbm93biBtaWRkbGV3YXJlIGlzIG5vdCBjb25maWd1cmVkIHByb3Blcmx5LiBDYW5ub3QgYWRkIHRvIEZsdXguJyk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IG1pZGRsZU5hbWU6IHN0cmluZyA9IG1pZGRsZU9iai5uYW1lIHx8ICcnO1xuICAgICAgaWYoIW1pZGRsZU5hbWUpIHtcbiAgICAgICAgdGhyb3cgRXJyb3IoJ1Vua25vd24gbWlkZGxld2FyZSBpcyBub3QgY29uZmlndXJlZCBwcm9wZXJseS4gUmVxdWlyZXMgbmFtZSBwcm9wZXJ0eS4gQ2Fubm90IGFkZCB0byBGbHV4LicpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBleGlzdGluZ01pZGRsZXdhcmUgPSB0aGlzLm1pZGRsZXdhcmUucHJlRGlzcGF0Y2hMaXN0Py5maW5kKChtKSA9PiBtLm5hbWUgPT09IG1pZGRsZU5hbWUpIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubWlkZGxld2FyZS5wb3N0RGlzcGF0Y2hMaXN0Py5maW5kKChtKSA9PiBtLm5hbWUgPT09IG1pZGRsZU5hbWUpO1xuXG4gICAgICBpZihleGlzdGluZ01pZGRsZXdhcmUpIHtcbiAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWNvbnNvbGVcbiAgICAgICAgY29uc29sZS53YXJuKGBNaWRkbGV3YXJlIFwiJHttaWRkbGVOYW1lfVwiIGFscmVhZHkgZXhpc3RzLiBTa2lwcGluZyBkdXBsaWNhdGUuYCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdGhpcy5wbHVnaW5UeXBlcy5mb3JFYWNoKCh0eXBlOiBzdHJpbmcpID0+IHtcbiAgICAgICAgY29uc3QgbWV0aG9kID0gbWlkZGxlT2JqW3R5cGUgYXMga2V5b2YgRmx1eE1pZGRsZXdhcmVUeXBlXTtcbiAgICAgICAgaWYobWV0aG9kICYmIHR5cGVvZiBtZXRob2QgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICBjb25zdCBwbHVnaW46IEZsdXhQbHVnaW5UeXBlID0ge21ldGhvZCwgbmFtZTogbWlkZGxlTmFtZX07XG4gICAgICAgICAgdGhpcy5taWRkbGV3YXJlW2Ake3R5cGV9TGlzdGBdID0gdGhpcy5hZGRQbHVnaW4odHlwZSwgcGx1Z2luKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cblxuICBjbGVhckFwcERhdGEoKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgT2JqZWN0LmtleXModGhpcy5zdG9yZUFjdGlvbnMpLmZvckVhY2goKHN0b3JlTmFtZTogc3RyaW5nKSA9PiB7XG4gICAgICBjb25zdCBzdG9yZUZuID0gdGhpcy5zdG9yZUFjdGlvbnNbc3RvcmVOYW1lXTtcbiAgICAgIGlmKHN0b3JlRm4pIHtcbiAgICAgICAgdGhpcy5zdGF0ZVtzdG9yZUZuLm5hbWVdID0gc3RvcmVGbi5pbml0aWFsU3RhdGU7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB0aGlzLnN0YXRlQ2FjaGUuY2xlYXIoKTtcbiAgICB0aGlzLnN0YXRlQ2hhbmdlZCA9IHRydWU7XG5cbiAgICBjb25zdCB7bmFtZSwgc3RvcmFnZX0gPSB0aGlzLm9wdGlvbnM7XG4gICAgaWYoc3RvcmFnZT8uc2V0U3RvcmFnZURhdGEpIHtcbiAgICAgIHJldHVybiBzdG9yYWdlLnNldFN0b3JhZ2VEYXRhKG5hbWUgPz8gJ2Fya2hhbWpzJywgdGhpcy5zdGF0ZSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh0cnVlKTtcbiAgfVxuXG4gIGNsZWFyTWlkZGxld2FyZSgpOiBib29sZWFuIHtcbiAgICBPYmplY3Qua2V5cyh0aGlzLm1pZGRsZXdhcmUpLmZvckVhY2goKHBsdWdpblR5cGU6IHN0cmluZykgPT4ge1xuICAgICAgdGhpcy5taWRkbGV3YXJlW3BsdWdpblR5cGVdID0gW107XG4gICAgfSk7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICByZW1vdmVTdG9yZXMoc3RvcmVOYW1lczogc3RyaW5nW10pOiB2b2lkIHtcbiAgICBzdG9yZU5hbWVzLmZvckVhY2goKG5hbWU6IHN0cmluZykgPT4gdGhpcy5kZXJlZ2lzdGVyKG5hbWUpKTtcbiAgfVxuXG4gIGFzeW5jIGRpc3BhdGNoKGFjdGlvbjogRmx1eEFjdGlvbiwgc2lsZW50OiBib29sZWFuID0gZmFsc2UpOiBQcm9taXNlPEZsdXhBY3Rpb24+IHtcbiAgICBpZighYWN0aW9uKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Fya2hhbUpTIEVycm9yOiBGbHV4LmRpc3BhdGNoIHJlcXVpcmVzIGFuIGFjdGlvbi4nKTtcbiAgICB9XG5cbiAgICBjb25zdCBzdGFydFRpbWU6IG51bWJlciA9IERhdGUubm93KCk7XG5cbiAgICBsZXQgY2xvbmVkQWN0aW9uOiBGbHV4QWN0aW9uID0gY2xvbmVEZWVwKGFjdGlvbik7XG5cbiAgICBsZXQgc3RhY2s6IGFueVtdID0gW107XG4gICAgaWYodGhpcy5vcHRpb25zLmRlYnVnKSB7XG4gICAgICBzdGFjayA9IHRoaXMuZ2V0Q2FjaGVkU3RhY2soKTtcbiAgICB9XG5cbiAgICBjb25zdCBhcHBJbmZvID0ge1xuICAgICAgZHVyYXRpb246IDAsXG4gICAgICBvcHRpb25zOiB0aGlzLm9wdGlvbnMsXG4gICAgICBzdGFja1xuICAgIH07XG5cbiAgICBjb25zdCB7cG9zdERpc3BhdGNoTGlzdCA9IFtdLCBwcmVEaXNwYXRjaExpc3QgPSBbXX0gPSB0aGlzLm1pZGRsZXdhcmU7XG5cbiAgICBpZihwcmVEaXNwYXRjaExpc3QubGVuZ3RoKSB7XG4gICAgICBjbG9uZWRBY3Rpb24gPSBhd2FpdCB0aGlzLnByb2Nlc3NNaWRkbGV3YXJlKHByZURpc3BhdGNoTGlzdCwgY2xvbmVkQWN0aW9uLCBhcHBJbmZvKTtcbiAgICB9XG5cbiAgICBjb25zdCB7dHlwZSwgLi4uZGF0YX0gPSBjbG9uZWRBY3Rpb247XG5cbiAgICBpZighdHlwZSB8fCB0eXBlID09PSAnJykge1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWNvbnNvbGVcbiAgICAgIGNvbnNvbGUud2FybignQXJraGFtSlMgV2FybmluZzogRmx1eC5kaXNwYXRjaCBpcyBtaXNzaW5nIGFuIGFjdGlvbiB0eXBlIGZvciB0aGUgcGF5bG9hZDonLCBkYXRhKTtcbiAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoY2xvbmVkQWN0aW9uKTtcbiAgICB9XG5cbiAgICB0aGlzLnVwZGF0ZVN0b3Jlc1N0YXRlKHR5cGUsIGRhdGEpO1xuXG4gICAgaWYodGhpcy5zdGF0ZUNoYW5nZWQgJiYgdGhpcy5vcHRpb25zLnN0b3JhZ2UgJiYgdGhpcy51cGRhdGVTdG9yYWdlKSB7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCB0aGlzLnVwZGF0ZVN0b3JhZ2UoKTtcbiAgICAgICAgdGhpcy5zdGF0ZUNoYW5nZWQgPSBmYWxzZTtcbiAgICAgIH0gY2F0Y2goZXJyb3IpIHtcbiAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWNvbnNvbGVcbiAgICAgICAgY29uc29sZS5lcnJvcignU3RvcmFnZSB1cGRhdGUgZmFpbGVkOicsIGVycm9yKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBkdXJhdGlvbjogbnVtYmVyID0gRGF0ZS5ub3coKSAtIHN0YXJ0VGltZTtcbiAgICBhcHBJbmZvLmR1cmF0aW9uID0gZHVyYXRpb247XG5cbiAgICBpZihwb3N0RGlzcGF0Y2hMaXN0Lmxlbmd0aCkge1xuICAgICAgY2xvbmVkQWN0aW9uID0gYXdhaXQgdGhpcy5wcm9jZXNzTWlkZGxld2FyZShwb3N0RGlzcGF0Y2hMaXN0LCBjbG9uZWRBY3Rpb24sIGFwcEluZm8pO1xuICAgIH1cblxuICAgIGlmKCFzaWxlbnQpIHtcbiAgICAgIHRoaXMuZW1pdCh0eXBlLCBjbG9uZWRBY3Rpb24pO1xuICAgICAgdGhpcy5lbWl0KCdhcmtoYW1qcycsIHRoaXMuc3RhdGUpO1xuICAgIH1cblxuICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoY2xvbmVkQWN0aW9uKTtcbiAgfVxuXG4gIGdldE9wdGlvbnMoKTogRmx1eE9wdGlvbnMge1xuICAgIHJldHVybiB0aGlzLm9wdGlvbnM7XG4gIH1cblxuICBnZXRTdGF0ZTxUID0gdW5rbm93bj4ocGF0aDogc3RyaW5nIHwgc3RyaW5nW10gPSAnJywgZGVmYXVsdFZhbHVlPzogVCk6IFQge1xuICAgIGNvbnN0IHBhdGhLZXkgPSBBcnJheS5pc0FycmF5KHBhdGgpID8gcGF0aC5qb2luKCcuJykgOiBwYXRoO1xuXG4gICAgaWYodGhpcy5zdGF0ZUNhY2hlLmhhcyhwYXRoS2V5KSkge1xuICAgICAgcmV0dXJuIHRoaXMuc3RhdGVDYWNoZS5nZXQocGF0aEtleSkgYXMgVDtcbiAgICB9XG5cbiAgICBsZXQgc3RvcmVWYWx1ZTogdW5rbm93bjtcbiAgICBpZighcGF0aCkge1xuICAgICAgc3RvcmVWYWx1ZSA9IHRoaXMuc3RhdGUgfHwge307XG4gICAgfSBlbHNlIHtcbiAgICAgIHN0b3JlVmFsdWUgPSBnZXQodGhpcy5zdGF0ZSwgcGF0aCk7XG4gICAgfVxuXG4gICAgY29uc3QgdmFsdWUgPSBzdG9yZVZhbHVlID8gY2xvbmVEZWVwKHN0b3JlVmFsdWUpIDogc3RvcmVWYWx1ZTtcbiAgICBjb25zdCByZXN1bHQgPSB2YWx1ZSA9PT0gdW5kZWZpbmVkID8gZGVmYXVsdFZhbHVlIDogdmFsdWU7XG5cbiAgICB0aGlzLnN0YXRlQ2FjaGUuc2V0KHBhdGhLZXksIHJlc3VsdCk7XG5cbiAgICByZXR1cm4gcmVzdWx0IGFzIFQ7XG4gIH1cblxuICBnZXRTdG9yZShuYW1lOiBzdHJpbmcgPSAnJyk6IEZsdXhTdG9yZSB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuc3RvcmVBY3Rpb25zW25hbWVdO1xuICB9XG5cbiAgYXN5bmMgaW5pdChvcHRpb25zOiBGbHV4T3B0aW9ucyA9IHt9LCByZXNldDogYm9vbGVhbiA9IGZhbHNlKTogUHJvbWlzZTxGbHV4RnJhbWV3b3JrPiB7XG4gICAgaWYocmVzZXQpIHtcbiAgICAgIHRoaXMuaXNJbml0ID0gZmFsc2U7XG4gICAgICBhd2FpdCB0aGlzLnJlc2V0KGZhbHNlKTtcbiAgICB9XG5cbiAgICBjb25zdCB1cGRhdGVkT3B0aW9ucyA9IHsuLi5vcHRpb25zfTtcbiAgICBpZih0aGlzLmlzSW5pdCAmJiB0aGlzLm9wdGlvbnMubmFtZSkge1xuICAgICAgdXBkYXRlZE9wdGlvbnMubmFtZSA9IHRoaXMub3B0aW9ucy5uYW1lO1xuICAgIH1cblxuICAgIHRoaXMub3B0aW9ucyA9IHsuLi50aGlzLmRlZmF1bHRPcHRpb25zLCAuLi51cGRhdGVkT3B0aW9uc307XG4gICAgY29uc3Qge2RlYnVnLCBtaWRkbGV3YXJlLCBuYW1lLCBzdG9yZXN9ID0gdGhpcy5vcHRpb25zO1xuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHRoaXMudXNlU3RvcmFnZShuYW1lID8/ICdhcmtoYW1qcycpO1xuICAgIH0gY2F0Y2goZXJyb3IpIHtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1jb25zb2xlXG4gICAgICBjb25zb2xlLmVycm9yKCdBcmtoYW0gRXJyb3I6IFRoZXJlIHdhcyBhbiBlcnJvciB3aGlsZSB1c2luZyBzdG9yYWdlLicsIG5hbWUpO1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuXG4gICAgaWYoc3RvcmVzPy5sZW5ndGgpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHRoaXMuYWRkU3RvcmVzKHN0b3Jlcyk7XG4gICAgICB9IGNhdGNoKGVycm9yKSB7XG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1jb25zb2xlXG4gICAgICAgIGNvbnNvbGUuZXJyb3IoJ0Fya2hhbSBFcnJvcjogVGhlcmUgd2FzIGFuIGVycm9yIHdoaWxlIGFkZGluZyBzdG9yZXMuJywgc3RvcmVzKTtcbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYobWlkZGxld2FyZT8ubGVuZ3RoKSB7XG4gICAgICB0aGlzLmFkZE1pZGRsZXdhcmUobWlkZGxld2FyZSk7XG4gICAgfVxuXG4gICAgY29uc3Qgd2luZG93UHJvcGVydHk6IHN0cmluZyA9ICdhcmtoYW1qcyc7XG4gICAgaWYoZGVidWcpIHtcbiAgICAgICh3aW5kb3cgYXMgYW55KVt3aW5kb3dQcm9wZXJ0eV0gPSB0aGlzO1xuICAgIH0gZWxzZSB7XG4gICAgICBkZWxldGUgKHdpbmRvdyBhcyBhbnkpW3dpbmRvd1Byb3BlcnR5XTtcbiAgICB9XG5cbiAgICB0aGlzLmlzSW5pdCA9IHRydWU7XG4gICAgdGhpcy5lbWl0KEFya2hhbUNvbnN0YW50cy5JTklUKTtcblxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgb25Jbml0KGxpc3RlbmVyOiAoLi4uYXJnczogYW55W10pID0+IHZvaWQpOiB2b2lkIHtcbiAgICB0aGlzLm9uKEFya2hhbUNvbnN0YW50cy5JTklULCBsaXN0ZW5lcik7XG5cbiAgICBpZih0aGlzLmlzSW5pdCkge1xuICAgICAgbGlzdGVuZXIoKTtcbiAgICB9XG4gIH1cblxuICBvZmZJbml0KGxpc3RlbmVyOiAoLi4uYXJnczogYW55W10pID0+IHZvaWQpOiB2b2lkIHtcbiAgICB0aGlzLm9mZihBcmtoYW1Db25zdGFudHMuSU5JVCwgbGlzdGVuZXIpO1xuICB9XG5cbiAgb3ZlcnJpZGUgb2ZmKGV2ZW50VHlwZTogc3RyaW5nLCBsaXN0ZW5lcjogKC4uLmFyZ3M6IGFueVtdKSA9PiB2b2lkKTogdGhpcyB7XG4gICAgcmV0dXJuIHRoaXMucmVtb3ZlTGlzdGVuZXIoZXZlbnRUeXBlLCBsaXN0ZW5lcik7XG4gIH1cblxuICBvdmVycmlkZSBvbihldmVudFR5cGU6IHN0cmluZywgbGlzdGVuZXI6ICguLi5hcmdzOiBhbnlbXSkgPT4gdm9pZCk6IHRoaXMge1xuICAgIHJldHVybiB0aGlzLmFkZExpc3RlbmVyKGV2ZW50VHlwZSwgbGlzdGVuZXIpO1xuICB9XG5cbiAgYXN5bmMgYWRkU3RvcmVzKHN0b3JlczogRmx1eFN0b3JlW10pOiBQcm9taXNlPEZsdXhTdG9yZVtdPiB7XG4gICAgY29uc3QgcmVnaXN0ZXJlZFN0b3JlczogRmx1eFN0b3JlW10gPSBzdG9yZXMubWFwKChzdG9yZTogRmx1eFN0b3JlKSA9PiB0aGlzLnJlZ2lzdGVyKHN0b3JlKSk7XG4gICAgY29uc3Qge25hbWUsIHN0b3JhZ2V9ID0gdGhpcy5vcHRpb25zO1xuXG4gICAgaWYoc3RvcmFnZT8uc2V0U3RvcmFnZURhdGEpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHN0b3JhZ2Uuc2V0U3RvcmFnZURhdGEobmFtZSA/PyAnYXJraGFtanMnLCB0aGlzLnN0YXRlKTtcbiAgICAgIH0gY2F0Y2goZXJyb3IpIHtcbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlZ2lzdGVyZWRTdG9yZXM7XG4gIH1cblxuICByZW1vdmVNaWRkbGV3YXJlKG5hbWVzOiBzdHJpbmdbXSk6IHZvaWQge1xuICAgIG5hbWVzLmZvckVhY2goKG5hbWU6IHN0cmluZykgPT4ge1xuICAgICAgdGhpcy5wbHVnaW5UeXBlcy5mb3JFYWNoKCh0eXBlOiBzdHJpbmcpID0+IHtcbiAgICAgICAgdGhpcy5taWRkbGV3YXJlW2Ake3R5cGV9TGlzdGBdID0gdGhpcy5yZW1vdmVQbHVnaW4odHlwZSwgbmFtZSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIGFzeW5jIHJlc2V0KGNsZWFyU3RvcmFnZTogYm9vbGVhbiA9IHRydWUpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB7bmFtZSwgc3RvcmFnZX0gPSB0aGlzLm9wdGlvbnM7XG5cbiAgICBpZihzdG9yYWdlICYmIGNsZWFyU3RvcmFnZSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgc3RvcmFnZS5zZXRTdG9yYWdlRGF0YT8uKG5hbWUgPz8gJ2Fya2hhbWpzJywge30pO1xuICAgICAgfSBjYXRjaChlcnJvcikge1xuICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLm1pZGRsZXdhcmUgPSB7fTtcbiAgICB0aGlzLm9wdGlvbnMgPSB7Li4udGhpcy5kZWZhdWx0T3B0aW9uc307XG4gICAgdGhpcy5zdGF0ZSA9IHt9O1xuICAgIHRoaXMuc3RvcmVBY3Rpb25zID0ge307XG4gICAgdGhpcy5zdGF0ZUNhY2hlLmNsZWFyKCk7XG4gICAgdGhpcy5zdGF0ZUNoYW5nZWQgPSBmYWxzZTtcbiAgICB0aGlzLmlzSW5pdCA9IGZhbHNlO1xuXG4gICAgdGhpcy5wbHVnaW5UeXBlcy5mb3JFYWNoKCh0eXBlOiBzdHJpbmcpID0+IHRoaXMubWlkZGxld2FyZVtgJHt0eXBlfUxpc3RgXSA9IFtdKTtcbiAgfVxuXG4gIHNldFN0YXRlKHBhdGg6IHN0cmluZyB8IHN0cmluZ1tdID0gJycsIHZhbHVlOiB1bmtub3duKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgaWYocGF0aCkge1xuICAgICAgdGhpcy5zdGF0ZSA9IHNldCh0aGlzLnN0YXRlLCBwYXRoLCBjbG9uZURlZXAodmFsdWUpKTtcbiAgICAgIHRoaXMuc3RhdGVDaGFuZ2VkID0gdHJ1ZTtcblxuICAgICAgY29uc3QgcGF0aEtleSA9IEFycmF5LmlzQXJyYXkocGF0aCkgPyBwYXRoLmpvaW4oJy4nKSA6IHBhdGg7XG4gICAgICB0aGlzLnN0YXRlQ2FjaGUuZGVsZXRlKHBhdGhLZXkpO1xuICAgIH1cblxuICAgIGlmKHRoaXMub3B0aW9ucy5zdG9yYWdlICYmIHRoaXMudXBkYXRlU3RvcmFnZSkge1xuICAgICAgcmV0dXJuIHRoaXMudXBkYXRlU3RvcmFnZSgpO1xuICAgIH1cblxuICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoZmFsc2UpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBwcm9jZXNzTWlkZGxld2FyZShcbiAgICBtaWRkbGV3YXJlTGlzdDogRmx1eFBsdWdpblR5cGVbXSxcbiAgICBhY3Rpb246IEZsdXhBY3Rpb24sXG4gICAgYXBwSW5mbzogUmVjb3JkPHN0cmluZywgdW5rbm93bj5cbiAgKTogUHJvbWlzZTxGbHV4QWN0aW9uPiB7XG4gICAgcmV0dXJuIFByb21pc2VcbiAgICAgIC5hbGwoXG4gICAgICAgIG1pZGRsZXdhcmVMaXN0Lm1hcCgocGx1Z2luOiBGbHV4UGx1Z2luVHlwZSkgPT5cbiAgICAgICAgICBwbHVnaW4ubWV0aG9kKGNsb25lRGVlcChhY3Rpb24pLCBjbG9uZURlZXAodGhpcy5zdGF0ZSksIGFwcEluZm8pXG4gICAgICAgIClcbiAgICAgIClcbiAgICAgIC50aGVuKFxuICAgICAgICAoYWN0aW9ucykgPT4gYWN0aW9ucy5yZWR1Y2UoKHVwZGF0ZWRBY3Rpb24sIGFjdGlvbikgPT5cbiAgICAgICAgICBtZXJnZSh1cGRhdGVkQWN0aW9uLCBhY3Rpb24pLCBhY3Rpb24pIGFzIEZsdXhBY3Rpb25cbiAgICAgIClcbiAgICAgIC5jYXRjaCgoZXJyb3IpID0+IHtcbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgdXBkYXRlU3RvcmFnZTogKCkgPT4gUHJvbWlzZTxib29sZWFuPiA9ICgpID0+IFByb21pc2UucmVzb2x2ZShmYWxzZSk7XG5cbiAgcHJpdmF0ZSB1cGRhdGVTdG9yZXNTdGF0ZSh0eXBlOiBzdHJpbmcsIGRhdGE6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogdm9pZCB7XG4gICAgT2JqZWN0LmtleXModGhpcy5zdG9yZUFjdGlvbnMpLmZvckVhY2goKHN0b3JlTmFtZTogc3RyaW5nKSA9PiB7XG4gICAgICBjb25zdCBzdG9yZUZuID0gdGhpcy5zdG9yZUFjdGlvbnNbc3RvcmVOYW1lXTtcbiAgICAgIGlmKHN0b3JlRm4pIHtcbiAgICAgICAgY29uc3QgY3VycmVudFN0YXRlID0gdGhpcy5zdGF0ZVtzdG9yZU5hbWVdIHx8IHN0b3JlRm4uaW5pdGlhbFN0YXRlIHx8IHt9O1xuXG4gICAgICAgIGNvbnN0IG5ld1N0YXRlID0gc3RvcmVGbi5hY3Rpb24odHlwZSwgZGF0YSwgY3VycmVudFN0YXRlKTtcbiAgICAgICAgaWYobmV3U3RhdGUgIT09IGN1cnJlbnRTdGF0ZSkge1xuICAgICAgICAgIHRoaXMuc3RhdGVbc3RvcmVOYW1lXSA9IGNsb25lRGVlcChuZXdTdGF0ZSkgfHwgY3VycmVudFN0YXRlO1xuICAgICAgICAgIHRoaXMuc3RhdGVDaGFuZ2VkID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRDYWNoZWRTdGFjaygpOiB1bmtub3duW10ge1xuICAgIGNvbnN0IGNhY2hlS2V5ID0gbmV3IEVycm9yKCkuc3RhY2s/LnNwbGl0KCdcXG4nKVsyXSB8fCAnJztcblxuICAgIGlmKFNUQUNLX0NBQ0hFLmhhcyhjYWNoZUtleSkpIHtcbiAgICAgIHJldHVybiBTVEFDS19DQUNIRS5nZXQoY2FjaGVLZXkpITtcbiAgICB9XG5cbiAgICBsZXQgc3RhY2s6IHVua25vd25bXSA9IFtdO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBzdGFja1Byb3BlcnR5ID0gJ3N0YWNrVHJhY2VMaW1pdCc7XG4gICAgICBjb25zdCBvcmlnaW5hbExpbWl0ID0gKEVycm9yIGFzIGFueSkuc3RhY2tUcmFjZUxpbWl0O1xuICAgICAgKEVycm9yIGFzIGFueSlbc3RhY2tQcm9wZXJ0eV0gPSBJbmZpbml0eTtcbiAgICAgIHN0YWNrID0gcGFyc2VTdGFjayhuZXcgRXJyb3IoKSk7XG4gICAgICAoRXJyb3IgYXMgYW55KVtzdGFja1Byb3BlcnR5XSA9IG9yaWdpbmFsTGltaXQ7XG5cbiAgICAgIGlmKFNUQUNLX0NBQ0hFLnNpemUgPj0gU1RBQ0tfQ0FDSEVfU0laRSkge1xuICAgICAgICBjb25zdCBmaXJzdEtleSA9IFNUQUNLX0NBQ0hFLmtleXMoKS5uZXh0KCkudmFsdWU7XG4gICAgICAgIGlmKGZpcnN0S2V5KSB7XG4gICAgICAgICAgU1RBQ0tfQ0FDSEUuZGVsZXRlKGZpcnN0S2V5KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgU1RBQ0tfQ0FDSEUuc2V0KGNhY2hlS2V5LCBzdGFjayk7XG4gICAgfSBjYXRjaChlcnJvcikge1xuICAgIH1cblxuICAgIHJldHVybiBzdGFjaztcbiAgfVxuXG4gIHByaXZhdGUgYWRkUGx1Z2luKHR5cGU6IHN0cmluZywgcGx1Z2luOiBGbHV4UGx1Z2luVHlwZSk6IEZsdXhQbHVnaW5UeXBlW10ge1xuICAgIGNvbnN0IGxpc3QgPSB0aGlzLm1pZGRsZXdhcmVbYCR7dHlwZX1MaXN0YF0gfHwgW107XG4gICAgY29uc3Qge21ldGhvZCwgbmFtZX0gPSBwbHVnaW47XG5cbiAgICBpZihtZXRob2QgJiYgdHlwZW9mIG1ldGhvZCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgY29uc3QgZXhpc3RzOiBib29sZWFuID0gbGlzdC5zb21lKChvYmo6IEZsdXhQbHVnaW5UeXBlKSA9PiBvYmoubmFtZSA9PT0gbmFtZSk7XG4gICAgICBpZighZXhpc3RzKSB7XG4gICAgICAgIGxpc3QucHVzaCh7bWV0aG9kLCBuYW1lfSk7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmKG1ldGhvZCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBFcnJvcihgJHtwbHVnaW4ubmFtZX0gbWlkZGxld2FyZSBpcyBub3QgY29uZmlndXJlZCBwcm9wZXJseS4gTWV0aG9kIGlzIG5vdCBhIGZ1bmN0aW9uLmApO1xuICAgIH1cblxuICAgIHJldHVybiBsaXN0O1xuICB9XG5cbiAgcHJpdmF0ZSBkZXJlZ2lzdGVyKG5hbWU6IHN0cmluZyA9ICcnKTogdm9pZCB7XG4gICAgZGVsZXRlIHRoaXMuc3RvcmVBY3Rpb25zW25hbWVdO1xuICAgIGRlbGV0ZSB0aGlzLnN0YXRlW25hbWVdO1xuICAgIHRoaXMuc3RhdGVDYWNoZS5jbGVhcigpOyAvLyBDbGVhciBjYWNoZSB3aGVuIHN0b3JlcyBjaGFuZ2VcbiAgfVxuXG4gIHByaXZhdGUgcmVnaXN0ZXIoc3RvcmU6IGFueSk6IEZsdXhTdG9yZSB7XG4gICAgaWYoIXN0b3JlKSB7XG4gICAgICB0aHJvdyBFcnJvcignU3RvcmUgaXMgdW5kZWZpbmVkLiBDYW5ub3QgcmVnaXN0ZXIgd2l0aCBGbHV4LicpO1xuICAgIH1cblxuICAgIGxldCBzdG9yZU5hbWU6IHN0cmluZztcbiAgICBsZXQgc3RvcmVBY3Rpb246ICh0eXBlOiBzdHJpbmcsIGRhdGE6IHVua25vd24sIHN0YXRlOiB1bmtub3duKSA9PiB1bmtub3duO1xuICAgIGxldCBpbml0aWFsU3RhdGU6IHVua25vd247XG5cbiAgICBpZih0eXBlb2Ygc3RvcmUgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgIC8vIEZ1bmN0aW9uIHN0b3JlIC0gZXh0cmFjdCBuYW1lIGZyb20gZnVuY3Rpb24ubmFtZVxuICAgICAgc3RvcmVOYW1lID0gc3RvcmUubmFtZSB8fCAnYW5vbnltb3VzJztcbiAgICAgIHN0b3JlQWN0aW9uID0gc3RvcmU7XG4gICAgICBpbml0aWFsU3RhdGUgPSBzdG9yZSgpO1xuICAgIH0gZWxzZSBpZih0eXBlb2Ygc3RvcmU/LmFjdGlvbiA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgLy8gT2JqZWN0IHN0b3JlIHdpdGggYWN0aW9uIG1ldGhvZFxuICAgICAgc3RvcmVOYW1lID0gc3RvcmUubmFtZSB8fCAnYW5vbnltb3VzJztcbiAgICAgIHN0b3JlQWN0aW9uID0gc3RvcmUuYWN0aW9uO1xuICAgICAgaW5pdGlhbFN0YXRlID0gc3RvcmUuaW5pdGlhbFN0YXRlIHx8IHN0b3JlLmFjdGlvbigpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBFcnJvcihgJHtzdG9yZX0gaXMgbm90IGEgdmFsaWQgc3RvcmUuIE11c3QgYmUgYSBmdW5jdGlvbiBvciBvYmplY3Qgd2l0aCBhY3Rpb24gbWV0aG9kLmApO1xuICAgIH1cblxuICAgIGlmKCFzdG9yZU5hbWUgfHwgc3RvcmVOYW1lID09PSAnYW5vbnltb3VzJykge1xuICAgICAgLy8gU2lsZW50bHkgaWdub3JlIGFub255bW91cyBzdG9yZXMgLSByZXR1cm4gdW5kZWZpbmVkXG4gICAgICByZXR1cm4gdW5kZWZpbmVkIGFzIGFueTtcbiAgICB9XG5cbiAgICBjb25zdCBmbHV4U3RvcmU6IEZsdXhTdG9yZSA9IHtcbiAgICAgIGFjdGlvbjogc3RvcmVBY3Rpb24sXG4gICAgICBpbml0aWFsU3RhdGUsXG4gICAgICBuYW1lOiBzdG9yZU5hbWVcbiAgICB9O1xuXG4gICAgaWYoIXRoaXMuc3RvcmVBY3Rpb25zW3N0b3JlTmFtZV0pIHtcbiAgICAgIHRoaXMuc3RvcmVBY3Rpb25zW3N0b3JlTmFtZV0gPSBmbHV4U3RvcmU7XG5cbiAgICAgIGlmKCF0aGlzLnN0YXRlW3N0b3JlTmFtZV0pIHtcbiAgICAgICAgdGhpcy5zdGF0ZVtzdG9yZU5hbWVdID0gY2xvbmVEZWVwKGluaXRpYWxTdGF0ZSB8fCB7fSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuc3RvcmVBY3Rpb25zW3N0b3JlTmFtZV0hO1xuICB9XG5cbiAgcHJpdmF0ZSByZW1vdmVQbHVnaW4odHlwZTogc3RyaW5nLCBuYW1lOiBzdHJpbmcpOiBGbHV4UGx1Z2luVHlwZVtdIHtcbiAgICBjb25zdCBsaXN0ID0gdGhpcy5taWRkbGV3YXJlW2Ake3R5cGV9TGlzdGBdIHx8IFtdO1xuICAgIHJldHVybiBsaXN0LmZpbHRlcigob2JqOiBGbHV4UGx1Z2luVHlwZSkgPT4gb2JqLm5hbWUgIT09IG5hbWUpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyB1c2VTdG9yYWdlKG5hbWU6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHtzdG9yYWdlLCBzdGF0ZSwgc3RvcmFnZVdhaXR9ID0gdGhpcy5vcHRpb25zO1xuXG4gICAgaWYoc3RvcmFnZSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgdGhpcy5zdGF0ZSA9IHN0YXRlIHx8IGF3YWl0IHN0b3JhZ2U/LmdldFN0b3JhZ2VEYXRhPy4obmFtZSkgfHwge307XG4gICAgICAgIHRoaXMudXBkYXRlU3RvcmFnZSA9IGRlYm91bmNlQ29tcGFjdChcbiAgICAgICAgICAoKSA9PiBzdG9yYWdlPy5zZXRTdG9yYWdlRGF0YT8uKG5hbWUsIHRoaXMuc3RhdGUpLFxuICAgICAgICAgIHN0b3JhZ2VXYWl0ID8/IDMwMFxuICAgICAgICApIGFzIGFueTtcbiAgICAgIH0gY2F0Y2goZXJyb3IpIHtcbiAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWNvbnNvbGVcbiAgICAgICAgY29uc29sZS5lcnJvcihgQXJraGFtSlMgRXJyb3I6IFVzaW5nIHN0b3JhZ2UsIFwiJHtuYW1lfVwiLmApO1xuICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5zdGF0ZSA9IHN0YXRlIHx8IHt9O1xuICAgIH1cbiAgfVxufVxuXG5leHBvcnQgY29uc3QgRmx1eDogRmx1eEZyYW1ld29yayA9IG5ldyBGbHV4RnJhbWV3b3JrKCk7XG4iXSwibmFtZXMiOlsiY2xvbmVEZWVwIiwiZGVib3VuY2VDb21wYWN0IiwiZ2V0IiwibWVyZ2UiLCJzZXQiLCJwYXJzZVN0YWNrIiwiRXZlbnRFbWl0dGVyIiwiQXJraGFtQ29uc3RhbnRzIiwiU1RBQ0tfQ0FDSEUiLCJNYXAiLCJTVEFDS19DQUNIRV9TSVpFIiwiRmx1eEZyYW1ld29yayIsImFkZE1pZGRsZXdhcmUiLCJtaWRkbGV3YXJlIiwiZm9yRWFjaCIsIm1pZGRsZU9iaiIsIkVycm9yIiwibWlkZGxlTmFtZSIsIm5hbWUiLCJleGlzdGluZ01pZGRsZXdhcmUiLCJwcmVEaXNwYXRjaExpc3QiLCJmaW5kIiwibSIsInBvc3REaXNwYXRjaExpc3QiLCJjb25zb2xlIiwid2FybiIsInBsdWdpblR5cGVzIiwidHlwZSIsIm1ldGhvZCIsInBsdWdpbiIsImFkZFBsdWdpbiIsImNsZWFyQXBwRGF0YSIsIk9iamVjdCIsImtleXMiLCJzdG9yZUFjdGlvbnMiLCJzdG9yZU5hbWUiLCJzdG9yZUZuIiwic3RhdGUiLCJpbml0aWFsU3RhdGUiLCJzdGF0ZUNhY2hlIiwiY2xlYXIiLCJzdGF0ZUNoYW5nZWQiLCJzdG9yYWdlIiwib3B0aW9ucyIsInNldFN0b3JhZ2VEYXRhIiwiUHJvbWlzZSIsInJlc29sdmUiLCJjbGVhck1pZGRsZXdhcmUiLCJwbHVnaW5UeXBlIiwicmVtb3ZlU3RvcmVzIiwic3RvcmVOYW1lcyIsImRlcmVnaXN0ZXIiLCJkaXNwYXRjaCIsImFjdGlvbiIsInNpbGVudCIsInN0YXJ0VGltZSIsIkRhdGUiLCJub3ciLCJjbG9uZWRBY3Rpb24iLCJzdGFjayIsImRlYnVnIiwiZ2V0Q2FjaGVkU3RhY2siLCJhcHBJbmZvIiwiZHVyYXRpb24iLCJsZW5ndGgiLCJwcm9jZXNzTWlkZGxld2FyZSIsImRhdGEiLCJ1cGRhdGVTdG9yZXNTdGF0ZSIsInVwZGF0ZVN0b3JhZ2UiLCJlcnJvciIsImVtaXQiLCJnZXRPcHRpb25zIiwiZ2V0U3RhdGUiLCJwYXRoIiwiZGVmYXVsdFZhbHVlIiwicGF0aEtleSIsIkFycmF5IiwiaXNBcnJheSIsImpvaW4iLCJoYXMiLCJzdG9yZVZhbHVlIiwidmFsdWUiLCJyZXN1bHQiLCJ1bmRlZmluZWQiLCJnZXRTdG9yZSIsImluaXQiLCJyZXNldCIsImlzSW5pdCIsInVwZGF0ZWRPcHRpb25zIiwiZGVmYXVsdE9wdGlvbnMiLCJzdG9yZXMiLCJ1c2VTdG9yYWdlIiwiYWRkU3RvcmVzIiwid2luZG93UHJvcGVydHkiLCJ3aW5kb3ciLCJJTklUIiwib25Jbml0IiwibGlzdGVuZXIiLCJvbiIsIm9mZkluaXQiLCJvZmYiLCJldmVudFR5cGUiLCJyZW1vdmVMaXN0ZW5lciIsImFkZExpc3RlbmVyIiwicmVnaXN0ZXJlZFN0b3JlcyIsIm1hcCIsInN0b3JlIiwicmVnaXN0ZXIiLCJyZW1vdmVNaWRkbGV3YXJlIiwibmFtZXMiLCJyZW1vdmVQbHVnaW4iLCJjbGVhclN0b3JhZ2UiLCJzZXRTdGF0ZSIsImRlbGV0ZSIsIm1pZGRsZXdhcmVMaXN0IiwiYWxsIiwidGhlbiIsImFjdGlvbnMiLCJyZWR1Y2UiLCJ1cGRhdGVkQWN0aW9uIiwiY2F0Y2giLCJjdXJyZW50U3RhdGUiLCJuZXdTdGF0ZSIsImNhY2hlS2V5Iiwic3BsaXQiLCJzdGFja1Byb3BlcnR5Iiwib3JpZ2luYWxMaW1pdCIsInN0YWNrVHJhY2VMaW1pdCIsIkluZmluaXR5Iiwic2l6ZSIsImZpcnN0S2V5IiwibmV4dCIsImxpc3QiLCJleGlzdHMiLCJzb21lIiwib2JqIiwicHVzaCIsInN0b3JlQWN0aW9uIiwiZmx1eFN0b3JlIiwiZmlsdGVyIiwic3RvcmFnZVdhaXQiLCJnZXRTdG9yYWdlRGF0YSIsInJvdXRlclR5cGUiLCJzY3JvbGxUb1RvcCIsInRpdGxlIiwiYmluZCIsImluaXRGbHV4IiwiRmx1eCJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7OztBQUFBOzs7Q0FHQyxHQUNELFNBQVFBLFNBQVMsUUFBTyw2QkFBNkI7QUFDckQsU0FBUUMsZUFBZSxRQUFPLHdDQUF3QztBQUN0RSxTQUFRQyxHQUFHLFFBQU8sMkJBQTJCO0FBQzdDLFNBQVFDLEtBQUssUUFBTyw2QkFBNkI7QUFDakQsU0FBUUMsR0FBRyxRQUFPLDJCQUEyQjtBQUM3QyxTQUFRQyxVQUFVLFFBQU8sb0NBQW9DO0FBQzdELFNBQVFDLFlBQVksUUFBTyxTQUFTO0FBRXBDLFNBQVFDLGVBQWUsUUFBTyxrQ0FBa0M7QUFJaEUsTUFBTUMsY0FBYyxJQUFJQztBQUN4QixNQUFNQyxtQkFBbUI7QUFFekIsT0FBTyxNQUFNQyxzQkFBc0JMO0lBNkNqQ00sY0FBY0MsVUFBZ0MsRUFBUTtRQUNwREEsV0FBV0MsT0FBTyxDQUFDLENBQUNDO1lBQ2xCLElBQUcsQ0FBQ0EsYUFBYyxPQUFPQSxjQUFjLGNBQWMsT0FBT0EsY0FBYyxVQUFXO2dCQUNuRixNQUFNQyxNQUFNO1lBQ2Q7WUFFQSxNQUFNQyxhQUFxQkYsVUFBVUcsSUFBSSxJQUFJO1lBQzdDLElBQUcsQ0FBQ0QsWUFBWTtnQkFDZCxNQUFNRCxNQUFN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