ngx-keycloak-authz-lib
Version:
Bibliothèque d'authorisation Keycloak pour Angular
318 lines • 41.1 kB
JavaScript
import { __awaiter } from "tslib";
import { Injectable } from '@angular/core';
import { throwError } from "rxjs";
import { map as __map, catchError } from 'rxjs/operators';
import { HttpParams, HttpHeaders } from '@angular/common/http';
import t from 'typy';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common/http";
/**
* Custom parameter codec to correctly handle the plus sign in parameter
* values. See https://github.com/angular/angular/issues/18261
*/
class ParameterCodec {
encodeKey(key) {
return encodeURIComponent(key);
}
encodeValue(value) {
return encodeURIComponent(value);
}
decodeKey(key) {
return decodeURIComponent(key);
}
decodeValue(value) {
return decodeURIComponent(value);
}
}
const PARAMETER_CODEC = new ParameterCodec();
export class KeycloakAuthorizationService {
constructor(http) {
this.http = http;
this.authConfig = null;
this.keycloakConfig = null;
/**
* Contains the RPT-Token after successfull Get-Entitlement-Call
*/
this._rpt = null;
/**
* Contains all permissions decoded from the RPT-Token after successful Get-Entitlement-Call
*/
this._permissions = [];
}
newParams() {
return new HttpParams({
encoder: PARAMETER_CODEC
});
}
/**
* Handles the class values initialization.
*
* @param options
*/
initServiceValues({ loadPermissionsInStartup = true, defaultResourceServerId = null }) {
this._loadPermissionsInStartup = loadPermissionsInStartup;
this._defaultResourceServerId = defaultResourceServerId;
}
/**
* KeycloakAuthorization initialization. It should be called to initialize the adapter.
* Options is a object with 2 main parameters: config and initOptions. The first one
* will be used to connect to Keycloak. The second one are options to initialize the
* keycloak authorization instance.
*
* @param options
* config: an object with the following content:
* - url: Keycloak json URL
* - realm: realm name
* - clientId: client id
*
* initOptions:
* - defaultResourceServerId: specifies the default resource-server
* - loadPermissionsInStartup: if set to true, load all permissions for default resource-server at initializiation of adapter
*
*
*/
init(options) {
const { config, initOptions } = options;
this.initServiceValues(initOptions);
this.keycloakConfig = config;
//console.log(this._defaultResourceServerId)
return new Promise((resolve, reject) => {
this.http.get(this.keycloakConfig.url + '/realms/' + this.keycloakConfig.realm + '/.well-known/uma2-configuration').subscribe((res) => __awaiter(this, void 0, void 0, function* () {
this.authConfig = res;
if ((this._defaultResourceServerId) && (this._loadPermissionsInStartup)) {
try {
yield this.getAuthorizations(this._defaultResourceServerId, {});
}
catch (err) {
reject("Error getting authorizations for resource-server-id " + this._defaultResourceServerId);
}
}
resolve(res);
}), err => {
let msg = "Fehler bei der Initialisierung des Keycloak-Authorization-Services";
reject(msg);
});
});
}
/**
* Checks if user has the required access to a resource and/or scope.
*
* @param authorization-check object
* - rsname : Name of the resource
* - scope : name of the scope
*
*
* @returns boolean true if user has access, false if not
*/
checkAuthorization(authorization) {
return this.hasAuthorization(authorization);
}
/**
* Internal method to check if user has the required access to a resource and/or scope
*
* @param authorization
*
* @returns boolean true if user has access, false if not
*/
hasAuthorization(authorization) {
let checkForResource = t(authorization, 'rsname').safeObject;
let checkForScope = t(authorization, 'scope').safeObject;
if (!t(this._permissions).isEmptyArray) {
let filteredResource = this._permissions.find(t => { if (t.rsname == checkForResource)
return t; });
//No access to resource
if (!t(filteredResource).isObject) {
//console.log("no access to resource granted");
return false;
}
//access to resource granted and no scope checking required
if (checkForScope == undefined) {
//console.log("no scope checking required.required auth is present - hooray");
return true;
}
//scope checking required, but resource has no scope defined
if (t(filteredResource.scopes).isEmptyArray) {
//console.log("scope checking required, but no scopes defined for resource");
return false;
}
let filteredScope = filteredResource.scopes.find(t => { if (t == checkForScope)
return t; });
//no access to scope
if (t(filteredScope).isUndefined) {
//console.log("required scope not found");
return false;
}
//console.log("required auth is present - hooray");
return true;
}
//console.log("no permissions loaded (yet)");
return false;
}
/**
* Return an array of all permissions present for the logged-in user
*
* @returns Array of permissions
*/
getPermissions() {
return this._permissions;
}
/**
* Gets authorizations for resource-server from keycloak. Also stores the permissions for future use
*
* @param resourceServerId
* The resource server for which the entitlements of the current user are checked
*
* @param authorizationRequest
*
* @returns Authorizations-Object
*/
getAuthorizations(resourceServerId, authorizationRequest) {
let perm = new Promise((resolve, reject) => {
this.getEntitlement(resourceServerId, authorizationRequest)
.subscribe(res => {
try {
let permissions = [];
if (res.access_token) {
this._rpt = res.access_token;
let decoded = this.decodeToken(res.access_token);
if (decoded.authorization) {
if (decoded.authorization.permissions) {
permissions = decoded.authorization.permissions;
}
}
}
this._permissions = permissions;
resolve(permissions);
}
catch (error) {
reject(error);
}
}, error => {
let msg = "Unable to get entitlements";
reject(msg);
});
});
return perm;
}
/**
* Gets entitlement fron resource-server from keycloak
*
* @param resourceServerId
* The resource server for which the entitlements of the current user are checked
*
* @param authorizationRequest
*
* @returns Object with RPT-Token containing the authorizations/entitlement
*/
getEntitlement(resourceServerId, authorizationRequest) {
let __params = this.newParams();
let __headers = new HttpHeaders();
let __body = null;
__headers = __headers.set("Content-type", "application/x-www-form-urlencoded");
if (!authorizationRequest) {
authorizationRequest = {};
}
__params = __params.set('grant_type', 'urn:ietf:params:oauth:grant-type:uma-ticket');
__params = __params.set('client_id', this.keycloakConfig.clientId);
__params = __params.set('audience', resourceServerId);
if (authorizationRequest.claimToken) {
__params = __params.set('claim_token', authorizationRequest.claimToken);
if (authorizationRequest.claimTokenFormat) {
__params = __params.set('claim_token_format', authorizationRequest.claimTokenFormat);
}
}
var permissions = authorizationRequest.permissions;
if (!permissions) {
permissions = [];
}
for (let i = 0; i < permissions.length; i++) {
var resource = permissions[i];
var permission = resource.id;
if (resource.scopes && resource.scopes.length > 0) {
permission += "#";
for (let j = 0; j < resource.scopes.length; j++) {
var scope = resource.scopes[j];
if (permission.indexOf('#') != permission.length - 1) {
permission += ",";
}
permission += scope;
}
}
__params = __params.append('permission', permission);
}
var metadata = authorizationRequest.metadata;
if (metadata) {
if (metadata.responseIncludeResourceName) {
__params = __params.set('response_include_resource_name', metadata.responseIncludeResourceName);
}
if (metadata.responsePermissionsLimit) {
__params = __params.set('response_permissions_limit', metadata.responsePermissionsLimit.toString());
}
}
if (this._rpt) {
__params = __params.set('rpt', this._rpt);
}
return this.http.post(this.authConfig.token_endpoint, __params.toString(), {
headers: __headers,
responseType: 'json'
})
.pipe(catchError(this.handleError), __map((_r) => {
//console.log(_r);
return _r;
}));
}
/**
* Decodes RPT-Token
*
* @param str - enoded token string
*
* @returns Decoded jwt-token object
*
*/
decodeToken(str) {
str = str.split('.')[1];
str = str.replace('/-/g', '+');
str = str.replace('/_/g', '/');
switch (str.length % 4) {
case 0:
break;
case 2:
str += '==';
break;
case 3:
str += '=';
break;
default:
throw 'Invalid token';
}
str = (str + '===').slice(0, str.length + (str.length % 4));
str = str.replace(/-/g, '+').replace(/_/g, '/');
str = decodeURIComponent(escape(atob(str)));
str = JSON.parse(str);
return str;
}
handleError(error) {
if (error.error instanceof ErrorEvent) {
// A client-side or network error occurred. Handle it accordingly.
console.error('An error occurred:', error.error.message);
}
else {
// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong,
console.error(`Backend returned code ${error.status}, ` +
`body was: ${error.error}`);
}
// return an observable with a user-facing error message
return throwError('Something bad happened; please try again later.');
}
;
}
KeycloakAuthorizationService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: KeycloakAuthorizationService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
KeycloakAuthorizationService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: KeycloakAuthorizationService, providedIn: 'root' });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: KeycloakAuthorizationService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}], ctorParameters: function () { return [{ type: i1.HttpClient }]; } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoia2V5Y2xvYWstYXV0aG9yaXphdGlvbi5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LWtleWNsb2FrLWF1dGh6LWxpYi9zcmMvbGliL2NvcmUvc2VydmljZXMva2V5Y2xvYWstYXV0aG9yaXphdGlvbi5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRzNDLE9BQU8sRUFBQyxVQUFVLEVBQUMsTUFBTSxNQUFNLENBQUM7QUFDaEMsT0FBTyxFQUFFLEdBQUcsSUFBSSxLQUFLLEVBQXFCLFVBQVUsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzdFLE9BQU8sRUFBa0MsVUFBVSxFQUFDLFdBQVcsRUFBNkMsTUFBTSxzQkFBc0IsQ0FBQztBQUN6SSxPQUFPLENBQUMsTUFBTSxNQUFNLENBQUM7OztBQU1yQjs7O0dBR0c7QUFDSCxNQUFNLGNBQWM7SUFDbEIsU0FBUyxDQUFDLEdBQVc7UUFDbkIsT0FBTyxrQkFBa0IsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNqQyxDQUFDO0lBRUQsV0FBVyxDQUFDLEtBQWE7UUFDdkIsT0FBTyxrQkFBa0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNuQyxDQUFDO0lBRUQsU0FBUyxDQUFDLEdBQVc7UUFDbkIsT0FBTyxrQkFBa0IsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNqQyxDQUFDO0lBRUQsV0FBVyxDQUFDLEtBQWE7UUFDdkIsT0FBTyxrQkFBa0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNuQyxDQUFDO0NBQ0Y7QUFDRCxNQUFNLGVBQWUsR0FBRyxJQUFJLGNBQWMsRUFBRSxDQUFDO0FBSzdDLE1BQU0sT0FBTyw0QkFBNEI7SUF5QnZDLFlBQW9CLElBQWU7UUFBZixTQUFJLEdBQUosSUFBSSxDQUFXO1FBdkJ6QixlQUFVLEdBQUcsSUFBSSxDQUFDO1FBQ2xCLG1C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QyxLQUFLLENBQUMsb0JBQW9CLEVBQUUsS0FBSyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztTQUMxRDthQUFNO1lBQ0wsc0RBQXNEO1lBQ3RELDZEQUE2RDtZQUM3RCxPQUFPLENBQUMsS0FBSyxDQUNYLHlCQUF5QixLQUFLLENBQUMsTUFBTSxJQUFJO2dCQUN6QyxhQUFhLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDO1NBQy9CO1FBQ0Qsd0RBQXdEO1FBQ3hELE9BQU8sVUFBVSxDQUNmLGlEQUFpRCxDQUFDLENBQUM7SUFDdkQsQ0FBQztJQUFBLENBQUM7OzBIQTVWTyw0QkFBNEI7OEhBQTVCLDRCQUE0QixjQUYzQixNQUFNOzRGQUVQLDRCQUE0QjtrQkFIeEMsVUFBVTttQkFBQztvQkFDVixVQUFVLEVBQUUsTUFBTTtpQkFDbkIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IEtleWNsb2FrU2VydmljZX0gZnJvbSAna2V5Y2xvYWstYW5ndWxhcic7XHJcbmltcG9ydCB7IEtleWNsb2FrQ29uZmlnfSBmcm9tICcuLi9pbnRlcmZhY2VzL0tleWNsb2FrQ29uZmlnJztcclxuaW1wb3J0IHt0aHJvd0Vycm9yfSBmcm9tIFwicnhqc1wiO1xyXG5pbXBvcnQgeyBtYXAgYXMgX19tYXAsIGZpbHRlciBhcyBfX2ZpbHRlcixjYXRjaEVycm9yIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xyXG5pbXBvcnQgeyBIdHRwQ2xpZW50LCBIdHRwUGFyYW1ldGVyQ29kZWMsIEh0dHBQYXJhbXMsSHR0cEhlYWRlcnMsSHR0cFJlcXVlc3QsSHR0cFJlc3BvbnNlLEh0dHBFcnJvclJlc3BvbnNlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnO1xyXG5pbXBvcnQgdCBmcm9tICd0eXB5JztcclxuaW1wb3J0IHtLZXljbG9ha0F1dGh6T3B0aW9uc30gZnJvbSAnLi4vaW50ZXJmYWNlcy9rZXljbG9hay1hdXRoei1vcHRpb25zJztcclxuaW1wb3J0IHtLZXljbG9ha0F1dGh6SW5pdE9wdGlvbnN9IGZyb20gJy4uL2ludGVyZmFjZXMva2V5Y2xvYWstYXV0aHotaW5pdC1vcHRpb25zJztcclxuaW1wb3J0IHtLZXljbG9ha0F1dGhvcml6YXRpb25SZXF1ZXN0LFJlc291cmNlUGVybWlzc2lvbiwgS2V5Y2xvYWtBdXRob3JpemF0aW9uUmVxdWVzdE1ldGFEYXRhfSBmcm9tICcuLi9pbnRlcmZhY2VzL2tleWNsb2FrLWF1dGhvcml6YXRpb24tcmVxdWVzdCc7XHJcbmltcG9ydCB7S2V5Y2xvYWtSZXNvdXJjZVBlcm1pc3Npb24sS2V5Y2xvYWtSZXNvdXJjZVBlcm1pc3Npb25zQ2hlY2t9IGZyb20gJy4uL2ludGVyZmFjZXMva2V5Y2xvYWstcGVybWlzc2lvbnMnO1xyXG5cclxuLyoqXHJcbiAqIEN1c3RvbSBwYXJhbWV0ZXIgY29kZWMgdG8gY29ycmVjdGx5IGhhbmRsZSB0aGUgcGx1cyBzaWduIGluIHBhcmFtZXRlclxyXG4gKiB2YWx1ZXMuIFNlZSBodHRwczovL2dpdGh1Yi5jb20vYW5ndWxhci9hbmd1bGFyL2lzc3Vlcy8xODI2MVxyXG4gKi9cclxuY2xhc3MgUGFyYW1ldGVyQ29kZWMgaW1wbGVtZW50cyBIdHRwUGFyYW1ldGVyQ29kZWMge1xyXG4gIGVuY29kZUtleShrZXk6IHN0cmluZyk6IHN0cmluZyB7XHJcbiAgICByZXR1cm4gZW5jb2RlVVJJQ29tcG9uZW50KGtleSk7XHJcbiAgfVxyXG5cclxuICBlbmNvZGVWYWx1ZSh2YWx1ZTogc3RyaW5nKTogc3RyaW5nIHtcclxuICAgIHJldHVybiBlbmNvZGVVUklDb21wb25lbnQodmFsdWUpO1xyXG4gIH1cclxuXHJcbiAgZGVjb2RlS2V5KGtleTogc3RyaW5nKTogc3RyaW5nIHtcclxuICAgIHJldHVybiBkZWNvZGVVUklDb21wb25lbnQoa2V5KTtcclxuICB9XHJcblxyXG4gIGRlY29kZVZhbHVlKHZhbHVlOiBzdHJpbmcpOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIGRlY29kZVVSSUNvbXBvbmVudCh2YWx1ZSk7XHJcbiAgfVxyXG59XHJcbmNvbnN0IFBBUkFNRVRFUl9DT0RFQyA9IG5ldyBQYXJhbWV0ZXJDb2RlYygpO1xyXG5cclxuQEluamVjdGFibGUoe1xyXG4gIHByb3ZpZGVkSW46ICdyb290J1xyXG59KVxyXG5leHBvcnQgY2xhc3MgS2V5Y2xvYWtBdXRob3JpemF0aW9uU2VydmljZSB7XHJcblxyXG4gICAgcHJpdmF0ZSBhdXRoQ29uZmlnID0gbnVsbDtcclxuICAgIHByaXZhdGUga2V5Y2xvYWtDb25maWc6IEtleWNsb2FrQ29uZmlnID0gbnVsbDtcclxuICAgIFxyXG4gICAgLyoqXHJcbiAgICAgKiBJbmRpY2F0ZXMgdGhhdCB0aGUgcGVybWlzc2lvbiBmb3IgdGhlIGRlZmF1bHQgcmVzb3VyY2Ugc2VydmVyIGJlIGxvYWRlZCBhdCB0aGUgYWRhcHRlciBpbml0aWFsaXphdGlvblxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIF9sb2FkUGVybWlzc2lvbnNJblN0YXJ0dXA6IGJvb2xlYW47XHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBEZWZpbmVzIHRoZSByZXNvdXJjZS1zZXJ2ZXIgb2Ygd2hpY2ggdGhlIHBlcm1pc3Npb25zIGFyZSBsb2FkZWQgYXQgYWRwYXRlciBpbml0aWFsaXphdGlvblxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIF9kZWZhdWx0UmVzb3VyY2VTZXJ2ZXJJZDogc3RyaW5nO1xyXG4gICAgXHJcbiAgICAvKipcclxuICAgICAqIENvbnRhaW5zIHRoZSBSUFQtVG9rZW4gYWZ0ZXIgc3VjY2Vzc2Z1bGwgR2V0LUVudGl0bGVtZW50LUNhbGxcclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSBfcnB0OiBzdHJpbmcgPSBudWxsO1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogQ29udGFpbnMgYWxsIHBlcm1pc3Npb25zIGRlY29kZWQgZnJvbSB0aGUgUlBULVRva2VuIGFmdGVyIHN1Y2Nlc3NmdWwgR2V0LUVudGl0bGVtZW50LUNhbGxcclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSBfcGVybWlzc2lvbnM6YW55W10gPSBbXTtcclxuXHJcbiAgY29uc3RydWN0b3IocHJpdmF0ZSBodHRwOkh0dHBDbGllbnQpIHtcclxuICB9XHJcbiAgXHJcbiAgcHJpdmF0ZSBuZXdQYXJhbXMoKTogSHR0cFBhcmFtcyB7XHJcbiAgICByZXR1cm4gbmV3IEh0dHBQYXJhbXMoe1xyXG4gICAgICBlbmNvZGVyOiBQQVJBTUVURVJfQ09ERUNcclxuICAgIH0pO1xyXG4gIH0gXHJcbiAgXHJcbiAgLyoqXHJcbiAgICogSGFuZGxlcyB0aGUgY2xhc3MgdmFsdWVzIGluaXRpYWxpemF0aW9uLlxyXG4gICAqXHJcbiAgICogQHBhcmFtIG9wdGlvbnNcclxuICAgKi9cclxuICBwcml2YXRlIGluaXRTZXJ2aWNlVmFsdWVzKHtcclxuICAgIGxvYWRQZXJtaXNzaW9uc0luU3RhcnR1cCA9IHRydWUsXHJcbiAgICBkZWZhdWx0UmVzb3VyY2VTZXJ2ZXJJZCA9IG51bGxcclxuICAgIFxyXG4gIH06IEtleWNsb2FrQXV0aHpJbml0T3B0aW9ucyk6IHZvaWQge1xyXG4gICAgdGhpcy5fbG9hZFBlcm1pc3Npb25zSW5TdGFydHVwID0gbG9hZFBlcm1pc3Npb25zSW5TdGFydHVwO1xyXG4gICAgdGhpcy5fZGVmYXVsdFJlc291cmNlU2VydmVySWQgPSBkZWZhdWx0UmVzb3VyY2VTZXJ2ZXJJZDtcclxuICB9XHJcbiAgXHJcbiAgXHJcbiAgLyoqXHJcbiAgICogS2V5Y2xvYWtBdXRob3JpemF0aW9uIGluaXRpYWxpemF0aW9uLiBJdCBzaG91bGQgYmUgY2FsbGVkIHRvIGluaXRpYWxpemUgdGhlIGFkYXB0ZXIuXHJcbiAgICogT3B0aW9ucyBpcyBhIG9iamVjdCB3aXRoIDIgbWFpbiBwYXJhbWV0ZXJzOiBjb25maWcgYW5kIGluaXRPcHRpb25zLiBUaGUgZmlyc3Qgb25lXHJcbiAgICogd2lsbCBiZSB1c2VkIHRvIGNvbm5lY3QgdG8gS2V5Y2xvYWsuIFRoZSBzZWNvbmQgb25lIGFyZSBvcHRpb25zIHRvIGluaXRpYWxpemUgdGhlXHJcbiAgICoga2V5Y2xvYWsgYXV0aG9yaXphdGlvbiBpbnN0YW5jZS5cclxuICAgKiBcclxuICAgKiBAcGFyYW0gb3B0aW9uc1xyXG4gICAqIGNvbmZpZzogYW4gb2JqZWN0IHdpdGggdGhlIGZvbGxvd2luZyBjb250ZW50OlxyXG4gICAqIC0gdXJsOiBLZXljbG9hayBqc29uIFVSTFxyXG4gICAqIC0gcmVhbG06IHJlYWxtIG5hbWVcclxuICAgKiAtIGNsaWVudElkOiBjbGllbnQgaWRcclxuICAgKlxyXG4gICAqIGluaXRPcHRpb25zOiBcclxuICAgKiAtIGRlZmF1bHRSZXNvdXJjZVNlcnZlcklkOiBzcGVjaWZpZXMgdGhlIGRlZmF1bHQgcmVzb3VyY2Utc2VydmVyXHJcbiAgICogLSBsb2FkUGVybWlzc2lvbnNJblN0YXJ0dXA6IGlmIHNldCB0byB0cnVlLCBsb2FkIGFsbCBwZXJtaXNzaW9ucyBmb3IgZGVmYXVsdCByZXNvdXJjZS1zZXJ2ZXIgYXQgaW5pdGlhbGl6aWF0aW9uIG9mIGFkYXB0ZXJcclxuICAgKiBcclxuICAgKiBcclxuICAgKi9cclxuICBpbml0KG9wdGlvbnM6IEtleWNsb2FrQXV0aHpPcHRpb25zKXtcclxuICAgICAgXHJcbiAgICAgIGNvbnN0IHsgY29uZmlnLCBpbml0T3B0aW9ucyB9ID0gb3B0aW9ucztcclxuICAgICAgdGhpcy5pbml0U2VydmljZVZhbHVlcyhpbml0T3B0aW9ucyk7XHJcbiAgICAgIFxyXG4gICAgICB0aGlzLmtleWNsb2FrQ29uZmlnID0gY29uZmlnO1xyXG4gICAgICAvL2NvbnNvbGUubG9nKHRoaXMuX2RlZmF1bHRSZXNvdXJjZVNlcnZlcklkKVxyXG5cclxuICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcclxuICAgICAgICB0aGlzLmh0dHAuZ2V0KHRoaXMua2V5Y2xvYWtDb25maWcudXJsICsgJy9yZWFsbXMvJyArIHRoaXMua2V5Y2xvYWtDb25maWcucmVhbG0gKyAnLy53ZWxsLWtub3duL3VtYTItY29uZmlndXJhdGlvbicpLnN1YnNjcmliZShhc3luYyByZXMgPT4ge1xyXG4gICAgICAgICAgdGhpcy5hdXRoQ29uZmlnPXJlcztcclxuICAgICAgICAgIGlmICgodGhpcy5fZGVmYXVsdFJlc291cmNlU2VydmVySWQpICYmICh0aGlzLl9sb2FkUGVybWlzc2lvbnNJblN0YXJ0dXApKXtcclxuICAgICAgICAgICAgdHJ5e1xyXG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5nZXRBdXRob3JpemF0aW9ucyh0aGlzLl9kZWZhdWx0UmVzb3VyY2VTZXJ2ZXJJZCx7fSk7XHJcbiAgICAgICAgICAgIH0gY2F0Y2ggKGVycil7XHJcbiAgICAgICAgICAgICAgICByZWplY3QgKFwiRXJyb3IgZ2V0dGluZyBhdXRob3JpemF0aW9ucyBmb3IgcmVzb3VyY2Utc2VydmVyLWlkIFwiICsgdGhpcy5fZGVmYXVsdFJlc291cmNlU2VydmVySWQpXHJcbiAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgcmVzb2x2ZShyZXMpO1xyXG4gICAgICAgIH0sIGVyciA9PiB7XHJcbiAgICAgICAgICAgIGxldCBtc2c9XCJGZWhsZXIgYmVpIGRlciBJbml0aWFsaXNpZXJ1bmcgZGVzIEtleWNsb2FrLUF1dGhvcml6YXRpb24tU2VydmljZXNcIjtcclxuICAgICAgICAgICAgcmVqZWN0KG1zZyk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0pO1xyXG4gIH1cclxuICBcclxuICAvKipcclxuICAgKiBDaGVja3MgaWYgdXNlciBoYXMgdGhlIHJlcXVpcmVkIGFjY2VzcyB0byBhIHJlc291cmNlIGFuZC9vciBzY29wZS4gXHJcbiAgICogXHJcbiAgICogQHBhcmFtIGF1dGhvcml6YXRpb24tY2hlY2sgb2JqZWN0XHJcbiAgICogLSByc25hbWUgOiBOYW1lIG9mIHRoZSByZXNvdXJjZVxyXG4gICAqIC0gc2NvcGUgOiBuYW1lIG9mIHRoZSBzY29wZVxyXG4gICAqIFxyXG4gICAqIFxyXG4gICAqIEByZXR1cm5zIGJvb2xlYW4gdHJ1ZSBpZiB1c2VyIGhhcyBhY2Nlc3MsIGZhbHNlIGlmIG5vdFxyXG4gICAqL1xyXG4gIHB1YmxpYyBjaGVja0F1dGhvcml6YXRpb24oYXV0aG9yaXphdGlvbjpLZXljbG9ha1Jlc291cmNlUGVybWlzc2lvbnNDaGVjaykge1xyXG4gICAgICByZXR1cm4gdGhpcy5oYXNBdXRob3JpemF0aW9uKGF1dGhvcml6YXRpb24pO1xyXG4gIH1cclxuICBcclxuICAvKipcclxuICAgKiBJbnRlcm5hbCBtZXRob2QgdG8gY2hlY2sgaWYgdXNlciBoYXMgdGhlIHJlcXVpcmVkIGFjY2VzcyB0byBhIHJlc291cmNlIGFuZC9vciBzY29wZVxyXG4gICAqIFxyXG4gICAqIEBwYXJhbSBhdXRob3JpemF0aW9uXHJcbiAgICogXHJcbiAgICogQHJldHVybnMgYm9vbGVhbiB0cnVlIGlmIHVzZXIgaGFzIGFjY2VzcywgZmFsc2UgaWYgbm90XHJcbiAgICovXHJcbiAgcHJpdmF0ZSBoYXNBdXRob3JpemF0aW9uKGF1dGhvcml6YXRpb246S2V5Y2xvYWtSZXNvdXJjZVBlcm1pc3Npb25zQ2hlY2spOmJvb2xlYW57XHJcbiAgICAgIFxyXG4gICAgICBsZXQgY2hlY2tGb3JSZXNvdXJjZSA9IHQoYXV0aG9yaXphdGlvbiwncnNuYW1lJykuc2FmZU9iamVjdDtcclxuICAgICAgbGV0IGNoZWNrRm9yU2NvcGUgPSB0KGF1dGhvcml6YXRpb24sJ3Njb3BlJykuc2FmZU9iamVjdDtcclxuICAgICAgXHJcbiAgICAgIGlmICghdCh0aGlzLl9wZXJtaXNzaW9ucykuaXNFbXB0eUFycmF5KXtcclxuICAgICAgICAgIFxyXG4gICAgICAgICAgbGV0IGZpbHRlcmVkUmVzb3VyY2UgPSB0aGlzLl9wZXJtaXNzaW9ucy5maW5kKHQgPT4ge2lmICh0LnJzbmFtZT09Y2hlY2tGb3JSZXNvdXJjZSkgcmV0dXJuIHQ7fSk7XHJcbiAgICAgICAgICAvL05vIGFjY2VzcyB0byByZXNvdXJjZVxyXG4gICAgICAgICAgaWYgKCF0KGZpbHRlcmVkUmVzb3VyY2UpLmlzT2JqZWN0KXtcclxuICAgICAgICAgICAgICAvL2NvbnNvbGUubG9nKFwibm8gYWNjZXNzIHRvIHJlc291cmNlIGdyYW50ZWRcIik7XHJcbiAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgLy9hY2Nlc3MgdG8gcmVzb3VyY2UgZ3JhbnRlZCBhbmQgbm8gc2NvcGUgY2hlY2tpbmcgcmVxdWlyZWRcclxuICAgICAgICAgIGlmIChjaGVja0ZvclNjb3BlID09IHVuZGVmaW5lZCl7XHJcbiAgICAgICAgICAgICAgLy9jb25zb2xlLmxvZyhcIm5vIHNjb3BlIGNoZWNraW5nIHJlcXVpcmVkLnJlcXVpcmVkIGF1dGggaXMgcHJlc2VudCAtIGhvb3JheVwiKTtcclxuICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIC8vc2NvcGUgY2hlY2tpbmcgcmVxdWlyZWQsIGJ1dCByZXNvdXJjZSBoYXMgbm8gc2NvcGUgZGVmaW5lZFxyXG4gICAgICAgICAgaWYgKHQoZmlsdGVyZWRSZXNvdXJjZS5zY29wZXMpLmlzRW1wdHlBcnJheSl7XHJcbiAgICAgICAgICAgICAgLy9jb25zb2xlLmxvZyhcInNjb3BlIGNoZWNraW5nIHJlcXVpcmVkLCBidXQgbm8gc2NvcGVzIGRlZmluZWQgZm9yIHJlc291cmNlXCIpO1xyXG4gICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIGxldCBmaWx0ZXJlZFNjb3BlID0gZmlsdGVyZWRSZXNvdXJjZS5zY29wZXMuZmluZCh0ID0+IHsgaWYgKHQgPT0gY2hlY2tGb3JTY29wZSkgcmV0dXJuIHQ7fSk7XHJcbiAgICAgICAgICAvL25vIGFjY2VzcyB0byBzY29wZVxyXG4gICAgICAgICAgaWYgKHQoZmlsdGVyZWRTY29wZSkuaXNVbmRlZmluZWQgKXtcclxuICAgICAgICAgICAgICAvL2NvbnNvbGUubG9nKFwicmVxdWlyZWQgc2NvcGUgbm90IGZvdW5kXCIpO1xyXG4gICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIC8vY29uc29sZS5sb2coXCJyZXF1aXJlZCBhdXRoIGlzIHByZXNlbnQgLSBob29yYXlcIik7XHJcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgfVxyXG4gICAgICAvL2NvbnNvbGUubG9nKFwibm8gcGVybWlzc2lvbnMgbG9hZGVkICh5ZXQpXCIpO1xyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgIFxyXG4gIH1cclxuICBcclxuICAvKipcclxuICAgKiBSZXR1cm4gYW4gYXJyYXkgb2YgYWxsIHBlcm1pc3Npb25zIHByZXNlbnQgZm9yIHRoZSBsb2dnZWQtaW4gdXNlclxyXG4gICAqIFxyXG4gICAqIEByZXR1cm5zIEFycmF5IG9mIHBlcm1pc3Npb25zXHJcbiAgICovXHJcbiAgcHVibGljIGdldFBlcm1pc3Npb25zKCk6S2V5Y2xvYWtSZXNvdXJjZVBlcm1pc3Npb25bXXtcclxuICAgICAgcmV0dXJuIHRoaXMuX3Blcm1pc3Npb25zO1xyXG4gICAgICBcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEdldHMgYXV0aG9yaXphdGlvbnMgZm9yIHJlc291cmNlLXNlcnZlciBmcm9tIGtleWNsb2FrLiBBbHNvIHN0b3JlcyB0aGUgcGVybWlzc2lvbnMgZm9yIGZ1dHVyZSB1c2VcclxuICAgKiBcclxuICAgKiBAcGFyYW0gcmVzb3VyY2VTZXJ2ZXJJZFxyXG4gICAqIFRoZSByZXNvdXJjZSBzZXJ2ZXIgZm9yIHdoaWNoIHRoZSBlbnRpdGxlbWVudHMgb2YgdGhlIGN1cnJlbnQgdXNlciBhcmUgY2hlY2tlZFxyXG4gICAqIFxyXG4gICAqIEBwYXJhbSBhdXRob3JpemF0aW9uUmVxdWVzdFxyXG4gICAqIFxyXG4gICAqIEByZXR1cm5zIEF1dGhvcml6YXRpb25zLU9iamVjdCBcclxuICAgKi9cclxuICBwdWJsaWMgZ2V0QXV0aG9yaXphdGlvbnMocmVzb3VyY2VTZXJ2ZXJJZCwgYXV0aG9yaXphdGlvblJlcXVlc3Q6S2V5Y2xvYWtBdXRob3JpemF0aW9uUmVxdWVzdCkge1xyXG4gICAgICBcclxuICAgICAgbGV0IHBlcm0gPSBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICAgIHRoaXMuZ2V0RW50aXRsZW1lbnQocmVzb3VyY2VTZXJ2ZXJJZCwgYXV0aG9yaXphdGlvblJlcXVlc3QpXHJcbiAgICAgIC5zdWJzY3JpYmUocmVzID0+IHtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICBcclxuICAgICAgICAgICAgbGV0IHBlcm1pc3Npb25zID0gW107XHJcbiAgICAgICAgICAgIGlmIChyZXMuYWNjZXNzX3Rva2VuKXtcclxuICAgICAgICAgICAgICAgIHRoaXMuX3JwdCA9IHJlcy5hY2Nlc3NfdG9rZW47XHJcbiAgICAgICAgICAgICAgICBsZXQgZGVjb2RlZCA9IHRoaXMuZGVjb2RlVG9rZW4ocmVzLmFjY2Vzc190b2tlbik7XHJcbiAgICAgICAgICAgICAgICBpZiAoZGVjb2RlZC5hdXRob3JpemF0aW9uKXtcclxuICAgICAgICAgICAgICAgICAgICBpZiAoZGVjb2RlZC5hdXRob3JpemF0aW9uLnBlcm1pc3Npb25zKXtcclxuICAgICAgICAgICAgICAgICAgICAgICAgcGVybWlzc2lvbnMgPSBkZWNvZGVkLmF1dGhvcml6YXRpb24ucGVybWlzc2lvbnM7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIHRoaXMuX3Blcm1pc3Npb25zID0gcGVybWlzc2lvbnM7XHJcbiAgICAgICAgICBcclxuICAgICAgICAgICAgcmVzb2x2ZShwZXJtaXNzaW9ucyk7XHJcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgICB9XHJcbiAgICB9LCBlcnJvciA9PiB7XHJcbiAgICAgICAgbGV0IG1zZyA9IFwiVW5hYmxlIHRvIGdldCBlbnRpdGxlbWVudHNcIjtcclxuICAgICAgICByZWplY3QobXNnKTtcclxuICAgIH0pO1xyXG4gICAgfSk7XHJcbiAgICBcclxuICAgIHJldHVybiBwZXJtO1xyXG4gICAgXHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBHZXRzIGVudGl0bGVtZW50IGZyb24gcmVzb3VyY2Utc2VydmVyIGZyb20ga2V5Y2xvYWtcclxuICAgKiBcclxuICAgKiBAcGFyYW0gcmVzb3VyY2VTZXJ2ZXJJZFxyXG4gICAqIFRoZSByZXNvdXJjZSBzZXJ2ZXIgZm9yIHdoaWNoIHRoZSBlbnRpdGxlbWVudHMgb2YgdGhlIGN1cnJlbnQgdXNlciBhcmUgY2hlY2tlZFxyXG4gICAqIFxyXG4gICAqIEBwYXJhbSBhdXRob3JpemF0aW9uUmVxdWVzdFxyXG4gICAqIFxyXG4gICAqIEByZXR1cm5zIE9iamVjdCB3aXRoIFJQVC1Ub2tlbiBjb250YWluaW5nIHRoZSBhdXRob3JpemF0aW9ucy9lbnRpdGxlbWVudFxyXG4gICAqL1xyXG4gIHByaXZhdGUgZ2V0RW50aXRsZW1lbnQocmVzb3VyY2VTZXJ2ZXJJZCwgYXV0aG9yaXphdGlvblJlcXVlc3Q6S2V5Y2xvYWtBdXRob3JpemF0aW9uUmVxdWVzdCkge1xyXG4gICAgICBcclxuICAgICAgXHJcbiAgICBsZXQgX19wYXJhbXMgPSB0aGlzLm5ld1BhcmFtcygpO1xyXG4gICAgbGV0IF9faGVhZGVycyA9IG5ldyBIdHRwSGVhZGVycygpO1xyXG4gICAgbGV0IF9fYm9keTogYW55ID0gbnVsbDtcclxuICAgIFxyXG4gICAgXHJcbiAgICBfX2hlYWRlcnMgPSBfX2hlYWRlcnMuc2V0KFwiQ29udGVudC10eXBlXCIsIFwiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkXCIpO1xyXG4gICAgXHJcbiAgICBpZiAoIWF1dGhvcml6YXRpb25SZXF1ZXN0KSB7XHJcbiAgICAgICBhdXRob3JpemF0aW9uUmVxdWVzdCA9IHt9O1xyXG4gICAgfVxyXG5cclxuICAgIF9fcGFyYW1zID0gX19wYXJhbXMuc2V0KCdncmFudF90eXBlJywgJ3VybjppZXRmOnBhcmFtczpvYXV0aDpncmFudC10eXBlOnVtYS10aWNrZXQnKTtcclxuICAgIF9fcGFyYW1zID0gX19wYXJhbXMuc2V0KCdjbGllbnRfaWQnLCB0aGlzLmtleWNsb2FrQ29uZmlnLmNsaWVudElkKTtcclxuICAgIF9fcGFyYW1zID0gX19wYXJhbXMuc2V0KCdhdWRpZW5jZScsIHJlc291cmNlU2VydmVySWQpO1xyXG4gICAgXHJcbiAgICBcclxuICAgIGlmIChhdXRob3JpemF0aW9uUmVxdWVzdC5jbGFpbVRva2VuKSB7XHJcbiAgICAgICAgX19wYXJhbXMgPSBfX3BhcmFtcy5zZXQoJ2NsYWltX3Rva2VuJyxhdXRob3JpemF0aW9uUmVxdWVzdC5jbGFpbVRva2VuKTtcclxuICAgICAgICBpZiAoYXV0aG9yaXphdGlvblJlcXVlc3QuY2xhaW1Ub2tlbkZvcm1hdCkge1xyXG4gICAgICAgICAgICBfX3BhcmFtcyA9IF9fcGFyYW1zLnNldCgnY2xhaW1fdG9rZW5fZm9ybWF0JyxhdXRob3JpemF0aW9uUmVxdWVzdC5jbGFpbVRva2VuRm9ybWF0KTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgdmFyIHBlcm1pc3Npb25zOlJlc291cmNlUGVybWlzc2lvbltdID0gYXV0aG9yaXphdGlvblJlcXVlc3QucGVybWlzc2lvbnM7XHJcblxyXG4gICAgaWYgKCFwZXJtaXNzaW9ucykge1xyXG4gICAgICAgIHBlcm1pc3Npb25zID0gW107XHJcbiAgICB9XHJcblxyXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBwZXJtaXNzaW9ucy5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgIHZhciByZXNvdXJjZSA9IHBlcm1pc3Npb25zW2ldO1xyXG4gICAgICAgIHZhciBwZXJtaXNzaW9uID0gcmVzb3VyY2UuaWQ7XHJcblxyXG4gICAgICAgIGlmIChyZXNvdXJjZS5zY29wZXMgJiYgcmVzb3VyY2Uuc2NvcGVzLmxlbmd0aCA+IDApIHtcclxuICAgICAgICAgICAgcGVybWlzc2lvbiArPSBcIiNcIjtcclxuICAgICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCByZXNvdXJjZS5zY29wZXMubGVuZ3RoOyBqKyspIHtcclxuICAgICAgICAgICAgICAgIHZhciBzY29wZSA9IHJlc291cmNlLnNjb3Blc1tqXTtcclxuICAgICAgICAgICAgICAgIGlmIChwZXJtaXNzaW9uLmluZGV4T2YoJyMnKSAhPSBwZXJtaXNzaW9uLmxlbmd0aCAtIDEpIHtcclxuICAgICAgICAgICAgICAgICAgICBwZXJtaXNzaW9uICs9IFwiLFwiO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgcGVybWlzc2lvbiArPSBzY29wZTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgICBcclxuICAgICAgICBfX3BhcmFtcyA9IF9fcGFyYW1zLmFwcGVuZCgncGVybWlzc2lvbicsIHBlcm1pc3Npb24pO1xyXG4gICAgfVxyXG5cclxuICAgIHZhciBtZXRhZGF0YTpLZXljbG9ha0F1dGhvcml6YXRpb25SZXF1ZXN0TWV0YURhdGEgPSBhdXRob3JpemF0aW9uUmVxdWVzdC5tZXRhZGF0YTtcclxuXHJcbiAgICBpZiAobWV0YWRhdGEpIHtcclxuICAgICAgICBpZiAobWV0YWRhdGEucmVzcG9uc2VJbmNsdWRlUmVzb3VyY2VOYW1lKSB7XHJcbiAgICAgICAgICAgIF9fcGFyYW1zID0gX19wYXJhbXMuc2V0KCdyZXNwb25zZV9pbmNsdWRlX3Jlc291cmNlX25hbWUnLG1ldGFkYXRhLnJlc3BvbnNlSW5jbHVkZVJlc291cmNlTmFtZSk7XHJcbiAgICAgICAgICAgIFxyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAobWV0YWRhdGEucmVzcG9uc2VQZXJtaXNzaW9uc0xpbWl0KSB7XHJcbiAgICAgICAgICAgIF9fcGFyYW1zID0gX19wYXJhbXMuc2V0KCdyZXNwb25zZV9wZXJtaXNzaW9uc19saW1pdCcsbWV0YWRhdGEucmVzcG9uc2VQZXJtaXNzaW9uc0xpbWl0LnRvU3RyaW5nKCkpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBpZiAodGhpcy5fcnB0KSB7XHJcbiAgICAgICAgX19wYXJhbXMgPSBfX3BhcmFtcy5zZXQoJ3JwdCcsdGhpcy5fcnB0KTtcclxuICAgIH1cclxuICAgIFxyXG4gICAgXHJcbiAgICByZXR1cm4gdGhpcy5odHRwLnBvc3Q8YW55Pih0aGlzLmF1dGhDb25maWcudG9rZW5fZW5kcG9pbnQsIF9fcGFyYW1zLnRvU3RyaW5nKCksIHtcclxuICAgICAgICBoZWFkZXJzOiBfX2hlYWRlcnMsXHJcbiAgICAgICAgcmVzcG9uc2VUeXBlOiAnanNvbidcclxuICAgIH0pXHJcbiAgICAucGlwZShcclxuICAgICAgICBjYXRjaEVycm9yKHRoaXMuaGFuZGxlRXJyb3IpLFxyXG4gICAgICAgIF9fbWFwKChfcikgPT4ge1xyXG4gICAgICAgICAgLy9jb25zb2xlLmxvZyhfcik7XHJcbiAgICAgICAgICByZXR1cm4gX3I7XHJcbiAgICAgICAgfSlcclxuICAgICk7XHJcbiAgICBcclxuXHJcbiAgICAgIFxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogRGVjb2RlcyBSUFQtVG9rZW5cclxuICAgKiBcclxuICAgKiBAcGFyYW0gc3RyIC0gZW5vZGVkIHRva2VuIHN0cmluZ1xyXG4gICAqIFxyXG4gICAqIEByZXR1cm5zIERlY29kZWQgand0LXRva2VuIG9iamVjdFxyXG4gICAqIFxyXG4gICAqL1xyXG4gIHByaXZhdGUgZGVjb2RlVG9rZW4oc3RyKSB7XHJcbiAgICAgICAgICAgIHN0ciA9IHN0ci5zcGxpdCgnLicpWzFdO1xyXG5cclxuICAgICAgICAgICAgc3RyID0gc3RyLnJlcGxhY2UoJy8tL2cnLCAnKycpO1xyXG4gICAgICAgICAgICBzdHIgPSBzdHIucmVwbGFjZSgnL18vZycsICcvJyk7XHJcbiAgICAgICAgICAgIHN3aXRjaCAoc3RyLmxlbmd0aCAlIDQpXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICAgIGNhc2UgMDpcclxuICAgICAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgICAgIGNhc2UgMjpcclxuICAgICAgICAgICAgICAgICAgICBzdHIgKz0gJz09JztcclxuICAgICAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgICAgIGNhc2UgMzpcclxuICAgICAgICAgICAgICAgICAgICBzdHIgKz0gJz0nO1xyXG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICAgICAgZGVmYXVsdDpcclxuICAgICAgICAgICAgICAgICAgICB0aHJvdyAnSW52YWxpZCB0b2tlbic7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIHN0ciA9IChzdHIgKyAnPT09Jykuc2xpY2UoMCwgc3RyLmxlbmd0aCArIChzdHIubGVuZ3RoICUgNCkpO1xyXG4gICAgICAgICAgICBzdHIgPSBzdHIucmVwbGFjZSgvLS9nLCAnKycpLnJlcGxhY2UoL18vZywgJy8nKTtcclxuXHJcbiAgICAgICAgICAgIHN0ciA9IGRlY29kZVVSSUNvbXBvbmVudChlc2NhcGUoYXRvYihzdHIpKSk7XHJcblxyXG4gICAgICAgICAgICBzdHIgPSBKU09OLnBhcnNlKHN0cik7XHJcbiAgICAgICAgICAgIHJldHVybiBzdHI7XHJcbiAgICB9XHJcbiAgICBcclxuICAgIHByaXZhdGUgaGFuZGxlRXJyb3IoZXJyb3I6IEh0dHBFcnJvclJlc3BvbnNlKSB7XHJcbiAgICAgIGlmIChlcnJvci5lcnJvciBpbnN0YW5jZW9mIEVycm9yRXZlbnQpIHtcclxuICAgICAgICAvLyBBIGNsaWVudC1zaWRlIG9yIG5ldHdvcmsgZXJyb3Igb2NjdXJyZWQuIEhhbmRsZSBpdCBhY2NvcmRpbmdseS5cclxuICAgICAgICBjb25zb2xlLmVycm9yKCdBbiBlcnJvciBvY2N1cnJlZDonLCBlcnJvci5lcnJvci5tZXNzYWdlKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBUaGUgYmFja2VuZCByZXR1cm5lZCBhbiB1bnN1Y2Nlc3NmdWwgcmVzcG9uc2UgY29kZS5cclxuICAgICAgICAvLyBUaGUgcmVzcG9uc2UgYm9keSBtYXkgY29udGFpbiBjbHVlcyBhcyB0byB3aGF0IHdlbnQgd3JvbmcsXHJcbiAgICAgICAgY29uc29sZS5lcnJvcihcclxuICAgICAgICAgIGBCYWNrZW5kIHJldHVybmVkIGNvZGUgJHtlcnJvci5zdGF0dXN9LCBgICtcclxuICAgICAgICAgIGBib2R5IHdhczogJHtlcnJvci5lcnJvcn1gKTtcclxuICAgICAgfVxyXG4gICAgICAvLyByZXR1cm4gYW4gb2JzZXJ2YWJsZSB3aXRoIGEgdXNlci1mYWNpbmcgZXJyb3IgbWVzc2FnZVxyXG4gICAgICByZXR1cm4gdGhyb3dFcnJvcihcclxuICAgICAgICAnU29tZXRoaW5nIGJhZCBoYXBwZW5lZDsgcGxlYXNlIHRyeSBhZ2FpbiBsYXRlci4nKTtcclxuICAgIH07XHJcbiAgXHJcbn1cclxuIl19