@aws-solutions-constructs/core
Version:
Core CDK Construct for patterns library
489 lines • 58.2 kB
JavaScript
"use strict";
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance
* with the License. A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES
* OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions
* and limitations under the License.
*/
Object.defineProperty(exports, "__esModule", { value: true });
const aws_cdk_lib_1 = require("aws-cdk-lib");
// import * as defaults from '../index';
const assertions_1 = require("aws-cdk-lib/assertions");
const kendra_helper_1 = require("../lib/kendra-helper");
const kendra = require("aws-cdk-lib/aws-kendra");
const iam = require("aws-cdk-lib/aws-iam");
// import { Construct } from 'constructs';
test('Launch Kendra index with defaults', () => {
const stack = new aws_cdk_lib_1.Stack(undefined, undefined);
(0, kendra_helper_1.buildKendraIndex)(stack, 'test', {});
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties('AWS::Kendra::Index', {});
template.resourceCountIs("AWS::IAM::Role", 1);
});
test('Confirm kendra has log writing privileges', () => {
const stack = new aws_cdk_lib_1.Stack(undefined, undefined);
(0, kendra_helper_1.buildKendraIndex)(stack, 'test', {});
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties("AWS::IAM::Role", {
Description: "Allow Kendra index to write CloudWatch Logs",
Policies: [
{
PolicyDocument: {
Statement: [
{
Action: "cloudwatch:PutMetricData",
Condition: {
StringEquals: {
"cloudwatch:namespace": "AWS/Kendra"
}
},
Effect: "Allow",
Resource: "*"
},
{
Action: "logs:CreateLogGroup",
Effect: "Allow",
Resource: {
"Fn::Join": [
"",
[
"arn:aws:logs:",
{
Ref: "AWS::Region"
},
":",
{
Ref: "AWS::AccountId"
},
":log-group:/aws/kendra/*"
]
]
}
},
{
Action: "logs:DescribeLogGroups",
Effect: "Allow",
Resource: {
"Fn::Join": [
"",
[
"arn:",
{
Ref: "AWS::Partition"
},
":logs:",
{
Ref: "AWS::Region"
},
":",
{
Ref: "AWS::AccountId"
},
":log-group:/aws/kendra/*"
]
]
}
},
{
Action: [
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:DescribeLogStream"
],
Effect: "Allow",
Resource: {
"Fn::Join": [
"",
[
"arn:",
{
Ref: "AWS::Partition"
},
":logs:",
{
Ref: "AWS::Region"
},
":",
{
Ref: "AWS::AccountId"
},
":log-group:/aws/kendra/*:log-stream:*"
]
]
}
}
],
Version: "2012-10-17"
},
PolicyName: "AllowLogging"
}
],
});
});
test('Launch Kendra index with custom properties', () => {
const testName = 'test-index-name';
const stack = new aws_cdk_lib_1.Stack(undefined, undefined);
(0, kendra_helper_1.buildKendraIndex)(stack, 'test', {
kendraIndexProps: {
name: testName
}
});
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties('AWS::Kendra::Index', {
Name: testName
});
template.resourceCountIs("AWS::IAM::Role", 1);
});
test('Launch Kendra index with existing role', () => {
const fakeRoleArn = 'fake-arn';
const stack = new aws_cdk_lib_1.Stack(undefined, undefined);
(0, kendra_helper_1.buildKendraIndex)(stack, 'test', {
kendraIndexProps: {
roleArn: fakeRoleArn
}
});
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties('AWS::Kendra::Index', {
RoleArn: fakeRoleArn
});
template.resourceCountIs("AWS::IAM::Role", 0);
});
test('use existing Kendra index', () => {
const stack = new aws_cdk_lib_1.Stack(undefined, undefined);
const indexProps = {
edition: 'DEVELOPER_EDITION',
name: 'kendra-test',
roleArn: 'fake-arn'
};
const testIndex = new kendra.CfnIndex(stack, `test`, indexProps);
(0, kendra_helper_1.buildKendraIndex)(stack, 'test', {
existingIndexObj: testIndex
});
const template = assertions_1.Template.fromStack(stack);
template.resourceCountIs('AWS::Kendra::Index', 1);
});
test('Launch Kendra index with an S3 data source', () => {
const testName = 'test-name';
const testBucketName = 'test-bucket-name';
const stack = new aws_cdk_lib_1.Stack(undefined, undefined);
const newIndex = (0, kendra_helper_1.buildKendraIndex)(stack, 'test', {});
(0, kendra_helper_1.AddKendraDataSource)(stack, 'testSource', newIndex, {
type: 'S3',
name: testName,
dataSourceConfiguration: {
s3Configuration: {
bucketName: testBucketName,
}
},
});
const template = assertions_1.Template.fromStack(stack);
template.resourceCountIs('AWS::Kendra::Index', 1);
template.resourceCountIs("AWS::Kendra::DataSource", 1);
template.resourceCountIs("AWS::IAM::Role", 2);
template.hasResourceProperties("AWS::Kendra::DataSource", {
Name: testName,
RoleArn: assertions_1.Match.anyValue(),
Type: 'S3',
DataSourceConfiguration: {
S3Configuration: {
BucketName: testBucketName
}
}
});
template.hasResourceProperties("AWS::IAM::Role", {
AssumeRolePolicyDocument: {
Statement: [
{
Action: "sts:AssumeRole",
Effect: "Allow",
Principal: {
Service: "kendra.amazonaws.com"
}
}
],
Version: "2012-10-17"
},
Policies: [
{
PolicyDocument: {
Statement: [
{
Action: "s3:GetObject",
Effect: "Allow",
Resource: `arn:aws:s3:::${testBucketName}/*`
},
{
Action: "s3:ListBucket",
Effect: "Allow",
Resource: `arn:aws:s3:::${testBucketName}`
},
{
Action: [
"kendra:BatchPutDocument",
"kendra:BatchDeleteDocument"
],
Effect: "Allow",
Resource: {
"Fn::GetAtt": [
"kendraindextest",
"Arn"
]
}
}
],
Version: "2012-10-17"
},
PolicyName: "s3CrawlPolicy"
}
]
});
});
test('Launch Kendra index with a customized S3 data source', () => {
const testName = 'test-name';
const testBucketName = 'test-bucket-name';
const stack = new aws_cdk_lib_1.Stack(undefined, undefined);
const newIndex = (0, kendra_helper_1.buildKendraIndex)(stack, 'test', {});
(0, kendra_helper_1.AddKendraDataSource)(stack, 'testSource', newIndex, {
type: 'S3',
name: testName,
dataSourceConfiguration: {
s3Configuration: {
bucketName: testBucketName,
inclusionPatterns: ['IncludeThis'],
}
},
});
const template = assertions_1.Template.fromStack(stack);
template.hasResourceProperties("AWS::Kendra::DataSource", {
DataSourceConfiguration: {
S3Configuration: {
BucketName: "test-bucket-name",
InclusionPatterns: ['IncludeThis'],
}
},
});
template.resourceCountIs('AWS::Kendra::Index', 1);
template.resourceCountIs("AWS::Kendra::DataSource", 1);
template.resourceCountIs("AWS::IAM::Role", 2);
});
test('Launch Kendra index with non-implemented data source', () => {
const nonImplementedSourceType = "WEBCRAWLER";
const nonImplementedSourceName = "test-other-source";
const stack = new aws_cdk_lib_1.Stack(undefined, undefined);
const testIndex = (0, kendra_helper_1.buildKendraIndex)(stack, 'test', {});
// Create a role
const fakeRole = new iam.Role(stack, 'fakeRole', {
assumedBy: new iam.ServicePrincipal('kendra.amazonaws.com'),
roleName: 'externalFakeRole'
});
// Create data source props
const dataSourceProps = {
name: nonImplementedSourceName,
roleArn: fakeRole.roleArn,
type: nonImplementedSourceType,
};
// Add a data source
(0, kendra_helper_1.AddKendraDataSource)(stack, 'test-other-source', testIndex, dataSourceProps);
const template = assertions_1.Template.fromStack(stack);
template.resourceCountIs('AWS::Kendra::Index', 1);
template.resourceCountIs('AWS::Kendra::DataSource', 1);
template.resourceCountIs('AWS::IAM::Role', 2);
template.hasResourceProperties("AWS::Kendra::DataSource", {
Name: nonImplementedSourceName,
Type: nonImplementedSourceType
});
});
test('Confirm error if client supplies an index in the DataSource props', () => {
const nonImplementedSourceType = "WEBCRAWLER";
const nonImplementedSourceName = "test-other-source";
const stack = new aws_cdk_lib_1.Stack(undefined, undefined);
const testIndex = (0, kendra_helper_1.buildKendraIndex)(stack, 'test', {});
// Create a role
const fakeRole = new iam.Role(stack, 'fakeRole', {
assumedBy: new iam.ServicePrincipal('kendra.amazonaws.com'),
roleName: 'externalFakeRole'
});
// Create data source props
const dataSourceProps = {
name: nonImplementedSourceName,
roleArn: fakeRole.roleArn,
type: nonImplementedSourceType,
indexId: testIndex.attrId,
};
// Add a data source
const app = () => {
(0, kendra_helper_1.AddKendraDataSource)(stack, 'test-other-source', testIndex, dataSourceProps);
};
expect(app).toThrowError(/Invalid DataSource prop specified - Construct must set the indexId prop/);
});
test('Confirm error if does not provide DataSource configuration', () => {
const stack = new aws_cdk_lib_1.Stack(undefined, undefined);
const testIndex = (0, kendra_helper_1.buildKendraIndex)(stack, 'test', {});
// Create data source props
const dataSourceProps = {
type: "S3"
};
// Add a data source
const app = () => {
(0, kendra_helper_1.AddKendraDataSource)(stack, 'test-bad-source', testIndex, dataSourceProps);
};
expect(app).toThrowError(/Error - an S3 Kendra DataSource requires an DataSourceConfiguration prop/);
});
test('Confirm error if does not provide S3 DataSource configuration', () => {
const stack = new aws_cdk_lib_1.Stack(undefined, undefined);
const testIndex = (0, kendra_helper_1.buildKendraIndex)(stack, 'test', {});
// Create data source props
const dataSourceProps = {
type: "S3",
dataSourceConfiguration: {}
};
// Add a data source
const app = () => {
(0, kendra_helper_1.AddKendraDataSource)(stack, 'test-bad-source', testIndex, dataSourceProps);
};
expect(app).toThrowError(/Error - an S3 Kendra DataSource requires an DataSourceConfiguration.S3Configuration prop/);
});
test('Confirm error if does not provide S3 Bucketname', () => {
const stack = new aws_cdk_lib_1.Stack(undefined, undefined);
const testIndex = (0, kendra_helper_1.buildKendraIndex)(stack, 'test', {});
// Create data source props
const dataSourceProps = {
type: "S3",
dataSourceConfiguration: {
s3Configuration: {
// Going through some hoops here to force this conditiion, but since we
// allow | any for props, a client could do this
}
}
};
// Add a data source
const app = () => {
(0, kendra_helper_1.AddKendraDataSource)(stack, 'test-bad-source', testIndex, dataSourceProps);
};
expect(app).toThrowError(/Error - an S3 Kendra DataSource requires the DataSourceConfiguration.S3Configuration.bucketName prop/);
});
test('Launch Kendra index with multiple data sources', () => {
const testName = 'test-name';
const testBucketName = 'test-bucket-name';
const nonImplementedSourceType = "WEBCRAWLER";
const nonImplementedSourceName = "test-other-source";
const stack = new aws_cdk_lib_1.Stack(undefined, undefined);
const newIndex = (0, kendra_helper_1.buildKendraIndex)(stack, 'test', {});
const s3DataSourceProps = {
type: 'S3',
name: testName,
dataSourceConfiguration: {
s3Configuration: {
bucketName: testBucketName,
}
},
};
// Create a role
const fakeRole = new iam.Role(stack, 'fakeRole', {
assumedBy: new iam.ServicePrincipal('kendra.amazonaws.com'),
roleName: 'externalFakeRole'
});
// Create data source props
const otherDataSourceProps = {
name: nonImplementedSourceName,
roleArn: fakeRole.roleArn,
type: nonImplementedSourceType
};
// Add a data source
const sourceObjects = (0, kendra_helper_1.AddMultipleKendraDataSources)(stack, 'test-other-source', newIndex, [
s3DataSourceProps,
otherDataSourceProps
]);
expect(sourceObjects.length).toEqual(2);
expect(sourceObjects[0].type).toEqual('S3');
expect(sourceObjects[1].name).toEqual(nonImplementedSourceName);
const template = assertions_1.Template.fromStack(stack);
template.resourceCountIs('AWS::Kendra::Index', 1);
template.resourceCountIs('AWS::Kendra::DataSource', 2);
template.resourceCountIs('AWS::IAM::Role', 3);
// Look for S3 data source
template.hasResourceProperties("AWS::Kendra::DataSource", {
Name: testName,
RoleArn: assertions_1.Match.anyValue(),
Type: 'S3',
DataSourceConfiguration: {
S3Configuration: {
BucketName: testBucketName
}
}
});
template.hasResourceProperties("AWS::IAM::Role", {
AssumeRolePolicyDocument: {
Statement: [
{
Action: "sts:AssumeRole",
Effect: "Allow",
Principal: {
Service: "kendra.amazonaws.com"
}
}
],
Version: "2012-10-17"
},
Policies: [
{
PolicyDocument: {
Statement: [
{
Action: "s3:GetObject",
Effect: "Allow",
Resource: `arn:aws:s3:::${testBucketName}/*`
},
{
Action: "s3:ListBucket",
Effect: "Allow",
Resource: `arn:aws:s3:::${testBucketName}`
},
{
Action: [
"kendra:BatchPutDocument",
"kendra:BatchDeleteDocument"
],
Effect: "Allow",
Resource: {
"Fn::GetAtt": [
"kendraindextest",
"Arn"
]
}
}
],
Version: "2012-10-17"
},
PolicyName: "s3CrawlPolicy"
}
]
});
// Look for non-implemented data source
template.hasResourceProperties("AWS::Kendra::DataSource", {
Name: nonImplementedSourceName,
Type: nonImplementedSourceType,
IndexId: assertions_1.Match.anyValue()
});
});
test('Confirm Errof for bad kendra Permission in normalizeKendraPermissions()', () => {
const inputs = ["read", "submitfeedback", "write"];
const outputs = (0, kendra_helper_1.normalizeKendraPermissions)(inputs);
expect(outputs.includes("READ")).toBeTruthy();
expect(outputs.includes("SUBMITFEEDBACK")).toBeTruthy();
expect(outputs.includes("WRITE")).toBeTruthy();
});
test('Confirm successful operation of normalizeKendraPermissions()', () => {
const inputs = ["badvalue", "write"];
const app = () => {
(0, kendra_helper_1.normalizeKendraPermissions)(inputs);
};
expect(app).toThrowError(/Invalid indexPermission value - valid values are "READ", "SUBMITFEEDBACK" and "WRITE"/);
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoia2VuZHJhLWhlbHBlci50ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsia2VuZHJhLWhlbHBlci50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7Ozs7Ozs7R0FXRzs7QUFFSCw2Q0FBb0M7QUFDcEMsd0NBQXdDO0FBQ3hDLHVEQUF5RDtBQUN6RCx3REFBdUk7QUFDdkksaURBQWlEO0FBQ2pELDJDQUEyQztBQUUzQywwQ0FBMEM7QUFFMUMsSUFBSSxDQUFDLG1DQUFtQyxFQUFFLEdBQUcsRUFBRTtJQUM3QyxNQUFNLEtBQUssR0FBRyxJQUFJLG1CQUFLLENBQUMsU0FBUyxFQUFFLFNBQVMsQ0FBQyxDQUFDO0lBRTlDLElBQUEsZ0NBQWdCLEVBQUMsS0FBSyxFQUFFLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQztJQUVwQyxNQUFNLFFBQVEsR0FBRyxxQkFBUSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUMzQyxRQUFRLENBQUMscUJBQXFCLENBQUMsb0JBQW9CLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDekQsUUFBUSxDQUFDLGVBQWUsQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDLENBQUMsQ0FBQztBQUNoRCxDQUFDLENBQUMsQ0FBQztBQUVILElBQUksQ0FBQywyQ0FBMkMsRUFBRSxHQUFHLEVBQUU7SUFDckQsTUFBTSxLQUFLLEdBQUcsSUFBSSxtQkFBSyxDQUFDLFNBQVMsRUFBRSxTQUFTLENBQUMsQ0FBQztJQUU5QyxJQUFBLGdDQUFnQixFQUFDLEtBQUssRUFBRSxNQUFNLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFFcEMsTUFBTSxRQUFRLEdBQUcscUJBQVEsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDM0MsUUFBUSxDQUFDLHFCQUFxQixDQUFDLGdCQUFnQixFQUFFO1FBQy9DLFdBQVcsRUFBRSw2Q0FBNkM7UUFDMUQsUUFBUSxFQUFFO1lBQ1I7Z0JBQ0UsY0FBYyxFQUFFO29CQUNkLFNBQVMs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LEdBQUcsRUFBRTtRQUNmLElBQUEsMENBQTBCLEVBQUMsTUFBTSxDQUFDLENBQUM7SUFDckMsQ0FBQyxDQUFDO0lBRUYsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLFlBQVksQ0FBQyx1RkFBdUYsQ0FBQyxDQUFDO0FBQ3BILENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiAgQ29weXJpZ2h0IEFtYXpvbi5jb20sIEluYy4gb3IgaXRzIGFmZmlsaWF0ZXMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIikuIFlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2VcbiAqICB3aXRoIHRoZSBMaWNlbnNlLiBBIGNvcHkgb2YgdGhlIExpY2Vuc2UgaXMgbG9jYXRlZCBhdFxuICpcbiAqICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogIG9yIGluIHRoZSAnbGljZW5zZScgZmlsZSBhY2NvbXBhbnlpbmcgdGhpcyBmaWxlLiBUaGlzIGZpbGUgaXMgZGlzdHJpYnV0ZWQgb24gYW4gJ0FTIElTJyBCQVNJUywgV0lUSE9VVCBXQVJSQU5USUVTXG4gKiAgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZXhwcmVzcyBvciBpbXBsaWVkLiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnNcbiAqICBhbmQgbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKi9cblxuaW1wb3J0IHsgU3RhY2sgfSBmcm9tICdhd3MtY2RrLWxpYic7XG4vLyBpbXBvcnQgKiBhcyBkZWZhdWx0cyBmcm9tICcuLi9pbmRleCc7XG5pbXBvcnQgeyBNYXRjaCwgVGVtcGxhdGUgfSBmcm9tICdhd3MtY2RrLWxpYi9hc3NlcnRpb25zJztcbmltcG9ydCB7IGJ1aWxkS2VuZHJhSW5kZXgsIEFkZEtlbmRyYURhdGFTb3VyY2UsIEFkZE11bHRpcGxlS2VuZHJhRGF0YVNvdXJjZXMsIG5vcm1hbGl6ZUtlbmRyYVBlcm1pc3Npb25zIH0gZnJvbSAnLi4vbGliL2tlbmRyYS1oZWxwZXInO1xuaW1wb3J0ICogYXMga2VuZHJhIGZyb20gJ2F3cy1jZGstbGliL2F3cy1rZW5kcmEnO1xuaW1wb3J0ICogYXMgaWFtIGZyb20gJ2F3cy1jZGstbGliL2F3cy1pYW0nO1xuXG4vLyBpbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcblxudGVzdCgnTGF1bmNoIEtlbmRyYSBpbmRleCB3aXRoIGRlZmF1bHRzJywgKCkgPT4ge1xuICBjb25zdCBzdGFjayA9IG5ldyBTdGFjayh1bmRlZmluZWQsIHVuZGVmaW5lZCk7XG5cbiAgYnVpbGRLZW5kcmFJbmRleChzdGFjaywgJ3Rlc3QnLCB7fSk7XG5cbiAgY29uc3QgdGVtcGxhdGUgPSBUZW1wbGF0ZS5mcm9tU3RhY2soc3RhY2spO1xuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoJ0FXUzo6S2VuZHJhOjpJbmRleCcsIHt9KTtcbiAgdGVtcGxhdGUucmVzb3VyY2VDb3VudElzKFwiQVdTOjpJQU06OlJvbGVcIiwgMSk7XG59KTtcblxudGVzdCgnQ29uZmlybSBrZW5kcmEgaGFzIGxvZyB3cml0aW5nIHByaXZpbGVnZXMnLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IFN0YWNrKHVuZGVmaW5lZCwgdW5kZWZpbmVkKTtcblxuICBidWlsZEtlbmRyYUluZGV4KHN0YWNrLCAndGVzdCcsIHt9KTtcblxuICBjb25zdCB0ZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG4gIHRlbXBsYXRlLmhhc1Jlc291cmNlUHJvcGVydGllcyhcIkFXUzo6SUFNOjpSb2xlXCIsIHtcbiAgICBEZXNjcmlwdGlvbjogXCJBbGxvdyBLZW5kcmEgaW5kZXggdG8gd3JpdGUgQ2xvdWRXYXRjaCBMb2dzXCIsXG4gICAgUG9saWNpZXM6IFtcbiAgICAgIHtcbiAgICAgICAgUG9saWN5RG9jdW1lbnQ6IHtcbiAgICAgICAgICBTdGF0ZW1lbnQ6IFtcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgQWN0aW9uOiBcImNsb3Vkd2F0Y2g6UHV0TWV0cmljRGF0YVwiLFxuICAgICAgICAgICAgICBDb25kaXRpb246IHtcbiAgICAgICAgICAgICAgICBTdHJpbmdFcXVhbHM6IHtcbiAgICAgICAgICAgICAgICAgIFwiY2xvdWR3YXRjaDpuYW1lc3BhY2VcIjogXCJBV1MvS2VuZHJhXCJcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIEVmZmVjdDogXCJBbGxvd1wiLFxuICAgICAgICAgICAgICBSZXNvdXJjZTogXCIqXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIEFjdGlvbjogXCJsb2dzOkNyZWF0ZUxvZ0dyb3VwXCIsXG4gICAgICAgICAgICAgIEVmZmVjdDogXCJBbGxvd1wiLFxuICAgICAgICAgICAgICBSZXNvdXJjZToge1xuICAgICAgICAgICAgICAgIFwiRm46OkpvaW5cIjogW1xuICAgICAgICAgICAgICAgICAgXCJcIixcbiAgICAgICAgICAgICAgICAgIFtcbiAgICAgICAgICAgICAgICAgICAgXCJhcm46YXdzOmxvZ3M6XCIsXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICBSZWY6IFwiQVdTOjpSZWdpb25cIlxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBcIjpcIixcbiAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgIFJlZjogXCJBV1M6OkFjY291bnRJZFwiXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIFwiOmxvZy1ncm91cDovYXdzL2tlbmRyYS8qXCJcbiAgICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIEFjdGlvbjogXCJsb2dzOkRlc2NyaWJlTG9nR3JvdXBzXCIsXG4gICAgICAgICAgICAgIEVmZmVjdDogXCJBbGxvd1wiLFxuICAgICAgICAgICAgICBSZXNvdXJjZToge1xuICAgICAgICAgICAgICAgIFwiRm46OkpvaW5cIjogW1xuICAgICAgICAgICAgICAgICAgXCJcIixcbiAgICAgICAgICAgICAgICAgIFtcbiAgICAgICAgICAgICAgICAgICAgXCJhcm46XCIsXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICBSZWY6IFwiQVdTOjpQYXJ0aXRpb25cIlxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBcIjpsb2dzOlwiLFxuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgUmVmOiBcIkFXUzo6UmVnaW9uXCJcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgXCI6XCIsXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICBSZWY6IFwiQVdTOjpBY2NvdW50SWRcIlxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBcIjpsb2ctZ3JvdXA6L2F3cy9rZW5kcmEvKlwiXG4gICAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBBY3Rpb246IFtcbiAgICAgICAgICAgICAgICBcImxvZ3M6Q3JlYXRlTG9nU3RyZWFtXCIsXG4gICAgICAgICAgICAgICAgXCJsb2dzOlB1dExvZ0V2ZW50c1wiLFxuICAgICAgICAgICAgICAgIFwibG9nczpEZXNjcmliZUxvZ1N0cmVhbVwiXG4gICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgIEVmZmVjdDogXCJBbGxvd1wiLFxuICAgICAgICAgICAgICBSZXNvdXJjZToge1xuICAgICAgICAgICAgICAgIFwiRm46OkpvaW5cIjogW1xuICAgICAgICAgICAgICAgICAgXCJcIixcbiAgICAgICAgICAgICAgICAgIFtcbiAgICAgICAgICAgICAgICAgICAgXCJhcm46XCIsXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICBSZWY6IFwiQVdTOjpQYXJ0aXRpb25cIlxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBcIjpsb2dzOlwiLFxuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgUmVmOiBcIkFXUzo6UmVnaW9uXCJcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgXCI6XCIsXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICBSZWY6IFwiQVdTOjpBY2NvdW50SWRcIlxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBcIjpsb2ctZ3JvdXA6L2F3cy9rZW5kcmEvKjpsb2ctc3RyZWFtOipcIlxuICAgICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIF0sXG4gICAgICAgICAgVmVyc2lvbjogXCIyMDEyLTEwLTE3XCJcbiAgICAgICAgfSxcbiAgICAgICAgUG9saWN5TmFtZTogXCJBbGxvd0xvZ2dpbmdcIlxuICAgICAgfVxuICAgIF0sXG4gIH0pO1xufSk7XG5cbnRlc3QoJ0xhdW5jaCBLZW5kcmEgaW5kZXggd2l0aCBjdXN0b20gcHJvcGVydGllcycsICgpID0+IHtcbiAgY29uc3QgdGVzdE5hbWUgPSAndGVzdC1pbmRleC1uYW1lJztcbiAgY29uc3Qgc3RhY2sgPSBuZXcgU3RhY2sodW5kZWZpbmVkLCB1bmRlZmluZWQpO1xuXG4gIGJ1aWxkS2VuZHJhSW5kZXgoc3RhY2ssICd0ZXN0Jywge1xuICAgIGtlbmRyYUluZGV4UHJvcHM6IHtcbiAgICAgIG5hbWU6IHRlc3ROYW1lXG4gICAgfVxuICB9KTtcblxuICBjb25zdCB0ZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG4gIHRlbXBsYXRlLmhhc1Jlc291cmNlUHJvcGVydGllcygnQVdTOjpLZW5kcmE6OkluZGV4Jywge1xuICAgIE5hbWU6IHRlc3ROYW1lXG4gIH0pO1xuICB0ZW1wbGF0ZS5yZXNvdXJjZUNvdW50SXMoXCJBV1M6OklBTTo6Um9sZVwiLCAxKTtcbn0pO1xuXG50ZXN0KCdMYXVuY2ggS2VuZHJhIGluZGV4IHdpdGggZXhpc3Rpbmcgcm9sZScsICgpID0+IHtcbiAgY29uc3QgZmFrZVJvbGVBcm4gPSAnZmFrZS1hcm4nO1xuICBjb25zdCBzdGFjayA9IG5ldyBTdGFjayh1bmRlZmluZWQsIHVuZGVmaW5lZCk7XG5cbiAgYnVpbGRLZW5kcmFJbmRleChzdGFjaywgJ3Rlc3QnLCB7XG4gICAga2VuZHJhSW5kZXhQcm9wczoge1xuICAgICAgcm9sZUFybjogZmFrZVJvbGVBcm5cbiAgICB9XG4gIH0pO1xuXG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKCdBV1M6OktlbmRyYTo6SW5kZXgnLCB7XG4gICAgUm9sZUFybjogZmFrZVJvbGVBcm5cbiAgfSk7XG4gIHRlbXBsYXRlLnJlc291cmNlQ291bnRJcyhcIkFXUzo6SUFNOjpSb2xlXCIsIDApO1xufSk7XG5cbnRlc3QoJ3VzZSBleGlzdGluZyBLZW5kcmEgaW5kZXgnLCAoKSA9PiB7XG4gIGNvbnN0IHN0YWNrID0gbmV3IFN0YWNrKHVuZGVmaW5lZCwgdW5kZWZpbmVkKTtcblxuICBjb25zdCBpbmRleFByb3BzOiBrZW5kcmEuQ2ZuSW5kZXhQcm9wcyA9IHtcbiAgICBlZGl0aW9uOiAnREVWRUxPUEVSX0VESVRJT04nLFxuICAgIG5hbWU6ICdrZW5kcmEtdGVzdCcsXG4gICAgcm9sZUFybjogJ2Zha2UtYXJuJ1xuICB9O1xuXG4gIGNvbnN0IHRlc3RJbmRleCA9IG5ldyBrZW5kcmEuQ2ZuSW5kZXgoc3RhY2ssIGB0ZXN0YCwgaW5kZXhQcm9wcyk7XG5cbiAgYnVpbGRLZW5kcmFJbmRleChzdGFjaywgJ3Rlc3QnLCB7XG4gICAgZXhpc3RpbmdJbmRleE9iajogdGVzdEluZGV4XG4gIH0pO1xuXG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcbiAgdGVtcGxhdGUucmVzb3VyY2VDb3VudElzKCdBV1M6OktlbmRyYTo6SW5kZXgnLCAxKTtcbn0pO1xuXG50ZXN0KCdMYXVuY2ggS2VuZHJhIGluZGV4IHdpdGggYW4gUzMgZGF0YSBzb3VyY2UnLCAoKSA9PiB7XG4gIGNvbnN0IHRlc3ROYW1lID0gJ3Rlc3QtbmFtZSc7XG4gIGNvbnN0IHRlc3RCdWNrZXROYW1lID0gJ3Rlc3QtYnVja2V0LW5hbWUnO1xuICBjb25zdCBzdGFjayA9IG5ldyBTdGFjayh1bmRlZmluZWQsIHVuZGVmaW5lZCk7XG5cbiAgY29uc3QgbmV3SW5kZXggPSBidWlsZEtlbmRyYUluZGV4KHN0YWNrLCAndGVzdCcsIHt9KTtcblxuICBBZGRLZW5kcmFEYXRhU291cmNlKHN0YWNrLCAndGVzdFNvdXJjZScsIG5ld0luZGV4LCB7XG4gICAgdHlwZTogJ1MzJyxcbiAgICBuYW1lOiB0ZXN0TmFtZSxcbiAgICBkYXRhU291cmNlQ29uZmlndXJhdGlvbjoge1xuICAgICAgczNDb25maWd1cmF0aW9uOiB7XG4gICAgICAgIGJ1Y2tldE5hbWU6IHRlc3RCdWNrZXROYW1lLFxuICAgICAgfVxuICAgIH0sXG4gIH0pO1xuXG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcbiAgdGVtcGxhdGUucmVzb3VyY2VDb3VudElzKCdBV1M6OktlbmRyYTo6SW5kZXgnLCAxKTtcbiAgdGVtcGxhdGUucmVzb3VyY2VDb3VudElzKFwiQVdTOjpLZW5kcmE6OkRhdGFTb3VyY2VcIiwgMSk7XG4gIHRlbXBsYXRlLnJlc291cmNlQ291bnRJcyhcIkFXUzo6SUFNOjpSb2xlXCIsIDIpO1xuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoXCJBV1M6OktlbmRyYTo6RGF0YVNvdXJjZVwiLCB7XG4gICAgTmFtZTogdGVzdE5hbWUsXG4gICAgUm9sZUFybjogTWF0Y2guYW55VmFsdWUoKSxcbiAgICBUeXBlOiAnUzMnLFxuICAgIERhdGFTb3VyY2VDb25maWd1cmF0aW9uOiB7XG4gICAgICBTM0NvbmZpZ3VyYXRpb246IHtcbiAgICAgICAgQnVja2V0TmFtZTogdGVzdEJ1Y2tldE5hbWVcbiAgICAgIH1cbiAgICB9XG4gIH0pO1xuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoXCJBV1M6OklBTTo6Um9sZVwiLCB7XG4gICAgQXNzdW1lUm9sZVBvbGljeURvY3VtZW50OiB7XG4gICAgICBTdGF0ZW1lbnQ6IFtcbiAgICAgICAge1xuICAgICAgICAgIEFjdGlvbjogXCJzdHM6QXNzdW1lUm9sZVwiLFxuICAgICAgICAgIEVmZmVjdDogXCJBbGxvd1wiLFxuICAgICAgICAgIFByaW5jaXBhbDoge1xuICAgICAgICAgICAgU2VydmljZTogXCJrZW5kcmEuYW1hem9uYXdzLmNvbVwiXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgVmVyc2lvbjogXCIyMDEyLTEwLTE3XCJcbiAgICB9LFxuICAgIFBvbGljaWVzOiBbXG4gICAgICB7XG4gICAgICAgIFBvbGljeURvY3VtZW50OiB7XG4gICAgICAgICAgU3RhdGVtZW50OiBbXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIEFjdGlvbjogXCJzMzpHZXRPYmplY3RcIixcbiAgICAgICAgICAgICAgRWZmZWN0OiBcIkFsbG93XCIsXG4gICAgICAgICAgICAgIFJlc291cmNlOiBgYXJuOmF3czpzMzo6OiR7dGVzdEJ1Y2tldE5hbWV9LypgXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBBY3Rpb246IFwiczM6TGlzdEJ1Y2tldFwiLFxuICAgICAgICAgICAgICBFZmZlY3Q6IFwiQWxsb3dcIixcbiAgICAgICAgICAgICAgUmVzb3VyY2U6IGBhcm46YXdzOnMzOjo6JHt0ZXN0QnVja2V0TmFtZX1gXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICBBY3Rpb246IFtcbiAgICAgICAgICAgICAgICBcImtlbmRyYTpCYXRjaFB1dERvY3VtZW50XCIsXG4gICAgICAgICAgICAgICAgXCJrZW5kcmE6QmF0Y2hEZWxldGVEb2N1bWVudFwiXG4gICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgIEVmZmVjdDogXCJBbGxvd1wiLFxuICAgICAgICAgICAgICBSZXNvdXJjZToge1xuICAgICAgICAgICAgICAgIFwiRm46OkdldEF0dFwiOiBbXG4gICAgICAgICAgICAgICAgICBcImtlbmRyYWluZGV4dGVzdFwiLFxuICAgICAgICAgICAgICAgICAgXCJBcm5cIlxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIF0sXG4gICAgICAgICAgVmVyc2lvbjogXCIyMDEyLTEwLTE3XCJcbiAgICAgICAgfSxcbiAgICAgICAgUG9saWN5TmFtZTogXCJzM0NyYXdsUG9saWN5XCJcbiAgICAgIH1cbiAgICBdXG4gIH0pO1xufSk7XG5cbnRlc3QoJ0xhdW5jaCBLZW5kcmEgaW5kZXggd2l0aCBhIGN1c3RvbWl6ZWQgUzMgZGF0YSBzb3VyY2UnLCAoKSA9PiB7XG4gIGNvbnN0IHRlc3ROYW1lID0gJ3Rlc3QtbmFtZSc7XG4gIGNvbnN0IHRlc3RCdWNrZXROYW1lID0gJ3Rlc3QtYnVja2V0LW5hbWUnO1xuICBjb25zdCBzdGFjayA9IG5ldyBTdGFjayh1bmRlZmluZWQsIHVuZGVmaW5lZCk7XG5cbiAgY29uc3QgbmV3SW5kZXggPSBidWlsZEtlbmRyYUluZGV4KHN0YWNrLCAndGVzdCcsIHt9KTtcblxuICBBZGRLZW5kcmFEYXRhU291cmNlKHN0YWNrLCAndGVzdFNvdXJjZScsIG5ld0luZGV4LCB7XG4gICAgdHlwZTogJ1MzJyxcbiAgICBuYW1lOiB0ZXN0TmFtZSxcbiAgICBkYXRhU291cmNlQ29uZmlndXJhdGlvbjoge1xuICAgICAgczNDb25maWd1cmF0aW9uOiB7XG4gICAgICAgIGJ1Y2tldE5hbWU6IHRlc3RCdWNrZXROYW1lLFxuICAgICAgICBpbmNsdXNpb25QYXR0ZXJuczogWydJbmNsdWRlVGhpcyddLFxuICAgICAgfVxuICAgIH0sXG4gIH0pO1xuXG4gIGNvbnN0IHRlbXBsYXRlID0gVGVtcGxhdGUuZnJvbVN0YWNrKHN0YWNrKTtcbiAgdGVtcGxhdGUuaGFzUmVzb3VyY2VQcm9wZXJ0aWVzKFwiQVdTOjpLZW5kcmE6OkRhdGFTb3VyY2VcIiwge1xuICAgIERhdGFTb3VyY2VDb25maWd1cmF0aW9uOiB7XG4gICAgICBTM0NvbmZpZ3VyYXRpb246IHtcbiAgICAgICAgQnVja2V0TmFtZTogXCJ0ZXN0LWJ1Y2tldC1uYW1lXCIsXG4gICAgICAgIEluY2x1c2lvblBhdHRlcm5zOiBbJ0luY2x1ZGVUaGlzJ10sXG4gICAgICB9XG4gICAgfSxcbiAgfSk7XG4gIHRlbXBsYXRlLnJlc291cmNlQ291bnRJcygnQVdTOjpLZW5kcmE6OkluZGV4JywgMSk7XG4gIHRlbXBsYXRlLnJlc291cmNlQ291bnRJcyhcIkFXUzo6S2VuZHJhOjpEYXRhU291cmNlXCIsIDEpO1xuICB0ZW1wbGF0ZS5yZXNvdXJjZUNvdW50SXMoXCJBV1M6OklBTTo6Um9sZVwiLCAyKTtcbn0pO1xuXG50ZXN0KCdMYXVuY2ggS2VuZHJhIGluZGV4IHdpdGggbm9uLWltcGxlbWVudGVkIGRhdGEgc291cmNlJywgKCkgPT4ge1xuICBjb25zdCBub25JbXBsZW1lbnRlZFNvdXJjZVR5cGUgPSBcIldFQkNSQVdMRVJcIjtcbiAgY29uc3Qgbm9uSW1wbGVtZW50ZWRTb3VyY2VOYW1lID0gXCJ0ZXN0LW90aGVyLXNvdXJjZVwiO1xuICBjb25zdCBzdGFjayA9IG5ldyBTdGFjayh1bmRlZmluZWQsIHVuZGVmaW5lZCk7XG4gIGNvbnN0IHRlc3RJbmRleCA9IGJ1aWxkS2VuZHJhSW5kZXgoc3RhY2ssICd0ZXN0Jywge30pO1xuXG4gIC8vIENyZWF0ZSBhIHJvbGVcbiAgY29uc3QgZmFrZVJvbGUgPSBuZXcgaWFtLlJvbGUoc3RhY2ssICdmYWtlUm9sZScsIHtcbiAgICBhc3N1bWVkQnk6IG5ldyBpYW0uU2VydmljZVByaW5jaXBhbCgna2VuZHJhLmFtYXpvbmF3cy5jb20nKSxcbiAgICByb2xlTmFtZTogJ2V4dGVybmFsRmFrZVJvbGUnXG4gIH0pO1xuXG4gIC8vIENyZWF0ZSBkYXRhIHNvdXJjZSBwcm9wc1xuICBjb25zdCBkYXRhU291cmNlUHJvcHM6IFBhcnRpYWw8a2VuZHJhLkNmbkRhdGFTb3VyY2VQcm9wcz4gPSB7XG4gICAgbmFtZTogbm9uSW1wbGVtZW50ZWRTb3VyY2VOYW1lLFxuICAgIHJvbGVBcm46IGZha2VSb2xlLnJvbGVBcm4sXG4gICAgdHlwZTogbm9uSW1wbGVtZW50ZWRTb3VyY2VUeXBlLFxuICB9O1xuXG4gIC8vIEFkZCBhIGRhdGEgc291cmNlXG4gIEFkZEtlbmRyYURhdGFTb3VyY2Uoc3RhY2ssICd0ZXN0LW90aGVyLXNvdXJjZScsIHRlc3RJbmRleCwgZGF0YVNvdXJjZVByb3BzKTtcblxuICBjb25zdCB0ZW1wbGF0ZSA9IFRlbXBsYXRlLmZyb21TdGFjayhzdGFjayk7XG4gIHRlbXBsYXRlLnJlc291cmNlQ291bnRJcygnQVdTOjpLZW5kcmE6OkluZGV4JywgMSk7XG4gIHRlbXBsYXRlLnJlc291cmNlQ291bnRJcygnQVdTOjpLZW5kcmE6OkRhdGFTb3VyY2UnLCAxKTtcbiAgdGVtcGxhdGUucmVzb3VyY2VDb3VudElzKCdBV1M6OklBTTo6Um9sZScsIDIpO1xuICB0ZW1wbGF0ZS5oYXNSZXNvdXJjZVByb3BlcnRpZXMoXCJBV1M6OktlbmRyYTo6RGF0YVNvdXJjZVwiLCB7XG4gICAgTmFtZTogbm9uSW1wbGVtZW50ZWRTb3VyY2VOYW1lLFxuICAgIFR5cGU6IG5vbkltcGxlbWVudGVkU291cmNlVHlwZVxuICB9KTtcbn0pO1xuXG50ZXN0KCdDb25maXJtIGVycm9yIGlmIGNsaWVudCBzdXBwbGllcyBhbiBpbmRleCBpbiB0aGUgRGF0YVNvdXJjZSBwcm9wcycsICgpID0+IHtcbiAgY29uc3Qgbm9uSW1wbGVtZW50ZWRTb3VyY2VUeXBlID0gXCJXRUJDUkFXTEVSXCI7XG4gIGNvbnN0IG5vbkltcGxlbWVudGVkU291cmNlTmFtZSA9IFwidGVzdC1vdGhlci1zb3VyY2VcIjtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgU3RhY2sodW5kZWZpbmVkLCB1bmRlZmluZWQpO1xuICBjb25zdCB0ZXN0SW5kZXggPSBidWlsZEtlbmRyYUluZGV4KHN0YWNrLCAndGVzdCcsIHt9KTtcblxuICAvLyBDcmVhdGUgYSByb2xlXG4gIGNvbnN0IGZha2VSb2xlID0gbmV3IGlhbS5Sb2xlKHN0YWNrLCAnZmFrZVJvbGUnLCB7XG4gICAgYXNzdW1lZEJ5OiBuZXcgaWFtLlNlcnZpY2VQcmluY2lwYWwoJ2tlbmRyYS5hbWF6b25hd3MuY29tJyksXG4gICAgcm9sZU5hbWU6ICdleHRlcm5hbEZha2VSb2xlJ1xuICB9KTtcblxuICAvLyBDcmVhdGUgZGF0YSBzb3VyY2UgcHJvcHNcbiAgY29uc3QgZGF0YVNvdXJjZVByb3BzOiBQYXJ0aWFsPGtlbmRyYS5DZm5EYXRhU291cmNlUHJvcHM+ID0ge1xuICAgIG5hbWU6IG5vbkltcGxlbWVudGVkU291cmNlTmFtZSxcbiAgICByb2xlQXJuOiBmYWtlUm9sZS5yb2xlQXJuLFxuICAgIHR5cGU6IG5vbkltcGxlbWVudGVkU291cmNlVHlwZSxcbiAgICBpbmRleElkOiB0ZXN0SW5kZXguYXR0cklkLFxuICB9O1xuXG4gIC8vIEFkZCBhIGRhdGEgc291cmNlXG4gIGNvbnN0IGFwcCA9ICgpID