UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

302 lines 40.8 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_SUPPORT_ADMIN = 'ROLE_SUPPORT_ADMIN'; } static { this.ROLE_SUPPORT_READ = 'ROLE_SUPPORT_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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RSxDQUFDLENBQUMsRUFBRSxDQUFDO1lBQzFFLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUNELE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQzsrR0FqU1UsV0FBVzttSEFBWCxXQUFXLGNBREUsTUFBTTs7QUE4TmQ7SUFEZixPQUFPLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDOzs7OytDQUt2QjtBQXdCZTtJQURmLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUM7Ozs7bURBY3ZCOzRGQXRRVSxXQUFXO2tCQUR2QixVQUFVO21CQUFDLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRTs2SUE4TmhCLFlBQVksTUE0QlosZ0JBQWdCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgSUlkZW50aWZpZWQsIElNYW5hZ2VkT2JqZWN0LCBJbnZlbnRvcnlTZXJ2aWNlLCBVc2VyU2VydmljZSB9IGZyb20gJ0BjOHkvY2xpZW50JztcbmltcG9ydCB7IHByb3BlcnR5IH0gZnJvbSAnbG9kYXNoLWVzJztcbmltcG9ydCB7IG1lbW9pemUgfSBmcm9tICcuL21lbW9pemUuZGVjb3JhdG9yJztcbmltcG9ydCB7IEFwcFN0YXRlU2VydmljZSB9IGZyb20gJy4vdWktc3RhdGUuc2VydmljZSc7XG5cbmV4cG9ydCB0eXBlIENhbkVkaXRDb25maWcgPSB7XG4gIC8qKlxuICAgKiBTa2lwcyByb2xlcyBjaGVjay5cbiAgICovXG4gIHNraXBSb2xlc0NoZWNrPzogYm9vbGVhbjtcbiAgLyoqXG4gICAqIFNraXBzIG1hbmFnZWQgb2JqZWN0IG93bmVyc2hpcCBjaGVjay5cbiAgICovXG4gIHNraXBPd25lckNoZWNrPzogYm9vbGVhbjtcbiAgLyoqXG4gICAqIFNraXBzIGNoZWNrcyB3aXRoIGEgcXVlcnkgdG8gdGhlIGludmVudG9yeSBBUEkuXG4gICAqL1xuICBza2lwUmVxdWVzdENoZWNrPzogYm9vbGVhbjtcbn07XG5cbkBJbmplY3RhYmxlKHsgcHJvdmlkZWRJbjogJ3Jvb3QnIH0pXG5leHBvcnQgY2xhc3MgUGVybWlzc2lvbnMge1xuICBzdGF0aWMgUk9MRV9BRFZBTkNFRF9TT0ZUV0FSRV9BRE1JTiA9ICdST0xFX0FEVkFOQ0VEX1NPRlRXQVJFX0FETUlOJztcbiAgc3RhdGljIFJPTEVfQURWQU5DRURfU09GVFdBUkVfUkVBRCA9ICdST0xFX0FEVkFOQ0VEX1NPRlRXQVJFX1JFQUQnO1xuICBzdGF0aWMgUk9MRV9BTEFSTV9BRE1JTiA9ICdST0xFX0FMQVJNX0FETUlOJztcbiAgc3RhdGljIFJPTEVfQUxBUk1fUkVBRCA9ICdST0xFX0FMQVJNX1JFQUQnO1xuICBzdGF0aWMgUk9MRV9BTkFMWVRJQ1NCVUlMREVSX1JFQUQgPSAnUk9MRV9BTkFMWVRJQ1NCVUlMREVSX1JFQUQnO1xuICBzdGF0aWMgUk9MRV9BUFBMSUNBVElPTl9NQU5BR0VNRU5UX0FETUlOID0gJ1JPTEVfQVBQTElDQVRJT05fTUFOQUdFTUVOVF9BRE1JTic7XG4gIHN0YXRpYyBST0xFX0FQUExJQ0FUSU9OX01BTkFHRU1FTlRfUkVBRCA9ICdST0xFX0FQUExJQ0FUSU9OX01BTkFHRU1FTlRfUkVBRCc7XG4gIHN0YXRpYyBST0xFX0FVRElUX0FETUlOID0gJ1JPTEVfQVVESVRfQURNSU4nO1xuICBzdGF0aWMgUk9MRV9BVURJVF9SRUFEID0gJ1JPTEVfQVVESVRfUkVBRCc7XG4gIHN0YXRpYyBST0xFX0JJTkFSWV9BRE1JTiA9ICdST0xFX0JJTkFSWV9BRE1JTic7XG4gIHN0YXRpYyBST0xFX0JJTkFSWV9DUkVBVEUgPSAnUk9MRV9CSU5BUllfQ1JFQVRFJztcbiAgc3RhdGljIFJPTEVfQklOQVJZX1JFQUQgPSAnUk9MRV9CSU5BUllfUkVBRCc7XG4gIHN0YXRpYyBST0xFX0JVTEtfT1BFUkFUSU9OX0FETUlOID0gJ1JPTEVfQlVMS19PUEVSQVRJT05fQURNSU4nO1xuICBzdGF0aWMgUk9MRV9CVUxLX09QRVJBVElPTl9SRUFEID0gJ1JPTEVfQlVMS19PUEVSQVRJT05fUkVBRCc7XG4gIHN0YXRpYyBST0xFX0NFUF9NQU5BR0VNRU5UX0FETUlOID0gJ1JPTEVfQ0VQX01BTkFHRU1FTlRfQURNSU4nO1xuICBzdGF0aWMgUk9MRV9DRVBfTUFOQUdFTUVOVF9SRUFEID0gJ1JPTEVfQ0VQX01BTkFHRU1FTlRfUkVBRCc7XG4gIHN0YXRpYyBST0xFX0RBVEFfQlJPS0VSX0FETUlOID0gJ1JPTEVfREFUQV9CUk9LRVJfQURNSU4nO1xuICBzdGF0aWMgUk9MRV9EQVRBX0JST0tFUl9SRUFEID0gJ1JPTEVfREFUQV9CUk9LRVJfUkVBRCc7XG4gIHN0YXRpYyBST0xFX0RFVklDRV9DT05UUk9MX0FETUlOID0gJ1JPTEVfREVWSUNFX0NPTlRST0xfQURNSU4nO1xuICBzdGF0aWMgUk9MRV9ERVZJQ0VfQ09OVFJPTF9SRUFEID0gJ1JPTEVfREVWSUNFX0NPTlRST0xfUkVBRCc7XG4gIHN0YXRpYyBST0xFX0VNQUlMX0NSRUFURSA9ICdST0xFX0VNQUlMX0NSRUFURSc7XG4gIHN0YXRpYyBST0xFX0VQTEFQUFNfUkVBRCA9ICdST0xFX0VQTEFQUFNfUkVBRCc7XG4gIHN0YXRpYyBST0xFX0VWRU5UX0FETUlOID0gJ1JPTEVfRVZFTlRfQURNSU4nO1xuICBzdGF0aWMgUk9MRV9FVkVOVF9SRUFEID0gJ1JPTEVfRVZFTlRfUkVBRCc7XG4gIHN0YXRpYyBST0xFX0dFTkVSSUNfTVFUVF9BRE1JTiA9ICdST0xFX0dFTkVSSUNfTVFUVF9BRE1JTic7XG4gIHN0YXRpYyBST0xFX0lERU5USVRZX0FETUlOID0gJ1JPTEVfSURFTlRJVFlfQURNSU4nO1xuICBzdGF0aWMgUk9MRV9JREVOVElUWV9SRUFEID0gJ1JPTEVfSURFTlRJVFlfUkVBRCc7XG4gIHN0YXRpYyBST0xFX0lOVkVOVE9SWV9BRE1JTiA9ICdST0xFX0lOVkVOVE9SWV9BRE1JTic7XG4gIHN0YXRpYyBST0xFX0lOVkVOVE9SWV9DUkVBVEUgPSAnUk9MRV9JTlZFTlRPUllfQ1JFQVRFJztcbiAgc3RhdGljIFJPTEVfSU5WRU5UT1JZX1JFQUQgPSAnUk9MRV9JTlZFTlRPUllfUkVBRCc7XG4gIHN0YXRpYyBST0xFX01BQ0hJTkVfTEVBUk5JTkdfUkVBRCA9ICdST0xFX01BQ0hJTkVfTEVBUk5JTkdfUkVBRCc7XG4gIHN0YXRpYyBST0xFX01BTkFHRURfT0JKRUNUX0FETUlOID0gJ1JPTEVfTUFOQUdFRF9PQkpFQ1RfQURNSU4nO1xuICBzdGF0aWMgUk9MRV9NQU5BR0VEX09CSkVDVF9DUkVBVEUgPSAnUk9MRV9NQU5BR0VEX09CSkVDVF9DUkVBVEUnO1xuICBzdGF0aWMgUk9MRV9NQU5BR0VEX09CSkVDVF9SRUFEID0gJ1JPTEVfTUFOQUdFRF9PQkpFQ1RfUkVBRCc7XG4gIHN0YXRpYyBST0xFX01FQVNVUkVNRU5UX0FETUlOID0gJ1JPTEVfTUVBU1VSRU1FTlRfQURNSU4nO1xuICBzdGF0aWMgUk9MRV9NRUFTVVJFTUVOVF9SRUFEID0gJ1JPTEVfTUVBU1VSRU1FTlRfUkVBRCc7XG4gIHN0YXRpYyBST0xFX01RVFRfQ09OTkVDVF9BRE1JTiA9ICdST0xFX01RVFRfQ09OTkVDVF9BRE1JTic7XG4gIHN0YXRpYyBST0xFX01RVFRfU0VSVklDRV9BRE1JTiA9ICdST0xFX01RVFRfU0VSVklDRV9BRE1JTic7XG4gIHN0YXRpYyBST0xFX05PVElGSUNBVElPTl8yX0FETUlOID0gJ1JPTEVfTk9USUZJQ0FUSU9OXzJfQURNSU4nO1xuICBzdGF0aWMgUk9MRV9PUFRJT05fTUFOQUdFTUVOVF9BRE1JTiA9ICdST0xFX09QVElPTl9NQU5BR0VNRU5UX0FETUlOJztcbiAgc3RhdGljIFJPTEVfT1BUSU9OX01BTkFHRU1FTlRfUkVBRCA9ICdST0xFX09QVElPTl9NQU5BR0VNRU5UX1JFQUQnO1xuICBzdGF0aWMgUk9MRV9QUk9WSVNJT05JTkdfQ1JFQVRFID0gJ1JPTEVfUFJPVklTSU9OSU5HX0NSRUFURSc7XG4gIHN0YXRpYyBST0xFX1BST1ZJU0lPTklOR19SRUFEID0gJ1JPTEVfUFJPVklTSU9OSU5HX1JFQUQnO1xuICBzdGF0aWMgUk9MRV9QUk9WSVNJT05JTkdfVVBEQVRFID0gJ1JPTEVfUFJPVklTSU9OSU5HX1VQREFURSc7XG4gIHN0YXRpYyBST0xFX1JFTU9URV9BQ0NFU1NfQURNSU4gPSAnUk9MRV9SRU1PVEVfQUNDRVNTX0FETUlOJztcbiAgc3RhdGljIFJPTEVfUkVURU5USU9OX1JVTEVfQURNSU4gPSAnUk9MRV9SRVRFTlRJT05fUlVMRV9BRE1JTic7XG4gIHN0YXRpYyBST0xFX1JFVEVOVElPTl9SVUxFX1JFQUQgPSAnUk9MRV9SRVRFTlRJT05fUlVMRV9SRUFEJztcbiAgc3RhdGljIFJPTEVfU0NIRURVTEVfUkVQT1JUX0FETUlOID0gJ1JPTEVfU0NIRURVTEVfUkVQT1JUX0FETUlOJztcbiAgc3RhdGljIFJPTEVfU0lNVUxBVE9SX0FETUlOID0gJ1JPTEVfU0lNVUxBVE9SX0FETUlOJztcbiAgc3RhdGljIFJPTEVfU01BUlRHUk9VUF9BRE1JTiA9ICdST0xFX1NNQVJUR1JPVVBfQURNSU4nO1xuICBzdGF0aWMgUk9MRV9TTUFSVEdST1VQX0NSRUFURSA9ICdST0xFX1NNQVJUR1JPVVBfQ1JFQVRFJztcbiAgc3RhdGljIFJPTEVfU01BUlRHUk9VUF9VUERBVEUgPSAnUk9MRV9TTUFSVEdST1VQX1VQREFURSc7XG4gIHN0YXRpYyBST0xFX1NNQVJUUlVMRV9BRE1JTiA9ICdST0xFX1NNQVJUUlVMRV9BRE1JTic7XG4gIHN0YXRpYyBST0xFX1NNQVJUUlVMRV9SRUFEID0gJ1JPTEVfU01BUlRSVUxFX1JFQUQnO1xuICBzdGF0aWMgUk9MRV9TTVNfQURNSU4gPSAnUk9MRV9TTVNfQURNSU4nO1xuICBzdGF0aWMgUk9MRV9TTVNfUkVBRCA9ICdST0xFX1NNU19SRUFEJztcbiAgc3RhdGljIFJPTEVfU1VQUE9SVF9BRE1JTiA9ICdST0xFX1NVUFBPUlRfQURNSU4nO1xuICBzdGF0aWMgUk9MRV9TVVBQT1JUX1JFQUQgPSAnUk9MRV9TVVBQT1JUX1JFQUQnO1xuICBzdGF0aWMgUk9MRV9URU5BTlRfQURNSU4gPSAnUk9MRV9URU5BTlRfQURNSU4nO1xuICBzdGF0aWMgUk9MRV9URU5BTlRfTUFOQUdFTUVOVF9BRE1JTiA9ICdST0xFX1RFTkFOVF9NQU5BR0VNRU5UX0FETUlOJztcbiAgc3RhdGljIFJPTEVfVEVOQU5UX01BTkFHRU1FTlRfQ1JFQVRFID0gJ1JPTEVfVEVOQU5UX01BTkFHRU1FTlRfQ1JFQVRFJztcbiAgc3RhdGljIFJPTEVfVEVOQU5UX01BTkFHRU1FTlRfUkVBRCA9ICdST0xFX1RFTkFOVF9NQU5BR0VNRU5UX1JFQUQnO1xuICBzdGF0aWMgUk9MRV9URU5BTlRfTUFOQUdFTUVOVF9VUERBVEUgPSAnUk9MRV9URU5BTlRfTUFOQUdFTUVOVF9VUERBVEUnO1xuICBzdGF0aWMgUk9MRV9URU5BTlRfU1RBVElTVElDU19SRUFEID0gJ1JPTEVfVEVOQU5UX1NUQVRJU1RJQ1NfUkVBRCc7XG4gIHN0YXRpYyBST0xFX1VTRVJfTUFOQUdFTUVOVF9BRE1JTiA9ICdST0xFX1VTRVJfTUFOQUdFTUVOVF9BRE1JTic7XG4gIHN0YXRpYyBST0xFX1VTRVJfTUFOQUdFTUVOVF9DUkVBVEUgPSAnUk9MRV9VU0VSX01BTkFHRU1FTlRfQ1JFQVRFJztcbiAgc3RhdGljIFJPTEVfVVNFUl9NQU5BR0VNRU5UX09XTl9BRE1JTiA9ICdST0xFX1VTRVJfTUFOQUdFTUVOVF9PV05fQURNSU4nO1xuICBzdGF0aWMgUk9MRV9VU0VSX01BTkFHRU1FTlRfT1dOX1JFQUQgPSAnUk9MRV9VU0VSX01BTkFHRU1FTlRfT1dOX1JFQUQnO1xuICBzdGF0aWMgUk9MRV9VU0VSX01BTkFHRU1FTlRfUkVBRCA9ICdST0xFX1VTRVJfTUFOQUdFTUVOVF9SRUFEJztcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIGFwcFN0YXRlOiBBcHBTdGF0ZVNlcnZpY2UsXG4gICAgcHJpdmF0ZSBpbnZlbnRvcnk6IEludmVudG9yeVNlcnZpY2UsXG4gICAgcHJpdmF0ZSB1c2VyOiBVc2VyU2VydmljZVxuICApIHt9XG5cbiAgLyoqXG4gICAqIENoZWNrcyBpZiB0aGUgY3VycmVudCB1c2VyIGhhcyB3cml0ZSBwZXJtaXNzaW9ucyBmb3IgdGhlIGdpdmVuIG1vXG4gICAqIChlaXRoZXIgdGhyb3VnaCBnbG9iYWwgcm9sZSwgaW5kaXZpZHVhbCBkZXZpY2UgcGVybWlzc2lvbnMgb3IgdmlhIGludmVudG9yeSByb2xlcykuXG4gICAqXG4gICAqIGBgYHRzXG4gICAqIGFzeW5jIGNhbkVkaXRHcm91cChncm91cDogSU1hbmFnZWRPYmplY3QpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICogICByZXR1cm4gYXdhaXQgdGhpcy5wZXJtaXNzaW9ucy5jYW5FZGl0KFxuICAgKiAgICAgW1Blcm1pc3Npb25zLlJPTEVfSU5WRU5UT1JZX0FETUlOLCBQZXJtaXNzaW9ucy5ST0xFX01BTkFHRURfT0JKRUNUX0FETUlOXSxcbiAgICogICAgIGdyb3VwXG4gICAqICAgKTtcbiAgICogfVxuICAgKiBgYGBcbiAgICpcbiAgICogQHBhcmFtIHJvbGVJZHMgLSBUaGUgYXJyYXkgb2Ygcm9sZSBpZHMgdG8gY2hlY2sgaWYgdGhlIGN1cnJlbnQgdXNlciBoYXZlIGF0IGxlYXN0IG9uZSBvZiB0aGVtLlxuICAgKiBAcGFyYW0gbW8gLSBUaGUgbWFuYWdlZCBvYmplY3QgZm9yIHdoaWNoIHdlIGFyZSBjaGVja2luZyB3aGV0aGVyIHRoZSB1c2VyIGhhcyBhY2Nlc3MuXG4gICAqIEBwYXJhbSBjb25maWcgLSBBIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHRoYXQgY2FuIHRha2UgdGhlIGZvbGxvd2luZyB2YWx1ZXM6IGBza2lwUm9sZXNDaGVja2A6IGBib29sZWFuYCAtIHNraXBzIHJvbGVzIGNoZWNrLCBgc2tpcE93bmVyQ2hlY2tgOiBgYm9vbGVhbmAgLSBza2lwcyBvd25lcnNoaXAgY2hlY2ssIGBza2lwUmVxdWVzdENoZWNrYDogYGJvb2xlYW5gIC0gc2tpcHMgY2hlY2tzIHdpdGggYSBxdWVyeSB0byB0aGUgaW52ZW50b3J5IEFQSS4gVUkgd2lsbCBtYWtlIGEgcXVlcnkgdG8gYmFja2VuZCB3aGV0aGVyIHRoZSB1c2VyIGNhbiBlZGl0IHRoZSBtYW5hZ2VkIG9iamVjdC4gQSByZWplY3Rpb24gZnJvbSBCRSBpbmRpY2F0ZXMgYSBsYWNrIG9mIHBlcm1pc3Npb24uXG4gICAqXG4gICAqIEByZXR1cm5zIEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gYSBib29sZWFuIHZhbHVlLiBgdHJ1ZWAgaWYgZWRpdGluZyBpcyBwZXJtaXR0ZWQgYmFzZWQgb24gdGhlIGdpdmVuIHBhcmFtZXRlcnMgYW5kIGNvbmZpZ3VyYXRpb247IG90aGVyd2lzZSwgYGZhbHNlYC5cbiAgICpcbiAgICovXG4gIGNhbkVkaXQoXG4gICAgcm9sZUlkczogc3RyaW5nW10sXG4gICAgbW86IElNYW5hZ2VkT2JqZWN0IHwgSUlkZW50aWZpZWQsXG4gICAgY29uZmlnOiBDYW5FZGl0Q29uZmlnID0ge1xuICAgICAgc2tpcFJvbGVzQ2hlY2s6IGZhbHNlLFxuICAgICAgc2tpcE93bmVyQ2hlY2s6IGZhbHNlLFxuICAgICAgc2tpcFJlcXVlc3RDaGVjazogZmFsc2VcbiAgICB9XG4gICk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIHJldHVybiB0aGlzLmNoZWNrSWZDYW5FZGl0KHJvbGVJZHMsIG1vLCBjb25maWcpO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyBpZiB0aGUgY3VycmVudCB1c2VyIGhhcyB0aGUgc3BlY2lmaWVkIHJvbGUuXG4gICAqXG4gICAqIGBgYHRzXG4gICAqIGhhc1Ntc1JlYWRSb2xlKCk6IGJvb2xlYW4ge1xuICAgKiAgcmV0dXJuIHRoaXMucGVybWlzc2lvbnMuaGFzUm9sZShQZXJtaXNzaW9ucy5ST0xFX1NNU19SRUFEKTtcbiAgICogfTtcbiAgICogYGBgXG4gICAqXG4gICAqIEBwYXJhbSByb2xlSWQgLSBUaGUgSUQgb2YgdGhlIHJvbGUgdG8gY2hlY2sgYWdhaW5zdCB0aGUgY3VycmVudCB1c2VyJ3Mgcm9sZXMuXG4gICAqIEByZXR1cm5zIEEgYm9vbGVhbiB2YWx1ZSBpbmRpY2F0aW5nIHdoZXRoZXIgdGhlIGN1cnJlbnQgdXNlciBoYXMgdGhlIHNwZWNpZmllZCByb2xlLlxuICAgKiBAdGhyb3dzIEVycm9yIGlmIG5vIHVzZXIgaXMgY3VycmVudGx5IGxvZ2dlZCBpbi5cbiAgICpcbiAgICovXG4gIGhhc1JvbGUocm9sZUlkOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICBjb25zdCBjdXJyZW50VXNlciA9IHRoaXMuYXBwU3RhdGUuY3VycmVudFVzZXIudmFsdWU7XG4gICAgaWYgKCFjdXJyZW50VXNlcikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdSb2xlcyBjYW4gb25seSBiZSByZXF1ZXN0ZWQgaWYgdGhlIHVzZXIgaXMgbG9nZ2VkIGluLicpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy51c2VyLmhhc1JvbGUoY3VycmVudFVzZXIsIHJvbGVJZCk7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIHRoZSBjdXJyZW50IHVzZXIgcG9zc2Vzc2VzIGFsbCB0aGUgc3BlY2lmaWVkIHJvbGVzLlxuICAgKlxuICAgKiBgYGB0c1xuICAgKiBoYXNNT1JlYWRBbmRCaW5hcnlSZWFkUm9sZXMoKTogYm9vbGVhbiB7XG4gICAqICAgcmV0dXJuIHRoaXMucGVybWlzc2lvbnMuaGFzQWxsUm9sZXMoW1xuICAgKiAgICAgUGVybWlzc2lvbnMuUk9MRV9NQU5BR0VEX09CSkVDVF9SRUFELFxuICAgKiAgICAgUGVybWlzc2lvbnMuUk9MRV9CSU5BUllfUkVBRFxuICAgKiAgIF0pO1xuICAgKiB9XG4gICAqIGBgYFxuICAgKlxuICAgKiBAcGFyYW0gcm9sZUlkcyAtIEFuIGFycmF5IG9mIHN0cmluZ3MgcmVwcmVzZW50aW5nIHRoZSByb2xlIElEcyB0byBjaGVjayBhZ2FpbnN0IHRoZSBjdXJyZW50IHVzZXIncyByb2xlcy5cbiAgICogQHJldHVybnMgQSBib29sZWFuIHZhbHVlIGluZGljYXRpbmcgd2hldGhlciB0aGUgY3VycmVudCB1c2VyIGhhcyBhbGwgdGhlIHNwZWNpZmllZCByb2xlcy5cbiAgICogQHRocm93cyBFcnJvciBpZiBubyB1c2VyIGlzIGN1cnJlbnRseSBsb2dnZWQgaW4uXG4gICAqXG4gICAqL1xuICBoYXNBbGxSb2xlcyhyb2xlSWRzOiBzdHJpbmdbXSk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IGN1cnJlbnRVc2VyID0gdGhpcy5hcHBTdGF0ZS5jdXJyZW50VXNlci52YWx1ZTtcbiAgICBpZiAoIWN1cnJlbnRVc2VyKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1JvbGVzIGNhbiBvbmx5IGJlIHJlcXVlc3RlZCBpZiB0aGUgdXNlciBpcyBsb2dnZWQgaW4uJyk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLnVzZXIuaGFzQWxsUm9sZXMoY3VycmVudFVzZXIsIHJvbGVJZHMpO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyBpZiB0aGUgY3VycmVudCB1c2VyIHBvc3Nlc3NlcyBhbnkgb2YgdGhlIHNwZWNpZmllZCByb2xlcy5cbiAgICpcbiAgICogYGBgdHNcbiAgICogaGFzVGVuYW50QWRtaW5PclRlbmFudE1hbmFnZW1lbnRBZG1pblJvbGVzKCk6IGJvb2xlYW4ge1xuICAgKiAgcmV0dXJuIHRoaXMucGVybWlzc2lvbnMuaGFzQW55Um9sZShbXG4gICAqICAgIFBlcm1pc3Npb25zLlJPTEVfVEVOQU5UX0FETUlOLFxuICAgKiAgICBQZXJtaXNzaW9ucy5ST0xFX1RFTkFOVF9NQU5BR0VNRU5UX0FETUlOXG4gICAqICBdKTtcbiAgICogfTtcbiAgICogYGBgXG4gICAqXG4gICAqIEBwYXJhbSByb2xlSWRzIC0gQW4gYXJyYXkgb2Ygc3RyaW5ncyByZXByZXNlbnRpbmcgdGhlIHJvbGUgSURzIHRvIGNoZWNrIGFnYWluc3QgdGhlIGN1cnJlbnQgdXNlcidzIHJvbGVzLlxuICAgKiBAcmV0dXJucyBBIGJvb2xlYW4gdmFsdWUgaW5kaWNhdGluZyB3aGV0aGVyIHRoZSBjdXJyZW50IHVzZXIgaGFzIGFueSBvZiB0aGUgc3BlY2lmaWVkIHJvbGVzLlxuICAgKiBAdGhyb3dzIEVycm9yIGlmIG5vIHVzZXIgaXMgY3VycmVudGx5IGxvZ2dlZCBpbi5cbiAgICpcbiAgICovXG4gIGhhc0FueVJvbGUocm9sZUlkczogc3RyaW5nW10pOiBib29sZWFuIHtcbiAgICBjb25zdCBjdXJyZW50VXNlciA9IHRoaXMuYXBwU3RhdGUuY3VycmVudFVzZXIudmFsdWU7XG4gICAgaWYgKCFjdXJyZW50VXNlcikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdSb2xlcyBjYW4gb25seSBiZSByZXF1ZXN0ZWQgaWYgdGhlIHVzZXIgaXMgbG9nZ2VkIGluLicpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy51c2VyLmhhc0FueVJvbGUoY3VycmVudFVzZXIsIHJvbGVJZHMpO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyBpZiB0aGUgY3VycmVudCB1c2VyIHBvc3Nlc3NlcyBhbnkgb2YgdGhlIHNwZWNpZmllZCBnbG9iYWwgcm9sZXMuXG4gICAqXG4gICAqIGBgYHRzXG4gICAqIGhhc0FueUdsb2JhbFJvbGVzKGRhc2hib2FyZDogQ29udGV4dERhc2hib2FyZE1hbmFnZWRPYmplY3QpOiBib29sZWFuIHtcbiAgICogICBjb25zdCBnbG9iYWxSb2xlc0lkcyA9IGRhc2hib2FyZD8uYzh5X0Rhc2hib2FyZD8uZ2xvYmFsUm9sZXNJZHM7XG4gICAqICAgcmV0dXJuIHRoaXMucGVybWlzc2lvbnMuaGFzQW55R2xvYmFsUm9sZShnbG9iYWxSb2xlc0lkcyk7XG4gICAqIH1cbiAgICogYGBgXG4gICAqXG4gICAqIEBwYXJhbSBnbG9iYWxSb2xlc0lkcyAtIEFuIGFycmF5IG9mIG51bWJlcnMgcmVwcmVzZW50aW5nIHRoZSBnbG9iYWwgcm9sZSBJRHMgdG8gY2hlY2sgYWdhaW5zdCB0aGUgY3VycmVudCB1c2VyJ3Mgcm9sZXMuXG4gICAqIEByZXR1cm5zIEEgYm9vbGVhbiB2YWx1ZSBpbmRpY2F0aW5nIHdoZXRoZXIgdGhlIGN1cnJlbnQgdXNlciBoYXMgYW55IG9mIHRoZSBzcGVjaWZpZWQgZ2xvYmFsIHJvbGVzLlxuICAgKiBAdGhyb3dzIEVycm9yIGlmIG5vIHVzZXIgaXMgY3VycmVudGx5IGxvZ2dlZCBpbi5cbiAgICpcbiAgICovXG4gIGhhc0FueUdsb2JhbFJvbGUoZ2xvYmFsUm9sZXNJZHM6IG51bWJlcltdKTogYm9vbGVhbiB7XG4gICAgY29uc3QgY3VycmVudFVzZXIgPSB0aGlzLmFwcFN0YXRlLmN1cnJlbnRVc2VyLnZhbHVlO1xuICAgIGlmICghY3VycmVudFVzZXIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignR2xvYmFsIHJvbGVzIGNhbiBvbmx5IGJlIHJlcXVlc3RlZCBpZiB0aGUgdXNlciBpcyBsb2dnZWQgaW4uJyk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLnVzZXIuaGFzQW55R2xvYmFsUm9sZShjdXJyZW50VXNlciwgZ2xvYmFsUm9sZXNJZHMpO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyBpZiB0aGUgY3VycmVudCB1c2VyIGlzIHRoZSBvd25lciBvZiB0aGUgbWFuYWdlZCBvYmplY3QuXG4gICAqIFV0aWxpemVzIG1lbW9pemF0aW9uIHRvIGNhY2hlIHRoZSByZXN1bHQgYmFzZWQgb24gdGhlIG1hbmFnZWQgb2JqZWN0J3MgaWQsXG4gICAqIGltcHJvdmluZyBwZXJmb3JtYW5jZSBmb3Igc3Vic2VxdWVudCBjaGVja3Mgb2YgdGhlIHNhbWUgb2JqZWN0LlxuICAgKlxuICAgKiBgYGB0c1xuICAgKiBjb25zdCBtYW5hZ2VkT2JqZWN0ID0geyBpZDogJzEyMycsIG93bmVyOiAnam9obkRvZScgfTtcbiAgICogdGhpcy5jaGVja0lmT3duZXIobWFuYWdlZE9iamVjdCkudGhlbihpc093bmVyID0+IHtcbiAgICogICBjb25zb2xlLmxvZyhpc093bmVyKTtcbiAgICogfSk7XG4gICAqIGBgYFxuICAgKlxuICAgKiBAcGFyYW0gbW8gLSBUaGUgbWFuYWdlZCBvYmplY3QgdG8gY2hlY2sgb3duZXJzaGlwIGFnYWluc3QuXG4gICAqIEByZXR1cm5zIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGB0cnVlYCBpZiB0aGUgY3VycmVudCB1c2VyIGlzIHRoZSBvd25lciBvZiB0aGUgbWFuYWdlZCBvYmplY3QsIGFuZCBgZmFsc2VgIG90aGVyd2lzZS5cbiAgICpcbiAgICovXG4gIEBtZW1vaXplKHByb3BlcnR5KCdpZCcpKVxuICBwcm90ZWN0ZWQgYXN5bmMgY2hlY2tJZk93bmVyKG1vOiBJTWFuYWdlZE9iamVjdCB8IElJZGVudGlmaWVkKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgY3VycmVudFVzZXJOYW1lID0gYXdhaXQgdGhpcy5hcHBTdGF0ZS5jdXJyZW50VXNlci52YWx1ZS51c2VyTmFtZTtcbiAgICBjb25zdCB7IGRhdGEgfSA9IGF3YWl0IHRoaXMuaW52ZW50b3J5LmRldGFpbChtby5pZCk7XG4gICAgcmV0dXJuIGN1cnJlbnRVc2VyTmFtZSA9PT0gZGF0YS5vd25lcjtcbiAgfVxuXG4gIC8qKlxuICAgKiBBdHRlbXB0cyB0byBwZXJmb3JtIGEgcGFydGlhbCB1cGRhdGUgb24gYSBtYW5hZ2VkIG9iamVjdCBhcyBhIG1lYW5zIHRvIGNoZWNrIGZvciBlZGl0IHBlcm1pc3Npb25zLlxuICAgKiBVdGlsaXplcyBtZW1vaXphdGlvbiB0byBjYWNoZSB0aGUgcmVzdWx0IGJhc2VkIG9uIHRoZSBtYW5hZ2VkIG9iamVjdCdzIGlkLFxuICAgKiB0aGVyZWJ5IGF2b2lkaW5nIHVubmVjZXNzYXJ5IHJlcGVhdGVkIHJlcXVlc3RzIGZvciB0aGUgc2FtZSBvYmplY3QuXG4gICAqXG4gICAqIFRoaXMgbWV0aG9kIGVzc2VudGlhbGx5IHRlc3RzIGlmIHRoZSBjdXJyZW50IHVzZXIgaGFzIHBlcm1pc3Npb24gdG8gdXBkYXRlIHRoZSBtYW5hZ2VkIG9iamVjdCxcbiAgICogc2VydmluZyBhcyBhbiBpbmRpcmVjdCBwZXJtaXNzaW9uIGNoZWNrLlxuICAgKlxuICAgKiBgYGB0c1xuICAgKiBjb25zdCBtYW5hZ2VkT2JqZWN0ID0geyBpZDogJzQ1NicgfTtcbiAgICogdGhpcy5jaGVja1dpdGhSZXF1ZXN0KG1hbmFnZWRPYmplY3QpLnRoZW4oaGFzUGVybWlzc2lvbiA9PiB7XG4gICAqICAgY29uc29sZS5sb2coaGFzUGVybWlzc2lvbik7XG4gICAqIH0pLmNhdGNoKGVycm9yID0+IHtcbiAgICogICBjb25zb2xlLmVycm9yKGVycm9yKTtcbiAgICogfSk7XG4gICAqIGBgYFxuICAgKlxuICAgKiBAcGFyYW0gbW8gLSBUaGUgbWFuYWdlZCBvYmplY3QgdG8gdGVzdCBlZGl0IHBlcm1pc3Npb25zIG9uLlxuICAgKiBAcmV0dXJucyBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byBgdHJ1ZWAgaWYgdGhlIHVwZGF0ZSByZXF1ZXN0IHN1Y2NlZWRzIChpbmRpY2F0aW5nIGVkaXQgcGVybWlzc2lvbnMpLCBhbmQgYGZhbHNlYCBpZiBpdCBmYWlscy5cbiAgICpcbiAgICovXG4gIEBtZW1vaXplKHByb3BlcnR5KCdpZCcpKVxuICBwcm90ZWN0ZWQgYXN5bmMgY2hlY2tXaXRoUmVxdWVzdChtbzogSU1hbmFnZWRPYmplY3QgfCBJSWRlbnRpZmllZCk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IG1vSWQgPSBtby5pZC50b1N0cmluZygpO1xuICAgIGNvbnN0IHBhcnRpYWxVcGRhdGVPYmplY3Q6IFBhcnRpYWw8SU1hbmFnZWRPYmplY3Q+ID0ge1xuICAgICAgaWQ6IG1vSWRcbiAgICB9O1xuICAgIHJldHVybiB0aGlzLmludmVudG9yeVxuICAgICAgLnVwZGF0ZShwYXJ0aWFsVXBkYXRlT2JqZWN0KVxuICAgICAgLnRoZW4oKCkgPT4ge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH0pXG4gICAgICAuY2F0Y2goKCkgPT4ge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVja3MgaWYgdGhlIGN1cnJlbnQgdXNlciBoYXMgdGhlIG5lY2Vzc2FyeSBwZXJtaXNzaW9ucyB0byBlZGl0IGEgbWFuYWdlZCBvYmplY3QuXG4gICAqIFRoaXMgbWV0aG9kIGNvbnNpZGVycyB2YXJpb3VzIGNvbmRpdGlvbnMgdG8gZGV0ZXJtaW5lIGVkaXRhYmlsaXR5LCBpbmNsdWRpbmcgcm9sZSBjaGVja3MsXG4gICAqIG93bmVyc2hpcCwgYW5kIGN1c3RvbSByZXF1ZXN0LWJhc2VkIGNoZWNrcy4gRWFjaCBvZiB0aGVzZSBjaGVja3MgY2FuIGJlIG9wdGlvbmFsbHkgc2tpcHBlZFxuICAgKiBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbi5cbiAgICpcbiAgICogQHBhcmFtIHJvbGVJZHMgLSBBbiBhcnJheSBvZiByb2xlIElEcyB0byBjaGVjayBhZ2FpbnN0IHRoZSBjdXJyZW50IHVzZXIncyByb2xlcy5cbiAgICogQHBhcmFtIG1vIC0gVGhlIG1hbmFnZWQgb2JqZWN0IG9yIGFuIGlkZW50aWZpZWQgcmVzb3VyY2UgdG8gY2hlY2sgZWRpdCBwZXJtaXNzaW9ucyBmb3IuXG4gICAqIEBwYXJhbSBjb25maWcgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgdG8gY3VzdG9taXplIHRoZSBjaGVja3MgcGVyZm9ybWVkLiBUaGlzIGluY2x1ZGVzIG9wdGlvbnMgdG8gc2tpcCByb2xlIGNoZWNrcywgb3duZXIgY2hlY2tzLCBvciBjdXN0b20gcmVxdWVzdCBjaGVja3MuXG4gICAqIEByZXR1cm5zIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGB0cnVlYCBpZiB0aGUgY3VycmVudCB1c2VyIGNhbiBlZGl0IHRoZSBtYW5hZ2VkIG9iamVjdCBiYXNlZCBvbiB0aGUgZ2l2ZW4gY29uZGl0aW9ucywgYW5kIGBmYWxzZWAgb3RoZXJ3aXNlLlxuICAgKlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBjaGVja0lmQ2FuRWRpdChcbiAgICByb2xlSWRzOiBzdHJpbmdbXSxcbiAgICBtbzogSU1hbmFnZWRPYmplY3QgfCBJSWRlbnRpZmllZCxcbiAgICBjb25maWc6IENhbkVkaXRDb25maWdcbiAgKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgaWYgKCFjb25maWc/LnNraXBSb2xlc0NoZWNrICYmIChhd2FpdCB0aGlzLmhhc0FueVJvbGUocm9sZUlkcykpKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9IGVsc2UgaWYgKCFjb25maWc/LnNraXBPd25lckNoZWNrICYmIChhd2FpdCB0aGlzLmNoZWNrSWZPd25lcihtbykpKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9IGVsc2UgaWYgKCFjb25maWc/LnNraXBSZXF1ZXN0Q2hlY2sgJiYgKGF3YWl0IHRoaXMuY2hlY2tXaXRoUmVxdWVzdChtbykpKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG59XG4iXX0=