UNPKG

aws-cdk

Version:

AWS CDK CLI, the command line tool for CDK apps

357 lines 53.8 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var SdkProvider_1; Object.defineProperty(exports, "__esModule", { value: true }); exports.SdkProvider = void 0; exports.initContextProviderSdk = initContextProviderSdk; const os = require("os"); const cx_api_1 = require("@aws-cdk/cx-api"); const credential_providers_1 = require("@aws-sdk/credential-providers"); const awscli_compatible_1 = require("./awscli-compatible"); const cached_1 = require("./cached"); const credential_plugins_1 = require("./credential-plugins"); const provider_caching_1 = require("./provider-caching"); const sdk_1 = require("./sdk"); const tracing_1 = require("./tracing"); const api_1 = require("../../../../@aws-cdk/tmp-toolkit-helpers/src/api"); const logging_1 = require("../../logging"); const util_1 = require("../../util"); const mode_1 = require("../plugin/mode"); const CACHED_ACCOUNT = Symbol('cached_account'); /** * Creates instances of the AWS SDK appropriate for a given account/region. * * Behavior is as follows: * * - First, a set of "base" credentials are established * - If a target environment is given and the default ("current") SDK credentials are for * that account, return those; otherwise * - If a target environment is given, scan all credential provider plugins * for credentials, and return those if found; otherwise * - Return default ("current") SDK credentials, noting that they might be wrong. * * - Second, a role may optionally need to be assumed. Use the base credentials * established in the previous process to assume that role. * - If assuming the role fails and the base credentials are for the correct * account, return those. This is a fallback for people who are trying to interact * with a Default Synthesized stack and already have right credentials setup. * * Typical cases we see in the wild: * - Credential plugin setup that, although not recommended, works for them * - Seeded terminal with `ReadOnly` credentials in order to do `cdk diff`--the `ReadOnly` * role doesn't have `sts:AssumeRole` and will fail for no real good reason. */ let SdkProvider = SdkProvider_1 = class SdkProvider { /** * Create a new SdkProvider which gets its defaults in a way that behaves like the AWS CLI does * * The AWS SDK for JS behaves slightly differently from the AWS CLI in a number of ways; see the * class `AwsCliCompatible` for the details. */ static async withAwsCliCompatibleDefaults(options = {}) { (0, tracing_1.callTrace)(SdkProvider_1.withAwsCliCompatibleDefaults.name, SdkProvider_1.constructor.name, options.logger); const credentialProvider = await awscli_compatible_1.AwsCliCompatible.credentialChainBuilder({ profile: options.profile, httpOptions: options.httpOptions, logger: options.logger, }); const region = await awscli_compatible_1.AwsCliCompatible.region(options.profile); const requestHandler = awscli_compatible_1.AwsCliCompatible.requestHandlerBuilder(options.httpOptions); return new SdkProvider_1(credentialProvider, region, requestHandler, options.logger); } constructor(defaultCredentialProvider, /** * Default region */ defaultRegion, requestHandler = {}, logger) { this.defaultCredentialProvider = defaultCredentialProvider; this.defaultRegion = defaultRegion; this.requestHandler = requestHandler; this.logger = logger; this.plugins = new credential_plugins_1.CredentialPlugins(); } /** * Return an SDK which can do operations in the given environment * * The `environment` parameter is resolved first (see `resolveEnvironment()`). */ async forEnvironment(environment, mode, options, quiet = false) { const env = await this.resolveEnvironment(environment); const baseCreds = await this.obtainBaseCredentials(env.account, mode); // At this point, we need at least SOME credentials if (baseCreds.source === 'none') { throw new api_1.AuthenticationError(fmtObtainCredentialsError(env.account, baseCreds)); } // Simple case is if we don't need to "assumeRole" here. If so, we must now have credentials for the right // account. if (options?.assumeRoleArn === undefined) { if (baseCreds.source === 'incorrectDefault') { throw new api_1.AuthenticationError(fmtObtainCredentialsError(env.account, baseCreds)); } // Our current credentials must be valid and not expired. Confirm that before we get into doing // actual CloudFormation calls, which might take a long time to hang. const sdk = new sdk_1.SDK(baseCreds.credentials, env.region, this.requestHandler, this.logger); await sdk.validateCredentials(); return { sdk, didAssumeRole: false }; } try { // We will proceed to AssumeRole using whatever we've been given. const sdk = await this.withAssumedRole(baseCreds, options.assumeRoleArn, options.assumeRoleExternalId, options.assumeRoleAdditionalOptions, env.region); return { sdk, didAssumeRole: true }; } catch (err) { if (err.name === 'ExpiredToken') { throw err; } // AssumeRole failed. Proceed and warn *if and only if* the baseCredentials were already for the right account // or returned from a plugin. This is to cover some current setups for people using plugins or preferring to // feed the CLI credentials which are sufficient by themselves. Prefer to assume the correct role if we can, // but if we can't then let's just try with available credentials anyway. if (baseCreds.source === 'correctDefault' || baseCreds.source === 'plugin') { (0, logging_1.debug)(err.message); const logger = quiet ? logging_1.debug : logging_1.warning; logger(`${fmtObtainedCredentials(baseCreds)} could not be used to assume '${options.assumeRoleArn}', but are for the right account. Proceeding anyway.`); return { sdk: new sdk_1.SDK(baseCreds.credentials, env.region, this.requestHandler, this.logger), didAssumeRole: false, }; } throw err; } } /** * Return the partition that base credentials are for * * Returns `undefined` if there are no base credentials. */ async baseCredentialsPartition(environment, mode) { const env = await this.resolveEnvironment(environment); const baseCreds = await this.obtainBaseCredentials(env.account, mode); if (baseCreds.source === 'none') { return undefined; } return (await new sdk_1.SDK(baseCreds.credentials, env.region, this.requestHandler, this.logger).currentAccount()).partition; } /** * Resolve the environment for a stack * * Replaces the magic values `UNKNOWN_REGION` and `UNKNOWN_ACCOUNT` * with the defaults for the current SDK configuration (`~/.aws/config` or * otherwise). * * It is an error if `UNKNOWN_ACCOUNT` is used but the user hasn't configured * any SDK credentials. */ async resolveEnvironment(env) { const region = env.region !== cx_api_1.UNKNOWN_REGION ? env.region : this.defaultRegion; const account = env.account !== cx_api_1.UNKNOWN_ACCOUNT ? env.account : (await this.defaultAccount())?.accountId; if (!account) { throw new api_1.AuthenticationError('Unable to resolve AWS account to use. It must be either configured when you define your CDK Stack, or through the environment'); } return { region, account, name: cx_api_1.EnvironmentUtils.format(account, region), }; } /** * The account we'd auth into if we used default credentials. * * Default credentials are the set of ambiently configured credentials using * one of the environment variables, or ~/.aws/credentials, or the *one* * profile that was passed into the CLI. * * Might return undefined if there are no default/ambient credentials * available (in which case the user should better hope they have * credential plugins configured). * * Uses a cache to avoid STS calls if we don't need 'em. */ async defaultAccount() { return (0, cached_1.cached)(this, CACHED_ACCOUNT, async () => { try { return await new sdk_1.SDK(this.defaultCredentialProvider, this.defaultRegion, this.requestHandler, this.logger).currentAccount(); } catch (e) { // Treat 'ExpiredToken' specially. This is a common situation that people may find themselves in, and // they are complaining about if we fail 'cdk synth' on them. We loudly complain in order to show that // the current situation is probably undesirable, but we don't fail. if (e.name === 'ExpiredToken') { (0, logging_1.warning)('There are expired AWS credentials in your environment. The CDK app will synth without current account information.'); return undefined; } (0, logging_1.debug)(`Unable to determine the default AWS account (${e.name}): ${(0, util_1.formatErrorMessage)(e)}`); return undefined; } }); } /** * Get credentials for the given account ID in the given mode * * 1. Use the default credentials if the destination account matches the * current credentials' account. * 2. Otherwise try all credential plugins. * 3. Fail if neither of these yield any credentials. * 4. Return a failure if any of them returned credentials */ async obtainBaseCredentials(accountId, mode) { // First try 'current' credentials const defaultAccountId = (await this.defaultAccount())?.accountId; if (defaultAccountId === accountId) { return { source: 'correctDefault', credentials: await this.defaultCredentialProvider, }; } // Then try the plugins const pluginCreds = await this.plugins.fetchCredentialsFor(accountId, mode); if (pluginCreds) { return { source: 'plugin', ...pluginCreds }; } // Fall back to default credentials with a note that they're not the right ones yet if (defaultAccountId !== undefined) { return { source: 'incorrectDefault', accountId: defaultAccountId, credentials: await this.defaultCredentialProvider, unusedPlugins: this.plugins.availablePluginNames, }; } // Apparently we didn't find any at all return { source: 'none', unusedPlugins: this.plugins.availablePluginNames, }; } /** * Return an SDK which uses assumed role credentials * * The base credentials used to retrieve the assumed role credentials will be the * same credentials returned by obtainCredentials if an environment and mode is passed, * otherwise it will be the current credentials. */ async withAssumedRole(mainCredentials, roleArn, externalId, additionalOptions, region) { (0, logging_1.debug)(`Assuming role '${roleArn}'.`); region = region ?? this.defaultRegion; const sourceDescription = fmtObtainedCredentials(mainCredentials); try { const credentials = await (0, provider_caching_1.makeCachingProvider)((0, credential_providers_1.fromTemporaryCredentials)({ masterCredentials: mainCredentials.credentials, params: { RoleArn: roleArn, ExternalId: externalId, RoleSessionName: `aws-cdk-${safeUsername()}`, ...additionalOptions, TransitiveTagKeys: additionalOptions?.Tags ? additionalOptions.Tags.map((t) => t.Key) : undefined, }, clientConfig: { region, requestHandler: this.requestHandler, customUserAgent: 'aws-cdk', logger: this.logger, }, logger: this.logger, })); // Call the provider at least once here, to catch an error if it occurs await credentials(); return new sdk_1.SDK(credentials, region, this.requestHandler, this.logger); } catch (err) { if (err.name === 'ExpiredToken') { throw err; } (0, logging_1.debug)(`Assuming role failed: ${err.message}`); throw new api_1.AuthenticationError([ 'Could not assume role in target account', ...(sourceDescription ? [`using ${sourceDescription}`] : []), err.message, ". Please make sure that this role exists in the account. If it doesn't exist, (re)-bootstrap the environment " + "with the right '--trust', using the latest version of the CDK CLI.", ].join(' ')); } } }; exports.SdkProvider = SdkProvider; exports.SdkProvider = SdkProvider = SdkProvider_1 = __decorate([ tracing_1.traceMemberMethods ], SdkProvider); /** * Return the username with characters invalid for a RoleSessionName removed * * @see https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html#API_AssumeRole_RequestParameters */ function safeUsername() { try { return os.userInfo().username.replace(/[^\w+=,.@-]/g, '@'); } catch { return 'noname'; } } /** * Isolating the code that translates calculation errors into human error messages * * We cover the following cases: * * - No credentials are available at all * - Default credentials are for the wrong account */ function fmtObtainCredentialsError(targetAccountId, obtainResult) { const msg = [`Need to perform AWS calls for account ${targetAccountId}`]; switch (obtainResult.source) { case 'incorrectDefault': msg.push(`but the current credentials are for ${obtainResult.accountId}`); break; case 'none': msg.push('but no credentials have been configured'); } if (obtainResult.unusedPlugins.length > 0) { msg.push(`and none of these plugins found any: ${obtainResult.unusedPlugins.join(', ')}`); } return msg.join(', '); } /** * Format a message indicating where we got base credentials for the assume role * * We cover the following cases: * * - Default credentials for the right account * - Default credentials for the wrong account * - Credentials returned from a plugin */ function fmtObtainedCredentials(obtainResult) { switch (obtainResult.source) { case 'correctDefault': return 'current credentials'; case 'plugin': return `credentials returned by plugin '${obtainResult.pluginName}'`; case 'incorrectDefault': const msg = []; msg.push(`current credentials (which are for account ${obtainResult.accountId}`); if (obtainResult.unusedPlugins.length > 0) { msg.push(`, and none of the following plugins provided credentials: ${obtainResult.unusedPlugins.join(', ')}`); } msg.push(')'); return msg.join(''); } } /** * Instantiate an SDK for context providers. This function ensures that all * lookup assume role options are used when context providers perform lookups. */ async function initContextProviderSdk(aws, options) { const account = options.account; const region = options.region; const creds = { assumeRoleArn: options.lookupRoleArn, assumeRoleExternalId: options.lookupRoleExternalId, assumeRoleAdditionalOptions: options.assumeRoleAdditionalOptions, }; return (await aws.forEnvironment(cx_api_1.EnvironmentUtils.make(account, region), mode_1.Mode.ForReading, creds)).sdk; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2RrLXByb3ZpZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsic2RrLXByb3ZpZGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7QUEwZ0JBLHdEQVdDO0FBcmhCRCx5QkFBeUI7QUFHekIsNENBQW9GO0FBRXBGLHdFQUF5RTtBQUd6RSwyREFBdUQ7QUFDdkQscUNBQWtDO0FBQ2xDLDZEQUF5RDtBQUN6RCx5REFBeUQ7QUFDekQsK0JBQTRCO0FBQzVCLHVDQUEwRDtBQUMxRCwwRUFBdUY7QUFDdkYsMkNBQStDO0FBQy9DLHFDQUFnRDtBQUNoRCx5Q0FBc0M7QUE2Q3RDLE1BQU0sY0FBYyxHQUFHLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0FBNkJoRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXNCRztBQUVJLElBQU0sV0FBVyxtQkFBakIsTUFBTSxXQUFXO0lBQ3RCOzs7OztPQUtHO0lBQ0ksTUFBTSxDQUFDLEtBQUssQ0FBQyw0QkFBNEIsQ0FBQyxVQUE4QixFQUFFO1FBQy9FLElBQUEsbUJBQVMsRUFBQyxhQUFXLENBQUMsNEJBQTRCLENBQUMsSUFBSSxFQUFFLGFBQVcsQ0FBQyxXQUFXLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUN2RyxNQUFNLGtCQUFrQixHQUFHLE1BQU0sb0NBQWdCLENBQUMsc0JBQXNCLENBQUM7WUFDdkUsT0FBTyxFQUFFLE9BQU8sQ0FBQyxPQUFPO1lBQ3hCLFdBQVcsRUFBRSxPQUFPLENBQUMsV0FBVztZQUNoQyxNQUFNLEVBQUUsT0FBTyxDQUFDLE1BQU07U0FDdkIsQ0FBQyxDQUFDO1FBRUgsTUFBTSxNQUFNLEdBQUcsTUFBTSxvQ0FBZ0IsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzlELE1BQU0sY0FBYyxHQUFHLG9DQUFnQixDQUFDLHFCQUFxQixDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUNuRixPQUFP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QWE7UUFDcEMsb0JBQW9CLEVBQUUsT0FBTyxDQUFDLG9CQUFvQjtRQUNsRCwyQkFBMkIsRUFBRSxPQUFPLENBQUMsMkJBQTJCO0tBQ2pFLENBQUM7SUFFRixPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsY0FBYyxDQUFDLHlCQUFnQixDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDLEVBQUUsV0FBSSxDQUFDLFVBQVUsRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQztBQUN4RyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgb3MgZnJvbSAnb3MnO1xuaW1wb3J0IHR5cGUgeyBDb250ZXh0TG9va3VwUm9sZU9wdGlvbnMgfSBmcm9tICdAYXdzLWNkay9jbG91ZC1hc3NlbWJseS1zY2hlbWEnO1xuaW1wb3J0IHR5cGUgeyBFbnZpcm9ubWVudCB9IGZyb20gJ0Bhd3MtY2RrL2N4LWFwaSc7XG5pbXBvcnQgeyBFbnZpcm9ubWVudFV0aWxzLCBVTktOT1dOX0FDQ09VTlQsIFVOS05PV05fUkVHSU9OIH0gZnJvbSAnQGF3cy1jZGsvY3gtYXBpJztcbmltcG9ydCB0eXBlIHsgQXNzdW1lUm9sZUNvbW1hbmRJbnB1dCB9IGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1zdHMnO1xuaW1wb3J0IHsgZnJvbVRlbXBvcmFyeUNyZWRlbnRpYWxzIH0gZnJvbSAnQGF3cy1zZGsvY3JlZGVudGlhbC1wcm92aWRlcnMnO1xuaW1wb3J0IHR5cGUgeyBOb2RlSHR0cEhhbmRsZXJPcHRpb25zIH0gZnJvbSAnQHNtaXRoeS9ub2RlLWh0dHAtaGFuZGxlcic7XG5pbXBvcnQgdHlwZSB7IEF3c0NyZWRlbnRpYWxJZGVudGl0eVByb3ZpZGVyLCBMb2dnZXIgfSBmcm9tICdAc21pdGh5L3R5cGVzJztcbmltcG9ydCB7IEF3c0NsaUNvbXBhdGlibGUgfSBmcm9tICcuL2F3c2NsaS1jb21wYXRpYmxlJztcbmltcG9ydCB7IGNhY2hlZCB9IGZyb20gJy4vY2FjaGVkJztcbmltcG9ydCB7IENyZWRlbnRpYWxQbHVnaW5zIH0gZnJvbSAnLi9jcmVkZW50aWFsLXBsdWdpbnMnO1xuaW1wb3J0IHsgbWFrZUNhY2hpbmdQcm92aWRlciB9IGZyb20gJy4vcHJvdmlkZXItY2FjaGluZyc7XG5pbXBvcnQgeyBTREsgfSBmcm9tICcuL3Nkayc7XG5pbXBvcnQgeyBjYWxsVHJhY2UsIHRyYWNlTWVtYmVyTWV0aG9kcyB9IGZyb20gJy4vdHJhY2luZyc7XG5pbXBvcnQgeyBBdXRoZW50aWNhdGlvbkVycm9yIH0gZnJvbSAnLi4vLi4vLi4vLi4vQGF3cy1jZGsvdG1wLXRvb2xraXQtaGVscGVycy9zcmMvYXBpJztcbmltcG9ydCB7IGRlYnVnLCB3YXJuaW5nIH0gZnJvbSAnLi4vLi4vbG9nZ2luZyc7XG5pbXBvcnQgeyBmb3JtYXRFcnJvck1lc3NhZ2UgfSBmcm9tICcuLi8uLi91dGlsJztcbmltcG9ydCB7IE1vZGUgfSBmcm9tICcuLi9wbHVnaW4vbW9kZSc7XG5cbmV4cG9ydCB0eXBlIEFzc3VtZVJvbGVBZGRpdGlvbmFsT3B0aW9ucyA9IFBhcnRpYWw8T21pdDxBc3N1bWVSb2xlQ29tbWFuZElucHV0LCAnRXh0ZXJuYWxJZCcgfCAnUm9sZUFybic+PjtcblxuLyoqXG4gKiBPcHRpb25zIGZvciB0aGUgZGVmYXVsdCBTREsgcHJvdmlkZXJcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTZGtQcm92aWRlck9wdGlvbnMge1xuICAvKipcbiAgICogUHJvZmlsZSB0byByZWFkIGZyb20gfi8uYXdzXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gTm8gcHJvZmlsZVxuICAgKi9cbiAgcmVhZG9ubHkgcHJvZmlsZT86IHN0cmluZztcblxuICAvKipcbiAgICogSFRUUCBvcHRpb25zIGZvciBTREtcbiAgICovXG4gIHJlYWRvbmx5IGh0dHBPcHRpb25zPzogU2RrSHR0cE9wdGlvbnM7XG5cbiAgLyoqXG4gICAqIFRoZSBsb2dnZXIgZm9yIHNkayBjYWxscy5cbiAgICovXG4gIHJlYWRvbmx5IGxvZ2dlcj86IExvZ2dlcjtcbn1cblxuLyoqXG4gKiBPcHRpb25zIGZvciBpbmRpdmlkdWFsIFNES3NcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTZGtIdHRwT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBQcm94eSBhZGRyZXNzIHRvIHVzZVxuICAgKlxuICAgKiBAZGVmYXVsdCBObyBwcm94eVxuICAgKi9cbiAgcmVhZG9ubHkgcHJveHlBZGRyZXNzPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBBIHBhdGggdG8gYSBjZXJ0aWZpY2F0ZSBidW5kbGUgdGhhdCBjb250YWlucyBhIGNlcnQgdG8gYmUgdHJ1c3RlZC5cbiAgICpcbiAgICogQGRlZmF1bHQgTm8gY2VydGlmaWNhdGUgYnVuZGxlXG4gICAqL1xuICByZWFkb25seSBjYUJ1bmRsZVBhdGg/OiBzdHJpbmc7XG59XG5cbmNvbnN0IENBQ0hFRF9BQ0NPVU5UID0gU3ltYm9sKCdjYWNoZWRfYWNjb3VudCcpO1xuXG4vKipcbiAqIFNESyBjb25maWd1cmF0aW9uIGZvciBhIGdpdmVuIGVudmlyb25tZW50XG4gKiAnZm9yRW52aXJvbm1lbnQnIHdpbGwgYXR0ZW1wdCB0byBhc3N1bWUgYSByb2xlIGFuZCBpZiBpdFxuICogaXMgbm90IHN1Y2Nlc3NmdWwsIHRoZW4gaXQgd2lsbCBlaXRoZXI6XG4gKiAgIDEuIENoZWNrIHRvIHNlZSBpZiB0aGUgZGVmYXVsdCBjcmVkZW50aWFscyAobG9jYWwgY3JlZGVudGlhbHMgdGhlIENMSSB3YXMgZXhlY3V0ZWQgd2l0aClcbiAqICAgICAgYXJlIGZvciB0aGUgZ2l2ZW4gZW52aXJvbm1lbnQuIElmIHRoZXkgYXJlIHRoZW4gcmV0dXJuIHRob3NlLlxuICogICAyLiBJZiB0aGUgZGVmYXVsdCBjcmVkZW50aWFscyBhcmUgbm90IGZvciB0aGUgZ2l2ZW4gZW52aXJvbm1lbnQgdGhlblxuICogICAgICB0aHJvdyBhbiBlcnJvclxuICpcbiAqICdkaWRBc3N1bWVSb2xlJyBhbGxvd3MgY2FsbGVycyB0byB3aGV0aGVyIHRoZXkgYXJlIHJlY2VpdmluZyB0aGUgYXNzdW1lIHJvbGVcbiAqIGNyZWRlbnRpYWxzIG9yIHRoZSBkZWZhdWx0IGNyZWRlbnRpYWxzLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFNka0ZvckVudmlyb25tZW50IHtcbiAgLyoqXG4gICAqIFRoZSBTREsgZm9yIHRoZSBnaXZlbiBlbnZpcm9ubWVudFxuICAgKi9cbiAgcmVhZG9ubHkgc2RrOiBTREs7XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgb3Igbm90IHRoZSBhc3N1bWUgcm9sZSB3YXMgc3VjY2Vzc2Z1bC5cbiAgICogSWYgdGhlIGFzc3VtZSByb2xlIHdhcyBub3Qgc3VjY2Vzc2Z1bCAoZmFsc2UpXG4gICAqIHRoZW4gdGhhdCBtZWFucyB0aGF0IHRoZSAnc2RrJyByZXR1cm5lZCBjb250YWluc1xuICAgKiB0aGUgZGVmYXVsdCBjcmVkZW50aWFscyAobm90IHRoZSBhc3N1bWUgcm9sZSBjcmVkZW50aWFscylcbiAgICovXG4gIHJlYWRvbmx5IGRpZEFzc3VtZVJvbGU6IGJvb2xlYW47XG59XG5cbi8qKlxuICogQ3JlYXRlcyBpbnN0YW5jZXMgb2YgdGhlIEFXUyBTREsgYXBwcm9wcmlhdGUgZm9yIGEgZ2l2ZW4gYWNjb3VudC9yZWdpb24uXG4gKlxuICogQmVoYXZpb3IgaXMgYXMgZm9sbG93czpcbiAqXG4gKiAtIEZpcnN0LCBhIHNldCBvZiBcImJhc2VcIiBjcmVkZW50aWFscyBhcmUgZXN0YWJsaXNoZWRcbiAqICAgLSBJZiBhIHRhcmdldCBlbnZpcm9ubWVudCBpcyBnaXZlbiBhbmQgdGhlIGRlZmF1bHQgKFwiY3VycmVudFwiKSBTREsgY3JlZGVudGlhbHMgYXJlIGZvclxuICogICAgIHRoYXQgYWNjb3VudCwgcmV0dXJuIHRob3NlOyBvdGhlcndpc2VcbiAqICAgLSBJZiBhIHRhcmdldCBlbnZpcm9ubWVudCBpcyBnaXZlbiwgc2NhbiBhbGwgY3JlZGVudGlhbCBwcm92aWRlciBwbHVnaW5zXG4gKiAgICAgZm9yIGNyZWRlbnRpYWxzLCBhbmQgcmV0dXJuIHRob3NlIGlmIGZvdW5kOyBvdGhlcndpc2VcbiAqICAgLSBSZXR1cm4gZGVmYXVsdCAoXCJjdXJyZW50XCIpIFNESyBjcmVkZW50aWFscywgbm90aW5nIHRoYXQgdGhleSBtaWdodCBiZSB3cm9uZy5cbiAqXG4gKiAtIFNlY29uZCwgYSByb2xlIG1heSBvcHRpb25hbGx5IG5lZWQgdG8gYmUgYXNzdW1lZC4gVXNlIHRoZSBiYXNlIGNyZWRlbnRpYWxzXG4gKiAgIGVzdGFibGlzaGVkIGluIHRoZSBwcmV2aW91cyBwcm9jZXNzIHRvIGFzc3VtZSB0aGF0IHJvbGUuXG4gKiAgIC0gSWYgYXNzdW1pbmcgdGhlIHJvbGUgZmFpbHMgYW5kIHRoZSBiYXNlIGNyZWRlbnRpYWxzIGFyZSBmb3IgdGhlIGNvcnJlY3RcbiAqICAgICBhY2NvdW50LCByZXR1cm4gdGhvc2UuIFRoaXMgaXMgYSBmYWxsYmFjayBmb3IgcGVvcGxlIHdobyBhcmUgdHJ5aW5nIHRvIGludGVyYWN0XG4gKiAgICAgd2l0aCBhIERlZmF1bHQgU3ludGhlc2l6ZWQgc3RhY2sgYW5kIGFscmVhZHkgaGF2ZSByaWdodCBjcmVkZW50aWFscyBzZXR1cC5cbiAqXG4gKiAgICAgVHlwaWNhbCBjYXNlcyB3ZSBzZWUgaW4gdGhlIHdpbGQ6XG4gKiAgICAgLSBDcmVkZW50aWFsIHBsdWdpbiBzZXR1cCB0aGF0LCBhbHRob3VnaCBub3QgcmVjb21tZW5kZWQsIHdvcmtzIGZvciB0aGVtXG4gKiAgICAgLSBTZWVkZWQgdGVybWluYWwgd2l0aCBgUmVhZE9ubHlgIGNyZWRlbnRpYWxzIGluIG9yZGVyIHRvIGRvIGBjZGsgZGlmZmAtLXRoZSBgUmVhZE9ubHlgXG4gKiAgICAgICByb2xlIGRvZXNuJ3QgaGF2ZSBgc3RzOkFzc3VtZVJvbGVgIGFuZCB3aWxsIGZhaWwgZm9yIG5vIHJlYWwgZ29vZCByZWFzb24uXG4gKi9cbkB0cmFjZU1lbWJlck1ldGhvZHNcbmV4cG9ydCBjbGFzcyBTZGtQcm92aWRlciB7XG4gIC8qKlxuICAgKiBDcmVhdGUgYSBuZXcgU2RrUHJvdmlkZXIgd2hpY2ggZ2V0cyBpdHMgZGVmYXVsdHMgaW4gYSB3YXkgdGhhdCBiZWhhdmVzIGxpa2UgdGhlIEFXUyBDTEkgZG9lc1xuICAgKlxuICAgKiBUaGUgQVdTIFNESyBmb3IgSlMgYmVoYXZlcyBzbGlnaHRseSBkaWZmZXJlbnRseSBmcm9tIHRoZSBBV1MgQ0xJIGluIGEgbnVtYmVyIG9mIHdheXM7IHNlZSB0aGVcbiAgICogY2xhc3MgYEF3c0NsaUNvbXBhdGlibGVgIGZvciB0aGUgZGV0YWlscy5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgYXN5bmMgd2l0aEF3c0NsaUNvbXBhdGlibGVEZWZhdWx0cyhvcHRpb25zOiBTZGtQcm92aWRlck9wdGlvbnMgPSB7fSkge1xuICAgIGNhbGxUcmFjZShTZGtQcm92aWRlci53aXRoQXdzQ2xpQ29tcGF0aWJsZURlZmF1bHRzLm5hbWUsIFNka1Byb3ZpZGVyLmNvbnN0cnVjdG9yLm5hbWUsIG9wdGlvbnMubG9nZ2VyKTtcbiAgICBjb25zdCBjcmVkZW50aWFsUHJvdmlkZXIgPSBhd2FpdCBBd3NDbGlDb21wYXRpYmxlLmNyZWRlbnRpYWxDaGFpbkJ1aWxkZXIoe1xuICAgICAgcHJvZmlsZTogb3B0aW9ucy5wcm9maWxlLFxuICAgICAgaHR0cE9wdGlvbnM6IG9wdGlvbnMuaHR0cE9wdGlvbnMsXG4gICAgICBsb2dnZXI6IG9wdGlvbnMubG9nZ2VyLFxuICAgIH0pO1xuXG4gICAgY29uc3QgcmVnaW9uID0gYXdhaXQgQXdzQ2xpQ29tcGF0aWJsZS5yZWdpb24ob3B0aW9ucy5wcm9maWxlKTtcbiAgICBjb25zdCByZXF1ZXN0SGFuZGxlciA9IEF3c0NsaUNvbXBhdGlibGUucmVxdWVzdEhhbmRsZXJCdWlsZGVyKG9wdGlvbnMuaHR0cE9wdGlvbnMpO1xuICAgIHJldHVybiBuZXcgU2RrUHJvdmlkZXIoY3JlZGVudGlhbFByb3ZpZGVyLCByZWdpb24sIHJlcXVlc3RIYW5kbGVyLCBvcHRpb25zLmxvZ2dlcik7XG4gIH1cblxuICBwcml2YXRlIHJlYWRvbmx5IHBsdWdpbnMgPSBuZXcgQ3JlZGVudGlhbFBsdWdpbnMoKTtcblxuICBwdWJsaWMgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByZWFkb25seSBkZWZhdWx0Q3JlZGVudGlhbFByb3ZpZGVyOiBBd3NDcmVkZW50aWFsSWRlbnRpdHlQcm92aWRlcixcbiAgICAvKipcbiAgICAgKiBEZWZhdWx0IHJlZ2lvblxuICAgICAqL1xuICAgIHB1YmxpYyByZWFkb25seSBkZWZhdWx0UmVnaW9uOiBzdHJpbmcsXG4gICAgcHJpdmF0ZSByZWFkb25seSByZXF1ZXN0SGFuZGxlcjogTm9kZUh0dHBIYW5kbGVyT3B0aW9ucyA9IHt9LFxuICAgIHByaXZhdGUgcmVhZG9ubHkgbG9nZ2VyPzogTG9nZ2VyLFxuICApIHtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gYW4gU0RLIHdoaWNoIGNhbiBkbyBvcGVyYXRpb25zIGluIHRoZSBnaXZlbiBlbnZpcm9ubWVudFxuICAgKlxuICAgKiBUaGUgYGVudmlyb25tZW50YCBwYXJhbWV0ZXIgaXMgcmVzb2x2ZWQgZmlyc3QgKHNlZSBgcmVzb2x2ZUVudmlyb25tZW50KClgKS5cbiAgICovXG4gIHB1YmxpYyBhc3luYyBmb3JFbnZpcm9ubWVudChcbiAgICBlbnZpcm9ubWVudDogRW52aXJvbm1lbnQsXG4gICAgbW9kZTogTW9kZSxcbiAgICBvcHRpb25zPzogQ3JlZGVudGlhbHNPcHRpb25zLFxuICAgIHF1aWV0ID0gZmFsc2UsXG4gICk6IFByb21pc2U8U2RrRm9yRW52aXJvbm1lbnQ+IHtcbiAgICBjb25zdCBlbnYgPSBhd2FpdCB0aGlzLnJlc29sdmVFbnZpcm9ubWVudChlbnZpcm9ubWVudCk7XG5cbiAgICBjb25zdCBiYXNlQ3JlZHMgPSBhd2FpdCB0aGlzLm9idGFpbkJhc2VDcmVkZW50aWFscyhlbnYuYWNjb3VudCwgbW9kZSk7XG5cbiAgICAvLyBBdCB0aGlzIHBvaW50LCB3ZSBuZWVkIGF0IGxlYXN0IFNPTUUgY3JlZGVudGlhbHNcbiAgICBpZiAoYmFzZUNyZWRzLnNvdXJjZSA9PT0gJ25vbmUnKSB7XG4gICAgICB0aHJvdyBuZXcgQXV0aGVudGljYXRpb25FcnJvcihmbXRPYnRhaW5DcmVkZW50aWFsc0Vycm9yKGVudi5hY2NvdW50LCBiYXNlQ3JlZHMpKTtcbiAgICB9XG5cbiAgICAvLyBTaW1wbGUgY2FzZSBpcyBpZiB3ZSBkb24ndCBuZWVkIHRvIFwiYXNzdW1lUm9sZVwiIGhlcmUuIElmIHNvLCB3ZSBtdXN0IG5vdyBoYXZlIGNyZWRlbnRpYWxzIGZvciB0aGUgcmlnaHRcbiAgICAvLyBhY2NvdW50LlxuICAgIGlmIChvcHRpb25zPy5hc3N1bWVSb2xlQXJuID09PSB1bmRlZmluZWQpIHtcbiAgICAgIGlmIChiYXNlQ3JlZHMuc291cmNlID09PSAnaW5jb3JyZWN0RGVmYXVsdCcpIHtcbiAgICAgICAgdGhyb3cgbmV3IEF1dGhlbnRpY2F0aW9uRXJyb3IoZm10T2J0YWluQ3JlZGVudGlhbHNFcnJvcihlbnYuYWNjb3VudCwgYmFzZUNyZWRzKSk7XG4gICAgICB9XG5cbiAgICAgIC8vIE91ciBjdXJyZW50IGNyZWRlbnRpYWxzIG11c3QgYmUgdmFsaWQgYW5kIG5vdCBleHBpcmVkLiBDb25maXJtIHRoYXQgYmVmb3JlIHdlIGdldCBpbnRvIGRvaW5nXG4gICAgICAvLyBhY3R1YWwgQ2xvdWRGb3JtYXRpb24gY2FsbHMsIHdoaWNoIG1pZ2h0IHRha2UgYSBsb25nIHRpbWUgdG8gaGFuZy5cbiAgICAgIGNvbnN0IHNkayA9IG5ldyBTREsoYmFzZUNyZWRzLmNyZWRlbnRpYWxzLCBlbnYucmVnaW9uLCB0aGlzLnJlcXVlc3RIYW5kbGVyLCB0aGlzLmxvZ2dlcik7XG4gICAgICBhd2FpdCBzZGsudmFsaWRhdGVDcmVkZW50aWFscygpO1xuICAgICAgcmV0dXJuIHsgc2RrLCBkaWRBc3N1bWVSb2xlOiBmYWxzZSB9O1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICAvLyBXZSB3aWxsIHByb2NlZWQgdG8gQXNzdW1lUm9sZSB1c2luZyB3aGF0ZXZlciB3ZSd2ZSBiZWVuIGdpdmVuLlxuICAgICAgY29uc3Qgc2RrID0gYXdhaXQgdGhpcy53aXRoQXNzdW1lZFJvbGUoXG4gICAgICAgIGJhc2VDcmVkcyxcbiAgICAgICAgb3B0aW9ucy5hc3N1bWVSb2xlQXJuLFxuICAgICAgICBvcHRpb25zLmFzc3VtZVJvbGVFeHRlcm5hbElkLFxuICAgICAgICBvcHRpb25zLmFzc3VtZVJvbGVBZGRpdGlvbmFsT3B0aW9ucyxcbiAgICAgICAgZW52LnJlZ2lvbixcbiAgICAgICk7XG5cbiAgICAgIHJldHVybiB7IHNkaywgZGlkQXNzdW1lUm9sZTogdHJ1ZSB9O1xuICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICBpZiAoZXJyLm5hbWUgPT09ICdFeHBpcmVkVG9rZW4nKSB7XG4gICAgICAgIHRocm93IGVycjtcbiAgICAgIH1cblxuICAgICAgLy8gQXNzdW1lUm9sZSBmYWlsZWQuIFByb2NlZWQgYW5kIHdhcm4gKmlmIGFuZCBvbmx5IGlmKiB0aGUgYmFzZUNyZWRlbnRpYWxzIHdlcmUgYWxyZWFkeSBmb3IgdGhlIHJpZ2h0IGFjY291bnRcbiAgICAgIC8vIG9yIHJldHVybmVkIGZyb20gYSBwbHVnaW4uIFRoaXMgaXMgdG8gY292ZXIgc29tZSBjdXJyZW50IHNldHVwcyBmb3IgcGVvcGxlIHVzaW5nIHBsdWdpbnMgb3IgcHJlZmVycmluZyB0b1xuICAgICAgLy8gZmVlZCB0aGUgQ0xJIGNyZWRlbnRpYWxzIHdoaWNoIGFyZSBzdWZmaWNpZW50IGJ5IHRoZW1zZWx2ZXMuIFByZWZlciB0byBhc3N1bWUgdGhlIGNvcnJlY3Qgcm9sZSBpZiB3ZSBjYW4sXG4gICAgICAvLyBidXQgaWYgd2UgY2FuJ3QgdGhlbiBsZXQncyBqdXN0IHRyeSB3aXRoIGF2YWlsYWJsZSBjcmVkZW50aWFscyBhbnl3YXkuXG4gICAgICBpZiAoYmFzZUNyZWRzLnNvdXJjZSA9PT0gJ2NvcnJlY3REZWZhdWx0JyB8fCBiYXNlQ3JlZHMuc291cmNlID09PSAncGx1Z2luJykge1xuICAgICAgICBkZWJ1ZyhlcnIubWVzc2FnZSk7XG4gICAgICAgIGNvbnN0IGxvZ2dlciA9IHF1aWV0ID8gZGVidWcgOiB3YXJuaW5nO1xuICAgICAgICBsb2dnZXIoXG4gICAgICAgICAgYCR7Zm10T2J0YWluZWRDcmVkZW50aWFscyhiYXNlQ3JlZHMpfSBjb3VsZCBub3QgYmUgdXNlZCB0byBhc3N1bWUgJyR7b3B0aW9ucy5hc3N1bWVSb2xlQXJufScsIGJ1dCBhcmUgZm9yIHRoZSByaWdodCBhY2NvdW50LiBQcm9jZWVkaW5nIGFueXdheS5gLFxuICAgICAgICApO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHNkazogbmV3IFNESyhiYXNlQ3JlZHMuY3JlZGVudGlhbHMsIGVudi5yZWdpb24sIHRoaXMucmVxdWVzdEhhbmRsZXIsIHRoaXMubG9nZ2VyKSxcbiAgICAgICAgICBkaWRBc3N1bWVSb2xlOiBmYWxzZSxcbiAgICAgICAgfTtcbiAgICAgIH1cblxuICAgICAgdGhyb3cgZXJyO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gdGhlIHBhcnRpdGlvbiB0aGF0IGJhc2UgY3JlZGVudGlhbHMgYXJlIGZvclxuICAgKlxuICAgKiBSZXR1cm5zIGB1bmRlZmluZWRgIGlmIHRoZXJlIGFyZSBubyBiYXNlIGNyZWRlbnRpYWxzLlxuICAgKi9cbiAgcHVibGljIGFzeW5jIGJhc2VDcmVkZW50aWFsc1BhcnRpdGlvbihlbnZpcm9ubWVudDogRW52aXJvbm1lbnQsIG1vZGU6IE1vZGUpOiBQcm9taXNlPHN0cmluZyB8IHVuZGVmaW5lZD4ge1xuICAgIGNvbnN0IGVudiA9IGF3YWl0IHRoaXMucmVzb2x2ZUVudmlyb25tZW50KGVudmlyb25tZW50KTtcbiAgICBjb25zdCBiYXNlQ3JlZHMgPSBhd2FpdCB0aGlzLm9idGFpbkJhc2VDcmVkZW50aWFscyhlbnYuYWNjb3VudCwgbW9kZSk7XG4gICAgaWYgKGJhc2VDcmVkcy5zb3VyY2UgPT09ICdub25lJykge1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gICAgcmV0dXJuIChhd2FpdCBuZXcgU0RLKGJhc2VDcmVkcy5jcmVkZW50aWFscywgZW52LnJlZ2lvbiwgdGhpcy5yZXF1ZXN0SGFuZGxlciwgdGhpcy5sb2dnZXIpLmN1cnJlbnRBY2NvdW50KCkpLnBhcnRpdGlvbjtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXNvbHZlIHRoZSBlbnZpcm9ubWVudCBmb3IgYSBzdGFja1xuICAgKlxuICAgKiBSZXBsYWNlcyB0aGUgbWFnaWMgdmFsdWVzIGBVTktOT1dOX1JFR0lPTmAgYW5kIGBVTktOT1dOX0FDQ09VTlRgXG4gICAqIHdpdGggdGhlIGRlZmF1bHRzIGZvciB0aGUgY3VycmVudCBTREsgY29uZmlndXJhdGlvbiAoYH4vLmF3cy9jb25maWdgIG9yXG4gICAqIG90aGVyd2lzZSkuXG4gICAqXG4gICAqIEl0IGlzIGFuIGVycm9yIGlmIGBVTktOT1dOX0FDQ09VTlRgIGlzIHVzZWQgYnV0IHRoZSB1c2VyIGhhc24ndCBjb25maWd1cmVkXG4gICAqIGFueSBTREsgY3JlZGVudGlhbHMuXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgcmVzb2x2ZUVudmlyb25tZW50KGVudjogRW52aXJvbm1lbnQpOiBQcm9taXNlPEVudmlyb25tZW50PiB7XG4gICAgY29uc3QgcmVnaW9uID0gZW52LnJlZ2lvbiAhPT0gVU5LTk9XTl9SRUdJT04gPyBlbnYucmVnaW9uIDogdGhpcy5kZWZhdWx0UmVnaW9uO1xuICAgIGNvbnN0IGFjY291bnQgPSBlbnYuYWNjb3VudCAhPT0gVU5LTk9XTl9BQ0NPVU5UID8gZW52LmFjY291bnQgOiAoYXdhaXQgdGhpcy5kZWZhdWx0QWNjb3VudCgpKT8uYWNjb3VudElkO1xuXG4gICAgaWYgKCFhY2NvdW50KSB7XG4gICAgICB0aHJvdyBuZXcgQXV0aGVudGljYXRpb25FcnJvcihcbiAgICAgICAgJ1VuYWJsZSB0byByZXNvbHZlIEFXUyBhY2NvdW50IHRvIHVzZS4gSXQgbXVzdCBiZSBlaXRoZXIgY29uZmlndXJlZCB3aGVuIHlvdSBkZWZpbmUgeW91ciBDREsgU3RhY2ssIG9yIHRocm91Z2ggdGhlIGVudmlyb25tZW50JyxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIHJlZ2lvbixcbiAgICAgIGFjY291bnQsXG4gICAgICBuYW1lOiBFbnZpcm9ubWVudFV0aWxzLmZvcm1hdChhY2NvdW50LCByZWdpb24pLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogVGhlIGFjY291bnQgd2UnZCBhdXRoIGludG8gaWYgd2UgdXNlZCBkZWZhdWx0IGNyZWRlbnRpYWxzLlxuICAgKlxuICAgKiBEZWZhdWx0IGNyZWRlbnRpYWxzIGFyZSB0aGUgc2V0IG9mIGFtYmllbnRseSBjb25maWd1cmVkIGNyZWRlbnRpYWxzIHVzaW5nXG4gICAqIG9uZSBvZiB0aGUgZW52aXJvbm1lbnQgdmFyaWFibGVzLCBvciB+Ly5hd3MvY3JlZGVudGlhbHMsIG9yIHRoZSAqb25lKlxuICAgKiBwcm9maWxlIHRoYXQgd2FzIHBhc3NlZCBpbnRvIHRoZSBDTEkuXG4gICAqXG4gICAqIE1pZ2h0IHJldHVybiB1bmRlZmluZWQgaWYgdGhlcmUgYXJlIG5vIGRlZmF1bHQvYW1iaWVudCBjcmVkZW50aWFsc1xuICAgKiBhdmFpbGFibGUgKGluIHdoaWNoIGNhc2UgdGhlIHVzZXIgc2hvdWxkIGJldHRlciBob3BlIHRoZXkgaGF2ZVxuICAgKiBjcmVkZW50aWFsIHBsdWdpbnMgY29uZmlndXJlZCkuXG4gICAqXG4gICAqIFVzZXMgYSBjYWNoZSB0byBhdm9pZCBTVFMgY2FsbHMgaWYgd2UgZG9uJ3QgbmVlZCAnZW0uXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgZGVmYXVsdEFjY291bnQoKTogUHJvbWlzZTxBY2NvdW50IHwgdW5kZWZpbmVkPiB7XG4gICAgcmV0dXJuIGNhY2hlZCh0aGlzLCBDQUNIRURfQUNDT1VOVCwgYXN5bmMgKCkgPT4ge1xuICAgICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IG5ldyBTREsodGhpcy5kZWZhdWx0Q3JlZGVudGlhbFByb3ZpZGVyLCB0aGlzLmRlZmF1bHRSZWdpb24sIHRoaXMucmVxdWVzdEhhbmRsZXIsIHRoaXMubG9nZ2VyKS5jdXJyZW50QWNjb3VudCgpO1xuICAgICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICAgIC8vIFRyZWF0ICdFeHBpcmVkVG9rZW4nIHNwZWNpYWxseS4gVGhpcyBpcyBhIGNvbW1vbiBzaXR1YXRpb24gdGhhdCBwZW9wbGUgbWF5IGZpbmQgdGhlbXNlbHZlcyBpbiwgYW5kXG4gICAgICAgIC8vIHRoZXkgYXJlIGNvbXBsYWluaW5nIGFib3V0IGlmIHdlIGZhaWwgJ2NkayBzeW50aCcgb24gdGhlbS4gV2UgbG91ZGx5IGNvbXBsYWluIGluIG9yZGVyIHRvIHNob3cgdGhhdFxuICAgICAgICAvLyB0aGUgY3VycmVudCBzaXR1YXRpb24gaXMgcHJvYmFibHkgdW5kZXNpcmFibGUsIGJ1dCB3ZSBkb24ndCBmYWlsLlxuICAgICAgICBpZiAoZS5uYW1lID09PSAnRXhwaXJlZFRva2VuJykge1xuICAgICAgICAgIHdhcm5pbmcoXG4gICAgICAgICAgICAnVGhlcmUgYXJlIGV4cGlyZWQgQVdTIGNyZWRlbnRpYWxzIGluIHlvdXIgZW52aXJvbm1lbnQuIFRoZSBDREsgYXBwIHdpbGwgc3ludGggd2l0aG91dCBjdXJyZW50IGFjY291bnQgaW5mb3JtYXRpb24uJyxcbiAgICAgICAgICApO1xuICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIH1cblxuICAgICAgICBkZWJ1ZyhgVW5hYmxlIHRvIGRldGVybWluZSB0aGUgZGVmYXVsdCBBV1MgYWNjb3VudCAoJHtlLm5hbWV9KTogJHtmb3JtYXRFcnJvck1lc3NhZ2UoZSl9YCk7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGNyZWRlbnRpYWxzIGZvciB0aGUgZ2l2ZW4gYWNjb3VudCBJRCBpbiB0aGUgZ2l2ZW4gbW9kZVxuICAgKlxuICAgKiAxLiBVc2UgdGhlIGRlZmF1bHQgY3JlZGVudGlhbHMgaWYgdGhlIGRlc3RpbmF0aW9uIGFjY291bnQgbWF0Y2hlcyB0aGVcbiAgICogICAgY3VycmVudCBjcmVkZW50aWFscycgYWNjb3VudC5cbiAgICogMi4gT3RoZXJ3aXNlIHRyeSBhbGwgY3JlZGVudGlhbCBwbHVnaW5zLlxuICAgKiAzLiBGYWlsIGlmIG5laXRoZXIgb2YgdGhlc2UgeWllbGQgYW55IGNyZWRlbnRpYWxzLlxuICAgKiA0LiBSZXR1cm4gYSBmYWlsdXJlIGlmIGFueSBvZiB0aGVtIHJldHVybmVkIGNyZWRlbnRpYWxzXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIG9idGFpbkJhc2VDcmVkZW50aWFscyhhY2NvdW50SWQ6IHN0cmluZywgbW9kZTogTW9kZSk6IFByb21pc2U8T2J0YWluQmFzZUNyZWRlbnRpYWxzUmVzdWx0PiB7XG4gICAgLy8gRmlyc3QgdHJ5ICdjdXJyZW50JyBjcmVkZW50aWFsc1xuICAgIGNvbnN0IGRlZmF1bHRBY2NvdW50SWQgPSAoYXdhaXQgdGhpcy5kZWZhdWx0QWNjb3VudCgpKT8uYWNjb3VudElkO1xuICAgIGlmIChkZWZhdWx0QWNjb3VudElkID09PSBhY2NvdW50SWQpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHNvdXJjZTogJ2NvcnJlY3REZWZhdWx0JyxcbiAgICAgICAgY3JlZGVudGlhbHM6IGF3YWl0IHRoaXMuZGVmYXVsdENyZWRlbnRpYWxQcm92aWRlcixcbiAgICAgIH07XG4gICAgfVxuXG4gICAgLy8gVGhlbiB0cnkgdGhlIHBsdWdpbnNcbiAgICBjb25zdCBwbHVnaW5DcmVkcyA9IGF3YWl0IHRoaXMucGx1Z2lucy5mZXRjaENyZWRlbnRpYWxzRm9yKGFjY291bnRJZCwgbW9kZSk7XG4gICAgaWYgKHBsdWdpbkNyZWRzKSB7XG4gICAgICByZXR1cm4geyBzb3VyY2U6ICdwbHVnaW4nLCAuLi5wbHVnaW5DcmVkcyB9O1xuICAgIH1cblxuICAgIC8vIEZhbGwgYmFjayB0byBkZWZhdWx0IGNyZWRlbnRpYWxzIHdpdGggYSBub3RlIHRoYXQgdGhleSdyZSBub3QgdGhlIHJpZ2h0IG9uZXMgeWV0XG4gICAgaWYgKGRlZmF1bHRBY2NvdW50SWQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgc291cmNlOiAnaW5jb3JyZWN0RGVmYXVsdCcsXG4gICAgICAgIGFjY291bnRJZDogZGVmYXVsdEFjY291bnRJZCxcbiAgICAgICAgY3JlZGVudGlhbHM6IGF3YWl0IHRoaXMuZGVmYXVsdENyZWRlbnRpYWxQcm92aWRlcixcbiAgICAgICAgdW51c2VkUGx1Z2luczogdGhpcy5wbHVnaW5zLmF2YWlsYWJsZVBsdWdpbk5hbWVzLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICAvLyBBcHBhcmVudGx5IHdlIGRpZG4ndCBmaW5kIGFueSBhdCBhbGxcbiAgICByZXR1cm4ge1xuICAgICAgc291cmNlOiAnbm9uZScsXG4gICAgICB1bnVzZWRQbHVnaW5zOiB0aGlzLnBsdWdpbnMuYXZhaWxhYmxlUGx1Z2luTmFtZXMsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gYW4gU0RLIHdoaWNoIHVzZXMgYXNzdW1lZCByb2xlIGNyZWRlbnRpYWxzXG4gICAqXG4gICAqIFRoZSBiYXNlIGNyZWRlbnRpYWxzIHVzZWQgdG8gcmV0cmlldmUgdGhlIGFzc3VtZWQgcm9sZSBjcmVkZW50aWFscyB3aWxsIGJlIHRoZVxuICAgKiBzYW1lIGNyZWRlbnRpYWxzIHJldHVybmVkIGJ5IG9idGFpbkNyZWRlbnRpYWxzIGlmIGFuIGVudmlyb25tZW50IGFuZCBtb2RlIGlzIHBhc3NlZCxcbiAgICogb3RoZXJ3aXNlIGl0IHdpbGwgYmUgdGhlIGN1cnJlbnQgY3JlZGVudGlhbHMuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHdpdGhBc3N1bWVkUm9sZShcbiAgICBtYWluQ3JlZGVudGlhbHM6IEV4Y2x1ZGU8T2J0YWluQmFzZUNyZWRlbnRpYWxzUmVzdWx0LCB7IHNvdXJjZTogJ25vbmUnIH0+LFxuICAgIHJvbGVBcm46IHN0cmluZyxcbiAgICBleHRlcm5hbElkPzogc3RyaW5nLFxuICAgIGFkZGl0aW9uYWxPcHRpb25zPzogQXNzdW1lUm9sZUFkZGl0aW9uYWxPcHRpb25zLFxuICAgIHJlZ2lvbj86IHN0cmluZyxcbiAgKTogUHJvbWlzZTxTREs+IHtcbiAgICBkZWJ1ZyhgQXNzdW1pbmcgcm9sZSAnJHtyb2xlQXJufScuYCk7XG5cbiAgICByZWdpb24gPSByZWdpb24gPz8gdGhpcy5kZWZhdWx0UmVnaW9uO1xuXG4gICAgY29uc3Qgc291cmNlRGVzY3JpcHRpb24gPSBmbXRPYnRhaW5lZENyZWRlbnRpYWxzKG1haW5DcmVkZW50aWFscyk7XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgY3JlZGVudGlhbHMgPSBhd2FpdCBtYWtlQ2FjaGluZ1Byb3ZpZGVyKGZyb21UZW1wb3JhcnlDcmVkZW50aWFscyh7XG4gICAgICAgIG1hc3RlckNyZWRlbnRpYWxzOiBtYWluQ3JlZGVudGlhbHMuY3JlZGVudGlhbHMsXG4gICAgICAgIHBhcmFtczoge1xuICAgICAgICAgIFJvbGVBcm46IHJvbGVBcm4sXG4gICAgICAgICAgRXh0ZXJuYWxJZDogZXh0ZXJuYWxJZCxcbiAgICAgICAgICBSb2xlU2Vzc2lvbk5hbWU6IGBhd3MtY2RrLSR7c2FmZVVzZXJuYW1lKCl9YCxcbiAgICAgICAgICAuLi5hZGRpdGlvbmFsT3B0aW9ucyxcbiAgICAgICAgICBUcmFuc2l0aXZlVGFnS2V5czogYWRkaXRpb25hbE9wdGlvbnM/LlRhZ3MgPyBhZGRpdGlvbmFsT3B0aW9ucy5UYWdzLm1hcCgodCkgPT4gdC5LZXkhKSA6IHVuZGVmaW5lZCxcbiAgICAgICAgfSxcbiAgICAgICAgY2xpZW50Q29uZmlnOiB7XG4gICAgICAgICAgcmVnaW9uLFxuICAgICAgICAgIHJlcXVlc3RIYW5kbGVyOiB0aGlzLnJlcXVlc3RIYW5kbGVyLFxuICAgICAgICAgIGN1c3RvbVVzZXJBZ2VudDogJ2F3cy1jZGsnLFxuICAgICAgICAgIGxvZ2dlcjogdGhpcy5sb2dnZXIsXG4gICAgICAgIH0sXG4gICAgICAgIGxvZ2dlcjogdGhpcy5sb2dnZXIsXG4gICAgICB9KSk7XG5cbiAgICAgIC8vIENhbGwgdGhlIHByb3ZpZGVyIGF0IGxlYXN0IG9uY2UgaGVyZSwgdG8gY2F0Y2ggYW4gZXJyb3IgaWYgaXQgb2NjdXJzXG4gICAgICBhd2FpdCBjcmVkZW50aWFscygpO1xuXG4gICAgICByZXR1cm4gbmV3IFNESyhjcmVkZW50aWFscywgcmVnaW9uLCB0aGlzLnJlcXVlc3RIYW5kbGVyLCB0aGlzLmxvZ2dlcik7XG4gICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgIGlmIChlcnIubmFtZSA9PT0gJ0V4cGlyZWRUb2tlbicpIHtcbiAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgfVxuXG4gICAgICBkZWJ1ZyhgQXNzdW1pbmcgcm9sZSBmYWlsZWQ6ICR7ZXJyLm1lc3NhZ2V9YCk7XG4gICAgICB0aHJvdyBuZXcgQXV0aGVudGljYXRpb25FcnJvcihcbiAgICAgICAgW1xuICAgICAgICAgICdDb3VsZCBub3QgYXNzdW1lIHJvbGUgaW4gdGFyZ2V0IGFjY291bnQnLFxuICAgICAgICAgIC4uLihzb3VyY2VEZXNjcmlwdGlvbiA/IFtgdXNpbmcgJHtzb3VyY2VEZXNjcmlwdGlvbn1gXSA6IFtdKSxcbiAgICAgICAgICBlcnIubWVzc2FnZSxcbiAgICAgICAgICBcIi4gUGxlYXNlIG1ha2Ugc3VyZSB0aGF0IHRoaXMgcm9sZSBleGlzdHMgaW4gdGhlIGFjY291bnQuIElmIGl0IGRvZXNuJ3QgZXhpc3QsIChyZSktYm9vdHN0cmFwIHRoZSBlbnZpcm9ubWVudCBcIiArXG4gICAgICAgICAgICBcIndpdGggdGhlIHJpZ2h0ICctLXRydXN0JywgdXNpbmcgdGhlIGxhdGVzdCB2ZXJzaW9uIG9mIHRoZSBDREsgQ0xJLlwiLFxuICAgICAgICBdLmpvaW4oJyAnKSxcbiAgICAgICk7XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogQW4gQVdTIGFjY291bnRcbiAqXG4gKiBBbiBBV1MgYWNjb3VudCBhbHdheXMgZXhpc3RzIGluIG9ubHkgb25lIHBhcnRpdGlvbi4gVXN1YWxseSB3ZSBkb24ndCBjYXJlIGFib3V0XG4gKiB0aGUgcGFydGl0aW9uLCBidXQgd2hlbiB3ZSBuZWVkIHRvIGZvcm0gQVJOcyB3ZSBkby5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBBY2NvdW50IHtcbiAgLyoqXG4gICAqIFRoZSBhY2NvdW50IG51bWJlclxuICAgKi9cbiAgcmVhZG9ubHkgYWNjb3VudElkOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBwYXJ0aXRpb24gKCdhd3MnIG9yICdhd3MtY24nIG9yIG90aGVyd2lzZSlcbiAgICovXG4gIHJlYWRvbmx5IHBhcnRpdGlvbjogc3RyaW5nO1xufVxuXG4vKipcbiAqIFJldHVybiB0aGUgdXNlcm5hbWUgd2l0aCBjaGFyYWN0ZXJzIGludmFsaWQgZm9yIGEgUm9sZVNlc3Npb25OYW1lIHJlbW92ZWRcbiAqXG4gKiBAc2VlIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9TVFMvbGF0ZXN0L0FQSVJlZmVyZW5jZS9BUElfQXNzdW1lUm9sZS5odG1sI0FQSV9Bc3N1bWVSb2xlX1JlcXVlc3RQYXJhbWV0ZXJzXG4gKi9cbmZ1bmN0aW9uIHNhZmVVc2VybmFtZSgpIHtcbiAgdHJ5IHtcbiAgICByZXR1cm4gb3MudXNlckluZm8oKS51c2VybmFtZS5yZXBsYWNlKC9bXlxcdys9LC5ALV0vZywgJ0AnKTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuICdub25hbWUnO1xuICB9XG59XG5cbi8qKlxuICogT3B0aW9ucyBmb3Igb2J0YWluaW5nIGNyZWRlbnRpYWxzIGZvciBhbiBlbnZpcm9ubWVudFxuICovXG5leHBvcnQgaW50ZXJmYWNlIENyZWRlbnRpYWxzT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBUaGUgQVJOIG9mIHRoZSByb2xlIHRoYXQgbmVlZHMgdG8gYmUgYXNzdW1lZCwgaWYgYW55XG4gICAqL1xuICByZWFkb25seSBhc3N1bWVSb2xlQXJuPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBFeHRlcm5hbCBJRCByZXF1aXJlZCB0byBhc3N1bWUgdGhlIGdpdmVuIHJvbGUuXG4gICAqL1xuICByZWFkb25seSBhc3N1bWVSb2xlRXh0ZXJuYWxJZD86IHN0cmluZztcblxuICAvKipcbiAgICogU2Vzc2lvbiB0YWdzIHJlcXVpcmVkIHRvIGFzc3VtZSB0aGUgZ2l2ZW4gcm9sZS5cbiAgICovXG4gIHJlYWRvbmx5IGFzc3VtZVJvbGVBZGRpdGlvbmFsT3B0aW9ucz86IEFzc3VtZVJvbGVBZGRpdGlvbmFsT3B0aW9ucztcbn1cblxuLyoqXG4gKiBSZXN1bHQgb2Ygb2J0YWluaW5nIGJhc2UgY3JlZGVudGlhbHNcbiAqL1xudHlwZSBPYnRhaW5CYXNlQ3JlZGVudGlhbHNSZXN1bHQgPVxuICB8IHsgc291cmNlOiAnY29ycmVjdERlZmF1bHQnOyBjcmVkZW50aWFsczogQXdzQ3JlZGVudGlhbElkZW50aXR5UHJvdmlkZXIgfVxuICB8IHsgc291cmNlOiAncGx1Z2luJzsgcGx