UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

196 lines 39.7 kB
import { Injectable } from '@angular/core'; import { GrantType, SystemOptionsService, TenantLoginOptionsService, TenantLoginOptionType, TenantOptionsService, TenantService, TfaStrategy, UserManagementSource } from '@c8y/client'; import { catchError, map } from 'rxjs/operators'; import { forkJoin, from, of } from 'rxjs'; import { defaults } from 'lodash-es'; import { AppStateService, TenantUiService } from '@c8y/ngx-components'; import { TypedOption } from './typed-option'; import { TenantLoginOptionMapper } from './tenant-login-option.mapper'; import * as i0 from "@angular/core"; import * as i1 from "@c8y/client"; import * as i2 from "@c8y/ngx-components"; import * as i3 from "./tenant-login-option.mapper"; export class AuthConfigurationService { constructor(tenantLoginOptionsService, tenantOptionsService, systemOptionsService, appState, tenantUiService, tenantLoginOptionMapper, tenantService) { this.tenantLoginOptionsService = tenantLoginOptionsService; this.tenantOptionsService = tenantOptionsService; this.systemOptionsService = systemOptionsService; this.appState = appState; this.tenantUiService = tenantUiService; this.tenantLoginOptionMapper = tenantLoginOptionMapper; this.tenantService = tenantService; this.systemOptionsWithDefaultValue = [ new TypedOption('password', 'limit.validity', 'number', null), new TypedOption('password', 'enforce.strength', 'boolean', false), new TypedOption('two-factor-authentication', 'tenant-scope-settings.enabled', 'boolean', false), new TypedOption('two-factor-authentication', 'enabled', 'boolean', false), // note: this definition is inconsistent with backend and is overridden in getSystemOptions$ new TypedOption('two-factor-authentication', 'enforced', 'boolean', false), new TypedOption('two-factor-authentication', 'enforced.group', 'string', '') ]; this.tenantOptionsWithDefaultValue = [ new TypedOption('password', 'limit.validity', 'number', 0), new TypedOption('password', 'strength.validity', 'boolean', false), new TypedOption('two-factor-authentication', 'enabled', 'boolean', false), new TypedOption('two-factor-authentication', 'token.validity', 'number', 43200), // 30 days new TypedOption('two-factor-authentication', 'pin.validity', 'number', 30), new TypedOption('two-factor-authentication', 'enforced', 'boolean', false), new TypedOption('two-factor-authentication', 'strategy', 'string', 'SMS'), new TypedOption('oauth.internal', 'basic-token.lifespan.seconds', 'number', null), new TypedOption('configuration', 'tenant.login.ignore-case', 'boolean', false) ]; } getAuthConfiguration$() { const loginOptions$ = this.getLoginOptions$(); return forkJoin({ loginOptions: this.map(loginOptions$), tenantOptions: this.getTenantOptions$(), systemOptions: this.getSystemOptions$(), smsGatewayAvailable: this.isSmsApplicationAvailable$(), preferredLoginOptionType: this.getPreferredLoginOptionType$(loginOptions$) }); } save(newAuthConfiguration, previousAuthConfiguration) { const tenantOptions = this.prepareTenantOptions(newAuthConfiguration, previousAuthConfiguration); const updateTenantOptions = tenantOptions.map(tenantOption => { const fixedOption = this.fixTfaStrategy(tenantOption); if (fixedOption) { return fixedOption; } return this.tenantOptionsService.create(tenantOption); }); const basicLoginOption = this.prepareBasicLoginOption(newAuthConfiguration, previousAuthConfiguration); const oauthInternalLoginOption = this.prepareOauthInternalLoginOption(newAuthConfiguration, previousAuthConfiguration); return Promise.all([ this.saveOrUpdateLoginOption(basicLoginOption), this.saveOrUpdateLoginOption(oauthInternalLoginOption), ...updateTenantOptions ]); } map(loginOptions$) { return loginOptions$.pipe(map(loginOptions => loginOptions.map(loginOption => this.tenantLoginOptionMapper.mapTo(loginOption)))); } saveOrUpdateLoginOption(loginOption) { return loginOption.id ? this.tenantLoginOptionsService.update(loginOption) : this.tenantLoginOptionsService.create(loginOption); } prepareBasicLoginOption(newAuthConfiguration, previousAuthConfiguration) { const basicLoginOption = this.originalLoginOptionWithDefaults(previousAuthConfiguration, TenantLoginOptionType.BASIC); basicLoginOption.visibleOnLoginPage = this.visibleOnLoginPage(newAuthConfiguration, TenantLoginOptionType.BASIC); return this.tenantLoginOptionMapper.mapFrom(basicLoginOption, this.getLoginOptionFromAuthConfiguration(newAuthConfiguration, TenantLoginOptionType.BASIC)); } prepareOauthInternalLoginOption(newAuthConfiguration, previousAuthConfiguration) { const oauthInternalLoginOption = this.originalLoginOptionWithDefaults(previousAuthConfiguration, TenantLoginOptionType.OAUTH2_INTERNAL); oauthInternalLoginOption.visibleOnLoginPage = this.visibleOnLoginPage(newAuthConfiguration, TenantLoginOptionType.OAUTH2_INTERNAL); return this.tenantLoginOptionMapper.mapFrom(oauthInternalLoginOption, this.getLoginOptionFromAuthConfiguration(newAuthConfiguration, TenantLoginOptionType.OAUTH2_INTERNAL)); } originalLoginOptionWithDefaults(previousAuthConfiguration, loginOptionType) { return defaults({}, this.getLoginOptionFromAuthConfiguration(previousAuthConfiguration, loginOptionType), this.getDefaultLoginOption(loginOptionType)); } getLoginOptionFromAuthConfiguration(authConfiguration, loginOptionType) { return authConfiguration.loginOptions.find(loginOption => loginOption.type === loginOptionType); } visibleOnLoginPage(authConfiguration, loginOptionType) { return authConfiguration.preferredLoginOptionType === loginOptionType; } prepareTenantOptions(newAuthConfiguration, previousAuthConfiguration) { const getValue = (authCfg, tenantOption) => authCfg.tenantOptions[tenantOption.category][tenantOption.key]; const hasChanged = tenantOption => getValue(newAuthConfiguration, tenantOption) !== getValue(previousAuthConfiguration, tenantOption); return this.tenantOptionsWithDefaultValue .filter(tenantOption => getValue(newAuthConfiguration, tenantOption) !== null) .filter(tenantOption => hasChanged(tenantOption)) .map(tenantOption => ({ category: tenantOption.category, key: tenantOption.key, value: getValue(newAuthConfiguration, tenantOption).toString() })); } getLoginOptions$() { return forkJoin([ this.getLoginOption(TenantLoginOptionType.OAUTH2), this.getLoginOption(TenantLoginOptionType.BASIC), this.getLoginOption(TenantLoginOptionType.OAUTH2_INTERNAL) ]).pipe(map(loginOptions => loginOptions.filter(loginOption => !!loginOption))); } getLoginOption(tenantLoginOptionType) { return from(this.tenantLoginOptionsService.detail(tenantLoginOptionType)).pipe(map(res => res.data), catchError(() => tenantLoginOptionType !== TenantLoginOptionType.OAUTH2 ? of(this.getDefaultLoginOption(tenantLoginOptionType)) : of(null))); } getPreferredLoginOptionType$(loginOptions$) { return loginOptions$.pipe(map(loginOptions => { return this.tenantUiService.getPreferredLoginOption(loginOptions).type; })); } getTenantOptions$() { return forkJoin(this.tenantOptionsWithDefaultValue.map((option) => from(this.tenantOptionsService.detail(option)).pipe(map(res => { option.apply(res.data); return option; }), catchError(() => of(option))))).pipe(map(options => this.getOptionsObject(options))); } getSystemOptions$() { return forkJoin(this.systemOptionsWithDefaultValue.map((option) => { const fixedOption = this.fixTfaEnforcedSystemOption(option); if (fixedOption) { return fixedOption; } return from(this.systemOptionsService.detail(option)).pipe(map(res => { option.apply(res.data); return option; }), catchError(() => of(option))); })).pipe(map(options => this.getOptionsObject(options))); } /** * Returns an observable with fixed `two-factor-authentication.enforced` system option or null. * This method fixes problem with inconsistent value. System option `two-factor-authentication.enforced` is list of tenants when UI using boolean value. * This part will be removed after implementing new endpoint in MTM-50490. */ fixTfaEnforcedSystemOption(option) { if (option.category === 'two-factor-authentication' && option.key === 'enforced') { return from(this.tenantService.getTfaSettings(this.tenantUiService.currentTenant)).pipe(map(tfaSettings => { option.value = tfaSettings.enforcedOnSystemLevel.toString(); return option; })); } return null; } /** * Returns a promise or null. * This method is needed now, because simply changing TFA strategy tenant option does not trigger all the necessary backend logic to apply the change, therefore, we need to call tenant's `/tfa` endpoint, which applies the change for all users in the tenant. * Within MTM-50490, we're going to simplify the process further by replacing multiple requests with one new endpoint that will handle saving of all authentication settings. */ fixTfaStrategy(option) { if (option.category === 'two-factor-authentication' && option.key === 'strategy') { const strategy = option.value === 'SMS' ? TfaStrategy.SMS : TfaStrategy.TOTP; return this.tenantService.updateTfaStrategy(this.tenantUiService.currentTenant, strategy); } return null; } isSmsApplicationAvailable$() { return from(this.appState.isApplicationAvailable('sms-gateway')); } getOptionsObject(options) { return options.reduce((optionsObject, option) => { optionsObject[option.category] = optionsObject[option.category] || {}; optionsObject[option.category][option.key] = option.getValue(); return optionsObject; }, {}); } getDefaultLoginOption(tenantLoginOptionType) { return { userManagementSource: UserManagementSource.INTERNAL, grantType: GrantType.PASSWORD, providerName: 'Cumulocity', visibleOnLoginPage: false, type: tenantLoginOptionType }; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AuthConfigurationService, deps: [{ token: i1.TenantLoginOptionsService }, { token: i1.TenantOptionsService }, { token: i1.SystemOptionsService }, { token: i2.AppStateService }, { token: i2.TenantUiService }, { token: i3.TenantLoginOptionMapper }, { token: i1.TenantService }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AuthConfigurationService }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AuthConfigurationService, decorators: [{ type: Injectable }], ctorParameters: () => [{ type: i1.TenantLoginOptionsService }, { type: i1.TenantOptionsService }, { type: i1.SystemOptionsService }, { type: i2.AppStateService }, { type: i2.TenantUiService }, { type: i3.TenantLoginOptionMapper }, { type: i1.TenantService }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC1jb25maWd1cmF0aW9uLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9hdXRoLWNvbmZpZ3VyYXRpb24vYmFzaWMtc2V0dGluZ3MvYXV0aC1jb25maWd1cmF0aW9uLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzQyxPQUFPLEVBQ0wsU0FBUyxFQUlULG9CQUFvQixFQUNwQix5QkFBeUIsRUFDekIscUJBQXFCLEVBQ3JCLG9CQUFvQixFQUNwQixhQUFhLEVBQ2IsV0FBVyxFQUNYLG9CQUFvQixFQUNyQixNQUFNLGFBQWEsQ0FBQztBQUNyQixPQUFPLEVBQUUsVUFBVSxFQUFFLEdBQUcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ2pELE9BQU8sRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFjLEVBQUUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUN0RCxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBRXJDLE9BQU8sRUFBRSxlQUFlLEVBQUUsZUFBZSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDdkUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRTdDLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLDhCQUE4QixDQUFDOzs7OztBQUd2RSxNQUFNLE9BQU8sd0JBQXdCO0lBdUJuQyxZQUNVLHlCQUFvRCxFQUNwRCxvQkFBMEMsRUFDMUMsb0JBQTBDLEVBQzFDLFFBQXlCLEVBQ3pCLGVBQWdDLEVBQ2hDLHVCQUFnRCxFQUNoRCxhQUE0QjtRQU41Qiw4QkFBeUIsR0FBekIseUJBQXlCLENBQTJCO1FBQ3BELHlCQUFvQixHQUFwQixvQkFBb0IsQ0FBc0I7UUFDMUMseUJBQW9CLEdBQXBCLG9CQUFvQixDQUFzQjtRQUMxQyxhQUFRLEdBQVIsUUFBUSxDQUFpQjtRQUN6QixvQkFBZSxH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QUcsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUMvRCxPQUFPLGFBQWEsQ0FBQztRQUN2QixDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDVCxDQUFDO0lBRU8scUJBQXFCLENBQUMscUJBQTRDO1FBQ3hFLE9BQU87WUFDTCxvQkFBb0IsRUFBRSxvQkFBb0IsQ0FBQyxRQUFRO1lBQ25ELFNBQVMsRUFBRSxTQUFTLENBQUMsUUFBUTtZQUM3QixZQUFZLEVBQUUsWUFBWTtZQUMxQixrQkFBa0IsRUFBRSxLQUFLO1lBQ3pCLElBQUksRUFBRSxxQkFBcUI7U0FDNUIsQ0FBQztJQUNKLENBQUM7K0dBOVJVLHdCQUF3QjttSEFBeEIsd0JBQXdCOzs0RkFBeEIsd0JBQXdCO2tCQURwQyxVQUFVIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtcbiAgR3JhbnRUeXBlLFxuICBJUmVzdWx0LFxuICBJVGVuYW50TG9naW5PcHRpb24sXG4gIElUZW5hbnRPcHRpb24sXG4gIFN5c3RlbU9wdGlvbnNTZXJ2aWNlLFxuICBUZW5hbnRMb2dpbk9wdGlvbnNTZXJ2aWNlLFxuICBUZW5hbnRMb2dpbk9wdGlvblR5cGUsXG4gIFRlbmFudE9wdGlvbnNTZXJ2aWNlLFxuICBUZW5hbnRTZXJ2aWNlLFxuICBUZmFTdHJhdGVneSxcbiAgVXNlck1hbmFnZW1lbnRTb3VyY2Vcbn0gZnJvbSAnQGM4eS9jbGllbnQnO1xuaW1wb3J0IHsgY2F0Y2hFcnJvciwgbWFwIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgZm9ya0pvaW4sIGZyb20sIE9ic2VydmFibGUsIG9mIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBkZWZhdWx0cyB9IGZyb20gJ2xvZGFzaC1lcyc7XG5pbXBvcnQgeyBBdXRoQ29uZmlndXJhdGlvbiwgT3B0aW9ucyB9IGZyb20gJy4vYXV0aC1jb25maWd1cmF0aW9uLm1vZGVsJztcbmltcG9ydCB7IEFwcFN0YXRlU2VydmljZSwgVGVuYW50VWlTZXJ2aWNlIH0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cyc7XG5pbXBvcnQgeyBUeXBlZE9wdGlvbiB9IGZyb20gJy4vdHlwZWQtb3B0aW9uJztcbmltcG9ydCB7IFRlbmFudExvZ2luT3B0aW9uIH0gZnJvbSAnLi9iYXNpYy1zZXR0aW5ncy5tb2RlbCc7XG5pbXBvcnQgeyBUZW5hbnRMb2dpbk9wdGlvbk1hcHBlciB9IGZyb20gJy4vdGVuYW50LWxvZ2luLW9wdGlvbi5tYXBwZXInO1xuXG5ASW5qZWN0YWJsZSgpXG5leHBvcnQgY2xhc3MgQXV0aENvbmZpZ3VyYXRpb25TZXJ2aWNlIHtcbiAgcHJpdmF0ZSBzeXN0ZW1PcHRpb25zV2l0aERlZmF1bHRWYWx1ZTogVHlwZWRPcHRpb25bXSA9IFtcbiAgICBuZXcgVHlwZWRPcHRpb24oJ3Bhc3N3b3JkJywgJ2xpbWl0LnZhbGlkaXR5JywgJ251bWJlcicsIG51bGwpLFxuICAgIG5ldyBUeXBlZE9wdGlvbigncGFzc3dvcmQnLCAnZW5mb3JjZS5zdHJlbmd0aCcsICdib29sZWFuJywgZmFsc2UpLFxuICAgIG5ldyBUeXBlZE9wdGlvbigndHdvLWZhY3Rvci1hdXRoZW50aWNhdGlvbicsICd0ZW5hbnQtc2NvcGUtc2V0dGluZ3MuZW5hYmxlZCcsICdib29sZWFuJywgZmFsc2UpLFxuICAgIG5ldyBUeXBlZE9wdGlvbigndHdvLWZhY3Rvci1hdXRoZW50aWNhdGlvbicsICdlbmFibGVkJywgJ2Jvb2xlYW4nLCBmYWxzZSksXG4gICAgLy8gbm90ZTogdGhpcyBkZWZpbml0aW9uIGlzIGluY29uc2lzdGVudCB3aXRoIGJhY2tlbmQgYW5kIGlzIG92ZXJyaWRkZW4gaW4gZ2V0U3lzdGVtT3B0aW9ucyRcbiAgICBuZXcgVHlwZWRPcHRpb24oJ3R3by1mYWN0b3ItYXV0aGVudGljYXRpb24nLCAnZW5mb3JjZWQnLCAnYm9vbGVhbicsIGZhbHNlKSxcbiAgICBuZXcgVHlwZWRPcHRpb24oJ3R3by1mYWN0b3ItYXV0aGVudGljYXRpb24nLCAnZW5mb3JjZWQuZ3JvdXAnLCAnc3RyaW5nJywgJycpXG4gIF07XG5cbiAgcHJpdmF0ZSB0ZW5hbnRPcHRpb25zV2l0aERlZmF1bHRWYWx1ZTogVHlwZWRPcHRpb25bXSA9IFtcbiAgICBuZXcgVHlwZWRPcHRpb24oJ3Bhc3N3b3JkJywgJ2xpbWl0LnZhbGlkaXR5JywgJ251bWJlcicsIDApLFxuICAgIG5ldyBUeXBlZE9wdGlvbigncGFzc3dvcmQnLCAnc3RyZW5ndGgudmFsaWRpdHknLCAnYm9vbGVhbicsIGZhbHNlKSxcbiAgICBuZXcgVHlwZWRPcHRpb24oJ3R3by1mYWN0b3ItYXV0aGVudGljYXRpb24nLCAnZW5hYmxlZCcsICdib29sZWFuJywgZmFsc2UpLFxuICAgIG5ldyBUeXBlZE9wdGlvbigndHdvLWZhY3Rvci1hdXRoZW50aWNhdGlvbicsICd0b2tlbi52YWxpZGl0eScsICdudW1iZXInLCA0MzIwMCksIC8vIDMwIGRheXNcbiAgICBuZXcgVHlwZWRPcHRpb24oJ3R3by1mYWN0b3ItYXV0aGVudGljYXRpb24nLCAncGluLnZhbGlkaXR5JywgJ251bWJlcicsIDMwKSxcbiAgICBuZXcgVHlwZWRPcHRpb24oJ3R3by1mYWN0b3ItYXV0aGVudGljYXRpb24nLCAnZW5mb3JjZWQnLCAnYm9vbGVhbicsIGZhbHNlKSxcbiAgICBuZXcgVHlwZWRPcHRpb24oJ3R3by1mYWN0b3ItYXV0aGVudGljYXRpb24nLCAnc3RyYXRlZ3knLCAnc3RyaW5nJywgJ1NNUycpLFxuICAgIG5ldyBUeXBlZE9wdGlvbignb2F1dGguaW50ZXJuYWwnLCAnYmFzaWMtdG9rZW4ubGlmZXNwYW4uc2Vjb25kcycsICdudW1iZXInLCBudWxsKSxcbiAgICBuZXcgVHlwZWRPcHRpb24oJ2NvbmZpZ3VyYXRpb24nLCAndGVuYW50LmxvZ2luLmlnbm9yZS1jYXNlJywgJ2Jvb2xlYW4nLCBmYWxzZSlcbiAgXTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHRlbmFudExvZ2luT3B0aW9uc1NlcnZpY2U6IFRlbmFudExvZ2luT3B0aW9uc1NlcnZpY2UsXG4gICAgcHJpdmF0ZSB0ZW5hbnRPcHRpb25zU2VydmljZTogVGVuYW50T3B0aW9uc1NlcnZpY2UsXG4gICAgcHJpdmF0ZSBzeXN0ZW1PcHRpb25zU2VydmljZTogU3lzdGVtT3B0aW9uc1NlcnZpY2UsXG4gICAgcHJpdmF0ZSBhcHBTdGF0ZTogQXBwU3RhdGVTZXJ2aWNlLFxuICAgIHByaXZhdGUgdGVuYW50VWlTZXJ2aWNlOiBUZW5hbnRVaVNlcnZpY2UsXG4gICAgcHJpdmF0ZSB0ZW5hbnRMb2dpbk9wdGlvbk1hcHBlcjogVGVuYW50TG9naW5PcHRpb25NYXBwZXIsXG4gICAgcHJpdmF0ZSB0ZW5hbnRTZXJ2aWNlOiBUZW5hbnRTZXJ2aWNlXG4gICkge31cblxuICBnZXRBdXRoQ29uZmlndXJhdGlvbiQoKTogT2JzZXJ2YWJsZTxBdXRoQ29uZmlndXJhdGlvbj4ge1xuICAgIGNvbnN0IGxvZ2luT3B0aW9ucyQgPSB0aGlzLmdldExvZ2luT3B0aW9ucyQoKTtcbiAgICByZXR1cm4gZm9ya0pvaW4oe1xuICAgICAgbG9naW5PcHRpb25zOiB0aGlzLm1hcChsb2dpbk9wdGlvbnMkKSxcbiAgICAgIHRlbmFudE9wdGlvbnM6IHRoaXMuZ2V0VGVuYW50T3B0aW9ucyQoKSxcbiAgICAgIHN5c3RlbU9wdGlvbnM6IHRoaXMuZ2V0U3lzdGVtT3B0aW9ucyQoKSxcbiAgICAgIHNtc0dhdGV3YXlBdmFpbGFibGU6IHRoaXMuaXNTbXNBcHBsaWNhdGlvbkF2YWlsYWJsZSQoKSxcbiAgICAgIHByZWZlcnJlZExvZ2luT3B0aW9uVHlwZTogdGhpcy5nZXRQcmVmZXJyZWRMb2dpbk9wdGlvblR5cGUkKGxvZ2luT3B0aW9ucyQpXG4gICAgfSk7XG4gIH1cblxuICBzYXZlKG5ld0F1dGhDb25maWd1cmF0aW9uOiBBdXRoQ29uZmlndXJhdGlvbiwgcHJldmlvdXNBdXRoQ29uZmlndXJhdGlvbjogQXV0aENvbmZpZ3VyYXRpb24pIHtcbiAgICBjb25zdCB0ZW5hbnRPcHRpb25zID0gdGhpcy5wcmVwYXJlVGVuYW50T3B0aW9ucyhcbiAgICAgIG5ld0F1dGhDb25maWd1cmF0aW9uLFxuICAgICAgcHJldmlvdXNBdXRoQ29uZmlndXJhdGlvblxuICAgICk7XG4gICAgY29uc3QgdXBkYXRlVGVuYW50T3B0aW9ucyA9IHRlbmFudE9wdGlvbnMubWFwKHRlbmFudE9wdGlvbiA9PiB7XG4gICAgICBjb25zdCBmaXhlZE9wdGlvbiA9IHRoaXMuZml4VGZhU3RyYXRlZ3kodGVuYW50T3B0aW9uKTtcbiAgICAgIGlmIChmaXhlZE9wdGlvbikge1xuICAgICAgICByZXR1cm4gZml4ZWRPcHRpb247XG4gICAgICB9XG4gICAgICByZXR1cm4gdGhpcy50ZW5hbnRPcHRpb25zU2VydmljZS5jcmVhdGUodGVuYW50T3B0aW9uKTtcbiAgICB9KTtcbiAgICBjb25zdCBiYXNpY0xvZ2luT3B0aW9uID0gdGhpcy5wcmVwYXJlQmFzaWNMb2dpbk9wdGlvbihcbiAgICAgIG5ld0F1dGhDb25maWd1cmF0aW9uLFxuICAgICAgcHJldmlvdXNBdXRoQ29uZmlndXJhdGlvblxuICAgICk7XG4gICAgY29uc3Qgb2F1dGhJbnRlcm5hbExvZ2luT3B0aW9uID0gdGhpcy5wcmVwYXJlT2F1dGhJbnRlcm5hbExvZ2luT3B0aW9uKFxuICAgICAgbmV3QXV0aENvbmZpZ3VyYXRpb24sXG4gICAgICBwcmV2aW91c0F1dGhDb25maWd1cmF0aW9uXG4gICAgKTtcblxuICAgIHJldHVybiBQcm9taXNlLmFsbChbXG4gICAgICB0aGlzLnNhdmVPclVwZGF0ZUxvZ2luT3B0aW9uKGJhc2ljTG9naW5PcHRpb24pLFxuICAgICAgdGhpcy5zYXZlT3JVcGRhdGVMb2dpbk9wdGlvbihvYXV0aEludGVybmFsTG9naW5PcHRpb24pLFxuICAgICAgLi4udXBkYXRlVGVuYW50T3B0aW9uc1xuICAgIF0pO1xuICB9XG5cbiAgcHJpdmF0ZSBtYXAobG9naW5PcHRpb25zJDogT2JzZXJ2YWJsZTxJVGVuYW50TG9naW5PcHRpb25bXT4pOiBPYnNlcnZhYmxlPFRlbmFudExvZ2luT3B0aW9uW10+IHtcbiAgICByZXR1cm4gbG9naW5PcHRpb25zJC5waXBlKFxuICAgICAgbWFwKGxvZ2luT3B0aW9ucyA9PlxuICAgICAgICBsb2dpbk9wdGlvbnMubWFwKGxvZ2luT3B0aW9uID0+IHRoaXMudGVuYW50TG9naW5PcHRpb25NYXBwZXIubWFwVG8obG9naW5PcHRpb24pKVxuICAgICAgKVxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIHNhdmVPclVwZGF0ZUxvZ2luT3B0aW9uKFxuICAgIGxvZ2luT3B0aW9uOiBJVGVuYW50TG9naW5PcHRpb25cbiAgKTogUHJvbWlzZTxJUmVzdWx0PElUZW5hbnRMb2dpbk9wdGlvbj4+IHtcbiAgICByZXR1cm4gbG9naW5PcHRpb24uaWRcbiAgICAgID8gdGhpcy50ZW5hbnRMb2dpbk9wdGlvbnNTZXJ2aWNlLnVwZGF0ZShsb2dpbk9wdGlvbilcbiAgICAgIDogdGhpcy50ZW5hbnRMb2dpbk9wdGlvbnNTZXJ2aWNlLmNyZWF0ZShsb2dpbk9wdGlvbik7XG4gIH1cblxuICBwcml2YXRlIHByZXBhcmVCYXNpY0xvZ2luT3B0aW9uKFxuICAgIG5ld0F1dGhDb25maWd1cmF0aW9uOiBBdXRoQ29uZmlndXJhdGlvbixcbiAgICBwcmV2aW91c0F1dGhDb25maWd1cmF0aW9uOiBBdXRoQ29uZmlndXJhdGlvblxuICApOiBJVGVuYW50TG9naW5PcHRpb24ge1xuICAgIGNvbnN0IGJhc2ljTG9naW5PcHRpb24gPSB0aGlzLm9yaWdpbmFsTG9naW5PcHRpb25XaXRoRGVmYXVsdHMoXG4gICAgICBwcmV2aW91c0F1dGhDb25maWd1cmF0aW9uLFxuICAgICAgVGVuYW50TG9naW5PcHRpb25UeXBlLkJBU0lDXG4gICAgKTtcbiAgICBiYXNpY0xvZ2luT3B0aW9uLnZpc2libGVPbkxvZ2luUGFnZSA9IHRoaXMudmlzaWJsZU9uTG9naW5QYWdlKFxuICAgICAgbmV3QXV0aENvbmZpZ3VyYXRpb24sXG4gICAgICBUZW5hbnRMb2dpbk9wdGlvblR5cGUuQkFTSUNcbiAgICApO1xuICAgIHJldHVybiB0aGlzLnRlbmFudExvZ2luT3B0aW9uTWFwcGVyLm1hcEZyb20oXG4gICAgICBiYXNpY0xvZ2luT3B0aW9uLFxuICAgICAgdGhpcy5nZXRMb2dpbk9wdGlvbkZyb21BdXRoQ29uZmlndXJhdGlvbihuZXdBdXRoQ29uZmlndXJhdGlvbiwgVGVuYW50TG9naW5PcHRpb25UeXBlLkJBU0lDKVxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIHByZXBhcmVPYXV0aEludGVybmFsTG9naW5PcHRpb24oXG4gICAgbmV3QXV0aENvbmZpZ3VyYXRpb246IEF1dGhDb25maWd1cmF0aW9uLFxuICAgIHByZXZpb3VzQXV0aENvbmZpZ3VyYXRpb246IEF1dGhDb25maWd1cmF0aW9uXG4gICk6IElUZW5hbnRMb2dpbk9wdGlvbiB7XG4gICAgY29uc3Qgb2F1dGhJbnRlcm5hbExvZ2luT3B0aW9uID0gdGhpcy5vcmlnaW5hbExvZ2luT3B0aW9uV2l0aERlZmF1bHRzKFxuICAgICAgcHJldmlvdXNBdXRoQ29uZmlndXJhdGlvbixcbiAgICAgIFRlbmFudExvZ2luT3B0aW9uVHlwZS5PQVVUSDJfSU5URVJOQUxcbiAgICApO1xuICAgIG9hdXRoSW50ZXJuYWxMb2dpbk9wdGlvbi52aXNpYmxlT25Mb2dpblBhZ2UgPSB0aGlzLnZpc2libGVPbkxvZ2luUGFnZShcbiAgICAgIG5ld0F1dGhDb25maWd1cmF0aW9uLFxuICAgICAgVGVuYW50TG9naW5PcHRpb25UeXBlLk9BVVRIMl9JTlRFUk5BTFxuICAgICk7XG4gICAgcmV0dXJuIHRoaXMudGVuYW50TG9naW5PcHRpb25NYXBwZXIubWFwRnJvbShcbiAgICAgIG9hdXRoSW50ZXJuYWxMb2dpbk9wdGlvbixcbiAgICAgIHRoaXMuZ2V0TG9naW5PcHRpb25Gcm9tQXV0aENvbmZpZ3VyYXRpb24oXG4gICAgICAgIG5ld0F1dGhDb25maWd1cmF0aW9uLFxuICAgICAgICBUZW5hbnRMb2dpbk9wdGlvblR5cGUuT0FVVEgyX0lOVEVSTkFMXG4gICAgICApXG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgb3JpZ2luYWxMb2dpbk9wdGlvbldpdGhEZWZhdWx0cyhcbiAgICBwcmV2aW91c0F1dGhDb25maWd1cmF0aW9uOiBBdXRoQ29uZmlndXJhdGlvbixcbiAgICBsb2dpbk9wdGlvblR5cGU6IFRlbmFudExvZ2luT3B0aW9uVHlwZVxuICApOiBUZW5hbnRMb2dpbk9wdGlvbiB7XG4gICAgcmV0dXJuIGRlZmF1bHRzKFxuICAgICAge30sXG4gICAgICB0aGlzLmdldExvZ2luT3B0aW9uRnJvbUF1dGhDb25maWd1cmF0aW9uKHByZXZpb3VzQXV0aENvbmZpZ3VyYXRpb24sIGxvZ2luT3B0aW9uVHlwZSksXG4gICAgICB0aGlzLmdldERlZmF1bHRMb2dpbk9wdGlvbihsb2dpbk9wdGlvblR5cGUpXG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0TG9naW5PcHRpb25Gcm9tQXV0aENvbmZpZ3VyYXRpb24oXG4gICAgYXV0aENvbmZpZ3VyYXRpb246IEF1dGhDb25maWd1cmF0aW9uLFxuICAgIGxvZ2luT3B0aW9uVHlwZTogVGVuYW50TG9naW5PcHRpb25UeXBlXG4gICkge1xuICAgIHJldHVybiBhdXRoQ29uZmlndXJhdGlvbi5sb2dpbk9wdGlvbnMuZmluZChsb2dpbk9wdGlvbiA9PiBsb2dpbk9wdGlvbi50eXBlID09PSBsb2dpbk9wdGlvblR5cGUpO1xuICB9XG5cbiAgcHJpdmF0ZSB2aXNpYmxlT25Mb2dpblBhZ2UoXG4gICAgYXV0aENvbmZpZ3VyYXRpb246IEF1dGhDb25maWd1cmF0aW9uLFxuICAgIGxvZ2luT3B0aW9uVHlwZTogVGVuYW50TG9naW5PcHRpb25UeXBlXG4gICk6IGJvb2xlYW4ge1xuICAgIHJldHVybiBhdXRoQ29uZmlndXJhdGlvbi5wcmVmZXJyZWRMb2dpbk9wdGlvblR5cGUgPT09IGxvZ2luT3B0aW9uVHlwZTtcbiAgfVxuXG4gIHByaXZhdGUgcHJlcGFyZVRlbmFudE9wdGlvbnMoXG4gICAgbmV3QXV0aENvbmZpZ3VyYXRpb246IEF1dGhDb25maWd1cmF0aW9uLFxuICAgIHByZXZpb3VzQXV0aENvbmZpZ3VyYXRpb246IEF1dGhDb25maWd1cmF0aW9uXG4gICk6IElUZW5hbnRPcHRpb25bXSB7XG4gICAgY29uc3QgZ2V0VmFsdWUgPSAoYXV0aENmZywgdGVuYW50T3B0aW9uKSA9PlxuICAgICAgYXV0aENmZy50ZW5hbnRPcHRpb25zW3RlbmFudE9wdGlvbi5jYXRlZ29yeV1bdGVuYW50T3B0aW9uLmtleV07XG4gICAgY29uc3QgaGFzQ2hhbmdlZCA9IHRlbmFudE9wdGlvbiA9PlxuICAgICAgZ2V0VmFsdWUobmV3QXV0aENvbmZpZ3VyYXRpb24sIHRlbmFudE9wdGlvbikgIT09XG4gICAgICBnZXRWYWx1ZShwcmV2aW91c0F1dGhDb25maWd1cmF0aW9uLCB0ZW5hbnRPcHRpb24pO1xuXG4gICAgcmV0dXJuIHRoaXMudGVuYW50T3B0aW9uc1dpdGhEZWZhdWx0VmFsdWVcbiAgICAgIC5maWx0ZXIodGVuYW50T3B0aW9uID0+IGdldFZhbHVlKG5ld0F1dGhDb25maWd1cmF0aW9uLCB0ZW5hbnRPcHRpb24pICE9PSBudWxsKVxuICAgICAgLmZpbHRlcih0ZW5hbnRPcHRpb24gPT4gaGFzQ2hhbmdlZCh0ZW5hbnRPcHRpb24pKVxuICAgICAgLm1hcCh0ZW5hbnRPcHRpb24gPT4gKHtcbiAgICAgICAgY2F0ZWdvcnk6IHRlbmFudE9wdGlvbi5jYXRlZ29yeSxcbiAgICAgICAga2V5OiB0ZW5hbnRPcHRpb24ua2V5LFxuICAgICAgICB2YWx1ZTogZ2V0VmFsdWUobmV3QXV0aENvbmZpZ3VyYXRpb24sIHRlbmFudE9wdGlvbikudG9TdHJpbmcoKVxuICAgICAgfSkpO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRMb2dpbk9wdGlvbnMkKCk6IE9ic2VydmFibGU8SVRlbmFudExvZ2luT3B0aW9uW10+IHtcbiAgICByZXR1cm4gZm9ya0pvaW4oW1xuICAgICAgdGhpcy5nZXRMb2dpbk9wdGlvbihUZW5hbnRMb2dpbk9wdGlvblR5cGUuT0FVVEgyKSxcbiAgICAgIHRoaXMuZ2V0TG9naW5PcHRpb24oVGVuYW50TG9naW5PcHRpb25UeXBlLkJBU0lDKSxcbiAgICAgIHRoaXMuZ2V0TG9naW5PcHRpb24oVGVuYW50TG9naW5PcHRpb25UeXBlLk9BVVRIMl9JTlRFUk5BTClcbiAgICBdKS5waXBlKG1hcChsb2dpbk9wdGlvbnMgPT4gbG9naW5PcHRpb25zLmZpbHRlcihsb2dpbk9wdGlvbiA9PiAhIWxvZ2luT3B0aW9uKSkpO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRMb2dpbk9wdGlvbihcbiAgICB0ZW5hbnRMb2dpbk9wdGlvblR5cGU6IFRlbmFudExvZ2luT3B0aW9uVHlwZVxuICApOiBPYnNlcnZhYmxlPElUZW5hbnRMb2dpbk9wdGlvbj4ge1xuICAgIHJldHVybiBmcm9tKHRoaXMudGVuYW50TG9naW5PcHRpb25zU2VydmljZS5kZXRhaWwodGVuYW50TG9naW5PcHRpb25UeXBlKSkucGlwZShcbiAgICAgIG1hcChyZXMgPT4gcmVzLmRhdGEpLFxuICAgICAgY2F0Y2hFcnJvcigoKSA9PlxuICAgICAgICB0ZW5hbnRMb2dpbk9wdGlvblR5cGUgIT09IFRlbmFudExvZ2luT3B0aW9uVHlwZS5PQVVUSDJcbiAgICAgICAgICA/IG9mKHRoaXMuZ2V0RGVmYXVsdExvZ2luT3B0aW9uKHRlbmFudExvZ2luT3B0aW9uVHlwZSkpXG4gICAgICAgICAgOiBvZihudWxsKVxuICAgICAgKVxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIGdldFByZWZlcnJlZExvZ2luT3B0aW9uVHlwZSQoXG4gICAgbG9naW5PcHRpb25zJDogT2JzZXJ2YWJsZTxJVGVuYW50TG9naW5PcHRpb25bXT5cbiAgKTogT2JzZXJ2YWJsZTxUZW5hbnRMb2dpbk9wdGlvblR5cGU+IHtcbiAgICByZXR1cm4gbG9naW5PcHRpb25zJC5waXBlKFxuICAgICAgbWFwKGxvZ2luT3B0aW9ucyA9PiB7XG4gICAgICAgIHJldHVybiB0aGlzLnRlbmFudFVpU2VydmljZS5nZXRQcmVmZXJyZWRMb2dpbk9wdGlvbihsb2dpbk9wdGlvbnMpLnR5cGU7XG4gICAgICB9KVxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIGdldFRlbmFudE9wdGlvbnMkKCk6IE9ic2VydmFibGU8T3B0aW9ucz4ge1xuICAgIHJldHVybiBmb3JrSm9pbihcbiAgICAgIHRoaXMudGVuYW50T3B0aW9uc1dpdGhEZWZhdWx0VmFsdWUubWFwKChvcHRpb246IFR5cGVkT3B0aW9uKSA9PlxuICAgICAgICBmcm9tKHRoaXMudGVuYW50T3B0aW9uc1NlcnZpY2UuZGV0YWlsKG9wdGlvbikpLnBpcGUoXG4gICAgICAgICAgbWFwKHJlcyA9PiB7XG4gICAgICAgICAgICBvcHRpb24uYXBwbHkocmVzLmRhdGEpO1xuICAgICAgICAgICAgcmV0dXJuIG9wdGlvbjtcbiAgICAgICAgICB9KSxcbiAgICAgICAgICBjYXRjaEVycm9yKCgpID0+IG9mKG9wdGlvbikpXG4gICAgICAgIClcbiAgICAgIClcbiAgICApLnBpcGUobWFwKG9wdGlvbnMgPT4gdGhpcy5nZXRPcHRpb25zT2JqZWN0KG9wdGlvbnMpKSk7XG4gIH1cblxuICBwcml2YXRlIGdldFN5c3RlbU9wdGlvbnMkKCk6IE9ic2VydmFibGU8T3B0aW9ucz4ge1xuICAgIHJldHVybiBmb3JrSm9pbihcbiAgICAgIHRoaXMuc3lzdGVtT3B0aW9uc1dpdGhEZWZhdWx0VmFsdWUubWFwKChvcHRpb246IFR5cGVkT3B0aW9uKSA9PiB7XG4gICAgICAgIGNvbnN0IGZpeGVkT3B0aW9uID0gdGhpcy5maXhUZmFFbmZvcmNlZFN5c3RlbU9wdGlvbihvcHRpb24pO1xuICAgICAgICBpZiAoZml4ZWRPcHRpb24pIHtcbiAgICAgICAgICByZXR1cm4gZml4ZWRPcHRpb247XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZnJvbSh0aGlzLnN5c3RlbU9wdGlvbnNTZXJ2aWNlLmRldGFpbChvcHRpb24pKS5waXBlKFxuICAgICAgICAgIG1hcChyZXMgPT4ge1xuICAgICAgICAgICAgb3B0aW9uLmFwcGx5KHJlcy5kYXRhKTtcbiAgICAgICAgICAgIHJldHVybiBvcHRpb247XG4gICAgICAgICAgfSksXG4gICAgICAgICAgY2F0Y2hFcnJvcigoKSA9PiBvZihvcHRpb24pKVxuICAgICAgICApO1xuICAgICAgfSlcbiAgICApLnBpcGUobWFwKG9wdGlvbnMgPT4gdGhpcy5nZXRPcHRpb25zT2JqZWN0KG9wdGlvbnMpKSk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBhbiBvYnNlcnZhYmxlIHdpdGggZml4ZWQgYHR3by1mYWN0b3ItYXV0aGVudGljYXRpb24uZW5mb3JjZWRgIHN5c3RlbSBvcHRpb24gb3IgbnVsbC5cbiAgICogVGhpcyBtZXRob2QgZml4ZXMgcHJvYmxlbSB3aXRoIGluY29uc2lzdGVudCB2YWx1ZS4gU3lzdGVtIG9wdGlvbiBgdHdvLWZhY3Rvci1hdXRoZW50aWNhdGlvbi5lbmZvcmNlZGAgaXMgbGlzdCBvZiB0ZW5hbnRzIHdoZW4gVUkgdXNpbmcgYm9vbGVhbiB2YWx1ZS5cbiAgICogVGhpcyBwYXJ0IHdpbGwgYmUgcmVtb3ZlZCBhZnRlciBpbXBsZW1lbnRpbmcgbmV3IGVuZHBvaW50IGluIE1UTS01MDQ5MC5cbiAgICovXG4gIHByaXZhdGUgZml4VGZhRW5mb3JjZWRTeXN0ZW1PcHRpb24ob3B0aW9uOiBUeXBlZE9wdGlvbik6IE9ic2VydmFibGU8VHlwZWRPcHRpb24+IHtcbiAgICBpZiAob3B0aW9uLmNhdGVnb3J5ID09PSAndHdvLWZhY3Rvci1hdXRoZW50aWNhdGlvbicgJiYgb3B0aW9uLmtleSA9PT0gJ2VuZm9yY2VkJykge1xuICAgICAgcmV0dXJuIGZyb20odGhpcy50ZW5hbnRTZXJ2aWNlLmdldFRmYVNldHRpbmdzKHRoaXMudGVuYW50VWlTZXJ2aWNlLmN1cnJlbnRUZW5hbnQpKS5waXBlKFxuICAgICAgICBtYXAodGZhU2V0dGluZ3MgPT4ge1xuICAgICAgICAgIG9wdGlvbi52YWx1ZSA9IHRmYVNldHRpbmdzLmVuZm9yY2VkT25TeXN0ZW1MZXZlbC50b1N0cmluZygpO1xuICAgICAgICAgIHJldHVybiBvcHRpb247XG4gICAgICAgIH0pXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGEgcHJvbWlzZSBvciBudWxsLlxuICAgKiBUaGlzIG1ldGhvZCBpcyBuZWVkZWQgbm93LCBiZWNhdXNlIHNpbXBseSBjaGFuZ2luZyBURkEgc3RyYXRlZ3kgdGVuYW50IG9wdGlvbiBkb2VzIG5vdCB0cmlnZ2VyIGFsbCB0aGUgbmVjZXNzYXJ5IGJhY2tlbmQgbG9naWMgdG8gYXBwbHkgdGhlIGNoYW5nZSwgdGhlcmVmb3JlLCB3ZSBuZWVkIHRvIGNhbGwgdGVuYW50J3MgYC90ZmFgIGVuZHBvaW50LCB3aGljaCBhcHBsaWVzIHRoZSBjaGFuZ2UgZm9yIGFsbCB1c2VycyBpbiB0aGUgdGVuYW50LlxuICAgKiBXaXRoaW4gTVRNLTUwNDkwLCB3ZSdyZSBnb2luZyB0byBzaW1wbGlmeSB0aGUgcHJvY2VzcyBmdXJ0aGVyIGJ5IHJlcGxhY2luZyBtdWx0aXBsZSByZXF1ZXN0cyB3aXRoIG9uZSBuZXcgZW5kcG9pbnQgdGhhdCB3aWxsIGhhbmRsZSBzYXZpbmcgb2YgYWxsIGF1dGhlbnRpY2F0aW9uIHNldHRpbmdzLlxuICAgKi9cbiAgcHJpdmF0ZSBmaXhUZmFTdHJhdGVneShvcHRpb246IElUZW5hbnRPcHRpb24pOiBQcm9taXNlPElSZXN1bHQ8bnVsbD4+IHtcbiAgICBpZiAob3B0aW9uLmNhdGVnb3J5ID09PSAndHdvLWZhY3Rvci1hdXRoZW50aWNhdGlvbicgJiYgb3B0aW9uLmtleSA9PT0gJ3N0cmF0ZWd5Jykge1xuICAgICAgY29uc3Qgc3RyYXRlZ3k6IFRmYVN0cmF0ZWd5ID0gb3B0aW9uLnZhbHVlID09PSAnU01TJyA/IFRmYVN0cmF0ZWd5LlNNUyA6IFRmYVN0cmF0ZWd5LlRPVFA7XG4gICAgICByZXR1cm4gdGhpcy50ZW5hbnRTZXJ2aWNlLnVwZGF0ZVRmYVN0cmF0ZWd5KHRoaXMudGVuYW50VWlTZXJ2aWNlLmN1cnJlbnRUZW5hbnQsIHN0cmF0ZWd5KTtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBwcml2YXRlIGlzU21zQXBwbGljYXRpb25BdmFpbGFibGUkKCk6IE9ic2VydmFibGU8Ym9vbGVhbj4ge1xuICAgIHJldHVybiBmcm9tKHRoaXMuYXBwU3RhdGUuaXNBcHBsaWNhdGlvbkF2YWlsYWJsZSgnc21zLWdhdGV3YXknKSk7XG4gIH1cblxuICBwcml2YXRlIGdldE9wdGlvbnNPYmplY3Qob3B0aW9uczogVHlwZWRPcHRpb25bXSkge1xuICAgIHJldHVybiBvcHRpb25zLnJlZHVjZSgob3B0aW9uc09iamVjdCwgb3B0aW9uKSA9PiB7XG4gICAgICBvcHRpb25zT2JqZWN0W29wdGlvbi5jYXRlZ29yeV0gPSBvcHRpb25zT2JqZWN0W29wdGlvbi5jYXRlZ29yeV0gfHwge307XG4gICAgICBvcHRpb25zT2JqZWN0W29wdGlvbi5jYXRlZ29yeV1bb3B0aW9uLmtleV0gPSBvcHRpb24uZ2V0VmFsdWUoKTtcbiAgICAgIHJldHVybiBvcHRpb25zT2JqZWN0O1xuICAgIH0sIHt9KTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0RGVmYXVsdExvZ2luT3B0aW9uKHRlbmFudExvZ2luT3B0aW9uVHlwZTogVGVuYW50TG9naW5PcHRpb25UeXBlKTogSVRlbmFudExvZ2luT3B0aW9uIHtcbiAgICByZXR1cm4ge1xuICAgICAgdXNlck1hbmFnZW1lbnRTb3VyY2U6IFVzZXJNYW5hZ2VtZW50U291cmNlLklOVEVSTkFMLFxuICAgICAgZ3JhbnRUeXBlOiBHcmFudFR5cGUuUEFTU1dPUkQsXG4gICAgICBwcm92aWRlck5hbWU6ICdDdW11bG9jaXR5JyxcbiAgICAgIHZpc2libGVPbkxvZ2luUGFnZTogZmFsc2UsXG4gICAgICB0eXBlOiB0ZW5hbnRMb2dpbk9wdGlvblR5cGVcbiAgICB9O1xuICB9XG59XG4iXX0=