@trautonen/cdk-dns-validated-certificate 0.1.39 → 0.1.41

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.
package/.jsii CHANGED
@@ -3465,7 +3465,7 @@
3465
3465
  "stability": "stable"
3466
3466
  },
3467
3467
  "homepage": "https://github.com/trautonen/cdk-dns-validated-certificate.git",
3468
- "jsiiVersion": "5.8.27 (build aebddcd)",
3468
+ "jsiiVersion": "5.9.32 (build ac92fbd)",
3469
3469
  "keywords": [
3470
3470
  "aws",
3471
3471
  "cdk",
@@ -3485,7 +3485,7 @@
3485
3485
  },
3486
3486
  "name": "@trautonen/cdk-dns-validated-certificate",
3487
3487
  "readme": {
3488
- "markdown": "# AWS CDK DNS Validated Certificate\n\nCDK does not have a built in construct to manage cross-region or cross-account DNS validated certificates. There's an\nattempt to work around the issue with a cross region references option for stacks, but it has a lot of issues and still\ndoes not solve the cross-account use case.\n\nThis construct solves these problems by managing the certificate as a custom resource and with direct API calls to ACM\nand Route53. In the future it will be possible to support not only Route53, but other DNS services too.\n\n## Usage for cross-region validation\n\n```typescript\n// hosted zone managed by the CDK application\nconst hostedZone: route53.IHostedZone = ...\n// no separate validation role is needed\nconst certificate = new DnsValidatedCertificate(this, 'CrossRegionCertificate', {\n hostedZone: hostedZone,\n domainName: 'example.com', // must be compatible with the hosted zone\n certificateRegion: 'us-east-1' // used by for example CloudFront\n})\n```\n\n## Usage for cross-account validation\n\n```typescript\n// external hosted zone\nconst hostedZone: route53.IHostedZone = route53.HostedZone.fromHostedZoneAttributes(this, 'HostedZone', {\n hostedZoneId: 'Z532DGDEDFS123456789',\n zoneName: 'example.com',\n})\n// validation role on the same account as the hosted zone\nconst roleArn = 'arn:aws:iam::123456789:role/ChangeDnsRecordsRole'\nconst externalId = 'domain-assume'\nconst validationRole: iam.IRole = iam.Role.fromRoleArn(this, 'ValidationRole', roleArn)\nconst certificate = new DnsValidatedCertificate(this, 'CrossAccountCertificate', {\n hostedZone: hostedZone,\n domainName: 'example.com',\n validationRole: validationRole,\n validationExternalId: externalId,\n})\n```\n\n## Usage for cross-account alternative names validation\n\n```typescript\n// example.com is validated on same account against managed hosted zone\n// and secondary.com is validated against external hosted zone on other account\nconst hostedZoneForMain: route53.IHostedZone = ...\nconst hostedZoneForAlternative: route53.IHostedZone =\n route53.HostedZone.fromHostedZoneAttributes(this, 'SecondaryHostedZone', {\n hostedZoneId: 'Z532DGDEDFS123456789',\n zoneName: 'secondary.com'\n})\nconst certificate = new DnsValidatedCertificate(this, 'CrossAccountCertificate', {\n domainName: 'example.com',\n alternativeDomainNames: ['secondary.com'],\n validationHostedZones: [{\n hostedZone: hostedZoneForMain\n },{\n hostedZone: hostedZoneForAlternative,\n validationRole: iam.Role.fromRoleArn(\n this, 'SecondaryValidationRole', 'arn:aws:iam::123456789:role/ChangeDnsRecordsRole'\n ),\n validationExternalId: 'domain-assume'\n }]\n})\n```\n"
3488
+ "markdown": "# @trautonen/cdk-dns-validated-certificate\n\n[![npm version](https://img.shields.io/npm/v/@trautonen/cdk-dns-validated-certificate.svg)](https://www.npmjs.com/package/@trautonen/cdk-dns-validated-certificate)\n[![npm downloads](https://img.shields.io/npm/dm/@trautonen/cdk-dns-validated-certificate.svg)](https://www.npmjs.com/package/@trautonen/cdk-dns-validated-certificate)\n[![license](https://img.shields.io/npm/l/@trautonen/cdk-dns-validated-certificate.svg)](https://github.com/trautonen/cdk-dns-validated-certificate/blob/main/LICENSE)\n[![release](https://github.com/trautonen/cdk-dns-validated-certificate/actions/workflows/release.yml/badge.svg)](https://github.com/trautonen/cdk-dns-validated-certificate/actions/workflows/release.yml)\n\nAn AWS CDK construct for creating DNS-validated ACM certificates with **cross-region** and **cross-account** support.\n\nThe built-in CDK `Certificate` construct does not support cross-region or cross-account DNS validation. The cross-region references workaround has known issues and still does not cover cross-account use cases. This construct solves both problems by managing the full certificate lifecycle — request, DNS validation, and cleanup — through a Lambda-backed custom resource with direct API calls to ACM and Route 53.\n\n## Features\n\n- **Cross-region certificates** — provision a certificate in `us-east-1` for CloudFront while your stack is in any other region\n- **Cross-account validation** — validate against a Route 53 hosted zone in a different AWS account using IAM role assumption\n- **Multiple hosted zones** — validate a primary domain and alternative names against different hosted zones, each with its own credentials\n- **Automatic DNS record management** — creates and cleans up CNAME validation records automatically\n- **Certificate Transparency logging** — configurable CT logging\n- **Tagging support** — tag your certificates via CDK's standard tagging mechanism\n- **Configurable removal policy** — retain certificates on stack deletion if needed\n\n## Installation\n\n```bash\n# npm\nnpm install @trautonen/cdk-dns-validated-certificate\n\n# yarn\nyarn add @trautonen/cdk-dns-validated-certificate\n\n# pnpm\npnpm add @trautonen/cdk-dns-validated-certificate\n\n# bun\nbun add @trautonen/cdk-dns-validated-certificate\n```\n\n### Peer Dependencies\n\nThis construct requires the following peer dependencies:\n\n| Package | Version |\n|---|---|\n| `aws-cdk-lib` | `>= 2.83.1` |\n| `constructs` | `>= 10.5.1` |\n\n## Quick Start\n\n```typescript\nimport { DnsValidatedCertificate } from '@trautonen/cdk-dns-validated-certificate';\nimport * as route53 from 'aws-cdk-lib/aws-route53';\n\nconst hostedZone = route53.HostedZone.fromLookup(this, 'HostedZone', {\n domainName: 'example.com',\n});\n\nconst certificate = new DnsValidatedCertificate(this, 'Certificate', {\n domainName: 'example.com',\n validationHostedZones: [{\n hostedZone,\n }],\n});\n```\n\n## Usage\n\n### Cross-Region Certificate\n\nA common scenario is provisioning a certificate in `us-east-1` for CloudFront while the CDK stack deploys to another region. Use the `certificateRegion` property to specify where the certificate should be created.\n\n```typescript\nimport { DnsValidatedCertificate } from '@trautonen/cdk-dns-validated-certificate';\nimport * as route53 from 'aws-cdk-lib/aws-route53';\nimport * as cloudfront from 'aws-cdk-lib/aws-cloudfront';\nimport * as origins from 'aws-cdk-lib/aws-cloudfront-origins';\nimport * as s3 from 'aws-cdk-lib/aws-s3';\n\nconst myBucket = new s3.Bucket(this, 'WebsiteBucket');\n\nconst hostedZone = route53.HostedZone.fromLookup(this, 'HostedZone', {\n domainName: 'example.com',\n});\n\n// Create the certificate in us-east-1 regardless of the stack's region\nconst certificate = new DnsValidatedCertificate(this, 'Certificate', {\n domainName: 'example.com',\n certificateRegion: 'us-east-1',\n validationHostedZones: [{\n hostedZone,\n }],\n});\n\n// Use with a CloudFront distribution\nconst distribution = new cloudfront.Distribution(this, 'Distribution', {\n domainNames: ['example.com'],\n certificate,\n defaultBehavior: {\n origin: new origins.S3Origin(myBucket),\n },\n});\n```\n\n### Cross-Account Validation\n\nWhen the Route 53 hosted zone is in a different AWS account, provide an IAM role that the construct can assume to create DNS validation records in the target account. Optionally, use an external ID for additional security.\n\n```typescript\nimport { DnsValidatedCertificate } from '@trautonen/cdk-dns-validated-certificate';\nimport * as route53 from 'aws-cdk-lib/aws-route53';\nimport * as iam from 'aws-cdk-lib/aws-iam';\n\n// Reference the hosted zone in the other account\nconst hostedZone = route53.HostedZone.fromHostedZoneAttributes(this, 'HostedZone', {\n hostedZoneId: 'Z0123456789ABCDEFGHIJ',\n zoneName: 'example.com',\n});\n\n// IAM role in the DNS account that permits Route 53 changes\nconst validationRole = iam.Role.fromRoleArn(\n this, 'ValidationRole',\n 'arn:aws:iam::111111111111:role/DnsValidationRole',\n);\n\nconst certificate = new DnsValidatedCertificate(this, 'Certificate', {\n domainName: 'example.com',\n validationHostedZones: [{\n hostedZone,\n validationRole,\n validationExternalId: 'my-external-id', // optional\n }],\n});\n```\n\n> **Note:** The role in the DNS account must trust the account running the CDK stack and have permissions to call `route53:ChangeResourceRecordSets` and `route53:GetChange`.\n\n### Multiple Hosted Zones with Alternative Names\n\nValidate a primary domain and subject alternative names (SANs) against different hosted zones, each with independent credentials. This is useful when your primary domain and alternative domains are managed in separate AWS accounts.\n\n```typescript\nimport { DnsValidatedCertificate } from '@trautonen/cdk-dns-validated-certificate';\nimport * as route53 from 'aws-cdk-lib/aws-route53';\nimport * as iam from 'aws-cdk-lib/aws-iam';\n\n// Primary domain — hosted zone in the current account\nconst primaryZone = route53.HostedZone.fromLookup(this, 'PrimaryZone', {\n domainName: 'example.com',\n});\n\n// Alternative domain — hosted zone in a different account\nconst secondaryZone = route53.HostedZone.fromHostedZoneAttributes(this, 'SecondaryZone', {\n hostedZoneId: 'Z0123456789ABCDEFGHIJ',\n zoneName: 'example.org',\n});\n\nconst certificate = new DnsValidatedCertificate(this, 'Certificate', {\n domainName: 'example.com',\n alternativeDomainNames: ['example.org'],\n certificateRegion: 'us-east-1',\n validationHostedZones: [{\n hostedZone: primaryZone,\n // No role needed — same account\n }, {\n hostedZone: secondaryZone,\n validationRole: iam.Role.fromRoleArn(\n this, 'SecondaryValidationRole',\n 'arn:aws:iam::222222222222:role/DnsValidationRole',\n ),\n validationExternalId: 'secondary-external-id',\n }],\n});\n```\n\n### Wildcard Certificate\n\nRequest a wildcard certificate that covers both the apex and all subdomains.\n\n```typescript\nimport { DnsValidatedCertificate } from '@trautonen/cdk-dns-validated-certificate';\nimport * as route53 from 'aws-cdk-lib/aws-route53';\n\nconst hostedZone = route53.HostedZone.fromLookup(this, 'HostedZone', {\n domainName: 'example.com',\n});\n\nconst certificate = new DnsValidatedCertificate(this, 'WildcardCertificate', {\n domainName: 'example.com',\n alternativeDomainNames: ['*.example.com'],\n validationHostedZones: [{\n hostedZone,\n }],\n});\n```\n\n### Configuring Removal Policy\n\nBy default, certificates are destroyed when the stack is deleted. Set a removal policy to retain the certificate instead.\n\n```typescript\nimport { DnsValidatedCertificate } from '@trautonen/cdk-dns-validated-certificate';\nimport * as cdk from 'aws-cdk-lib';\nimport * as route53 from 'aws-cdk-lib/aws-route53';\n\nconst hostedZone = route53.HostedZone.fromLookup(this, 'HostedZone', {\n domainName: 'example.com',\n});\n\nconst certificate = new DnsValidatedCertificate(this, 'Certificate', {\n domainName: 'example.com',\n validationHostedZones: [{ hostedZone }],\n removalPolicy: cdk.RemovalPolicy.RETAIN,\n});\n```\n\n### Disabling DNS Record Cleanup\n\nBy default, validation CNAME records are removed when the certificate is deleted. To keep them in DNS (useful for faster re-provisioning), set `cleanupValidationRecords` to `false`.\n\n```typescript\nimport { DnsValidatedCertificate } from '@trautonen/cdk-dns-validated-certificate';\nimport * as route53 from 'aws-cdk-lib/aws-route53';\n\nconst hostedZone = route53.HostedZone.fromLookup(this, 'HostedZone', {\n domainName: 'example.com',\n});\n\nconst certificate = new DnsValidatedCertificate(this, 'Certificate', {\n domainName: 'example.com',\n validationHostedZones: [{ hostedZone }],\n cleanupValidationRecords: false,\n});\n```\n\n### Using a Custom Lambda Execution Role\n\nProvide your own IAM role for the Lambda function that manages the certificate lifecycle. This is useful when you need fine-grained control over permissions or want to use a shared role.\n\n```typescript\nimport { DnsValidatedCertificate } from '@trautonen/cdk-dns-validated-certificate';\nimport * as iam from 'aws-cdk-lib/aws-iam';\nimport * as route53 from 'aws-cdk-lib/aws-route53';\n\nconst hostedZone = route53.HostedZone.fromLookup(this, 'HostedZone', {\n domainName: 'example.com',\n});\n\nconst lambdaRole = new iam.Role(this, 'CertificateLambdaRole', {\n assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),\n managedPolicies: [\n iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole'),\n ],\n});\n\nconst certificate = new DnsValidatedCertificate(this, 'Certificate', {\n domainName: 'example.com',\n validationHostedZones: [{ hostedZone }],\n customResourceRole: lambdaRole,\n});\n```\n\n## API Reference\n\n### `DnsValidatedCertificate`\n\n| Property | Type | Description |\n|---|---|---|\n| `certificateArn` | `string` | The ARN of the certificate |\n| `certificateRegion` | `string` | The region the certificate is deployed to |\n| `tags` | `TagManager` | Tag manager for the certificate |\n\n### `DnsValidatedCertificateProps`\n\n| Property | Type | Required | Default | Description |\n|---|---|---|---|---|\n| `domainName` | `string` | Yes | — | Fully qualified domain name. May contain a wildcard (`*.example.com`). |\n| `validationHostedZones` | `ValidationHostedZone[]` | Yes | — | Route 53 hosted zones to use for DNS validation. |\n| `alternativeDomainNames` | `string[]` | No | — | Subject Alternative Names (SANs) for the certificate. |\n| `certificateRegion` | `string` | No | Stack region | Region for the certificate (e.g. `us-east-1` for CloudFront). |\n| `customResourceRole` | `IRole` | No | Auto-created | IAM role for the Lambda custom resource. |\n| `cleanupValidationRecords` | `boolean` | No | `true` | Remove DNS validation records on certificate deletion. |\n| `transparencyLoggingEnabled` | `boolean` | No | `true` | Enable Certificate Transparency logging. |\n| `removalPolicy` | `RemovalPolicy` | No | `DESTROY` | What to do with the certificate when the stack is deleted. |\n\n### `ValidationHostedZone`\n\n| Property | Type | Required | Default | Description |\n|---|---|---|---|---|\n| `hostedZone` | `IHostedZone` | Yes | — | The Route 53 hosted zone for DNS validation. |\n| `validationRole` | `IRole` | No | — | IAM role to assume for cross-account DNS changes. |\n| `validationExternalId` | `string` | No | — | External ID for the role assumption. |\n\nFor the full API reference, see [API.md](API.md).\n\n## How It Works\n\nThe construct deploys a Lambda function (Node.js 22.x, ARM64) as a CloudFormation custom resource that:\n\n1. **Requests** a DNS-validated certificate from ACM\n2. **Creates** CNAME validation records in the specified Route 53 hosted zones (assuming cross-account roles when needed)\n3. **Waits** for ACM to validate the certificate\n4. **Applies** tags to the certificate\n5. **Cleans up** validation records and deletes the certificate on stack removal\n\nThe Lambda function handles the full lifecycle including updates (detecting when a new certificate is needed vs. a tag-only update) and graceful deletion (waiting for the certificate to stop being in-use before deleting).\n\n## License\n\n[Apache-2.0](LICENSE)\n"
3489
3489
  },
3490
3490
  "repository": {
3491
3491
  "type": "git",
@@ -3921,6 +3921,6 @@
3921
3921
  "symbolId": "src/dns-validated-certificate:ValidationHostedZone"
3922
3922
  }
3923
3923
  },
3924
- "version": "0.1.39",
3925
- "fingerprint": "QOILIWNqo2DTd8LzGwmqSEaGj1Sytl7rzwzK/GS+Hh4="
3924
+ "version": "0.1.41",
3925
+ "fingerprint": "8UKvOSI61xK0XIkClXpyOghMN/QKKHrwwCNIKmQAtRk="
3926
3926
  }
package/README.md CHANGED
@@ -1,67 +1,308 @@
1
- # AWS CDK DNS Validated Certificate
1
+ # @trautonen/cdk-dns-validated-certificate
2
2
 
3
- CDK does not have a built in construct to manage cross-region or cross-account DNS validated certificates. There's an
4
- attempt to work around the issue with a cross region references option for stacks, but it has a lot of issues and still
5
- does not solve the cross-account use case.
3
+ [![npm version](https://img.shields.io/npm/v/@trautonen/cdk-dns-validated-certificate.svg)](https://www.npmjs.com/package/@trautonen/cdk-dns-validated-certificate)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@trautonen/cdk-dns-validated-certificate.svg)](https://www.npmjs.com/package/@trautonen/cdk-dns-validated-certificate)
5
+ [![license](https://img.shields.io/npm/l/@trautonen/cdk-dns-validated-certificate.svg)](https://github.com/trautonen/cdk-dns-validated-certificate/blob/main/LICENSE)
6
+ [![release](https://github.com/trautonen/cdk-dns-validated-certificate/actions/workflows/release.yml/badge.svg)](https://github.com/trautonen/cdk-dns-validated-certificate/actions/workflows/release.yml)
6
7
 
7
- This construct solves these problems by managing the certificate as a custom resource and with direct API calls to ACM
8
- and Route53. In the future it will be possible to support not only Route53, but other DNS services too.
8
+ An AWS CDK construct for creating DNS-validated ACM certificates with **cross-region** and **cross-account** support.
9
9
 
10
- ## Usage for cross-region validation
10
+ The built-in CDK `Certificate` construct does not support cross-region or cross-account DNS validation. The cross-region references workaround has known issues and still does not cover cross-account use cases. This construct solves both problems by managing the full certificate lifecycle — request, DNS validation, and cleanup — through a Lambda-backed custom resource with direct API calls to ACM and Route 53.
11
+
12
+ ## Features
13
+
14
+ - **Cross-region certificates** — provision a certificate in `us-east-1` for CloudFront while your stack is in any other region
15
+ - **Cross-account validation** — validate against a Route 53 hosted zone in a different AWS account using IAM role assumption
16
+ - **Multiple hosted zones** — validate a primary domain and alternative names against different hosted zones, each with its own credentials
17
+ - **Automatic DNS record management** — creates and cleans up CNAME validation records automatically
18
+ - **Certificate Transparency logging** — configurable CT logging
19
+ - **Tagging support** — tag your certificates via CDK's standard tagging mechanism
20
+ - **Configurable removal policy** — retain certificates on stack deletion if needed
21
+
22
+ ## Installation
23
+
24
+ ```bash
25
+ # npm
26
+ npm install @trautonen/cdk-dns-validated-certificate
27
+
28
+ # yarn
29
+ yarn add @trautonen/cdk-dns-validated-certificate
30
+
31
+ # pnpm
32
+ pnpm add @trautonen/cdk-dns-validated-certificate
33
+
34
+ # bun
35
+ bun add @trautonen/cdk-dns-validated-certificate
36
+ ```
37
+
38
+ ### Peer Dependencies
39
+
40
+ This construct requires the following peer dependencies:
41
+
42
+ | Package | Version |
43
+ |---|---|
44
+ | `aws-cdk-lib` | `>= 2.83.1` |
45
+ | `constructs` | `>= 10.5.1` |
46
+
47
+ ## Quick Start
11
48
 
12
49
  ```typescript
13
- // hosted zone managed by the CDK application
14
- const hostedZone: route53.IHostedZone = ...
15
- // no separate validation role is needed
16
- const certificate = new DnsValidatedCertificate(this, 'CrossRegionCertificate', {
17
- hostedZone: hostedZone,
18
- domainName: 'example.com', // must be compatible with the hosted zone
19
- certificateRegion: 'us-east-1' // used by for example CloudFront
20
- })
50
+ import { DnsValidatedCertificate } from '@trautonen/cdk-dns-validated-certificate';
51
+ import * as route53 from 'aws-cdk-lib/aws-route53';
52
+
53
+ const hostedZone = route53.HostedZone.fromLookup(this, 'HostedZone', {
54
+ domainName: 'example.com',
55
+ });
56
+
57
+ const certificate = new DnsValidatedCertificate(this, 'Certificate', {
58
+ domainName: 'example.com',
59
+ validationHostedZones: [{
60
+ hostedZone,
61
+ }],
62
+ });
21
63
  ```
22
64
 
23
- ## Usage for cross-account validation
65
+ ## Usage
66
+
67
+ ### Cross-Region Certificate
68
+
69
+ A common scenario is provisioning a certificate in `us-east-1` for CloudFront while the CDK stack deploys to another region. Use the `certificateRegion` property to specify where the certificate should be created.
24
70
 
25
71
  ```typescript
26
- // external hosted zone
27
- const hostedZone: route53.IHostedZone = route53.HostedZone.fromHostedZoneAttributes(this, 'HostedZone', {
28
- hostedZoneId: 'Z532DGDEDFS123456789',
72
+ import { DnsValidatedCertificate } from '@trautonen/cdk-dns-validated-certificate';
73
+ import * as route53 from 'aws-cdk-lib/aws-route53';
74
+ import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
75
+ import * as origins from 'aws-cdk-lib/aws-cloudfront-origins';
76
+ import * as s3 from 'aws-cdk-lib/aws-s3';
77
+
78
+ const myBucket = new s3.Bucket(this, 'WebsiteBucket');
79
+
80
+ const hostedZone = route53.HostedZone.fromLookup(this, 'HostedZone', {
81
+ domainName: 'example.com',
82
+ });
83
+
84
+ // Create the certificate in us-east-1 regardless of the stack's region
85
+ const certificate = new DnsValidatedCertificate(this, 'Certificate', {
86
+ domainName: 'example.com',
87
+ certificateRegion: 'us-east-1',
88
+ validationHostedZones: [{
89
+ hostedZone,
90
+ }],
91
+ });
92
+
93
+ // Use with a CloudFront distribution
94
+ const distribution = new cloudfront.Distribution(this, 'Distribution', {
95
+ domainNames: ['example.com'],
96
+ certificate,
97
+ defaultBehavior: {
98
+ origin: new origins.S3Origin(myBucket),
99
+ },
100
+ });
101
+ ```
102
+
103
+ ### Cross-Account Validation
104
+
105
+ When the Route 53 hosted zone is in a different AWS account, provide an IAM role that the construct can assume to create DNS validation records in the target account. Optionally, use an external ID for additional security.
106
+
107
+ ```typescript
108
+ import { DnsValidatedCertificate } from '@trautonen/cdk-dns-validated-certificate';
109
+ import * as route53 from 'aws-cdk-lib/aws-route53';
110
+ import * as iam from 'aws-cdk-lib/aws-iam';
111
+
112
+ // Reference the hosted zone in the other account
113
+ const hostedZone = route53.HostedZone.fromHostedZoneAttributes(this, 'HostedZone', {
114
+ hostedZoneId: 'Z0123456789ABCDEFGHIJ',
29
115
  zoneName: 'example.com',
30
- })
31
- // validation role on the same account as the hosted zone
32
- const roleArn = 'arn:aws:iam::123456789:role/ChangeDnsRecordsRole'
33
- const externalId = 'domain-assume'
34
- const validationRole: iam.IRole = iam.Role.fromRoleArn(this, 'ValidationRole', roleArn)
35
- const certificate = new DnsValidatedCertificate(this, 'CrossAccountCertificate', {
36
- hostedZone: hostedZone,
116
+ });
117
+
118
+ // IAM role in the DNS account that permits Route 53 changes
119
+ const validationRole = iam.Role.fromRoleArn(
120
+ this, 'ValidationRole',
121
+ 'arn:aws:iam::111111111111:role/DnsValidationRole',
122
+ );
123
+
124
+ const certificate = new DnsValidatedCertificate(this, 'Certificate', {
37
125
  domainName: 'example.com',
38
- validationRole: validationRole,
39
- validationExternalId: externalId,
40
- })
126
+ validationHostedZones: [{
127
+ hostedZone,
128
+ validationRole,
129
+ validationExternalId: 'my-external-id', // optional
130
+ }],
131
+ });
41
132
  ```
42
133
 
43
- ## Usage for cross-account alternative names validation
134
+ > **Note:** The role in the DNS account must trust the account running the CDK stack and have permissions to call `route53:ChangeResourceRecordSets` and `route53:GetChange`.
135
+
136
+ ### Multiple Hosted Zones with Alternative Names
137
+
138
+ Validate a primary domain and subject alternative names (SANs) against different hosted zones, each with independent credentials. This is useful when your primary domain and alternative domains are managed in separate AWS accounts.
44
139
 
45
140
  ```typescript
46
- // example.com is validated on same account against managed hosted zone
47
- // and secondary.com is validated against external hosted zone on other account
48
- const hostedZoneForMain: route53.IHostedZone = ...
49
- const hostedZoneForAlternative: route53.IHostedZone =
50
- route53.HostedZone.fromHostedZoneAttributes(this, 'SecondaryHostedZone', {
51
- hostedZoneId: 'Z532DGDEDFS123456789',
52
- zoneName: 'secondary.com'
53
- })
54
- const certificate = new DnsValidatedCertificate(this, 'CrossAccountCertificate', {
141
+ import { DnsValidatedCertificate } from '@trautonen/cdk-dns-validated-certificate';
142
+ import * as route53 from 'aws-cdk-lib/aws-route53';
143
+ import * as iam from 'aws-cdk-lib/aws-iam';
144
+
145
+ // Primary domain — hosted zone in the current account
146
+ const primaryZone = route53.HostedZone.fromLookup(this, 'PrimaryZone', {
147
+ domainName: 'example.com',
148
+ });
149
+
150
+ // Alternative domain — hosted zone in a different account
151
+ const secondaryZone = route53.HostedZone.fromHostedZoneAttributes(this, 'SecondaryZone', {
152
+ hostedZoneId: 'Z0123456789ABCDEFGHIJ',
153
+ zoneName: 'example.org',
154
+ });
155
+
156
+ const certificate = new DnsValidatedCertificate(this, 'Certificate', {
55
157
  domainName: 'example.com',
56
- alternativeDomainNames: ['secondary.com'],
158
+ alternativeDomainNames: ['example.org'],
159
+ certificateRegion: 'us-east-1',
57
160
  validationHostedZones: [{
58
- hostedZone: hostedZoneForMain
59
- },{
60
- hostedZone: hostedZoneForAlternative,
161
+ hostedZone: primaryZone,
162
+ // No role needed — same account
163
+ }, {
164
+ hostedZone: secondaryZone,
61
165
  validationRole: iam.Role.fromRoleArn(
62
- this, 'SecondaryValidationRole', 'arn:aws:iam::123456789:role/ChangeDnsRecordsRole'
166
+ this, 'SecondaryValidationRole',
167
+ 'arn:aws:iam::222222222222:role/DnsValidationRole',
63
168
  ),
64
- validationExternalId: 'domain-assume'
65
- }]
66
- })
169
+ validationExternalId: 'secondary-external-id',
170
+ }],
171
+ });
67
172
  ```
173
+
174
+ ### Wildcard Certificate
175
+
176
+ Request a wildcard certificate that covers both the apex and all subdomains.
177
+
178
+ ```typescript
179
+ import { DnsValidatedCertificate } from '@trautonen/cdk-dns-validated-certificate';
180
+ import * as route53 from 'aws-cdk-lib/aws-route53';
181
+
182
+ const hostedZone = route53.HostedZone.fromLookup(this, 'HostedZone', {
183
+ domainName: 'example.com',
184
+ });
185
+
186
+ const certificate = new DnsValidatedCertificate(this, 'WildcardCertificate', {
187
+ domainName: 'example.com',
188
+ alternativeDomainNames: ['*.example.com'],
189
+ validationHostedZones: [{
190
+ hostedZone,
191
+ }],
192
+ });
193
+ ```
194
+
195
+ ### Configuring Removal Policy
196
+
197
+ By default, certificates are destroyed when the stack is deleted. Set a removal policy to retain the certificate instead.
198
+
199
+ ```typescript
200
+ import { DnsValidatedCertificate } from '@trautonen/cdk-dns-validated-certificate';
201
+ import * as cdk from 'aws-cdk-lib';
202
+ import * as route53 from 'aws-cdk-lib/aws-route53';
203
+
204
+ const hostedZone = route53.HostedZone.fromLookup(this, 'HostedZone', {
205
+ domainName: 'example.com',
206
+ });
207
+
208
+ const certificate = new DnsValidatedCertificate(this, 'Certificate', {
209
+ domainName: 'example.com',
210
+ validationHostedZones: [{ hostedZone }],
211
+ removalPolicy: cdk.RemovalPolicy.RETAIN,
212
+ });
213
+ ```
214
+
215
+ ### Disabling DNS Record Cleanup
216
+
217
+ By default, validation CNAME records are removed when the certificate is deleted. To keep them in DNS (useful for faster re-provisioning), set `cleanupValidationRecords` to `false`.
218
+
219
+ ```typescript
220
+ import { DnsValidatedCertificate } from '@trautonen/cdk-dns-validated-certificate';
221
+ import * as route53 from 'aws-cdk-lib/aws-route53';
222
+
223
+ const hostedZone = route53.HostedZone.fromLookup(this, 'HostedZone', {
224
+ domainName: 'example.com',
225
+ });
226
+
227
+ const certificate = new DnsValidatedCertificate(this, 'Certificate', {
228
+ domainName: 'example.com',
229
+ validationHostedZones: [{ hostedZone }],
230
+ cleanupValidationRecords: false,
231
+ });
232
+ ```
233
+
234
+ ### Using a Custom Lambda Execution Role
235
+
236
+ Provide your own IAM role for the Lambda function that manages the certificate lifecycle. This is useful when you need fine-grained control over permissions or want to use a shared role.
237
+
238
+ ```typescript
239
+ import { DnsValidatedCertificate } from '@trautonen/cdk-dns-validated-certificate';
240
+ import * as iam from 'aws-cdk-lib/aws-iam';
241
+ import * as route53 from 'aws-cdk-lib/aws-route53';
242
+
243
+ const hostedZone = route53.HostedZone.fromLookup(this, 'HostedZone', {
244
+ domainName: 'example.com',
245
+ });
246
+
247
+ const lambdaRole = new iam.Role(this, 'CertificateLambdaRole', {
248
+ assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
249
+ managedPolicies: [
250
+ iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole'),
251
+ ],
252
+ });
253
+
254
+ const certificate = new DnsValidatedCertificate(this, 'Certificate', {
255
+ domainName: 'example.com',
256
+ validationHostedZones: [{ hostedZone }],
257
+ customResourceRole: lambdaRole,
258
+ });
259
+ ```
260
+
261
+ ## API Reference
262
+
263
+ ### `DnsValidatedCertificate`
264
+
265
+ | Property | Type | Description |
266
+ |---|---|---|
267
+ | `certificateArn` | `string` | The ARN of the certificate |
268
+ | `certificateRegion` | `string` | The region the certificate is deployed to |
269
+ | `tags` | `TagManager` | Tag manager for the certificate |
270
+
271
+ ### `DnsValidatedCertificateProps`
272
+
273
+ | Property | Type | Required | Default | Description |
274
+ |---|---|---|---|---|
275
+ | `domainName` | `string` | Yes | — | Fully qualified domain name. May contain a wildcard (`*.example.com`). |
276
+ | `validationHostedZones` | `ValidationHostedZone[]` | Yes | — | Route 53 hosted zones to use for DNS validation. |
277
+ | `alternativeDomainNames` | `string[]` | No | — | Subject Alternative Names (SANs) for the certificate. |
278
+ | `certificateRegion` | `string` | No | Stack region | Region for the certificate (e.g. `us-east-1` for CloudFront). |
279
+ | `customResourceRole` | `IRole` | No | Auto-created | IAM role for the Lambda custom resource. |
280
+ | `cleanupValidationRecords` | `boolean` | No | `true` | Remove DNS validation records on certificate deletion. |
281
+ | `transparencyLoggingEnabled` | `boolean` | No | `true` | Enable Certificate Transparency logging. |
282
+ | `removalPolicy` | `RemovalPolicy` | No | `DESTROY` | What to do with the certificate when the stack is deleted. |
283
+
284
+ ### `ValidationHostedZone`
285
+
286
+ | Property | Type | Required | Default | Description |
287
+ |---|---|---|---|---|
288
+ | `hostedZone` | `IHostedZone` | Yes | — | The Route 53 hosted zone for DNS validation. |
289
+ | `validationRole` | `IRole` | No | — | IAM role to assume for cross-account DNS changes. |
290
+ | `validationExternalId` | `string` | No | — | External ID for the role assumption. |
291
+
292
+ For the full API reference, see [API.md](API.md).
293
+
294
+ ## How It Works
295
+
296
+ The construct deploys a Lambda function (Node.js 22.x, ARM64) as a CloudFormation custom resource that:
297
+
298
+ 1. **Requests** a DNS-validated certificate from ACM
299
+ 2. **Creates** CNAME validation records in the specified Route 53 hosted zones (assuming cross-account roles when needed)
300
+ 3. **Waits** for ACM to validate the certificate
301
+ 4. **Applies** tags to the certificate
302
+ 5. **Cleans up** validation records and deletes the certificate on stack removal
303
+
304
+ The Lambda function handles the full lifecycle including updates (detecting when a new certificate is needed vs. a tag-only update) and graceful deletion (waiting for the certificate to stop being in-use before deleting).
305
+
306
+ ## License
307
+
308
+ [Apache-2.0](LICENSE)
@@ -243,5 +243,5 @@ class DnsValidatedCertificate extends cdk.Resource {
243
243
  }
244
244
  exports.DnsValidatedCertificate = DnsValidatedCertificate;
245
245
  _a = JSII_RTTI_SYMBOL_1;
246
- DnsValidatedCertificate[_a] = { fqn: "@trautonen/cdk-dns-validated-certificate.DnsValidatedCertificate", version: "0.1.39" };
246
+ DnsValidatedCertificate[_a] = { fqn: "@trautonen/cdk-dns-validated-certificate.DnsValidatedCertificate", version: "0.1.41" };
247
247
  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZG5zLXZhbGlkYXRlZC1jZXJ0aWZpY2F0ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9kbnMtdmFsaWRhdGVkLWNlcnRpZmljYXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsbUNBQWtDO0FBRWxDLHlEQUF3RDtBQUN4RCwyQ0FBMEM7QUFDMUMsaURBQWdEO0FBRWhELGlFQUFnRTtBQUVoRSxxRkFBK0U7QUFFL0UsbUNBQWdHO0FBaUhoRyxNQUFNLDhCQUE4QixHQUFHLGlDQUFpQyxDQUFBO0FBQ3hFLE1BQU0sMEJBQTBCLEdBQUcsc0NBQXNDLENBQUE7QUFFekU7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBaUVHO0FBQ0gsTUFBYSx1QkFBd0IsU0FBUSxHQUFHLENBQUMsUUFBUTtJQWF2RDs7Ozs7O09BTUc7SUFDSCxZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLEtBQW1DO1FBQzNFLEtBQUssQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUE7UUFFaEIsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLG1CQUFtQixDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQTtRQUM3RCxNQUFNLHNCQUFzQixHQUFHLEtBQUssQ0FBQyxzQkFBc0IsRUFBRSxHQUFHLENBQUMsQ0FBQyxxQkFBcUIsRUFBRSxFQUFFLENBQ3pGLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxxQkFBcUIsQ0FBQyxDQUNoRCxDQUFBO1FBQ0QsTUFBTSxVQUFVLEdBQUcsQ0FBQyxVQUFVLEVBQUUsR0FBRyxDQUFDLHNCQUFzQixJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUE7UUFFbEUsSUFBSSxDQUFDLGlCQUFpQixHQUFHLEtBQUssQ0FBQyxpQkFBaUIsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQTtRQUNyRSxJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksR0FBRyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSwwQkFBMEIsQ0FBQyxDQUFBO1FBQzNFLElBQUksQ0FBQyxhQUFhLEdBQUcsS0FBSyxDQUFDLGFBQWEsSUFBSSxHQUFHLENBQUMsYUFBYSxDQUFDLE9BQU8sQ0FBQTtRQUVyRSxNQUFNLGlCQUFpQixHQUFHLElBQUksNkRBQTRCLENBQUMsSUFBSSxFQUFFLG1CQUFtQixFQUFFO1lBQ3BGLFlBQVksRUFBRSxNQUFNLENBQUMsWUFBWSxDQUFDLE1BQU07WUFDeEMsT0FBTyxFQUFFLEdBQUcsQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUNqQyxJQUFJLEVBQUUsS0FBSyxDQUFDLGtCQUFrQjtTQUMvQixDQUFDLENBQUE7UUFFRixpQkFBaUIsQ0FBQyxlQUFlLENBQy9CLElBQUksR0FBRyxDQUFDLGVBQWUsQ0FBQztZQUN0QixNQUFNLEVBQUUsR0FBRyxDQUFDLE1BQU0sQ0FBQyxLQUFLO1lBQ3hCLE9BQU8sRUFBRTtnQkFDUCx3QkFBd0I7Z0JBQ3hCLHlCQUF5QjtnQkFDekIsdUJBQXVCO2dCQUN2QiwwQkFBMEI7YUFDM0I7WUFDRCxTQUFTLEVBQUUsQ0FBQyxHQUFHLENBQUM7U0FDakIsQ0FBQyxDQUNILENBQUE7UUFFRCxNQUFNLGNBQWMsR0FBRyxJQUFBLHlCQUFpQixFQUN0QyxLQUFLLENBQUMscUJBQXFCLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxFQUNuRSxVQUFVLEVBQ1YsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FDbkIsQ0FBQTtRQUNELE1BQU0sbUJBQW1CLEdBQUcsS0FBSyxDQUFDLHFCQUFxQixDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLGNBQWMsS0FBSyxTQUFTLENBQUMsQ0FBQTtRQUMzRyxNQUFNLHNCQUFzQixHQUFHLEtBQUssQ0FBQyxxQkFBcUIsQ0FBQyxNQUFNLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxjQUFjLEtBQUssU0FBUyxDQUFDLENBQUE7UUFFOUcsbUJBQW1CLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUU7WUFDbkMsaUJBQWlCLENBQUMsZUFBZSxDQUMvQixJQUFJLEdBQUcsQ0FBQyxlQUFlLENBQUM7Z0JBQ3RCLE1BQU0sRUFBRSxHQUFHLENBQUMsTUFBTSxDQUFDLEtBQUs7Z0JBQ3hCLE9BQU8sRUFBRSxDQUFDLGdCQUFnQixDQUFDO2dCQUMzQixTQUFTLEVBQUUsQ0FBQyxJQUFJLENBQUMsY0FBZSxDQUFDLE9BQU8sQ0FBQzthQUMxQyxDQUFDLENBQ0gsQ0FBQTtRQUNILENBQUMsQ0FBQyxDQUFBO1FBRUYsc0JBQXNCLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUU7WUFDdEMsaUJBQWlCLENBQUMsZUFBZSxDQUMvQixJQUFJLEdBQUcsQ0FBQyxlQUFlLENBQUM7Z0JBQ3RCLE9BQU8sRUFBRSxDQUFDLG1CQUFtQixDQUFDO2dCQUM5QixTQUFTLEVBQUUsQ0FBQyxHQUFHLENBQUM7YUFDakIsQ0FBQyxDQUNILENBQUE7WUFDRCxNQUFNLFdBQVcsR0FBRyxjQUFjLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsQ0FBQTtZQUM1RCxJQUFJLFdBQVcsSUFBSSxXQUFXLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUMxQyxpQkFBaUIsQ0FBQyxlQUFlLENBQy9CLElBQUksR0FBRyxDQUFDLGVBQWUsQ0FBQztvQkFDdEIsT0FBTyxFQUFFLENBQUMsa0NBQWtDLENBQUM7b0JBQzdDLFNBQVMsRUFBRSxDQUFDLGdDQUFnQyxJQUFJLENBQUMscUJBQXFCLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxZQUFZLENBQUMsRUFBRSxDQUFDO29CQUN2RyxVQUFVLEVBQUU7d0JBQ1YsMkJBQTJCLEVBQUU7NEJBQzNCLDZDQUE2QyxFQUFFLENBQUMsT0FBTyxDQUFDOzRCQUN4RCx5Q0FBeUMsRUFBRSxDQUFDLFFBQVEsRUFBRSxRQUFRLENBQUM7eUJBQ2hFO3dCQUNELHlCQUF5QixFQUFFOzRCQUN6Qix1REFBdUQsRUFBRSxXQUFXLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxFQUFFO2dDQUN2RixPQUFPLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxpQkFBaUIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsRUFBRSxHQUFHLEtBQUssRUFBRSxFQUFFLElBQUksQ0FBQyxDQUFBOzRCQUMxRixDQUFDLENBQUM7eUJBQ0g7cUJBQ0Y7aUJBQ0YsQ0FBQyxDQUNILENBQUE7WUFDSCxDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUE7UUFFRixNQUFNLGlCQUFpQixHQUFHLElBQUksZ0JBQWdCLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRSxtQkFBbUIsRUFBRTtZQUNqRixjQUFjLEVBQUUsaUJBQWlCO1NBQ2xDLENBQUMsQ0FBQTtRQUVGLE1BQU0scUJBQXFCLEdBQUcsS0FBSyxDQUFDLHFCQUFxQixDQUFDLEdBQUcsQ0FBMkMsQ0FBQyxJQUFJLEVBQUUsRUFBRTtZQUMvRyxNQUFNLFVBQVUsR0FBbUM7Z0JBQ2pELFVBQVUsRUFBRSxJQUFJLENBQUMsbUJBQW1CLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUM7Z0JBQzlELFlBQVksRUFBRSxJQUFJLENBQUMscUJBQXFCLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxZQUFZLENBQUM7Z0JBQ3RFLGlCQUFpQixFQUFFLElBQUksQ0FBQyxjQUFjLEVBQUUsT0FBTztnQkFDL0Msb0JBQW9CLEVBQUUsSUFBSSxDQUFDLG9CQUFvQjthQUNoRCxDQUFBO1lBQ0QsT0FBTyxDQUFDLFVBQVUsQ0FBQyxVQUFVLEVBQUUsVUFBVSxDQUFDLENBQUE7UUFDNUMsQ0FBQyxDQUFDLENBQUE7UUFFRixNQUFNLFVBQVUsR0FBZTtZQUM3QixVQUFVLEVBQUUsVUFBVTtZQUN0QixzQkFBc0IsRUFBRSxzQkFBc0I7WUFDOUMscUJBQXFCLEVBQUUsTUFBTSxDQUFDLFdBQVcsQ0FBQyxxQkFBcUIsQ0FBQztZQUNoRSxpQkFBaUIsRUFBRSxJQUFJLENBQUMsaUJBQWlCO1lBQ3pDLHdCQUF3QixFQUFFLElBQUEsdUJBQWUsRUFBQyxLQUFLLENBQUMsd0JBQXdCLElBQUksSUFBSSxDQUFDO1lBQ2pGLDBCQUEwQixFQUFFLElBQUEsdUJBQWUsRUFBQyxLQUFLLENBQUMsMEJBQTBCLElBQUksSUFBSSxDQUFDO1lBQ3JGLElBQUksRUFBRSxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLE9BQU8sRUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxFQUFFLENBQXNDO1lBQ2xHLGFBQWEsRUFBRSxHQUFHLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFFLE9BQU8sRUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7U0FDdEUsQ0FBQTtRQUVELE1BQU0sV0FBVyxHQUFHLElBQUksR0FBRyxDQUFDLGNBQWMsQ0FBQyxJQUFJLEVBQUUsbUJBQW1CLEVBQUU7WUFDcEUsWUFBWSxFQUFFLGlCQUFpQixDQUFDLFlBQVk7WUFDNUMsWUFBWSxFQUFFLDhCQUE4QjtZQUM1QyxVQUFVO1NBQ1gsQ0FBQyxDQUFBO1FBRUYsc0VBQXNFO1FBQ3RFLG1FQUFtRTtRQUNuRSxxRUFBcUU7UUFDckUsa0VBQWtFO1FBQ2xFLFdBQVcsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLGlCQUFpQixDQUFDLENBQUE7UUFDakQsSUFBSSxpQkFBaUIsQ0FBQyxJQUFJLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDekMsV0FBVyxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsaUJBQWlCLENBQUMsSUFBSSxDQUFDLENBQUE7WUFDdEQsTUFBTSxNQUFNLEdBQUcsaUJBQWlCLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsZUFBZSxDQUFDLENBQUE7WUFDeEUsSUFBSSxNQUFNLEtBQUssU0FBUyxFQUFFLENBQUM7Z0JBQ3pCLFdBQVcsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxDQUFBO1lBQ3hDLENBQUM7UUFDSCxDQUFDO1FBRUQsSUFBSSxDQUFDLGNBQWMsR0FBRyxXQUFXLENBQUMsWUFBWSxDQUFDLEtBQUssQ0FBQyxDQUFBO1FBRXJELElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDO1lBQ3RCLFFBQVEsRUFBRSxHQUFHLEVBQUUsQ0FDYixJQUFJLENBQUMsNEJBQTRCLENBQy9CLFVBQVUsRUFDVixxQkFBcUIsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsUUFBUSxDQUFDLENBQ3ZEO1NBQ0osQ0FBQyxDQUFBO0lBQ0osQ0FBQztJQUVELGtCQUFrQixDQUFDLEtBQW9EO1FBQ3JFLE9BQU8sSUFBSSxVQUFVLENBQUMsTUFBTSxDQUFDO1lBQzNCLE1BQU0sRUFBRSxHQUFHLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7WUFDNUIsR0FBRyxLQUFLO1lBQ1IsYUFBYSxFQUFFLEVBQUUsY0FBYyxFQUFFLElBQUksQ0FBQyxjQUFjLEVBQUU7WUFDdEQsVUFBVSxFQUFFLGNBQWM7WUFDMUIsU0FBUyxFQUFFLHdCQUF3QjtZQUNuQyxNQUFNLEVBQUUsSUFBSSxDQUFDLGlCQUFpQjtZQUM5QixTQUFTLEVBQUUsVUFBVSxDQUFDLEtBQUssQ0FBQyxPQUFPO1NBQ3BDLENBQUMsQ0FBQTtJQUNKLENBQUM7SUFFRCxrQkFBa0IsQ0FBQyxNQUF5QjtRQUMxQyxJQUFJLENBQUMsYUFBYSxHQUFHLE1BQU0sQ0FBQTtJQUM3QixDQUFDO0lBRUQsK0lBQStJO0lBQy9JLHFFQUFxRTtJQUNyRSw2Q0FBNkM7SUFDN0MsSUFBVyxjQUFjO1FBQ3ZCLE9BQU87WUFDTCxhQUFhLEVBQUUsSUFBSSxDQUFDLGNBQWM7U0FDbkMsQ0FBQTtJQUNILENBQUM7SUFFTyxtQkFBbUIsQ0FBQyxVQUFrQjtRQUM1QyxJQUFJLEdBQUcsQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7WUFDdkMsT0FBTyxVQUFVLENBQUE7UUFDbkIsQ0FBQztRQUNELE9BQU8sSUFBQSx1QkFBZSxFQUFDLFVBQVUsQ0FBQyxDQUFBO0lBQ3BDLENBQUM7SUFFTyxxQkFBcUIsQ0FBQyxZQUFvQjtRQUNoRCxJQUFJLEdBQUcsQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLFlBQVksQ0FBQyxFQUFFLENBQUM7WUFDekMsT0FBTyxZQUFZLENBQUE7UUFDckIsQ0FBQztRQUNELE9BQU8sSUFBQSx5QkFBaUIsRUFBQyxZQUFZLENBQUMsQ0FBQTtJQUN4QyxDQUFDO0lBRU8sa0JBQWtCLENBQUMsRUFBVSxFQUFFLFVBQWtCO1FBQ3ZELE1BQU0sS0FBSyxHQUFHLEdBQUcsQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxVQUFVLENBQUMsQ0FBQTtRQUMzQyxNQUFNLEtBQUssR0FBRyxHQUFHLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUE7UUFDckMsTUFBTSxVQUFVLEdBQUcsSUFBSSxHQUFHLENBQUMsWUFBWSxDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFO1lBQ3ZELFVBQVUsRUFBRSxHQUFHLENBQUMsRUFBRSxDQUFDLGVBQWUsQ0FBQyxLQUFLLEVBQUUsR0FBRyxDQUFDO1NBQy9DLENBQUMsQ0FBQTtRQUNGLE9BQU8sR0FBRyxDQUFDLEVBQUUsQ0FBQyxXQUFXLENBQUMsVUFBVSxDQUFDLFNBQVMsRUFBRSxVQUFVLEVBQUUsS0FBSyxVQUFVLEVBQUUsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFBO0lBQzNGLENBQUM7SUFFTyw0QkFBNEIsQ0FBQyxXQUFxQixFQUFFLFNBQW1CO1FBQzdFLE1BQU0sTUFBTSxHQUFhLEVBQUUsQ0FBQTtRQUMzQixLQUFLLE1BQU0sVUFBVSxJQUFJLFdBQVcsRUFBRSxDQUFDO1lBQ3JDLE1BQU0sb0JBQW9CLEdBQUcsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLFlBQVksQ0FBQyxVQUFVLENBQUMsQ0FBQTtZQUNoRSxNQUFNLG1CQUFtQixHQUFHLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDLFFBQVEsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQTtZQUMzRixJQUFJLG9CQUFvQixJQUFJLG1CQUFtQixJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDLFFBQVEsRUFBRSxFQUFFLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQyxFQUFFLENBQUM7Z0JBQ2hILE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxVQUFVLGlEQUFpRCxDQUFDLENBQUE7WUFDcEYsQ0FBQztRQUNILENBQUM7UUFDRCxPQUFPLE1BQU0sQ0FBQTtJQUNmLENBQUM7O0FBcE5ILDBEQXFOQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGNkayBmcm9tICdhd3MtY2RrLWxpYidcbmltcG9ydCAqIGFzIGNlcnRpZmljYXRlbWFuYWdlciBmcm9tICdhd3MtY2RrLWxpYi9hd3MtY2VydGlmaWNhdGVtYW5hZ2VyJ1xuaW1wb3J0ICogYXMgY2xvdWR3YXRjaCBmcm9tICdhd3MtY2RrLWxpYi9hd3MtY2xvdWR3YXRjaCdcbmltcG9ydCAqIGFzIGlhbSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtaWFtJ1xuaW1wb3J0ICogYXMgbGFtYmRhIGZyb20gJ2F3cy1jZGstbGliL2F3cy1sYW1iZGEnXG5pbXBvcnQgKiBhcyByb3V0ZTUzIGZyb20gJ2F3cy1jZGstbGliL2F3cy1yb3V0ZTUzJ1xuaW1wb3J0ICogYXMgY3VzdG9tX3Jlc291cmNlcyBmcm9tICdhd3MtY2RrLWxpYi9jdXN0b20tcmVzb3VyY2VzJ1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cydcbmltcG9ydCB7IENlcnRpZmljYXRlUmVxdWVzdG9yRnVuY3Rpb24gfSBmcm9tICcuL2NlcnRpZmljYXRlLXJlcXVlc3Rvci1mdW5jdGlvbidcbmltcG9ydCB7IFByb3BlcnRpZXMsIFZhbGlkYXRpb25Ib3N0ZWRab25lUHJvcGVydGllcyB9IGZyb20gJy4vY2VydGlmaWNhdGUtcmVxdWVzdG9yLmxhbWJkYSdcbmltcG9ydCB7IGJvb2xlYW5Ub1N0cmluZywgY2xlYW5Eb21haW5OYW1lLCBjbGVhbkhvc3RlZFpvbmVJZCwgbWF0Y2hOYW1lc1RvWm9uZXMgfSBmcm9tICcuL3V0aWxzJ1xuXG5leHBvcnQgaW50ZXJmYWNlIFZhbGlkYXRpb25Ib3N0ZWRab25lIHtcbiAgLyoqXG4gICAqIEhvc3RlZCB6b25lIHRvIHVzZSBmb3IgRE5TIHZhbGlkYXRpb24uIFRoZSB6b25lIG5hbWUgaXMgbWF0Y2hlZCB0byBkb21haW4gbmFtZSB0byB1c2UgdGhlIHJpZ2h0XG4gICAqIGhvc3RlZCB6b25lIGZvciB2YWxpZGF0aW9uLlxuICAgKlxuICAgKiBJZiB0aGUgaG9zdGVkIHpvbmUgaXMgbm90IG1hbmFnZWQgYnkgdGhlIENESyBhcHBsaWNhdGlvbiwgaXQgbmVlZHMgdG8gYmUgcHJvdmlkZWQgdmlhXG4gICAqIGBgSG9zdGVkWm9uZS5mcm9tSG9zdGVkWm9uZUF0dHJpYnV0ZXMoKWBgLlxuICAgKi9cbiAgcmVhZG9ubHkgaG9zdGVkWm9uZTogcm91dGU1My5JSG9zdGVkWm9uZVxuXG4gIC8qKlxuICAgKiBUaGUgcm9sZSB0aGF0IGlzIGFzc3VtZWQgZm9yIEROUyByZWNvcmQgY2hhbmdlcyBmb3IgY2VydGlmaWNhdGUgdmFsaWRhdGlvbi5cbiAgICpcbiAgICogVGhpcyByb2xlIHNob3VsZCBleGlzdCBpbiB0aGUgc2FtZSBhY2NvdW50IGFzIHRoZSBob3N0ZWQgem9uZSBhbmQgaW5jbHVkZSBwZXJtaXNzaW9ucyB0byBjaGFuZ2UgdGhlIEROUyByZWNvcmRzXG4gICAqIGZvciB0aGUgZ2l2ZW4gYGBob3N0ZWRab25lYGAuIFRoZSBgYGN1c3RvbVJlc291cmNlUm9sZWBgIG9yIHRoZSBkZWZhdWx0IGV4ZWN1dGlvbiByb2xlIGlzIGdpdmVuIHBlcm1pc3Npb24gdG9cbiAgICogYXNzdW1lIHRoaXMgcm9sZS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBObyBzZXBhcmF0ZSByb2xlIGZvciBETlMgcmVjb3JkIGNoYW5nZXMuIFRoZSBnaXZlbiBjdXN0b21SZXNvdXJjZVJvbGUgb3IgdGhlIGRlZmF1bHQgcm9sZSBpcyB1c2VkXG4gICAqIGZvciBETlMgcmVjb3JkIGNoYW5nZXMuXG4gICAqL1xuICByZWFkb25seSB2YWxpZGF0aW9uUm9sZT86IGlhbS5JUm9sZVxuXG4gIC8qKlxuICAgKiBFeHRlcm5hbCBpZCBmb3IgYGB2YWxpZGF0aW9uUm9sZWBgIHJvbGUgYXNzdW1lIHZlcmlmaWNhdGlvbi5cbiAgICpcbiAgICogVGhpcyBzaG91bGQgYmUgdXNlZCBvbmx5IHdoZW4gYGB2YWxpZGF0aW9uUm9sZWBgIGlzIGdpdmVuIGFuZCB0aGUgcm9sZSBleHBlY3RzIGFuIGV4dGVybmFsIGlkIHByb3ZpZGVkIG9uIGFzc3VtZS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBObyBleHRlcm5hbCBpZCBwcm92aWRlZCBkdXJpbmcgYXNzdW1lLlxuICAgKi9cbiAgcmVhZG9ubHkgdmFsaWRhdGlvbkV4dGVybmFsSWQ/OiBzdHJpbmdcbn1cblxuZXhwb3J0IGludGVyZmFjZSBEbnNWYWxpZGF0ZWRDZXJ0aWZpY2F0ZVByb3BzIHtcbiAgLyoqXG4gICAqIEZ1bGx5LXF1YWxpZmllZCBkb21haW4gbmFtZSB0byByZXF1ZXN0IGEgY2VydGlmaWNhdGUgZm9yLlxuICAgKlxuICAgKiBNYXkgY29udGFpbiB3aWxkY2FyZHMsIHN1Y2ggYXMgYGAqLmRvbWFpbi5jb21gYC5cbiAgICovXG4gIHJlYWRvbmx5IGRvbWFpbk5hbWU6IHN0cmluZ1xuXG4gIC8qKlxuICAgKiBGdWxseS1xdWFsaWZpZWQgYWx0ZXJuYXRpdmUgZG9tYWluIG5hbWVzIHRvIHJlcXVlc3QgYSBjZXJ0aWZpY2F0ZSBmb3IuXG4gICAqXG4gICAqIE1heSBjb250YWluIHdpbGRjYXJkcywgc3VjaCBhcyBgYCoub3RoZXJkb21haW4uY29tYGAuXG4gICAqL1xuICByZWFkb25seSBhbHRlcm5hdGl2ZURvbWFpbk5hbWVzPzogc3RyaW5nW11cblxuICAvKipcbiAgICogTGlzdCBvZiBob3N0ZWQgem9uZXMgdG8gdXNlIGZvciB2YWxpZGF0aW9uLiBIb3N0ZWQgem9uZXMgYXJlIG1hcHBlZCB0byBkb21haW4gbmFtZXMgYnkgdGhlIHpvbmUgbmFtZS5cbiAgICovXG4gIHJlYWRvbmx5IHZhbGlkYXRpb25Ib3N0ZWRab25lczogVmFsaWRhdGlvbkhvc3RlZFpvbmVbXVxuXG4gIC8qKlxuICAgKiBBV1MgcmVnaW9uIHdoZXJlIHRoZSBjZXJ0aWZpY2F0ZSBpcyBkZXBsb3llZC5cbiAgICpcbiAgICogWW91IHNob3VsZCB1c2UgdGhlIGRlZmF1bHQgYGBDZXJ0aWZpY2F0ZWBgIGNvbnN0cnVjdCBpbnN0ZWFkIGlmIHRoZSByZWdpb24gaXMgc2FtZSBhcyB0aGUgc3RhY2sncyBhbmQgdGhlIGhvc3RlZFxuICAgKiB6b25lIGlzIGluIHRoZSBzYW1lIGFjY291bnQuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gU2FtZSByZWdpb24gYXMgdGhlIHN0YWNrLlxuICAgKi9cbiAgcmVhZG9ubHkgY2VydGlmaWNhdGVSZWdpb24/OiBzdHJpbmdcblxuICAvKipcbiAgICogVGhlIHJvbGUgdGhhdCBpcyB1c2VkIGZvciB0aGUgY3VzdG9tIHJlc291cmNlIExhbWJkYSBleGVjdXRpb24uXG4gICAqXG4gICAqIFRoZSByb2xlIGlzIGdpdmVuIHBlcm1pc3Npb25zIHRvIHJlcXVlc3QgY2VydGlmaWNhdGVzIGZyb20gQUNNLiBJZiB0aGVyZSBhcmUgYW55IGBgdmFsaWRhdGlvblJvbGVgYHMgcHJvdmlkZWQsXG4gICAqIHRoaXMgcm9sZSBpcyBhbHNvIGdpdmVuIHBlcm1pc3Npb24gdG8gYXNzdW1lIHRoZSBgYHZhbGlkYXRpb25Sb2xlYGAuIE90aGVyd2lzZSBpdCBpcyBhc3N1bWVkIHRoYXQgdGhlIGhvc3RlZCB6b25lXG4gICAqIGlzIGluIHNhbWUgYWNjb3VudCBhbmQgdGhlIGV4ZWN1dGlvbiByb2xlIGlzIGdpdmVuIHBlcm1pc3Npb25zIHRvIGNoYW5nZSBETlMgcmVjb3JkcyBmb3IgdGhlIGdpdmVuIGBgZG9tYWluTmFtZWBgLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIExhbWJkYSBjcmVhdGVzIGEgZGVmYXVsdCBleGVjdXRpb24gcm9sZS5cbiAgICovXG4gIHJlYWRvbmx5IGN1c3RvbVJlc291cmNlUm9sZT86IGlhbS5JUm9sZVxuXG4gIC8qKlxuICAgKiBFbmFibGUgb3IgZGlzYWJsZSBjbGVhbmluZyBvZiB2YWxpZGF0aW9uIEROUyByZWNvcmRzIGZyb20gdGhlIGhvc3RlZCB6b25lLlxuICAgKlxuICAgKiBJZiB0aGVyZSdzIG11bHRpcGxlIGNlcnRpZmljYXRlcyBjcmVhdGVkIGZvciBzYW1lIGRvbWFpbiwgaXQgaXMgcG9zc2libGUgdG8gZW5jb3V0ZXIgYSByYWNlIGNvbmRpdGlvbiB3aGVyZSBzb21lXG4gICAqIGNlcnRpZmljYXRlIGlzIHJlbW92ZWQgYW5kIGFub3RoZXIgY2VydGlmaWNhdGUgd291bGQgbmVlZCB0aGUgc2FtZSB2YWxpZGF0aW9uIHJlY29yZC4gUHJlZmVyIHNpbmdsZSBjZXJ0aWZpY2F0ZVxuICAgKiBmb3IgYSBkb21haW4gb3Igc2V0IHRoaXMgdG8gZmFsc2UgYW5kIGNsZWFudXAgcmVjb3JkcyBtYW51YWxseSB3aGVuIG5vdCBuZWVkZWQgYW55bW9yZS4gSWYgeW91IGNoYW5nZSB0aGlzXG4gICAqIHByb3BlcnR5IGFmdGVyIGNyZWF0aW9uLCBhIG5ldyBjZXJ0aWZpY2F0ZSB3aWxsIGJlIHJlcXVlc3RlZC5cbiAgICpcbiAgICogQGRlZmF1bHQgdHJ1ZVxuICAgKi9cbiAgcmVhZG9ubHkgY2xlYW51cFZhbGlkYXRpb25SZWNvcmRzPzogYm9vbGVhblxuXG4gIC8qKlxuICAgKiBFbmFibGUgb3IgZGlzYWJsZSB0cmFuc3BhcmVuY3kgbG9nZ2luZyBmb3IgdGhpcyBjZXJ0aWZpY2F0ZS5cbiAgICpcbiAgICogT25jZSBhIGNlcnRpZmljYXRlIGhhcyBiZWVuIGxvZ2dlZCwgaXQgY2Fubm90IGJlIHJlbW92ZWQgZnJvbSB0aGUgbG9nLiBPcHRpbmcgb3V0IGF0IHRoYXQgcG9pbnQgd2lsbCBoYXZlIG5vXG4gICAqIGVmZmVjdC4gSWYgeW91IGNoYW5nZSB0aGlzIHByb3BlcnR5IGFmdGVyIGNyZWF0aW9uLCBhIG5ldyBjZXJ0aWZpY2F0ZSB3aWxsIGJlIHJlcXVlc3RlZC5cbiAgICpcbiAgICogQHNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vYWNtL2xhdGVzdC91c2VyZ3VpZGUvYWNtLWJlc3RwcmFjdGljZXMuaHRtbCNiZXN0LXByYWN0aWNlcy10cmFuc3BhcmVuY3lcbiAgICpcbiAgICogQGRlZmF1bHQgdHJ1ZVxuICAgKi9cbiAgcmVhZG9ubHkgdHJhbnNwYXJlbmN5TG9nZ2luZ0VuYWJsZWQ/OiBib29sZWFuXG5cbiAgLyoqXG4gICAqIEFwcGx5IHRoZSBnaXZlbiByZW1vdmFsIHBvbGljeSB0byB0aGlzIHJlc291cmNlLlxuICAgKlxuICAgKiBUaGUgcmVtb3ZhbCBwb2xpY3kgY29udHJvbHMgd2hhdCBoYXBwZW5zIHRvIHRoaXMgcmVzb3VyY2Ugd2hlbiBpdCBzdG9wcyBiZWluZyBtYW5hZ2VkIGJ5IENsb3VkRm9ybWF0aW9uLCBlaXRoZXJcbiAgICogYmVjYXVzZSB5b3UndmUgcmVtb3ZlZCBpdCBmcm9tIHRoZSBDREsgYXBwbGljYXRpb24gb3IgYmVjYXVzZSB5b3UndmUgbWFkZSBhIGNoYW5nZSB0aGF0IHJlcXVpcmVzIHRoZSByZXNvdXJjZSB0b1xuICAgKiBiZSByZXBsYWNlZC4gVGhlIHJlc291cmNlIGNhbiBiZSBkZWxldGVkIChgYFJlbW92YWxQb2xpY3kuREVTVFJPWWBgKSwgb3IgbGVmdCBpbiB5b3VyIEFXUyBhY2NvdW50IGZvciBkYXRhXG4gICAqIHJlY292ZXJ5IGFuZCBjbGVhbnVwIGxhdGVyIChgYFJlbW92YWxQb2xpY3kuUkVUQUlOYGApLiBJZiB5b3UgY2hhbmdlIHRoaXMgcHJvcGVydHkgYWZ0ZXIgY3JlYXRpb24sIGEgbmV3XG4gICAqIGNlcnRpZmljYXRlIHdpbGwgYmUgcmVxdWVzdGVkLlxuICAgKlxuICAgKiBAZGVmYXVsdCBSZW1vdmFsUG9saWN5LkRFU1RST1lcbiAgICovXG4gIHJlYWRvbmx5IHJlbW92YWxQb2xpY3k/OiBjZGsuUmVtb3ZhbFBvbGljeVxufVxuXG5jb25zdCBETlNfVkFMSURBVEVEX0NFUlRJRklDQVRFX1RZUEUgPSAnQ3VzdG9tOjpEbnNWYWxpZGF0ZWRDZXJ0aWZpY2F0ZSdcbmNvbnN0IENFUlRUSUZJQ0FURV9SRVNPVVJDRV9UWVBFID0gJ0FXUzo6Q2VydGlmaWNhdGVNYW5hZ2VyOjpDZXJ0aWZpY2F0ZSdcblxuLyoqXG4gKiBBIGNlcnRpZmljYXRlIG1hbmFnZWQgYnkgQVdTIENlcnRpZmljYXRlIE1hbmFnZXIuIFdpbGwgYmUgYXV0b21hdGljYWxseSB2YWxpZGF0ZWQgdXNpbmcgRE5TIHZhbGlkYXRpb24gYWdhaW5zdCB0aGVcbiAqIHNwZWNpZmllZCBSb3V0ZSA1MyBob3N0ZWQgem9uZS4gVGhpcyBjb25zdHJ1Y3Qgc2hvdWxkIGJlIHVzZWQgb25seSBmb3IgY3Jvc3MtcmVnaW9uIG9yIGNyb3NzLWFjY291bnQgY2VydGlmaWNhdGVcbiAqIHZhbGlkYXRpb25zLiBUaGUgZGVmYXVsdCBgYENlcnRpZmljYXRlYGAgY29uc3RydWN0IGlzIGJldHRlciBpbiBjYXNlcyB3aGVyZSBldmVyeXRoaW5nIGlzIG1hbmFnZWQgYnkgdGhlIENES1xuICogYXBwbGljYXRpb24uXG4gKlxuICogUGxlYXNlIG5vdGUgdGhhdCB0aGlzIGNvbnN0cnVjdCBkb2VzIG5vdCBzdXBwb3J0IGFsdGVybmF0aXZlIG5hbWVzIHlldCBhcyBpdCB3b3VsZCByZXF1aXJlIGRvbWFpbiB0byByb2xlIG1hcHBpbmcuXG4gKlxuICogQGV4YW1wbGVcbiAqIC8vICMjIyBDcm9zcy1yZWdpb24gY2VydGlmaWNhdGUgdmFsaWRhdGlvblxuICogLy8gaG9zdGVkIHpvbmUgbWFuYWdlZCBieSB0aGUgQ0RLIGFwcGxpY2F0aW9uXG4gKiBjb25zdCBob3N0ZWRab25lOiByb3V0ZTUzLklIb3N0ZWRab25lID0gLi4uXG4gKiAvLyBubyBzZXBhcmF0ZSB2YWxpZGF0aW9uIHJvbGUgaXMgbmVlZGVkXG4gKiBjb25zdCBjZXJ0aWZpY2F0ZSA9IG5ldyBEbnNWYWxpZGF0ZWRDZXJ0aWZpY2F0ZSh0aGlzLCAnQ3Jvc3NSZWdpb25DZXJ0aWZpY2F0ZScsIHtcbiAqICAgZG9tYWluTmFtZTogJ2V4YW1wbGUuY29tJywgICAgIC8vIG11c3QgYmUgY29tcGF0aWJsZSB3aXRoIHRoZSBob3N0ZWQgem9uZVxuICogICB2YWxpZGF0aW9uSG9zdGVkWm9uZXM6IFt7ICAgICAgLy8gaG9zdGVkIHpvbmUgdXNlZCB3aXRoIHRoZSBleGVjdXRpb24gcm9sZSdzIHBlcm1pc3Npb25zXG4gKiAgICAgaG9zdGVkWm9uZTogaG9zdGVkWm9uZVxuICogICB9XSxcbiAqICAgY2VydGlmaWNhdGVSZWdpb246ICd1cy1lYXN0LTEnIC8vIHVzZWQgYnkgZm9yIGV4YW1wbGUgQ2xvdWRGcm9udFxuICogfSlcbiAqIC8vICMjIyBDcm9zcy1hY2NvdW50IGNlcnRpZmljYXRlIHZhbGlkYXRpb25cbiAqIC8vIGV4dGVybmFsIGhvc3RlZCB6b25lXG4gKiBjb25zdCBob3N0ZWRab25lOiByb3V0ZTUzLklIb3N0ZWRab25lID1cbiAqICAgcm91dGU1My5Ib3N0ZWRab25lLmZyb21Ib3N0ZWRab25lQXR0cmlidXRlcyh0aGlzLCAnSG9zdGVkWm9uZScsIHtcbiAqICAgICBob3N0ZWRab25lSWQ6ICdaNTMyREdERURGUzEyMzQ1Njc4OScsXG4gKiAgICAgem9uZU5hbWU6ICdleGFtcGxlLmNvbSdcbiAqICAgfSlcbiAqIC8vIHZhbGlkYXRpb24gcm9sZSBpbiB0aGUgc2FtZSBhY2NvdW50IGFzIHRoZSBob3N0ZWQgem9uZVxuICogY29uc3Qgcm9sZUFybiA9ICdhcm46YXdzOmlhbTo6MTIzNDU2Nzg5OnJvbGUvQ2hhbmdlRG5zUmVjb3Jkc1JvbGUnXG4gKiBjb25zdCBleHRlcm5hbElkID0gJ2RvbWFpbi1hc3N1bWUnXG4gKiBjb25zdCB2YWxpZGF0aW9uUm9sZTogaWFtLklSb2xlID1cbiAqICAgaWFtLlJvbGUuZnJvbVJvbGVBcm4odGhpcywgJ1ZhbGlkYXRpb25Sb2xlJywgcm9sZUFybilcbiAqIGNvbnN0IGNlcnRpZmljYXRlID0gbmV3IERuc1ZhbGlkYXRlZENlcnRpZmljYXRlKHRoaXMsICdDcm9zc0FjY291bnRDZXJ0aWZpY2F0ZScsIHtcbiAqICAgZG9tYWluTmFtZTogJ2V4YW1wbGUuY29tJyxcbiAqICAgdmFsaWRhdGlvbkhvc3RlZFpvbmVzOiBbe1xuICogICAgIGhvc3RlZFpvbmU6IGhvc3RlZFpvbmUsXG4gKiAgICAgdmFsaWRhdGlvblJvbGU6IHZhbGlkYXRpb25Sb2xlLFxuICogICAgIHZhbGlkYXRpb25FeHRlcm5hbElkOiBleHRlcm5hbElkXG4gKiAgIH1dXG4gKiB9KVxuICogLy8gIyMjIENyb3NzLWFjY291bnQgYWx0ZXJuYXRpdmUgbmFtZSB2YWxpZGF0aW9uXG4gKiAvLyBleGFtcGxlLmNvbSBpcyB2YWxpZGF0ZWQgb24gc2FtZSBhY2NvdW50IGFnYWluc3QgbWFuYWdlZCBob3N0ZWQgem9uZVxuICogLy8gYW5kIHNlY29uZGFyeS5jb20gaXMgdmFsaWRhdGVkIGFnYWluc3QgZXh0ZXJuYWwgaG9zdGVkIHpvbmUgb24gb3RoZXIgYWNjb3VudFxuICogY29uc3QgaG9zdGVkWm9uZUZvck1haW46IHJvdXRlNTMuSUhvc3RlZFpvbmUgPSAuLi5cbiAqIGNvbnN0IGhvc3RlZFpvbmVGb3JBbHRlcm5hdGl2ZTogcm91dGU1My5JSG9zdGVkWm9uZSA9XG4gKiAgIHJvdXRlNTMuSG9zdGVkWm9uZS5mcm9tSG9zdGVkWm9uZUF0dHJpYnV0ZXModGhpcywgJ1NlY29uZGFyeUhvc3RlZFpvbmUnLCB7XG4gKiAgICAgaG9zdGVkWm9uZUlkOiAnWjUzMkRHREVERlMxMjM0NTY3ODknLFxuICogICAgIHpvbmVOYW1lOiAnc2Vjb25kYXJ5LmNvbSdcbiAqICAgfSlcbiAqIGNvbnN0IGNlcnRpZmljYXRlID0gbmV3IERuc1ZhbGlkYXRlZENlcnRpZmljYXRlKHRoaXMsICdDcm9zc0FjY291bnRDZXJ0aWZpY2F0ZScsIHtcbiAqICAgZG9tYWluTmFtZTogJ2V4YW1wbGUuY29tJyxcbiAqICAgYWx0ZXJuYXRpdmVEb21haW5OYW1lczogWydzZWNvbmRhcnkuY29tJ10sXG4gKiAgIHZhbGlkYXRpb25Ib3N0ZWRab25lczogW3tcbiAqICAgICBob3N0ZWRab25lOiBob3N0ZWRab25lRm9yTWFpblxuICogICB9LHtcbiAqICAgICBob3N0ZWRab25lOiBob3N0ZWRab25lRm9yQWx0ZXJuYXRpdmUsXG4gKiAgICAgdmFsaWRhdGlvblJvbGU6IGlhbS5Sb2xlLmZyb21Sb2xlQXJuKFxuICogICAgICAgdGhpcywgJ1NlY29uZGFyeVZhbGlkYXRpb25Sb2xlJywgJ2Fybjphd3M6aWFtOjoxMjM0NTY3ODk6cm9sZS9DaGFuZ2VEbnNSZWNvcmRzUm9sZSdcbiAqICAgICApLFxuICogICAgIHZhbGlkYXRpb25FeHRlcm5hbElkOiAnZG9tYWluLWFzc3VtZSdcbiAqICAgfV1cbiAqIH0pXG4gKlxuICogQHJlc291cmNlIEN1c3RvbTo6RG5zVmFsaWRhdGVkQ2VydGlmaWNhdGVcbiAqIEByZXNvdXJjZSBBV1M6OkNlcnRpZmljYXRlTWFuYWdlcjo6Q2VydGlmaWNhdGVcbiAqL1xuZXhwb3J0IGNsYXNzIERuc1ZhbGlkYXRlZENlcnRpZmljYXRlIGV4dGVuZHMgY2RrLlJlc291cmNlIGltcGxlbWVudHMgY2VydGlmaWNhdGVtYW5hZ2VyLklDZXJ0aWZpY2F0ZSwgY2RrLklUYWdnYWJsZSB7XG4gIC8qKiBUaGUgY2VydGlmaWNhdGUncyBBUk4gKi9cbiAgcHVibGljIHJlYWRvbmx5IGNlcnRpZmljYXRlQXJuOiBzdHJpbmdcblxuICAvKiogVGhlIHJlZ2lvbiB3aGVyZSB0aGUgY2VydGlmaWNhdGUgaXMgZGVwbG95ZWQgdG8gKi9cbiAgcHVibGljIHJlYWRvbmx5IGNlcnRpZmljYXRlUmVnaW9uOiBzdHJpbmdcblxuICAvKiogVGhlIHRhZyBtYW5hZ2VyIHRvIHNldCwgcmVtb3ZlIGFuZCBmb3JtYXQgdGFncyBmb3IgdGhlIGNlcnRpZmljYXRlICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgdGFnczogY2RrLlRhZ01hbmFnZXJcblxuICAvKiogVGhlIHJlbW92YWwgcG9saWN5IGZvciB0aGUgY2VydGlmaWNhdGUgKi9cbiAgcHJpdmF0ZSByZW1vdmFsUG9saWN5OiBjZGsuUmVtb3ZhbFBvbGljeVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIERuc1ZhbGlkYXRlZENlcnRpZmljYXRlIGNvbnN0cnVjdC5cbiAgICpcbiAgICogQHBhcmFtIHNjb3BlIGNvbnN0cnVjdCBob3N0aW5nIHRoaXMgY29uc3RydWN0XG4gICAqIEBwYXJhbSBpZCBjb25zdHJ1Y3QncyBpZGVudGlmaWVyXG4gICAqIEBwYXJhbSBwcm9wcyBwcm9wZXJ0aWVzIGZvciB0aGUgY29uc3RydWN0XG4gICAqL1xuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogRG5zVmFsaWRhdGVkQ2VydGlmaWNhdGVQcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZClcblxuICAgIGNvbnN0IGRvbWFpbk5hbWUgPSB0aGlzLm5vcm1hbGl6ZURvbWFpbk5hbWUocHJvcHMuZG9tYWluTmFtZSlcbiAgICBjb25zdCBhbHRlcm5hdGl2ZURvbWFpbk5hbWVzID0gcHJvcHMuYWx0ZXJuYXRpdmVEb21haW5OYW1lcz8ubWFwKChhbHRlcm5hdGl2ZURvbWFpbk5hbWUpID0+XG4gICAgICB0aGlzLm5vcm1hbGl6ZURvbWFpbk5hbWUoYWx0ZXJuYXRpdmVEb21haW5OYW1lKVxuICAgIClcbiAgICBjb25zdCBhbGxEb21haW5zID0gW2RvbWFpbk5hbWUsIC4uLihhbHRlcm5hdGl2ZURvbWFpbk5hbWVzID8/IFtdKV1cblxuICAgIHRoaXMuY2VydGlmaWNhdGVSZWdpb24gPSBwcm9wcy5jZXJ0aWZpY2F0ZVJlZ2lvbiA/PyB0aGlzLnN0YWNrLnJlZ2lvblxuICAgIHRoaXMudGFncyA9IG5ldyBjZGsuVGFnTWFuYWdlcihjZGsuVGFnVHlwZS5NQVAsIENFUlRUSUZJQ0FURV9SRVNPVVJDRV9UWVBFKVxuICAgIHRoaXMucmVtb3ZhbFBvbGljeSA9IHByb3BzLnJlbW92YWxQb2xpY3kgPz8gY2RrLlJlbW92YWxQb2xpY3kuREVTVFJPWVxuXG4gICAgY29uc3QgcmVxdWVzdG9yRnVuY3Rpb24gPSBuZXcgQ2VydGlmaWNhdGVSZXF1ZXN0b3JGdW5jdGlvbih0aGlzLCAnUmVxdWVzdG9yRnVuY3Rpb24nLCB7XG4gICAgICBhcmNoaXRlY3R1cmU6IGxhbWJkYS5BcmNoaXRlY3R1cmUuQVJNXzY0LFxuICAgICAgdGltZW91dDogY2RrLkR1cmF0aW9uLm1pbnV0ZXMoMTQpLFxuICAgICAgcm9sZTogcHJvcHMuY3VzdG9tUmVzb3VyY2VSb2xlLFxuICAgIH0pXG5cbiAgICByZXF1ZXN0b3JGdW5jdGlvbi5hZGRUb1JvbGVQb2xpY3koXG4gICAgICBuZXcgaWFtLlBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgIGVmZmVjdDogaWFtLkVmZmVjdC5BTExPVyxcbiAgICAgICAgYWN0aW9uczogW1xuICAgICAgICAgICdhY206UmVxdWVzdENlcnRpZmljYXRlJyxcbiAgICAgICAgICAnYWNtOkRlc2NyaWJlQ2VydGlmaWNhdGUnLFxuICAgICAgICAgICdhY206RGVsZXRlQ2VydGlmaWNhdGUnLFxuICAgICAgICAgICdhY206QWRkVGFnc1RvQ2VydGlmaWNhdGUnLFxuICAgICAgICBdLFxuICAgICAgICByZXNvdXJjZXM6IFsnKiddLFxuICAgICAgfSlcbiAgICApXG5cbiAgICBjb25zdCBkb21haW5zVG9ab25lcyA9IG1hdGNoTmFtZXNUb1pvbmVzKFxuICAgICAgcHJvcHMudmFsaWRhdGlvbkhvc3RlZFpvbmVzLm1hcCgoem9uZSkgPT4gem9uZS5ob3N0ZWRab25lLnpvbmVOYW1lKSxcbiAgICAgIGFsbERvbWFpbnMsXG4gICAgICAoZG9tYWluKSA9PiBkb21haW5cbiAgICApXG4gICAgY29uc3QgaG9zdGVkWm9uZXNXaXRoUm9sZSA9IHByb3BzLnZhbGlkYXRpb25Ib3N0ZWRab25lcy5maWx0ZXIoKHpvbmUpID0+IHpvbmUudmFsaWRhdGlvblJvbGUgIT09IHVuZGVmaW5lZClcbiAgICBjb25zdCBob3N0ZWRab25lc1dpdGhvdXRSb2xlID0gcHJvcHMudmFsaWRhdGlvbkhvc3RlZFpvbmVzLmZpbHRlcigoem9uZSkgPT4gem9uZS52YWxpZGF0aW9uUm9sZSA9PT0gdW5kZWZpbmVkKVxuXG4gICAgaG9zdGVkWm9uZXNXaXRoUm9sZS5mb3JFYWNoKCh6b25lKSA9PiB7XG4gICAgICByZXF1ZXN0b3JGdW5jdGlvbi5hZGRUb1JvbGVQb2xpY3koXG4gICAgICAgIG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgICBlZmZlY3Q6IGlhbS5FZmZlY3QuQUxMT1csXG4gICAgICAgICAgYWN0aW9uczogWydzdHM6QXNzdW1lUm9sZSddLFxuICAgICAgICAgIHJlc291cmNlczogW3pvbmUudmFsaWRhdGlvblJvbGUhLnJvbGVBcm5dLFxuICAgICAgICB9KVxuICAgICAgKVxuICAgIH0pXG5cbiAgICBob3N0ZWRab25lc1dpdGhvdXRSb2xlLmZvckVhY2goKHpvbmUpID0+IHtcbiAgICAgIHJlcXVlc3RvckZ1bmN0aW9uLmFkZFRvUm9sZVBvbGljeShcbiAgICAgICAgbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICAgIGFjdGlvbnM6IFsncm91dGU1MzpHZXRDaGFuZ2UnXSxcbiAgICAgICAgICByZXNvdXJjZXM6IFsnKiddLFxuICAgICAgICB9KVxuICAgICAgKVxuICAgICAgY29uc3QgZG9tYWluTmFtZXMgPSBkb21haW5zVG9ab25lc1t6b25lLmhvc3RlZFpvbmUuem9uZU5hbWVdXG4gICAgICBpZiAoZG9tYWluTmFtZXMgJiYgZG9tYWluTmFtZXMubGVuZ3RoID4gMCkge1xuICAgICAgICByZXF1ZXN0b3JGdW5jdGlvbi5hZGRUb1JvbGVQb2xpY3koXG4gICAgICAgICAgbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICAgICAgYWN0aW9uczogWydyb3V0ZTUzOkNoYW5nZVJlc291cmNlUmVjb3JkU2V0cyddLFxuICAgICAgICAgICAgcmVzb3VyY2VzOiBbYGFybjphd3M6cm91dGU1Mzo6Omhvc3RlZHpvbmUvJHt0aGlzLm5vcm1hbGl6ZUhvc3RlZFpvbmVJZCh6b25lLmhvc3RlZFpvbmUuaG9zdGVkWm9uZUlkKX1gXSxcbiAgICAgICAgICAgIGNvbmRpdGlvbnM6IHtcbiAgICAgICAgICAgICAgJ0ZvckFsbFZhbHVlczpTdHJpbmdFcXVhbHMnOiB7XG4gICAgICAgICAgICAgICAgJ3JvdXRlNTM6Q2hhbmdlUmVzb3VyY2VSZWNvcmRTZXRzUmVjb3JkVHlwZXMnOiBbJ0NOQU1FJ10sXG4gICAgICAgICAgICAgICAgJ3JvdXRlNTM6Q2hhbmdlUmVzb3VyY2VSZWNvcmRTZXRzQWN0aW9ucyc6IFsnVVBTRVJUJywgJ0RFTEVURSddLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAnRm9yQWxsVmFsdWVzOlN0cmluZ0xpa2UnOiB7XG4gICAgICAgICAgICAgICAgJ3JvdXRlNTM6Q2hhbmdlUmVzb3VyY2VSZWNvcmRTZXRzTm9ybWFsaXplZFJlY29yZE5hbWVzJzogZG9tYWluTmFtZXMubWFwKChuYW1lLCBpbmRleCkgPT4ge1xuICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMud2lsZGNhcmREb21haW5OYW1lKGBEb21haW5XaWxkY2FyZCR7em9uZS5ob3N0ZWRab25lLm5vZGUuaWR9JHtpbmRleH1gLCBuYW1lKVxuICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9KVxuICAgICAgICApXG4gICAgICB9XG4gICAgfSlcblxuICAgIGNvbnN0IHJlcXVlc3RvclByb3ZpZGVyID0gbmV3IGN1c3RvbV9yZXNvdXJjZXMuUHJvdmlkZXIodGhpcywgJ1JlcXVlc3RvclByb3ZpZGVyJywge1xuICAgICAgb25FdmVudEhhbmRsZXI6IHJlcXVlc3RvckZ1bmN0aW9uLFxuICAgIH0pXG5cbiAgICBjb25zdCB2YWxpZGF0aW9uSG9zdGVkWm9uZXMgPSBwcm9wcy52YWxpZGF0aW9uSG9zdGVkWm9uZXMubWFwPFtzdHJpbmcsIFZhbGlkYXRpb25Ib3N0ZWRab25lUHJvcGVydGllc10+KCh6b25lKSA9PiB7XG4gICAgICBjb25zdCBwcm9wZXJ0aWVzOiBWYWxpZGF0aW9uSG9zdGVkWm9uZVByb3BlcnRpZXMgPSB7XG4gICAgICAgIERvbWFpbk5hbWU6IHRoaXMubm9ybWFsaXplRG9tYWluTmFtZSh6b25lLmhvc3RlZFpvbmUuem9uZU5hbWUpLFxuICAgICAgICBIb3N0ZWRab25lSWQ6IHRoaXMubm9ybWFsaXplSG9zdGVkWm9uZUlkKHpvbmUuaG9zdGVkWm9uZS5ob3N0ZWRab25lSWQpLFxuICAgICAgICBWYWxpZGF0aW9uUm9sZUFybjogem9uZS52YWxpZGF0aW9uUm9sZT8ucm9sZUFybixcbiAgICAgICAgVmFsaWRhdGlvbkV4dGVybmFsSWQ6IHpvbmUudmFsaWRhdGlvbkV4dGVybmFsSWQsXG4gICAgICB9XG4gICAgICByZXR1cm4gW3Byb3BlcnRpZXMuRG9tYWluTmFtZSwgcHJvcGVydGllc11cbiAgICB9KVxuXG4gICAgY29uc3QgcHJvcGVydGllczogUHJvcGVydGllcyA9IHtcbiAgICAgIERvbWFpbk5hbWU6IGRvbWFpbk5hbWUsXG4gICAgICBBbHRlcm5hdGl2ZURvbWFpbk5hbWVzOiBhbHRlcm5hdGl2ZURvbWFpbk5hbWVzLFxuICAgICAgVmFsaWRhdGlvbkhvc3RlZFpvbmVzOiBPYmplY3QuZnJvbUVudHJpZXModmFsaWRhdGlvbkhvc3RlZFpvbmVzKSxcbiAgICAgIENlcnRpZmljYXRlUmVnaW9uOiB0aGlzLmNlcnRpZmljYXRlUmVnaW9uLFxuICAgICAgQ2xlYW51cFZhbGlkYXRpb25SZWNvcmRzOiBib29sZWFuVG9TdHJpbmcocHJvcHMuY2xlYW51cFZhbGlkYXRpb25SZWNvcmRzID8/IHRydWUpLFxuICAgICAgVHJhbnNwYXJlbmN5TG9nZ2luZ0VuYWJsZWQ6IGJvb2xlYW5Ub1N0cmluZyhwcm9wcy50cmFuc3BhcmVuY3lMb2dnaW5nRW5hYmxlZCA/PyB0cnVlKSxcbiAgICAgIFRhZ3M6IGNkay5MYXp5LmFueSh7IHByb2R1Y2U6ICgpID0+IHRoaXMudGFncy5yZW5kZXJUYWdzKCkgfSkgYXMgdW5rbm93biBhcyBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+LFxuICAgICAgUmVtb3ZhbFBvbGljeTogY2RrLkxhenkuc3RyaW5nKHsgcHJvZHVjZTogKCkgPT4gdGhpcy5yZW1vdmFsUG9saWN5IH0pLFxuICAgIH1cblxuICAgIGNvbnN0IGNlcnRpZmljYXRlID0gbmV3IGNkay5DdXN0b21SZXNvdXJjZSh0aGlzLCAnUmVxdWVzdG9yUmVzb3VyY2UnLCB7XG4gICAgICBzZXJ2aWNlVG9rZW46IHJlcXVlc3RvclByb3ZpZGVyLnNlcnZpY2VUb2tlbixcbiAgICAgIHJlc291cmNlVHlwZTogRE5TX1ZBTElEQVRFRF9DRVJUSUZJQ0FURV9UWVBFLFxuICAgICAgcHJvcGVydGllcyxcbiAgICB9KVxuXG4gICAgLy8gRW5zdXJlIENsb3VkRm9ybWF0aW9uIGRlbGV0ZXMgdGhlIGN1c3RvbSByZXNvdXJjZSBiZWZvcmUgdGhlIExhbWJkYVxuICAgIC8vIGZ1bmN0aW9uIGFuZCBpdHMgSUFNIHBvbGljaWVzLiBDbG91ZEZvcm1hdGlvbiBtYXkgZGVsZXRlIHRoZW0gaW5cbiAgICAvLyBwYXJhbGxlbCBkdXJpbmcgc3RhY2sgZGVsZXRpb24sIGNhdXNpbmcgdGhlIERFTEVURSBoYW5kbGVyIHRvIGZhaWxcbiAgICAvLyBiZWNhdXNlIHRoZSBMYW1iZGEncyBBQ00gcGVybWlzc2lvbnMgaGF2ZSBhbHJlYWR5IGJlZW4gcmVtb3ZlZC5cbiAgICBjZXJ0aWZpY2F0ZS5ub2RlLmFkZERlcGVuZGVuY3kocmVxdWVzdG9yRnVuY3Rpb24pXG4gICAgaWYgKHJlcXVlc3RvckZ1bmN0aW9uLnJvbGUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgY2VydGlmaWNhdGUubm9kZS5hZGREZXBlbmRlbmN5KHJlcXVlc3RvckZ1bmN0aW9uLnJvbGUpXG4gICAgICBjb25zdCBwb2xpY3kgPSByZXF1ZXN0b3JGdW5jdGlvbi5yb2xlLm5vZGUudHJ5RmluZENoaWxkKCdEZWZhdWx0UG9saWN5JylcbiAgICAgIGlmIChwb2xpY3kgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBjZXJ0aWZpY2F0ZS5ub2RlLmFkZERlcGVuZGVuY3kocG9saWN5KVxuICAgICAgfVxuICAgIH1cblxuICAgIHRoaXMuY2VydGlmaWNhdGVBcm4gPSBjZXJ0aWZpY2F0ZS5nZXRBdHRTdHJpbmcoJ0FybicpXG5cbiAgICB0aGlzLm5vZGUuYWRkVmFsaWRhdGlvbih7XG4gICAgICB2YWxpZGF0ZTogKCkgPT5cbiAgICAgICAgdGhpcy52YWxpZGF0ZURvbWFpbnNUb0hvc3RlZFpvbmVzKFxuICAgICAgICAgIGFsbERvbWFpbnMsXG4gICAgICAgICAgdmFsaWRhdGlvbkhvc3RlZFpvbmVzLm1hcCgoW3pvbmVOYW1lLCBfXSkgPT4gem9uZU5hbWUpXG4gICAgICAgICksXG4gICAgfSlcbiAgfVxuXG4gIG1ldHJpY0RheXNUb0V4cGlyeShwcm9wcz86IGNkay5hd3NfY2xvdWR3YXRjaC5NZXRyaWNPcHRpb25zIHwgdW5kZWZpbmVkKTogY2RrLmF3c19jbG91ZHdhdGNoLk1ldHJpYyB7XG4gICAgcmV0dXJuIG5ldyBjbG91ZHdhdGNoLk1ldHJpYyh7XG4gICAgICBwZXJpb2Q6IGNkay5EdXJhdGlvbi5kYXlzKDEpLFxuICAgICAgLi4ucHJvcHMsXG4gICAgICBkaW1lbnNpb25zTWFwOiB7IENlcnRpZmljYXRlQXJuOiB0aGlzLmNlcnRpZmljYXRlQXJuIH0sXG4gICAgICBtZXRyaWNOYW1lOiAnRGF5c1RvRXhwaXJ5JyxcbiAgICAgIG5hbWVzcGFjZTogJ0FXUy9DZXJ0aWZpY2F0ZU1hbmFnZXInLFxuICAgICAgcmVnaW9uOiB0aGlzLmNlcnRpZmljYXRlUmVnaW9uLFxuICAgICAgc3RhdGlzdGljOiBjbG91ZHdhdGNoLlN0YXRzLk1JTklNVU0sXG4gICAgfSlcbiAgfVxuXG4gIGFwcGx5UmVtb3ZhbFBvbGljeShwb2xpY3k6IGNkay5SZW1vdmFsUG9saWN5KTogdm9pZCB7XG4gICAgdGhpcy5yZW1vdmFsUG9saWN5ID0gcG9saWN5XG4gIH1cblxuICAvLyBjZXJ0aWZpY2F0ZVJlZiBpcyBhIHJlcXVpcmVkIHByb3BlcnR5IG9mIHR5cGUgY2VydGlmaWNhdGVtYW5hZ2VyLklDZXJ0aWZpY2F0ZVJlZiBvbiBjZXJ0aWZpY2F0ZW1hbmFnZXIuSUNlcnRpZmljYXRlIHNpbmNlIGF3cy1jZGstbGliIDIuMzUuMFxuICAvLyBXZSB1c2UgdHlwZSBhbnkgaGVyZSB0byBrZWVwIGNvbXBhdGFiaWxpdHkgd2l0aCBvbGRlciBDREsgdmVyc2lvbnNcbiAgLyoqIEEgcmVmZXJlbmNlIHRvIGEgQ2VydGlmaWNhdGUgcmVzb3VyY2UuICovXG4gIHB1YmxpYyBnZXQgY2VydGlmaWNhdGVSZWYoKTogYW55IHtcbiAgICByZXR1cm4ge1xuICAgICAgY2VydGlmaWNhdGVJZDogdGhpcy5jZXJ0aWZpY2F0ZUFybixcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIG5vcm1hbGl6ZURvbWFpbk5hbWUoZG9tYWluTmFtZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBpZiAoY2RrLlRva2VuLmlzVW5yZXNvbHZlZChkb21haW5OYW1lKSkge1xuICAgICAgcmV0dXJuIGRvbWFpbk5hbWVcbiAgICB9XG4gICAgcmV0dXJuIGNsZWFuRG9tYWluTmFtZShkb21haW5OYW1lKVxuICB9XG5cbiAgcHJpdmF0ZSBub3JtYWxpemVIb3N0ZWRab25lSWQoaG9zdGVkWm9uZUlkOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGlmIChjZGsuVG9rZW4uaXNVbnJlc29sdmVkKGhvc3RlZFpvbmVJZCkpIHtcbiAgICAgIHJldHVybiBob3N0ZWRab25lSWRcbiAgICB9XG4gICAgcmV0dXJuIGNsZWFuSG9zdGVkWm9uZUlkKGhvc3RlZFpvbmVJZClcbiAgfVxuXG4gIHByaXZhdGUgd2lsZGNhcmREb21haW5OYW1lKGlkOiBzdHJpbmcsIGRvbWFpbk5hbWU6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgY29uc3QgcGFydHMgPSBjZGsuRm4uc3BsaXQoJy4nLCBkb21haW5OYW1lKVxuICAgIGNvbnN0IGZpcnN0ID0gY2RrLkZuLnNlbGVjdCgwLCBwYXJ0cylcbiAgICBjb25zdCBpc1dpbGRjYXJkID0gbmV3IGNkay5DZm5Db25kaXRpb24odGhpcywgYElzJHtpZH1gLCB7XG4gICAgICBleHByZXNzaW9uOiBjZGsuRm4uY29uZGl0aW9uRXF1YWxzKGZpcnN0LCAnKicpLFxuICAgIH0pXG4gICAgcmV0dXJuIGNkay5Gbi5jb25kaXRpb25JZihpc1dpbGRjYXJkLmxvZ2ljYWxJZCwgZG9tYWluTmFtZSwgYCouJHtkb21haW5OYW1lfWApLnRvU3RyaW5nKClcbiAgfVxuXG4gIHByaXZhdGUgdmFsaWRhdGVEb21haW5zVG9Ib3N0ZWRab25lcyhkb21haW5OYW1lczogc3RyaW5nW10sIHpvbmVOYW1lczogc3RyaW5nW10pOiBzdHJpbmdbXSB7XG4gICAgY29uc3QgZXJyb3JzOiBzdHJpbmdbXSA9IFtdXG4gICAgZm9yIChjb25zdCBkb21haW5OYW1lIG9mIGRvbWFpbk5hbWVzKSB7XG4gICAgICBjb25zdCByZXNvbHZhYmxlRG9tYWluTmFtZSA9ICFjZGsuVG9rZW4uaXNVbnJlc29sdmVkKGRvbWFpbk5hbWUpXG4gICAgICBjb25zdCByZXNvbHZhYmxlWm9uZU5hbWVzID0gIXpvbmVOYW1lcy5zb21lKCh6b25lTmFtZSkgPT4gY2RrLlRva2VuLmlzVW5yZXNvbHZlZCh6b25lTmFtZSkpXG4gICAgICBpZiAocmVzb2x2YWJsZURvbWFpbk5hbWUgJiYgcmVzb2x2YWJsZVpvbmVOYW1lcyAmJiAhem9uZU5hbWVzLnNvbWUoKHpvbmVOYW1lKSA9PiBkb21haW5OYW1lLmVuZHNXaXRoKHpvbmVOYW1lKSkpIHtcbiAgICAgICAgZXJyb3JzLnB1c2goYERvbWFpbiAke2RvbWFpbk5hbWV9IGlzIG5vdCBwcm92aWRlZCB3aXRoIGF1dGhvcml0YXRpdmUgaG9zdGVkIHpvbmVgKVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gZXJyb3JzXG4gIH1cbn1cbiJdfQ==
package/package.json CHANGED
@@ -59,11 +59,11 @@
59
59
  "eslint-plugin-prettier": "^4.2.5",
60
60
  "jest": "^29.7.0",
61
61
  "jest-junit": "^16",
62
- "jsii": "~5.8.0",
62
+ "jsii": "~5.9.0",
63
63
  "jsii-diff": "^1.126.0",
64
64
  "jsii-docgen": "^10.5.0",
65
65
  "jsii-pacmak": "^1.126.0",
66
- "jsii-rosetta": "~5.8.0",
66
+ "jsii-rosetta": "~5.9.0",
67
67
  "prettier": "^2.8.8",
68
68
  "projen": "^0.99.16",
69
69
  "ts-jest": "^29.4.6",
@@ -87,7 +87,7 @@
87
87
  "publishConfig": {
88
88
  "access": "public"
89
89
  },
90
- "version": "0.1.39",
90
+ "version": "0.1.41",
91
91
  "jest": {
92
92
  "coverageProvider": "v8",
93
93
  "testMatch": [