@scloud/cdk-patterns
Version:
Serverless CDK patterns for common infrastructure needs
106 lines • 19.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebApp = void 0;
const aws_cdk_lib_1 = require("aws-cdk-lib");
const aws_certificatemanager_1 = require("aws-cdk-lib/aws-certificatemanager");
const aws_route53_targets_1 = require("aws-cdk-lib/aws-route53-targets");
const aws_cloudfront_origins_1 = require("aws-cdk-lib/aws-cloudfront-origins");
const aws_cloudfront_1 = require("aws-cdk-lib/aws-cloudfront");
const aws_apigateway_1 = require("aws-cdk-lib/aws-apigateway");
const constructs_1 = require("constructs");
const aws_route53_1 = require("aws-cdk-lib/aws-route53");
const RedirectWww_1 = require("./RedirectWww");
const GithubActions_1 = require("./GithubActions");
const PrivateBucket_1 = require("./PrivateBucket");
const ZipFunction_1 = require("./ZipFunction");
/**
* Builds a dynamic web application, backed by a single Lambda function, also knowm as a "Lambda-lith" (https://github.com/cdk-patterns/serverless/blob/main/the-lambda-trilogy/README.md)
*
* This construct sends requests that don't have a file extension to the Lambda. Static content is handled by routing requests that match *.* (eg *.js. *.css) to an S3 bucket.
*/
class WebApp extends constructs_1.Construct {
constructor(scope, id, props) {
super(scope, `${id}WebApp`);
const domainName = props.domainName || `${props.zone.zoneName}`;
// Static content
this.bucket = PrivateBucket_1.PrivateBucket.expendable(scope, `${id}Static`);
(0, GithubActions_1.githubActions)(scope).addGhaBucket(id, this.bucket);
// Web app handler - default values can be overridden using lambdaProps
this.lambda = props.lambda;
this.api = new aws_apigateway_1.LambdaRestApi(scope, `${id}ApiGateway`, {
handler: this.lambda,
proxy: true,
description: `${aws_cdk_lib_1.Stack.of(scope).stackName} ${id}`,
binaryMediaTypes: ['multipart/form-data'],
});
this.certificate = new aws_certificatemanager_1.DnsValidatedCertificate(scope, `${id}Certificate`, {
domainName,
hostedZone: props.zone,
region: 'us-east-1',
subjectAlternativeNames: props.redirectWww !== false ? [`www.${domainName}`] : undefined,
});
// This enables us to separate out the defaultBehavior props (if any) from the distributionProps (if provided)
// See https://stackoverflow.com/a/34710102/723506 for an explanation of this destructuring
const { defaultBehavior, additionalBehaviors, ...distributionProps } = props.distributionProps || {};
this.distribution = new aws_cloudfront_1.Distribution(scope, `${id}Distribution`, {
domainNames: [domainName],
comment: domainName,
defaultRootObject: props.defaultIndex ? 'index.html' : undefined,
defaultBehavior: {
origin: new aws_cloudfront_origins_1.RestApiOrigin(this.api),
allowedMethods: aws_cloudfront_1.AllowedMethods.ALLOW_ALL,
viewerProtocolPolicy: aws_cloudfront_1.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
cachePolicy: aws_cloudfront_1.CachePolicy.CACHING_DISABLED, // Assume dynamic content
originRequestPolicy: aws_cloudfront_1.OriginRequestPolicy.ALL_VIEWER_EXCEPT_HOST_HEADER,
...defaultBehavior,
},
// All requests for something with a file extension go to s3 (actually, any path that contains a period).
// The aim is to route *.css, *.js, *.jpeg, etc)
additionalBehaviors: {
'*.*': {
origin: aws_cloudfront_origins_1.S3BucketOrigin.withOriginAccessControl(this.bucket),
allowedMethods: aws_cloudfront_1.AllowedMethods.ALLOW_GET_HEAD_OPTIONS,
viewerProtocolPolicy: aws_cloudfront_1.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
compress: true,
},
...additionalBehaviors,
},
certificate: this.certificate,
errorResponses: props.errorResponses,
...distributionProps,
});
(0, GithubActions_1.githubActions)(scope).addGhaDistribution(id, this.distribution);
// DNS record for the Cloudfront distribution
new aws_route53_1.ARecord(scope, `${id}ARecord`, {
recordName: domainName,
target: aws_route53_1.RecordTarget.fromAlias(new aws_route53_targets_1.CloudFrontTarget(this.distribution)),
zone: props.zone,
});
if (props.redirectWww !== false)
new RedirectWww_1.RedirectWww(scope, id, { zone: props.zone, certificate: this.certificate, domainName });
}
/**
* Creates a WebApp backed by a Node.js Lambda function.
*
* Memory defaults to 3008 MB because this has the effest of assigning more compute resource and therefore reduces latency.
*/
static node(scope, id, zone, domainName, defaultIndex, redirectWww, functionProps) {
const lambda = ZipFunction_1.ZipFunction.node(scope, id, { memorySize: 3008, ...functionProps });
return new WebApp(scope, id, {
lambda, zone, domainName, defaultIndex, redirectWww,
});
}
/**
* Creates a WebApp backed by a Python Lambda function.
*
* Memory defaults to 3008 MB because this has the effest of assigning more compute resource and therefore reduces latency.
*/
static python(scope, id, zone, domainName, defaultIndex, redirectWww, functionProps) {
const lambda = ZipFunction_1.ZipFunction.python(scope, id, { memorySize: 3008, ...functionProps });
return new WebApp(scope, id, {
lambda, zone, domainName, defaultIndex, redirectWww,
});
}
}
exports.WebApp = WebApp;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiV2ViQXBwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL1dlYkFwcC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSw2Q0FFcUI7QUFDckIsK0VBQTZFO0FBQzdFLHlFQUFtRTtBQUVuRSwrRUFBbUY7QUFDbkYsK0RBTW9DO0FBQ3BDLCtEQUVvQztBQUVwQywyQ0FBdUM7QUFDdkMseURBQTZFO0FBQzdFLCtDQUE0QztBQUM1QyxtREFBZ0Q7QUFDaEQsbURBQWdEO0FBQ2hELCtDQUE4RDtBQW9COUQ7Ozs7R0FJRztBQUNILE1BQWEsTUFBTyxTQUFRLHNCQUFTO0lBV25DLFlBQ0UsS0FBZ0IsRUFDaEIsRUFBVSxFQUNWLEtBQWtCO1FBRWxCLEtBQUssQ0FBQyxLQUFLLEVBQUUsR0FBRyxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBRTVCLE1BQU0sVUFBVSxHQUFHLEtBQUssQ0FBQyxVQUFVLElBQUksR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBRWhFLGlCQUFpQjtRQUNqQixJQUFJLENBQUMsTUFBTSxHQUFHLDZCQUFhLENBQUMsVUFBVSxDQUFDLEtBQUssRUFBRSxHQUFHLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDN0QsSUFBQSw2QkFBYSxFQUFDLEtBQUssQ0FBQyxDQUFDLFlBQVksQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBRW5ELHVFQUF1RTtRQUN2RSxJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUM7UUFFM0IsSUFBSSxDQUFDLEdBQUcsR0FBRyxJQUFJLDhCQUFhLENBQUMsS0FBSyxFQUFFLEdBQUcsRUFBRSxZQUFZLEVBQUU7WUFDckQsT0FBTyxFQUFFLElBQUksQ0FBQyxNQUFNO1lBQ3BCLEtBQUssRUFBRSxJQUFJO1lBQ1gsV0FBVyxFQUFFLEdBQUcsbUJBQUssQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsU0FBUyxJQUFJLEVB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TUFBTSxNQUFNLEdBQUcseUJBQVcsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRSxFQUFFLFVBQVUsRUFBRSxJQUFJLEVBQUUsR0FBRyxhQUFhLEVBQUUsQ0FBQyxDQUFDO1FBQ25GLE9BQU8sSUFBSSxNQUFNLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRTtZQUMzQixNQUFNLEVBQUUsSUFBSSxFQUFFLFVBQVUsRUFBRSxZQUFZLEVBQUUsV0FBVztTQUNwRCxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILE1BQU0sQ0FBQyxNQUFNLENBQ1gsS0FBZ0IsRUFDaEIsRUFBVSxFQUNWLElBQWlCLEVBQ2pCLFVBQW1CLEVBQ25CLFlBQXNCLEVBQ3RCLFdBQXFCLEVBQ3JCLGFBQWdDO1FBRWhDLE1BQU0sTUFBTSxHQUFHLHlCQUFXLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxFQUFFLEVBQUUsRUFBRSxVQUFVLEVBQUUsSUFBSSxFQUFFLEdBQUcsYUFBYSxFQUFFLENBQUMsQ0FBQztRQUNyRixPQUFPLElBQUksTUFBTSxDQUFDLEtBQUssRUFBRSxFQUFFLEVBQUU7WUFDM0IsTUFBTSxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsWUFBWSxFQUFFLFdBQVc7U0FDcEQsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztDQUNGO0FBMUhELHdCQTBIQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIFN0YWNrLFxufSBmcm9tICdhd3MtY2RrLWxpYic7XG5pbXBvcnQgeyBEbnNWYWxpZGF0ZWRDZXJ0aWZpY2F0ZSB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1jZXJ0aWZpY2F0ZW1hbmFnZXInO1xuaW1wb3J0IHsgQ2xvdWRGcm9udFRhcmdldCB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1yb3V0ZTUzLXRhcmdldHMnO1xuaW1wb3J0IHsgQnVja2V0IH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLXMzJztcbmltcG9ydCB7IFJlc3RBcGlPcmlnaW4sIFMzQnVja2V0T3JpZ2luIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWNsb3VkZnJvbnQtb3JpZ2lucyc7XG5pbXBvcnQge1xuICBBbGxvd2VkTWV0aG9kcywgQ2FjaGVQb2xpY3ksIERpc3RyaWJ1dGlvbixcbiAgRGlzdHJpYnV0aW9uUHJvcHMsXG4gIEVycm9yUmVzcG9uc2UsXG4gIE9yaWdpblJlcXVlc3RQb2xpY3ksXG4gIFZpZXdlclByb3RvY29sUG9saWN5LFxufSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtY2xvdWRmcm9udCc7XG5pbXBvcnQge1xuICBMYW1iZGFSZXN0QXBpLFxufSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtYXBpZ2F0ZXdheSc7XG5pbXBvcnQgeyBGdW5jdGlvbiB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1sYW1iZGEnO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgeyBBUmVjb3JkLCBJSG9zdGVkWm9uZSwgUmVjb3JkVGFyZ2V0IH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLXJvdXRlNTMnO1xuaW1wb3J0IHsgUmVkaXJlY3RXd3cgfSBmcm9tICcuL1JlZGlyZWN0V3d3JztcbmltcG9ydCB7IGdpdGh1YkFjdGlvbnMgfSBmcm9tICcuL0dpdGh1YkFjdGlvbnMnO1xuaW1wb3J0IHsgUHJpdmF0ZUJ1Y2tldCB9IGZyb20gJy4vUHJpdmF0ZUJ1Y2tldCc7XG5pbXBvcnQgeyBaaXBGdW5jdGlvbiwgWmlwRnVuY3Rpb25Qcm9wcyB9IGZyb20gJy4vWmlwRnVuY3Rpb24nO1xuLyoqXG4gKiBAcGFyYW0gbGFtYmRhIFRoZSBmdW5jdGlvbiB3aGljaCB3aWxsIHJlc3BvbmQgdG8gaW5jb21pbmcgcmVxdWVzdCBldmVudHMuXG4gKiBAcGFyYW0gem9uZSBUaGUgRE5TIHpvbmUgZm9yIHRoaXMgd2ViIGFwcC5cbiAqIEBwYXJhbSBkb21haW5OYW1lIE9wdGlvbmFsOiBieSBkZWZhdWx0IHRoZSB6b25lIG5hbWUgd2lsbCBiZSB1c2VkIChlLmcuICdleGFtcGxlLmNvbScpIGEgZGlmZmVyZW50IGRvbWFpbiBoZXJlIChlLmcuICdzdWJkb21haW4uZXhhbXBsZS5jb20nKS5cbiAqIEBwYXJhbSBkZWZhdWx0SW5kZXggRGVmYXVsdDogZmFsc2UuIElmIHRydWUsIG1hcHMgYSB2aWV3ZXIgcmVxdWVzdCBmb3IgJy8nIHRvIGFuIHMzIHJlcXVlc3QgZm9yIC9pbmRleC5odG1sLlxuICogQHBhcmFtIHJlZGlyZWN0V3d3IERlZmF1bHQ6IHRydWUuIFJlZGlyZWN0cyB3d3cgcmVxdWVzdHMgdG8gdGhlIGJhcmUgZG9tYWluIG5hbWUsIGUuZy4gd3d3LmV4YW1wbGUuY29tLT5leGFtcGxlLmNvbSwgd3d3LnN1Yi5leGFtcGxlLmNvbS0+c3ViLmV4YW1wbGUuY29tLlxuICogQHBhcmFtIGRpc3RyaWJ1dGlvblByb3BzIE9wdGlvbmFsOiBJZiB5b3Ugd2FudCB0byBhZGQgYWRkaXRpb25hbCBwcm9wZXJ0aWVzIHRvIHRoZSBDbG91ZGZyb250IGRpc3RyaWJ1dGlvbiwgeW91IGNhbiBwYXNzIHRoZW0gaGVyZS5cbiAqIEBwYXJhbSBlcnJvclJlc3BvbnNlcyBPcHRpb25hbDogSWYgeW91IHdhbnQgdG8gYWRkIGN1c3RvbSBlcnJvciByZXNwb25zZXMgdG8gdGhlIENsb3VkZnJvbnQgZGlzdHJpYnV0aW9uLCB5b3UgY2FuIHBhc3MgdGhlbSBoZXJlLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFdlYkFwcFByb3BzIHtcbiAgbGFtYmRhOiBGdW5jdGlvbixcbiAgem9uZTogSUhvc3RlZFpvbmUsXG4gIGRvbWFpbk5hbWU/OiBzdHJpbmcsXG4gIGRlZmF1bHRJbmRleD86IGJvb2xlYW4sXG4gIHJlZGlyZWN0V3d3PzogYm9vbGVhbixcbiAgZGlzdHJpYnV0aW9uUHJvcHM/OiBQYXJ0aWFsPERpc3RyaWJ1dGlvblByb3BzPixcbiAgZXJyb3JSZXNwb25zZXM/OiBFcnJvclJlc3BvbnNlW10sXG59XG5cbi8qKlxuICogQnVpbGRzIGEgZHluYW1pYyB3ZWIgYXBwbGljYXRpb24sIGJhY2tlZCBieSBhIHNpbmdsZSBMYW1iZGEgZnVuY3Rpb24sIGFsc28ga25vd20gYXMgYSBcIkxhbWJkYS1saXRoXCIgKGh0dHBzOi8vZ2l0aHViLmNvbS9jZGstcGF0dGVybnMvc2VydmVybGVzcy9ibG9iL21haW4vdGhlLWxhbWJkYS10cmlsb2d5L1JFQURNRS5tZClcbiAqXG4gKiBUaGlzIGNvbnN0cnVjdCBzZW5kcyByZXF1ZXN0cyB0aGF0IGRvbid0IGhhdmUgYSBmaWxlIGV4dGVuc2lvbiB0byB0aGUgTGFtYmRhLiBTdGF0aWMgY29udGVudCBpcyBoYW5kbGVkIGJ5IHJvdXRpbmcgcmVxdWVzdHMgdGhhdCBtYXRjaCAqLiogKGVnICouanMuICouY3NzKSB0byBhbiBTMyBidWNrZXQuXG4gKi9cbmV4cG9ydCBjbGFzcyBXZWJBcHAgZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuICBsYW1iZGE6IEZ1bmN0aW9uO1xuXG4gIGJ1Y2tldDogQnVja2V0O1xuXG4gIGRpc3RyaWJ1dGlvbjogRGlzdHJpYnV0aW9uO1xuXG4gIGFwaTogTGFtYmRhUmVzdEFwaTtcblxuICBjZXJ0aWZpY2F0ZTogRG5zVmFsaWRhdGVkQ2VydGlmaWNhdGU7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgc2NvcGU6IENvbnN0cnVjdCxcbiAgICBpZDogc3RyaW5nLFxuICAgIHByb3BzOiBXZWJBcHBQcm9wcyxcbiAgKSB7XG4gICAgc3VwZXIoc2NvcGUsIGAke2lkfVdlYkFwcGApO1xuXG4gICAgY29uc3QgZG9tYWluTmFtZSA9IHByb3BzLmRvbWFpbk5hbWUgfHwgYCR7cHJvcHMuem9uZS56b25lTmFtZX1gO1xuXG4gICAgLy8gU3RhdGljIGNvbnRlbnRcbiAgICB0aGlzLmJ1Y2tldCA9IFByaXZhdGVCdWNrZXQuZXhwZW5kYWJsZShzY29wZSwgYCR7aWR9U3RhdGljYCk7XG4gICAgZ2l0aHViQWN0aW9ucyhzY29wZSkuYWRkR2hhQnVja2V0KGlkLCB0aGlzLmJ1Y2tldCk7XG5cbiAgICAvLyBXZWIgYXBwIGhhbmRsZXIgLSBkZWZhdWx0IHZhbHVlcyBjYW4gYmUgb3ZlcnJpZGRlbiB1c2luZyBsYW1iZGFQcm9wc1xuICAgIHRoaXMubGFtYmRhID0gcHJvcHMubGFtYmRhO1xuXG4gICAgdGhpcy5hcGkgPSBuZXcgTGFtYmRhUmVzdEFwaShzY29wZSwgYCR7aWR9QXBpR2F0ZXdheWAsIHtcbiAgICAgIGhhbmRsZXI6IHRoaXMubGFtYmRhLFxuICAgICAgcHJveHk6IHRydWUsXG4gICAgICBkZXNjcmlwdGlvbjogYCR7U3RhY2sub2Yoc2NvcGUpLnN0YWNrTmFtZX0gJHtpZH1gLFxuICAgICAgYmluYXJ5TWVkaWFUeXBlczogWydtdWx0aXBhcnQvZm9ybS1kYXRhJ10sXG4gICAgfSk7XG5cbiAgICB0aGlzLmNlcnRpZmljYXRlID0gbmV3IERuc1ZhbGlkYXRlZENlcnRpZmljYXRlKHNjb3BlLCBgJHtpZH1DZXJ0aWZpY2F0ZWAsIHtcbiAgICAgIGRvbWFpbk5hbWUsXG4gICAgICBob3N0ZWRab25lOiBwcm9wcy56b25lLFxuICAgICAgcmVnaW9uOiAndXMtZWFzdC0xJyxcbiAgICAgIHN1YmplY3RBbHRlcm5hdGl2ZU5hbWVzOiBwcm9wcy5yZWRpcmVjdFd3dyAhPT0gZmFsc2UgPyBbYHd3dy4ke2RvbWFpbk5hbWV9YF0gOiB1bmRlZmluZWQsXG4gICAgfSk7XG5cbiAgICAvLyBUaGlzIGVuYWJsZXMgdXMgdG8gc2VwYXJhdGUgb3V0IHRoZSBkZWZhdWx0QmVoYXZpb3IgcHJvcHMgKGlmIGFueSkgZnJvbSB0aGUgZGlzdHJpYnV0aW9uUHJvcHMgKGlmIHByb3ZpZGVkKVxuICAgIC8vIFNlZSBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL2EvMzQ3MTAxMDIvNzIzNTA2IGZvciBhbiBleHBsYW5hdGlvbiBvZiB0aGlzIGRlc3RydWN0dXJpbmdcbiAgICBjb25zdCB7IGRlZmF1bHRCZWhhdmlvciwgYWRkaXRpb25hbEJlaGF2aW9ycywgLi4uZGlzdHJpYnV0aW9uUHJvcHMgfSA9IHByb3BzLmRpc3RyaWJ1dGlvblByb3BzIHx8ICh7fSBhcyBQYXJ0aWFsPERpc3RyaWJ1dGlvblByb3BzPik7XG4gICAgdGhpcy5kaXN0cmlidXRpb24gPSBuZXcgRGlzdHJpYnV0aW9uKHNjb3BlLCBgJHtpZH1EaXN0cmlidXRpb25gLCB7XG4gICAgICBkb21haW5OYW1lczogW2RvbWFpbk5hbWVdLFxuICAgICAgY29tbWVudDogZG9tYWluTmFtZSxcbiAgICAgIGRlZmF1bHRSb290T2JqZWN0OiBwcm9wcy5kZWZhdWx0SW5kZXggPyAnaW5kZXguaHRtbCcgOiB1bmRlZmluZWQsXG4gICAgICBkZWZhdWx0QmVoYXZpb3I6IHtcbiAgICAgICAgb3JpZ2luOiBuZXcgUmVzdEFwaU9yaWdpbih0aGlzLmFwaSksXG4gICAgICAgIGFsbG93ZWRNZXRob2RzOiBBbGxvd2VkTWV0aG9kcy5BTExPV19BTEwsXG4gICAgICAgIHZpZXdlclByb3RvY29sUG9saWN5OiBWaWV3ZXJQcm90b2NvbFBvbGljeS5SRURJUkVDVF9UT19IVFRQUyxcbiAgICAgICAgY2FjaGVQb2xpY3k6IENhY2hlUG9saWN5LkNBQ0hJTkdfRElTQUJMRUQsIC8vIEFzc3VtZSBkeW5hbWljIGNvbnRlbnRcbiAgICAgICAgb3JpZ2luUmVxdWVzdFBvbGljeTogT3JpZ2luUmVxdWVzdFBvbGljeS5BTExfVklFV0VSX0VYQ0VQVF9IT1NUX0hFQURFUixcbiAgICAgICAgLi4uZGVmYXVsdEJlaGF2aW9yLFxuICAgICAgfSxcbiAgICAgIC8vIEFsbCByZXF1ZXN0cyBmb3Igc29tZXRoaW5nIHdpdGggYSBmaWxlIGV4dGVuc2lvbiBnbyB0byBzMyAoYWN0dWFsbHksIGFueSBwYXRoIHRoYXQgY29udGFpbnMgYSBwZXJpb2QpLlxuICAgICAgLy8gVGhlIGFpbSBpcyB0byByb3V0ZSAqLmNzcywgKi5qcywgKi5qcGVnLCBldGMpXG4gICAgICBhZGRpdGlvbmFsQmVoYXZpb3JzOiB7XG4gICAgICAgICcqLionOiB7XG4gICAgICAgICAgb3JpZ2luOiBTM0J1Y2tldE9yaWdpbi53aXRoT3JpZ2luQWNjZXNzQ29udHJvbCh0aGlzLmJ1Y2tldCksXG4gICAgICAgICAgYWxsb3dlZE1ldGhvZHM6IEFsbG93ZWRNZXRob2RzLkFMTE9XX0dFVF9IRUFEX09QVElPTlMsXG4gICAgICAgICAgdmlld2VyUHJvdG9jb2xQb2xpY3k6IFZpZXdlclByb3RvY29sUG9saWN5LlJFRElSRUNUX1RPX0hUVFBTLFxuICAgICAgICAgIGNvbXByZXNzOiB0cnVlLFxuICAgICAgICB9LFxuICAgICAgICAuLi5hZGRpdGlvbmFsQmVoYXZpb3JzLFxuICAgICAgfSxcbiAgICAgIGNlcnRpZmljYXRlOiB0aGlzLmNlcnRpZmljYXRlLFxuICAgICAgZXJyb3JSZXNwb25zZXM6IHByb3BzLmVycm9yUmVzcG9uc2VzLFxuICAgICAgLi4uZGlzdHJpYnV0aW9uUHJvcHMsXG4gICAgfSk7XG4gICAgZ2l0aHViQWN0aW9ucyhzY29wZSkuYWRkR2hhRGlzdHJpYnV0aW9uKGlkLCB0aGlzLmRpc3RyaWJ1dGlvbik7XG5cbiAgICAvLyBETlMgcmVjb3JkIGZvciB0aGUgQ2xvdWRmcm9udCBkaXN0cmlidXRpb25cbiAgICBuZXcgQVJlY29yZChzY29wZSwgYCR7aWR9QVJlY29yZGAsIHtcbiAgICAgIHJlY29yZE5hbWU6IGRvbWFpbk5hbWUsXG4gICAgICB0YXJnZXQ6IFJlY29yZFRhcmdldC5mcm9tQWxpYXMobmV3IENsb3VkRnJvbnRUYXJnZXQodGhpcy5kaXN0cmlidXRpb24pKSxcbiAgICAgIHpvbmU6IHByb3BzLnpvbmUsXG4gICAgfSk7XG5cbiAgICBpZiAocHJvcHMucmVkaXJlY3RXd3cgIT09IGZhbHNlKSBuZXcgUmVkaXJlY3RXd3coc2NvcGUsIGlkLCB7IHpvbmU6IHByb3BzLnpvbmUsIGNlcnRpZmljYXRlOiB0aGlzLmNlcnRpZmljYXRlLCBkb21haW5OYW1lIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBXZWJBcHAgYmFja2VkIGJ5IGEgTm9kZS5qcyBMYW1iZGEgZnVuY3Rpb24uXG4gICAqXG4gICAqIE1lbW9yeSBkZWZhdWx0cyB0byAzMDA4IE1CIGJlY2F1c2UgdGhpcyBoYXMgdGhlIGVmZmVzdCBvZiBhc3NpZ25pbmcgbW9yZSBjb21wdXRlIHJlc291cmNlIGFuZCB0aGVyZWZvcmUgcmVkdWNlcyBsYXRlbmN5LlxuICAgKi9cbiAgc3RhdGljIG5vZGUoXG4gICAgc2NvcGU6IENvbnN0cnVjdCxcbiAgICBpZDogc3RyaW5nLFxuICAgIHpvbmU6IElIb3N0ZWRab25lLFxuICAgIGRvbWFpbk5hbWU/OiBzdHJpbmcsXG4gICAgZGVmYXVsdEluZGV4PzogYm9vbGVhbixcbiAgICByZWRpcmVjdFd3dz86IGJvb2xlYW4sXG4gICAgZnVuY3Rpb25Qcm9wcz86IFppcEZ1bmN0aW9uUHJvcHMsXG4gICk6IFdlYkFwcCB7XG4gICAgY29uc3QgbGFtYmRhID0gWmlwRnVuY3Rpb24ubm9kZShzY29wZSwgaWQsIHsgbWVtb3J5U2l6ZTogMzAwOCwgLi4uZnVuY3Rpb25Qcm9wcyB9KTtcbiAgICByZXR1cm4gbmV3IFdlYkFwcChzY29wZSwgaWQsIHtcbiAgICAgIGxhbWJkYSwgem9uZSwgZG9tYWluTmFtZSwgZGVmYXVsdEluZGV4LCByZWRpcmVjdFd3dyxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgV2ViQXBwIGJhY2tlZCBieSBhIFB5dGhvbiBMYW1iZGEgZnVuY3Rpb24uXG4gICAqXG4gICAqIE1lbW9yeSBkZWZhdWx0cyB0byAzMDA4IE1CIGJlY2F1c2UgdGhpcyBoYXMgdGhlIGVmZmVzdCBvZiBhc3NpZ25pbmcgbW9yZSBjb21wdXRlIHJlc291cmNlIGFuZCB0aGVyZWZvcmUgcmVkdWNlcyBsYXRlbmN5LlxuICAgKi9cbiAgc3RhdGljIHB5dGhvbihcbiAgICBzY29wZTogQ29uc3RydWN0LFxuICAgIGlkOiBzdHJpbmcsXG4gICAgem9uZTogSUhvc3RlZFpvbmUsXG4gICAgZG9tYWluTmFtZT86IHN0cmluZyxcbiAgICBkZWZhdWx0SW5kZXg/OiBib29sZWFuLFxuICAgIHJlZGlyZWN0V3d3PzogYm9vbGVhbixcbiAgICBmdW5jdGlvblByb3BzPzogWmlwRnVuY3Rpb25Qcm9wcyxcbiAgKTogV2ViQXBwIHtcbiAgICBjb25zdCBsYW1iZGEgPSBaaXBGdW5jdGlvbi5weXRob24oc2NvcGUsIGlkLCB7IG1lbW9yeVNpemU6IDMwMDgsIC4uLmZ1bmN0aW9uUHJvcHMgfSk7XG4gICAgcmV0dXJuIG5ldyBXZWJBcHAoc2NvcGUsIGlkLCB7XG4gICAgICBsYW1iZGEsIHpvbmUsIGRvbWFpbk5hbWUsIGRlZmF1bHRJbmRleCwgcmVkaXJlY3RXd3csXG4gICAgfSk7XG4gIH1cbn1cbiJdfQ==