UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

300 lines 40.4 kB
import { __decorate, __metadata } from "tslib"; import { Injectable } from '@angular/core'; import { InventoryService, UserService } from '@c8y/client'; import { property } from 'lodash-es'; import { memoize } from './memoize.decorator'; import { AppStateService } from './ui-state.service'; import * as i0 from "@angular/core"; import * as i1 from "./ui-state.service"; import * as i2 from "@c8y/client"; export class Permissions { static { this.ROLE_ADVANCED_SOFTWARE_ADMIN = 'ROLE_ADVANCED_SOFTWARE_ADMIN'; } static { this.ROLE_ADVANCED_SOFTWARE_READ = 'ROLE_ADVANCED_SOFTWARE_READ'; } static { this.ROLE_ALARM_ADMIN = 'ROLE_ALARM_ADMIN'; } static { this.ROLE_ALARM_READ = 'ROLE_ALARM_READ'; } static { this.ROLE_ANALYTICSBUILDER_READ = 'ROLE_ANALYTICSBUILDER_READ'; } static { this.ROLE_APPLICATION_MANAGEMENT_ADMIN = 'ROLE_APPLICATION_MANAGEMENT_ADMIN'; } static { this.ROLE_APPLICATION_MANAGEMENT_READ = 'ROLE_APPLICATION_MANAGEMENT_READ'; } static { this.ROLE_AUDIT_ADMIN = 'ROLE_AUDIT_ADMIN'; } static { this.ROLE_AUDIT_READ = 'ROLE_AUDIT_READ'; } static { this.ROLE_BINARY_ADMIN = 'ROLE_BINARY_ADMIN'; } static { this.ROLE_BINARY_CREATE = 'ROLE_BINARY_CREATE'; } static { this.ROLE_BINARY_READ = 'ROLE_BINARY_READ'; } static { this.ROLE_BULK_OPERATION_ADMIN = 'ROLE_BULK_OPERATION_ADMIN'; } static { this.ROLE_BULK_OPERATION_READ = 'ROLE_BULK_OPERATION_READ'; } static { this.ROLE_CEP_MANAGEMENT_ADMIN = 'ROLE_CEP_MANAGEMENT_ADMIN'; } static { this.ROLE_CEP_MANAGEMENT_READ = 'ROLE_CEP_MANAGEMENT_READ'; } static { this.ROLE_DATA_BROKER_ADMIN = 'ROLE_DATA_BROKER_ADMIN'; } static { this.ROLE_DATA_BROKER_READ = 'ROLE_DATA_BROKER_READ'; } static { this.ROLE_DEVICE_CONTROL_ADMIN = 'ROLE_DEVICE_CONTROL_ADMIN'; } static { this.ROLE_DEVICE_CONTROL_READ = 'ROLE_DEVICE_CONTROL_READ'; } static { this.ROLE_EMAIL_CREATE = 'ROLE_EMAIL_CREATE'; } static { this.ROLE_EPLAPPS_READ = 'ROLE_EPLAPPS_READ'; } static { this.ROLE_EVENT_ADMIN = 'ROLE_EVENT_ADMIN'; } static { this.ROLE_EVENT_READ = 'ROLE_EVENT_READ'; } static { this.ROLE_GENERIC_MQTT_ADMIN = 'ROLE_GENERIC_MQTT_ADMIN'; } static { this.ROLE_IDENTITY_ADMIN = 'ROLE_IDENTITY_ADMIN'; } static { this.ROLE_IDENTITY_READ = 'ROLE_IDENTITY_READ'; } static { this.ROLE_INVENTORY_ADMIN = 'ROLE_INVENTORY_ADMIN'; } static { this.ROLE_INVENTORY_CREATE = 'ROLE_INVENTORY_CREATE'; } static { this.ROLE_INVENTORY_READ = 'ROLE_INVENTORY_READ'; } static { this.ROLE_MACHINE_LEARNING_READ = 'ROLE_MACHINE_LEARNING_READ'; } static { this.ROLE_MANAGED_OBJECT_ADMIN = 'ROLE_MANAGED_OBJECT_ADMIN'; } static { this.ROLE_MANAGED_OBJECT_CREATE = 'ROLE_MANAGED_OBJECT_CREATE'; } static { this.ROLE_MANAGED_OBJECT_READ = 'ROLE_MANAGED_OBJECT_READ'; } static { this.ROLE_MEASUREMENT_ADMIN = 'ROLE_MEASUREMENT_ADMIN'; } static { this.ROLE_MEASUREMENT_READ = 'ROLE_MEASUREMENT_READ'; } static { this.ROLE_MQTT_CONNECT_ADMIN = 'ROLE_MQTT_CONNECT_ADMIN'; } static { this.ROLE_MQTT_SERVICE_ADMIN = 'ROLE_MQTT_SERVICE_ADMIN'; } static { this.ROLE_NOTIFICATION_2_ADMIN = 'ROLE_NOTIFICATION_2_ADMIN'; } static { this.ROLE_OPTION_MANAGEMENT_ADMIN = 'ROLE_OPTION_MANAGEMENT_ADMIN'; } static { this.ROLE_OPTION_MANAGEMENT_READ = 'ROLE_OPTION_MANAGEMENT_READ'; } static { this.ROLE_PROVISIONING_CREATE = 'ROLE_PROVISIONING_CREATE'; } static { this.ROLE_PROVISIONING_READ = 'ROLE_PROVISIONING_READ'; } static { this.ROLE_PROVISIONING_UPDATE = 'ROLE_PROVISIONING_UPDATE'; } static { this.ROLE_REMOTE_ACCESS_ADMIN = 'ROLE_REMOTE_ACCESS_ADMIN'; } static { this.ROLE_RETENTION_RULE_ADMIN = 'ROLE_RETENTION_RULE_ADMIN'; } static { this.ROLE_RETENTION_RULE_READ = 'ROLE_RETENTION_RULE_READ'; } static { this.ROLE_SCHEDULE_REPORT_ADMIN = 'ROLE_SCHEDULE_REPORT_ADMIN'; } static { this.ROLE_SIMULATOR_ADMIN = 'ROLE_SIMULATOR_ADMIN'; } static { this.ROLE_SMARTGROUP_ADMIN = 'ROLE_SMARTGROUP_ADMIN'; } static { this.ROLE_SMARTGROUP_CREATE = 'ROLE_SMARTGROUP_CREATE'; } static { this.ROLE_SMARTGROUP_UPDATE = 'ROLE_SMARTGROUP_UPDATE'; } static { this.ROLE_SMARTRULE_ADMIN = 'ROLE_SMARTRULE_ADMIN'; } static { this.ROLE_SMARTRULE_READ = 'ROLE_SMARTRULE_READ'; } static { this.ROLE_SMS_ADMIN = 'ROLE_SMS_ADMIN'; } static { this.ROLE_SMS_READ = 'ROLE_SMS_READ'; } static { this.ROLE_TENANT_ADMIN = 'ROLE_TENANT_ADMIN'; } static { this.ROLE_TENANT_MANAGEMENT_ADMIN = 'ROLE_TENANT_MANAGEMENT_ADMIN'; } static { this.ROLE_TENANT_MANAGEMENT_CREATE = 'ROLE_TENANT_MANAGEMENT_CREATE'; } static { this.ROLE_TENANT_MANAGEMENT_READ = 'ROLE_TENANT_MANAGEMENT_READ'; } static { this.ROLE_TENANT_MANAGEMENT_UPDATE = 'ROLE_TENANT_MANAGEMENT_UPDATE'; } static { this.ROLE_TENANT_STATISTICS_READ = 'ROLE_TENANT_STATISTICS_READ'; } static { this.ROLE_USER_MANAGEMENT_ADMIN = 'ROLE_USER_MANAGEMENT_ADMIN'; } static { this.ROLE_USER_MANAGEMENT_CREATE = 'ROLE_USER_MANAGEMENT_CREATE'; } static { this.ROLE_USER_MANAGEMENT_OWN_ADMIN = 'ROLE_USER_MANAGEMENT_OWN_ADMIN'; } static { this.ROLE_USER_MANAGEMENT_OWN_READ = 'ROLE_USER_MANAGEMENT_OWN_READ'; } static { this.ROLE_USER_MANAGEMENT_READ = 'ROLE_USER_MANAGEMENT_READ'; } constructor(appState, inventory, user) { this.appState = appState; this.inventory = inventory; this.user = user; } /** * Checks if the current user has write permissions for the given mo * (either through global role, individual device permissions or via inventory roles). * * ```ts * async canEditGroup(group: IManagedObject): Promise<boolean> { * return await this.permissions.canEdit( * [Permissions.ROLE_INVENTORY_ADMIN, Permissions.ROLE_MANAGED_OBJECT_ADMIN], * group * ); * } * ``` * * @param roleIds - The array of role ids to check if the current user have at least one of them. * @param mo - The managed object for which we are checking whether the user has access. * @param config - A configuration object that can take the following values: `skipRolesCheck`: `boolean` - skips roles check, `skipOwnerCheck`: `boolean` - skips ownership check, `skipRequestCheck`: `boolean` - skips checks with a query to the inventory API. UI will make a query to backend whether the user can edit the managed object. A rejection from BE indicates a lack of permission. * * @returns A Promise resolving to a boolean value. `true` if editing is permitted based on the given parameters and configuration; otherwise, `false`. * */ canEdit(roleIds, mo, config = { skipRolesCheck: false, skipOwnerCheck: false, skipRequestCheck: false }) { return this.checkIfCanEdit(roleIds, mo, config); } /** * Checks if the current user has the specified role. * * ```ts * hasSmsReadRole(): boolean { * return this.permissions.hasRole(Permissions.ROLE_SMS_READ); * }; * ``` * * @param roleId - The ID of the role to check against the current user's roles. * @returns A boolean value indicating whether the current user has the specified role. * @throws Error if no user is currently logged in. * */ hasRole(roleId) { const currentUser = this.appState.currentUser.value; if (!currentUser) { throw new Error('Roles can only be requested if the user is logged in.'); } return this.user.hasRole(currentUser, roleId); } /** * Checks if the current user possesses all the specified roles. * * ```ts * hasMOReadAndBinaryReadRoles(): boolean { * return this.permissions.hasAllRoles([ * Permissions.ROLE_MANAGED_OBJECT_READ, * Permissions.ROLE_BINARY_READ * ]); * } * ``` * * @param roleIds - An array of strings representing the role IDs to check against the current user's roles. * @returns A boolean value indicating whether the current user has all the specified roles. * @throws Error if no user is currently logged in. * */ hasAllRoles(roleIds) { const currentUser = this.appState.currentUser.value; if (!currentUser) { throw new Error('Roles can only be requested if the user is logged in.'); } return this.user.hasAllRoles(currentUser, roleIds); } /** * Checks if the current user possesses any of the specified roles. * * ```ts * hasTenantAdminOrTenantManagementAdminRoles(): boolean { * return this.permissions.hasAnyRole([ * Permissions.ROLE_TENANT_ADMIN, * Permissions.ROLE_TENANT_MANAGEMENT_ADMIN * ]); * }; * ``` * * @param roleIds - An array of strings representing the role IDs to check against the current user's roles. * @returns A boolean value indicating whether the current user has any of the specified roles. * @throws Error if no user is currently logged in. * */ hasAnyRole(roleIds) { const currentUser = this.appState.currentUser.value; if (!currentUser) { throw new Error('Roles can only be requested if the user is logged in.'); } return this.user.hasAnyRole(currentUser, roleIds); } /** * Checks if the current user possesses any of the specified global roles. * * ```ts * hasAnyGlobalRoles(dashboard: ContextDashboardManagedObject): boolean { * const globalRolesIds = dashboard?.c8y_Dashboard?.globalRolesIds; * return this.permissions.hasAnyGlobalRole(globalRolesIds); * } * ``` * * @param globalRolesIds - An array of numbers representing the global role IDs to check against the current user's roles. * @returns A boolean value indicating whether the current user has any of the specified global roles. * @throws Error if no user is currently logged in. * */ hasAnyGlobalRole(globalRolesIds) { const currentUser = this.appState.currentUser.value; if (!currentUser) { throw new Error('Global roles can only be requested if the user is logged in.'); } return this.user.hasAnyGlobalRole(currentUser, globalRolesIds); } /** * Checks if the current user is the owner of the managed object. * Utilizes memoization to cache the result based on the managed object's id, * improving performance for subsequent checks of the same object. * * ```ts * const managedObject = { id: '123', owner: 'johnDoe' }; * this.checkIfOwner(managedObject).then(isOwner => { * console.log(isOwner); * }); * ``` * * @param mo - The managed object to check ownership against. * @returns A promise that resolves to `true` if the current user is the owner of the managed object, and `false` otherwise. * */ async checkIfOwner(mo) { const currentUserName = await this.appState.currentUser.value.userName; const { data } = await this.inventory.detail(mo.id); return currentUserName === data.owner; } /** * Attempts to perform a partial update on a managed object as a means to check for edit permissions. * Utilizes memoization to cache the result based on the managed object's id, * thereby avoiding unnecessary repeated requests for the same object. * * This method essentially tests if the current user has permission to update the managed object, * serving as an indirect permission check. * * ```ts * const managedObject = { id: '456' }; * this.checkWithRequest(managedObject).then(hasPermission => { * console.log(hasPermission); * }).catch(error => { * console.error(error); * }); * ``` * * @param mo - The managed object to test edit permissions on. * @returns A promise that resolves to `true` if the update request succeeds (indicating edit permissions), and `false` if it fails. * */ async checkWithRequest(mo) { const moId = mo.id.toString(); const partialUpdateObject = { id: moId }; return this.inventory .update(partialUpdateObject) .then(() => { return true; }) .catch(() => { return false; }); } /** * Checks if the current user has the necessary permissions to edit a managed object. * This method considers various conditions to determine editability, including role checks, * ownership, and custom request-based checks. Each of these checks can be optionally skipped * based on the provided configuration. * * @param roleIds - An array of role IDs to check against the current user's roles. * @param mo - The managed object or an identified resource to check edit permissions for. * @param config - Configuration options to customize the checks performed. This includes options to skip role checks, owner checks, or custom request checks. * @returns A promise that resolves to `true` if the current user can edit the managed object based on the given conditions, and `false` otherwise. * */ async checkIfCanEdit(roleIds, mo, config) { if (!config?.skipRolesCheck && (await this.hasAnyRole(roleIds))) { return true; } else if (!config?.skipOwnerCheck && (await this.checkIfOwner(mo))) { return true; } else if (!config?.skipRequestCheck && (await this.checkWithRequest(mo))) { return true; } return false; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: Permissions, deps: [{ token: i1.AppStateService }, { token: i2.InventoryService }, { token: i2.UserService }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: Permissions, providedIn: 'root' }); } } __decorate([ memoize(property('id')), __metadata("design:type", Function), __metadata("design:paramtypes", [Object]), __metadata("design:returntype", Promise) ], Permissions.prototype, "checkIfOwner", null); __decorate([ memoize(property('id')), __metadata("design:type", Function), __metadata("design:paramtypes", [Object]), __metadata("design:returntype", Promise) ], Permissions.prototype, "checkWithRequest", null); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: Permissions, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [{ type: i1.AppStateService }, { type: i2.InventoryService }, { type: i2.UserService }], propDecorators: { checkIfOwner: [], checkWithRequest: [] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGVybWlzc2lvbnMuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2NvcmUvY29tbW9uL3Blcm1pc3Npb25zLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0MsT0FBTyxFQUErQixnQkFBZ0IsRUFBRSxXQUFXLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDekYsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNyQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDOUMsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLG9CQUFvQixDQUFDOzs7O0FBa0JyRCxNQUFNLE9BQU8sV0FBVzthQUNmLGlDQUE0QixHQUFHLDhCQUE4QixBQUFqQyxDQUFrQzthQUM5RCxnQ0FBMkIsR0FBRyw2QkFBNkIsQUFBaEMsQ0FBaUM7YUFDNUQscUJBQWdCLEdBQUcsa0JBQWtCLEFBQXJCLENBQXNCO2FBQ3RDLG9CQUFlLEdBQUcsaUJBQWlCLEFBQXBCLENBQXFCO2FBQ3BDLCtCQUEwQixHQUFHLDRCQUE0QixBQUEvQixDQUFnQzthQUMxRCxzQ0FBaUMsR0FBRyxtQ0FBbUMsQUFBdEMsQ0FBdUM7YUFDeEUscUNBQWdDLEdBQUcsa0NBQWtDLEFBQXJDLENBQXNDO2FBQ3RFLHFCQUFnQixHQUFHLGtCQUFrQixBQUFyQixDQUFzQjthQUN0QyxvQkFBZSxHQUFHLGlCQUFpQixBQUFwQixDQUFxQjthQUNwQyxzQkFBaUIsR0FBRyxtQkFBbUIsQUFBdEIsQ0FBdUI7YUFDeEMsdUJBQWtCLEdBQUcsb0JBQW9CLEFBQXZCLENBQXdCO2FBQzFDLHFCQUFnQixHQUFHLGtCQUFrQixBQUFyQixDQUFzQjthQUN0Qyw4QkFBeUIsR0FBRywyQkFBMkIsQUFBOUIsQ0FBK0I7YUFDeEQsNkJBQXdCLEdBQUcsMEJBQTBCLEFBQTdC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QUNmLENBQUM7K0dBL1JVLFdBQVc7bUhBQVgsV0FBVyxjQURFLE1BQU07O0FBNE5kO0lBRGYsT0FBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQzs7OzsrQ0FLdkI7QUF3QmU7SUFEZixPQUFPLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDOzs7O21EQWN2Qjs0RkFwUVUsV0FBVztrQkFEdkIsVUFBVTttQkFBQyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUU7NklBNE5oQixZQUFZLE1BNEJaLGdCQUFnQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IElJZGVudGlmaWVkLCBJTWFuYWdlZE9iamVjdCwgSW52ZW50b3J5U2VydmljZSwgVXNlclNlcnZpY2UgfSBmcm9tICdAYzh5L2NsaWVudCc7XG5pbXBvcnQgeyBwcm9wZXJ0eSB9IGZyb20gJ2xvZGFzaC1lcyc7XG5pbXBvcnQgeyBtZW1vaXplIH0gZnJvbSAnLi9tZW1vaXplLmRlY29yYXRvcic7XG5pbXBvcnQgeyBBcHBTdGF0ZVNlcnZpY2UgfSBmcm9tICcuL3VpLXN0YXRlLnNlcnZpY2UnO1xuXG5leHBvcnQgdHlwZSBDYW5FZGl0Q29uZmlnID0ge1xuICAvKipcbiAgICogU2tpcHMgcm9sZXMgY2hlY2suXG4gICAqL1xuICBza2lwUm9sZXNDaGVjaz86IGJvb2xlYW47XG4gIC8qKlxuICAgKiBTa2lwcyBtYW5hZ2VkIG9iamVjdCBvd25lcnNoaXAgY2hlY2suXG4gICAqL1xuICBza2lwT3duZXJDaGVjaz86IGJvb2xlYW47XG4gIC8qKlxuICAgKiBTa2lwcyBjaGVja3Mgd2l0aCBhIHF1ZXJ5IHRvIHRoZSBpbnZlbnRvcnkgQVBJLlxuICAgKi9cbiAgc2tpcFJlcXVlc3RDaGVjaz86IGJvb2xlYW47XG59O1xuXG5ASW5qZWN0YWJsZSh7IHByb3ZpZGVkSW46ICdyb290JyB9KVxuZXhwb3J0IGNsYXNzIFBlcm1pc3Npb25zIHtcbiAgc3RhdGljIFJPTEVfQURWQU5DRURfU09GVFdBUkVfQURNSU4gPSAnUk9MRV9BRFZBTkNFRF9TT0ZUV0FSRV9BRE1JTic7XG4gIHN0YXRpYyBST0xFX0FEVkFOQ0VEX1NPRlRXQVJFX1JFQUQgPSAnUk9MRV9BRFZBTkNFRF9TT0ZUV0FSRV9SRUFEJztcbiAgc3RhdGljIFJPTEVfQUxBUk1fQURNSU4gPSAnUk9MRV9BTEFSTV9BRE1JTic7XG4gIHN0YXRpYyBST0xFX0FMQVJNX1JFQUQgPSAnUk9MRV9BTEFSTV9SRUFEJztcbiAgc3RhdGljIFJPTEVfQU5BTFlUSUNTQlVJTERFUl9SRUFEID0gJ1JPTEVfQU5BTFlUSUNTQlVJTERFUl9SRUFEJztcbiAgc3RhdGljIFJPTEVfQVBQTElDQVRJT05fTUFOQUdFTUVOVF9BRE1JTiA9ICdST0xFX0FQUExJQ0FUSU9OX01BTkFHRU1FTlRfQURNSU4nO1xuICBzdGF0aWMgUk9MRV9BUFBMSUNBVElPTl9NQU5BR0VNRU5UX1JFQUQgPSAnUk9MRV9BUFBMSUNBVElPTl9NQU5BR0VNRU5UX1JFQUQnO1xuICBzdGF0aWMgUk9MRV9BVURJVF9BRE1JTiA9ICdST0xFX0FVRElUX0FETUlOJztcbiAgc3RhdGljIFJPTEVfQVVESVRfUkVBRCA9ICdST0xFX0FVRElUX1JFQUQnO1xuICBzdGF0aWMgUk9MRV9CSU5BUllfQURNSU4gPSAnUk9MRV9CSU5BUllfQURNSU4nO1xuICBzdGF0aWMgUk9MRV9CSU5BUllfQ1JFQVRFID0gJ1JPTEVfQklOQVJZX0NSRUFURSc7XG4gIHN0YXRpYyBST0xFX0JJTkFSWV9SRUFEID0gJ1JPTEVfQklOQVJZX1JFQUQnO1xuICBzdGF0aWMgUk9MRV9CVUxLX09QRVJBVElPTl9BRE1JTiA9ICdST0xFX0JVTEtfT1BFUkFUSU9OX0FETUlOJztcbiAgc3RhdGljIFJPTEVfQlVMS19PUEVSQVRJT05fUkVBRCA9ICdST0xFX0JVTEtfT1BFUkFUSU9OX1JFQUQnO1xuICBzdGF0aWMgUk9MRV9DRVBfTUFOQUdFTUVOVF9BRE1JTiA9ICdST0xFX0NFUF9NQU5BR0VNRU5UX0FETUlOJztcbiAgc3RhdGljIFJPTEVfQ0VQX01BTkFHRU1FTlRfUkVBRCA9ICdST0xFX0NFUF9NQU5BR0VNRU5UX1JFQUQnO1xuICBzdGF0aWMgUk9MRV9EQVRBX0JST0tFUl9BRE1JTiA9ICdST0xFX0RBVEFfQlJPS0VSX0FETUlOJztcbiAgc3RhdGljIFJPTEVfREFUQV9CUk9LRVJfUkVBRCA9ICdST0xFX0RBVEFfQlJPS0VSX1JFQUQnO1xuICBzdGF0aWMgUk9MRV9ERVZJQ0VfQ09OVFJPTF9BRE1JTiA9ICdST0xFX0RFVklDRV9DT05UUk9MX0FETUlOJztcbiAgc3RhdGljIFJPTEVfREVWSUNFX0NPTlRST0xfUkVBRCA9ICdST0xFX0RFVklDRV9DT05UUk9MX1JFQUQnO1xuICBzdGF0aWMgUk9MRV9FTUFJTF9DUkVBVEUgPSAnUk9MRV9FTUFJTF9DUkVBVEUnO1xuICBzdGF0aWMgUk9MRV9FUExBUFBTX1JFQUQgPSAnUk9MRV9FUExBUFBTX1JFQUQnO1xuICBzdGF0aWMgUk9MRV9FVkVOVF9BRE1JTiA9ICdST0xFX0VWRU5UX0FETUlOJztcbiAgc3RhdGljIFJPTEVfRVZFTlRfUkVBRCA9ICdST0xFX0VWRU5UX1JFQUQnO1xuICBzdGF0aWMgUk9MRV9HRU5FUklDX01RVFRfQURNSU4gPSAnUk9MRV9HRU5FUklDX01RVFRfQURNSU4nO1xuICBzdGF0aWMgUk9MRV9JREVOVElUWV9BRE1JTiA9ICdST0xFX0lERU5USVRZX0FETUlOJztcbiAgc3RhdGljIFJPTEVfSURFTlRJVFlfUkVBRCA9ICdST0xFX0lERU5USVRZX1JFQUQnO1xuICBzdGF0aWMgUk9MRV9JTlZFTlRPUllfQURNSU4gPSAnUk9MRV9JTlZFTlRPUllfQURNSU4nO1xuICBzdGF0aWMgUk9MRV9JTlZFTlRPUllfQ1JFQVRFID0gJ1JPTEVfSU5WRU5UT1JZX0NSRUFURSc7XG4gIHN0YXRpYyBST0xFX0lOVkVOVE9SWV9SRUFEID0gJ1JPTEVfSU5WRU5UT1JZX1JFQUQnO1xuICBzdGF0aWMgUk9MRV9NQUNISU5FX0xFQVJOSU5HX1JFQUQgPSAnUk9MRV9NQUNISU5FX0xFQVJOSU5HX1JFQUQnO1xuICBzdGF0aWMgUk9MRV9NQU5BR0VEX09CSkVDVF9BRE1JTiA9ICdST0xFX01BTkFHRURfT0JKRUNUX0FETUlOJztcbiAgc3RhdGljIFJPTEVfTUFOQUdFRF9PQkpFQ1RfQ1JFQVRFID0gJ1JPTEVfTUFOQUdFRF9PQkpFQ1RfQ1JFQVRFJztcbiAgc3RhdGljIFJPTEVfTUFOQUdFRF9PQkpFQ1RfUkVBRCA9ICdST0xFX01BTkFHRURfT0JKRUNUX1JFQUQnO1xuICBzdGF0aWMgUk9MRV9NRUFTVVJFTUVOVF9BRE1JTiA9ICdST0xFX01FQVNVUkVNRU5UX0FETUlOJztcbiAgc3RhdGljIFJPTEVfTUVBU1VSRU1FTlRfUkVBRCA9ICdST0xFX01FQVNVUkVNRU5UX1JFQUQnO1xuICBzdGF0aWMgUk9MRV9NUVRUX0NPTk5FQ1RfQURNSU4gPSAnUk9MRV9NUVRUX0NPTk5FQ1RfQURNSU4nO1xuICBzdGF0aWMgUk9MRV9NUVRUX1NFUlZJQ0VfQURNSU4gPSAnUk9MRV9NUVRUX1NFUlZJQ0VfQURNSU4nO1xuICBzdGF0aWMgUk9MRV9OT1RJRklDQVRJT05fMl9BRE1JTiA9ICdST0xFX05PVElGSUNBVElPTl8yX0FETUlOJztcbiAgc3RhdGljIFJPTEVfT1BUSU9OX01BTkFHRU1FTlRfQURNSU4gPSAnUk9MRV9PUFRJT05fTUFOQUdFTUVOVF9BRE1JTic7XG4gIHN0YXRpYyBST0xFX09QVElPTl9NQU5BR0VNRU5UX1JFQUQgPSAnUk9MRV9PUFRJT05fTUFOQUdFTUVOVF9SRUFEJztcbiAgc3RhdGljIFJPTEVfUFJPVklTSU9OSU5HX0NSRUFURSA9ICdST0xFX1BST1ZJU0lPTklOR19DUkVBVEUnO1xuICBzdGF0aWMgUk9MRV9QUk9WSVNJT05JTkdfUkVBRCA9ICdST0xFX1BST1ZJU0lPTklOR19SRUFEJztcbiAgc3RhdGljIFJPTEVfUFJPVklTSU9OSU5HX1VQREFURSA9ICdST0xFX1BST1ZJU0lPTklOR19VUERBVEUnO1xuICBzdGF0aWMgUk9MRV9SRU1PVEVfQUNDRVNTX0FETUlOID0gJ1JPTEVfUkVNT1RFX0FDQ0VTU19BRE1JTic7XG4gIHN0YXRpYyBST0xFX1JFVEVOVElPTl9SVUxFX0FETUlOID0gJ1JPTEVfUkVURU5USU9OX1JVTEVfQURNSU4nO1xuICBzdGF0aWMgUk9MRV9SRVRFTlRJT05fUlVMRV9SRUFEID0gJ1JPTEVfUkVURU5USU9OX1JVTEVfUkVBRCc7XG4gIHN0YXRpYyBST0xFX1NDSEVEVUxFX1JFUE9SVF9BRE1JTiA9ICdST0xFX1NDSEVEVUxFX1JFUE9SVF9BRE1JTic7XG4gIHN0YXRpYyBST0xFX1NJTVVMQVRPUl9BRE1JTiA9ICdST0xFX1NJTVVMQVRPUl9BRE1JTic7XG4gIHN0YXRpYyBST0xFX1NNQVJUR1JPVVBfQURNSU4gPSAnUk9MRV9TTUFSVEdST1VQX0FETUlOJztcbiAgc3RhdGljIFJPTEVfU01BUlRHUk9VUF9DUkVBVEUgPSAnUk9MRV9TTUFSVEdST1VQX0NSRUFURSc7XG4gIHN0YXRpYyBST0xFX1NNQVJUR1JPVVBfVVBEQVRFID0gJ1JPTEVfU01BUlRHUk9VUF9VUERBVEUnO1xuICBzdGF0aWMgUk9MRV9TTUFSVFJVTEVfQURNSU4gPSAnUk9MRV9TTUFSVFJVTEVfQURNSU4nO1xuICBzdGF0aWMgUk9MRV9TTUFSVFJVTEVfUkVBRCA9ICdST0xFX1NNQVJUUlVMRV9SRUFEJztcbiAgc3RhdGljIFJPTEVfU01TX0FETUlOID0gJ1JPTEVfU01TX0FETUlOJztcbiAgc3RhdGljIFJPTEVfU01TX1JFQUQgPSAnUk9MRV9TTVNfUkVBRCc7XG4gIHN0YXRpYyBST0xFX1RFTkFOVF9BRE1JTiA9ICdST0xFX1RFTkFOVF9BRE1JTic7XG4gIHN0YXRpYyBST0xFX1RFTkFOVF9NQU5BR0VNRU5UX0FETUlOID0gJ1JPTEVfVEVOQU5UX01BTkFHRU1FTlRfQURNSU4nO1xuICBzdGF0aWMgUk9MRV9URU5BTlRfTUFOQUdFTUVOVF9DUkVBVEUgPSAnUk9MRV9URU5BTlRfTUFOQUdFTUVOVF9DUkVBVEUnO1xuICBzdGF0aWMgUk9MRV9URU5BTlRfTUFOQUdFTUVOVF9SRUFEID0gJ1JPTEVfVEVOQU5UX01BTkFHRU1FTlRfUkVBRCc7XG4gIHN0YXRpYyBST0xFX1RFTkFOVF9NQU5BR0VNRU5UX1VQREFURSA9ICdST0xFX1RFTkFOVF9NQU5BR0VNRU5UX1VQREFURSc7XG4gIHN0YXRpYyBST0xFX1RFTkFOVF9TVEFUSVNUSUNTX1JFQUQgPSAnUk9MRV9URU5BTlRfU1RBVElTVElDU19SRUFEJztcbiAgc3RhdGljIFJPTEVfVVNFUl9NQU5BR0VNRU5UX0FETUlOID0gJ1JPTEVfVVNFUl9NQU5BR0VNRU5UX0FETUlOJztcbiAgc3RhdGljIFJPTEVfVVNFUl9NQU5BR0VNRU5UX0NSRUFURSA9ICdST0xFX1VTRVJfTUFOQUdFTUVOVF9DUkVBVEUnO1xuICBzdGF0aWMgUk9MRV9VU0VSX01BTkFHRU1FTlRfT1dOX0FETUlOID0gJ1JPTEVfVVNFUl9NQU5BR0VNRU5UX09XTl9BRE1JTic7XG4gIHN0YXRpYyBST0xFX1VTRVJfTUFOQUdFTUVOVF9PV05fUkVBRCA9ICdST0xFX1VTRVJfTUFOQUdFTUVOVF9PV05fUkVBRCc7XG4gIHN0YXRpYyBST0xFX1VTRVJfTUFOQUdFTUVOVF9SRUFEID0gJ1JPTEVfVVNFUl9NQU5BR0VNRU5UX1JFQUQnO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgYXBwU3RhdGU6IEFwcFN0YXRlU2VydmljZSxcbiAgICBwcml2YXRlIGludmVudG9yeTogSW52ZW50b3J5U2VydmljZSxcbiAgICBwcml2YXRlIHVzZXI6IFVzZXJTZXJ2aWNlXG4gICkge31cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIHRoZSBjdXJyZW50IHVzZXIgaGFzIHdyaXRlIHBlcm1pc3Npb25zIGZvciB0aGUgZ2l2ZW4gbW9cbiAgICogKGVpdGhlciB0aHJvdWdoIGdsb2JhbCByb2xlLCBpbmRpdmlkdWFsIGRldmljZSBwZXJtaXNzaW9ucyBvciB2aWEgaW52ZW50b3J5IHJvbGVzKS5cbiAgICpcbiAgICogYGBgdHNcbiAgICogYXN5bmMgY2FuRWRpdEdyb3VwKGdyb3VwOiBJTWFuYWdlZE9iamVjdCk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgKiAgIHJldHVybiBhd2FpdCB0aGlzLnBlcm1pc3Npb25zLmNhbkVkaXQoXG4gICAqICAgICBbUGVybWlzc2lvbnMuUk9MRV9JTlZFTlRPUllfQURNSU4sIFBlcm1pc3Npb25zLlJPTEVfTUFOQUdFRF9PQkpFQ1RfQURNSU5dLFxuICAgKiAgICAgZ3JvdXBcbiAgICogICApO1xuICAgKiB9XG4gICAqIGBgYFxuICAgKlxuICAgKiBAcGFyYW0gcm9sZUlkcyAtIFRoZSBhcnJheSBvZiByb2xlIGlkcyB0byBjaGVjayBpZiB0aGUgY3VycmVudCB1c2VyIGhhdmUgYXQgbGVhc3Qgb25lIG9mIHRoZW0uXG4gICAqIEBwYXJhbSBtbyAtIFRoZSBtYW5hZ2VkIG9iamVjdCBmb3Igd2hpY2ggd2UgYXJlIGNoZWNraW5nIHdoZXRoZXIgdGhlIHVzZXIgaGFzIGFjY2Vzcy5cbiAgICogQHBhcmFtIGNvbmZpZyAtIEEgY29uZmlndXJhdGlvbiBvYmplY3QgdGhhdCBjYW4gdGFrZSB0aGUgZm9sbG93aW5nIHZhbHVlczogYHNraXBSb2xlc0NoZWNrYDogYGJvb2xlYW5gIC0gc2tpcHMgcm9sZXMgY2hlY2ssIGBza2lwT3duZXJDaGVja2A6IGBib29sZWFuYCAtIHNraXBzIG93bmVyc2hpcCBjaGVjaywgYHNraXBSZXF1ZXN0Q2hlY2tgOiBgYm9vbGVhbmAgLSBza2lwcyBjaGVja3Mgd2l0aCBhIHF1ZXJ5IHRvIHRoZSBpbnZlbnRvcnkgQVBJLiBVSSB3aWxsIG1ha2UgYSBxdWVyeSB0byBiYWNrZW5kIHdoZXRoZXIgdGhlIHVzZXIgY2FuIGVkaXQgdGhlIG1hbmFnZWQgb2JqZWN0LiBBIHJlamVjdGlvbiBmcm9tIEJFIGluZGljYXRlcyBhIGxhY2sgb2YgcGVybWlzc2lvbi5cbiAgICpcbiAgICogQHJldHVybnMgQSBQcm9taXNlIHJlc29sdmluZyB0byBhIGJvb2xlYW4gdmFsdWUuIGB0cnVlYCBpZiBlZGl0aW5nIGlzIHBlcm1pdHRlZCBiYXNlZCBvbiB0aGUgZ2l2ZW4gcGFyYW1ldGVycyBhbmQgY29uZmlndXJhdGlvbjsgb3RoZXJ3aXNlLCBgZmFsc2VgLlxuICAgKlxuICAgKi9cbiAgY2FuRWRpdChcbiAgICByb2xlSWRzOiBzdHJpbmdbXSxcbiAgICBtbzogSU1hbmFnZWRPYmplY3QgfCBJSWRlbnRpZmllZCxcbiAgICBjb25maWc6IENhbkVkaXRDb25maWcgPSB7XG4gICAgICBza2lwUm9sZXNDaGVjazogZmFsc2UsXG4gICAgICBza2lwT3duZXJDaGVjazogZmFsc2UsXG4gICAgICBza2lwUmVxdWVzdENoZWNrOiBmYWxzZVxuICAgIH1cbiAgKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgcmV0dXJuIHRoaXMuY2hlY2tJZkNhbkVkaXQocm9sZUlkcywgbW8sIGNvbmZpZyk7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIHRoZSBjdXJyZW50IHVzZXIgaGFzIHRoZSBzcGVjaWZpZWQgcm9sZS5cbiAgICpcbiAgICogYGBgdHNcbiAgICogaGFzU21zUmVhZFJvbGUoKTogYm9vbGVhbiB7XG4gICAqICByZXR1cm4gdGhpcy5wZXJtaXNzaW9ucy5oYXNSb2xlKFBlcm1pc3Npb25zLlJPTEVfU01TX1JFQUQpO1xuICAgKiB9O1xuICAgKiBgYGBcbiAgICpcbiAgICogQHBhcmFtIHJvbGVJZCAtIFRoZSBJRCBvZiB0aGUgcm9sZSB0byBjaGVjayBhZ2FpbnN0IHRoZSBjdXJyZW50IHVzZXIncyByb2xlcy5cbiAgICogQHJldHVybnMgQSBib29sZWFuIHZhbHVlIGluZGljYXRpbmcgd2hldGhlciB0aGUgY3VycmVudCB1c2VyIGhhcyB0aGUgc3BlY2lmaWVkIHJvbGUuXG4gICAqIEB0aHJvd3MgRXJyb3IgaWYgbm8gdXNlciBpcyBjdXJyZW50bHkgbG9nZ2VkIGluLlxuICAgKlxuICAgKi9cbiAgaGFzUm9sZShyb2xlSWQ6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IGN1cnJlbnRVc2VyID0gdGhpcy5hcHBTdGF0ZS5jdXJyZW50VXNlci52YWx1ZTtcbiAgICBpZiAoIWN1cnJlbnRVc2VyKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1JvbGVzIGNhbiBvbmx5IGJlIHJlcXVlc3RlZCBpZiB0aGUgdXNlciBpcyBsb2dnZWQgaW4uJyk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLnVzZXIuaGFzUm9sZShjdXJyZW50VXNlciwgcm9sZUlkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVja3MgaWYgdGhlIGN1cnJlbnQgdXNlciBwb3NzZXNzZXMgYWxsIHRoZSBzcGVjaWZpZWQgcm9sZXMuXG4gICAqXG4gICAqIGBgYHRzXG4gICAqIGhhc01PUmVhZEFuZEJpbmFyeVJlYWRSb2xlcygpOiBib29sZWFuIHtcbiAgICogICByZXR1cm4gdGhpcy5wZXJtaXNzaW9ucy5oYXNBbGxSb2xlcyhbXG4gICAqICAgICBQZXJtaXNzaW9ucy5ST0xFX01BTkFHRURfT0JKRUNUX1JFQUQsXG4gICAqICAgICBQZXJtaXNzaW9ucy5ST0xFX0JJTkFSWV9SRUFEXG4gICAqICAgXSk7XG4gICAqIH1cbiAgICogYGBgXG4gICAqXG4gICAqIEBwYXJhbSByb2xlSWRzIC0gQW4gYXJyYXkgb2Ygc3RyaW5ncyByZXByZXNlbnRpbmcgdGhlIHJvbGUgSURzIHRvIGNoZWNrIGFnYWluc3QgdGhlIGN1cnJlbnQgdXNlcidzIHJvbGVzLlxuICAgKiBAcmV0dXJucyBBIGJvb2xlYW4gdmFsdWUgaW5kaWNhdGluZyB3aGV0aGVyIHRoZSBjdXJyZW50IHVzZXIgaGFzIGFsbCB0aGUgc3BlY2lmaWVkIHJvbGVzLlxuICAgKiBAdGhyb3dzIEVycm9yIGlmIG5vIHVzZXIgaXMgY3VycmVudGx5IGxvZ2dlZCBpbi5cbiAgICpcbiAgICovXG4gIGhhc0FsbFJvbGVzKHJvbGVJZHM6IHN0cmluZ1tdKTogYm9vbGVhbiB7XG4gICAgY29uc3QgY3VycmVudFVzZXIgPSB0aGlzLmFwcFN0YXRlLmN1cnJlbnRVc2VyLnZhbHVlO1xuICAgIGlmICghY3VycmVudFVzZXIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignUm9sZXMgY2FuIG9ubHkgYmUgcmVxdWVzdGVkIGlmIHRoZSB1c2VyIGlzIGxvZ2dlZCBpbi4nKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMudXNlci5oYXNBbGxSb2xlcyhjdXJyZW50VXNlciwgcm9sZUlkcyk7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIHRoZSBjdXJyZW50IHVzZXIgcG9zc2Vzc2VzIGFueSBvZiB0aGUgc3BlY2lmaWVkIHJvbGVzLlxuICAgKlxuICAgKiBgYGB0c1xuICAgKiBoYXNUZW5hbnRBZG1pbk9yVGVuYW50TWFuYWdlbWVudEFkbWluUm9sZXMoKTogYm9vbGVhbiB7XG4gICAqICByZXR1cm4gdGhpcy5wZXJtaXNzaW9ucy5oYXNBbnlSb2xlKFtcbiAgICogICAgUGVybWlzc2lvbnMuUk9MRV9URU5BTlRfQURNSU4sXG4gICAqICAgIFBlcm1pc3Npb25zLlJPTEVfVEVOQU5UX01BTkFHRU1FTlRfQURNSU5cbiAgICogIF0pO1xuICAgKiB9O1xuICAgKiBgYGBcbiAgICpcbiAgICogQHBhcmFtIHJvbGVJZHMgLSBBbiBhcnJheSBvZiBzdHJpbmdzIHJlcHJlc2VudGluZyB0aGUgcm9sZSBJRHMgdG8gY2hlY2sgYWdhaW5zdCB0aGUgY3VycmVudCB1c2VyJ3Mgcm9sZXMuXG4gICAqIEByZXR1cm5zIEEgYm9vbGVhbiB2YWx1ZSBpbmRpY2F0aW5nIHdoZXRoZXIgdGhlIGN1cnJlbnQgdXNlciBoYXMgYW55IG9mIHRoZSBzcGVjaWZpZWQgcm9sZXMuXG4gICAqIEB0aHJvd3MgRXJyb3IgaWYgbm8gdXNlciBpcyBjdXJyZW50bHkgbG9nZ2VkIGluLlxuICAgKlxuICAgKi9cbiAgaGFzQW55Um9sZShyb2xlSWRzOiBzdHJpbmdbXSk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IGN1cnJlbnRVc2VyID0gdGhpcy5hcHBTdGF0ZS5jdXJyZW50VXNlci52YWx1ZTtcbiAgICBpZiAoIWN1cnJlbnRVc2VyKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1JvbGVzIGNhbiBvbmx5IGJlIHJlcXVlc3RlZCBpZiB0aGUgdXNlciBpcyBsb2dnZWQgaW4uJyk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLnVzZXIuaGFzQW55Um9sZShjdXJyZW50VXNlciwgcm9sZUlkcyk7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIHRoZSBjdXJyZW50IHVzZXIgcG9zc2Vzc2VzIGFueSBvZiB0aGUgc3BlY2lmaWVkIGdsb2JhbCByb2xlcy5cbiAgICpcbiAgICogYGBgdHNcbiAgICogaGFzQW55R2xvYmFsUm9sZXMoZGFzaGJvYXJkOiBDb250ZXh0RGFzaGJvYXJkTWFuYWdlZE9iamVjdCk6IGJvb2xlYW4ge1xuICAgKiAgIGNvbnN0IGdsb2JhbFJvbGVzSWRzID0gZGFzaGJvYXJkPy5jOHlfRGFzaGJvYXJkPy5nbG9iYWxSb2xlc0lkcztcbiAgICogICByZXR1cm4gdGhpcy5wZXJtaXNzaW9ucy5oYXNBbnlHbG9iYWxSb2xlKGdsb2JhbFJvbGVzSWRzKTtcbiAgICogfVxuICAgKiBgYGBcbiAgICpcbiAgICogQHBhcmFtIGdsb2JhbFJvbGVzSWRzIC0gQW4gYXJyYXkgb2YgbnVtYmVycyByZXByZXNlbnRpbmcgdGhlIGdsb2JhbCByb2xlIElEcyB0byBjaGVjayBhZ2FpbnN0IHRoZSBjdXJyZW50IHVzZXIncyByb2xlcy5cbiAgICogQHJldHVybnMgQSBib29sZWFuIHZhbHVlIGluZGljYXRpbmcgd2hldGhlciB0aGUgY3VycmVudCB1c2VyIGhhcyBhbnkgb2YgdGhlIHNwZWNpZmllZCBnbG9iYWwgcm9sZXMuXG4gICAqIEB0aHJvd3MgRXJyb3IgaWYgbm8gdXNlciBpcyBjdXJyZW50bHkgbG9nZ2VkIGluLlxuICAgKlxuICAgKi9cbiAgaGFzQW55R2xvYmFsUm9sZShnbG9iYWxSb2xlc0lkczogbnVtYmVyW10pOiBib29sZWFuIHtcbiAgICBjb25zdCBjdXJyZW50VXNlciA9IHRoaXMuYXBwU3RhdGUuY3VycmVudFVzZXIudmFsdWU7XG4gICAgaWYgKCFjdXJyZW50VXNlcikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdHbG9iYWwgcm9sZXMgY2FuIG9ubHkgYmUgcmVxdWVzdGVkIGlmIHRoZSB1c2VyIGlzIGxvZ2dlZCBpbi4nKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMudXNlci5oYXNBbnlHbG9iYWxSb2xlKGN1cnJlbnRVc2VyLCBnbG9iYWxSb2xlc0lkcyk7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIHRoZSBjdXJyZW50IHVzZXIgaXMgdGhlIG93bmVyIG9mIHRoZSBtYW5hZ2VkIG9iamVjdC5cbiAgICogVXRpbGl6ZXMgbWVtb2l6YXRpb24gdG8gY2FjaGUgdGhlIHJlc3VsdCBiYXNlZCBvbiB0aGUgbWFuYWdlZCBvYmplY3QncyBpZCxcbiAgICogaW1wcm92aW5nIHBlcmZvcm1hbmNlIGZvciBzdWJzZXF1ZW50IGNoZWNrcyBvZiB0aGUgc2FtZSBvYmplY3QuXG4gICAqXG4gICAqIGBgYHRzXG4gICAqIGNvbnN0IG1hbmFnZWRPYmplY3QgPSB7IGlkOiAnMTIzJywgb3duZXI6ICdqb2huRG9lJyB9O1xuICAgKiB0aGlzLmNoZWNrSWZPd25lcihtYW5hZ2VkT2JqZWN0KS50aGVuKGlzT3duZXIgPT4ge1xuICAgKiAgIGNvbnNvbGUubG9nKGlzT3duZXIpO1xuICAgKiB9KTtcbiAgICogYGBgXG4gICAqXG4gICAqIEBwYXJhbSBtbyAtIFRoZSBtYW5hZ2VkIG9iamVjdCB0byBjaGVjayBvd25lcnNoaXAgYWdhaW5zdC5cbiAgICogQHJldHVybnMgQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYHRydWVgIGlmIHRoZSBjdXJyZW50IHVzZXIgaXMgdGhlIG93bmVyIG9mIHRoZSBtYW5hZ2VkIG9iamVjdCwgYW5kIGBmYWxzZWAgb3RoZXJ3aXNlLlxuICAgKlxuICAgKi9cbiAgQG1lbW9pemUocHJvcGVydHkoJ2lkJykpXG4gIHByb3RlY3RlZCBhc3luYyBjaGVja0lmT3duZXIobW86IElNYW5hZ2VkT2JqZWN0IHwgSUlkZW50aWZpZWQpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBjb25zdCBjdXJyZW50VXNlck5hbWUgPSBhd2FpdCB0aGlzLmFwcFN0YXRlLmN1cnJlbnRVc2VyLnZhbHVlLnVzZXJOYW1lO1xuICAgIGNvbnN0IHsgZGF0YSB9ID0gYXdhaXQgdGhpcy5pbnZlbnRvcnkuZGV0YWlsKG1vLmlkKTtcbiAgICByZXR1cm4gY3VycmVudFVzZXJOYW1lID09PSBkYXRhLm93bmVyO1xuICB9XG5cbiAgLyoqXG4gICAqIEF0dGVtcHRzIHRvIHBlcmZvcm0gYSBwYXJ0aWFsIHVwZGF0ZSBvbiBhIG1hbmFnZWQgb2JqZWN0IGFzIGEgbWVhbnMgdG8gY2hlY2sgZm9yIGVkaXQgcGVybWlzc2lvbnMuXG4gICAqIFV0aWxpemVzIG1lbW9pemF0aW9uIHRvIGNhY2hlIHRoZSByZXN1bHQgYmFzZWQgb24gdGhlIG1hbmFnZWQgb2JqZWN0J3MgaWQsXG4gICAqIHRoZXJlYnkgYXZvaWRpbmcgdW5uZWNlc3NhcnkgcmVwZWF0ZWQgcmVxdWVzdHMgZm9yIHRoZSBzYW1lIG9iamVjdC5cbiAgICpcbiAgICogVGhpcyBtZXRob2QgZXNzZW50aWFsbHkgdGVzdHMgaWYgdGhlIGN1cnJlbnQgdXNlciBoYXMgcGVybWlzc2lvbiB0byB1cGRhdGUgdGhlIG1hbmFnZWQgb2JqZWN0LFxuICAgKiBzZXJ2aW5nIGFzIGFuIGluZGlyZWN0IHBlcm1pc3Npb24gY2hlY2suXG4gICAqXG4gICAqIGBgYHRzXG4gICAqIGNvbnN0IG1hbmFnZWRPYmplY3QgPSB7IGlkOiAnNDU2JyB9O1xuICAgKiB0aGlzLmNoZWNrV2l0aFJlcXVlc3QobWFuYWdlZE9iamVjdCkudGhlbihoYXNQZXJtaXNzaW9uID0+IHtcbiAgICogICBjb25zb2xlLmxvZyhoYXNQZXJtaXNzaW9uKTtcbiAgICogfSkuY2F0Y2goZXJyb3IgPT4ge1xuICAgKiAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xuICAgKiB9KTtcbiAgICogYGBgXG4gICAqXG4gICAqIEBwYXJhbSBtbyAtIFRoZSBtYW5hZ2VkIG9iamVjdCB0byB0ZXN0IGVkaXQgcGVybWlzc2lvbnMgb24uXG4gICAqIEByZXR1cm5zIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGB0cnVlYCBpZiB0aGUgdXBkYXRlIHJlcXVlc3Qgc3VjY2VlZHMgKGluZGljYXRpbmcgZWRpdCBwZXJtaXNzaW9ucyksIGFuZCBgZmFsc2VgIGlmIGl0IGZhaWxzLlxuICAgKlxuICAgKi9cbiAgQG1lbW9pemUocHJvcGVydHkoJ2lkJykpXG4gIHByb3RlY3RlZCBhc3luYyBjaGVja1dpdGhSZXF1ZXN0KG1vOiBJTWFuYWdlZE9iamVjdCB8IElJZGVudGlmaWVkKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgbW9JZCA9IG1vLmlkLnRvU3RyaW5nKCk7XG4gICAgY29uc3QgcGFydGlhbFVwZGF0ZU9iamVjdDogUGFydGlhbDxJTWFuYWdlZE9iamVjdD4gPSB7XG4gICAgICBpZDogbW9JZFxuICAgIH07XG4gICAgcmV0dXJuIHRoaXMuaW52ZW50b3J5XG4gICAgICAudXBkYXRlKHBhcnRpYWxVcGRhdGVPYmplY3QpXG4gICAgICAudGhlbigoKSA9PiB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfSlcbiAgICAgIC5jYXRjaCgoKSA9PiB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyBpZiB0aGUgY3VycmVudCB1c2VyIGhhcyB0aGUgbmVjZXNzYXJ5IHBlcm1pc3Npb25zIHRvIGVkaXQgYSBtYW5hZ2VkIG9iamVjdC5cbiAgICogVGhpcyBtZXRob2QgY29uc2lkZXJzIHZhcmlvdXMgY29uZGl0aW9ucyB0byBkZXRlcm1pbmUgZWRpdGFiaWxpdHksIGluY2x1ZGluZyByb2xlIGNoZWNrcyxcbiAgICogb3duZXJzaGlwLCBhbmQgY3VzdG9tIHJlcXVlc3QtYmFzZWQgY2hlY2tzLiBFYWNoIG9mIHRoZXNlIGNoZWNrcyBjYW4gYmUgb3B0aW9uYWxseSBza2lwcGVkXG4gICAqIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLlxuICAgKlxuICAgKiBAcGFyYW0gcm9sZUlkcyAtIEFuIGFycmF5IG9mIHJvbGUgSURzIHRvIGNoZWNrIGFnYWluc3QgdGhlIGN1cnJlbnQgdXNlcidzIHJvbGVzLlxuICAgKiBAcGFyYW0gbW8gLSBUaGUgbWFuYWdlZCBvYmplY3Qgb3IgYW4gaWRlbnRpZmllZCByZXNvdXJjZSB0byBjaGVjayBlZGl0IHBlcm1pc3Npb25zIGZvci5cbiAgICogQHBhcmFtIGNvbmZpZyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyB0byBjdXN0b21pemUgdGhlIGNoZWNrcyBwZXJmb3JtZWQuIFRoaXMgaW5jbHVkZXMgb3B0aW9ucyB0byBza2lwIHJvbGUgY2hlY2tzLCBvd25lciBjaGVja3MsIG9yIGN1c3RvbSByZXF1ZXN0IGNoZWNrcy5cbiAgICogQHJldHVybnMgQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYHRydWVgIGlmIHRoZSBjdXJyZW50IHVzZXIgY2FuIGVkaXQgdGhlIG1hbmFnZWQgb2JqZWN0IGJhc2VkIG9uIHRoZSBnaXZlbiBjb25kaXRpb25zLCBhbmQgYGZhbHNlYCBvdGhlcndpc2UuXG4gICAqXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGNoZWNrSWZDYW5FZGl0KFxuICAgIHJvbGVJZHM6IHN0cmluZ1tdLFxuICAgIG1vOiBJTWFuYWdlZE9iamVjdCB8IElJZGVudGlmaWVkLFxuICAgIGNvbmZpZzogQ2FuRWRpdENvbmZpZ1xuICApOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBpZiAoIWNvbmZpZz8uc2tpcFJvbGVzQ2hlY2sgJiYgKGF3YWl0IHRoaXMuaGFzQW55Um9sZShyb2xlSWRzKSkpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gZWxzZSBpZiAoIWNvbmZpZz8uc2tpcE93bmVyQ2hlY2sgJiYgKGF3YWl0IHRoaXMuY2hlY2tJZk93bmVyKG1vKSkpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gZWxzZSBpZiAoIWNvbmZpZz8uc2tpcFJlcXVlc3RDaGVjayAmJiAoYXdhaXQgdGhpcy5jaGVja1dpdGhSZXF1ZXN0KG1vKSkpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbn1cbiJdfQ==