@umccr/htsget-lambda 0.9.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,363 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.HtsgetLambda = void 0;
7
+ const fs_1 = require("fs");
8
+ const node_path_1 = require("node:path");
9
+ const os_1 = require("os");
10
+ const aws_cdk_lib_1 = require("aws-cdk-lib");
11
+ const constructs_1 = require("constructs");
12
+ const aws_cognito_1 = require("aws-cdk-lib/aws-cognito");
13
+ const aws_iam_1 = require("aws-cdk-lib/aws-iam");
14
+ const aws_lambda_1 = require("aws-cdk-lib/aws-lambda");
15
+ const aws_certificatemanager_1 = require("aws-cdk-lib/aws-certificatemanager");
16
+ const aws_route53_1 = require("aws-cdk-lib/aws-route53");
17
+ const aws_route53_targets_1 = require("aws-cdk-lib/aws-route53-targets");
18
+ const cargo_lambda_cdk_1 = require("cargo-lambda-cdk");
19
+ const path_1 = __importDefault(require("path"));
20
+ const aws_apigatewayv2_integrations_1 = require("aws-cdk-lib/aws-apigatewayv2-integrations");
21
+ const aws_apigatewayv2_1 = require("aws-cdk-lib/aws-apigatewayv2");
22
+ const aws_apigatewayv2_authorizers_1 = require("aws-cdk-lib/aws-apigatewayv2-authorizers");
23
+ const aws_s3_1 = require("aws-cdk-lib/aws-s3");
24
+ const aws_s3_deployment_1 = require("aws-cdk-lib/aws-s3-deployment");
25
+ const aws_secretsmanager_1 = require("aws-cdk-lib/aws-secretsmanager");
26
+ const util_1 = require("cargo-lambda-cdk/lib/util");
27
+ /**
28
+ * @ignore
29
+ * Construct used to deploy htsget-lambda.
30
+ */
31
+ class HtsgetLambda extends constructs_1.Construct {
32
+ constructor(scope, id, props) {
33
+ super(scope, id);
34
+ props.htsgetConfig ??= {
35
+ locations: [],
36
+ };
37
+ let httpApi;
38
+ if (props.httpApi !== undefined) {
39
+ httpApi = props.httpApi;
40
+ }
41
+ else {
42
+ if (props.domain === undefined) {
43
+ throw Error("domain must be defined if httpApi is not specified");
44
+ }
45
+ httpApi = this.createHttpApi(props.domain, props.jwt, props.cors, props.subDomain, props.hostedZone, props.certificateArn);
46
+ }
47
+ let lambdaRole;
48
+ if (props.role == undefined) {
49
+ lambdaRole = HtsgetLambda.createRole(this, id, props.roleName);
50
+ }
51
+ props.buildEnvironment ??= {};
52
+ const htsgetLambda = new cargo_lambda_cdk_1.RustFunction(this, "Function", {
53
+ gitRemote: "https://github.com/umccr/htsget-rs",
54
+ gitForceClone: props.gitForceClone,
55
+ gitReference: props.gitReference,
56
+ functionName: props.functionName,
57
+ binaryName: "htsget-lambda",
58
+ bundling: {
59
+ environment: {
60
+ RUSTFLAGS: "-C target-cpu=neoverse-n1",
61
+ CARGO_PROFILE_RELEASE_LTO: "true",
62
+ CARGO_PROFILE_RELEASE_CODEGEN_UNITS: "1",
63
+ AWS_LAMBDA_HTTP_IGNORE_STAGE_IN_PATH: "true",
64
+ ...props.buildEnvironment,
65
+ },
66
+ cargoLambdaFlags: props.cargoLambdaFlags ?? [
67
+ HtsgetLambda.resolveFeatures(props.htsgetConfig, props.copyTestData ?? false),
68
+ ],
69
+ },
70
+ memorySize: 128,
71
+ timeout: aws_cdk_lib_1.Duration.seconds(28),
72
+ architecture: aws_lambda_1.Architecture.ARM_64,
73
+ role: lambdaRole ?? props.role,
74
+ vpc: props.vpc,
75
+ });
76
+ let bucket = undefined;
77
+ let privateKey = undefined;
78
+ let publicKey = undefined;
79
+ if (props.copyTestData) {
80
+ [bucket, privateKey, publicKey] = this.setupTestData(props.gitReference, props.bucketName);
81
+ }
82
+ if (lambdaRole !== undefined) {
83
+ HtsgetLambda.setPermissions(lambdaRole, props.htsgetConfig, bucket, privateKey, publicKey);
84
+ }
85
+ const env = HtsgetLambda.configToEnv(props.htsgetConfig, props.cors, bucket, privateKey, publicKey);
86
+ for (const key in env) {
87
+ htsgetLambda.addEnvironment(key, env[key]);
88
+ }
89
+ htsgetLambda.addEnvironment("RUST_LOG", "trace");
90
+ const httpIntegration = new aws_apigatewayv2_integrations_1.HttpLambdaIntegration("Integration", htsgetLambda);
91
+ [aws_apigatewayv2_1.HttpMethod.GET, aws_apigatewayv2_1.HttpMethod.POST].map((method) => {
92
+ const path = "/{proxy+}";
93
+ new aws_apigatewayv2_1.HttpRoute(this, `${method}${path}`, {
94
+ httpApi: httpApi,
95
+ routeKey: aws_apigatewayv2_1.HttpRouteKey.with(path, method),
96
+ integration: httpIntegration,
97
+ });
98
+ });
99
+ if (httpApi.defaultAuthorizer === undefined) {
100
+ console.warn("This will create an instance of htsget-rs that is public! Anyone will be able to query the server without authorization.");
101
+ }
102
+ }
103
+ /**
104
+ * Determine the correct features based on the locations.
105
+ */
106
+ static resolveFeatures(config, bucketSetup) {
107
+ const features = [];
108
+ if (config.locations?.some((location) => location.location.startsWith("s3://")) ||
109
+ bucketSetup) {
110
+ features.push("aws");
111
+ }
112
+ if (config.locations?.some((location) => location.location.startsWith("http://") ||
113
+ location.location.startsWith("https://"))) {
114
+ features.push("url");
115
+ }
116
+ if (config.locations?.some((location) => location.private_key !== undefined ||
117
+ location.public_key !== undefined) ||
118
+ bucketSetup) {
119
+ features.push("experimental");
120
+ }
121
+ return features.length === 0
122
+ ? "--all-features"
123
+ : `--features ${features.join(",")}`;
124
+ }
125
+ /**
126
+ * Create a bucket and copy test data if configured.
127
+ */
128
+ setupTestData(gitReference, bucketName) {
129
+ const gitRemote = "https://github.com/umccr/htsget-rs";
130
+ const latestCommit = (0, util_1.exec)("git", [
131
+ "ls-remote",
132
+ gitRemote,
133
+ gitReference ?? "HEAD",
134
+ ])
135
+ .stdout.toString()
136
+ .split(/(\s+)/)[0];
137
+ const localPath = (0, node_path_1.join)((0, os_1.tmpdir)(), latestCommit);
138
+ const bucket = new aws_s3_1.Bucket(this, "Bucket", {
139
+ blockPublicAccess: aws_s3_1.BlockPublicAccess.BLOCK_ALL,
140
+ encryption: aws_s3_1.BucketEncryption.S3_MANAGED,
141
+ enforceSSL: true,
142
+ removalPolicy: aws_cdk_lib_1.RemovalPolicy.RETAIN,
143
+ bucketName,
144
+ });
145
+ // Copy data from upstream htsget repo
146
+ const localDataPath = path_1.default.join(localPath, "data");
147
+ new aws_s3_deployment_1.BucketDeployment(this, "DeployFiles", {
148
+ sources: [
149
+ aws_s3_deployment_1.Source.asset(path_1.default.join(localDataPath, "c4gh")),
150
+ aws_s3_deployment_1.Source.asset(path_1.default.join(localDataPath, "bam")),
151
+ aws_s3_deployment_1.Source.asset(path_1.default.join(localDataPath, "cram")),
152
+ aws_s3_deployment_1.Source.asset(path_1.default.join(localDataPath, "vcf")),
153
+ aws_s3_deployment_1.Source.asset(path_1.default.join(localDataPath, "bcf")),
154
+ ],
155
+ destinationBucket: bucket,
156
+ });
157
+ const keyDir = path_1.default.join(localPath, "data", "c4gh", "keys");
158
+ const privateKey = new aws_secretsmanager_1.Secret(this, "PrivateKey", {
159
+ secretStringValue: aws_cdk_lib_1.SecretValue.unsafePlainText((0, fs_1.readFileSync)(path_1.default.join(keyDir, "bob.sec")).toString()),
160
+ removalPolicy: aws_cdk_lib_1.RemovalPolicy.DESTROY,
161
+ });
162
+ const publicKey = new aws_secretsmanager_1.Secret(this, "PublicKey", {
163
+ secretStringValue: aws_cdk_lib_1.SecretValue.unsafePlainText((0, fs_1.readFileSync)(path_1.default.join(keyDir, "alice.pub")).toString()),
164
+ removalPolicy: aws_cdk_lib_1.RemovalPolicy.DESTROY,
165
+ });
166
+ new aws_cdk_lib_1.CfnOutput(this, "BucketName", { value: bucket.bucketName });
167
+ return [bucket, privateKey, publicKey];
168
+ }
169
+ /**
170
+ * Set permissions for the Lambda role.
171
+ */
172
+ static setPermissions(role, config, bucket, privateKey, publicKey) {
173
+ role.addManagedPolicy(aws_iam_1.ManagedPolicy.fromAwsManagedPolicyName("service-role/AWSLambdaBasicExecutionRole"));
174
+ const locations = config.locations ?? [];
175
+ // Add any "s3://" locations to policy.
176
+ const buckets = locations.flatMap((location) => {
177
+ if (location.location.startsWith("s3://")) {
178
+ return [location.location.split("/")[2]];
179
+ }
180
+ else {
181
+ return [];
182
+ }
183
+ });
184
+ if (bucket !== undefined) {
185
+ buckets.push(bucket.bucketName);
186
+ }
187
+ const bucketPolicy = new aws_iam_1.PolicyStatement({
188
+ actions: ["s3:GetObject"],
189
+ resources: buckets.map((bucket) => `arn:aws:s3:::${bucket}/*`),
190
+ });
191
+ if (bucketPolicy.resources.length !== 0) {
192
+ role.addToPolicy(bucketPolicy);
193
+ }
194
+ // Add any keys from the locations.
195
+ const keys = locations.flatMap((location) => {
196
+ const keys = [];
197
+ if (location.private_key !== undefined) {
198
+ keys.push([false, location.private_key]);
199
+ }
200
+ if (location.public_key !== undefined) {
201
+ keys.push([false, location.public_key]);
202
+ }
203
+ return keys;
204
+ });
205
+ if (privateKey !== undefined) {
206
+ keys.push([true, privateKey.secretArn]);
207
+ }
208
+ if (publicKey !== undefined) {
209
+ keys.push([true, publicKey.secretArn]);
210
+ }
211
+ const secretPolicy = new aws_iam_1.PolicyStatement({
212
+ actions: ["secretsmanager:GetSecretValue"],
213
+ resources: keys.map(([arn, key]) => {
214
+ if (arn) {
215
+ return key;
216
+ }
217
+ else {
218
+ return `arn:aws:secretsmanager:${aws_cdk_lib_1.Aws.REGION}:${aws_cdk_lib_1.Aws.ACCOUNT_ID}:secret:${key}-*`;
219
+ }
220
+ }),
221
+ });
222
+ if (secretPolicy.resources.length !== 0) {
223
+ role.addToPolicy(secretPolicy);
224
+ }
225
+ }
226
+ /**
227
+ * Creates a lambda role with the configured permissions.
228
+ */
229
+ static createRole(scope, id, roleName) {
230
+ return new aws_iam_1.Role(scope, "Role", {
231
+ assumedBy: new aws_iam_1.ServicePrincipal("lambda.amazonaws.com"),
232
+ description: "Lambda execution role for " + id,
233
+ roleName,
234
+ });
235
+ }
236
+ /**
237
+ * Create stateful config related to the httpApi and the API itself.
238
+ */
239
+ createHttpApi(domain, jwtAuthorizer, config, subDomain, hostedZone, certificateArn) {
240
+ // Add an authorizer if auth is required.
241
+ let authorizer = undefined;
242
+ if (jwtAuthorizer !== undefined) {
243
+ // If the cog user pool id is not specified, create a new one.
244
+ if (jwtAuthorizer.cogUserPoolId === undefined) {
245
+ const pool = new aws_cognito_1.UserPool(this, "UserPool");
246
+ jwtAuthorizer.cogUserPoolId = pool.userPoolId;
247
+ }
248
+ authorizer = new aws_apigatewayv2_authorizers_1.HttpJwtAuthorizer("HtsgetAuthorizer", `https://cognito-idp.${aws_cdk_lib_1.Stack.of(this).region}.amazonaws.com/${jwtAuthorizer.cogUserPoolId}`, {
249
+ identitySource: ["$request.header.Authorization"],
250
+ jwtAudience: jwtAuthorizer.audience ?? [],
251
+ });
252
+ }
253
+ let zone;
254
+ if (hostedZone === undefined) {
255
+ zone = aws_route53_1.HostedZone.fromLookup(this, "HostedZone", {
256
+ domainName: domain,
257
+ });
258
+ }
259
+ else {
260
+ zone = hostedZone;
261
+ }
262
+ const url = `${subDomain ?? "htsget"}.${domain}`;
263
+ let certificate;
264
+ if (certificateArn !== undefined) {
265
+ certificate = aws_certificatemanager_1.Certificate.fromCertificateArn(this, "Certificate", certificateArn);
266
+ }
267
+ else {
268
+ certificate = new aws_certificatemanager_1.Certificate(this, "Certificate", {
269
+ domainName: url,
270
+ validation: aws_certificatemanager_1.CertificateValidation.fromDns(hostedZone),
271
+ certificateName: url,
272
+ });
273
+ }
274
+ const domainName = new aws_apigatewayv2_1.DomainName(this, "DomainName", {
275
+ certificate: certificate,
276
+ domainName: url,
277
+ });
278
+ new aws_route53_1.ARecord(this, "ARecord", {
279
+ zone,
280
+ recordName: subDomain ?? "htsget",
281
+ target: aws_route53_1.RecordTarget.fromAlias(new aws_route53_targets_1.ApiGatewayv2DomainProperties(domainName.regionalDomainName, domainName.regionalHostedZoneId)),
282
+ });
283
+ return new aws_apigatewayv2_1.HttpApi(this, "HtsGetApiGateway", {
284
+ defaultAuthorizer: authorizer,
285
+ defaultDomainMapping: {
286
+ domainName: domainName,
287
+ },
288
+ corsPreflight: {
289
+ allowCredentials: config?.allowCredentials ?? false,
290
+ allowHeaders: config?.allowHeaders ?? ["*"],
291
+ allowMethods: config?.allowMethods ?? [aws_apigatewayv2_1.CorsHttpMethod.ANY],
292
+ allowOrigins: config?.allowOrigins ?? ["*"],
293
+ exposeHeaders: config?.exposeHeaders ?? ["*"],
294
+ maxAge: config?.maxAge ?? aws_cdk_lib_1.Duration.days(30),
295
+ },
296
+ });
297
+ }
298
+ /**
299
+ * Convert JSON config to htsget-rs env representation.
300
+ */
301
+ static configToEnv(config, corsConfig, bucket, privateKey, publicKey) {
302
+ const toHtsgetEnv = (value) => {
303
+ return JSON.stringify(value)
304
+ .replaceAll(new RegExp(/"( )*:( )*/g), "=")
305
+ .replaceAll('"', "");
306
+ };
307
+ const out = {};
308
+ const locations = config.locations ?? [];
309
+ if (bucket !== undefined) {
310
+ locations.push({
311
+ location: `s3://${bucket.bucketName}`,
312
+ private_key: privateKey?.secretArn,
313
+ public_key: publicKey?.secretArn,
314
+ });
315
+ }
316
+ let locationsEnv = locations
317
+ .map((location) => {
318
+ return toHtsgetEnv({
319
+ location: location.location,
320
+ ...(location.private_key !== undefined &&
321
+ location.public_key !== undefined && {
322
+ keys: {
323
+ kind: "SecretsManager",
324
+ private: location.private_key,
325
+ public: location.public_key,
326
+ },
327
+ }),
328
+ });
329
+ })
330
+ .join(",");
331
+ locationsEnv = `[${locationsEnv}]`;
332
+ if (locationsEnv == "[]" &&
333
+ config.environment_override?.HTSGET_LOCATIONS === undefined) {
334
+ locationsEnv = undefined;
335
+ }
336
+ out.HTSGET_LOCATIONS = locationsEnv;
337
+ out.HTSGET_TICKET_SERVER_CORS_ALLOW_CREDENTIALS =
338
+ corsConfig?.allowCredentials?.toString();
339
+ // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style
340
+ out.HTSGET_TICKET_SERVER_CORS_ALLOW_HEADERS = `[${corsConfig?.allowHeaders?.join(",")}]`;
341
+ // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style
342
+ out.HTSGET_TICKET_SERVER_CORS_ALLOW_METHODS = `[${corsConfig?.allowMethods?.join(",")}]`;
343
+ // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style
344
+ out.HTSGET_TICKET_SERVER_CORS_ALLOW_ORIGINS = `[${corsConfig?.allowOrigins?.join(",")}]`;
345
+ // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style
346
+ out.HTSGET_TICKET_SERVER_CORS_EXPOSE_HEADERS = `[${corsConfig?.exposeHeaders?.join(",")}]`;
347
+ out.HTSGET_TICKET_SERVER_CORS_MAX_AGE = corsConfig?.maxAge
348
+ ?.toSeconds()
349
+ .toString();
350
+ for (const key in config.service_info) {
351
+ out[`HTSGET_SERVICE_INFO_${key.toUpperCase()}`] = toHtsgetEnv(config.service_info[key]);
352
+ }
353
+ for (const key in config.environment_override) {
354
+ out[key] = toHtsgetEnv(config.environment_override[key]);
355
+ }
356
+ Object.keys(out).forEach((key) =>
357
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
358
+ (out[key] == `[undefined]` || out[key] == "[]") && delete out[key]);
359
+ return out;
360
+ }
361
+ }
362
+ exports.HtsgetLambda = HtsgetLambda;
363
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHRzZ2V0LWxhbWJkYS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImh0c2dldC1sYW1iZGEudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsMkJBQWtDO0FBQ2xDLHlDQUFpQztBQUNqQywyQkFBNEI7QUFFNUIsNkNBT3FCO0FBQ3JCLDJDQUF1QztBQUV2Qyx5REFBbUQ7QUFDbkQsaURBSzZCO0FBQzdCLHVEQUFzRDtBQUN0RCwrRUFJNEM7QUFDNUMseURBS2lDO0FBQ2pDLHlFQUErRTtBQUMvRSx1REFBZ0Q7QUFDaEQsZ0RBQXdCO0FBQ3hCLDZGQUFrRjtBQUNsRixtRUFRc0M7QUFDdEMsMkZBQTZFO0FBQzdFLCtDQUk0QjtBQUM1QixxRUFBeUU7QUFDekUsdUVBQXdEO0FBT3hELG9EQUFpRDtBQUVqRDs7O0dBR0c7QUFDSCxNQUFhLFlBQWEsU0FBUSxzQkFBUztJQUN6QyxZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLEtBQXdCO1FBQ2hFLEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFFakIsS0FBSyxDQUFDLFlBQVksS0FBSztZQUNyQixTQUFTLEVBQUUsRUFBRTtTQUNkLENBQUM7UUFFRixJQUFJLE9BQWlCLENBQUM7UUFDdEIsSUFBSSxLQUFLLENBQUMsT0FBTyxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ2hDLE9BQU8sR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDO1FBQzFCLENBQUM7YUFBTSxDQUFDO1lBQ04sSUFBSSxLQUFLLENBQUMsTUFBTSxLQUFLLFNBQVMsRUFBRSxDQUFDO2dCQUMvQixNQUFNLEtBQUssQ0FBQyxvREFBb0QsQ0FBQyxDQUFDO1lBQ3BFLENBQUM7WUFFRCxPQUFPLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FDMUIsS0FBSyxDQUFDLE1BQU0sRUFDWixLQUFLLENBQUMsR0FBRyxFQUNULEtBQUssQ0FBQyxJQUFJLEVBQ1YsS0FBSyxDQUFDLFNBQVMsRUFDZixLQUFLLENBQUMsVUFBVSxF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TSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxPQUFPLENBQ3RCLENBQUMsR0FBRyxFQUFFLEVBQUU7UUFDTixnRUFBZ0U7UUFDaEUsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLElBQUksYUFBYSxJQUFJLEdBQUcsQ0FBQyxHQUFHLENBQUMsSUFBSSxJQUFJLENBQUMsSUFBSSxPQUFPLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FDckUsQ0FBQztRQUNGLE9BQU8sR0FBNkIsQ0FBQztJQUN2QyxDQUFDO0NBQ0Y7QUFuZEQsb0NBbWRDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSBcImZzXCI7XG5pbXBvcnQgeyBqb2luIH0gZnJvbSBcIm5vZGU6cGF0aFwiO1xuaW1wb3J0IHsgdG1wZGlyIH0gZnJvbSBcIm9zXCI7XG5cbmltcG9ydCB7XG4gIEF3cyxcbiAgQ2ZuT3V0cHV0LFxuICBEdXJhdGlvbixcbiAgUmVtb3ZhbFBvbGljeSxcbiAgU2VjcmV0VmFsdWUsXG4gIFN0YWNrLFxufSBmcm9tIFwiYXdzLWNkay1saWJcIjtcbmltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gXCJjb25zdHJ1Y3RzXCI7XG5cbmltcG9ydCB7IFVzZXJQb29sIH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1jb2duaXRvXCI7XG5pbXBvcnQge1xuICBNYW5hZ2VkUG9saWN5LFxuICBQb2xpY3lTdGF0ZW1lbnQsXG4gIFJvbGUsXG4gIFNlcnZpY2VQcmluY2lwYWwsXG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtaWFtXCI7XG5pbXBvcnQgeyBBcmNoaXRlY3R1cmUgfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWxhbWJkYVwiO1xuaW1wb3J0IHtcbiAgQ2VydGlmaWNhdGUsXG4gIENlcnRpZmljYXRlVmFsaWRhdGlvbixcbiAgSUNlcnRpZmljYXRlLFxufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWNlcnRpZmljYXRlbWFuYWdlclwiO1xuaW1wb3J0IHtcbiAgQVJlY29yZCxcbiAgSG9zdGVkWm9uZSxcbiAgSUhvc3RlZFpvbmUsXG4gIFJlY29yZFRhcmdldCxcbn0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1yb3V0ZTUzXCI7XG5pbXBvcnQgeyBBcGlHYXRld2F5djJEb21haW5Qcm9wZXJ0aWVzIH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1yb3V0ZTUzLXRhcmdldHNcIjtcbmltcG9ydCB7IFJ1c3RGdW5jdGlvbiB9IGZyb20gXCJjYXJnby1sYW1iZGEtY2RrXCI7XG5pbXBvcnQgcGF0aCBmcm9tIFwicGF0aFwiO1xuaW1wb3J0IHsgSHR0cExhbWJkYUludGVncmF0aW9uIH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1hcGlnYXRld2F5djItaW50ZWdyYXRpb25zXCI7XG5pbXBvcnQge1xuICBDb3JzSHR0cE1ldGhvZCxcbiAgRG9tYWluTmFtZSxcbiAgSHR0cEFwaSxcbiAgSHR0cE1ldGhvZCxcbiAgSHR0cFJvdXRlLFxuICBIdHRwUm91dGVLZXksXG4gIElIdHRwQXBpLFxufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWFwaWdhdGV3YXl2MlwiO1xuaW1wb3J0IHsgSHR0cEp3dEF1dGhvcml6ZXIgfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWFwaWdhdGV3YXl2Mi1hdXRob3JpemVyc1wiO1xuaW1wb3J0IHtcbiAgQmxvY2tQdWJsaWNBY2Nlc3MsXG4gIEJ1Y2tldCxcbiAgQnVja2V0RW5jcnlwdGlvbixcbn0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1zM1wiO1xuaW1wb3J0IHsgQnVja2V0RGVwbG95bWVudCwgU291cmNlIH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1zMy1kZXBsb3ltZW50XCI7XG5pbXBvcnQgeyBTZWNyZXQgfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLXNlY3JldHNtYW5hZ2VyXCI7XG5pbXBvcnQge1xuICBDb3JzQ29uaWZnLFxuICBIdHNnZXRDb25maWcsXG4gIEh0c2dldExhbWJkYVByb3BzLFxuICBKd3RDb25maWcsXG59IGZyb20gXCIuL2NvbmZpZ1wiO1xuaW1wb3J0IHsgZXhlYyB9IGZyb20gXCJjYXJnby1sYW1iZGEtY2RrL2xpYi91dGlsXCI7XG5cbi8qKlxuICogQGlnbm9yZVxuICogQ29uc3RydWN0IHVzZWQgdG8gZGVwbG95IGh0c2dldC1sYW1iZGEuXG4gKi9cbmV4cG9ydCBjbGFzcyBIdHNnZXRMYW1iZGEgZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogSHRzZ2V0TGFtYmRhUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgcHJvcHMuaHRzZ2V0Q29uZmlnID8/PSB7XG4gICAgICBsb2NhdGlvbnM6IFtdLFxuICAgIH07XG5cbiAgICBsZXQgaHR0cEFwaTogSUh0dHBBcGk7XG4gICAgaWYgKHByb3BzLmh0dHBBcGkgIT09IHVuZGVmaW5lZCkge1xuICAgICAgaHR0cEFwaSA9IHByb3BzLmh0dHBBcGk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGlmIChwcm9wcy5kb21haW4gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICB0aHJvdyBFcnJvcihcImRvbWFpbiBtdXN0IGJlIGRlZmluZWQgaWYgaHR0cEFwaSBpcyBub3Qgc3BlY2lmaWVkXCIpO1xuICAgICAgfVxuXG4gICAgICBodHRwQXBpID0gdGhpcy5jcmVhdGVIdHRwQXBpKFxuICAgICAgICBwcm9wcy5kb21haW4sXG4gICAgICAgIHByb3BzLmp3dCxcbiAgICAgICAgcHJvcHMuY29ycyxcbiAgICAgICAgcHJvcHMuc3ViRG9tYWluLFxuICAgICAgICBwcm9wcy5ob3N0ZWRab25lLFxuICAgICAgICBwcm9wcy5jZXJ0aWZpY2F0ZUFybixcbiAgICAgICk7XG4gICAgfVxuXG4gICAgbGV0IGxhbWJkYVJvbGU6IFJvbGUgfCB1bmRlZmluZWQ7XG4gICAgaWYgKHByb3BzLnJvbGUgPT0gdW5kZWZpbmVkKSB7XG4gICAgICBsYW1iZGFSb2xlID0gSHRzZ2V0TGFtYmRhLmNyZWF0ZVJvbGUodGhpcywgaWQsIHByb3BzLnJvbGVOYW1lKTtcbiAgICB9XG5cbiAgICBwcm9wcy5idWlsZEVudmlyb25tZW50ID8/PSB7fTtcblxuICAgIGNvbnN0IGh0c2dldExhbWJkYSA9IG5ldyBSdXN0RnVuY3Rpb24odGhpcywgXCJGdW5jdGlvblwiLCB7XG4gICAgICBnaXRSZW1vdGU6IFwiaHR0cHM6Ly9naXRodWIuY29tL3VtY2NyL2h0c2dldC1yc1wiLFxuICAgICAgZ2l0Rm9yY2VDbG9uZTogcHJvcHMuZ2l0Rm9yY2VDbG9uZSxcbiAgICAgIGdpdFJlZmVyZW5jZTogcHJvcHMuZ2l0UmVmZXJlbmNlLFxuICAgICAgZnVuY3Rpb25OYW1lOiBwcm9wcy5mdW5jdGlvbk5hbWUsXG4gICAgICBiaW5hcnlOYW1lOiBcImh0c2dldC1sYW1iZGFcIixcbiAgICAgIGJ1bmRsaW5nOiB7XG4gICAgICAgIGVudmlyb25tZW50OiB7XG4gICAgICAgICAgUlVTVEZMQUdTOiBcIi1DIHRhcmdldC1jcHU9bmVvdmVyc2UtbjFcIixcbiAgICAgICAgICBDQVJHT19QUk9GSUxFX1JFTEVBU0VfTFRPOiBcInRydWVcIixcbiAgICAgICAgICBDQVJHT19QUk9GSUxFX1JFTEVBU0VfQ09ERUdFTl9VTklUUzogXCIxXCIsXG4gICAgICAgICAgQVdTX0xBTUJEQV9IVFRQX0lHTk9SRV9TVEFHRV9JTl9QQVRIOiBcInRydWVcIixcbiAgICAgICAgICAuLi5wcm9wcy5idWlsZEVudmlyb25tZW50LFxuICAgICAgICB9LFxuICAgICAgICBjYXJnb0xhbWJkYUZsYWdzOiBwcm9wcy5jYXJnb0xhbWJkYUZsYWdzID8/IFtcbiAgICAgICAgICBIdHNnZXRMYW1iZGEucmVzb2x2ZUZlYXR1cmVzKFxuICAgICAgICAgICAgcHJvcHMuaHRzZ2V0Q29uZmlnLFxuICAgICAgICAgICAgcHJvcHMuY29weVRlc3REYXRhID8/IGZhbHNlLFxuICAgICAgICAgICksXG4gICAgICAgIF0sXG4gICAgICB9LFxuICAgICAgbWVtb3J5U2l6ZTogMTI4LFxuICAgICAgdGltZW91dDogRHVyYXRpb24uc2Vjb25kcygyOCksXG4gICAgICBhcmNoaXRlY3R1cmU6IEFyY2hpdGVjdHVyZS5BUk1fNjQsXG4gICAgICByb2xlOiBsYW1iZGFSb2xlID8/IHByb3BzLnJvbGUsXG4gICAgICB2cGM6IHByb3BzLnZwYyxcbiAgICB9KTtcblxuICAgIGxldCBidWNrZXQ6IEJ1Y2tldCB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcbiAgICBsZXQgcHJpdmF0ZUtleTogU2VjcmV0IHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkO1xuICAgIGxldCBwdWJsaWNLZXk6IFNlY3JldCB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcbiAgICBpZiAocHJvcHMuY29weVRlc3REYXRhKSB7XG4gICAgICBbYnVja2V0LCBwcml2YXRlS2V5LCBwdWJsaWNLZXldID0gdGhpcy5zZXR1cFRlc3REYXRhKFxuICAgICAgICBwcm9wcy5naXRSZWZlcmVuY2UsXG4gICAgICAgIHByb3BzLmJ1Y2tldE5hbWUsXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmIChsYW1iZGFSb2xlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIEh0c2dldExhbWJkYS5zZXRQZXJtaXNzaW9ucyhcbiAgICAgICAgbGFtYmRhUm9sZSxcbiAgICAgICAgcHJvcHMuaHRzZ2V0Q29uZmlnLFxuICAgICAgICBidWNrZXQsXG4gICAgICAgIHByaXZhdGVLZXksXG4gICAgICAgIHB1YmxpY0tleSxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgY29uc3QgZW52ID0gSHRzZ2V0TGFtYmRhLmNvbmZpZ1RvRW52KFxuICAgICAgcHJvcHMuaHRzZ2V0Q29uZmlnLFxuICAgICAgcHJvcHMuY29ycyxcbiAgICAgIGJ1Y2tldCxcbiAgICAgIHByaXZhdGVLZXksXG4gICAgICBwdWJsaWNLZXksXG4gICAgKTtcbiAgICBmb3IgKGNvbnN0IGtleSBpbiBlbnYpIHtcbiAgICAgIGh0c2dldExhbWJkYS5hZGRFbnZpcm9ubWVudChrZXksIGVudltrZXldKTtcbiAgICB9XG4gICAgaHRzZ2V0TGFtYmRhLmFkZEVudmlyb25tZW50KFwiUlVTVF9MT0dcIiwgXCJ0cmFjZVwiKTtcblxuICAgIGNvbnN0IGh0dHBJbnRlZ3JhdGlvbiA9IG5ldyBIdHRwTGFtYmRhSW50ZWdyYXRpb24oXG4gICAgICBcIkludGVncmF0aW9uXCIsXG4gICAgICBodHNnZXRMYW1iZGEsXG4gICAgKTtcblxuICAgIFtIdHRwTWV0aG9kLkdFVCwgSHR0cE1ldGhvZC5QT1NUXS5tYXAoKG1ldGhvZCkgPT4ge1xuICAgICAgY29uc3QgcGF0aCA9IFwiL3twcm94eSt9XCI7XG4gICAgICBuZXcgSHR0cFJvdXRlKHRoaXMsIGAke21ldGhvZH0ke3BhdGh9YCwge1xuICAgICAgICBodHRwQXBpOiBodHRwQXBpLFxuICAgICAgICByb3V0ZUtleTogSHR0cFJvdXRlS2V5LndpdGgocGF0aCwgbWV0aG9kKSxcbiAgICAgICAgaW50ZWdyYXRpb246IGh0dHBJbnRlZ3JhdGlvbixcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgaWYgKGh0dHBBcGkuZGVmYXVsdEF1dGhvcml6ZXIgPT09IHVuZGVmaW5lZCkge1xuICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICBcIlRoaXMgd2lsbCBjcmVhdGUgYW4gaW5zdGFuY2Ugb2YgaHRzZ2V0LXJzIHRoYXQgaXMgcHVibGljISBBbnlvbmUgd2lsbCBiZSBhYmxlIHRvIHF1ZXJ5IHRoZSBzZXJ2ZXIgd2l0aG91dCBhdXRob3JpemF0aW9uLlwiLFxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRGV0ZXJtaW5lIHRoZSBjb3JyZWN0IGZlYXR1cmVzIGJhc2VkIG9uIHRoZSBsb2NhdGlvbnMuXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIHJlc29sdmVGZWF0dXJlcyhcbiAgICBjb25maWc6IEh0c2dldENvbmZpZyxcbiAgICBidWNrZXRTZXR1cDogYm9vbGVhbixcbiAgKTogc3RyaW5nIHtcbiAgICBjb25zdCBmZWF0dXJlcyA9IFtdO1xuXG4gICAgaWYgKFxuICAgICAgY29uZmlnLmxvY2F0aW9ucz8uc29tZSgobG9jYXRpb24pID0+XG4gICAgICAgIGxvY2F0aW9uLmxvY2F0aW9uLnN0YXJ0c1dpdGgoXCJzMzovL1wiKSxcbiAgICAgICkgfHxcbiAgICAgIGJ1Y2tldFNldHVwXG4gICAgKSB7XG4gICAgICBmZWF0dXJlcy5wdXNoKFwiYXdzXCIpO1xuICAgIH1cbiAgICBpZiAoXG4gICAgICBjb25maWcubG9jYXRpb25zPy5zb21lKFxuICAgICAgICAobG9jYXRpb24pID0+XG4gICAgICAgICAgbG9jYXRpb24ubG9jYXRpb24uc3RhcnRzV2l0aChcImh0dHA6Ly9cIikgfHxcbiAgICAgICAgICBsb2NhdGlvbi5sb2NhdGlvbi5zdGFydHNXaXRoKFwiaHR0cHM6Ly9cIiksXG4gICAgICApXG4gICAgKSB7XG4gICAgICBmZWF0dXJlcy5wdXNoKFwidXJsXCIpO1xuICAgIH1cbiAgICBpZiAoXG4gICAgICBjb25maWcubG9jYXRpb25zPy5zb21lKFxuICAgICAgICAobG9jYXRpb24pID0+XG4gICAgICAgICAgbG9jYXRpb24ucHJpdmF0ZV9rZXkgIT09IHVuZGVmaW5lZCB8fFxuICAgICAgICAgIGxvY2F0aW9uLnB1YmxpY19rZXkgIT09IHVuZGVmaW5lZCxcbiAgICAgICkgfHxcbiAgICAgIGJ1Y2tldFNldHVwXG4gICAgKSB7XG4gICAgICBmZWF0dXJlcy5wdXNoKFwiZXhwZXJpbWVudGFsXCIpO1xuICAgIH1cblxuICAgIHJldHVybiBmZWF0dXJlcy5sZW5ndGggPT09IDBcbiAgICAgID8gXCItLWFsbC1mZWF0dXJlc1wiXG4gICAgICA6IGAtLWZlYXR1cmVzICR7ZmVhdHVyZXMuam9pbihcIixcIil9YDtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSBidWNrZXQgYW5kIGNvcHkgdGVzdCBkYXRhIGlmIGNvbmZpZ3VyZWQuXG4gICAqL1xuICBwcml2YXRlIHNldHVwVGVzdERhdGEoXG4gICAgZ2l0UmVmZXJlbmNlPzogc3RyaW5nLFxuICAgIGJ1Y2tldE5hbWU/OiBzdHJpbmcsXG4gICk6IFtCdWNrZXQsIFNlY3JldCwgU2VjcmV0XSB7XG4gICAgY29uc3QgZ2l0UmVtb3RlID0gXCJodHRwczovL2dpdGh1Yi5jb20vdW1jY3IvaHRzZ2V0LXJzXCI7XG4gICAgY29uc3QgbGF0ZXN0Q29tbWl0ID0gZXhlYyhcImdpdFwiLCBbXG4gICAgICBcImxzLXJlbW90ZVwiLFxuICAgICAgZ2l0UmVtb3RlLFxuICAgICAgZ2l0UmVmZXJlbmNlID8/IFwiSEVBRFwiLFxuICAgIF0pXG4gICAgICAuc3Rkb3V0LnRvU3RyaW5nKClcbiAgICAgIC5zcGxpdCgvKFxccyspLylbMF07XG4gICAgY29uc3QgbG9jYWxQYXRoID0gam9pbih0bXBkaXIoKSwgbGF0ZXN0Q29tbWl0KTtcblxuICAgIGNvbnN0IGJ1Y2tldCA9IG5ldyBCdWNrZXQodGhpcywgXCJCdWNrZXRcIiwge1xuICAgICAgYmxvY2tQdWJsaWNBY2Nlc3M6IEJsb2NrUHVibGljQWNjZXNzLkJMT0NLX0FMTCxcbiAgICAgIGVuY3J5cHRpb246IEJ1Y2tldEVuY3J5cHRpb24uUzNfTUFOQUdFRCxcbiAgICAgIGVuZm9yY2VTU0w6IHRydWUsXG4gICAgICByZW1vdmFsUG9saWN5OiBSZW1vdmFsUG9saWN5LlJFVEFJTixcbiAgICAgIGJ1Y2tldE5hbWUsXG4gICAgfSk7XG5cbiAgICAvLyBDb3B5IGRhdGEgZnJvbSB1cHN0cmVhbSBodHNnZXQgcmVwb1xuICAgIGNvbnN0IGxvY2FsRGF0YVBhdGggPSBwYXRoLmpvaW4obG9jYWxQYXRoLCBcImRhdGFcIik7XG4gICAgbmV3IEJ1Y2tldERlcGxveW1lbnQodGhpcywgXCJEZXBsb3lGaWxlc1wiLCB7XG4gICAgICBzb3VyY2VzOiBbXG4gICAgICAgIFNvdXJjZS5hc3NldChwYXRoLmpvaW4obG9jYWxEYXRhUGF0aCwgXCJjNGdoXCIpKSxcbiAgICAgICAgU291cmNlLmFzc2V0KHBhdGguam9pbihsb2NhbERhdGFQYXRoLCBcImJhbVwiKSksXG4gICAgICAgIFNvdXJjZS5hc3NldChwYXRoLmpvaW4obG9jYWxEYXRhUGF0aCwgXCJjcmFtXCIpKSxcbiAgICAgICAgU291cmNlLmFzc2V0KHBhdGguam9pbihsb2NhbERhdGFQYXRoLCBcInZjZlwiKSksXG4gICAgICAgIFNvdXJjZS5hc3NldChwYXRoLmpvaW4obG9jYWxEYXRhUGF0aCwgXCJiY2ZcIikpLFxuICAgICAgXSxcbiAgICAgIGRlc3RpbmF0aW9uQnVja2V0OiBidWNrZXQsXG4gICAgfSk7XG5cbiAgICBjb25zdCBrZXlEaXIgPSBwYXRoLmpvaW4obG9jYWxQYXRoLCBcImRhdGFcIiwgXCJjNGdoXCIsIFwia2V5c1wiKTtcbiAgICBjb25zdCBwcml2YXRlS2V5ID0gbmV3IFNlY3JldCh0aGlzLCBcIlByaXZhdGVLZXlcIiwge1xuICAgICAgc2VjcmV0U3RyaW5nVmFsdWU6IFNlY3JldFZhbHVlLnVuc2FmZVBsYWluVGV4dChcbiAgICAgICAgcmVhZEZpbGVTeW5jKHBhdGguam9pbihrZXlEaXIsIFwiYm9iLnNlY1wiKSkudG9TdHJpbmcoKSxcbiAgICAgICksXG4gICAgICByZW1vdmFsUG9saWN5OiBSZW1vdmFsUG9saWN5LkRFU1RST1ksXG4gICAgfSk7XG4gICAgY29uc3QgcHVibGljS2V5ID0gbmV3IFNlY3JldCh0aGlzLCBcIlB1YmxpY0tleVwiLCB7XG4gICAgICBzZWNyZXRTdHJpbmdWYWx1ZTogU2VjcmV0VmFsdWUudW5zYWZlUGxhaW5UZXh0KFxuICAgICAgICByZWFkRmlsZVN5bmMocGF0aC5qb2luKGtleURpciwgXCJhbGljZS5wdWJcIikpLnRvU3RyaW5nKCksXG4gICAgICApLFxuICAgICAgcmVtb3ZhbFBvbGljeTogUmVtb3ZhbFBvbGljeS5ERVNUUk9ZLFxuICAgIH0pO1xuXG4gICAgbmV3IENmbk91dHB1dCh0aGlzLCBcIkJ1Y2tldE5hbWVcIiwgeyB2YWx1ZTogYnVja2V0LmJ1Y2tldE5hbWUgfSk7XG5cbiAgICByZXR1cm4gW2J1Y2tldCwgcHJpdmF0ZUtleSwgcHVibGljS2V5XTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXQgcGVybWlzc2lvbnMgZm9yIHRoZSBMYW1iZGEgcm9sZS5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgc2V0UGVybWlzc2lvbnMoXG4gICAgcm9sZTogUm9sZSxcbiAgICBjb25maWc6IEh0c2dldENvbmZpZyxcbiAgICBidWNrZXQ/OiBCdWNrZXQsXG4gICAgcHJpdmF0ZUtleT86IFNlY3JldCxcbiAgICBwdWJsaWNLZXk/OiBTZWNyZXQsXG4gICkge1xuICAgIHJvbGUuYWRkTWFuYWdlZFBvbGljeShcbiAgICAgIE1hbmFnZWRQb2xpY3kuZnJvbUF3c01hbmFnZWRQb2xpY3lOYW1lKFxuICAgICAgICBcInNlcnZpY2Utcm9sZS9BV1NMYW1iZGFCYXNpY0V4ZWN1dGlvblJvbGVcIixcbiAgICAgICksXG4gICAgKTtcblxuICAgIGNvbnN0IGxvY2F0aW9ucyA9IGNvbmZpZy5sb2NhdGlvbnMgPz8gW107XG4gICAgLy8gQWRkIGFueSBcInMzOi8vXCIgbG9jYXRpb25zIHRvIHBvbGljeS5cbiAgICBjb25zdCBidWNrZXRzID0gbG9jYXRpb25zLmZsYXRNYXAoKGxvY2F0aW9uKSA9PiB7XG4gICAgICBpZiAobG9jYXRpb24ubG9jYXRpb24uc3RhcnRzV2l0aChcInMzOi8vXCIpKSB7XG4gICAgICAgIHJldHVybiBbbG9jYXRpb24ubG9jYXRpb24uc3BsaXQoXCIvXCIpWzJdXTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBbXTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICBpZiAoYnVja2V0ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGJ1Y2tldHMucHVzaChidWNrZXQuYnVja2V0TmFtZSk7XG4gICAgfVxuXG4gICAgY29uc3QgYnVja2V0UG9saWN5ID0gbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICBhY3Rpb25zOiBbXCJzMzpHZXRPYmplY3RcIl0sXG4gICAgICByZXNvdXJjZXM6IGJ1Y2tldHMubWFwKChidWNrZXQpID0+IGBhcm46YXdzOnMzOjo6JHtidWNrZXR9LypgKSxcbiAgICB9KTtcbiAgICBpZiAoYnVja2V0UG9saWN5LnJlc291cmNlcy5sZW5ndGggIT09IDApIHtcbiAgICAgIHJvbGUuYWRkVG9Qb2xpY3koYnVja2V0UG9saWN5KTtcbiAgICB9XG5cbiAgICAvLyBBZGQgYW55IGtleXMgZnJvbSB0aGUgbG9jYXRpb25zLlxuICAgIGNvbnN0IGtleXMgPSBsb2NhdGlvbnMuZmxhdE1hcCgobG9jYXRpb24pID0+IHtcbiAgICAgIGNvbnN0IGtleXM6IFtib29sZWFuLCBzdHJpbmddW10gPSBbXTtcbiAgICAgIGlmIChsb2NhdGlvbi5wcml2YXRlX2tleSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGtleXMucHVzaChbZmFsc2UsIGxvY2F0aW9uLnByaXZhdGVfa2V5XSk7XG4gICAgICB9XG4gICAgICBpZiAobG9jYXRpb24ucHVibGljX2tleSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGtleXMucHVzaChbZmFsc2UsIGxvY2F0aW9uLnB1YmxpY19rZXldKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBrZXlzO1xuICAgIH0pO1xuICAgIGlmIChwcml2YXRlS2V5ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGtleXMucHVzaChbdHJ1ZSwgcHJpdmF0ZUtleS5zZWNyZXRBcm5dKTtcbiAgICB9XG4gICAgaWYgKHB1YmxpY0tleSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBrZXlzLnB1c2goW3RydWUsIHB1YmxpY0tleS5zZWNyZXRBcm5dKTtcbiAgICB9XG5cbiAgICBjb25zdCBzZWNyZXRQb2xpY3kgPSBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgIGFjdGlvbnM6IFtcInNlY3JldHNtYW5hZ2VyOkdldFNlY3JldFZhbHVlXCJdLFxuICAgICAgcmVzb3VyY2VzOiBrZXlzLm1hcCgoW2Fybiwga2V5XSkgPT4ge1xuICAgICAgICBpZiAoYXJuKSB7XG4gICAgICAgICAgcmV0dXJuIGtleTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICByZXR1cm4gYGFybjphd3M6c2VjcmV0c21hbmFnZXI6JHtBd3MuUkVHSU9OfToke0F3cy5BQ0NPVU5UX0lEfTpzZWNyZXQ6JHtrZXl9LSpgO1xuICAgICAgICB9XG4gICAgICB9KSxcbiAgICB9KTtcbiAgICBpZiAoc2VjcmV0UG9saWN5LnJlc291cmNlcy5sZW5ndGggIT09IDApIHtcbiAgICAgIHJvbGUuYWRkVG9Qb2xpY3koc2VjcmV0UG9saWN5KTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhIGxhbWJkYSByb2xlIHdpdGggdGhlIGNvbmZpZ3VyZWQgcGVybWlzc2lvbnMuXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGNyZWF0ZVJvbGUoXG4gICAgc2NvcGU6IENvbnN0cnVjdCxcbiAgICBpZDogc3RyaW5nLFxuICAgIHJvbGVOYW1lPzogc3RyaW5nLFxuICApOiBSb2xlIHtcbiAgICByZXR1cm4gbmV3IFJvbGUoc2NvcGUsIFwiUm9sZVwiLCB7XG4gICAgICBhc3N1bWVkQnk6IG5ldyBTZXJ2aWNlUHJpbmNpcGFsKFwibGFtYmRhLmFtYXpvbmF3cy5jb21cIiksXG4gICAgICBkZXNjcmlwdGlvbjogXCJMYW1iZGEgZXhlY3V0aW9uIHJvbGUgZm9yIFwiICsgaWQsXG4gICAgICByb2xlTmFtZSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGUgc3RhdGVmdWwgY29uZmlnIHJlbGF0ZWQgdG8gdGhlIGh0dHBBcGkgYW5kIHRoZSBBUEkgaXRzZWxmLlxuICAgKi9cbiAgcHJpdmF0ZSBjcmVhdGVIdHRwQXBpKFxuICAgIGRvbWFpbjogc3RyaW5nLFxuICAgIGp3dEF1dGhvcml6ZXI/OiBKd3RDb25maWcsXG4gICAgY29uZmlnPzogQ29yc0NvbmlmZyxcbiAgICBzdWJEb21haW4/OiBzdHJpbmcsXG4gICAgaG9zdGVkWm9uZT86IElIb3N0ZWRab25lLFxuICAgIGNlcnRpZmljYXRlQXJuPzogc3RyaW5nLFxuICApOiBIdHRwQXBpIHtcbiAgICAvLyBBZGQgYW4gYXV0aG9yaXplciBpZiBhdXRoIGlzIHJlcXVpcmVkLlxuICAgIGxldCBhdXRob3JpemVyOiBIdHRwSnd0QXV0aG9yaXplciB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcbiAgICBpZiAoand0QXV0aG9yaXplciAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAvLyBJZiB0aGUgY29nIHVzZXIgcG9vbCBpZCBpcyBub3Qgc3BlY2lmaWVkLCBjcmVhdGUgYSBuZXcgb25lLlxuICAgICAgaWYgKGp3dEF1dGhvcml6ZXIuY29nVXNlclBvb2xJZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGNvbnN0IHBvb2wgPSBuZXcgVXNlclBvb2wodGhpcywgXCJVc2VyUG9vbFwiKTtcbiAgICAgICAgand0QXV0aG9yaXplci5jb2dVc2VyUG9vbElkID0gcG9vbC51c2VyUG9vbElkO1xuICAgICAgfVxuXG4gICAgICBhdXRob3JpemVyID0gbmV3IEh0dHBKd3RBdXRob3JpemVyKFxuICAgICAgICBcIkh0c2dldEF1dGhvcml6ZXJcIixcbiAgICAgICAgYGh0dHBzOi8vY29nbml0by1pZHAuJHtTdGFjay5vZih0aGlzKS5yZWdpb259LmFtYXpvbmF3cy5jb20vJHtqd3RBdXRob3JpemVyLmNvZ1VzZXJQb29sSWR9YCxcbiAgICAgICAge1xuICAgICAgICAgIGlkZW50aXR5U291cmNlOiBbXCIkcmVxdWVzdC5oZWFkZXIuQXV0aG9yaXphdGlvblwiXSxcbiAgICAgICAgICBqd3RBdWRpZW5jZTogand0QXV0aG9yaXplci5hdWRpZW5jZSA/PyBbXSxcbiAgICAgICAgfSxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgbGV0IHpvbmU6IElIb3N0ZWRab25lO1xuICAgIGlmIChob3N0ZWRab25lID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHpvbmUgPSBIb3N0ZWRab25lLmZyb21Mb29rdXAodGhpcywgXCJIb3N0ZWRab25lXCIsIHtcbiAgICAgICAgZG9tYWluTmFtZTogZG9tYWluLFxuICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHpvbmUgPSBob3N0ZWRab25lO1xuICAgIH1cblxuICAgIGNvbnN0IHVybCA9IGAke3N1YkRvbWFpbiA/PyBcImh0c2dldFwifS4ke2RvbWFpbn1gO1xuICAgIGxldCBjZXJ0aWZpY2F0ZTogSUNlcnRpZmljYXRlO1xuICAgIGlmIChjZXJ0aWZpY2F0ZUFybiAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBjZXJ0aWZpY2F0ZSA9IENlcnRpZmljYXRlLmZyb21DZXJ0aWZpY2F0ZUFybihcbiAgICAgICAgdGhpcyxcbiAgICAgICAgXCJDZXJ0aWZpY2F0ZVwiLFxuICAgICAgICBjZXJ0aWZpY2F0ZUFybixcbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNlcnRpZmljYXRlID0gbmV3IENlcnRpZmljYXRlKHRoaXMsIFwiQ2VydGlmaWNhdGVcIiwge1xuICAgICAgICBkb21haW5OYW1lOiB1cmwsXG4gICAgICAgIHZhbGlkYXRpb246IENlcnRpZmljYXRlVmFsaWRhdGlvbi5mcm9tRG5zKGhvc3RlZFpvbmUpLFxuICAgICAgICBjZXJ0aWZpY2F0ZU5hbWU6IHVybCxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGNvbnN0IGRvbWFpbk5hbWUgPSBuZXcgRG9tYWluTmFtZSh0aGlzLCBcIkRvbWFpbk5hbWVcIiwge1xuICAgICAgY2VydGlmaWNhdGU6IGNlcnRpZmljYXRlLFxuICAgICAgZG9tYWluTmFtZTogdXJsLFxuICAgIH0pO1xuXG4gICAgbmV3IEFSZWNvcmQodGhpcywgXCJBUmVjb3JkXCIsIHtcbiAgICAgIHpvbmUsXG4gICAgICByZWNvcmROYW1lOiBzdWJEb21haW4gPz8gXCJodHNnZXRcIixcbiAgICAgIHRhcmdldDogUmVjb3JkVGFyZ2V0LmZyb21BbGlhcyhcbiAgICAgICAgbmV3IEFwaUdhdGV3YXl2MkRvbWFpblByb3BlcnRpZXMoXG4gICAgICAgICAgZG9tYWluTmFtZS5yZWdpb25hbERvbWFpbk5hbWUsXG4gICAgICAgICAgZG9tYWluTmFtZS5yZWdpb25hbEhvc3RlZFpvbmVJZCxcbiAgICAgICAgKSxcbiAgICAgICksXG4gICAgfSk7XG5cbiAgICByZXR1cm4gbmV3IEh0dHBBcGkodGhpcywgXCJIdHNHZXRBcGlHYXRld2F5XCIsIHtcbiAgICAgIGRlZmF1bHRBdXRob3JpemVyOiBhdXRob3JpemVyLFxuICAgICAgZGVmYXVsdERvbWFpbk1hcHBpbmc6IHtcbiAgICAgICAgZG9tYWluTmFtZTogZG9tYWluTmFtZSxcbiAgICAgIH0sXG4gICAgICBjb3JzUHJlZmxpZ2h0OiB7XG4gICAgICAgIGFsbG93Q3JlZGVudGlhbHM6IGNvbmZpZz8uYWxsb3dDcmVkZW50aWFscyA/PyBmYWxzZSxcbiAgICAgICAgYWxsb3dIZWFkZXJzOiBjb25maWc/LmFsbG93SGVhZGVycyA/PyBbXCIqXCJdLFxuICAgICAgICBhbGxvd01ldGhvZHM6IGNvbmZpZz8uYWxsb3dNZXRob2RzID8/IFtDb3JzSHR0cE1ldGhvZC5BTlldLFxuICAgICAgICBhbGxvd09yaWdpbnM6IGNvbmZpZz8uYWxsb3dPcmlnaW5zID8/IFtcIipcIl0sXG4gICAgICAgIGV4cG9zZUhlYWRlcnM6IGNvbmZpZz8uZXhwb3NlSGVhZGVycyA/PyBbXCIqXCJdLFxuICAgICAgICBtYXhBZ2U6IGNvbmZpZz8ubWF4QWdlID8/IER1cmF0aW9uLmRheXMoMzApLFxuICAgICAgfSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb252ZXJ0IEpTT04gY29uZmlnIHRvIGh0c2dldC1ycyBlbnYgcmVwcmVzZW50YXRpb24uXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGNvbmZpZ1RvRW52KFxuICAgIGNvbmZpZzogSHRzZ2V0Q29uZmlnLFxuICAgIGNvcnNDb25maWc/OiBDb3JzQ29uaWZnLFxuICAgIGJ1Y2tldD86IEJ1Y2tldCxcbiAgICBwcml2YXRlS2V5PzogU2VjcmV0LFxuICAgIHB1YmxpY0tleT86IFNlY3JldCxcbiAgKTogUmVjb3JkPHN0cmluZywgc3RyaW5nPiB7XG4gICAgY29uc3QgdG9IdHNnZXRFbnYgPSAodmFsdWU6IHVua25vd24pID0+IHtcbiAgICAgIHJldHVybiBKU09OLnN0cmluZ2lmeSh2YWx1ZSlcbiAgICAgICAgLnJlcGxhY2VBbGwobmV3IFJlZ0V4cCgvXCIoICkqOiggKSovZyksIFwiPVwiKVxuICAgICAgICAucmVwbGFjZUFsbCgnXCInLCBcIlwiKTtcbiAgICB9O1xuXG4gICAgY29uc3Qgb3V0OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCB1bmRlZmluZWQ+ID0ge307XG4gICAgY29uc3QgbG9jYXRpb25zID0gY29uZmlnLmxvY2F0aW9ucyA/PyBbXTtcblxuICAgIGlmIChidWNrZXQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgbG9jYXRpb25zLnB1c2goe1xuICAgICAgICBsb2NhdGlvbjogYHMzOi8vJHtidWNrZXQuYnVja2V0TmFtZX1gLFxuICAgICAgICBwcml2YXRlX2tleTogcHJpdmF0ZUtleT8uc2VjcmV0QXJuLFxuICAgICAgICBwdWJsaWNfa2V5OiBwdWJsaWNLZXk/LnNlY3JldEFybixcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGxldCBsb2NhdGlvbnNFbnY6IHN0cmluZyB8IHVuZGVmaW5lZCA9IGxvY2F0aW9uc1xuICAgICAgLm1hcCgobG9jYXRpb24pID0+IHtcbiAgICAgICAgcmV0dXJuIHRvSHRzZ2V0RW52KHtcbiAgICAgICAgICBsb2NhdGlvbjogbG9jYXRpb24ubG9jYXRpb24sXG4gICAgICAgICAgLi4uKGxvY2F0aW9uLnByaXZhdGVfa2V5ICE9PSB1bmRlZmluZWQgJiZcbiAgICAgICAgICAgIGxvY2F0aW9uLnB1YmxpY19rZXkgIT09IHVuZGVmaW5lZCAmJiB7XG4gICAgICAgICAgICAgIGtleXM6IHtcbiAgICAgICAgICAgICAgICBraW5kOiBcIlNlY3JldHNNYW5hZ2VyXCIsXG4gICAgICAgICAgICAgICAgcHJpdmF0ZTogbG9jYXRpb24ucHJpdmF0ZV9rZXksXG4gICAgICAgICAgICAgICAgcHVibGljOiBsb2NhdGlvbi5wdWJsaWNfa2V5LFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSksXG4gICAgICAgIH0pO1xuICAgICAgfSlcbiAgICAgIC5qb2luKFwiLFwiKTtcbiAgICBsb2NhdGlvbnNFbnYgPSBgWyR7bG9jYXRpb25zRW52fV1gO1xuXG4gICAgaWYgKFxuICAgICAgbG9jYXRpb25zRW52ID09IFwiW11cIiAmJlxuICAgICAgY29uZmlnLmVudmlyb25tZW50X292ZXJyaWRlPy5IVFNHRVRfTE9DQVRJT05TID09PSB1bmRlZmluZWRcbiAgICApIHtcbiAgICAgIGxvY2F0aW9uc0VudiA9IHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICBvdXQuSFRTR0VUX0xPQ0FUSU9OUyA9IGxvY2F0aW9uc0VudjtcbiAgICBvdXQuSFRTR0VUX1RJQ0tFVF9TRVJWRVJfQ09SU19BTExPV19DUkVERU5USUFMUyA9XG4gICAgICBjb3JzQ29uZmlnPy5hbGxvd0NyZWRlbnRpYWxzPy50b1N0cmluZygpO1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm9uLW51bGxhYmxlLXR5cGUtYXNzZXJ0aW9uLXN0eWxlXG4gICAgb3V0LkhUU0dFVF9USUNLRVRfU0VSVkVSX0NPUlNfQUxMT1dfSEVBREVSUyA9IGBbJHtjb3JzQ29uZmlnPy5hbGxvd0hlYWRlcnM/LmpvaW4oXCIsXCIpIGFzIHN0cmluZ31dYDtcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vbi1udWxsYWJsZS10eXBlLWFzc2VydGlvbi1zdHlsZVxuICAgIG91dC5IVFNHRVRfVElDS0VUX1NFUlZFUl9DT1JTX0FMTE9XX01FVEhPRFMgPSBgWyR7Y29yc0NvbmZpZz8uYWxsb3dNZXRob2RzPy5qb2luKFwiLFwiKSBhcyBzdHJpbmd9XWA7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9ub24tbnVsbGFibGUtdHlwZS1hc3NlcnRpb24tc3R5bGVcbiAgICBvdXQuSFRTR0VUX1RJQ0tFVF9TRVJWRVJfQ09SU19BTExPV19PUklHSU5TID0gYFske2NvcnNDb25maWc/LmFsbG93T3JpZ2lucz8uam9pbihcIixcIikgYXMgc3RyaW5nfV1gO1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm9uLW51bGxhYmxlLXR5cGUtYXNzZXJ0aW9uLXN0eWxlXG4gICAgb3V0LkhUU0dFVF9USUNLRVRfU0VSVkVSX0NPUlNfRVhQT1NFX0hFQURFUlMgPSBgWyR7Y29yc0NvbmZpZz8uZXhwb3NlSGVhZGVycz8uam9pbihcIixcIikgYXMgc3RyaW5nfV1gO1xuICAgIG91dC5IVFNHRVRfVElDS0VUX1NFUlZFUl9DT1JTX01BWF9BR0UgPSBjb3JzQ29uZmlnPy5tYXhBZ2VcbiAgICAgID8udG9TZWNvbmRzKClcbiAgICAgIC50b1N0cmluZygpO1xuXG4gICAgZm9yIChjb25zdCBrZXkgaW4gY29uZmlnLnNlcnZpY2VfaW5mbykge1xuICAgICAgb3V0W2BIVFNHRVRfU0VSVklDRV9JTkZPXyR7a2V5LnRvVXBwZXJDYXNlKCl9YF0gPSB0b0h0c2dldEVudihcbiAgICAgICAgY29uZmlnLnNlcnZpY2VfaW5mb1trZXldLFxuICAgICAgKTtcbiAgICB9XG4gICAgZm9yIChjb25zdCBrZXkgaW4gY29uZmlnLmVudmlyb25tZW50X292ZXJyaWRlKSB7XG4gICAgICBvdXRba2V5XSA9IHRvSHRzZ2V0RW52KGNvbmZpZy5lbnZpcm9ubWVudF9vdmVycmlkZVtrZXldKTtcbiAgICB9XG5cbiAgICBPYmplY3Qua2V5cyhvdXQpLmZvckVhY2goXG4gICAgICAoa2V5KSA9PlxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWR5bmFtaWMtZGVsZXRlXG4gICAgICAgIChvdXRba2V5XSA9PSBgW3VuZGVmaW5lZF1gIHx8IG91dFtrZXldID09IFwiW11cIikgJiYgZGVsZXRlIG91dFtrZXldLFxuICAgICk7XG4gICAgcmV0dXJuIG91dCBhcyBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xuICB9XG59XG4iXX0=