@aws-cdk-testing/cli-integ
Version:
Integration tests for the AWS CDK CLI
352 lines • 45.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AwsClients = void 0;
exports.isStackMissingError = isStackMissingError;
exports.isBucketMissingError = isBucketMissingError;
exports.retry = retry;
exports.outputFromStack = outputFromStack;
exports.sleep = sleep;
exports.retryOnMatchingErrors = retryOnMatchingErrors;
const client_cloudformation_1 = require("@aws-sdk/client-cloudformation");
const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
const client_ecr_1 = require("@aws-sdk/client-ecr");
const client_ecr_public_1 = require("@aws-sdk/client-ecr-public");
const client_ecs_1 = require("@aws-sdk/client-ecs");
const client_iam_1 = require("@aws-sdk/client-iam");
const client_lambda_1 = require("@aws-sdk/client-lambda");
const client_s3_1 = require("@aws-sdk/client-s3");
const client_secrets_manager_1 = require("@aws-sdk/client-secrets-manager");
const client_sns_1 = require("@aws-sdk/client-sns");
const client_ssm_1 = require("@aws-sdk/client-ssm");
const client_sso_1 = require("@aws-sdk/client-sso");
const client_sts_1 = require("@aws-sdk/client-sts");
const credential_providers_1 = require("@aws-sdk/credential-providers");
const util_retry_1 = require("@smithy/util-retry");
class AwsClients {
randomString;
region;
output;
identity;
static async forIdentity(randomString, region, identity, output) {
return new AwsClients(randomString, region, output, identity);
}
static async forRegion(randomString, region, output) {
return new AwsClients(randomString, region, output);
}
cleanup = [];
config;
cloudFormation;
s3;
ecr;
ecrPublic;
ecs;
sso;
ssm;
sns;
iam;
lambda;
sts;
secretsManager;
dynamoDb;
constructor(
/** A random string to use for temporary resources, like roles (should preferably match unique test-specific randomString) */
randomString, region, output, identity) {
this.randomString = randomString;
this.region = region;
this.output = output;
this.identity = identity;
this.config = {
credentials: this.identity ?? chainableCredentials(this.region),
region: this.region,
retryStrategy: new util_retry_1.ConfiguredRetryStrategy(9, (attempt) => attempt ** 500),
};
this.cloudFormation = new client_cloudformation_1.CloudFormationClient(this.config);
this.s3 = new client_s3_1.S3Client(this.config);
this.ecr = new client_ecr_1.ECRClient(this.config);
this.ecrPublic = new client_ecr_public_1.ECRPUBLICClient({ ...this.config, region: 'us-east-1' /* public gallery is only available in us-east-1 */ });
this.ecs = new client_ecs_1.ECSClient(this.config);
this.sso = new client_sso_1.SSOClient(this.config);
this.ssm = new client_ssm_1.SSMClient(this.config);
this.sns = new client_sns_1.SNSClient(this.config);
this.iam = new client_iam_1.IAMClient(this.config);
this.lambda = new client_lambda_1.LambdaClient(this.config);
this.sts = new client_sts_1.STSClient(this.config);
this.secretsManager = new client_secrets_manager_1.SecretsManagerClient(this.config);
this.dynamoDb = new client_dynamodb_1.DynamoDB(this.config);
}
addCleanup(cleanup) {
this.cleanup.push(cleanup);
}
async dispose() {
for (const cleanup of this.cleanup) {
try {
await cleanup();
}
catch (e) {
this.output.write(`⚠️ Error during cleanup: ${e.message}\n`);
}
}
this.cleanup.splice(0, this.cleanup.length);
}
async account() {
// Reduce # of retries, we use this as a circuit breaker for detecting no-config
const stsClient = new client_sts_1.STSClient({
credentials: this.config.credentials,
region: this.config.region,
maxAttempts: 2,
});
return (await stsClient.send(new client_sts_1.GetCallerIdentityCommand({}))).Account;
}
/**
* If the clients already has an established identity (via atmosphere for example),
* return an environment variable map activating it.
*
* Otherwise, returns undefined.
*/
identityEnv() {
return this.identity ? {
AWS_ACCESS_KEY_ID: this.identity.accessKeyId,
AWS_SECRET_ACCESS_KEY: this.identity.secretAccessKey,
AWS_SESSION_TOKEN: this.identity.sessionToken,
// unset any previously used profile because the SDK will prefer
// this over static env credentials. this is relevant for tests running on CodeBuild
// because we use a profile as our main credentials source.
AWS_PROFILE: '',
} : undefined;
}
/**
* Resolve the current identity or identity provider to credentials
*/
async credentials() {
const x = this.config.credentials;
if (isAwsCredentialIdentity(x)) {
return x;
}
return x();
}
async deleteStacks(...stackNames) {
if (stackNames.length === 0) {
return;
}
// We purposely do all stacks serially, because they've been ordered
// to do the bootstrap stack last.
for (const stackName of stackNames) {
await this.cloudFormation.send(new client_cloudformation_1.UpdateTerminationProtectionCommand({
EnableTerminationProtection: false,
StackName: stackName,
}));
await this.cloudFormation.send(new client_cloudformation_1.DeleteStackCommand({
StackName: stackName,
}));
await retry(this.output, `Deleting ${stackName}`, retry.forSeconds(600), async () => {
const status = await this.stackStatus(stackName);
if (status !== undefined && status.endsWith('_FAILED')) {
throw retry.abort(new Error(`'${stackName}' is in state '${status}'`));
}
if (status !== undefined) {
throw new Error(`Delete of '${stackName}' not complete yet, status: '${status}'`);
}
});
}
}
async stackStatus(stackName) {
try {
return (await this.cloudFormation.send(new client_cloudformation_1.DescribeStacksCommand({
StackName: stackName,
}))).Stacks?.[0].StackStatus;
}
catch (e) {
if (isStackMissingError(e)) {
return undefined;
}
throw e;
}
}
async emptyBucket(bucketName, options) {
const objects = await this.s3.send(new client_s3_1.ListObjectVersionsCommand({
Bucket: bucketName,
}));
const deletes = [...(objects.Versions || []), ...(objects.DeleteMarkers || [])].reduce((acc, obj) => {
if (typeof obj.VersionId !== 'undefined' && typeof obj.Key !== 'undefined') {
acc.push({ Key: obj.Key, VersionId: obj.VersionId });
}
else if (typeof obj.Key !== 'undefined') {
acc.push({ Key: obj.Key });
}
return acc;
}, []);
if (deletes.length === 0) {
return Promise.resolve();
}
return this.s3.send(new client_s3_1.DeleteObjectsCommand({
Bucket: bucketName,
Delete: {
Objects: deletes,
Quiet: false,
},
BypassGovernanceRetention: options?.bypassGovernance ? true : undefined,
}));
}
async deleteImageRepository(repositoryName) {
await this.ecr.send(new client_ecr_1.DeleteRepositoryCommand({
repositoryName: repositoryName,
force: true,
}));
}
async deleteBucket(bucketName) {
try {
await this.emptyBucket(bucketName);
await this.s3.send(new client_s3_1.DeleteBucketCommand({
Bucket: bucketName,
}));
}
catch (e) {
if (isBucketMissingError(e)) {
return;
}
throw e;
}
}
/**
* Create a role that will be cleaned up when the AwsClients object is cleaned up
*/
async temporaryRole(namePrefix, assumeRolePolicyStatements, policyStatements) {
const response = await this.iam.send(new client_iam_1.CreateRoleCommand({
RoleName: `${namePrefix}-${this.randomString}`,
AssumeRolePolicyDocument: JSON.stringify({
Version: '2012-10-17',
Statement: assumeRolePolicyStatements,
}, undefined, 2),
Tags: [
{
Key: 'deleteme',
Value: 'true',
},
],
}));
await this.iam.send(new client_iam_1.PutRolePolicyCommand({
RoleName: `${namePrefix}-${this.randomString}`,
PolicyName: 'DefaultPolicy',
PolicyDocument: JSON.stringify({
Version: '2012-10-17',
Statement: policyStatements,
}, undefined, 2),
}));
this.addCleanup(() => this.deleteRole(response.Role.RoleName));
return response.Role?.Arn ?? '*CreateRole did not return an ARN*';
}
async waitForAssumeRole(roleArn) {
await retryOnMatchingErrors(() => this.sts.send(new client_sts_1.AssumeRoleCommand({
RoleArn: roleArn,
RoleSessionName: 'test-existence',
})), ['AccessDenied'], retry.forSeconds(60));
}
async deleteRole(name) {
const policiesResponse = await this.iam.send(new client_iam_1.ListRolePoliciesCommand({
RoleName: name,
}));
for (const policyName of policiesResponse.PolicyNames ?? []) {
await this.iam.send(new client_iam_1.DeleteRolePolicyCommand({
RoleName: name,
PolicyName: policyName,
}));
}
await this.iam.send(new client_iam_1.DeleteRoleCommand({
RoleName: name,
}));
}
}
exports.AwsClients = AwsClients;
function isStackMissingError(e) {
return e.message.indexOf('does not exist') > -1;
}
function isBucketMissingError(e) {
return e.message.indexOf('does not exist') > -1;
}
/**
* Retry an async operation until a deadline is hit.
*
* Use `retry.forSeconds()` to construct a deadline relative to right now.
*
* Exceptions will cause the operation to retry. Use `retry.abort` to annotate an exception
* to stop the retry and end in a failure.
*/
async function retry(output, operation, deadline, block) {
let i = 0;
output.write(`💈 ${operation}\n`);
while (true) {
try {
i++;
const ret = await block();
output.write(`💈 ${operation}: succeeded after ${i} attempts\n`);
return ret;
}
catch (e) {
if (e.abort || Date.now() > deadline.getTime()) {
throw new Error(`${operation}: did not succeed after ${i} attempts: ${e}`);
}
output.write(`⏳ ${operation} (${e.message})\n`);
await sleep(5000);
}
}
}
/**
* Make a deadline for the `retry` function relative to the current time.
*/
retry.forSeconds = (seconds) => {
return new Date(Date.now() + seconds * 1000);
};
/**
* Annotate an error to stop the retrying
*/
retry.abort = (e) => {
e.abort = true;
return e;
};
function outputFromStack(key, stack) {
return (stack.Outputs ?? []).find((o) => o.OutputKey === key)?.OutputValue;
}
async function sleep(ms) {
return new Promise((ok) => setTimeout(ok, ms));
}
/**
* Retry an async operation with error filtering until a deadline is hit.
*
* Use `retry.forSeconds()` to construct a deadline relative to right now.
*
* Only retries on errors with matching names in errorNames array.
*/
async function retryOnMatchingErrors(operation, errorNames, deadline, interval = 5000) {
let i = 0;
while (true) {
try {
i++;
return await operation();
}
catch (e) {
if (Date.now() > deadline.getTime()) {
throw new Error(`Operation did not succeed after ${i} attempts: ${e}`);
}
if (!errorNames.includes(e.name)) {
throw e;
}
await sleep(interval);
}
}
}
function chainableCredentials(region) {
if ((process.env.CODEBUILD_BUILD_ARN || process.env.GITHUB_RUN_ID) && process.env.AWS_PROFILE) {
// in codebuild we must assume the role that the cdk uses
// otherwise credentials will just be picked up by the normal sdk
// heuristics and expire after an hour.
return (0, credential_providers_1.fromIni)({
clientConfig: { region },
});
}
// Otherwise just get what's default
return (0, credential_providers_1.fromNodeProviderChain)({ clientConfig: { region } });
}
function isAwsCredentialIdentity(x) {
return Boolean(x && typeof x === 'object' && x.accessKeyId);
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXdzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiYXdzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQXdUQSxrREFFQztBQUVELG9EQUVDO0FBVUQsc0JBc0JDO0FBaUJELDBDQUVDO0FBRUQsc0JBRUM7QUFTRCxzREFxQkM7QUFuWkQsMEVBTXdDO0FBQ3hDLDhEQUFvRDtBQUNwRCxvREFBeUU7QUFDekUsa0VBQTZEO0FBQzdELG9EQUFnRDtBQUNoRCxvREFBOEo7QUFDOUosMERBQXNEO0FBQ3RELGtEQU00QjtBQUM1Qiw0RUFBdUU7QUFDdkUsb0RBQWdEO0FBQ2hELG9EQUFnRDtBQUNoRCxvREFBZ0Q7QUFDaEQsb0RBQTZGO0FBQzdGLHdFQUErRTtBQUUvRSxtREFBNkQ7QUFTN0QsTUFBYSxVQUFVO0lBNEJGO0lBQ0Q7SUFDQztJQUNEO0lBOUJYLE1BQU0sQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLFlBQW9CLEVBQUUsTUFBYyxFQUFFLFFBQStCLEVBQUUsTUFBNkI7UUFDbEksT0FBTyxJQUFJLFVBQVUsQ0FBQyxZQUFZLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxRQUFRLENBQUMsQ0FBQztJQUNoRSxDQUFDO0lBRU0sTUFBTSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsWUFBb0IsRUFBRSxNQUFjLEVBQUUsTUFBNkI7UUFDL0YsT0FBTyxJQUFJLFVBQVUsQ0FBQyxZQUFZLEVBQUUsTUFBTSxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQ3RELENBQUM7SUFFZ0IsT0FBTyxHQUE0QixFQUFFLENBQUM7SUFDdEMsTUFBTSxDQUFlO0lBRXRCLGNBQWMsQ0FBdUI7SUFDckMsRUFBRSxDQUFXO0lBQ2IsR0FBRyxDQUFZO0lBQ2YsU0FBUyxDQUFrQjtJQUMzQixHQUFHLENBQVk7SUFDZixHQUFHLENBQVk7SUFDZixHQUFHLENBQVk7SUFDZixHQUFHLENBQVk7SUFDZixHQUFHLENBQVk7SUFDZixNQUFNLENBQWU7SUFDckIsR0FBRyxDQUFZO0lB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QkFBbUIsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLGFBQWEsQ0FBQyxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDOUYseURBQXlEO1FBQ3pELGlFQUFpRTtRQUNqRSx1Q0FBdUM7UUFDdkMsT0FBTyxJQUFBLDhCQUFPLEVBQUM7WUFDYixZQUFZLEVBQUUsRUFBRSxNQUFNLEVBQUU7U0FDekIsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVELG9DQUFvQztJQUNwQyxPQUFPLElBQUEsNENBQXFCLEVBQUMsRUFBRSxZQUFZLEVBQUUsRUFBRSxNQUFNLEVBQUUsRUFBRSxDQUFDLENBQUM7QUFDN0QsQ0FBQztBQUVELFNBQVMsdUJBQXVCLENBQUMsQ0FBTTtJQUNyQyxPQUFPLE9BQU8sQ0FBQyxDQUFDLElBQUksT0FBTyxDQUFDLEtBQUssUUFBUSxJQUFJLENBQUMsQ0FBQyxXQUFXLENBQUMsQ0FBQztBQUM5RCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQ2xvdWRGb3JtYXRpb25DbGllbnQsXG4gIERlbGV0ZVN0YWNrQ29tbWFuZCxcbiAgRGVzY3JpYmVTdGFja3NDb21tYW5kLFxuICBVcGRhdGVUZXJtaW5hdGlvblByb3RlY3Rpb25Db21tYW5kLFxuICB0eXBlIFN0YWNrLFxufSBmcm9tICdAYXdzLXNkay9jbGllbnQtY2xvdWRmb3JtYXRpb24nO1xuaW1wb3J0IHsgRHluYW1vREIgfSBmcm9tICdAYXdzLXNkay9jbGllbnQtZHluYW1vZGInO1xuaW1wb3J0IHsgRGVsZXRlUmVwb3NpdG9yeUNvbW1hbmQsIEVDUkNsaWVudCB9IGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1lY3InO1xuaW1wb3J0IHsgRUNSUFVCTElDQ2xpZW50IH0gZnJvbSAnQGF3cy1zZGsvY2xpZW50LWVjci1wdWJsaWMnO1xuaW1wb3J0IHsgRUNTQ2xpZW50IH0gZnJvbSAnQGF3cy1zZGsvY2xpZW50LWVjcyc7XG5pbXBvcnQgeyBDcmVhdGVSb2xlQ29tbWFuZCwgRGVsZXRlUm9sZUNvbW1hbmQsIERlbGV0ZVJvbGVQb2xpY3lDb21tYW5kLCBJQU1DbGllbnQsIExpc3RSb2xlUG9saWNpZXNDb21tYW5kLCBQdXRSb2xlUG9saWN5Q29tbWFuZCB9IGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1pYW0nO1xuaW1wb3J0IHsgTGFtYmRhQ2xpZW50IH0gZnJvbSAnQGF3cy1zZGsvY2xpZW50LWxhbWJkYSc7XG5pbXBvcnQge1xuICBTM0NsaWVudCxcbiAgRGVsZXRlT2JqZWN0c0NvbW1hbmQsXG4gIExpc3RPYmplY3RWZXJzaW9uc0NvbW1hbmQsXG4gIHR5cGUgT2JqZWN0SWRlbnRpZmllcixcbiAgRGVsZXRlQnVja2V0Q29tbWFuZCxcbn0gZnJvbSAnQGF3cy1zZGsvY2xpZW50LXMzJztcbmltcG9ydCB7IFNlY3JldHNNYW5hZ2VyQ2xpZW50IH0gZnJvbSAnQGF3cy1zZGsvY2xpZW50LXNlY3JldHMtbWFuYWdlcic7XG5pbXBvcnQgeyBTTlNDbGllbnQgfSBmcm9tICdAYXdzLXNkay9jbGllbnQtc25zJztcbmltcG9ydCB7IFNTTUNsaWVudCB9IGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1zc20nO1xuaW1wb3J0IHsgU1NPQ2xpZW50IH0gZnJvbSAnQGF3cy1zZGsvY2xpZW50LXNzbyc7XG5pbXBvcnQgeyBBc3N1bWVSb2xlQ29tbWFuZCwgU1RTQ2xpZW50LCBHZXRDYWxsZXJJZGVudGl0eUNvbW1hbmQgfSBmcm9tICdAYXdzLXNkay9jbGllbnQtc3RzJztcbmltcG9ydCB7IGZyb21JbmksIGZyb21Ob2RlUHJvdmlkZXJDaGFpbiB9IGZyb20gJ0Bhd3Mtc2RrL2NyZWRlbnRpYWwtcHJvdmlkZXJzJztcbmltcG9ydCB0eXBlIHsgQXdzQ3JlZGVudGlhbElkZW50aXR5LCBBd3NDcmVkZW50aWFsSWRlbnRpdHlQcm92aWRlciwgTm9kZUh0dHBIYW5kbGVyT3B0aW9ucyB9IGZyb20gJ0BzbWl0aHkvdHlwZXMnO1xuaW1wb3J0IHsgQ29uZmlndXJlZFJldHJ5U3RyYXRlZ3kgfSBmcm9tICdAc21pdGh5L3V0aWwtcmV0cnknO1xuXG5pbnRlcmZhY2UgQ2xpZW50Q29uZmlnIHtcbiAgcmVhZG9ubHkgY3JlZGVudGlhbHM6IEF3c0NyZWRlbnRpYWxJZGVudGl0eVByb3ZpZGVyIHwgQXdzQ3JlZGVudGlhbElkZW50aXR5O1xuICByZWFkb25seSByZWdpb246IHN0cmluZztcbiAgcmVhZG9ubHkgcmV0cnlTdHJhdGVneTogQ29uZmlndXJlZFJldHJ5U3RyYXRlZ3k7XG4gIHJlYWRvbmx5IHJlcXVlc3RIYW5kbGVyPzogTm9kZUh0dHBIYW5kbGVyT3B0aW9ucztcbn1cblxuZXhwb3J0IGNsYXNzIEF3c0NsaWVudHMge1xuICBwdWJsaWMgc3RhdGljIGFzeW5jIGZvcklkZW50aXR5KHJhbmRvbVN0cmluZzogc3RyaW5nLCByZWdpb246IHN0cmluZywgaWRlbnRpdHk6IEF3c0NyZWRlbnRpYWxJZGVudGl0eSwgb3V0cHV0OiBOb2RlSlMuV3JpdGFibGVTdHJlYW0pIHtcbiAgICByZXR1cm4gbmV3IEF3c0NsaWVudHMocmFuZG9tU3RyaW5nLCByZWdpb24sIG91dHB1dCwgaWRlbnRpdHkpO1xuICB9XG5cbiAgcHVibGljIHN0YXRpYyBhc3luYyBmb3JSZWdpb24ocmFuZG9tU3RyaW5nOiBzdHJpbmcsIHJlZ2lvbjogc3RyaW5nLCBvdXRwdXQ6IE5vZGVKUy5Xcml0YWJsZVN0cmVhbSkge1xuICAgIHJldHVybiBuZXcgQXdzQ2xpZW50cyhyYW5kb21TdHJpbmcsIHJlZ2lvbiwgb3V0cHV0KTtcbiAgfVxuXG4gIHByaXZhdGUgcmVhZG9ubHkgY2xlYW51cDogKCgpID0+IFByb21pc2U8dm9pZD4pW10gPSBbXTtcbiAgcHJpdmF0ZSByZWFkb25seSBjb25maWc6IENsaWVudENvbmZpZztcblxuICBwdWJsaWMgcmVhZG9ubHkgY2xvdWRGb3JtYXRpb246IENsb3VkRm9ybWF0aW9uQ2xpZW50O1xuICBwdWJsaWMgcmVhZG9ubHkgczM6IFMzQ2xpZW50O1xuICBwdWJsaWMgcmVhZG9ubHkgZWNyOiBFQ1JDbGllbnQ7XG4gIHB1YmxpYyByZWFkb25seSBlY3JQdWJsaWM6IEVDUlBVQkxJQ0NsaWVudDtcbiAgcHVibGljIHJlYWRvbmx5IGVjczogRUNTQ2xpZW50O1xuICBwdWJsaWMgcmVhZG9ubHkgc3NvOiBTU09DbGllbnQ7XG4gIHB1YmxpYyByZWFkb25seSBzc206IFNTTUNsaWVudDtcbiAgcHVibGljIHJlYWRvbmx5IHNuczogU05TQ2xpZW50O1xuICBwdWJsaWMgcmVhZG9ubHkgaWFtOiBJQU1DbGllbnQ7XG4gIHB1YmxpYyByZWFkb25seSBsYW1iZGE6IExhbWJkYUNsaWVudDtcbiAgcHVibGljIHJlYWRvbmx5IHN0czogU1RTQ2xpZW50O1xuICBwdWJsaWMgcmVhZG9ubHkgc2VjcmV0c01hbmFnZXI6IFNlY3JldHNNYW5hZ2VyQ2xpZW50O1xuICBwdWJsaWMgcmVhZG9ubHkgZHluYW1vRGI6IER5bmFtb0RCO1xuXG4gIHByaXZhdGUgY29uc3RydWN0b3IoXG4gICAgLyoqIEEgcmFuZG9tIHN0cmluZyB0byB1c2UgZm9yIHRlbXBvcmFyeSByZXNvdXJjZXMsIGxpa2Ugcm9sZXMgKHNob3VsZCBwcmVmZXJhYmx5IG1hdGNoIHVuaXF1ZSB0ZXN0LXNwZWNpZmljIHJhbmRvbVN0cmluZykgKi9cbiAgICBwcml2YXRlIHJlYWRvbmx5IHJhbmRvbVN0cmluZzogc3RyaW5nLFxuICAgIHB1YmxpYyByZWFkb25seSByZWdpb246IHN0cmluZyxcbiAgICBwcml2YXRlIHJlYWRvbmx5IG91dHB1dDogTm9kZUpTLldyaXRhYmxlU3RyZWFtLFxuICAgIHB1YmxpYyByZWFkb25seSBpZGVudGl0eT86IEF3c0NyZWRlbnRpYWxJZGVudGl0eSkge1xuICAgIHRoaXMuY29uZmlnID0ge1xuICAgICAgY3JlZGVudGlhbHM6IHRoaXMuaWRlbnRpdHkgPz8gY2hhaW5hYmxlQ3JlZGVudGlhbHModGhpcy5yZWdpb24pLFxuICAgICAgcmVnaW9uOiB0aGlzLnJlZ2lvbixcbiAgICAgIHJldHJ5U3RyYXRlZ3k6IG5ldyBDb25maWd1cmVkUmV0cnlTdHJhdGVneSg5LCAoYXR0ZW1wdDogbnVtYmVyKSA9PiBhdHRlbXB0ICoqIDUwMCksXG4gICAgfTtcblxuICAgIHRoaXMuY2xvdWRGb3JtYXRpb24gPSBuZXcgQ2xvdWRGb3JtYXRpb25DbGllbnQodGhpcy5jb25maWcpO1xuICAgIHRoaXMuczMgPSBuZXcgUzNDbGllbnQodGhpcy5jb25maWcpO1xuICAgIHRoaXMuZWNyID0gbmV3IEVDUkNsaWVudCh0aGlzLmNvbmZpZyk7XG4gICAgdGhpcy5lY3JQdWJsaWMgPSBuZXcgRUNSUFVCTElDQ2xpZW50KHsgLi4udGhpcy5jb25maWcsIHJlZ2lvbjogJ3VzLWVhc3QtMScgLyogcHVibGljIGdhbGxlcnkgaXMgb25seSBhdmFpbGFibGUgaW4gdXMtZWFzdC0xICovIH0pO1xuICAgIHRoaXMuZWNzID0gbmV3IEVDU0NsaWVudCh0aGlzLmNvbmZpZyk7XG4gICAgdGhpcy5zc28gPSBuZXcgU1NPQ2xpZW50KHRoaXMuY29uZmlnKTtcbiAgICB0aGlzLnNzbSA9IG5ldyBTU01DbGllbnQodGhpcy5jb25maWcpO1xuICAgIHRoaXMuc25zID0gbmV3IFNOU0NsaWVudCh0aGlzLmNvbmZpZyk7XG4gICAgdGhpcy5pYW0gPSBuZXcgSUFNQ2xpZW50KHRoaXMuY29uZmlnKTtcbiAgICB0aGlzLmxhbWJkYSA9IG5ldyBMYW1iZGFDbGllbnQodGhpcy5jb25maWcpO1xuICAgIHRoaXMuc3RzID0gbmV3IFNUU0NsaWVudCh0aGlzLmNvbmZpZyk7XG4gICAgdGhpcy5zZWNyZXRzTWFuYWdlciA9IG5ldyBTZWNyZXRzTWFuYWdlckNsaWVudCh0aGlzLmNvbmZpZyk7XG4gICAgdGhpcy5keW5hbW9EYiA9IG5ldyBEeW5hbW9EQih0aGlzLmNvbmZpZyk7XG4gIH1cblxuICBwdWJsaWMgYWRkQ2xlYW51cChjbGVhbnVwOiAoKSA9PiBQcm9taXNlPGFueT4pIHtcbiAgICB0aGlzLmNsZWFudXAucHVzaChjbGVhbnVwKTtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBkaXNwb3NlKCkge1xuICAgIGZvciAoY29uc3QgY2xlYW51cCBvZiB0aGlzLmNsZWFudXApIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IGNsZWFudXAoKTtcbiAgICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgICB0aGlzLm91dHB1dC53cml0ZShg4pqg77iPIEVycm9yIGR1cmluZyBjbGVhbnVwOiAke2UubWVzc2FnZX1cXG5gKTtcbiAgICAgIH1cbiAgICB9XG4gICAgdGhpcy5jbGVhbnVwLnNwbGljZSgwLCB0aGlzLmNsZWFudXAubGVuZ3RoKTtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBhY2NvdW50KCk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgLy8gUmVkdWNlICMgb2YgcmV0cmllcywgd2UgdXNlIHRoaXMgYXMgYSBjaXJjdWl0IGJyZWFrZXIgZm9yIGRldGVjdGluZyBuby1jb25maWdcbiAgICBjb25zdCBzdHNDbGllbnQgPSBuZXcgU1RTQ2xpZW50KHtcbiAgICAgIGNyZWRlbnRpYWxzOiB0aGlzLmNvbmZpZy5jcmVkZW50aWFscyxcbiAgICAgIHJlZ2lvbjogdGhpcy5jb25maWcucmVnaW9uLFxuICAgICAgbWF4QXR0ZW1wdHM6IDIsXG4gICAgfSk7XG5cbiAgICByZXR1cm4gKGF3YWl0IHN0c0NsaWVudC5zZW5kKG5ldyBHZXRDYWxsZXJJZGVudGl0eUNvbW1hbmQoe30pKSkuQWNjb3VudCE7XG4gIH1cblxuICAvKipcbiAgICogSWYgdGhlIGNsaWVudHMgYWxyZWFkeSBoYXMgYW4gZXN0YWJsaXNoZWQgaWRlbnRpdHkgKHZpYSBhdG1vc3BoZXJlIGZvciBleGFtcGxlKSxcbiAgICogcmV0dXJuIGFuIGVudmlyb25tZW50IHZhcmlhYmxlIG1hcCBhY3RpdmF0aW5nIGl0LlxuICAgKlxuICAgKiBPdGhlcndpc2UsIHJldHVybnMgdW5kZWZpbmVkLlxuICAgKi9cbiAgcHVibGljIGlkZW50aXR5RW52KCk6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLmlkZW50aXR5ID8ge1xuICAgICAgQVdTX0FDQ0VTU19LRVlfSUQ6IHRoaXMuaWRlbnRpdHkuYWNjZXNzS2V5SWQsXG4gICAgICBBV1NfU0VDUkVUX0FDQ0VTU19LRVk6IHRoaXMuaWRlbnRpdHkuc2VjcmV0QWNjZXNzS2V5LFxuICAgICAgQVdTX1NFU1NJT05fVE9LRU46IHRoaXMuaWRlbnRpdHkuc2Vzc2lvblRva2VuISxcblxuICAgICAgLy8gdW5zZXQgYW55IHByZXZpb3VzbHkgdXNlZCBwcm9maWxlIGJlY2F1c2UgdGhlIFNESyB3aWxsIHByZWZlclxuICAgICAgLy8gdGhpcyBvdmVyIHN0YXRpYyBlbnYgY3JlZGVudGlhbHMuIHRoaXMgaXMgcmVsZXZhbnQgZm9yIHRlc3RzIHJ1bm5pbmcgb24gQ29kZUJ1aWxkXG4gICAgICAvLyBiZWNhdXNlIHdlIHVzZSBhIHByb2ZpbGUgYXMgb3VyIG1haW4gY3JlZGVudGlhbHMgc291cmNlLlxuICAgICAgQVdTX1BST0ZJTEU6ICcnLFxuICAgIH0gOiB1bmRlZmluZWQ7XG4gIH1cblxuICAvKipcbiAgICogUmVzb2x2ZSB0aGUgY3VycmVudCBpZGVudGl0eSBvciBpZGVudGl0eSBwcm92aWRlciB0byBjcmVkZW50aWFsc1xuICAgKi9cbiAgcHVibGljIGFzeW5jIGNyZWRlbnRpYWxzKCkge1xuICAgIGNvbnN0IHggPSB0aGlzLmNvbmZpZy5jcmVkZW50aWFscztcbiAgICBpZiAoaXNBd3NDcmVkZW50aWFsSWRlbnRpdHkoeCkpIHtcbiAgICAgIHJldHVybiB4O1xuICAgIH1cbiAgICByZXR1cm4geCgpO1xuICB9XG5cbiAgcHVibGljIGFzeW5jIGRlbGV0ZVN0YWNrcyguLi5zdGFja05hbWVzOiBzdHJpbmdbXSkge1xuICAgIGlmIChzdGFja05hbWVzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIFdlIHB1cnBvc2VseSBkbyBhbGwgc3RhY2tzIHNlcmlhbGx5LCBiZWNhdXNlIHRoZXkndmUgYmVlbiBvcmRlcmVkXG4gICAgLy8gdG8gZG8gdGhlIGJvb3RzdHJhcCBzdGFjayBsYXN0LlxuICAgIGZvciAoY29uc3Qgc3RhY2tOYW1lIG9mIHN0YWNrTmFtZXMpIHtcbiAgICAgIGF3YWl0IHRoaXMuY2xvdWRGb3JtYXRpb24uc2VuZChcbiAgICAgICAgbmV3IFVwZGF0ZVRlcm1pbmF0aW9uUHJvdGVjdGlvbkNvbW1hbmQoe1xuICAgICAgICAgIEVuYWJsZVRlcm1pbmF0aW9uUHJvdGVjdGlvbjogZmFsc2UsXG4gICAgICAgICAgU3RhY2tOYW1lOiBzdGFja05hbWUsXG4gICAgICAgIH0pLFxuICAgICAgKTtcbiAgICAgIGF3YWl0IHRoaXMuY2xvdWRGb3JtYXRpb24uc2VuZChcbiAgICAgICAgbmV3IERlbGV0ZVN0YWNrQ29tbWFuZCh7XG4gICAgICAgICAgU3RhY2tOYW1lOiBzdGFja05hbWUsXG4gICAgICAgIH0pLFxuICAgICAgKTtcblxuICAgICAgYXdhaXQgcmV0cnkodGhpcy5vdXRwdXQsIGBEZWxldGluZyAke3N0YWNrTmFtZX1gLCByZXRyeS5mb3JTZWNvbmRzKDYwMCksIGFzeW5jICgpID0+IHtcbiAgICAgICAgY29uc3Qgc3RhdHVzID0gYXdhaXQgdGhpcy5zdGFja1N0YXR1cyhzdGFja05hbWUpO1xuICAgICAgICBpZiAoc3RhdHVzICE9PSB1bmRlZmluZWQgJiYgc3RhdHVzLmVuZHNXaXRoKCdfRkFJTEVEJykpIHtcbiAgICAgICAgICB0aHJvdyByZXRyeS5hYm9ydChuZXcgRXJyb3IoYCcke3N0YWNrTmFtZX0nIGlzIGluIHN0YXRlICcke3N0YXR1c30nYCkpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChzdGF0dXMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgRGVsZXRlIG9mICcke3N0YWNrTmFtZX0nIG5vdCBjb21wbGV0ZSB5ZXQsIHN0YXR1czogJyR7c3RhdHVzfSdgKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgcHVibGljIGFzeW5jIHN0YWNrU3RhdHVzKHN0YWNrTmFtZTogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmcgfCB1bmRlZmluZWQ+IHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIChcbiAgICAgICAgYXdhaXQgdGhpcy5jbG91ZEZvcm1hdGlvbi5zZW5kKFxuICAgICAgICAgIG5ldyBEZXNjcmliZVN0YWNrc0NvbW1hbmQoe1xuICAgICAgICAgICAgU3RhY2tOYW1lOiBzdGFja05hbWUsXG4gICAgICAgICAgfSksXG4gICAgICAgIClcbiAgICAgICkuU3RhY2tzPy5bMF0uU3RhY2tTdGF0dXM7XG4gICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICBpZiAoaXNTdGFja01pc3NpbmdFcnJvcihlKSkge1xuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgfVxuICAgICAgdGhyb3cgZTtcbiAgICB9XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgZW1wdHlCdWNrZXQoYnVja2V0TmFtZTogc3RyaW5nLCBvcHRpb25zPzogeyBieXBhc3NHb3Zlcm5hbmNlPzogYm9vbGVhbiB9KSB7XG4gICAgY29uc3Qgb2JqZWN0cyA9IGF3YWl0IHRoaXMuczMuc2VuZChcbiAgICAgIG5ldyBMaXN0T2JqZWN0VmVyc2lvbnNDb21tYW5kKHtcbiAgICAgICAgQnVja2V0OiBidWNrZXROYW1lLFxuICAgICAgfSksXG4gICAgKTtcblxuICAgIGNvbnN0IGRlbGV0ZXMgPSBbLi4uKG9iamVjdHMuVmVyc2lvbnMgfHwgW10pLCAuLi4ob2JqZWN0cy5EZWxldGVNYXJrZXJzIHx8IFtdKV0ucmVkdWNlKChhY2MsIG9iaikgPT4ge1xuICAgICAgaWYgKHR5cGVvZiBvYmouVmVyc2lvbklkICE9PSAndW5kZWZpbmVkJyAmJiB0eXBlb2Ygb2JqLktleSAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgYWNjLnB1c2goeyBLZXk6IG9iai5LZXksIFZlcnNpb25JZDogb2JqLlZlcnNpb25JZCB9KTtcbiAgICAgIH0gZWxzZSBpZiAodHlwZW9mIG9iai5LZXkgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgIGFjYy5wdXNoKHsgS2V5OiBvYmouS2V5IH0pO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGFjYztcbiAgICB9LCBbXSBhcyBPYmplY3RJZGVudGlmaWVyW10pO1xuXG4gICAgaWYgKGRlbGV0ZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuczMuc2VuZChcbiAgICAgIG5ldyBEZWxldGVPYmplY3RzQ29tbWFuZCh7XG4gICAgICAgIEJ1Y2tldDogYnVja2V0TmFtZSxcbiAgICAgICAgRGVsZXRlOiB7XG4gICAgICAgICAgT2JqZWN0czogZGVsZXRlcyxcbiAgICAgICAgICBRdWlldDogZmFsc2UsXG4gICAgICAgIH0sXG4gICAgICAgIEJ5cGFzc0dvdmVybmFuY2VSZXRlbnRpb246IG9wdGlvbnM/LmJ5cGFzc0dvdmVybmFuY2UgPyB0cnVlIDogdW5kZWZpbmVkLFxuICAgICAgfSksXG4gICAgKTtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBkZWxldGVJbWFnZVJlcG9zaXRvcnkocmVwb3NpdG9yeU5hbWU6IHN0cmluZykge1xuICAgIGF3YWl0IHRoaXMuZWNyLnNlbmQoXG4gICAgICBuZXcgRGVsZXRlUmVwb3NpdG9yeUNvbW1hbmQoe1xuICAgICAgICByZXBvc2l0b3J5TmFtZTogcmVwb3NpdG9yeU5hbWUsXG4gICAgICAgIGZvcmNlOiB0cnVlLFxuICAgICAgfSksXG4gICAgKTtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBkZWxldGVCdWNrZXQoYnVja2V0TmFtZTogc3RyaW5nKSB7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHRoaXMuZW1wdHlCdWNrZXQoYnVja2V0TmFtZSk7XG5cbiAgICAgIGF3YWl0IHRoaXMuczMuc2VuZChcbiAgICAgICAgbmV3IERlbGV0ZUJ1Y2tldENvbW1hbmQoe1xuICAgICAgICAgIEJ1Y2tldDogYnVja2V0TmFtZSxcbiAgICAgICAgfSksXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgaWYgKGlzQnVja2V0TWlzc2luZ0Vycm9yKGUpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHRocm93IGU7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZSBhIHJvbGUgdGhhdCB3aWxsIGJlIGNsZWFuZWQgdXAgd2hlbiB0aGUgQXdzQ2xpZW50cyBvYmplY3QgaXMgY2xlYW5lZCB1cFxuICAgKi9cbiAgcHVibGljIGFzeW5jIHRlbXBvcmFyeVJvbGUobmFtZVByZWZpeDogc3RyaW5nLCBhc3N1bWVSb2xlUG9saWN5U3RhdGVtZW50czogYW55W10sIHBvbGljeVN0YXRlbWVudHM6IGFueVtdKSB7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCB0aGlzLmlhbS5zZW5kKG5ldyBDcmVhdGVSb2xlQ29tbWFuZCh7XG4gICAgICBSb2xlTmFtZTogYCR7bmFtZVByZWZpeH0tJHt0aGlzLnJhbmRvbVN0cmluZ31gLFxuICAgICAgQXNzdW1lUm9sZVBvbGljeURvY3VtZW50OiBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgIFZlcnNpb246ICcyMDEyLTEwLTE3JyxcbiAgICAgICAgU3RhdGVtZW50OiBhc3N1bWVSb2xlUG9saWN5U3RhdGVtZW50cyxcbiAgICAgIH0sIHVuZGVmaW5lZCwgMiksXG4gICAgICBUYWdzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBLZXk6ICdkZWxldGVtZScsXG4gICAgICAgICAgVmFsdWU6ICd0cnVlJyxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgfSkpO1xuICAgIGF3YWl0IHRoaXMuaWFtLnNlbmQobmV3IFB1dFJvbGVQb2xpY3lDb21tYW5kKHtcbiAgICAgIFJvbGVOYW1lOiBgJHtuYW1lUHJlZml4fS0ke3RoaXMucmFuZG9tU3RyaW5nfWAsXG4gICAgICBQb2xpY3lOYW1lOiAnRGVmYXVsdFBvbGljeScsXG4gICAgICBQb2xpY3lEb2N1bWVudDogSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICBWZXJzaW9uOiAnMjAxMi0xMC0xNycsXG4gICAgICAgIFN0YXRlbWVudDogcG9saWN5U3RhdGVtZW50cyxcbiAgICAgIH0sIHVuZGVmaW5lZCwgMiksXG4gICAgfSkpO1xuXG4gICAgdGhpcy5hZGRDbGVhbnVwKCgpID0+IHRoaXMuZGVsZXRlUm9sZShyZXNwb25zZS5Sb2xlIS5Sb2xlTmFtZSEpKTtcblxuICAgIHJldHVybiByZXNwb25zZS5Sb2xlPy5Bcm4gPz8gJypDcmVhdGVSb2xlIGRpZCBub3QgcmV0dXJuIGFuIEFSTionO1xuICB9XG5cbiAgcHVibGljIGFzeW5jIHdhaXRGb3JBc3N1bWVSb2xlKHJvbGVBcm46IHN0cmluZykge1xuICAgIGF3YWl0IHJldHJ5T25NYXRjaGluZ0Vycm9ycyhcbiAgICAgICgpID0+IHRoaXMuc3RzLnNlbmQobmV3IEFzc3VtZVJvbGVDb21tYW5kKHtcbiAgICAgICAgUm9sZUFybjogcm9sZUFybixcbiAgICAgICAgUm9sZVNlc3Npb25OYW1lOiAndGVzdC1leGlzdGVuY2UnLFxuICAgICAgfSkpLFxuICAgICAgWydBY2Nlc3NEZW5pZWQnXSxcbiAgICAgIHJldHJ5LmZvclNlY29uZHMoNjApLFxuICAgICk7XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgZGVsZXRlUm9sZShuYW1lOiBzdHJpbmcpIHtcbiAgICBjb25zdCBwb2xpY2llc1Jlc3BvbnNlID0gYXdhaXQgdGhpcy5pYW0uc2VuZChuZXcgTGlzdFJvbGVQb2xpY2llc0NvbW1hbmQoe1xuICAgICAgUm9sZU5hbWU6IG5hbWUsXG4gICAgfSkpO1xuXG4gICAgZm9yIChjb25zdCBwb2xpY3lOYW1lIG9mIHBvbGljaWVzUmVzcG9uc2UuUG9saWN5TmFtZXMgPz8gW10pIHtcbiAgICAgIGF3YWl0IHRoaXMuaWFtLnNlbmQobmV3IERlbGV0ZVJvbGVQb2xpY3lDb21tYW5kKHtcbiAgICAgICAgUm9sZU5hbWU6IG5hbWUsXG4gICAgICAgIFBvbGljeU5hbWU6IHBvbGljeU5hbWUsXG4gICAgICB9KSk7XG4gICAgfVxuXG4gICAgYXdhaXQgdGhpcy5pYW0uc2VuZChuZXcgRGVsZXRlUm9sZUNvbW1hbmQoe1xuICAgICAgUm9sZU5hbWU6IG5hbWUsXG4gICAgfSkpO1xuICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpc1N0YWNrTWlzc2luZ0Vycm9yKGU6IEVycm9yKSB7XG4gIHJldHVybiBlLm1lc3NhZ2UuaW5kZXhPZignZG9lcyBub3QgZXhpc3QnKSA+IC0xO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaXNCdWNrZXRNaXNzaW5nRXJyb3IoZTogRXJyb3IpIHtcbiAgcmV0dXJuIGUubWVzc2FnZS5pbmRleE9mKCdkb2VzIG5vdCBleGlzdCcpID4gLTE7XG59XG5cbi8qKlxuICogUmV0cnkgYW4gYXN5bmMgb3BlcmF0aW9uIHVudGlsIGEgZGVhZGxpbmUgaXMgaGl0LlxuICpcbiAqIFVzZSBgcmV0cnkuZm9yU2Vjb25kcygpYCB0byBjb25zdHJ1Y3QgYSBkZWFkbGluZSByZWxhdGl2ZSB0byByaWdodCBub3cuXG4gKlxuICogRXhjZXB0aW9ucyB3aWxsIGNhdXNlIHRoZSBvcGVyYXRpb24gdG8gcmV0cnkuIFVzZSBgcmV0cnkuYWJvcnRgIHRvIGFubm90YXRlIGFuIGV4Y2VwdGlvblxuICogdG8gc3RvcCB0aGUgcmV0cnkgYW5kIGVuZCBpbiBhIGZhaWx1cmUuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZXRyeTxBPihcbiAgb3V0cHV0OiBOb2RlSlMuV3JpdGFibGVTdHJlYW0sXG4gIG9wZXJhdGlvbjogc3RyaW5nLFxuICBkZWFkbGluZTogRGF0ZSxcbiAgYmxvY2s6ICgpID0+IFByb21pc2U8QT4sXG4pOiBQcm9taXNlPEE+IHtcbiAgbGV0IGkgPSAwO1xuICBvdXRwdXQud3JpdGUoYPCfkoggJHtvcGVyYXRpb259XFxuYCk7XG4gIHdoaWxlICh0cnVlKSB7XG4gICAgdHJ5IHtcbiAgICAgIGkrKztcbiAgICAgIGNvbnN0IHJldCA9IGF3YWl0IGJsb2NrKCk7XG4gICAgICBvdXRwdXQud3JpdGUoYPCfkoggJHtvcGVyYXRpb259OiBzdWNjZWVkZWQgYWZ0ZXIgJHtpfSBhdHRlbXB0c1xcbmApO1xuICAgICAgcmV0dXJuIHJldDtcbiAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgIGlmIChlLmFib3J0IHx8IERhdGUubm93KCkgPiBkZWFkbGluZS5nZXRUaW1lKCkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGAke29wZXJhdGlvbn06IGRpZCBub3Qgc3VjY2VlZCBhZnRlciAke2l9IGF0dGVtcHRzOiAke2V9YCk7XG4gICAgICB9XG4gICAgICBvdXRwdXQud3JpdGUoYOKPsyAke29wZXJhdGlvbn0gKCR7ZS5tZXNzYWdlfSlcXG5gKTtcbiAgICAgIGF3YWl0IHNsZWVwKDUwMDApO1xuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIE1ha2UgYSBkZWFkbGluZSBmb3IgdGhlIGByZXRyeWAgZnVuY3Rpb24gcmVsYXRpdmUgdG8gdGhlIGN1cnJlbnQgdGltZS5cbiAqL1xucmV0cnkuZm9yU2Vjb25kcyA9IChzZWNvbmRzOiBudW1iZXIpOiBEYXRlID0+IHtcbiAgcmV0dXJuIG5ldyBEYXRlKERhdGUubm93KCkgKyBzZWNvbmRzICogMTAwMCk7XG59O1xuXG4vKipcbiAqIEFubm90YXRlIGFuIGVycm9yIHRvIHN0b3AgdGhlIHJldHJ5aW5nXG4gKi9cbnJldHJ5LmFib3J0ID0gKGU6IEVycm9yKTogRXJyb3IgPT4ge1xuICAoZSBhcyBhbnkpLmFib3J0ID0gdHJ1ZTtcbiAgcmV0dXJuIGU7XG59O1xuXG5leHBvcnQgZnVuY3Rpb24gb3V0cHV0RnJvbVN0YWNrKGtleTogc3RyaW5nLCBzdGFjazogU3RhY2spOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICByZXR1cm4gKHN0YWNrLk91dHB1dHMgPz8gW10pLmZpbmQoKG8pID0+IG8uT3V0cHV0S2V5ID09PSBrZXkpPy5PdXRwdXRWYWx1ZTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNsZWVwKG1zOiBudW1iZXIpIHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChvaykgPT4gc2V0VGltZW91dChvaywgbXMpKTtcbn1cblxuLyoqXG4gKiBSZXRyeSBhbiBhc3luYyBvcGVyYXRpb24gd2l0aCBlcnJvciBmaWx0ZXJpbmcgdW50aWwgYSBkZWFkbGluZSBpcyBoaXQuXG4gKlxuICogVXNlIGByZXRyeS5mb3JTZWNvbmRzKClgIHRvIGNvbnN0cnVjdCBhIGRlYWRsaW5lIHJlbGF0aXZlIHRvIHJpZ2h0IG5vdy5cbiAqXG4gKiBPbmx5IHJldHJpZXMgb24gZXJyb3JzIHdpdGggbWF0Y2hpbmcgbmFtZXMgaW4gZXJyb3JOYW1lcyBhcnJheS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJldHJ5T25NYXRjaGluZ0Vycm9yczxUPihcbiAgb3BlcmF0aW9uOiAoKSA9PiBQcm9taXNlPFQ+LFxuICBlcnJvck5hbWVzOiBzdHJpbmdbXSxcbiAgZGVhZGxpbmU6IERhdGUsXG4gIGludGVydmFsOiBudW1iZXIgPSA1MDAwLFxuKTogUHJvbWlzZTxUPiB7XG4gIGxldCBpID0gMDtcbiAgd2hpbGUgKHRydWUpIHtcbiAgICB0cnkge1xuICAgICAgaSsrO1xuICAgICAgcmV0dXJuIGF3YWl0IG9wZXJhdGlvbigpO1xuICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgaWYgKERhdGUubm93KCkgPiBkZWFkbGluZS5nZXRUaW1lKCkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBPcGVyYXRpb24gZGlkIG5vdCBzdWNjZWVkIGFmdGVyICR7aX0gYXR0ZW1wdHM6ICR7ZX1gKTtcbiAgICAgIH1cbiAgICAgIGlmICghZXJyb3JOYW1lcy5pbmNsdWRlcyhlLm5hbWUpKSB7XG4gICAgICAgIHRocm93IGU7XG4gICAgICB9XG4gICAgICBhd2FpdCBzbGVlcChpbnRlcnZhbCk7XG4gICAgfVxuICB9XG59XG5cbmZ1bmN0aW9uIGNoYWluYWJsZUNyZWRlbnRpYWxzKHJlZ2lvbjogc3RyaW5nKTogQXdzQ3JlZGVudGlhbElkZW50aXR5UHJvdmlkZXIge1xuICBpZiAoKHByb2Nlc3MuZW52LkNPREVCVUlMRF9CVUlMRF9BUk4gfHwgcHJvY2Vzcy5lbnYuR0lUSFVCX1JVTl9JRCkgJiYgcHJvY2Vzcy5lbnYuQVdTX1BST0ZJTEUpIHtcbiAgICAvLyBpbiBjb2RlYnVpbGQgd2UgbXVzdCBhc3N1bWUgdGhlIHJvbGUgdGhhdCB0aGUgY2RrIHVzZXNcbiAgICAvLyBvdGhlcndpc2UgY3JlZGVudGlhbHMgd2lsbCBqdXN0IGJlIHBpY2tlZCB1cCBieSB0aGUgbm9ybWFsIHNka1xuICAgIC8vIGhldXJpc3RpY3MgYW5kIGV4cGlyZSBhZnRlciBhbiBob3VyLlxuICAgIHJldHVybiBmcm9tSW5pKHtcbiAgICAgIGNsaWVudENvbmZpZzogeyByZWdpb24gfSxcbiAgICB9KTtcbiAgfVxuXG4gIC8vIE90aGVyd2lzZSBqdXN0IGdldCB3aGF0J3MgZGVmYXVsdFxuICByZXR1cm4gZnJvbU5vZGVQcm92aWRlckNoYWluKHsgY2xpZW50Q29uZmlnOiB7IHJlZ2lvbiB9IH0pO1xufVxuXG5mdW5jdGlvbiBpc0F3c0NyZWRlbnRpYWxJZGVudGl0eSh4OiBhbnkpOiB4IGlzIEF3c0NyZWRlbnRpYWxJZGVudGl0eSB7XG4gIHJldHVybiBCb29sZWFuKHggJiYgdHlwZW9mIHggPT09ICdvYmplY3QnICYmIHguYWNjZXNzS2V5SWQpO1xufVxuIl19