UNPKG

23.6 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.AssetManifestBuilder = void 0;
4const fs = require("fs");
5const path = require("path");
6const cxschema = require("@aws-cdk/cloud-assembly-schema");
7const assets_1 = require("../assets");
8const cfn_fn_1 = require("../cfn-fn");
9const _shared_1 = require("./_shared");
10/**
11 * Build an manifest from assets added to a stack synthesizer
12 */
13class AssetManifestBuilder {
14 constructor() {
15 this.files = {};
16 this.dockerImages = {};
17 }
18 addFileAssetDefault(asset, stack, bucketName, bucketPrefix, role) {
19 validateFileAssetSource(asset);
20 const extension = asset.fileName != undefined ? path.extname(asset.fileName) : '';
21 const objectKey = bucketPrefix +
22 asset.sourceHash +
23 (asset.packaging === assets_1.FileAssetPackaging.ZIP_DIRECTORY
24 ? '.zip'
25 : extension);
26 // Add to manifest
27 this.files[asset.sourceHash] = {
28 source: {
29 path: asset.fileName,
30 executable: asset.executable,
31 packaging: asset.packaging,
32 },
33 destinations: {
34 [this.manifestEnvName(stack)]: {
35 bucketName: bucketName,
36 objectKey,
37 region: _shared_1.resolvedOr(stack.region, undefined),
38 assumeRoleArn: role?.assumeRoleArn,
39 assumeRoleExternalId: role?.assumeRoleExternalId,
40 },
41 },
42 };
43 const { region, urlSuffix } = stackLocationOrInstrinsics(stack);
44 const httpUrl = cfnify(`https://s3.${region}.${urlSuffix}/${bucketName}/${objectKey}`);
45 const s3ObjectUrlWithPlaceholders = `s3://${bucketName}/${objectKey}`;
46 // Return CFN expression
47 //
48 // 's3ObjectUrlWithPlaceholders' is intended for the CLI. The CLI ultimately needs a
49 // 'https://s3.REGION.amazonaws.com[.cn]/name/hash' URL to give to CloudFormation.
50 // However, there's no way for us to actually know the URL_SUFFIX in the framework, so
51 // we can't construct that URL. Instead, we record the 's3://.../...' form, and the CLI
52 // transforms it to the correct 'https://.../' URL before calling CloudFormation.
53 return {
54 bucketName: cfnify(bucketName),
55 objectKey,
56 httpUrl,
57 s3ObjectUrl: cfnify(s3ObjectUrlWithPlaceholders),
58 s3ObjectUrlWithPlaceholders,
59 s3Url: httpUrl,
60 };
61 }
62 addDockerImageAssetDefault(asset, stack, repositoryName, dockerTagPrefix, role) {
63 validateDockerImageAssetSource(asset);
64 const imageTag = dockerTagPrefix + asset.sourceHash;
65 // Add to manifest
66 this.dockerImages[asset.sourceHash] = {
67 source: {
68 executable: asset.executable,
69 directory: asset.directoryName,
70 dockerBuildArgs: asset.dockerBuildArgs,
71 dockerBuildTarget: asset.dockerBuildTarget,
72 dockerFile: asset.dockerFile,
73 networkMode: asset.networkMode,
74 platform: asset.platform,
75 },
76 destinations: {
77 [this.manifestEnvName(stack)]: {
78 repositoryName: repositoryName,
79 imageTag,
80 region: _shared_1.resolvedOr(stack.region, undefined),
81 assumeRoleArn: role?.assumeRoleArn,
82 assumeRoleExternalId: role?.assumeRoleExternalId,
83 },
84 },
85 };
86 const { account, region, urlSuffix } = stackLocationOrInstrinsics(stack);
87 // Return CFN expression
88 return {
89 repositoryName: cfnify(repositoryName),
90 imageUri: cfnify(`${account}.dkr.ecr.${region}.${urlSuffix}/${repositoryName}:${imageTag}`),
91 };
92 }
93 /**
94 * Write the manifest to disk, and add it to the synthesis session
95 *
96 * Reutrn the artifact Id
97 */
98 writeManifest(stack, session, additionalProps = {}) {
99 const artifactId = `${stack.artifactId}.assets`;
100 const manifestFile = `${artifactId}.json`;
101 const outPath = path.join(session.assembly.outdir, manifestFile);
102 const manifest = {
103 version: cxschema.Manifest.version(),
104 files: this.files,
105 dockerImages: this.dockerImages,
106 };
107 fs.writeFileSync(outPath, JSON.stringify(manifest, undefined, 2));
108 session.assembly.addArtifact(artifactId, {
109 type: cxschema.ArtifactType.ASSET_MANIFEST,
110 properties: {
111 file: manifestFile,
112 ...additionalProps,
113 },
114 });
115 return artifactId;
116 }
117 manifestEnvName(stack) {
118 return [
119 _shared_1.resolvedOr(stack.account, 'current_account'),
120 _shared_1.resolvedOr(stack.region, 'current_region'),
121 ].join('-');
122 }
123}
124exports.AssetManifestBuilder = AssetManifestBuilder;
125function validateFileAssetSource(asset) {
126 if (!!asset.executable === !!asset.fileName) {
127 throw new Error(`Exactly one of 'fileName' or 'executable' is required, got: ${JSON.stringify(asset)}`);
128 }
129 if (!!asset.packaging !== !!asset.fileName) {
130 throw new Error(`'packaging' is expected in combination with 'fileName', got: ${JSON.stringify(asset)}`);
131 }
132}
133function validateDockerImageAssetSource(asset) {
134 if (!!asset.executable === !!asset.directoryName) {
135 throw new Error(`Exactly one of 'directoryName' or 'executable' is required, got: ${JSON.stringify(asset)}`);
136 }
137 check('dockerBuildArgs');
138 check('dockerBuildTarget');
139 check('dockerFile');
140 function check(key) {
141 if (asset[key] && !asset.directoryName) {
142 throw new Error(`'${key}' is only allowed in combination with 'directoryName', got: ${JSON.stringify(asset)}`);
143 }
144 }
145}
146/**
147 * Return the stack locations if they're concrete, or the original CFN intrisics otherwise
148 *
149 * We need to return these instead of the tokenized versions of the strings,
150 * since we must accept those same ${AWS::AccountId}/${AWS::Region} placeholders
151 * in bucket names and role names (in order to allow environment-agnostic stacks).
152 *
153 * We'll wrap a single {Fn::Sub} around the final string in order to replace everything,
154 * but we can't have the token system render part of the string to {Fn::Join} because
155 * the CFN specification doesn't allow the {Fn::Sub} template string to be an arbitrary
156 * expression--it must be a string literal.
157 */
158function stackLocationOrInstrinsics(stack) {
159 return {
160 account: _shared_1.resolvedOr(stack.account, '${AWS::AccountId}'),
161 region: _shared_1.resolvedOr(stack.region, '${AWS::Region}'),
162 urlSuffix: _shared_1.resolvedOr(stack.urlSuffix, '${AWS::URLSuffix}'),
163 };
164}
165/**
166 * If the string still contains placeholders, wrap it in a Fn::Sub so they will be substituted at CFN deployment time
167 *
168 * (This happens to work because the placeholders we picked map directly onto CFN
169 * placeholders. If they didn't we'd have to do a transformation here).
170 */
171function cfnify(s) {
172 return s.indexOf('${') > -1 ? cfn_fn_1.Fn.sub(s) : s;
173}
174//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiX2Fzc2V0LW1hbmlmZXN0LWJ1aWxkZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJfYXNzZXQtbWFuaWZlc3QtYnVpbGRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSx5QkFBeUI7QUFDekIsNkJBQTZCO0FBRTdCLDJEQUEyRDtBQUMzRCxzQ0FBcUk7QUFDckksc0NBQStCO0FBRy9CLHVDQUF1QztBQUV2Qzs7R0FFRztBQUNILE1BQWEsb0JBQW9CO0lBQWpDO1FBQ21CLFVBQUssR0FBaUQsRUFBRSxDQUFDO1FBQ3pELGlCQUFZLEdBQXdELEVBQUUsQ0FBQztJQStJMUYsQ0FBQztJQTdJUSxtQkFBbUIsQ0FDeEIsS0FBc0IsRUFDdEIsS0FBWSxFQUNaLFVBQWtCLEVBQ2xCLFlBQW9CLEVBQ3BCLElBQWtCO1FBRWxCLHVCQUF1QixDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRS9CLE1BQU0sU0FBUyxHQUNiLEtBQUssQ0FBQyxRQUFRLElBQUksU0FBUyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQ2xFLE1BQU0sU0FBUyxHQUNiLFlBQVk7WUFDWixLQUFLLENBQUMsVUFBVTtZQUNoQixDQUFDLEtBQUssQ0FBQyxTQUFTLEtBQUssMkJBQWtCLENBQUMsYUFBYTtnQkFDbkQsQ0FBQyxDQUFDLE1BQU07Z0JBQ1IsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBRWpCLGtCQUFrQjtRQUNsQixJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsR0FBRztZQUM3QixNQUFNLEVBQUU7Z0JBQ04sSUFBSSxFQUFFLEtBQUssQ0FBQyxRQUFRO2dCQUNwQixVQUFVLEVBQUUsS0FBSyxDQUFDLFVBQVU7Z0JBQzVCLFNBQVMsRUFBRSxLQUFLLENBQUMsU0FBUzthQUMzQjtZQUNELFlBQVksRUFBRTtnQkFDWixDQUFDLElBQUks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LENBQUMsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFdBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUM5QyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgZnMgZnJvbSAnZnMnO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcblxuaW1wb3J0ICogYXMgY3hzY2hlbWEgZnJvbSAnQGF3cy1jZGsvY2xvdWQtYXNzZW1ibHktc2NoZW1hJztcbmltcG9ydCB7IEZpbGVBc3NldFNvdXJjZSwgRmlsZUFzc2V0TG9jYXRpb24sIEZpbGVBc3NldFBhY2thZ2luZywgRG9ja2VySW1hZ2VBc3NldFNvdXJjZSwgRG9ja2VySW1hZ2VBc3NldExvY2F0aW9uIH0gZnJvbSAnLi4vYXNzZXRzJztcbmltcG9ydCB7IEZuIH0gZnJvbSAnLi4vY2ZuLWZuJztcbmltcG9ydCB7IElTeW50aGVzaXNTZXNzaW9uIH0gZnJvbSAnLi4vY29uc3RydWN0LWNvbXBhdCc7XG5pbXBvcnQgeyBTdGFjayB9IGZyb20gJy4uL3N0YWNrJztcbmltcG9ydCB7IHJlc29sdmVkT3IgfSBmcm9tICcuL19zaGFyZWQnO1xuXG4vKipcbiAqIEJ1aWxkIGFuIG1hbmlmZXN0IGZyb20gYXNzZXRzIGFkZGVkIHRvIGEgc3RhY2sgc3ludGhlc2l6ZXJcbiAqL1xuZXhwb3J0IGNsYXNzIEFzc2V0TWFuaWZlc3RCdWlsZGVyIHtcbiAgcHJpdmF0ZSByZWFkb25seSBmaWxlczogTm9uTnVsbGFibGU8Y3hzY2hlbWEuQXNzZXRNYW5pZmVzdFsnZmlsZXMnXT4gPSB7fTtcbiAgcHJpdmF0ZSByZWFkb25seSBkb2NrZXJJbWFnZXM6IE5vbk51bGxhYmxlPGN4c2NoZW1hLkFzc2V0TWFuaWZlc3RbJ2RvY2tlckltYWdlcyddPiA9IHt9O1xuXG4gIHB1YmxpYyBhZGRGaWxlQXNzZXREZWZhdWx0KFxuICAgIGFzc2V0OiBGaWxlQXNzZXRTb3VyY2UsXG4gICAgc3RhY2s6IFN0YWNrLFxuICAgIGJ1Y2tldE5hbWU6IHN0cmluZyxcbiAgICBidWNrZXRQcmVmaXg6IHN0cmluZyxcbiAgICByb2xlPzogUm9sZU9wdGlvbnMsXG4gICk6IEZpbGVBc3NldExvY2F0aW9uIHtcbiAgICB2YWxpZGF0ZUZpbGVBc3NldFNvdXJjZShhc3NldCk7XG5cbiAgICBjb25zdCBleHRlbnNpb24gPVxuICAgICAgYXNzZXQuZmlsZU5hbWUgIT0gdW5kZWZpbmVkID8gcGF0aC5leHRuYW1lKGFzc2V0LmZpbGVOYW1lKSA6ICcnO1xuICAgIGNvbnN0IG9iamVjdEtleSA9XG4gICAgICBidWNrZXRQcmVmaXggK1xuICAgICAgYXNzZXQuc291cmNlSGFzaCArXG4gICAgICAoYXNzZXQucGFja2FnaW5nID09PSBGaWxlQXNzZXRQYWNrYWdpbmcuWklQX0RJUkVDVE9SWVxuICAgICAgICA/ICcuemlwJ1xuICAgICAgICA6IGV4dGVuc2lvbik7XG5cbiAgICAvLyBBZGQgdG8gbWFuaWZlc3RcbiAgICB0aGlzLmZpbGVzW2Fzc2V0LnNvdXJjZUhhc2hdID0ge1xuICAgICAgc291cmNlOiB7XG4gICAgICAgIHBhdGg6IGFzc2V0LmZpbGVOYW1lLFxuICAgICAgICBleGVjdXRhYmxlOiBhc3NldC5leGVjdXRhYmxlLFxuICAgICAgICBwYWNrYWdpbmc6IGFzc2V0LnBhY2thZ2luZyxcbiAgICAgIH0sXG4gICAgICBkZXN0aW5hdGlvbnM6IHtcbiAgICAgICAgW3RoaXMubWFuaWZlc3RFbnZOYW1lKHN0YWNrKV06IHtcbiAgICAgICAgICBidWNrZXROYW1lOiBidWNrZXROYW1lLFxuICAgICAgICAgIG9iamVjdEtleSxcbiAgICAgICAgICByZWdpb246IHJlc29sdmVkT3Ioc3RhY2sucmVnaW9uLCB1bmRlZmluZWQpLFxuICAgICAgICAgIGFzc3VtZVJvbGVBcm46IHJvbGU/LmFzc3VtZVJvbGVBcm4sXG4gICAgICAgICAgYXNzdW1lUm9sZUV4dGVybmFsSWQ6IHJvbGU/LmFzc3VtZVJvbGVFeHRlcm5hbElkLFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICB9O1xuXG4gICAgY29uc3QgeyByZWdpb24sIHVybFN1ZmZpeCB9ID0gc3RhY2tMb2NhdGlvbk9ySW5zdHJpbnNpY3Moc3RhY2spO1xuICAgIGNvbnN0IGh0dHBVcmwgPSBjZm5pZnkoXG4gICAgICBgaHR0cHM6Ly9zMy4ke3JlZ2lvbn0uJHt1cmxTdWZmaXh9LyR7YnVja2V0TmFtZX0vJHtvYmplY3RLZXl9YCxcbiAgICApO1xuICAgIGNvbnN0IHMzT2JqZWN0VXJsV2l0aFBsYWNlaG9sZGVycyA9IGBzMzovLyR7YnVja2V0TmFtZX0vJHtvYmplY3RLZXl9YDtcblxuICAgIC8vIFJldHVybiBDRk4gZXhwcmVzc2lvblxuICAgIC8vXG4gICAgLy8gJ3MzT2JqZWN0VXJsV2l0aFBsYWNlaG9sZGVycycgaXMgaW50ZW5kZWQgZm9yIHRoZSBDTEkuIFRoZSBDTEkgdWx0aW1hdGVseSBuZWVkcyBhXG4gICAgLy8gJ2h0dHBzOi8vczMuUkVHSU9OLmFtYXpvbmF3cy5jb21bLmNuXS9uYW1lL2hhc2gnIFVSTCB0byBnaXZlIHRvIENsb3VkRm9ybWF0aW9uLlxuICAgIC8vIEhvd2V2ZXIsIHRoZXJlJ3Mgbm8gd2F5IGZvciB1cyB0byBhY3R1YWxseSBrbm93IHRoZSBVUkxfU1VGRklYIGluIHRoZSBmcmFtZXdvcmssIHNvXG4gICAgLy8gd2UgY2FuJ3QgY29uc3RydWN0IHRoYXQgVVJMLiBJbnN0ZWFkLCB3ZSByZWNvcmQgdGhlICdzMzovLy4uLi8uLi4nIGZvcm0sIGFuZCB0aGUgQ0xJXG4gICAgLy8gdHJhbnNmb3JtcyBpdCB0byB0aGUgY29ycmVjdCAnaHR0cHM6Ly8uLi4vJyBVUkwgYmVmb3JlIGNhbGxpbmcgQ2xvdWRGb3JtYXRpb24uXG4gICAgcmV0dXJuIHtcbiAgICAgIGJ1Y2tldE5hbWU6IGNmbmlmeShidWNrZXROYW1lKSxcbiAgICAgIG9iamVjdEtleSxcbiAgICAgIGh0dHBVcmwsXG4gICAgICBzM09iamVjdFVybDogY2ZuaWZ5KHMzT2JqZWN0VXJsV2l0aFBsYWNlaG9sZGVycyksXG4gICAgICBzM09iamVjdFVybFdpdGhQbGFjZWhvbGRlcnMsXG4gICAgICBzM1VybDogaHR0cFVybCxcbiAgICB9O1xuICB9XG5cbiAgcHVibGljIGFkZERvY2tlckltYWdlQXNzZXREZWZhdWx0KFxuICAgIGFzc2V0OiBEb2NrZXJJbWFnZUFzc2V0U291cmNlLFxuICAgIHN0YWNrOiBTdGFjayxcbiAgICByZXBvc2l0b3J5TmFtZTogc3RyaW5nLFxuICAgIGRvY2tlclRhZ1ByZWZpeDogc3RyaW5nLFxuICAgIHJvbGU/OiBSb2xlT3B0aW9ucyxcbiAgKTogRG9ja2VySW1hZ2VBc3NldExvY2F0aW9uIHtcbiAgICB2YWxpZGF0ZURvY2tlckltYWdlQXNzZXRTb3VyY2UoYXNzZXQpO1xuICAgIGNvbnN0IGltYWdlVGFnID0gZG9ja2VyVGFnUHJlZml4ICsgYXNzZXQuc291cmNlSGFzaDtcblxuICAgIC8vIEFkZCB0byBtYW5pZmVzdFxuICAgIHRoaXMuZG9ja2VySW1hZ2VzW2Fzc2V0LnNvdXJjZUhhc2hdID0ge1xuICAgICAgc291cmNlOiB7XG4gICAgICAgIGV4ZWN1dGFibGU6IGFzc2V0LmV4ZWN1dGFibGUsXG4gICAgICAgIGRpcmVjdG9yeTogYXNzZXQuZGlyZWN0b3J5TmFtZSxcbiAgICAgICAgZG9ja2VyQnVpbGRBcmdzOiBhc3NldC5kb2NrZXJCdWlsZEFyZ3MsXG4gICAgICAgIGRvY2tlckJ1aWxkVGFyZ2V0OiBhc3NldC5kb2NrZXJCdWlsZFRhcmdldCxcbiAgICAgICAgZG9ja2VyRmlsZTogYXNzZXQuZG9ja2VyRmlsZSxcbiAgICAgICAgbmV0d29ya01vZGU6IGFzc2V0Lm5ldHdvcmtNb2RlLFxuICAgICAgICBwbGF0Zm9ybTogYXNzZXQucGxhdGZvcm0sXG4gICAgICB9LFxuICAgICAgZGVzdGluYXRpb25zOiB7XG4gICAgICAgIFt0aGlzLm1hbmlmZXN0RW52TmFtZShzdGFjayldOiB7XG4gICAgICAgICAgcmVwb3NpdG9yeU5hbWU6IHJlcG9zaXRvcnlOYW1lLFxuICAgICAgICAgIGltYWdlVGFnLFxuICAgICAgICAgIHJlZ2lvbjogcmVzb2x2ZWRPcihzdGFjay5yZWdpb24sIHVuZGVmaW5lZCksXG4gICAgICAgICAgYXNzdW1lUm9sZUFybjogcm9sZT8uYXNzdW1lUm9sZUFybixcbiAgICAgICAgICBhc3N1bWVSb2xlRXh0ZXJuYWxJZDogcm9sZT8uYXNzdW1lUm9sZUV4dGVybmFsSWQsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH07XG5cbiAgICBjb25zdCB7IGFjY291bnQsIHJlZ2lvbiwgdXJsU3VmZml4IH0gPSBzdGFja0xvY2F0aW9uT3JJbnN0cmluc2ljcyhzdGFjayk7XG5cbiAgICAvLyBSZXR1cm4gQ0ZOIGV4cHJlc3Npb25cbiAgICByZXR1cm4ge1xuICAgICAgcmVwb3NpdG9yeU5hbWU6IGNmbmlmeShyZXBvc2l0b3J5TmFtZSksXG4gICAgICBpbWFnZVVyaTogY2ZuaWZ5KFxuICAgICAgICBgJHthY2NvdW50fS5ka3IuZWNyLiR7cmVnaW9ufS4ke3VybFN1ZmZpeH0vJHtyZXBvc2l0b3J5TmFtZX06JHtpbWFnZVRhZ31gLFxuICAgICAgKSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFdyaXRlIHRoZSBtYW5pZmVzdCB0byBkaXNrLCBhbmQgYWRkIGl0IHRvIHRoZSBzeW50aGVzaXMgc2Vzc2lvblxuICAgKlxuICAgKiBSZXV0cm4gdGhlIGFydGlmYWN0IElkXG4gICAqL1xuICBwdWJsaWMgd3JpdGVNYW5pZmVzdChcbiAgICBzdGFjazogU3RhY2ssXG4gICAgc2Vzc2lvbjogSVN5bnRoZXNpc1Nlc3Npb24sXG4gICAgYWRkaXRpb25hbFByb3BzOiBQYXJ0aWFsPGN4c2NoZW1hLkFzc2V0TWFuaWZlc3RQcm9wZXJ0aWVzPiA9IHt9LFxuICApOiBzdHJpbmcge1xuICAgIGNvbnN0IGFydGlmYWN0SWQgPSBgJHtzdGFjay5hcnRpZmFjdElkfS5hc3NldHNgO1xuICAgIGNvbnN0IG1hbmlmZXN0RmlsZSA9IGAke2FydGlmYWN0SWR9Lmpzb25gO1xuICAgIGNvbnN0IG91dFBhdGggPSBwYXRoLmpvaW4oc2Vzc2lvbi5hc3NlbWJseS5vdXRkaXIsIG1hbmlmZXN0RmlsZSk7XG5cbiAgICBjb25zdCBtYW5pZmVzdDogY3hzY2hlbWEuQXNzZXRNYW5pZmVzdCA9IHtcbiAgICAgIHZlcnNpb246IGN4c2NoZW1hLk1hbmlmZXN0LnZlcnNpb24oKSxcbiAgICAgIGZpbGVzOiB0aGlzLmZpbGVzLFxuICAgICAgZG9ja2VySW1hZ2VzOiB0aGlzLmRvY2tlckltYWdlcyxcbiAgICB9O1xuXG4gICAgZnMud3JpdGVGaWxlU3luYyhvdXRQYXRoLCBKU09OLnN0cmluZ2lmeShtYW5pZmVzdCwgdW5kZWZpbmVkLCAyKSk7XG5cbiAgICBzZXNzaW9uLmFzc2VtYmx5LmFkZEFydGlmYWN0KGFydGlmYWN0SWQsIHtcbiAgICAgIHR5cGU6IGN4c2NoZW1hLkFydGlmYWN0VHlwZS5BU1NFVF9NQU5JRkVTVCxcbiAgICAgIHByb3BlcnRpZXM6IHtcbiAgICAgICAgZmlsZTogbWFuaWZlc3RGaWxlLFxuICAgICAgICAuLi5hZGRpdGlvbmFsUHJvcHMsXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgcmV0dXJuIGFydGlmYWN0SWQ7XG4gIH1cblxuICBwcml2YXRlIG1hbmlmZXN0RW52TmFtZShzdGFjazogU3RhY2spOiBzdHJpbmcge1xuICAgIHJldHVybiBbXG4gICAgICByZXNvbHZlZE9yKHN0YWNrLmFjY291bnQsICdjdXJyZW50X2FjY291bnQnKSxcbiAgICAgIHJlc29sdmVkT3Ioc3RhY2sucmVnaW9uLCAnY3VycmVudF9yZWdpb24nKSxcbiAgICBdLmpvaW4oJy0nKTtcbiAgfVxufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJvbGVPcHRpb25zIHtcbiAgcmVhZG9ubHkgYXNzdW1lUm9sZUFybj86IHN0cmluZztcbiAgcmVhZG9ubHkgYXNzdW1lUm9sZUV4dGVybmFsSWQ/OiBzdHJpbmc7XG59XG5cbmZ1bmN0aW9uIHZhbGlkYXRlRmlsZUFzc2V0U291cmNlKGFzc2V0OiBGaWxlQXNzZXRTb3VyY2UpIHtcbiAgaWYgKCEhYXNzZXQuZXhlY3V0YWJsZSA9PT0gISFhc3NldC5maWxlTmFtZSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgRXhhY3RseSBvbmUgb2YgJ2ZpbGVOYW1lJyBvciAnZXhlY3V0YWJsZScgaXMgcmVxdWlyZWQsIGdvdDogJHtKU09OLnN0cmluZ2lmeShhc3NldCl9YCk7XG4gIH1cblxuICBpZiAoISFhc3NldC5wYWNrYWdpbmcgIT09ICEhYXNzZXQuZmlsZU5hbWUpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYCdwYWNrYWdpbmcnIGlzIGV4cGVjdGVkIGluIGNvbWJpbmF0aW9uIHdpdGggJ2ZpbGVOYW1lJywgZ290OiAke0pTT04uc3RyaW5naWZ5KGFzc2V0KX1gKTtcbiAgfVxufVxuXG5mdW5jdGlvbiB2YWxpZGF0ZURvY2tlckltYWdlQXNzZXRTb3VyY2UoYXNzZXQ6IERvY2tlckltYWdlQXNzZXRTb3VyY2UpIHtcbiAgaWYgKCEhYXNzZXQuZXhlY3V0YWJsZSA9PT0gISFhc3NldC5kaXJlY3RvcnlOYW1lKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBFeGFjdGx5IG9uZSBvZiAnZGlyZWN0b3J5TmFtZScgb3IgJ2V4ZWN1dGFibGUnIGlzIHJlcXVpcmVkLCBnb3Q6ICR7SlNPTi5zdHJpbmdpZnkoYXNzZXQpfWApO1xuICB9XG5cbiAgY2hlY2soJ2RvY2tlckJ1aWxkQXJncycpO1xuICBjaGVjaygnZG9ja2VyQnVpbGRUYXJnZXQnKTtcbiAgY2hlY2soJ2RvY2tlckZpbGUnKTtcblxuICBmdW5jdGlvbiBjaGVjazxLIGV4dGVuZHMga2V5b2YgRG9ja2VySW1hZ2VBc3NldFNvdXJjZT4oa2V5OiBLKSB7XG4gICAgaWYgKGFzc2V0W2tleV0gJiYgIWFzc2V0LmRpcmVjdG9yeU5hbWUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgJyR7a2V5fScgaXMgb25seSBhbGxvd2VkIGluIGNvbWJpbmF0aW9uIHdpdGggJ2RpcmVjdG9yeU5hbWUnLCBnb3Q6ICR7SlNPTi5zdHJpbmdpZnkoYXNzZXQpfWApO1xuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIFJldHVybiB0aGUgc3RhY2sgbG9jYXRpb25zIGlmIHRoZXkncmUgY29uY3JldGUsIG9yIHRoZSBvcmlnaW5hbCBDRk4gaW50cmlzaWNzIG90aGVyd2lzZVxuICpcbiAqIFdlIG5lZWQgdG8gcmV0dXJuIHRoZXNlIGluc3RlYWQgb2YgdGhlIHRva2VuaXplZCB2ZXJzaW9ucyBvZiB0aGUgc3RyaW5ncyxcbiAqIHNpbmNlIHdlIG11c3QgYWNjZXB0IHRob3NlIHNhbWUgJHtBV1M6OkFjY291bnRJZH0vJHtBV1M6OlJlZ2lvbn0gcGxhY2Vob2xkZXJzXG4gKiBpbiBidWNrZXQgbmFtZXMgYW5kIHJvbGUgbmFtZXMgKGluIG9yZGVyIHRvIGFsbG93IGVudmlyb25tZW50LWFnbm9zdGljIHN0YWNrcykuXG4gKlxuICogV2UnbGwgd3JhcCBhIHNpbmdsZSB7Rm46OlN1Yn0gYXJvdW5kIHRoZSBmaW5hbCBzdHJpbmcgaW4gb3JkZXIgdG8gcmVwbGFjZSBldmVyeXRoaW5nLFxuICogYnV0IHdlIGNhbid0IGhhdmUgdGhlIHRva2VuIHN5c3RlbSByZW5kZXIgcGFydCBvZiB0aGUgc3RyaW5nIHRvIHtGbjo6Sm9pbn0gYmVjYXVzZVxuICogdGhlIENGTiBzcGVjaWZpY2F0aW9uIGRvZXNuJ3QgYWxsb3cgdGhlIHtGbjo6U3VifSB0ZW1wbGF0ZSBzdHJpbmcgdG8gYmUgYW4gYXJiaXRyYXJ5XG4gKiBleHByZXNzaW9uLS1pdCBtdXN0IGJlIGEgc3RyaW5nIGxpdGVyYWwuXG4gKi9cbmZ1bmN0aW9uIHN0YWNrTG9jYXRpb25Pckluc3RyaW5zaWNzKHN0YWNrOiBTdGFjaykge1xuICByZXR1cm4ge1xuICAgIGFjY291bnQ6IHJlc29sdmVkT3Ioc3RhY2suYWNjb3VudCwgJyR7QVdTOjpBY2NvdW50SWR9JyksXG4gICAgcmVnaW9uOiByZXNvbHZlZE9yKHN0YWNrLnJlZ2lvbiwgJyR7QVdTOjpSZWdpb259JyksXG4gICAgdXJsU3VmZml4OiByZXNvbHZlZE9yKHN0YWNrLnVybFN1ZmZpeCwgJyR7QVdTOjpVUkxTdWZmaXh9JyksXG4gIH07XG59XG5cbi8qKlxuICogSWYgdGhlIHN0cmluZyBzdGlsbCBjb250YWlucyBwbGFjZWhvbGRlcnMsIHdyYXAgaXQgaW4gYSBGbjo6U3ViIHNvIHRoZXkgd2lsbCBiZSBzdWJzdGl0dXRlZCBhdCBDRk4gZGVwbG95bWVudCB0aW1lXG4gKlxuICogKFRoaXMgaGFwcGVucyB0byB3b3JrIGJlY2F1c2UgdGhlIHBsYWNlaG9sZGVycyB3ZSBwaWNrZWQgbWFwIGRpcmVjdGx5IG9udG8gQ0ZOXG4gKiBwbGFjZWhvbGRlcnMuIElmIHRoZXkgZGlkbid0IHdlJ2QgaGF2ZSB0byBkbyBhIHRyYW5zZm9ybWF0aW9uIGhlcmUpLlxuICovXG5mdW5jdGlvbiBjZm5pZnkoczogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIHMuaW5kZXhPZignJHsnKSA+IC0xID8gRm4uc3ViKHMpIDogcztcbn0iXX0=
\No newline at end of file