@netgrif/components-core
Version:
Netgrif Application engine frontend core Angular library
284 lines • 42 kB
JavaScript
import { BehaviorSubject, of } from 'rxjs';
import { catchError, take, tap, map, distinctUntilChanged } from 'rxjs/operators';
export class ConfigurationService {
configuration;
_configurationResource;
_applicationConfiguration;
_dataFieldConfiguration;
APPLICATION_CONFIG;
_config$ = new BehaviorSubject(null);
config$ = this._config$.asObservable();
loaded$ = this.config$.pipe(map(cfg => !!cfg), distinctUntilChanged());
constructor(configuration, _configurationResource, _applicationConfiguration) {
this.configuration = configuration;
this._configurationResource = _configurationResource;
this._applicationConfiguration = _applicationConfiguration;
this.APPLICATION_CONFIG = _applicationConfiguration;
if (!this._applicationConfiguration?.resolve_configuration) {
this.initialize();
}
}
get snapshot() {
return this.configuration ? this.createConfigurationCopy() : null;
}
initialize() {
this.resolveEndpointURLs();
this._dataFieldConfiguration = this.getConfigurationSubtree(['services', 'dataFields']);
this._config$.next(this.createConfigurationCopy());
}
getAsync() {
return of(this.get());
}
/**
* Calls to this method should be avoided as creating a deep copy of the configuration has a large overhead
*
* @returns a deep copy of the entire configuration object
*/
get() {
return this.createConfigurationCopy();
}
/**
* Get view configuration from nae.json for view at given config path.
* @param viewConfigPath configuration path to the requested view. No leading backslash.
* @return requested configuration if it exists. `undefined` otherwise.
*/
getViewByPath(viewConfigPath) {
const viewPathSegments = viewConfigPath.split('/');
const configTreePathSegments = ['views'];
for (let i = 0; i < viewPathSegments.length; i++) {
if (i > 0) {
configTreePathSegments.push('children');
}
configTreePathSegments.push(viewPathSegments[i]);
}
return this.getConfigurationSubtree(configTreePathSegments);
}
/**
* Get view configuration from nae.json for view at given url.
* @param url to the requested view. Necessary backslash.
* @return requested configuration if it exists. `undefined` otherwise.
*/
getViewByUrl(url) {
const views = this.getViewsCopy();
if (!views) {
return undefined;
}
let map = new Map();
map = this.getChildren(views, map, '');
if (map.get(url) === undefined) {
for (const [key, value] of map) {
if (key?.includes('/**') && url?.includes(key.split('/**')[0]))
return value;
}
}
return map.get(url);
}
getChildren(views, map, prefix) {
Object.keys(views).forEach(view => {
if (!!views[view].routing.path) {
prefix = prefix.charAt(prefix.length - 1) === '/' ?
prefix.length > 1 ? prefix.substring(0, prefix.length - 2) : '' :
prefix;
const viewPath = views[view].routing.path.charAt(0) === '/' ?
views[view].routing.path.length > 1 ? views[view].routing.path.substring(1) : '' :
views[view].routing.path;
map.set(views[view].routing.match ?
prefix + '/' + viewPath + '/**' :
prefix + '/' + viewPath, views[view]);
}
if (views[view].children) {
this.getChildren(views[view].children, map, prefix + '/' + views[view].routing.path);
}
});
return map;
}
/**
* Get all URLs/paths of views with specified layout.
* @param layout Search views with this layout
* @returns Paths with prefixed '/' of all views with specified layout, empty array otherwise.
*/
getPathsByView(layout) {
const config = this.createConfigurationCopy();
const result = [];
if (!config.views) {
return result;
}
Object.values(config.views).forEach(view => {
result.push(...this.getView(layout, view).map(path => '/' + path));
});
return result;
}
getConfigurationSubtreeByPath(path) {
return this.getConfigurationSubtree(path.split('.'));
}
/**
* @param pathSegments the keys specifying the path trough the configuration that should be accessed
* @returns a deep copy of a specified subsection of the configuration object, or `undefined` if such subsection doesn't exist.
* Calling this method with an empty array as argument is equivalent to calling the [get()]{@link ConfigurationService#get} method.
*/
getConfigurationSubtree(pathSegments) {
let root = this.configuration;
for (const segment of pathSegments) {
if (root[segment] === undefined) {
return undefined;
}
root = root[segment];
}
return this.deepCopy(root);
}
/**
* @returns the appropriate template configuration for data fields, or `undefined` if such configuration is not present.
*/
getDatafieldConfiguration() {
if (this._dataFieldConfiguration === undefined) {
return undefined;
}
return { ...this._dataFieldConfiguration };
}
/**
* Resolves the URL addresses of backend endpoints based on the provided configuration.
*
* If the URLs begin with either `http://`, or `https://` the provided URL will be used.
*
* If not, then the URLs are considered to be relative to the location of the frontend application and it's URL will be used
* as the base path. `/api` is appended automatically.
*/
resolveEndpointURLs() {
if (this.configuration?.providers?.auth?.address === undefined) {
throw new Error(`'provider.auth.address' is a required property and must be present in the configuration!`);
}
this.configuration.providers.auth.address = this.resolveURL(this.configuration.providers.auth.address);
if (this.configuration?.providers?.resources === undefined) {
throw new Error(`'provider.resources' is a required property and must be present in the configuration!`);
}
if (Array.isArray(this.configuration.providers.resources)) {
this.configuration.providers.resources.forEach(resource => {
if (resource?.address === undefined) {
throw new Error(`Resources defined in 'provider.resources' must define an address property!`);
}
resource.address = this.resolveURL(resource.address);
});
}
else {
if (this.configuration?.providers?.resources?.address === undefined) {
throw new Error(`Resources defined in 'provider.resources' must define an address property!`);
}
this.configuration.providers.resources.address = this.resolveURL(this.configuration.providers.resources.address);
}
}
/**
* Resolves a single URL address.
*
* If the URL begins with either `http://`, or `https://` the provided URL will be used.
*
* If not, then the URL is considered to be relative to the location of the frontend application and it's URL will be used
* as the base path. `/api` is appended automatically.
*
* @param configURL value from the configuration file
* @returns the resolved URL
*/
resolveURL(configURL) {
if (configURL.startsWith('http://') || configURL.startsWith('https://')) {
return configURL;
}
else {
return location.origin + '/api' + configURL;
}
}
/**
* @returns the services configuration, or `undefined` if such configuration is not present.
*/
getServicesConfiguration() {
const subtree = this.getConfigurationSubtree(['services']);
return subtree !== undefined ? this.deepCopy(subtree) : undefined;
}
/**
* @returns the value stored in the [onLogoutRedirect]{@link Services#auth.onLogoutRedirect} attribute if defined.
* If not and the deprecated attribute [logoutRedirect]{@link Services#auth.logoutRedirect} is defined then its value is returned.
* Otherwise, `undefined` is returned.
*/
getOnLogoutPath() {
return this.configuration?.services?.auth?.onLogoutRedirect ?? this.configuration?.services?.auth?.logoutRedirect;
}
/**
* @returns the value stored in the [toLoginRedirect]{@link Services#auth.toLoginRedirect} attribute if defined.
* If not and the deprecated attribute [loginRedirect]{@link Services#auth.loginRedirect} is defined then its value is returned.
* Otherwise, `undefined` is returned.
*/
getToLoginPath() {
return this.configuration?.services?.auth?.toLoginRedirect ?? this.configuration?.services?.auth?.loginRedirect;
}
/**
* @returns the value stored in the [onLoginRedirect]{@link Services#auth.onLoginRedirect} attribute if defined.
* Otherwise, `undefined` is returned.
*/
getOnLoginPath() {
return this.configuration?.services?.auth?.onLoginRedirect;
}
getView(searched, view) {
const paths = [];
if (!!view.layout && view.layout.name === searched) {
paths.push(view.routing.path);
}
if (view.children && Object.keys(view.children).length !== 0) {
Object.values(view.children).forEach(child => {
paths.push(...this.getView(searched, child).map(path => view.routing.path + '/' + path));
});
}
return paths;
}
/**
* @param endpointKey the attribute name of the endpoint address in `nae.json`
* @returns the endpoint address or `undefined` if such endpoint is not defined in `nae.json`
*/
resolveProvidersEndpoint(endpointKey) {
const config = this.configuration;
if (!config
|| !config.providers
|| !config.providers.auth
|| !config.providers.auth.address
|| !config.providers.auth.endpoints
|| !config.providers.auth.endpoints[endpointKey]) {
throw new Error('Authentication provider address is not set!');
}
return config.providers.auth.address + config.providers.auth.endpoints[endpointKey];
}
/**
* Loads and initializes application configuration from the backend.
* If configuration resolution is disabled in APPLICATION_CONFIG, returns null Observable.
* Otherwise fetches public configuration via ConfigurationResourceService.
*
* @returns Observable<any> that emits null if resolution is disabled, otherwise emits the loaded configuration
* @fires initialize() Upon successful configuration load to setup endpoints and data field configurations
* @see ApplicationConfiguration
* @see NetgrifApplicationEngine
*/
loadConfiguration() {
if (!this.APPLICATION_CONFIG?.resolve_configuration) {
return of(void 0);
}
return this._configurationResource.getPublicApplicationConfiguration(this.APPLICATION_CONFIG).pipe(catchError((err) => {
if (err.status === 404) {
return of(null);
}
console.log(err.message);
return of(null);
}), tap((data) => {
if (!data?.properties) {
return;
}
this.configuration = data.properties;
this.initialize();
}), take(1), map(() => void 0));
}
createConfigurationCopy() {
return this.deepCopy(this.configuration);
}
getViewsCopy() {
return this.getConfigurationSubtree(['views']);
}
deepCopy(obj) {
return JSON.parse(JSON.stringify(obj));
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlndXJhdGlvbi5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmV0Z3JpZi1jb21wb25lbnRzLWNvcmUvc3JjL2xpYi9jb25maWd1cmF0aW9uL2NvbmZpZ3VyYXRpb24uc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUMsZUFBZSxFQUFjLEVBQUUsRUFBQyxNQUFNLE1BQU0sQ0FBQztBQUdyRCxPQUFPLEVBQUMsVUFBVSxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLG9CQUFvQixFQUFDLE1BQU0sZ0JBQWdCLENBQUM7QUFJaEYsTUFBTSxPQUFnQixvQkFBb0I7SUFVTjtJQUNBO0lBQ0E7SUFWeEIsdUJBQXVCLENBQXlCO0lBRXZDLGtCQUFrQixDQUEyQjtJQUU3QyxRQUFRLEdBQUcsSUFBSSxlQUFlLENBQWtDLElBQUksQ0FBQyxDQUFDO0lBQ3ZFLE9BQU8sR0FBZ0QsSUFBSSxDQUFDLFFBQVEsQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUNwRixPQUFPLEdBQXdCLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFBRSxvQkFBb0IsRUFBRSxDQUFDLENBQUM7SUFFNUcsWUFBZ0MsYUFBdUMsRUFDdkMsc0JBQW9ELEVBQ3BELHlCQUFtRDtRQUZuRCxrQkFBYSxHQUFiLGFBQWEsQ0FBMEI7UUFDdkMsMkJBQXNCLEdBQXRCLHNCQUFzQixDQUE4QjtRQUNwRCw4QkFBeUIsR0FBekIseUJBQXlCLENBQTBCO1FBQy9FLElBQUksQ0FBQyxrQkFBa0IsR0FBRyx5QkFBeUIsQ0FBQztRQUNwRCxJQUFJLENBQUMsSUFBSSxDQUFDLHlCQUF5QixFQUFFLHFCQUFxQixFQUFFO1lBQ3hELElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztTQUNyQjtJQUNMLENB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QztJQUNOLENBQUM7SUFFTyx1QkFBdUI7UUFDM0IsT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQztJQUM3QyxDQUFDO0lBRU8sWUFBWTtRQUNoQixPQUFPLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFVLENBQUM7SUFDNUQsQ0FBQztJQUVPLFFBQVEsQ0FBQyxHQUFXO1FBQ3hCLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDM0MsQ0FBQztDQUNKIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtOZXRncmlmQXBwbGljYXRpb25FbmdpbmUsIFNlcnZpY2VzLCBWaWV3LCBWaWV3c30gZnJvbSAnLi4vLi4vY29tbW9ucy9zY2hlbWEnO1xuaW1wb3J0IHtCZWhhdmlvclN1YmplY3QsIE9ic2VydmFibGUsIG9mfSBmcm9tICdyeGpzJztcbmltcG9ydCB7QXBwbGljYXRpb25Db25maWd1cmF0aW9ufSBmcm9tICcuL2FwcGxpY2F0aW9uLWNvbmZpZ3VyYXRpb24nO1xuaW1wb3J0IHtDb25maWd1cmF0aW9uUmVzb3VyY2VTZXJ2aWNlfSBmcm9tICcuLi9yZXNvdXJjZXMvZW5naW5lLWVuZHBvaW50L2NvbmZpZ3VyYXRpb24tcmVzb3VyY2Uuc2VydmljZSc7XG5pbXBvcnQge2NhdGNoRXJyb3IsIHRha2UsIHRhcCwgbWFwLCBkaXN0aW5jdFVudGlsQ2hhbmdlZH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHtIdHRwRXJyb3JSZXNwb25zZX0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnO1xuXG5cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBDb25maWd1cmF0aW9uU2VydmljZSB7XG5cbiAgICBwcml2YXRlIF9kYXRhRmllbGRDb25maWd1cmF0aW9uOiBTZXJ2aWNlc1snZGF0YUZpZWxkcyddO1xuXG4gICAgcHJpdmF0ZSByZWFkb25seSBBUFBMSUNBVElPTl9DT05GSUc6IEFwcGxpY2F0aW9uQ29uZmlndXJhdGlvbjtcblxuICAgIHByaXZhdGUgcmVhZG9ubHkgX2NvbmZpZyQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PE5ldGdyaWZBcHBsaWNhdGlvbkVuZ2luZSB8IG51bGw+KG51bGwpO1xuICAgIHB1YmxpYyByZWFkb25seSBjb25maWckOiBPYnNlcnZhYmxlPE5ldGdyaWZBcHBsaWNhdGlvbkVuZ2luZSB8IG51bGw+ID0gdGhpcy5fY29uZmlnJC5hc09ic2VydmFibGUoKTtcbiAgICBwdWJsaWMgcmVhZG9ubHkgbG9hZGVkJDogT2JzZXJ2YWJsZTxib29sZWFuPiA9IHRoaXMuY29uZmlnJC5waXBlKG1hcChjZmcgPT4gISFjZmcpLCBkaXN0aW5jdFVudGlsQ2hhbmdlZCgpKTtcblxuICAgIHByb3RlY3RlZCBjb25zdHJ1Y3Rvcihwcm90ZWN0ZWQgY29uZmlndXJhdGlvbjogTmV0Z3JpZkFwcGxpY2F0aW9uRW5naW5lLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBwcm90ZWN0ZWQgX2NvbmZpZ3VyYXRpb25SZXNvdXJjZTogQ29uZmlndXJhdGlvblJlc291cmNlU2VydmljZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvdGVjdGVkIF9hcHBsaWNhdGlvbkNvbmZpZ3VyYXRpb246IEFwcGxpY2F0aW9uQ29uZmlndXJhdGlvbikge1xuICAgICAgICB0aGlzLkFQUExJQ0FUSU9OX0NPTkZJRyA9IF9hcHBsaWNhdGlvbkNvbmZpZ3VyYXRpb247XG4gICAgICAgIGlmICghdGhpcy5fYXBwbGljYXRpb25Db25maWd1cmF0aW9uPy5yZXNvbHZlX2NvbmZpZ3VyYXRpb24pIHtcbiAgICAgICAgICAgIHRoaXMuaW5pdGlhbGl6ZSgpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGljIGdldCBzbmFwc2hvdCgpOiBOZXRncmlmQXBwbGljYXRpb25FbmdpbmUgfCBudWxsIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuY29uZmlndXJhdGlvbiA/ICh0aGlzLmNyZWF0ZUNvbmZpZ3VyYXRpb25Db3B5KCkgYXMgTmV0Z3JpZkFwcGxpY2F0aW9uRW5naW5lKSA6IG51bGw7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBpbml0aWFsaXplKCk6IHZvaWQge1xuICAgICAgICB0aGlzLnJlc29sdmVFbmRwb2ludFVSTHMoKTtcbiAgICAgICAgdGhpcy5fZGF0YUZpZWxkQ29uZmlndXJhdGlvbiA9IHRoaXMuZ2V0Q29uZmlndXJhdGlvblN1YnRyZWUoWydzZXJ2aWNlcycsICdkYXRhRmllbGRzJ10pO1xuICAgICAgICB0aGlzLl9jb25maWckLm5leHQodGhpcy5jcmVhdGVDb25maWd1cmF0aW9uQ29weSgpIGFzIE5ldGdyaWZBcHBsaWNhdGlvbkVuZ2luZSk7XG4gICAgfVxuXG4gICAgcHVibGljIGdldEFzeW5jKCk6IE9ic2VydmFibGU8TmV0Z3JpZkFwcGxpY2F0aW9uRW5naW5lPiB7XG4gICAgICAgIHJldHVybiBvZih0aGlzLmdldCgpKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDYWxscyB0byB0aGlzIG1ldGhvZCBzaG91bGQgYmUgYXZvaWRlZCBhcyBjcmVhdGluZyBhIGRlZXAgY29weSBvZiB0aGUgY29uZmlndXJhdGlvbiBoYXMgYSBsYXJnZSBvdmVyaGVhZFxuICAgICAqXG4gICAgICogQHJldHVybnMgYSBkZWVwIGNvcHkgb2YgdGhlIGVudGlyZSBjb25maWd1cmF0aW9uIG9iamVjdFxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQoKTogTmV0Z3JpZkFwcGxpY2F0aW9uRW5naW5lIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuY3JlYXRlQ29uZmlndXJhdGlvbkNvcHkoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgdmlldyBjb25maWd1cmF0aW9uIGZyb20gbmFlLmpzb24gZm9yIHZpZXcgYXQgZ2l2ZW4gY29uZmlnIHBhdGguXG4gICAgICogQHBhcmFtIHZpZXdDb25maWdQYXRoIGNvbmZpZ3VyYXRpb24gcGF0aCB0byB0aGUgcmVxdWVzdGVkIHZpZXcuIE5vIGxlYWRpbmcgYmFja3NsYXNoLlxuICAgICAqIEByZXR1cm4gcmVxdWVzdGVkIGNvbmZpZ3VyYXRpb24gaWYgaXQgZXhpc3RzLiBgdW5kZWZpbmVkYCBvdGhlcndpc2UuXG4gICAgICovXG4gICAgcHVibGljIGdldFZpZXdCeVBhdGgodmlld0NvbmZpZ1BhdGg6IHN0cmluZyk6IFZpZXcgfCB1bmRlZmluZWQge1xuICAgICAgICBjb25zdCB2aWV3UGF0aFNlZ21lbnRzID0gdmlld0NvbmZpZ1BhdGguc3BsaXQoJy8nKTtcbiAgICAgICAgY29uc3QgY29uZmlnVHJlZVBhdGhTZWdtZW50cyA9IFsndmlld3MnXTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB2aWV3UGF0aFNlZ21lbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBpZiAoaSA+IDApIHtcbiAgICAgICAgICAgICAgICBjb25maWdUcmVlUGF0aFNlZ21lbnRzLnB1c2goJ2NoaWxkcmVuJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25maWdUcmVlUGF0aFNlZ21lbnRzLnB1c2godmlld1BhdGhTZWdtZW50c1tpXSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0Q29uZmlndXJhdGlvblN1YnRyZWUoY29uZmlnVHJlZVBhdGhTZWdtZW50cyk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IHZpZXcgY29uZmlndXJhdGlvbiBmcm9tIG5hZS5qc29uIGZvciB2aWV3IGF0IGdpdmVuIHVybC5cbiAgICAgKiBAcGFyYW0gdXJsIHRvIHRoZSByZXF1ZXN0ZWQgdmlldy4gTmVjZXNzYXJ5IGJhY2tzbGFzaC5cbiAgICAgKiBAcmV0dXJuIHJlcXVlc3RlZCBjb25maWd1cmF0aW9uIGlmIGl0IGV4aXN0cy4gYHVuZGVmaW5lZGAgb3RoZXJ3aXNlLlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXRWaWV3QnlVcmwodXJsOiBzdHJpbmcpOiBWaWV3IHwgdW5kZWZpbmVkIHtcbiAgICAgICAgY29uc3Qgdmlld3MgPSB0aGlzLmdldFZpZXdzQ29weSgpO1xuICAgICAgICBpZiAoIXZpZXdzKSB7XG4gICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgICAgIGxldCBtYXA6IE1hcDxzdHJpbmcsIFZpZXc+ID0gbmV3IE1hcCgpO1xuICAgICAgICBtYXAgPSB0aGlzLmdldENoaWxkcmVuKHZpZXdzLCBtYXAsICcnKTtcbiAgICAgICAgaWYgKG1hcC5nZXQodXJsKSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBtYXApIHtcbiAgICAgICAgICAgICAgICBpZiAoa2V5Py5pbmNsdWRlcygnLyoqJykgJiYgdXJsPy5pbmNsdWRlcyhrZXkuc3BsaXQoJy8qKicpWzBdKSlcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHZhbHVlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBtYXAuZ2V0KHVybCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBnZXRDaGlsZHJlbih2aWV3czogVmlld3MsIG1hcDogTWFwPHN0cmluZywgVmlldz4sIHByZWZpeDogc3RyaW5nKTogTWFwPHN0cmluZywgVmlldz4ge1xuICAgICAgICBPYmplY3Qua2V5cyh2aWV3cykuZm9yRWFjaCh2aWV3ID0+IHtcbiAgICAgICAgICAgIGlmICghIXZpZXdzW3ZpZXddLnJvdXRpbmcucGF0aCkge1xuICAgICAgICAgICAgICAgIHByZWZpeCA9IHByZWZpeC5jaGFyQXQocHJlZml4Lmxlbmd0aCAtIDEpID09PSAnLycgP1xuICAgICAgICAgICAgICAgICAgICBwcmVmaXgubGVuZ3RoID4gMSA/IHByZWZpeC5zdWJzdHJpbmcoMCwgcHJlZml4Lmxlbmd0aCAtIDIpIDogJycgOlxuICAgICAgICAgICAgICAgICAgICBwcmVmaXg7XG4gICAgICAgICAgICAgICAgY29uc3Qgdmlld1BhdGggPSB2aWV3c1t2aWV3XS5yb3V0aW5nLnBhdGguY2hhckF0KDApID09PSAnLycgP1xuICAgICAgICAgICAgICAgICAgICB2aWV3c1t2aWV3XS5yb3V0aW5nLnBhdGgubGVuZ3RoID4gMSA/IHZpZXdzW3ZpZXddLnJvdXRpbmcucGF0aC5zdWJzdHJpbmcoMSkgOiAnJyA6XG4gICAgICAgICAgICAgICAgICAgIHZpZXdzW3ZpZXddLnJvdXRpbmcucGF0aDtcbiAgICAgICAgICAgICAgICBtYXAuc2V0KFxuICAgICAgICAgICAgICAgICAgICB2aWV3c1t2aWV3XS5yb3V0aW5nLm1hdGNoID9cbiAgICAgICAgICAgICAgICAgICAgICAgIHByZWZpeCArICcvJyArIHZpZXdQYXRoICsgJy8qKicgOlxuICAgICAgICAgICAgICAgICAgICAgICAgcHJlZml4ICsgJy8nICsgdmlld1BhdGgsXG4gICAgICAgICAgICAgICAgICAgIHZpZXdzW3ZpZXddKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh2aWV3c1t2aWV3XS5jaGlsZHJlbikge1xuICAgICAgICAgICAgICAgIHRoaXMuZ2V0Q2hpbGRyZW4odmlld3Nbdmlld10uY2hpbGRyZW4sIG1hcCwgcHJlZml4ICsgJy8nICsgdmlld3Nbdmlld10ucm91dGluZy5wYXRoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiBtYXA7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IGFsbCBVUkxzL3BhdGhzIG9mIHZpZXdzIHdpdGggc3BlY2lmaWVkIGxheW91dC5cbiAgICAgKiBAcGFyYW0gbGF5b3V0IFNlYXJjaCB2aWV3cyB3aXRoIHRoaXMgbGF5b3V0XG4gICAgICogQHJldHVybnMgUGF0aHMgd2l0aCBwcmVmaXhlZCAnLycgb2YgYWxsIHZpZXdzIHdpdGggc3BlY2lmaWVkIGxheW91dCwgZW1wdHkgYXJyYXkgb3RoZXJ3aXNlLlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXRQYXRoc0J5VmlldyhsYXlvdXQ6IHN0cmluZyk6IEFycmF5PHN0cmluZz4ge1xuICAgICAgICBjb25zdCBjb25maWcgPSB0aGlzLmNyZWF0ZUNvbmZpZ3VyYXRpb25Db3B5KCkgYXMgTmV0Z3JpZkFwcGxpY2F0aW9uRW5naW5lO1xuICAgICAgICBjb25zdCByZXN1bHQgPSBbXTtcbiAgICAgICAgaWYgKCFjb25maWcudmlld3MpIHtcbiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgIH1cbiAgICAgICAgT2JqZWN0LnZhbHVlcyhjb25maWcudmlld3MpLmZvckVhY2godmlldyA9PiB7XG4gICAgICAgICAgICByZXN1bHQucHVzaCguLi50aGlzLmdldFZpZXcobGF5b3V0LCB2aWV3KS5tYXAocGF0aCA9PiAnLycgKyBwYXRoKSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgcHVibGljIGdldENvbmZpZ3VyYXRpb25TdWJ0cmVlQnlQYXRoKHBhdGg6IHN0cmluZyk6IGFueSB8IHVuZGVmaW5lZCB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldENvbmZpZ3VyYXRpb25TdWJ0cmVlKHBhdGguc3BsaXQoJy4nKSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQHBhcmFtIHBhdGhTZWdtZW50cyB0aGUga2V5cyBzcGVjaWZ5aW5nIHRoZSBwYXRoIHRyb3VnaCB0aGUgY29uZmlndXJhdGlvbiB0aGF0IHNob3VsZCBiZSBhY2Nlc3NlZFxuICAgICAqIEByZXR1cm5zIGEgZGVlcCBjb3B5IG9mIGEgc3BlY2lmaWVkIHN1YnNlY3Rpb24gb2YgdGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0LCBvciBgdW5kZWZpbmVkYCBpZiBzdWNoIHN1YnNlY3Rpb24gZG9lc24ndCBleGlzdC5cbiAgICAgKiBDYWxsaW5nIHRoaXMgbWV0aG9kIHdpdGggYW4gZW1wdHkgYXJyYXkgYXMgYXJndW1lbnQgaXMgZXF1aXZhbGVudCB0byBjYWxsaW5nIHRoZSBbZ2V0KClde0BsaW5rIENvbmZpZ3VyYXRpb25TZXJ2aWNlI2dldH0gbWV0aG9kLlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXRDb25maWd1cmF0aW9uU3VidHJlZShwYXRoU2VnbWVudHM6IEFycmF5PHN0cmluZz4pOiBhbnkgfCB1bmRlZmluZWQge1xuICAgICAgICBsZXQgcm9vdCA9IHRoaXMuY29uZmlndXJhdGlvbjtcbiAgICAgICAgZm9yIChjb25zdCBzZWdtZW50IG9mIHBhdGhTZWdtZW50cykge1xuICAgICAgICAgICAgaWYgKHJvb3Rbc2VnbWVudF0gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByb290ID0gcm9vdFtzZWdtZW50XTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5kZWVwQ29weShyb290KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAcmV0dXJucyB0aGUgYXBwcm9wcmlhdGUgdGVtcGxhdGUgY29uZmlndXJhdGlvbiBmb3IgZGF0YSBmaWVsZHMsIG9yIGB1bmRlZmluZWRgIGlmIHN1Y2ggY29uZmlndXJhdGlvbiBpcyBub3QgcHJlc2VudC5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0RGF0YWZpZWxkQ29uZmlndXJhdGlvbigpOiBTZXJ2aWNlc1snZGF0YUZpZWxkcyddIHwgdW5kZWZpbmVkIHtcbiAgICAgICAgaWYgKHRoaXMuX2RhdGFGaWVsZENvbmZpZ3VyYXRpb24gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gey4uLnRoaXMuX2RhdGFGaWVsZENvbmZpZ3VyYXRpb259O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlc29sdmVzIHRoZSBVUkwgYWRkcmVzc2VzIG9mIGJhY2tlbmQgZW5kcG9pbnRzIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLlxuICAgICAqXG4gICAgICogSWYgdGhlIFVSTHMgYmVnaW4gd2l0aCBlaXRoZXIgYGh0dHA6Ly9gLCBvciBgaHR0cHM6Ly9gIHRoZSBwcm92aWRlZCBVUkwgd2lsbCBiZSB1c2VkLlxuICAgICAqXG4gICAgICogSWYgbm90LCB0aGVuIHRoZSBVUkxzIGFyZSBjb25zaWRlcmVkIHRvIGJlIHJlbGF0aXZlIHRvIHRoZSBsb2NhdGlvbiBvZiB0aGUgZnJvbnRlbmQgYXBwbGljYXRpb24gYW5kIGl0J3MgVVJMIHdpbGwgYmUgdXNlZFxuICAgICAqIGFzIHRoZSBiYXNlIHBhdGguIGAvYXBpYCBpcyBhcHBlbmRlZCBhdXRvbWF0aWNhbGx5LlxuICAgICAqL1xuICAgIHByb3RlY3RlZCByZXNvbHZlRW5kcG9pbnRVUkxzKCkge1xuICAgICAgICBpZiAodGhpcy5jb25maWd1cmF0aW9uPy5wcm92aWRlcnM/LmF1dGg/LmFkZHJlc3MgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGAncHJvdmlkZXIuYXV0aC5hZGRyZXNzJyBpcyBhIHJlcXVpcmVkIHByb3BlcnR5IGFuZCBtdXN0IGJlIHByZXNlbnQgaW4gdGhlIGNvbmZpZ3VyYXRpb24hYCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5jb25maWd1cmF0aW9uLnByb3ZpZGVycy5hdXRoLmFkZHJlc3MgPSB0aGlzLnJlc29sdmVVUkwodGhpcy5jb25maWd1cmF0aW9uLnByb3ZpZGVycy5hdXRoLmFkZHJlc3MpO1xuXG4gICAgICAgIGlmICh0aGlzLmNvbmZpZ3VyYXRpb24/LnByb3ZpZGVycz8ucmVzb3VyY2VzID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgJ3Byb3ZpZGVyLnJlc291cmNlcycgaXMgYSByZXF1aXJlZCBwcm9wZXJ0eSBhbmQgbXVzdCBiZSBwcmVzZW50IGluIHRoZSBjb25maWd1cmF0aW9uIWApO1xuICAgICAgICB9XG4gICAgICAgIGlmIChBcnJheS5pc0FycmF5KHRoaXMuY29uZmlndXJhdGlvbi5wcm92aWRlcnMucmVzb3VyY2VzKSkge1xuICAgICAgICAgICAgdGhpcy5jb25maWd1cmF0aW9uLnByb3ZpZGVycy5yZXNvdXJjZXMuZm9yRWFjaChyZXNvdXJjZSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHJlc291cmNlPy5hZGRyZXNzID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBSZXNvdXJjZXMgZGVmaW5lZCBpbiAncHJvdmlkZXIucmVzb3VyY2VzJyBtdXN0IGRlZmluZSBhbiBhZGRyZXNzIHByb3BlcnR5IWApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXNvdXJjZS5hZGRyZXNzID0gdGhpcy5yZXNvbHZlVVJMKHJlc291cmNlLmFkZHJlc3MpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpZiAodGhpcy5jb25maWd1cmF0aW9uPy5wcm92aWRlcnM/LnJlc291cmNlcz8uYWRkcmVzcyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBSZXNvdXJjZXMgZGVmaW5lZCBpbiAncHJvdmlkZXIucmVzb3VyY2VzJyBtdXN0IGRlZmluZSBhbiBhZGRyZXNzIHByb3BlcnR5IWApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5jb25maWd1cmF0aW9uLnByb3ZpZGVycy5yZXNvdXJjZXMuYWRkcmVzcyA9IHRoaXMucmVzb2x2ZVVSTCh0aGlzLmNvbmZpZ3VyYXRpb24ucHJvdmlkZXJzLnJlc291cmNlcy5hZGRyZXNzKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlc29sdmVzIGEgc2luZ2xlIFVSTCBhZGRyZXNzLlxuICAgICAqXG4gICAgICogSWYgdGhlIFVSTCBiZWdpbnMgd2l0aCBlaXRoZXIgYGh0dHA6Ly9gLCBvciBgaHR0cHM6Ly9gIHRoZSBwcm92aWRlZCBVUkwgd2lsbCBiZSB1c2VkLlxuICAgICAqXG4gICAgICogSWYgbm90LCB0aGVuIHRoZSBVUkwgaXMgY29uc2lkZXJlZCB0byBiZSByZWxhdGl2ZSB0byB0aGUgbG9jYXRpb24gb2YgdGhlIGZyb250ZW5kIGFwcGxpY2F0aW9uIGFuZCBpdCdzIFVSTCB3aWxsIGJlIHVzZWRcbiAgICAgKiBhcyB0aGUgYmFzZSBwYXRoLiBgL2FwaWAgaXMgYXBwZW5kZWQgYXV0b21hdGljYWxseS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBjb25maWdVUkwgdmFsdWUgZnJvbSB0aGUgY29uZmlndXJhdGlvbiBmaWxlXG4gICAgICogQHJldHVybnMgdGhlIHJlc29sdmVkIFVSTFxuICAgICAqL1xuICAgIHByb3RlY3RlZCByZXNvbHZlVVJMKGNvbmZpZ1VSTDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICAgICAgaWYgKGNvbmZpZ1VSTC5zdGFydHNXaXRoKCdodHRwOi8vJykgfHwgY29uZmlnVVJMLnN0YXJ0c1dpdGgoJ2h0dHBzOi8vJykpIHtcbiAgICAgICAgICAgIHJldHVybiBjb25maWdVUkw7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gbG9jYXRpb24ub3JpZ2luICsgJy9hcGknICsgY29uZmlnVVJMO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQHJldHVybnMgdGhlIHNlcnZpY2VzIGNvbmZpZ3VyYXRpb24sIG9yIGB1bmRlZmluZWRgIGlmIHN1Y2ggY29uZmlndXJhdGlvbiBpcyBub3QgcHJlc2VudC5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0U2VydmljZXNDb25maWd1cmF0aW9uKCk6IFNlcnZpY2VzIHwgdW5kZWZpbmVkIHtcbiAgICAgICAgY29uc3Qgc3VidHJlZSA9IHRoaXMuZ2V0Q29uZmlndXJhdGlvblN1YnRyZWUoWydzZXJ2aWNlcyddKSBhcyBTZXJ2aWNlcztcbiAgICAgICAgcmV0dXJuIHN1YnRyZWUgIT09IHVuZGVmaW5lZCA/IHRoaXMuZGVlcENvcHkoc3VidHJlZSkgYXMgU2VydmljZXMgOiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQHJldHVybnMgdGhlIHZhbHVlIHN0b3JlZCBpbiB0aGUgW29uTG9nb3V0UmVkaXJlY3Rde0BsaW5rIFNlcnZpY2VzI2F1dGgub25Mb2dvdXRSZWRpcmVjdH0gYXR0cmlidXRlIGlmIGRlZmluZWQuXG4gICAgICogSWYgbm90IGFuZCB0aGUgZGVwcmVjYXRlZCBhdHRyaWJ1dGUgW2xvZ291dFJlZGlyZWN0XXtAbGluayBTZXJ2aWNlcyNhdXRoLmxvZ291dFJlZGlyZWN0fSBpcyBkZWZpbmVkIHRoZW4gaXRzIHZhbHVlIGlzIHJldHVybmVkLlxuICAgICAqIE90aGVyd2lzZSwgYHVuZGVmaW5lZGAgaXMgcmV0dXJuZWQuXG4gICAgICovXG4gICAgcHVibGljIGdldE9uTG9nb3V0UGF0aCgpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgICAgICByZXR1cm4gdGhpcy5jb25maWd1cmF0aW9uPy5zZXJ2aWNlcz8uYXV0aD8ub25Mb2dvdXRSZWRpcmVjdCA/PyB0aGlzLmNvbmZpZ3VyYXRpb24/LnNlcnZpY2VzPy5hdXRoPy5sb2dvdXRSZWRpcmVjdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAcmV0dXJucyB0aGUgdmFsdWUgc3RvcmVkIGluIHRoZSBbdG9Mb2dpblJlZGlyZWN0XXtAbGluayBTZXJ2aWNlcyNhdXRoLnRvTG9naW5SZWRpcmVjdH0gYXR0cmlidXRlIGlmIGRlZmluZWQuXG4gICAgICogSWYgbm90IGFuZCB0aGUgZGVwcmVjYXRlZCBhdHRyaWJ1dGUgW2xvZ2luUmVkaXJlY3Rde0BsaW5rIFNlcnZpY2VzI2F1dGgubG9naW5SZWRpcmVjdH0gaXMgZGVmaW5lZCB0aGVuIGl0cyB2YWx1ZSBpcyByZXR1cm5lZC5cbiAgICAgKiBPdGhlcndpc2UsIGB1bmRlZmluZWRgIGlzIHJldHVybmVkLlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXRUb0xvZ2luUGF0aCgpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgICAgICByZXR1cm4gdGhpcy5jb25maWd1cmF0aW9uPy5zZXJ2aWNlcz8uYXV0aD8udG9Mb2dpblJlZGlyZWN0ID8/IHRoaXMuY29uZmlndXJhdGlvbj8uc2VydmljZXM/LmF1dGg/LmxvZ2luUmVkaXJlY3Q7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQHJldHVybnMgdGhlIHZhbHVlIHN0b3JlZCBpbiB0aGUgW29uTG9naW5SZWRpcmVjdF17QGxpbmsgU2VydmljZXMjYXV0aC5vbkxvZ2luUmVkaXJlY3R9IGF0dHJpYnV0ZSBpZiBkZWZpbmVkLlxuICAgICAqIE90aGVyd2lzZSwgYHVuZGVmaW5lZGAgaXMgcmV0dXJuZWQuXG4gICAgICovXG4gICAgcHVibGljIGdldE9uTG9naW5QYXRoKCk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gICAgICAgIHJldHVybiB0aGlzLmNvbmZpZ3VyYXRpb24/LnNlcnZpY2VzPy5hdXRoPy5vbkxvZ2luUmVkaXJlY3Q7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBnZXRWaWV3KHNlYXJjaGVkOiBzdHJpbmcsIHZpZXc6IFZpZXcpOiBBcnJheTxzdHJpbmc+IHtcbiAgICAgICAgY29uc3QgcGF0aHMgPSBbXTtcbiAgICAgICAgaWYgKCEhdmlldy5sYXlvdXQgJiYgdmlldy5sYXlvdXQubmFtZSA9PT0gc2VhcmNoZWQpIHtcbiAgICAgICAgICAgIHBhdGhzLnB1c2godmlldy5yb3V0aW5nLnBhdGgpO1xuICAgICAgICB9XG4gICAgICAgIGlmICh2aWV3LmNoaWxkcmVuICYmIE9iamVjdC5rZXlzKHZpZXcuY2hpbGRyZW4pLmxlbmd0aCAhPT0gMCkge1xuICAgICAgICAgICAgT2JqZWN0LnZhbHVlcyh2aWV3LmNoaWxkcmVuKS5mb3JFYWNoKGNoaWxkID0+IHtcbiAgICAgICAgICAgICAgICBwYXRocy5wdXNoKC4uLnRoaXMuZ2V0VmlldyhzZWFyY2hlZCwgY2hpbGQpLm1hcChwYXRoID0+IHZpZXcucm91dGluZy5wYXRoICsgJy8nICsgcGF0aCkpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHBhdGhzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEBwYXJhbSBlbmRwb2ludEtleSB0aGUgYXR0cmlidXRlIG5hbWUgb2YgdGhlIGVuZHBvaW50IGFkZHJlc3MgaW4gYG5hZS5qc29uYFxuICAgICAqIEByZXR1cm5zIHRoZSBlbmRwb2ludCBhZGRyZXNzIG9yIGB1bmRlZmluZWRgIGlmIHN1Y2ggZW5kcG9pbnQgaXMgbm90IGRlZmluZWQgaW4gYG5hZS5qc29uYFxuICAgICAqL1xuICAgIHB1YmxpYyByZXNvbHZlUHJvdmlkZXJzRW5kcG9pbnQoZW5kcG9pbnRLZXk6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgICAgIGNvbnN0IGNvbmZpZyA9IHRoaXMuY29uZmlndXJhdGlvbjtcbiAgICAgICAgaWYgKCFjb25maWdcbiAgICAgICAgICAgIHx8ICFjb25maWcucHJvdmlkZXJzXG4gICAgICAgICAgICB8fCAhY29uZmlnLnByb3ZpZGVycy5hdXRoXG4gICAgICAgICAgICB8fCAhY29uZmlnLnByb3ZpZGVycy5hdXRoLmFkZHJlc3NcbiAgICAgICAgICAgIHx8ICFjb25maWcucHJvdmlkZXJzLmF1dGguZW5kcG9pbnRzXG4gICAgICAgICAgICB8fCAhY29uZmlnLnByb3ZpZGVycy5hdXRoLmVuZHBvaW50c1tlbmRwb2ludEtleV0pIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignQXV0aGVudGljYXRpb24gcHJvdmlkZXIgYWRkcmVzcyBpcyBub3Qgc2V0IScpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBjb25maWcucHJvdmlkZXJzLmF1dGguYWRkcmVzcyArIGNvbmZpZy5wcm92aWRlcnMuYXV0aC5lbmRwb2ludHNbZW5kcG9pbnRLZXldO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIExvYWRzIGFuZCBpbml0aWFsaXplcyBhcHBsaWNhdGlvbiBjb25maWd1cmF0aW9uIGZyb20gdGhlIGJhY2tlbmQuXG4gICAgICogSWYgY29uZmlndXJhdGlvbiByZXNvbHV0aW9uIGlzIGRpc2FibGVkIGluIEFQUExJQ0FUSU9OX0NPTkZJRywgcmV0dXJucyBudWxsIE9ic2VydmFibGUuXG4gICAgICogT3RoZXJ3aXNlIGZldGNoZXMgcHVibGljIGNvbmZpZ3VyYXRpb24gdmlhIENvbmZpZ3VyYXRpb25SZXNvdXJjZVNlcnZpY2UuXG4gICAgICpcbiAgICAgKiBAcmV0dXJucyBPYnNlcnZhYmxlPGFueT4gdGhhdCBlbWl0cyBudWxsIGlmIHJlc29sdXRpb24gaXMgZGlzYWJsZWQsIG90aGVyd2lzZSBlbWl0cyB0aGUgbG9hZGVkIGNvbmZpZ3VyYXRpb25cbiAgICAgKiBAZmlyZXMgaW5pdGlhbGl6ZSgpIFVwb24gc3VjY2Vzc2Z1bCBjb25maWd1cmF0aW9uIGxvYWQgdG8gc2V0dXAgZW5kcG9pbnRzIGFuZCBkYXRhIGZpZWxkIGNvbmZpZ3VyYXRpb25zXG4gICAgICogQHNlZSBBcHBsaWNhdGlvbkNvbmZpZ3VyYXRpb25cbiAgICAgKiBAc2VlIE5ldGdyaWZBcHBsaWNhdGlvbkVuZ2luZVxuICAgICAqL1xuICAgIHB1YmxpYyBsb2FkQ29uZmlndXJhdGlvbigpOiBPYnNlcnZhYmxlPHZvaWQ+IHtcbiAgICAgICAgaWYgKCF0aGlzLkFQUExJQ0FUSU9OX0NPTkZJRz8ucmVzb2x2ZV9jb25maWd1cmF0aW9uKSB7XG4gICAgICAgICAgICByZXR1cm4gb2Yodm9pZCAwKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzLl9jb25maWd1cmF0aW9uUmVzb3VyY2UuZ2V0UHVibGljQXBwbGljYXRpb25Db25maWd1cmF0aW9uKHRoaXMuQVBQTElDQVRJT05fQ09ORklHKS5waXBlKFxuICAgICAgICAgICAgY2F0Y2hFcnJvcigoZXJyOiBIdHRwRXJyb3JSZXNwb25zZSkgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChlcnIuc3RhdHVzID09PSA0MDQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG9mKG51bGwpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhlcnIubWVzc2FnZSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG9mKG51bGwpO1xuICAgICAgICAgICAgfSksXG4gICAgICAgICAgICB0YXAoKGRhdGE6IEFwcGxpY2F0aW9uQ29uZmlndXJhdGlvbiB8IG51bGwpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoIWRhdGE/LnByb3BlcnRpZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB0aGlzLmNvbmZpZ3VyYXRpb24gPSBkYXRhLnByb3BlcnRpZXMgYXMgTmV0Z3JpZkFwcGxpY2F0aW9uRW5naW5lO1xuICAgICAgICAgICAgICAgIHRoaXMuaW5pdGlhbGl6ZSgpO1xuICAgICAgICAgICAgfSksXG4gICAgICAgICAgICB0YWtlKDEpLFxuICAgICAgICAgICAgbWFwKCgpID0+IHZvaWQgMClcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGNyZWF0ZUNvbmZpZ3VyYXRpb25Db3B5KCk6IGFueSB7XG4gICAgICAgIHJldHVybiB0aGlzLmRlZXBDb3B5KHRoaXMuY29uZmlndXJhdGlvbik7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBnZXRWaWV3c0NvcHkoKTogVmlld3Mge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRDb25maWd1cmF0aW9uU3VidHJlZShbJ3ZpZXdzJ10pIGFzIFZpZXdzO1xuICAgIH1cblxuICAgIHByaXZhdGUgZGVlcENvcHkob2JqOiBvYmplY3QpOiBvYmplY3Qge1xuICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShKU09OLnN0cmluZ2lmeShvYmopKTtcbiAgICB9XG59XG4iXX0=