token-injectable-docker-builder 1.9.0 → 1.11.0

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
@@ -8536,7 +8536,7 @@
8536
8536
  },
8537
8537
  "name": "token-injectable-docker-builder",
8538
8538
  "readme": {
8539
- "markdown": "# TokenInjectableDockerBuilder\n\nThe `TokenInjectableDockerBuilder` is a flexible AWS CDK construct that enables the usage of AWS CDK tokens in the building, pushing, and deployment of Docker images to Amazon Elastic Container Registry (ECR). It leverages AWS CodeBuild and Lambda custom resources.\n\n---\n\n## Why?\n\nAWS CDK already provides mechanisms for creating deployable assets using Docker, such as [DockerImageAsset](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ecr_assets.DockerImageAsset.html) and [DockerImageCode](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda.DockerImageCode.html), but these constructs are limited because they cannot accept CDK tokens as build-args. The `TokenInjectableDockerBuilder` allows injecting CDK tokens as build-time arguments into Docker-based assets, enabling more dynamic dependency relationships.\n\nFor example, a Next.js frontend Docker image may require an API Gateway URL as an argument to create a reference from the UI to the associated API in a given deployment. With this construct, you can deploy the API Gateway first, then pass its URL as a build-time argument to the Next.js Docker image. As a result, your Next.js frontend can dynamically fetch data from the API Gateway without hardcoding the URL or needing multiple separate stacks.\n\n---\n\n## Features\n\n- **Build and Push Docker Images**: Automatically builds and pushes Docker images to ECR.\n- **Token Support**: Supports custom build arguments for Docker builds, including CDK tokens resolved at deployment time.\n- **Shared Provider (Singleton)**: When building multiple Docker images in the same stack, use `TokenInjectableDockerBuilderProvider` to share a single pair of Lambda functions across all builders, reducing resource overhead from ~2 Lambdas per image to 2 Lambdas total.\n- **Custom Install and Pre-Build Commands**: Allows specifying custom commands to run during the `install` and `pre_build` phases of the CodeBuild build process.\n- **VPC Configuration**: Supports deploying the CodeBuild project within a VPC, with customizable security groups and subnet selection.\n- **Docker Login**: Supports Docker login using credentials stored in AWS Secrets Manager.\n- **ECR Repository Management**: Creates an ECR repository with lifecycle rules and encryption.\n- **Integration with ECS and Lambda**: Provides outputs for use in AWS ECS and AWS Lambda.\n- **Custom Build Query Interval**: Configure how frequently the custom resource polls for build completion using the `completenessQueryInterval` property (defaults to 30 seconds).\n- **Custom Dockerfile**: Specify a custom Dockerfile name via the `file` property (e.g. `Dockerfile.production`), allowing multiple Docker images from the same source directory.\n- **ECR Docker Layer Caching**: By default, builds use `docker buildx` with ECR as a remote cache backend, reducing build times by reusing layers across deploys. Set `cacheDisabled: true` to force a clean build from scratch.\n- **Persistent Build Logs**: Pass `buildLogGroup` with a log group that has RETAIN removal policy so build logs survive rollbacks and stack deletion for debugging.\n\n---\n\n## Installation\n\n### For NPM\n\nInstall the construct using NPM:\n\n```bash\nnpm install token-injectable-docker-builder\n```\n\n### For Python\n\nInstall the construct using pip:\n\n```bash\npip install token-injectable-docker-builder\n```\n\n---\n\n## API Reference\n\n### `TokenInjectableDockerBuilderProvider`\n\nA singleton construct that creates the `onEvent` and `isComplete` Lambda functions once per stack. When building multiple Docker images, share a single provider to avoid creating redundant Lambda functions.\n\n#### Static Methods\n\n| Method | Description |\n|---|---|\n| `getOrCreate(scope, props?)` | Returns the existing provider for the stack, or creates one if it doesn't exist. |\n\n#### Properties in `TokenInjectableDockerBuilderProviderProps`\n\n| Property | Type | Required | Description |\n|---|---|---|---|\n| `queryInterval` | `Duration` | No | How often the provider polls for build completion. Defaults to `Duration.seconds(30)`. |\n\n#### Instance Properties\n\n| Property | Type | Description |\n|---|---|---|\n| `serviceToken` | `string` | The service token used by CustomResource instances. |\n\n#### Instance Methods\n\n| Method | Description |\n|---|---|\n| `registerProject(project, ecrRepo, encryptionKey?)` | Grants the shared Lambdas permission to start builds and access ECR for a specific CodeBuild project. Called automatically when `provider` is passed to `TokenInjectableDockerBuilder`. |\n\n---\n\n### `TokenInjectableDockerBuilder`\n\n#### Parameters\n\n- **`scope`**: The construct's parent scope.\n- **`id`**: The construct ID.\n- **`props`**: Configuration properties.\n\n#### Properties in `TokenInjectableDockerBuilderProps`\n\n| Property | Type | Required | Description |\n|----------------------------|-----------------------------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `path` | `string` | Yes | The file path to the Dockerfile or source code directory. |\n| `buildArgs` | `{ [key: string]: string }` | No | Build arguments to pass to the Docker build process. These are transformed into `--build-arg` flags. To use in Dockerfile, leverage the `ARG` keyword. For more details, please see the [official Docker docs](https://docs.docker.com/build/building/variables/). |\n| `provider` | `TokenInjectableDockerBuilderProvider` | No | Shared provider for the custom resource Lambdas. Use `TokenInjectableDockerBuilderProvider.getOrCreate(this)` to share a single pair of Lambdas across all builders in the same stack. When omitted, each builder creates its own Lambdas (original behavior). |\n| `dockerLoginSecretArn` | `string` | No | ARN of an AWS Secrets Manager secret for Docker credentials. Skips login if not provided. |\n| `vpc` | `IVpc` | No | The VPC in which the CodeBuild project will be deployed. If provided, the CodeBuild project will be launched within the specified VPC. |\n| `securityGroups` | `ISecurityGroup[]` | No | The security groups to attach to the CodeBuild project. These should define the network access rules for the CodeBuild project. |\n| `subnetSelection` | `SubnetSelection` | No | The subnet selection to specify which subnets to use within the VPC. Allows the user to select private, public, or isolated subnets. |\n| `installCommands` | `string[]` | No | Custom commands to run during the `install` phase of the CodeBuild build process. Will be executed before the Docker image is built. Useful for installing necessary dependencies for running pre-build scripts. |\n| `preBuildCommands` | `string[]` | No | Custom commands to run during the `pre_build` phase of the CodeBuild build process. Will be executed before the Docker image is built. Useful for running pre-build scripts, such as fetching configs. |\n| `kmsEncryption` | `boolean` | No | Whether to enable KMS encryption for the ECR repository. If `true`, a KMS key will be created for encrypting ECR images; otherwise, AES-256 encryption is used. Defaults to `false`. |\n| `completenessQueryInterval`| `Duration` | No | The query interval for checking if the CodeBuild project has completed. This determines how frequently the custom resource polls for build completion. Defaults to `Duration.seconds(30)`. Ignored when `provider` is set (the provider's `queryInterval` is used instead). |\n| `exclude` | `string[]` | No | A list of file paths in the Docker directory to exclude from the S3 asset bundle. If a `.dockerignore` file is present in the source directory, its contents will be used if this prop is not set. Defaults to an empty list or `.dockerignore` contents. |\n| `file` | `string` | No | The name of the Dockerfile to use for the build. Passed as `--file` to `docker build`. Useful when a project has multiple Dockerfiles (e.g. `Dockerfile.production`, `Dockerfile.admin`). Defaults to `Dockerfile`. |\n| `cacheDisabled` | `boolean` | No | When `true`, disables Docker layer caching. Every build runs from scratch. Use for debugging, corrupted cache, or major dependency changes. Defaults to `false`. |\n| `buildLogGroup` | `ILogGroup` | No | CloudWatch log group for CodeBuild build logs. When provided with RETAIN removal policy, logs survive rollbacks and stack deletion. If not provided, CodeBuild uses default logging (logs are deleted on rollback). |\n\n#### Instance Properties\n\n| Property | Type | Description |\n|---|---|---|\n| `containerImage` | `ContainerImage` | An ECS-compatible container image referencing the built Docker image. |\n| `dockerImageCode` | `DockerImageCode` | A Lambda-compatible Docker image code referencing the built Docker image. |\n\n---\n\n## Usage Examples\n\n### Shared Provider (Recommended for Multiple Images)\n\nWhen building multiple Docker images in the same stack, use a shared provider to avoid creating redundant Lambda functions. Without a shared provider, each builder creates 2 Lambdas + 1 Provider framework Lambda. With 10 images, that's 30 Lambdas. A shared provider reduces this to just 3 Lambdas total.\n\n#### TypeScript/NPM Example\n\n```typescript\nimport * as cdk from 'aws-cdk-lib';\nimport {\n TokenInjectableDockerBuilder,\n TokenInjectableDockerBuilderProvider,\n} from 'token-injectable-docker-builder';\nimport * as ecs from 'aws-cdk-lib/aws-ecs';\n\nexport class MultiImageStack extends cdk.Stack {\n constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {\n super(scope, id, props);\n\n // Create a shared provider once per stack (singleton)\n const provider = TokenInjectableDockerBuilderProvider.getOrCreate(this);\n\n // Build multiple Docker images sharing the same provider\n const apiBuilder = new TokenInjectableDockerBuilder(this, 'ApiImage', {\n path: './src/api',\n provider,\n });\n\n const workerBuilder = new TokenInjectableDockerBuilder(this, 'WorkerImage', {\n path: './src/worker',\n provider,\n });\n\n const frontendBuilder = new TokenInjectableDockerBuilder(this, 'FrontendImage', {\n path: './src/frontend',\n buildArgs: { API_URL: 'https://api.example.com' },\n provider,\n });\n\n // Use in ECS task definitions\n const taskDef = new ecs.FargateTaskDefinition(this, 'TaskDef');\n taskDef.addContainer('api', { image: apiBuilder.containerImage });\n taskDef.addContainer('worker', { image: workerBuilder.containerImage });\n }\n}\n```\n\n#### Python Example\n\n```python\nfrom aws_cdk import aws_ecs as ecs, core as cdk\nfrom token_injectable_docker_builder import (\n TokenInjectableDockerBuilder,\n TokenInjectableDockerBuilderProvider,\n)\n\nclass MultiImageStack(cdk.Stack):\n def __init__(self, scope: cdk.App, id: str, **kwargs):\n super().__init__(scope, id, **kwargs)\n\n # Create a shared provider once per stack (singleton)\n provider = TokenInjectableDockerBuilderProvider.get_or_create(self)\n\n # Build multiple Docker images sharing the same provider\n api_builder = TokenInjectableDockerBuilder(self, \"ApiImage\",\n path=\"./src/api\",\n provider=provider,\n )\n\n worker_builder = TokenInjectableDockerBuilder(self, \"WorkerImage\",\n path=\"./src/worker\",\n provider=provider,\n )\n\n frontend_builder = TokenInjectableDockerBuilder(self, \"FrontendImage\",\n path=\"./src/frontend\",\n build_args={\"API_URL\": \"https://api.example.com\"},\n provider=provider,\n )\n```\n\n### Simple Usage Example\n\nThis example demonstrates the basic usage of the `TokenInjectableDockerBuilder`, where a Next.js frontend Docker image requires an API Gateway URL as a build argument to create a reference from the UI to the associated API in a given deployment.\n\n#### TypeScript/NPM Example\n\n```typescript\nimport * as cdk from 'aws-cdk-lib';\nimport { TokenInjectableDockerBuilder } from 'token-injectable-docker-builder';\nimport * as ecs from 'aws-cdk-lib/aws-ecs';\nimport * as ec2 from 'aws-cdk-lib/aws-ec2';\nimport * as apigateway from 'aws-cdk-lib/aws-apigateway';\n\nexport class SimpleStack extends cdk.Stack {\n constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {\n super(scope, id, props);\n\n // Create your API Gateway\n const api = new apigateway.RestApi(this, 'MyApiGateway', {\n restApiName: 'MyService',\n });\n\n // Create the Docker builder\n const dockerBuilder = new TokenInjectableDockerBuilder(this, 'SimpleDockerBuilder', {\n path: './nextjs-app', // Path to your Next.js app Docker context\n buildArgs: {\n API_URL: api.url, // Pass the API Gateway URL as a build argument\n },\n // Optionally override the default completeness query interval:\n // completenessQueryInterval: cdk.Duration.seconds(45),\n });\n\n // Use in ECS\n const cluster = new ecs.Cluster(this, 'EcsCluster', {\n vpc: new ec2.Vpc(this, 'Vpc'),\n });\n\n const service = new ecs.FargateService(this, 'FargateService', {\n cluster,\n taskDefinition: new ecs.FargateTaskDefinition(this, 'TaskDef', {\n cpu: 512,\n memoryLimitMiB: 1024,\n }).addContainer('Container', {\n image: dockerBuilder.containerImage,\n logging: ecs.LogDriver.awsLogs({ streamPrefix: 'MyApp' }),\n }),\n });\n\n service.node.addDependency(dockerBuilder);\n }\n}\n```\n\n#### Python Example\n\n```python\nfrom aws_cdk import (\n aws_ecs as ecs,\n aws_ec2 as ec2,\n aws_apigateway as apigateway,\n Duration,\n core as cdk,\n)\nfrom token_injectable_docker_builder import TokenInjectableDockerBuilder\n\nclass SimpleStack(cdk.Stack):\n\n def __init__(self, scope: cdk.App, id: str, **kwargs):\n super().__init__(scope, id, **kwargs)\n\n # Create your API Gateway\n api = apigateway.RestApi(self, \"MyApiGateway\",\n rest_api_name=\"MyService\",\n )\n\n # Create the Docker builder\n docker_builder = TokenInjectableDockerBuilder(self, \"SimpleDockerBuilder\",\n path=\"./nextjs-app\", # Path to your Next.js app Docker context\n build_args={\n \"API_URL\": api.url, # Pass the API Gateway URL as a build argument\n },\n # Optionally override the default completeness query interval:\n # completeness_query_interval=Duration.seconds(45)\n )\n\n # Use in ECS\n vpc = ec2.Vpc(self, \"Vpc\")\n cluster = ecs.Cluster(self, \"EcsCluster\", vpc=vpc)\n\n task_definition = ecs.FargateTaskDefinition(self, \"TaskDef\",\n cpu=512,\n memory_limit_mib=1024,\n )\n\n task_definition.node.add_dependency(docker_builder)\n\n task_definition.add_container(\"Container\",\n image=docker_builder.container_image,\n logging=ecs.LogDriver.aws_logs(stream_prefix=\"MyApp\"),\n )\n\n ecs.FargateService(self, \"FargateService\",\n cluster=cluster,\n task_definition=task_definition,\n )\n```\n\n---\n\n### Advanced Usage Example\n\nBuilding on the previous example, this advanced usage demonstrates how to include additional configurations, such as fetching private API endpoints and configuration files during the build process.\n\n#### TypeScript/NPM Example\n\n```typescript\nimport * as cdk from 'aws-cdk-lib';\nimport { TokenInjectableDockerBuilder } from 'token-injectable-docker-builder';\nimport * as ecs from 'aws-cdk-lib/aws-ecs';\nimport * as ec2 from 'aws-cdk-lib/aws-ec2';\nimport * as apigateway from 'aws-cdk-lib/aws-apigateway';\n\nexport class AdvancedStack extends cdk.Stack {\n constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {\n super(scope, id, props);\n\n // Create your API Gateway\n const api = new apigateway.RestApi(this, 'MyApiGateway', {\n restApiName: 'MyService',\n });\n\n // VPC and Security Group for CodeBuild\n const vpc = new ec2.Vpc(this, 'MyVpc');\n const securityGroup = new ec2.SecurityGroup(this, 'MySecurityGroup', {\n vpc,\n });\n\n // Create the Docker builder with additional pre-build commands\n const dockerBuilder = new TokenInjectableDockerBuilder(this, 'AdvancedDockerBuilder', {\n path: './nextjs-app',\n buildArgs: {\n API_URL: api.url,\n },\n vpc,\n securityGroups: [securityGroup],\n subnetSelection: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS },\n installCommands: [\n 'echo \"Updating package lists...\"',\n 'apt-get update -y',\n 'echo \"Installing necessary packages...\"',\n 'apt-get install -y curl',\n ],\n preBuildCommands: [\n 'echo \"Fetching private API configuration...\"',\n // Replace with your actual command to fetch configs\n 'curl -o config.json https://internal-api.example.com/config',\n ],\n // Optionally override the default completeness query interval:\n // completenessQueryInterval: cdk.Duration.seconds(45),\n });\n\n // Use in ECS\n const cluster = new ecs.Cluster(this, 'EcsCluster', { vpc });\n\n const service = new ecs.FargateService(this, 'FargateService', {\n cluster,\n taskDefinition: new ecs.FargateTaskDefinition(this, 'TaskDef', {\n cpu: 512,\n memoryLimitMiB: 1024,\n }).addContainer('Container', {\n image: dockerBuilder.containerImage,\n logging: ecs.LogDriver.awsLogs({ streamPrefix: 'MyApp' }),\n }),\n });\n\n service.node.addDependency(dockerBuilder);\n }\n}\n```\n\n#### Python Example\n\n```python\nfrom aws_cdk import (\n aws_ecs as ecs,\n aws_ec2 as ec2,\n aws_apigateway as apigateway,\n Duration,\n core as cdk,\n)\nfrom token_injectable_docker_builder import TokenInjectableDockerBuilder\n\nclass AdvancedStack(cdk.Stack):\n\n def __init__(self, scope: cdk.App, id: str, **kwargs):\n super().__init__(scope, id, **kwargs)\n\n # Create your API Gateway\n api = apigateway.RestApi(self, \"MyApiGateway\",\n rest_api_name=\"MyService\",\n )\n\n # VPC and Security Group for CodeBuild\n vpc = ec2.Vpc(self, \"MyVpc\")\n security_group = ec2.SecurityGroup(self, \"MySecurityGroup\", vpc=vpc)\n\n # Create the Docker builder with additional pre-build commands\n docker_builder = TokenInjectableDockerBuilder(self, \"AdvancedDockerBuilder\",\n path=\"./nextjs-app\",\n build_args={\n \"API_URL\": api.url,\n },\n vpc=vpc,\n security_groups=[security_group],\n subnet_selection=ec2.SubnetSelection(subnet_type=ec2.SubnetType.PRIVATE_WITH_EGRESS),\n install_commands=[\n 'echo \"Updating package lists...\"',\n 'apt-get update -y',\n 'echo \"Installing necessary packages...\"',\n 'apt-get install -y curl',\n ],\n pre_build_commands=[\n 'echo \"Fetching private API configuration...\"',\n # Replace with your actual command to fetch configs\n 'curl -o config.json https://internal-api.example.com/config',\n ],\n # Optionally override the default completeness query interval:\n # completeness_query_interval=Duration.seconds(45)\n )\n\n # Use in ECS\n cluster = ecs.Cluster(self, \"EcsCluster\", vpc=vpc)\n\n task_definition = ecs.FargateTaskDefinition(self, \"TaskDef\",\n cpu=512,\n memory_limit_mib=1024,\n )\n\n task_definition.node.add_dependency(docker_builder)\n\n task_definition.add_container(\"Container\",\n image=docker_builder.container_image,\n logging=ecs.LogDriver.aws_logs(stream_prefix=\"MyApp\"),\n )\n\n ecs.FargateService(self, \"FargateService\",\n cluster=cluster,\n task_definition=task_definition,\n )\n```\n\nIn this advanced example:\n\n- **VPC Configuration**: The CodeBuild project is configured to run inside a VPC with specified security groups and subnet selection, allowing it to access internal resources such as a private API endpoint.\n- **Custom Install and Pre-Build Commands**: The `installCommands` and `preBuildCommands` properties are used to install necessary packages and fetch configuration files from a private API before building the Docker image.\n- **Access to Internal APIs**: By running inside a VPC and configuring the security groups appropriately, the CodeBuild project can access private endpoints not accessible over the public internet.\n\n---\n\n## How It Works\n\n1. **Docker Source**: Packages the source code or Dockerfile specified in the `path` property as an S3 asset.\n2. **CodeBuild Project**:\n - Uses the packaged asset and `buildArgs` to build the Docker image.\n - Executes any custom `installCommands` and `preBuildCommands` during the build process.\n - Pushes the image to an ECR repository.\n - By default, uses `docker buildx` with ECR registry cache to speed up builds.\n3. **Custom Resource**:\n - Triggers the build process using a Lambda function (`onEvent`).\n - Monitors the build status using another Lambda function (`isComplete`) which polls at the interval specified by `completenessQueryInterval` (defaulting to 30 seconds if not provided).\n - When using a shared `provider`, the same pair of Lambdas handles all builders in the stack.\n4. **Outputs**:\n - `.containerImage`: Returns the Docker image for ECS.\n - `.dockerImageCode`: Returns the Docker image code for Lambda.\n\n### Resource Comparison\n\n| Scenario | Lambdas Created | CodeBuild Projects | ECR Repos |\n|---|---|---|---|\n| 5 images, no shared provider | 15 (3 per image) | 5 | 5 |\n| 5 images, shared provider | 3 (shared) | 5 | 5 |\n| 10 images, no shared provider | 30 (3 per image) | 10 | 10 |\n| 10 images, shared provider | 3 (shared) | 10 | 10 |\n\n---\n\n## IAM Permissions\n\nThe construct automatically grants permissions for:\n\n- **CodeBuild**:\n - Pull and push images to ECR.\n - Access to AWS Secrets Manager if `dockerLoginSecretArn` is provided.\n - Access to the KMS key for encryption.\n- **Lambda Functions** (per-instance or shared provider):\n - Start and monitor CodeBuild builds.\n - Access CloudWatch Logs.\n - Access to the KMS key for encryption.\n - Pull and push images to ECR.\n\nWhen using the shared provider, `registerProject()` incrementally adds IAM permissions for each CodeBuild project and ECR repository.\n\n---\n\n## Notes\n\n- **Shared Provider**: Use `TokenInjectableDockerBuilderProvider.getOrCreate(this)` when building multiple images in the same stack. This is the recommended approach for stacks with 2+ Docker images.\n- **Build Arguments**: Pass custom arguments via `buildArgs` as `--build-arg` flags. CDK tokens can be used to inject dynamic values resolved at deployment time.\n- **Custom Commands**: Use `installCommands` and `preBuildCommands` to run custom shell commands during the build process. This can be useful for installing dependencies or fetching configuration files.\n- **VPC Configuration**: If your build process requires access to resources within a VPC, you can specify the VPC, security groups, and subnet selection.\n- **Docker Login**: If you need to log in to a private Docker registry before building the image, provide the ARN of a secret in AWS Secrets Manager containing the Docker credentials.\n- **ECR Repository**: Automatically creates an ECR repository with lifecycle rules to manage image retention, encryption with a KMS key, and image scanning on push.\n- **Build Query Interval**: The polling frequency for checking build completion can be customized via the `completenessQueryInterval` property (per-instance) or `queryInterval` (shared provider).\n- **Custom Dockerfile**: Use the `file` property to specify a Dockerfile other than the default `Dockerfile`. This is passed as the `--file` flag to `docker build`.\n- **Docker Layer Caching**: By default, builds use ECR as a remote cache backend (via `docker buildx`), which can reduce build times by up to 25%. Set `cacheDisabled: true` when you need a clean build—for example, when debugging, the cache is corrupted, or after major dependency upgrades.\n- **Build Log Retention**: Pass `buildLogGroup` with a log group that has RETAIN removal policy to ensure build logs survive CloudFormation rollbacks and stack deletion.\n- **Backward Compatibility**: The `provider` prop is optional. Omitting it preserves the original behavior where each builder creates its own Lambdas. Existing code works without changes.\n\n---\n\n## Troubleshooting\n\n1. **Build Errors**: Check the CodeBuild logs in CloudWatch Logs for detailed error messages. If you pass `buildLogGroup` with RETAIN removal policy, logs persist even after rollbacks. Otherwise, logs are deleted when the CodeBuild project is removed during rollback.\n2. **Lambda Errors**: Check the `onEvent` and `isComplete` Lambda function logs in CloudWatch Logs. With a shared provider, both builders' events flow through the same Lambdas—filter by `ProjectName` in the logs.\n3. **Permissions**: Ensure IAM roles have the required permissions for CodeBuild, ECR, Secrets Manager, and KMS if applicable. When using a shared provider, verify that `registerProject()` was called for each builder (this happens automatically when passing the `provider` prop).\n4. **Network Access**: If the build requires network access (e.g., to download dependencies or access internal APIs), ensure that the VPC configuration allows necessary network connectivity, and adjust security group rules accordingly.\n\n---\n\n## Support\n\nFor issues or feature requests, please open an issue on [GitHub](https://github.com/AlexTech314/TokenInjectableDockerBuilder).\n\n---\n\n## Reference Links\n\n[![View on Construct Hub](https://constructs.dev/badge?package=token-injectable-docker-builder)](https://constructs.dev/packages/token-injectable-docker-builder)\n\n---\n\n## License\n\nThis project is licensed under the terms of the MIT license.\n\n---\n\n## Acknowledgements\n\n- Inspired by the need for more dynamic Docker asset management in AWS CDK.\n- Thanks to the AWS CDK community for their continuous support and contributions.\n\n---\n\nFeel free to reach out if you have any questions or need further assistance!\n"
8539
+ "markdown": "# TokenInjectableDockerBuilder\n\nThe `TokenInjectableDockerBuilder` is a flexible AWS CDK construct that enables the usage of AWS CDK tokens in the building, pushing, and deployment of Docker images to Amazon Elastic Container Registry (ECR). It leverages AWS CodeBuild and Lambda custom resources.\n\n---\n\n## Why?\n\nAWS CDK already provides mechanisms for creating deployable assets using Docker, such as [DockerImageAsset](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_ecr_assets.DockerImageAsset.html) and [DockerImageCode](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda.DockerImageCode.html), but these constructs are limited because they cannot accept CDK tokens as build-args. The `TokenInjectableDockerBuilder` allows injecting CDK tokens as build-time arguments into Docker-based assets, enabling more dynamic dependency relationships.\n\nFor example, a Next.js frontend Docker image may require an API Gateway URL as an argument to create a reference from the UI to the associated API in a given deployment. With this construct, you can deploy the API Gateway first, then pass its URL as a build-time argument to the Next.js Docker image. As a result, your Next.js frontend can dynamically fetch data from the API Gateway without hardcoding the URL or needing multiple separate stacks.\n\n---\n\n## Features\n\n- **Build and Push Docker Images**: Automatically builds and pushes Docker images to ECR.\n- **Token Support**: Supports custom build arguments for Docker builds, including CDK tokens resolved at deployment time.\n- **Shared Provider (Singleton)**: When building multiple Docker images in the same stack, use `TokenInjectableDockerBuilderProvider` to share a single pair of Lambda functions across all builders, reducing resource overhead from ~2 Lambdas per image to 2 Lambdas total.\n- **Custom Install and Pre-Build Commands**: Allows specifying custom commands to run during the `install` and `pre_build` phases of the CodeBuild build process.\n- **VPC Configuration**: Supports deploying the CodeBuild project within a VPC, with customizable security groups and subnet selection.\n- **Docker Login**: Supports Docker login using credentials stored in AWS Secrets Manager.\n- **ECR Repository Management**: Creates an ECR repository with lifecycle rules and encryption.\n- **Integration with ECS and Lambda**: Provides outputs for use in AWS ECS and AWS Lambda.\n- **Custom Build Query Interval**: Configure how frequently the custom resource polls for build completion using the `completenessQueryInterval` property (defaults to 30 seconds).\n- **Custom Dockerfile**: Specify a custom Dockerfile name via the `file` property (e.g. `Dockerfile.production`), allowing multiple Docker images from the same source directory.\n- **ECR Docker Layer Caching**: By default, builds use `docker buildx` with ECR as a remote cache backend, reducing build times by reusing layers across deploys. Set `cacheDisabled: true` to force a clean build from scratch.\n- **Platform Support**: Build images for `linux/amd64` (x86_64) or `linux/arm64` (Graviton) using native CodeBuild instances — no emulation, no QEMU. ARM builds are faster and cheaper.\n- **Persistent Build Logs**: Pass `buildLogGroup` with a log group that has RETAIN removal policy so build logs survive rollbacks and stack deletion for debugging.\n- **ECR Pull-Through Cache**: When your Dockerfile uses base images from ECR pull-through cache (e.g. `docker-hub/library/node:20-slim`, `ghcr/org/image:tag`), pass `ecrPullThroughCachePrefixes` to grant the CodeBuild role pull access to those cache prefixes.\n\n---\n\n## Installation\n\n### For NPM\n\nInstall the construct using NPM:\n\n```bash\nnpm install token-injectable-docker-builder\n```\n\n### For Python\n\nInstall the construct using pip:\n\n```bash\npip install token-injectable-docker-builder\n```\n\n---\n\n## API Reference\n\n### `TokenInjectableDockerBuilderProvider`\n\nA singleton construct that creates the `onEvent` and `isComplete` Lambda functions once per stack. When building multiple Docker images, share a single provider to avoid creating redundant Lambda functions.\n\n#### Static Methods\n\n| Method | Description |\n|---|---|\n| `getOrCreate(scope, props?)` | Returns the existing provider for the stack, or creates one if it doesn't exist. |\n\n#### Properties in `TokenInjectableDockerBuilderProviderProps`\n\n| Property | Type | Required | Description |\n|---|---|---|---|\n| `queryInterval` | `Duration` | No | How often the provider polls for build completion. Defaults to `Duration.seconds(30)`. |\n\n#### Instance Properties\n\n| Property | Type | Description |\n|---|---|---|\n| `serviceToken` | `string` | The service token used by CustomResource instances. |\n\n#### Instance Methods\n\n| Method | Description |\n|---|---|\n| `registerProject(project, ecrRepo, encryptionKey?)` | Grants the shared Lambdas permission to start builds and access ECR for a specific CodeBuild project. Called automatically when `provider` is passed to `TokenInjectableDockerBuilder`. |\n\n---\n\n### `TokenInjectableDockerBuilder`\n\n#### Parameters\n\n- **`scope`**: The construct's parent scope.\n- **`id`**: The construct ID.\n- **`props`**: Configuration properties.\n\n#### Properties in `TokenInjectableDockerBuilderProps`\n\n| Property | Type | Required | Description |\n|----------------------------|-----------------------------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `path` | `string` | Yes | The file path to the Dockerfile or source code directory. |\n| `buildArgs` | `{ [key: string]: string }` | No | Build arguments to pass to the Docker build process. These are transformed into `--build-arg` flags. To use in Dockerfile, leverage the `ARG` keyword. For more details, please see the [official Docker docs](https://docs.docker.com/build/building/variables/). |\n| `provider` | `TokenInjectableDockerBuilderProvider` | No | Shared provider for the custom resource Lambdas. Use `TokenInjectableDockerBuilderProvider.getOrCreate(this)` to share a single pair of Lambdas across all builders in the same stack. When omitted, each builder creates its own Lambdas (original behavior). |\n| `dockerLoginSecretArn` | `string` | No | ARN of an AWS Secrets Manager secret for Docker credentials. Skips login if not provided. |\n| `vpc` | `IVpc` | No | The VPC in which the CodeBuild project will be deployed. If provided, the CodeBuild project will be launched within the specified VPC. |\n| `securityGroups` | `ISecurityGroup[]` | No | The security groups to attach to the CodeBuild project. These should define the network access rules for the CodeBuild project. |\n| `subnetSelection` | `SubnetSelection` | No | The subnet selection to specify which subnets to use within the VPC. Allows the user to select private, public, or isolated subnets. |\n| `installCommands` | `string[]` | No | Custom commands to run during the `install` phase of the CodeBuild build process. Will be executed before the Docker image is built. Useful for installing necessary dependencies for running pre-build scripts. |\n| `preBuildCommands` | `string[]` | No | Custom commands to run during the `pre_build` phase of the CodeBuild build process. Will be executed before the Docker image is built. Useful for running pre-build scripts, such as fetching configs. |\n| `kmsEncryption` | `boolean` | No | Whether to enable KMS encryption for the ECR repository. If `true`, a KMS key will be created for encrypting ECR images; otherwise, AES-256 encryption is used. Defaults to `false`. |\n| `completenessQueryInterval`| `Duration` | No | The query interval for checking if the CodeBuild project has completed. This determines how frequently the custom resource polls for build completion. Defaults to `Duration.seconds(30)`. Ignored when `provider` is set (the provider's `queryInterval` is used instead). |\n| `exclude` | `string[]` | No | A list of file paths in the Docker directory to exclude from the S3 asset bundle. If a `.dockerignore` file is present in the source directory, its contents will be used if this prop is not set. Defaults to an empty list or `.dockerignore` contents. |\n| `file` | `string` | No | The name of the Dockerfile to use for the build. Passed as `--file` to `docker build`. Useful when a project has multiple Dockerfiles (e.g. `Dockerfile.production`, `Dockerfile.admin`). Defaults to `Dockerfile`. |\n| `cacheDisabled` | `boolean` | No | When `true`, disables Docker layer caching. Every build runs from scratch. Use for debugging, corrupted cache, or major dependency changes. Defaults to `false`. |\n| `platform` | `'linux/amd64' \\| 'linux/arm64'` | No | Target platform for the Docker image. When set to `'linux/arm64'`, uses a native ARM/Graviton CodeBuild instance for fast builds without emulation. Defaults to `'linux/amd64'`. |\n| `buildLogGroup` | `ILogGroup` | No | CloudWatch log group for CodeBuild build logs. When provided with RETAIN removal policy, logs survive rollbacks and stack deletion. If not provided, CodeBuild uses default logging (logs are deleted on rollback). |\n| `ecrPullThroughCachePrefixes` | `string[]` | No | ECR pull-through cache repository prefixes to grant pull access to. Use when your Dockerfile references base images from ECR pull-through cache (e.g. `docker-hub/library/node:20-slim`, `ghcr/org/image:tag`). The CodeBuild role is granted `ecr:BatchGetImage`, `ecr:GetDownloadUrlForLayer`, and `ecr:BatchCheckLayerAvailability` on repositories matching each prefix. Example: `['docker-hub', 'ghcr']`. Defaults to no pull-through cache access. |\n\n#### Instance Properties\n\n| Property | Type | Description |\n|---|---|---|\n| `containerImage` | `ContainerImage` | An ECS-compatible container image referencing the built Docker image. |\n| `dockerImageCode` | `DockerImageCode` | A Lambda-compatible Docker image code referencing the built Docker image. |\n\n---\n\n## Usage Examples\n\n### Shared Provider (Recommended for Multiple Images)\n\nWhen building multiple Docker images in the same stack, use a shared provider to avoid creating redundant Lambda functions. Without a shared provider, each builder creates 2 Lambdas + 1 Provider framework Lambda. With 10 images, that's 30 Lambdas. A shared provider reduces this to just 3 Lambdas total.\n\n#### TypeScript/NPM Example\n\n```typescript\nimport * as cdk from 'aws-cdk-lib';\nimport {\n TokenInjectableDockerBuilder,\n TokenInjectableDockerBuilderProvider,\n} from 'token-injectable-docker-builder';\nimport * as ecs from 'aws-cdk-lib/aws-ecs';\n\nexport class MultiImageStack extends cdk.Stack {\n constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {\n super(scope, id, props);\n\n // Create a shared provider once per stack (singleton)\n const provider = TokenInjectableDockerBuilderProvider.getOrCreate(this);\n\n // Build multiple Docker images sharing the same provider\n const apiBuilder = new TokenInjectableDockerBuilder(this, 'ApiImage', {\n path: './src/api',\n provider,\n });\n\n const workerBuilder = new TokenInjectableDockerBuilder(this, 'WorkerImage', {\n path: './src/worker',\n provider,\n });\n\n const frontendBuilder = new TokenInjectableDockerBuilder(this, 'FrontendImage', {\n path: './src/frontend',\n buildArgs: { API_URL: 'https://api.example.com' },\n platform: 'linux/arm64', // Build natively on Graviton\n provider,\n });\n\n // Use in ECS task definitions\n const taskDef = new ecs.FargateTaskDefinition(this, 'TaskDef');\n taskDef.addContainer('api', { image: apiBuilder.containerImage });\n taskDef.addContainer('worker', { image: workerBuilder.containerImage });\n }\n}\n```\n\n#### Python Example\n\n```python\nfrom aws_cdk import aws_ecs as ecs, core as cdk\nfrom token_injectable_docker_builder import (\n TokenInjectableDockerBuilder,\n TokenInjectableDockerBuilderProvider,\n)\n\nclass MultiImageStack(cdk.Stack):\n def __init__(self, scope: cdk.App, id: str, **kwargs):\n super().__init__(scope, id, **kwargs)\n\n # Create a shared provider once per stack (singleton)\n provider = TokenInjectableDockerBuilderProvider.get_or_create(self)\n\n # Build multiple Docker images sharing the same provider\n api_builder = TokenInjectableDockerBuilder(self, \"ApiImage\",\n path=\"./src/api\",\n provider=provider,\n )\n\n worker_builder = TokenInjectableDockerBuilder(self, \"WorkerImage\",\n path=\"./src/worker\",\n provider=provider,\n )\n\n frontend_builder = TokenInjectableDockerBuilder(self, \"FrontendImage\",\n path=\"./src/frontend\",\n build_args={\"API_URL\": \"https://api.example.com\"},\n provider=provider,\n )\n```\n\n### Simple Usage Example\n\nThis example demonstrates the basic usage of the `TokenInjectableDockerBuilder`, where a Next.js frontend Docker image requires an API Gateway URL as a build argument to create a reference from the UI to the associated API in a given deployment.\n\n#### TypeScript/NPM Example\n\n```typescript\nimport * as cdk from 'aws-cdk-lib';\nimport { TokenInjectableDockerBuilder } from 'token-injectable-docker-builder';\nimport * as ecs from 'aws-cdk-lib/aws-ecs';\nimport * as ec2 from 'aws-cdk-lib/aws-ec2';\nimport * as apigateway from 'aws-cdk-lib/aws-apigateway';\n\nexport class SimpleStack extends cdk.Stack {\n constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {\n super(scope, id, props);\n\n // Create your API Gateway\n const api = new apigateway.RestApi(this, 'MyApiGateway', {\n restApiName: 'MyService',\n });\n\n // Create the Docker builder\n const dockerBuilder = new TokenInjectableDockerBuilder(this, 'SimpleDockerBuilder', {\n path: './nextjs-app', // Path to your Next.js app Docker context\n buildArgs: {\n API_URL: api.url, // Pass the API Gateway URL as a build argument\n },\n // Optionally override the default completeness query interval:\n // completenessQueryInterval: cdk.Duration.seconds(45),\n });\n\n // Use in ECS\n const cluster = new ecs.Cluster(this, 'EcsCluster', {\n vpc: new ec2.Vpc(this, 'Vpc'),\n });\n\n const service = new ecs.FargateService(this, 'FargateService', {\n cluster,\n taskDefinition: new ecs.FargateTaskDefinition(this, 'TaskDef', {\n cpu: 512,\n memoryLimitMiB: 1024,\n }).addContainer('Container', {\n image: dockerBuilder.containerImage,\n logging: ecs.LogDriver.awsLogs({ streamPrefix: 'MyApp' }),\n }),\n });\n\n service.node.addDependency(dockerBuilder);\n }\n}\n```\n\n#### Python Example\n\n```python\nfrom aws_cdk import (\n aws_ecs as ecs,\n aws_ec2 as ec2,\n aws_apigateway as apigateway,\n Duration,\n core as cdk,\n)\nfrom token_injectable_docker_builder import TokenInjectableDockerBuilder\n\nclass SimpleStack(cdk.Stack):\n\n def __init__(self, scope: cdk.App, id: str, **kwargs):\n super().__init__(scope, id, **kwargs)\n\n # Create your API Gateway\n api = apigateway.RestApi(self, \"MyApiGateway\",\n rest_api_name=\"MyService\",\n )\n\n # Create the Docker builder\n docker_builder = TokenInjectableDockerBuilder(self, \"SimpleDockerBuilder\",\n path=\"./nextjs-app\", # Path to your Next.js app Docker context\n build_args={\n \"API_URL\": api.url, # Pass the API Gateway URL as a build argument\n },\n # Optionally override the default completeness query interval:\n # completeness_query_interval=Duration.seconds(45)\n )\n\n # Use in ECS\n vpc = ec2.Vpc(self, \"Vpc\")\n cluster = ecs.Cluster(self, \"EcsCluster\", vpc=vpc)\n\n task_definition = ecs.FargateTaskDefinition(self, \"TaskDef\",\n cpu=512,\n memory_limit_mib=1024,\n )\n\n task_definition.node.add_dependency(docker_builder)\n\n task_definition.add_container(\"Container\",\n image=docker_builder.container_image,\n logging=ecs.LogDriver.aws_logs(stream_prefix=\"MyApp\"),\n )\n\n ecs.FargateService(self, \"FargateService\",\n cluster=cluster,\n task_definition=task_definition,\n )\n```\n\n---\n\n### Advanced Usage Example\n\nBuilding on the previous example, this advanced usage demonstrates how to include additional configurations, such as fetching private API endpoints and configuration files during the build process.\n\n#### TypeScript/NPM Example\n\n```typescript\nimport * as cdk from 'aws-cdk-lib';\nimport { TokenInjectableDockerBuilder } from 'token-injectable-docker-builder';\nimport * as ecs from 'aws-cdk-lib/aws-ecs';\nimport * as ec2 from 'aws-cdk-lib/aws-ec2';\nimport * as apigateway from 'aws-cdk-lib/aws-apigateway';\n\nexport class AdvancedStack extends cdk.Stack {\n constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {\n super(scope, id, props);\n\n // Create your API Gateway\n const api = new apigateway.RestApi(this, 'MyApiGateway', {\n restApiName: 'MyService',\n });\n\n // VPC and Security Group for CodeBuild\n const vpc = new ec2.Vpc(this, 'MyVpc');\n const securityGroup = new ec2.SecurityGroup(this, 'MySecurityGroup', {\n vpc,\n });\n\n // Create the Docker builder with additional pre-build commands\n const dockerBuilder = new TokenInjectableDockerBuilder(this, 'AdvancedDockerBuilder', {\n path: './nextjs-app',\n buildArgs: {\n API_URL: api.url,\n },\n vpc,\n securityGroups: [securityGroup],\n subnetSelection: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS },\n installCommands: [\n 'echo \"Updating package lists...\"',\n 'apt-get update -y',\n 'echo \"Installing necessary packages...\"',\n 'apt-get install -y curl',\n ],\n preBuildCommands: [\n 'echo \"Fetching private API configuration...\"',\n // Replace with your actual command to fetch configs\n 'curl -o config.json https://internal-api.example.com/config',\n ],\n // Optionally override the default completeness query interval:\n // completenessQueryInterval: cdk.Duration.seconds(45),\n });\n\n // Use in ECS\n const cluster = new ecs.Cluster(this, 'EcsCluster', { vpc });\n\n const service = new ecs.FargateService(this, 'FargateService', {\n cluster,\n taskDefinition: new ecs.FargateTaskDefinition(this, 'TaskDef', {\n cpu: 512,\n memoryLimitMiB: 1024,\n }).addContainer('Container', {\n image: dockerBuilder.containerImage,\n logging: ecs.LogDriver.awsLogs({ streamPrefix: 'MyApp' }),\n }),\n });\n\n service.node.addDependency(dockerBuilder);\n }\n}\n```\n\n#### Python Example\n\n```python\nfrom aws_cdk import (\n aws_ecs as ecs,\n aws_ec2 as ec2,\n aws_apigateway as apigateway,\n Duration,\n core as cdk,\n)\nfrom token_injectable_docker_builder import TokenInjectableDockerBuilder\n\nclass AdvancedStack(cdk.Stack):\n\n def __init__(self, scope: cdk.App, id: str, **kwargs):\n super().__init__(scope, id, **kwargs)\n\n # Create your API Gateway\n api = apigateway.RestApi(self, \"MyApiGateway\",\n rest_api_name=\"MyService\",\n )\n\n # VPC and Security Group for CodeBuild\n vpc = ec2.Vpc(self, \"MyVpc\")\n security_group = ec2.SecurityGroup(self, \"MySecurityGroup\", vpc=vpc)\n\n # Create the Docker builder with additional pre-build commands\n docker_builder = TokenInjectableDockerBuilder(self, \"AdvancedDockerBuilder\",\n path=\"./nextjs-app\",\n build_args={\n \"API_URL\": api.url,\n },\n vpc=vpc,\n security_groups=[security_group],\n subnet_selection=ec2.SubnetSelection(subnet_type=ec2.SubnetType.PRIVATE_WITH_EGRESS),\n install_commands=[\n 'echo \"Updating package lists...\"',\n 'apt-get update -y',\n 'echo \"Installing necessary packages...\"',\n 'apt-get install -y curl',\n ],\n pre_build_commands=[\n 'echo \"Fetching private API configuration...\"',\n # Replace with your actual command to fetch configs\n 'curl -o config.json https://internal-api.example.com/config',\n ],\n # Optionally override the default completeness query interval:\n # completeness_query_interval=Duration.seconds(45)\n )\n\n # Use in ECS\n cluster = ecs.Cluster(self, \"EcsCluster\", vpc=vpc)\n\n task_definition = ecs.FargateTaskDefinition(self, \"TaskDef\",\n cpu=512,\n memory_limit_mib=1024,\n )\n\n task_definition.node.add_dependency(docker_builder)\n\n task_definition.add_container(\"Container\",\n image=docker_builder.container_image,\n logging=ecs.LogDriver.aws_logs(stream_prefix=\"MyApp\"),\n )\n\n ecs.FargateService(self, \"FargateService\",\n cluster=cluster,\n task_definition=task_definition,\n )\n```\n\n### ECR Pull-Through Cache Example\n\nWhen your Dockerfile uses base images from an ECR pull-through cache (e.g. to avoid Docker Hub rate limits), pass `ecrPullThroughCachePrefixes` so the CodeBuild role can pull those images:\n\n```typescript\nimport * as cdk from 'aws-cdk-lib';\nimport {\n TokenInjectableDockerBuilder,\n TokenInjectableDockerBuilderProvider,\n} from 'token-injectable-docker-builder';\nimport * as lambda from 'aws-cdk-lib/aws-lambda';\n\nexport class PullThroughCacheStack extends cdk.Stack {\n constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {\n super(scope, id, props);\n\n const provider = TokenInjectableDockerBuilderProvider.getOrCreate(this);\n const node20Slim = `${this.account}.dkr.ecr.${this.region}.amazonaws.com/docker-hub/library/node:20-slim`;\n\n const apiImage = new TokenInjectableDockerBuilder(this, 'ApiImage', {\n path: './src',\n file: 'api/Dockerfile',\n platform: 'linux/arm64',\n provider,\n buildArgs: { NODE_20_SLIM: node20Slim },\n ecrPullThroughCachePrefixes: ['docker-hub', 'ghcr'],\n });\n\n new lambda.DockerImageFunction(this, 'ApiLambda', {\n code: apiImage.dockerImageCode,\n architecture: lambda.Architecture.ARM_64,\n });\n }\n}\n```\n\n---\n\nIn this advanced example:\n\n- **VPC Configuration**: The CodeBuild project is configured to run inside a VPC with specified security groups and subnet selection, allowing it to access internal resources such as a private API endpoint.\n- **Custom Install and Pre-Build Commands**: The `installCommands` and `preBuildCommands` properties are used to install necessary packages and fetch configuration files from a private API before building the Docker image.\n- **Access to Internal APIs**: By running inside a VPC and configuring the security groups appropriately, the CodeBuild project can access private endpoints not accessible over the public internet.\n\n---\n\n## How It Works\n\n1. **Docker Source**: Packages the source code or Dockerfile specified in the `path` property as an S3 asset.\n2. **CodeBuild Project**:\n - Uses the packaged asset and `buildArgs` to build the Docker image.\n - Executes any custom `installCommands` and `preBuildCommands` during the build process.\n - Pushes the image to an ECR repository.\n - By default, uses `docker buildx` with ECR registry cache to speed up builds.\n3. **Custom Resource**:\n - Triggers the build process using a Lambda function (`onEvent`).\n - Monitors the build status using another Lambda function (`isComplete`) which polls at the interval specified by `completenessQueryInterval` (defaulting to 30 seconds if not provided).\n - When using a shared `provider`, the same pair of Lambdas handles all builders in the stack.\n4. **Outputs**:\n - `.containerImage`: Returns the Docker image for ECS.\n - `.dockerImageCode`: Returns the Docker image code for Lambda.\n\n### Resource Comparison\n\n| Scenario | Lambdas Created | CodeBuild Projects | ECR Repos |\n|---|---|---|---|\n| 5 images, no shared provider | 15 (3 per image) | 5 | 5 |\n| 5 images, shared provider | 3 (shared) | 5 | 5 |\n| 10 images, no shared provider | 30 (3 per image) | 10 | 10 |\n| 10 images, shared provider | 3 (shared) | 10 | 10 |\n\n---\n\n## IAM Permissions\n\nThe construct automatically grants permissions for:\n\n- **CodeBuild**:\n - Pull and push images to ECR.\n - Pull from ECR pull-through cache prefixes when `ecrPullThroughCachePrefixes` is provided (e.g. `['docker-hub', 'ghcr']`).\n - Access to AWS Secrets Manager if `dockerLoginSecretArn` is provided.\n - Access to the KMS key for encryption.\n- **Lambda Functions** (per-instance or shared provider):\n - Start and monitor CodeBuild builds.\n - Access CloudWatch Logs.\n - Access to the KMS key for encryption.\n - Pull and push images to ECR.\n\nWhen using the shared provider, `registerProject()` incrementally adds IAM permissions for each CodeBuild project and ECR repository.\n\n---\n\n## Notes\n\n- **Shared Provider**: Use `TokenInjectableDockerBuilderProvider.getOrCreate(this)` when building multiple images in the same stack. This is the recommended approach for stacks with 2+ Docker images.\n- **Build Arguments**: Pass custom arguments via `buildArgs` as `--build-arg` flags. CDK tokens can be used to inject dynamic values resolved at deployment time.\n- **Custom Commands**: Use `installCommands` and `preBuildCommands` to run custom shell commands during the build process. This can be useful for installing dependencies or fetching configuration files.\n- **VPC Configuration**: If your build process requires access to resources within a VPC, you can specify the VPC, security groups, and subnet selection.\n- **Docker Login**: If you need to log in to a private Docker registry before building the image, provide the ARN of a secret in AWS Secrets Manager containing the Docker credentials.\n- **ECR Repository**: Automatically creates an ECR repository with lifecycle rules to manage image retention, encryption with a KMS key, and image scanning on push.\n- **Build Query Interval**: The polling frequency for checking build completion can be customized via the `completenessQueryInterval` property (per-instance) or `queryInterval` (shared provider).\n- **Custom Dockerfile**: Use the `file` property to specify a Dockerfile other than the default `Dockerfile`. This is passed as the `--file` flag to `docker build`.\n- **Docker Layer Caching**: By default, builds use ECR as a remote cache backend (via `docker buildx`), which can reduce build times by up to 25%. Set `cacheDisabled: true` when you need a clean build—for example, when debugging, the cache is corrupted, or after major dependency upgrades.\n- **Platform / Architecture**: Set `platform: 'linux/arm64'` to build ARM64/Graviton images using a native ARM CodeBuild instance. Defaults to `'linux/amd64'` (x86_64). Native builds are faster and cheaper than cross-compilation with QEMU.\n- **Build Log Retention**: Pass `buildLogGroup` with a log group that has RETAIN removal policy to ensure build logs survive CloudFormation rollbacks and stack deletion.\n- **ECR Pull-Through Cache**: When using ECR pull-through cache for base images (e.g. to avoid Docker Hub rate limits), pass `ecrPullThroughCachePrefixes: ['docker-hub', 'ghcr']` so the CodeBuild role can pull from those cached repositories. Your ECR registry must have a pull-through cache rule and registry policy configured separately.\n- **Backward Compatibility**: The `provider` prop is optional. Omitting it preserves the original behavior where each builder creates its own Lambdas. Existing code works without changes.\n\n---\n\n## Troubleshooting\n\n1. **Build Errors**: Check the CodeBuild logs in CloudWatch Logs for detailed error messages. If you pass `buildLogGroup` with RETAIN removal policy, logs persist even after rollbacks. Otherwise, logs are deleted when the CodeBuild project is removed during rollback.\n2. **Lambda Errors**: Check the `onEvent` and `isComplete` Lambda function logs in CloudWatch Logs. With a shared provider, both builders' events flow through the same Lambdas—filter by `ProjectName` in the logs.\n3. **Permissions**: Ensure IAM roles have the required permissions for CodeBuild, ECR, Secrets Manager, and KMS if applicable. When using a shared provider, verify that `registerProject()` was called for each builder (this happens automatically when passing the `provider` prop).\n4. **Network Access**: If the build requires network access (e.g., to download dependencies or access internal APIs), ensure that the VPC configuration allows necessary network connectivity, and adjust security group rules accordingly.\n\n---\n\n## Support\n\nFor issues or feature requests, please open an issue on [GitHub](https://github.com/AlexTech314/TokenInjectableDockerBuilder).\n\n---\n\n## Reference Links\n\n[![View on Construct Hub](https://constructs.dev/badge?package=token-injectable-docker-builder)](https://constructs.dev/packages/token-injectable-docker-builder)\n\n---\n\n## License\n\nThis project is licensed under the terms of the MIT license.\n\n---\n\n## Acknowledgements\n\n- Inspired by the need for more dynamic Docker asset management in AWS CDK.\n- Thanks to the AWS CDK community for their continuous support and contributions.\n\n---\n\nFeel free to reach out if you have any questions or need further assistance!\n"
8540
8540
  },
8541
8541
  "repository": {
8542
8542
  "type": "git",
@@ -8568,7 +8568,7 @@
8568
8568
  },
8569
8569
  "locationInModule": {
8570
8570
  "filename": "src/index.ts",
8571
- "line": 301
8571
+ "line": 323
8572
8572
  },
8573
8573
  "parameters": [
8574
8574
  {
@@ -8603,7 +8603,7 @@
8603
8603
  "kind": "class",
8604
8604
  "locationInModule": {
8605
8605
  "filename": "src/index.ts",
8606
- "line": 276
8606
+ "line": 298
8607
8607
  },
8608
8608
  "name": "TokenInjectableDockerBuilder",
8609
8609
  "properties": [
@@ -8615,7 +8615,7 @@
8615
8615
  "immutable": true,
8616
8616
  "locationInModule": {
8617
8617
  "filename": "src/index.ts",
8618
- "line": 286
8618
+ "line": 308
8619
8619
  },
8620
8620
  "name": "containerImage",
8621
8621
  "type": {
@@ -8630,7 +8630,7 @@
8630
8630
  "immutable": true,
8631
8631
  "locationInModule": {
8632
8632
  "filename": "src/index.ts",
8633
- "line": 292
8633
+ "line": 314
8634
8634
  },
8635
8635
  "name": "dockerImageCode",
8636
8636
  "type": {
@@ -8771,6 +8771,31 @@
8771
8771
  "primitive": "string"
8772
8772
  }
8773
8773
  },
8774
+ {
8775
+ "abstract": true,
8776
+ "docs": {
8777
+ "default": "- No pull-through cache access",
8778
+ "example": "['docker-hub', 'ghcr']",
8779
+ "remarks": "Use when your Dockerfile references base images from ECR pull-through\ncache (e.g. docker-hub/library/node:20-slim, ghcr/org/image:tag).\nThe CodeBuild role will be granted ecr:BatchGetImage, ecr:GetDownloadUrlForLayer,\nand ecr:BatchCheckLayerAvailability on repositories matching each prefix.",
8780
+ "stability": "stable",
8781
+ "summary": "ECR pull-through cache repository prefixes to grant pull access to."
8782
+ },
8783
+ "immutable": true,
8784
+ "locationInModule": {
8785
+ "filename": "src/index.ts",
8786
+ "line": 290
8787
+ },
8788
+ "name": "ecrPullThroughCachePrefixes",
8789
+ "optional": true,
8790
+ "type": {
8791
+ "collection": {
8792
+ "elementtype": {
8793
+ "primitive": "string"
8794
+ },
8795
+ "kind": "array"
8796
+ }
8797
+ }
8798
+ },
8774
8799
  {
8775
8800
  "abstract": true,
8776
8801
  "docs": {
@@ -8858,6 +8883,25 @@
8858
8883
  "primitive": "boolean"
8859
8884
  }
8860
8885
  },
8886
+ {
8887
+ "abstract": true,
8888
+ "docs": {
8889
+ "default": "'linux/amd64'",
8890
+ "remarks": "When set to `'linux/arm64'`, the construct uses a native ARM/Graviton\nCodeBuild instance for fast builds without emulation.",
8891
+ "stability": "stable",
8892
+ "summary": "Target platform for the Docker image."
8893
+ },
8894
+ "immutable": true,
8895
+ "locationInModule": {
8896
+ "filename": "src/index.ts",
8897
+ "line": 267
8898
+ },
8899
+ "name": "platform",
8900
+ "optional": true,
8901
+ "type": {
8902
+ "primitive": "string"
8903
+ }
8904
+ },
8861
8905
  {
8862
8906
  "abstract": true,
8863
8907
  "docs": {
@@ -8893,7 +8937,7 @@
8893
8937
  "immutable": true,
8894
8938
  "locationInModule": {
8895
8939
  "filename": "src/index.ts",
8896
- "line": 268
8940
+ "line": 278
8897
8941
  },
8898
8942
  "name": "provider",
8899
8943
  "optional": true,
@@ -9104,6 +9148,6 @@
9104
9148
  "symbolId": "src/index:TokenInjectableDockerBuilderProviderProps"
9105
9149
  }
9106
9150
  },
9107
- "version": "1.9.0",
9108
- "fingerprint": "iUy4UQRv2C4McVNRJmK44WI9+MYQNepqPxoYytrMqDk="
9151
+ "version": "1.11.0",
9152
+ "fingerprint": "QxZS2pmpftMS65LHwYQOY429j60UA6eA3BOrmbNdAzA="
9109
9153
  }
package/API.md CHANGED
@@ -296,10 +296,12 @@ const tokenInjectableDockerBuilderProps: TokenInjectableDockerBuilderProps = { .
296
296
  | <code><a href="#token-injectable-docker-builder.TokenInjectableDockerBuilderProps.property.cacheDisabled">cacheDisabled</a></code> | <code>boolean</code> | When `true`, disables Docker layer caching. |
297
297
  | <code><a href="#token-injectable-docker-builder.TokenInjectableDockerBuilderProps.property.completenessQueryInterval">completenessQueryInterval</a></code> | <code>aws-cdk-lib.Duration</code> | The query interval for checking if the CodeBuild project has completed. |
298
298
  | <code><a href="#token-injectable-docker-builder.TokenInjectableDockerBuilderProps.property.dockerLoginSecretArn">dockerLoginSecretArn</a></code> | <code>string</code> | The ARN of the AWS Secrets Manager secret containing Docker login credentials. |
299
+ | <code><a href="#token-injectable-docker-builder.TokenInjectableDockerBuilderProps.property.ecrPullThroughCachePrefixes">ecrPullThroughCachePrefixes</a></code> | <code>string[]</code> | ECR pull-through cache repository prefixes to grant pull access to. |
299
300
  | <code><a href="#token-injectable-docker-builder.TokenInjectableDockerBuilderProps.property.exclude">exclude</a></code> | <code>string[]</code> | A list of file paths in the Docker directory to exclude from build. |
300
301
  | <code><a href="#token-injectable-docker-builder.TokenInjectableDockerBuilderProps.property.file">file</a></code> | <code>string</code> | The name of the Dockerfile to use for the build. |
301
302
  | <code><a href="#token-injectable-docker-builder.TokenInjectableDockerBuilderProps.property.installCommands">installCommands</a></code> | <code>string[]</code> | Custom commands to run during the install phase of CodeBuild. |
302
303
  | <code><a href="#token-injectable-docker-builder.TokenInjectableDockerBuilderProps.property.kmsEncryption">kmsEncryption</a></code> | <code>boolean</code> | Whether to enable KMS encryption for the ECR repository. |
304
+ | <code><a href="#token-injectable-docker-builder.TokenInjectableDockerBuilderProps.property.platform">platform</a></code> | <code>string</code> | Target platform for the Docker image. |
303
305
  | <code><a href="#token-injectable-docker-builder.TokenInjectableDockerBuilderProps.property.preBuildCommands">preBuildCommands</a></code> | <code>string[]</code> | Custom commands to run during the pre_build phase of CodeBuild. |
304
306
  | <code><a href="#token-injectable-docker-builder.TokenInjectableDockerBuilderProps.property.provider">provider</a></code> | <code><a href="#token-injectable-docker-builder.TokenInjectableDockerBuilderProvider">TokenInjectableDockerBuilderProvider</a></code> | Shared provider for the custom resource Lambdas. |
305
307
  | <code><a href="#token-injectable-docker-builder.TokenInjectableDockerBuilderProps.property.securityGroups">securityGroups</a></code> | <code>aws-cdk-lib.aws_ec2.ISecurityGroup[]</code> | The security groups to attach to the CodeBuild project. |
@@ -421,6 +423,31 @@ If not provided (or not needed), the construct will skip Docker Hub login.
421
423
  ```
422
424
 
423
425
 
426
+ ##### `ecrPullThroughCachePrefixes`<sup>Optional</sup> <a name="ecrPullThroughCachePrefixes" id="token-injectable-docker-builder.TokenInjectableDockerBuilderProps.property.ecrPullThroughCachePrefixes"></a>
427
+
428
+ ```typescript
429
+ public readonly ecrPullThroughCachePrefixes: string[];
430
+ ```
431
+
432
+ - *Type:* string[]
433
+ - *Default:* No pull-through cache access
434
+
435
+ ECR pull-through cache repository prefixes to grant pull access to.
436
+
437
+ Use when your Dockerfile references base images from ECR pull-through
438
+ cache (e.g. docker-hub/library/node:20-slim, ghcr/org/image:tag).
439
+ The CodeBuild role will be granted ecr:BatchGetImage, ecr:GetDownloadUrlForLayer,
440
+ and ecr:BatchCheckLayerAvailability on repositories matching each prefix.
441
+
442
+ ---
443
+
444
+ *Example*
445
+
446
+ ```typescript
447
+ ['docker-hub', 'ghcr']
448
+ ```
449
+
450
+
424
451
  ##### `exclude`<sup>Optional</sup> <a name="exclude" id="token-injectable-docker-builder.TokenInjectableDockerBuilderProps.property.exclude"></a>
425
452
 
426
453
  ```typescript
@@ -497,6 +524,22 @@ If `false`, the repository will use AES-256 encryption.
497
524
 
498
525
  ---
499
526
 
527
+ ##### `platform`<sup>Optional</sup> <a name="platform" id="token-injectable-docker-builder.TokenInjectableDockerBuilderProps.property.platform"></a>
528
+
529
+ ```typescript
530
+ public readonly platform: string;
531
+ ```
532
+
533
+ - *Type:* string
534
+ - *Default:* 'linux/amd64'
535
+
536
+ Target platform for the Docker image.
537
+
538
+ When set to `'linux/arm64'`, the construct uses a native ARM/Graviton
539
+ CodeBuild instance for fast builds without emulation.
540
+
541
+ ---
542
+
500
543
  ##### `preBuildCommands`<sup>Optional</sup> <a name="preBuildCommands" id="token-injectable-docker-builder.TokenInjectableDockerBuilderProps.property.preBuildCommands"></a>
501
544
 
502
545
  ```typescript
package/README.md CHANGED
@@ -25,7 +25,9 @@ For example, a Next.js frontend Docker image may require an API Gateway URL as a
25
25
  - **Custom Build Query Interval**: Configure how frequently the custom resource polls for build completion using the `completenessQueryInterval` property (defaults to 30 seconds).
26
26
  - **Custom Dockerfile**: Specify a custom Dockerfile name via the `file` property (e.g. `Dockerfile.production`), allowing multiple Docker images from the same source directory.
27
27
  - **ECR Docker Layer Caching**: By default, builds use `docker buildx` with ECR as a remote cache backend, reducing build times by reusing layers across deploys. Set `cacheDisabled: true` to force a clean build from scratch.
28
+ - **Platform Support**: Build images for `linux/amd64` (x86_64) or `linux/arm64` (Graviton) using native CodeBuild instances — no emulation, no QEMU. ARM builds are faster and cheaper.
28
29
  - **Persistent Build Logs**: Pass `buildLogGroup` with a log group that has RETAIN removal policy so build logs survive rollbacks and stack deletion for debugging.
30
+ - **ECR Pull-Through Cache**: When your Dockerfile uses base images from ECR pull-through cache (e.g. `docker-hub/library/node:20-slim`, `ghcr/org/image:tag`), pass `ecrPullThroughCachePrefixes` to grant the CodeBuild role pull access to those cache prefixes.
29
31
 
30
32
  ---
31
33
 
@@ -107,7 +109,9 @@ A singleton construct that creates the `onEvent` and `isComplete` Lambda functio
107
109
  | `exclude` | `string[]` | No | A list of file paths in the Docker directory to exclude from the S3 asset bundle. If a `.dockerignore` file is present in the source directory, its contents will be used if this prop is not set. Defaults to an empty list or `.dockerignore` contents. |
108
110
  | `file` | `string` | No | The name of the Dockerfile to use for the build. Passed as `--file` to `docker build`. Useful when a project has multiple Dockerfiles (e.g. `Dockerfile.production`, `Dockerfile.admin`). Defaults to `Dockerfile`. |
109
111
  | `cacheDisabled` | `boolean` | No | When `true`, disables Docker layer caching. Every build runs from scratch. Use for debugging, corrupted cache, or major dependency changes. Defaults to `false`. |
112
+ | `platform` | `'linux/amd64' \| 'linux/arm64'` | No | Target platform for the Docker image. When set to `'linux/arm64'`, uses a native ARM/Graviton CodeBuild instance for fast builds without emulation. Defaults to `'linux/amd64'`. |
110
113
  | `buildLogGroup` | `ILogGroup` | No | CloudWatch log group for CodeBuild build logs. When provided with RETAIN removal policy, logs survive rollbacks and stack deletion. If not provided, CodeBuild uses default logging (logs are deleted on rollback). |
114
+ | `ecrPullThroughCachePrefixes` | `string[]` | No | ECR pull-through cache repository prefixes to grant pull access to. Use when your Dockerfile references base images from ECR pull-through cache (e.g. `docker-hub/library/node:20-slim`, `ghcr/org/image:tag`). The CodeBuild role is granted `ecr:BatchGetImage`, `ecr:GetDownloadUrlForLayer`, and `ecr:BatchCheckLayerAvailability` on repositories matching each prefix. Example: `['docker-hub', 'ghcr']`. Defaults to no pull-through cache access. |
111
115
 
112
116
  #### Instance Properties
113
117
 
@@ -155,6 +159,7 @@ export class MultiImageStack extends cdk.Stack {
155
159
  const frontendBuilder = new TokenInjectableDockerBuilder(this, 'FrontendImage', {
156
160
  path: './src/frontend',
157
161
  buildArgs: { API_URL: 'https://api.example.com' },
162
+ platform: 'linux/arm64', // Build natively on Graviton
158
163
  provider,
159
164
  });
160
165
 
@@ -451,6 +456,44 @@ class AdvancedStack(cdk.Stack):
451
456
  )
452
457
  ```
453
458
 
459
+ ### ECR Pull-Through Cache Example
460
+
461
+ When your Dockerfile uses base images from an ECR pull-through cache (e.g. to avoid Docker Hub rate limits), pass `ecrPullThroughCachePrefixes` so the CodeBuild role can pull those images:
462
+
463
+ ```typescript
464
+ import * as cdk from 'aws-cdk-lib';
465
+ import {
466
+ TokenInjectableDockerBuilder,
467
+ TokenInjectableDockerBuilderProvider,
468
+ } from 'token-injectable-docker-builder';
469
+ import * as lambda from 'aws-cdk-lib/aws-lambda';
470
+
471
+ export class PullThroughCacheStack extends cdk.Stack {
472
+ constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
473
+ super(scope, id, props);
474
+
475
+ const provider = TokenInjectableDockerBuilderProvider.getOrCreate(this);
476
+ const node20Slim = `${this.account}.dkr.ecr.${this.region}.amazonaws.com/docker-hub/library/node:20-slim`;
477
+
478
+ const apiImage = new TokenInjectableDockerBuilder(this, 'ApiImage', {
479
+ path: './src',
480
+ file: 'api/Dockerfile',
481
+ platform: 'linux/arm64',
482
+ provider,
483
+ buildArgs: { NODE_20_SLIM: node20Slim },
484
+ ecrPullThroughCachePrefixes: ['docker-hub', 'ghcr'],
485
+ });
486
+
487
+ new lambda.DockerImageFunction(this, 'ApiLambda', {
488
+ code: apiImage.dockerImageCode,
489
+ architecture: lambda.Architecture.ARM_64,
490
+ });
491
+ }
492
+ }
493
+ ```
494
+
495
+ ---
496
+
454
497
  In this advanced example:
455
498
 
456
499
  - **VPC Configuration**: The CodeBuild project is configured to run inside a VPC with specified security groups and subnet selection, allowing it to access internal resources such as a private API endpoint.
@@ -492,6 +535,7 @@ The construct automatically grants permissions for:
492
535
 
493
536
  - **CodeBuild**:
494
537
  - Pull and push images to ECR.
538
+ - Pull from ECR pull-through cache prefixes when `ecrPullThroughCachePrefixes` is provided (e.g. `['docker-hub', 'ghcr']`).
495
539
  - Access to AWS Secrets Manager if `dockerLoginSecretArn` is provided.
496
540
  - Access to the KMS key for encryption.
497
541
  - **Lambda Functions** (per-instance or shared provider):
@@ -515,7 +559,9 @@ When using the shared provider, `registerProject()` incrementally adds IAM permi
515
559
  - **Build Query Interval**: The polling frequency for checking build completion can be customized via the `completenessQueryInterval` property (per-instance) or `queryInterval` (shared provider).
516
560
  - **Custom Dockerfile**: Use the `file` property to specify a Dockerfile other than the default `Dockerfile`. This is passed as the `--file` flag to `docker build`.
517
561
  - **Docker Layer Caching**: By default, builds use ECR as a remote cache backend (via `docker buildx`), which can reduce build times by up to 25%. Set `cacheDisabled: true` when you need a clean build—for example, when debugging, the cache is corrupted, or after major dependency upgrades.
562
+ - **Platform / Architecture**: Set `platform: 'linux/arm64'` to build ARM64/Graviton images using a native ARM CodeBuild instance. Defaults to `'linux/amd64'` (x86_64). Native builds are faster and cheaper than cross-compilation with QEMU.
518
563
  - **Build Log Retention**: Pass `buildLogGroup` with a log group that has RETAIN removal policy to ensure build logs survive CloudFormation rollbacks and stack deletion.
564
+ - **ECR Pull-Through Cache**: When using ECR pull-through cache for base images (e.g. to avoid Docker Hub rate limits), pass `ecrPullThroughCachePrefixes: ['docker-hub', 'ghcr']` so the CodeBuild role can pull from those cached repositories. Your ECR registry must have a pull-through cache rule and registry policy configured separately.
519
565
  - **Backward Compatibility**: The `provider` prop is optional. Omitting it preserves the original behavior where each builder creates its own Lambdas. Existing code works without changes.
520
566
 
521
567
  ---
package/lib/index.d.ts CHANGED
@@ -173,6 +173,15 @@ export interface TokenInjectableDockerBuilderProps {
173
173
  * @default - CodeBuild default logging (logs are deleted on rollback)
174
174
  */
175
175
  readonly buildLogGroup?: ILogGroup;
176
+ /**
177
+ * Target platform for the Docker image.
178
+ *
179
+ * When set to `'linux/arm64'`, the construct uses a native ARM/Graviton
180
+ * CodeBuild instance for fast builds without emulation.
181
+ *
182
+ * @default 'linux/amd64'
183
+ */
184
+ readonly platform?: 'linux/amd64' | 'linux/arm64';
176
185
  /**
177
186
  * Shared provider for the custom resource Lambdas.
178
187
  * Use `TokenInjectableDockerBuilderProvider.getOrCreate(this)` to create
@@ -183,6 +192,17 @@ export interface TokenInjectableDockerBuilderProps {
183
192
  * @default - A new provider is created per builder instance
184
193
  */
185
194
  readonly provider?: TokenInjectableDockerBuilderProvider;
195
+ /**
196
+ * ECR pull-through cache repository prefixes to grant pull access to.
197
+ * Use when your Dockerfile references base images from ECR pull-through
198
+ * cache (e.g. docker-hub/library/node:20-slim, ghcr/org/image:tag).
199
+ * The CodeBuild role will be granted ecr:BatchGetImage, ecr:GetDownloadUrlForLayer,
200
+ * and ecr:BatchCheckLayerAvailability on repositories matching each prefix.
201
+ *
202
+ * @example ['docker-hub', 'ghcr']
203
+ * @default - No pull-through cache access
204
+ */
205
+ readonly ecrPullThroughCachePrefixes?: string[];
186
206
  }
187
207
  /**
188
208
  * A CDK construct to build and push Docker images to an ECR repository using
package/lib/index.js CHANGED
@@ -87,7 +87,7 @@ class TokenInjectableDockerBuilderProvider extends constructs_1.Construct {
87
87
  }
88
88
  exports.TokenInjectableDockerBuilderProvider = TokenInjectableDockerBuilderProvider;
89
89
  _a = JSII_RTTI_SYMBOL_1;
90
- TokenInjectableDockerBuilderProvider[_a] = { fqn: "token-injectable-docker-builder.TokenInjectableDockerBuilderProvider", version: "1.9.0" };
90
+ TokenInjectableDockerBuilderProvider[_a] = { fqn: "token-injectable-docker-builder.TokenInjectableDockerBuilderProvider", version: "1.11.0" };
91
91
  /**
92
92
  * A CDK construct to build and push Docker images to an ECR repository using
93
93
  * CodeBuild and Lambda custom resources, **then** retrieve the final image tag
@@ -103,7 +103,7 @@ class TokenInjectableDockerBuilder extends constructs_1.Construct {
103
103
  */
104
104
  constructor(scope, id, props) {
105
105
  super(scope, id);
106
- const { path: sourcePath, buildArgs, dockerLoginSecretArn, vpc, securityGroups, subnetSelection, installCommands, preBuildCommands, kmsEncryption = false, completenessQueryInterval, exclude, file: dockerFile, cacheDisabled = false, buildLogGroup: buildLogGroupProp, provider: sharedProvider, } = props;
106
+ const { path: sourcePath, buildArgs, dockerLoginSecretArn, vpc, securityGroups, subnetSelection, installCommands, preBuildCommands, kmsEncryption = false, completenessQueryInterval, exclude, file: dockerFile, cacheDisabled = false, buildLogGroup: buildLogGroupProp, platform = 'linux/amd64', provider: sharedProvider, ecrPullThroughCachePrefixes, } = props;
107
107
  // Generate an ephemeral tag for CodeBuild
108
108
  const imageTag = crypto.randomUUID();
109
109
  // Optionally define a KMS key for ECR encryption if requested
@@ -176,9 +176,10 @@ class TokenInjectableDockerBuilder extends constructs_1.Construct {
176
176
  'echo "Setting up Docker buildx for ECR layer cache..."',
177
177
  'docker buildx create --driver docker-container --name ecr-cache-builder --use 2>/dev/null || docker buildx use ecr-cache-builder',
178
178
  ];
179
+ const platformFlag = `--platform ${platform}`;
179
180
  const buildCommand = cacheDisabled
180
- ? `docker build ${dockerFileFlag} ${buildArgsString} -t $ECR_REPO_URI:${imageTag} $CODEBUILD_SRC_DIR`
181
- : `docker buildx build --push --cache-from type=registry,ref=$ECR_REPO_URI:cache --cache-to type=registry,ref=$ECR_REPO_URI:cache,mode=max,image-manifest=true ${dockerFileFlag} ${buildArgsString} -t $ECR_REPO_URI:${imageTag} $CODEBUILD_SRC_DIR`;
181
+ ? `docker build ${platformFlag} ${dockerFileFlag} ${buildArgsString} -t $ECR_REPO_URI:${imageTag} $CODEBUILD_SRC_DIR`
182
+ : `docker buildx build --push ${platformFlag} --cache-from type=registry,ref=$ECR_REPO_URI:cache --cache-to type=registry,ref=$ECR_REPO_URI:cache,mode=max,image-manifest=true ${dockerFileFlag} ${buildArgsString} -t $ECR_REPO_URI:${imageTag} $CODEBUILD_SRC_DIR`;
182
183
  const buildSpecObj = {
183
184
  version: '0.2',
184
185
  phases: {
@@ -215,6 +216,10 @@ class TokenInjectableDockerBuilder extends constructs_1.Construct {
215
216
  }),
216
217
  },
217
218
  };
219
+ const isArm = platform === 'linux/arm64';
220
+ const codeBuildImage = isArm
221
+ ? aws_codebuild_1.LinuxArmBuildImage.AMAZON_LINUX_2_STANDARD_3_0
222
+ : aws_codebuild_1.LinuxBuildImage.STANDARD_7_0;
218
223
  // Create the CodeBuild project
219
224
  const codeBuildProject = new aws_codebuild_1.Project(this, 'CodeBuildProject', {
220
225
  source: aws_codebuild_1.Source.s3({
@@ -222,7 +227,7 @@ class TokenInjectableDockerBuilder extends constructs_1.Construct {
222
227
  path: sourceAsset.s3ObjectKey,
223
228
  }),
224
229
  environment: {
225
- buildImage: aws_codebuild_1.LinuxBuildImage.STANDARD_7_0,
230
+ buildImage: codeBuildImage,
226
231
  privileged: true,
227
232
  },
228
233
  environmentVariables: {
@@ -247,9 +252,21 @@ class TokenInjectableDockerBuilder extends constructs_1.Construct {
247
252
  'ecr:GetAuthorizationToken',
248
253
  'ecr:GetDownloadUrlForLayer',
249
254
  'ecr:BatchCheckLayerAvailability',
255
+ 'ecr:BatchGetImage',
250
256
  ],
251
257
  resources: ['*'],
252
258
  }));
259
+ if (ecrPullThroughCachePrefixes && ecrPullThroughCachePrefixes.length > 0) {
260
+ const stack = aws_cdk_lib_1.Stack.of(this);
261
+ codeBuildProject.addToRolePolicy(new aws_iam_1.PolicyStatement({
262
+ actions: [
263
+ 'ecr:BatchGetImage',
264
+ 'ecr:GetDownloadUrlForLayer',
265
+ 'ecr:BatchCheckLayerAvailability',
266
+ ],
267
+ resources: ecrPullThroughCachePrefixes.map((prefix) => `arn:aws:ecr:${stack.region}:${stack.account}:repository/${prefix}/*`),
268
+ }));
269
+ }
253
270
  if (dockerLoginSecretArn) {
254
271
  codeBuildProject.addToRolePolicy(new aws_iam_1.PolicyStatement({
255
272
  actions: ['secretsmanager:GetSecretValue'],
@@ -329,5 +346,5 @@ class TokenInjectableDockerBuilder extends constructs_1.Construct {
329
346
  }
330
347
  exports.TokenInjectableDockerBuilder = TokenInjectableDockerBuilder;
331
348
  _b = JSII_RTTI_SYMBOL_1;
332
- TokenInjectableDockerBuilder[_b] = { fqn: "token-injectable-docker-builder.TokenInjectableDockerBuilder", version: "1.9.0" };
333
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxpQ0FBaUM7QUFDakMseUJBQXlCO0FBQ3pCLDZCQUE2QjtBQUU3Qiw2Q0FBOEQ7QUFDOUQsNkRBQXdGO0FBRXhGLGlEQUFrRjtBQUNsRixpREFBcUQ7QUFDckQsaURBQXNEO0FBQ3RELGlEQUEwQztBQUMxQyx1REFBa0Y7QUFFbEYsNkRBQWtEO0FBQ2xELG1FQUF3RDtBQUN4RCwyQ0FBdUM7QUFFdkMsTUFBTSxxQkFBcUIsR0FBRyxzQ0FBc0MsQ0FBQztBQWNyRTs7Ozs7O0dBTUc7QUFDSCxNQUFhLG9DQUFxQyxTQUFRLHNCQUFTO0lBQ2pFOzs7O09BSUc7SUFDSSxNQUFNLENBQUMsV0FBVyxDQUFDLEtBQWdCLEVBQUUsS0FBaUQ7UUFDM0YsTUFBTSxLQUFLLEdBQUcsbUJBQUssQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDOUIsTUFBTSxRQUFRLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMscUJBQXFCLENBQXFELENBQUM7UUFDcEgsSUFBSSxRQUFRO1lBQUUsT0FBTyxRQUFRLENBQUM7UUFDOUIsT0FBTyxJQUFJLG9DQUFvQyxDQUFDLEtBQUssRUFBRSxxQkFBcUIsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUN2RixDQUFDO0lBUUQsWUFBb0IsS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBaUQ7UUFDakcsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUVqQixJQUFJLENBQUMsc0JBQXNCLEdBQUcsSUFBSSxxQkFBUSxDQUFDLElBQUksRUFBRSxnQkFBZ0IsRUFBRTtZQUNqRSxPQUFPLEVBQUUsb0JBQU8sQ0FBQyxXQUFXO1lBQzVCLElBQUksRUFBRSxpQkFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFBRSxZQUFZLENBQUMs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QUF5QjtnQkFDNUMsYUFBYSxFQUFFLHlCQUF5QixJQUFJLHNCQUFRLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQzthQUNqRSxDQUFDLENBQUM7WUFDSCxZQUFZLEdBQUcsUUFBUSxDQUFDLFlBQVksQ0FBQztRQUN2QyxDQUFDO1FBRUQsdUVBQXVFO1FBQ3ZFLE1BQU0sb0JBQW9CLEdBQUcsSUFBSSw0QkFBYyxDQUFDLElBQUksRUFBRSxzQkFBc0IsRUFBRTtZQUM1RSxZQUFZO1lBQ1osVUFBVSxFQUFFO2dCQUNWLFdBQVcsRUFBRSxnQkFBZ0IsQ0FBQyxXQUFXO2dCQUN6QyxRQUFRLEVBQUUsUUFBUTtnQkFDbEIsT0FBTyxFQUFFLFdBQVcsQ0FBQyxTQUFTO2FBQy9CO1NBQ0YsQ0FBQyxDQUFDO1FBQ0gsb0JBQW9CLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1FBRTFELHlEQUF5RDtRQUN6RCxNQUFNLFdBQVcsR0FBRyxvQkFBb0IsQ0FBQyxZQUFZLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDbEUsSUFBSSxDQUFDLGNBQWMsR0FBRyx3QkFBYyxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUUsV0FBVyxDQUFDLENBQUM7UUFDeEYsSUFBSSxDQUFDLGVBQWUsR0FBRyw0QkFBZSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsYUFBYSxFQUFFO1lBQ2pFLFdBQVcsRUFBRSxXQUFXO1NBQ3pCLENBQUMsQ0FBQztJQUNMLENBQUM7O0FBdFNILG9FQXVTQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGNyeXB0byBmcm9tICdjcnlwdG8nO1xuaW1wb3J0ICogYXMgZnMgZnJvbSAnZnMnO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcblxuaW1wb3J0IHsgQ3VzdG9tUmVzb3VyY2UsIER1cmF0aW9uLCBTdGFjayB9IGZyb20gJ2F3cy1jZGstbGliJztcbmltcG9ydCB7IFByb2plY3QsIFNvdXJjZSwgTGludXhCdWlsZEltYWdlLCBCdWlsZFNwZWMgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtY29kZWJ1aWxkJztcbmltcG9ydCB7IElWcGMsIElTZWN1cml0eUdyb3VwLCBTdWJuZXRTZWxlY3Rpb24gfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtZWMyJztcbmltcG9ydCB7IFJlcG9zaXRvcnksIFJlcG9zaXRvcnlFbmNyeXB0aW9uLCBUYWdTdGF0dXMgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtZWNyJztcbmltcG9ydCB7IENvbnRhaW5lckltYWdlIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWVjcyc7XG5pbXBvcnQgeyBQb2xpY3lTdGF0ZW1lbnQgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtaWFtJztcbmltcG9ydCB7IEtleSB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1rbXMnO1xuaW1wb3J0IHsgUnVudGltZSwgQ29kZSwgRG9ja2VySW1hZ2VDb2RlLCBGdW5jdGlvbiB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1sYW1iZGEnO1xuaW1wb3J0IHsgSUxvZ0dyb3VwIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWxvZ3MnO1xuaW1wb3J0IHsgQXNzZXQgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtczMtYXNzZXRzJztcbmltcG9ydCB7IFByb3ZpZGVyIH0gZnJvbSAnYXdzLWNkay1saWIvY3VzdG9tLXJlc291cmNlcyc7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcblxuY29uc3QgUFJPVklERVJfU0lOR0xFVE9OX0lEID0gJ1Rva2VuSW5qZWN0YWJsZURvY2tlckJ1aWxkZXJQcm92aWRlcic7XG5cbi8qKlxuICogT3B0aW9ucyBmb3IgY3JlYXRpbmcgYSBgVG9rZW5JbmplY3RhYmxlRG9ja2VyQnVpbGRlclByb3ZpZGVyYC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBUb2tlbkluamVjdGFibGVEb2NrZXJCdWlsZGVyUHJvdmlkZXJQcm9wcyB7XG4gIC8qKlxuICAgKiBIb3cgb2Z0ZW4gdGhlIHByb3ZpZGVyIHBvbGxzIGZvciBidWlsZCBjb21wbGV0aW9uLlxuICAgKlxuICAgKiBAZGVmYXVsdCBEdXJhdGlvbi5zZWNvbmRzKDMwKVxuICAgKi9cbiAgcmVhZG9ubHkgcXVlcnlJbnRlcnZhbD86IER1cmF0aW9uO1xufVxuXG4vKipcbiAqIFNoYXJlZCBwcm92aWRlciBmb3IgYFRva2VuSW5qZWN0YWJsZURvY2tlckJ1aWxkZXJgIGluc3RhbmNlcy5cbiAqXG4gKiBDcmVhdGVzIHRoZSBvbkV2ZW50IGFuZCBpc0NvbXBsZXRlIExhbWJkYSBmdW5jdGlvbnMgb25jZSBwZXIgc3RhY2suXG4gKiBFYWNoIGJ1aWxkZXIgaW5zdGFuY2UgcmVnaXN0ZXJzIGl0cyBDb2RlQnVpbGQgcHJvamVjdCBBUk4gc28gdGhlXG4gKiBzaGFyZWQgTGFtYmRhcyBoYXZlIHBlcm1pc3Npb24gdG8gc3RhcnQgYnVpbGRzIGFuZCByZWFkIGxvZ3MuXG4gKi9cbmV4cG9ydCBjbGFzcyBUb2tlbkluamVjdGFibGVEb2NrZXJCdWlsZGVyUHJvdmlkZXIgZXh0ZW5kcyBDb25zdHJ1Y3Qge1xuICAvKipcbiAgICogR2V0IG9yIGNyZWF0ZSB0aGUgc2luZ2xldG9uIHByb3ZpZGVyIGZvciB0aGlzIHN0YWNrLlxuICAgKiBBbGwgYFRva2VuSW5qZWN0YWJsZURvY2tlckJ1aWxkZXJgIGluc3RhbmNlcyBpbiB0aGUgc2FtZSBzdGFja1xuICAgKiBzaGFyZSBhIHNpbmdsZSBwYWlyIG9mIExhbWJkYSBmdW5jdGlvbnMuXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGdldE9yQ3JlYXRlKHNjb3BlOiBDb25zdHJ1Y3QsIHByb3BzPzogVG9rZW5JbmplY3RhYmxlRG9ja2VyQnVpbGRlclByb3ZpZGVyUHJvcHMpOiBUb2tlbkluamVjdGFibGVEb2NrZXJCdWlsZGVyUHJvdmlkZXIge1xuICAgIGNvbnN0IHN0YWNrID0gU3RhY2sub2Yoc2NvcGUpO1xuICAgIGNvbnN0IGV4aXN0aW5nID0gc3RhY2subm9kZS50cnlGaW5kQ2hpbGQoUFJPVklERVJfU0lOR0xFVE9OX0lEKSBhcyBUb2tlbkluamVjdGFibGVEb2NrZXJCdWlsZGVyUHJvdmlkZXIgfCB1bmRlZmluZWQ7XG4gICAgaWYgKGV4aXN0aW5nKSByZXR1cm4gZXhpc3Rpbmc7XG4gICAgcmV0dXJuIG5ldyBUb2tlbkluamVjdGFibGVEb2NrZXJCdWlsZGVyUHJvdmlkZXIoc3RhY2ssIFBST1ZJREVSX1NJTkdMRVRPTl9JRCwgcHJvcHMpO1xuICB9XG5cbiAgLyoqIFRoZSBzZXJ2aWNlIHRva2VuIHVzZWQgYnkgQ3VzdG9tUmVzb3VyY2UgaW5zdGFuY2VzLiAqL1xuICBwdWJsaWMgcmVhZG9ubHkgc2VydmljZVRva2VuOiBzdHJpbmc7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBvbkV2ZW50SGFuZGxlckZ1bmN0aW9uOiBGdW5jdGlvbjtcbiAgcHJpdmF0ZSByZWFkb25seSBpc0NvbXBsZXRlSGFuZGxlckZ1bmN0aW9uOiBGdW5jdGlvbjtcblxuICBwcml2YXRlIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzPzogVG9rZW5JbmplY3RhYmxlRG9ja2VyQnVpbGRlclByb3ZpZGVyUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgdGhpcy5vbkV2ZW50SGFuZGxlckZ1bmN0aW9uID0gbmV3IEZ1bmN0aW9uKHRoaXMsICdPbkV2ZW50SGFuZGxlcicsIHtcbiAgICAgIHJ1bnRpbWU6IFJ1bnRpbWUuTk9ERUpTXzIyX1gsXG4gICAgICBjb2RlOiBDb2RlLmZyb21Bc3NldChwYXRoLnJlc29sdmUoX19kaXJuYW1lLCAnLi4vb25FdmVudCcpKSxcbiAgICAgIGhhbmRsZXI6ICdvbkV2ZW50LmhhbmRsZXInLFxuICAgICAgdGltZW91dDogRHVyYXRpb24ubWludXRlcygxNSksXG4gICAgfSk7XG5cbiAgICB0aGlzLmlzQ29tcGxldGVIYW5kbGVyRnVuY3Rpb24gPSBuZXcgRnVuY3Rpb24odGhpcywgJ0lzQ29tcGxldGVIYW5kbGVyJywge1xuICAgICAgcnVudGltZTogUnVudGltZS5OT0RFSlNfMjJfWCxcbiAgICAgIGNvZGU6IENvZGUuZnJvbUFzc2V0KHBhdGgucmVzb2x2ZShfX2Rpcm5hbWUsICcuLi9pc0NvbXBsZXRlJykpLFxuICAgICAgaGFuZGxlcjogJ2lzQ29tcGxldGUuaGFuZGxlcicsXG4gICAgICB0aW1lb3V0OiBEdXJhdGlvbi5taW51dGVzKDE1KSxcbiAgICB9KTtcbiAgICB0aGlzLmlzQ29tcGxldGVIYW5kbGVyRnVuY3Rpb24uYWRkVG9Sb2xlUG9saWN5KFxuICAgICAgbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgICAnY29kZWJ1aWxkOkJhdGNoR2V0QnVpbGRzJyxcbiAgICAgICAgICAnY29kZWJ1aWxkOkxpc3RCdWlsZHNGb3JQcm9qZWN0JyxcbiAgICAgICAgICAnbG9nczpHZXRMb2dFdmVudHMnLFxuICAgICAgICAgICdsb2dzOkRlc2NyaWJlTG9nU3RyZWFtcycsXG4gICAgICAgICAgJ2xvZ3M6RGVzY3JpYmVMb2dHcm91cHMnLFxuICAgICAgICBdLFxuICAgICAgICByZXNvdXJjZXM6IFsnKiddLFxuICAgICAgfSksXG4gICAgKTtcblxuICAgIGNvbnN0IHByb3ZpZGVyID0gbmV3IFByb3ZpZGVyKHRoaXMsICdQcm92aWRlcicsIHtcbiAgICAgIG9uRXZlbnRIYW5kbGVyOiB0aGlzLm9uRXZlbnRIYW5kbGVyRnVuY3Rpb24sXG4gICAgICBpc0NvbXBsZXRlSGFuZGxlcjogdGhpcy5pc0NvbXBsZXRlSGFuZGxlckZ1bmN0aW9uLFxuICAgICAgcXVlcnlJbnRlcnZhbDogcHJvcHM/LnF1ZXJ5SW50ZXJ2YWwgPz8gRHVyYXRpb24uc2Vjb25kcygzMCksXG4gICAgfSk7XG5cbiAgICB0aGlzLnNlcnZpY2VUb2tlbiA9IHByb3ZpZGVyLnNlcnZpY2VUb2tlbjtcbiAgfVxuXG4gIC8qKlxuICAgKiBHcmFudCB0aGUgc2hhcmVkIExhbWJkYXMgcGVybWlzc2lvbiB0byBzdGFydCBidWlsZHMgZm9yIGEgc3BlY2lmaWNcbiAgICogQ29kZUJ1aWxkIHByb2plY3QgYW5kIHB1bGwvcHVzaCB0byBpdHMgRUNSIHJlcG9zaXRvcnkuXG4gICAqL1xuICBwdWJsaWMgcmVnaXN0ZXJQcm9qZWN0KHByb2plY3Q6IFByb2plY3QsIGVjclJlcG86IFJlcG9zaXRvcnksIGVuY3J5cHRpb25LZXk/OiBLZXkpOiB2b2lkIHtcbiAgICB0aGlzLm9uRXZlbnRIYW5kbGVyRnVuY3Rpb24uYWRkVG9Sb2xlUG9saWN5KFxuICAgICAgbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgIGFjdGlvbnM6IFsnY29kZWJ1aWxkOlN0YXJ0QnVpbGQnXSxcbiAgICAgICAgcmVzb3VyY2VzOiBbcHJvamVjdC5wcm9qZWN0QXJuXSxcbiAgICAgIH0pLFxuICAgICk7XG4gICAgZWNyUmVwby5ncmFudFB1bGxQdXNoKHRoaXMub25FdmVudEhhbmRsZXJGdW5jdGlvbik7XG4gICAgZWNyUmVwby5ncmFudFB1bGxQdXNoKHRoaXMuaXNDb21wbGV0ZUhhbmRsZXJGdW5jdGlvbik7XG5cbiAgICBpZiAoZW5jcnlwdGlvbktleSkge1xuICAgICAgZW5jcnlwdGlvbktleS5ncmFudEVuY3J5cHREZWNyeXB0KHRoaXMub25FdmVudEhhbmRsZXJGdW5jdGlvbik7XG4gICAgICBlbmNyeXB0aW9uS2V5LmdyYW50RW5jcnlwdERlY3J5cHQodGhpcy5pc0NvbXBsZXRlSGFuZGxlckZ1bmN0aW9uKTtcbiAgICB9XG4gIH1cbn1cblxuLyoqXG4gKiBQcm9wZXJ0aWVzIGZvciB0aGUgYFRva2VuSW5qZWN0YWJsZURvY2tlckJ1aWxkZXJgIGNvbnN0cnVjdC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBUb2tlbkluamVjdGFibGVEb2NrZXJCdWlsZGVyUHJvcHMge1xuICAvKipcbiAgICogVGhlIHBhdGggdG8gdGhlIGRpcmVjdG9yeSBjb250YWluaW5nIHRoZSBEb2NrZXJmaWxlIG9yIHNvdXJjZSBjb2RlLlxuICAgKi9cbiAgcmVhZG9ubHkgcGF0aDogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBCdWlsZCBhcmd1bWVudHMgdG8gcGFzcyB0byB0aGUgRG9ja2VyIGJ1aWxkIHByb2Nlc3MuXG4gICAqIFRoZXNlIGFyZSB0cmFuc2Zvcm1lZCBpbnRvIGAtLWJ1aWxkLWFyZyBLRVk9VkFMVUVgIGZsYWdzLlxuICAgKiBAZXhhbXBsZVxuICAgKiB7XG4gICAqICAgVE9LRU46ICdteS1zZWNyZXQtdG9rZW4nLFxuICAgKiAgIEVOVjogJ3Byb2R1Y3Rpb24nXG4gICAqIH1cbiAgICovXG4gIHJlYWRvbmx5IGJ1aWxkQXJncz86IHsgW2tleTogc3RyaW5nXTogc3RyaW5nIH07XG5cbiAgLyoqXG4gICAqIFRoZSBBUk4gb2YgdGhlIEFXUyBTZWNyZXRzIE1hbmFnZXIgc2VjcmV0IGNvbnRhaW5pbmcgRG9ja2VyIGxvZ2luIGNyZWRlbnRpYWxzLlxuICAgKiBUaGlzIHNlY3JldCBzaG91bGQgc3RvcmUgYSBKU09OIG9iamVjdCB3aXRoIHRoZSBmb2xsb3dpbmcgc3RydWN0dXJlOlxuICAgKiBgYGBqc29uXG4gICAqIHtcbiAgICogICBcInVzZXJuYW1lXCI6IFwibXktZG9ja2VyLXVzZXJuYW1lXCIsXG4gICAqICAgXCJwYXNzd29yZFwiOiBcIm15LWRvY2tlci1wYXNzd29yZFwiXG4gICAqIH1cbiAgICogYGBgXG4gICAqIElmIG5vdCBwcm92aWRlZCAob3Igbm90IG5lZWRlZCksIHRoZSBjb25zdHJ1Y3Qgd2lsbCBza2lwIERvY2tlciBIdWIgbG9naW4uXG4gICAqXG4gICAqICoqTm90ZSoqOiBUaGUgc2VjcmV0IG11c3QgYmUgaW4gdGhlIHNhbWUgcmVnaW9uIGFzIHRoZSBzdGFjay5cbiAgICpcbiAgICogQGV4YW1wbGUgJ2Fybjphd3M6c2VjcmV0c21hbmFnZXI6dXMtZWFzdC0xOjEyMzQ1Njc4OTAxMjpzZWNyZXQ6RG9ja2VyTG9naW5TZWNyZXQnXG4gICAqL1xuICByZWFkb25seSBkb2NrZXJMb2dpblNlY3JldEFybj86IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIFZQQyBpbiB3aGljaCB0aGUgQ29kZUJ1aWxkIHByb2plY3Qgd2lsbCBiZSBkZXBsb3llZC5cbiAgICogSWYgcHJvdmlkZWQsIHRoZSBDb2RlQnVpbGQgcHJvamVjdCB3aWxsIGJlIGxhdW5jaGVkIHdpdGhpbiB0aGUgc3BlY2lmaWVkIFZQQy5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBObyBWUEMgaXMgYXR0YWNoZWQsIGFuZCB0aGUgQ29kZUJ1aWxkIHByb2plY3Qgd2lsbCB1c2UgcHVibGljIGludGVybmV0LlxuICAgKi9cbiAgcmVhZG9ubHkgdnBjPzogSVZwYztcblxuICAvKipcbiAgICogVGhlIHNlY3VyaXR5IGdyb3VwcyB0byBhdHRhY2ggdG8gdGhlIENvZGVCdWlsZCBwcm9qZWN0LlxuICAgKiBUaGVzZSBkZWZpbmUgdGhlIG5ldHdvcmsgYWNjZXNzIHJ1bGVzIGZvciB0aGUgQ29kZUJ1aWxkIHByb2plY3QuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gTm8gc2VjdXJpdHkgZ3JvdXBzIGFyZSBhdHRhY2hlZC5cbiAgICovXG4gIHJlYWRvbmx5IHNlY3VyaXR5R3JvdXBzPzogSVNlY3VyaXR5R3JvdXBbXTtcblxuICAvKipcbiAgICogVGhlIHN1Ym5ldCBzZWxlY3Rpb24gdG8gc3BlY2lmeSB3aGljaCBzdWJuZXRzIHRvIHVzZSB3aXRoaW4gdGhlIFZQQy5cbiAgICogQWxsb3dzIHRoZSB1c2VyIHRvIHNlbGVjdCBwcml2YXRlLCBwdWJsaWMsIG9yIGlzb2xhdGVkIHN1Ym5ldHMuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gQWxsIHN1Ym5ldHMgaW4gdGhlIFZQQyBhcmUgdXNlZC5cbiAgICovXG4gIHJlYWRvbmx5IHN1Ym5ldFNlbGVjdGlvbj86IFN1Ym5ldFNlbGVjdGlvbjtcblxuICAvKipcbiAgICogQ3VzdG9tIGNvbW1hbmRzIHRvIHJ1biBkdXJpbmcgdGhlIGluc3RhbGwgcGhhc2Ugb2YgQ29kZUJ1aWxkLlxuICAgKlxuICAgKiAqKkV4YW1wbGUqKjpcbiAgICogYGBgdHNcbiAgICogaW5zdGFsbENvbW1hbmRzOiBbXG4gICAqICAgJ2VjaG8gXCJVcGRhdGluZyBwYWNrYWdlIGxpc3RzLi4uXCInLFxuICAgKiAgICdhcHQtZ2V0IHVwZGF0ZSAteScsXG4gICAqICAgJ2VjaG8gXCJJbnN0YWxsaW5nIHJlcXVpcmVkIHBhY2thZ2VzLi4uXCInLFxuICAgKiAgICdhcHQtZ2V0IGluc3RhbGwgLXkgY3VybCBkbnN1dGlscycsXG4gICAqIF0sXG4gICAqIGBgYFxuICAgKiBAZGVmYXVsdCAtIE5vIGFkZGl0aW9uYWwgaW5zdGFsbCBjb21tYW5kcy5cbiAgICovXG4gIHJlYWRvbmx5IGluc3RhbGxDb21tYW5kcz86IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBDdXN0b20gY29tbWFuZHMgdG8gcnVuIGR1cmluZyB0aGUgcHJlX2J1aWxkIHBoYXNlIG9mIENvZGVCdWlsZC5cbiAgICpcbiAgICogKipFeGFtcGxlKio6XG4gICAqIGBgYHRzXG4gICAqIHByZUJ1aWxkQ29tbWFuZHM6IFtcbiAgICogICAnZWNobyBcIkZldGNoaW5nIGNvbmZpZ3VyYXRpb24gZnJvbSBwcml2YXRlIEFQSS4uLlwiJyxcbiAgICogICAnY3VybCAtbyBjb25maWcuanNvbiBodHRwczovL2FwaS5leGFtcGxlLmNvbS9jb25maWcnLFxuICAgKiBdLFxuICAgKiBgYGBcbiAgICogQGRlZmF1bHQgLSBObyBhZGRpdGlvbmFsIHByZS1idWlsZCBjb21tYW5kcy5cbiAgICovXG4gIHJlYWRvbmx5IHByZUJ1aWxkQ29tbWFuZHM/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogV2hldGhlciB0byBlbmFibGUgS01TIGVuY3J5cHRpb24gZm9yIHRoZSBFQ1IgcmVwb3NpdG9yeS5cbiAgICogSWYgYHRydWVgLCBhIEtNUyBrZXkgd2lsbCBiZSBjcmVhdGVkIGZvciBlbmNyeXB0aW5nIEVDUiBpbWFnZXMuXG4gICAqIElmIGBmYWxzZWAsIHRoZSByZXBvc2l0b3J5IHdpbGwgdXNlIEFFUy0yNTYgZW5jcnlwdGlvbi5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBmYWxzZVxuICAgKi9cbiAgcmVhZG9ubHkga21zRW5jcnlwdGlvbj86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFRoZSBxdWVyeSBpbnRlcnZhbCBmb3IgY2hlY2tpbmcgaWYgdGhlIENvZGVCdWlsZCBwcm9qZWN0IGhhcyBjb21wbGV0ZWQuXG4gICAqIFRoaXMgZGV0ZXJtaW5lcyBob3cgZnJlcXVlbnRseSB0aGUgY3VzdG9tIHJlc291cmNlIHBvbGxzIGZvciBidWlsZCBjb21wbGV0aW9uLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIER1cmF0aW9uLnNlY29uZHMoMzApXG4gICAqL1xuICByZWFkb25seSBjb21wbGV0ZW5lc3NRdWVyeUludGVydmFsPzogRHVyYXRpb247XG5cbiAgLyoqXG4gICAqIEEgbGlzdCBvZiBmaWxlIHBhdGhzIGluIHRoZSBEb2NrZXIgZGlyZWN0b3J5IHRvIGV4Y2x1ZGUgZnJvbSBidWlsZC5cbiAgICogV2lsbCB1c2UgcGF0aHMgaW4gLmRvY2tlcmlnbm9yZSBmaWxlIGlmIHByZXNlbnQuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gTm8gZmlsZSBwYXRoIGV4Y2x1c2lvbnNcbiAgICovXG4gIHJlYWRvbmx5IGV4Y2x1ZGU/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogVGhlIG5hbWUgb2YgdGhlIERvY2tlcmZpbGUgdG8gdXNlIGZvciB0aGUgYnVpbGQuXG4gICAqIFBhc3NlZCBhcyBgLS1maWxlYCB0byBgZG9ja2VyIGJ1aWxkYC5cbiAgICpcbiAgICogQGV4YW1wbGUgJ0RvY2tlcmZpbGUucHJvZHVjdGlvbidcbiAgICogQGRlZmF1bHQgJ0RvY2tlcmZpbGUnXG4gICAqL1xuICByZWFkb25seSBmaWxlPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBXaGVuIGB0cnVlYCwgZGlzYWJsZXMgRG9ja2VyIGxheWVyIGNhY2hpbmcuIEV2ZXJ5IGJ1aWxkIHJ1bnMgZnJvbSBzY3JhdGNoLlxuICAgKiBVc2UgZm9yIGRlYnVnZ2luZywgY29ycnVwdGVkIGNhY2hlLCBvciBtYWpvciBkZXBlbmRlbmN5IGNoYW5nZXMuXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBjYWNoZURpc2FibGVkPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogQ2xvdWRXYXRjaCBsb2cgZ3JvdXAgZm9yIENvZGVCdWlsZCBidWlsZCBsb2dzLlxuICAgKiBXaGVuIHByb3ZpZGVkIHdpdGggYSBSRVRBSU4gcmVtb3ZhbCBwb2xpY3ksIGJ1aWxkIGxvZ3Mgc3Vydml2ZSByb2xsYmFja3NcbiAgICogYW5kIHN0YWNrIGRlbGV0aW9uIGZvciBkZWJ1Z2dpbmcuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gQ29kZUJ1aWxkIGRlZmF1bHQgbG9nZ2luZyAobG9ncyBhcmUgZGVsZXRlZCBvbiByb2xsYmFjaylcbiAgICovXG4gIHJlYWRvbmx5IGJ1aWxkTG9nR3JvdXA/OiBJTG9nR3JvdXA7XG5cbiAgLyoqXG4gICAqIFNoYXJlZCBwcm92aWRlciBmb3IgdGhlIGN1c3RvbSByZXNvdXJjZSBMYW1iZGFzLlxuICAgKiBVc2UgYFRva2VuSW5qZWN0YWJsZURvY2tlckJ1aWxkZXJQcm92aWRlci5nZXRPckNyZWF0ZSh0aGlzKWAgdG8gY3JlYXRlXG4gICAqIGEgc2luZ2xldG9uIHRoYXQgaXMgc2hhcmVkIGFjcm9zcyBhbGwgYnVpbGRlcnMgaW4gdGhlIHNhbWUgc3RhY2suXG4gICAqXG4gICAqIFdoZW4gb21pdHRlZCwgZWFjaCBidWlsZGVyIGNyZWF0ZXMgaXRzIG93biBMYW1iZGFzIChvcmlnaW5hbCBiZWhhdmlvcikuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gQSBuZXcgcHJvdmlkZXIgaXMgY3JlYXRlZCBwZXIgYnVpbGRlciBpbnN0YW5jZVxuICAgKi9cbiAgcmVhZG9ubHkgcHJvdmlkZXI/OiBUb2tlbkluamVjdGFibGVEb2NrZXJCdWlsZGVyUHJvdmlkZXI7XG59XG5cbi8qKlxuICogQSBDREsgY29uc3RydWN0IHRvIGJ1aWxkIGFuZCBwdXNoIERvY2tlciBpbWFnZXMgdG8gYW4gRUNSIHJlcG9zaXRvcnkgdXNpbmdcbiAqIENvZGVCdWlsZCBhbmQgTGFtYmRhIGN1c3RvbSByZXNvdXJjZXMsICoqdGhlbioqIHJldHJpZXZlIHRoZSBmaW5hbCBpbWFnZSB0YWdcbiAqIHNvIHRoYXQgRUNTL0xhbWJkYSByZWZlcmVuY2VzIHVzZSB0aGUgZXhhY3QgZGlnZXN0LlxuICovXG5leHBvcnQgY2xhc3MgVG9rZW5JbmplY3RhYmxlRG9ja2VyQnVpbGRlciBleHRlbmRzIENvbnN0cnVjdCB7XG4gIC8qKlxuICAgKiBUaGUgRUNSIHJlcG9zaXRvcnkgdGhhdCBzdG9yZXMgdGhlIHJlc3VsdGluZyBEb2NrZXIgaW1hZ2UuXG4gICAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGVjclJlcG9zaXRvcnk6IFJlcG9zaXRvcnk7XG5cbiAgLyoqXG4gICAqIEFuIEVDUy1jb21wYXRpYmxlIGNvbnRhaW5lciBpbWFnZSByZWZlcmVuY2luZyB0aGUgdGFnXG4gICAqIG9mIHRoZSBidWlsdCBEb2NrZXIgaW1hZ2UuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgY29udGFpbmVySW1hZ2U6IENvbnRhaW5lckltYWdlO1xuXG4gIC8qKlxuICAgKiBBIExhbWJkYS1jb21wYXRpYmxlIERvY2tlckltYWdlQ29kZSByZWZlcmVuY2luZyB0aGUgdGFnXG4gICAqIG9mIHRoZSBidWlsdCBEb2NrZXIgaW1hZ2UuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgZG9ja2VySW1hZ2VDb2RlOiBEb2NrZXJJbWFnZUNvZGU7XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBuZXcgYFRva2VuSW5qZWN0YWJsZURvY2tlckJ1aWxkZXJgLlxuICAgKlxuICAgKiBAcGFyYW0gc2NvcGUgVGhlIHNjb3BlIGluIHdoaWNoIHRvIGRlZmluZSB0aGlzIGNvbnN0cnVjdC5cbiAgICogQHBhcmFtIGlkIFRoZSBzY29wZWQgY29uc3RydWN0IElELlxuICAgKiBAcGFyYW0gcHJvcHMgQ29uZmlndXJhdGlvbiBmb3IgYnVpbGRpbmcgYW5kIHB1c2hpbmcgdGhlIERvY2tlciBpbWFnZS5cbiAgICovXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBUb2tlbkluamVjdGFibGVEb2NrZXJCdWlsZGVyUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgY29uc3Qge1xuICAgICAgcGF0aDogc291cmNlUGF0aCxcbiAgICAgIGJ1aWxkQXJncyxcbiAgICAgIGRvY2tlckxvZ2luU2VjcmV0QXJuLFxuICAgICAgdnBjLFxuICAgICAgc2VjdXJpdHlHcm91cHMsXG4gICAgICBzdWJuZXRTZWxlY3Rpb24sXG4gICAgICBpbnN0YWxsQ29tbWFuZHMsXG4gICAgICBwcmVCdWlsZENvbW1hbmRzLFxuICAgICAga21zRW5jcnlwdGlvbiA9IGZhbHNlLFxuICAgICAgY29tcGxldGVuZXNzUXVlcnlJbnRlcnZhbCxcbiAgICAgIGV4Y2x1ZGUsXG4gICAgICBmaWxlOiBkb2NrZXJGaWxlLFxuICAgICAgY2FjaGVEaXNhYmxlZCA9IGZhbHNlLFxuICAgICAgYnVpbGRMb2dHcm91cDogYnVpbGRMb2dHcm91cFByb3AsXG4gICAgICBwcm92aWRlcjogc2hhcmVkUHJvdmlkZXIsXG4gICAgfSA9IHByb3BzO1xuXG4gICAgLy8gR2VuZXJhdGUgYW4gZXBoZW1lcmFsIHRhZyBmb3IgQ29kZUJ1aWxkXG4gICAgY29uc3QgaW1hZ2VUYWcgPSBjcnlwdG8ucmFuZG9tVVVJRCgpO1xuXG4gICAgLy8gT3B0aW9uYWxseSBkZWZpbmUgYSBLTVMga2V5IGZvciBFQ1IgZW5jcnlwdGlvbiBpZiByZXF1ZXN0ZWRcbiAgICBsZXQgZW5jcnlwdGlvbktleTogS2V5IHwgdW5kZWZpbmVkO1xuICAgIGlmIChrbXNFbmNyeXB0aW9uKSB7XG4gICAgICBlbmNyeXB0aW9uS2V5ID0gbmV3IEtleSh0aGlzLCAnRWNyRW5jcnlwdGlvbktleScsIHtcbiAgICAgICAgZW5hYmxlS2V5Um90YXRpb246IHRydWUsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyBDcmVhdGUgYW4gRUNSIHJlcG9zaXRvcnkgKG9wdGlvbmFsbHkgd2l0aCBLTVMgZW5jcnlwdGlvbilcbiAgICB0aGlzLmVjclJlcG9zaXRvcnkgPSBuZXcgUmVwb3NpdG9yeSh0aGlzLCAnRUNSUmVwb3NpdG9yeScsIHtcbiAgICAgIGxpZmVjeWNsZVJ1bGVzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBydWxlUHJpb3JpdHk6IDEsXG4gICAgICAgICAgZGVzY3JpcHRpb246ICdSZW1vdmUgdW50YWdnZWQgaW1hZ2VzIGFmdGVyIDEgZGF5JyxcbiAgICAgICAgICB0YWdTdGF0dXM6IFRhZ1N0YXR1cy5VTlRBR0dFRCxcbiAgICAgICAgICBtYXhJbWFnZUFnZTogRHVyYXRpb24uZGF5cygxKSxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgICBlbmNyeXB0aW9uOiBrbXNFbmNyeXB0aW9uID8gUmVwb3NpdG9yeUVuY3J5cHRpb24uS01TIDogUmVwb3NpdG9yeUVuY3J5cHRpb24uQUVTXzI1NixcbiAgICAgIGVuY3J5cHRpb25LZXk6IGttc0VuY3J5cHRpb24gPyBlbmNyeXB0aW9uS2V5IDogdW5kZWZpbmVkLFxuICAgICAgaW1hZ2VTY2FuT25QdXNoOiB0cnVlLFxuICAgIH0pO1xuXG4gICAgbGV0IGVmZmVjdGl2ZUV4Y2x1ZGUgPSBleGNsdWRlO1xuICAgIGlmICghZWZmZWN0aXZlRXhjbHVkZSkge1xuICAgICAgY29uc3QgZG9ja2VyaWdub3JlUGF0aCA9IHBhdGguam9pbihzb3VyY2VQYXRoLCAnLmRvY2tlcmlnbm9yZScpO1xuICAgICAgaWYgKGZzLmV4aXN0c1N5bmMoZG9ja2VyaWdub3JlUGF0aCkpIHtcbiAgICAgICAgY29uc3QgZmlsZUNvbnRlbnQgPSBmcy5yZWFkRmlsZVN5bmMoZG9ja2VyaWdub3JlUGF0aCwgJ3V0ZjgnKTtcbiAgICAgICAgZWZmZWN0aXZlRXhjbHVkZSA9IGZpbGVDb250ZW50XG4gICAgICAgICAgLnNwbGl0KCdcXG4nKVxuICAgICAgICAgIC5tYXAoKGxpbmU6IHN0cmluZykgPT4gbGluZS50cmltKCkpXG4gICAgICAgICAgLmZpbHRlcigobGluZTogc3RyaW5nKSA9PiBsaW5lLmxlbmd0aCA+IDAgJiYgIWxpbmUuc3RhcnRzV2l0aCgnIycpKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBFbnN1cmUgdGhlIHRhcmdldCBEb2NrZXJmaWxlIGlzIG5ldmVyIGV4Y2x1ZGVkIChoYW5kbGVzIGdsb2JzIGxpa2UgXCJEb2NrZXJmaWxlKlwiKVxuICAgIGNvbnN0IGRvY2tlckZpbGVOYW1lID0gZG9ja2VyRmlsZSA/PyAnRG9ja2VyZmlsZSc7XG4gICAgaWYgKGVmZmVjdGl2ZUV4Y2x1ZGUpIHtcbiAgICAgIGVmZmVjdGl2ZUV4Y2x1ZGUgPSBlZmZlY3RpdmVFeGNsdWRlLmZpbHRlcigocGF0dGVybjogc3RyaW5nKSA9PiB7XG4gICAgICAgIGNvbnN0IGVzY2FwZWQgPSBwYXR0ZXJuLnJlcGxhY2UoL1suK14ke30oKXxbXFxdXFxcXF0vZywgJ1xcXFwkJicpO1xuICAgICAgICBjb25zdCByZWdleCA9IG5ldyBSZWdFeHAoYF4ke2VzY2FwZWQucmVwbGFjZSgvXFwqL2csICcuKicpLnJlcGxhY2UoL1xcPy9nLCAnLicpfSRgLCAnaScpO1xuICAgICAgICByZXR1cm4gIXJlZ2V4LnRlc3QoZG9ja2VyRmlsZU5hbWUpO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gV3JhcCB0aGUgc291cmNlIGZvbGRlciBhcyBhbiBTMyBhc3NldCBmb3IgQ29kZUJ1aWxkIHRvIHVzZVxuICAgIGNvbnN0IHNvdXJjZUFzc2V0ID0gbmV3IEFzc2V0KHRoaXMsICdTb3VyY2VBc3NldCcsIHtcbiAgICAgIHBhdGg6IHNvdXJjZVBhdGgsXG4gICAgICBleGNsdWRlOiBlZmZlY3RpdmVFeGNsdWRlLFxuICAgIH0pO1xuXG4gICAgLy8gQ29udmVydCBidWlsZEFyZ3MgdG8gYSBDTEktZnJpZW5kbHkgc3RyaW5nXG4gICAgY29uc3QgYnVpbGRBcmdzU3RyaW5nID0gYnVpbGRBcmdzXG4gICAgICA/IE9iamVjdC5lbnRyaWVzKGJ1aWxkQXJncylcbiAgICAgICAgLm1hcCgoW2ssIHZdKSA9PiBgLS1idWlsZC1hcmcgJHtrfT0ke3Z9YClcbiAgICAgICAgLmpvaW4oJyAnKVxuICAgICAgOiAnJztcblxuICAgIGNvbnN0IGRvY2tlckZpbGVGbGFnID0gZG9ja2VyRmlsZSA/IGAtZiAkQ09ERUJVSUxEX1NSQ19ESVIvJHtkb2NrZXJGaWxlfWAgOiAnJztcblxuICAgIC8vIE9wdGlvbmFsIERvY2tlckh1YiBsb2dpbiwgaWYgYSBzZWNyZXQgQVJOIGlzIHByb3ZpZGVkXG4gICAgY29uc3QgZG9ja2VyTG9naW5Db21tYW5kcyA9IGRvY2tlckxvZ2luU2VjcmV0QXJuXG4gICAgICA/IFtcbiAgICAgICAgJ2VjaG8gXCJSZXRyaWV2aW5nIERvY2tlciBjcmVkZW50aWFscy4uLlwiJyxcbiAgICAgICAgJ2FwdC1nZXQgdXBkYXRlIC15ICYmIGFwdC1nZXQgaW5zdGFsbCAteSBqcScsXG4gICAgICAgIGBET0NLRVJfVVNFUk5BTUU9JChhd3Mgc2VjcmV0c21hbmFnZXIgZ2V0LXNlY3JldC12YWx1ZSAtLXNlY3JldC1pZCAke2RvY2tlckxvZ2luU2VjcmV0QXJufSAtLXF1ZXJ5IFNlY3JldFN0cmluZyAtLW91dHB1dCB0ZXh0IHwganEgLXIgLnVzZXJuYW1lKWAsXG4gICAgICAgIGBET0NLRVJfUEFTU1dPUkQ9JChhd3Mgc2VjcmV0c21hbmFnZXIgZ2V0LXNlY3JldC12YWx1ZSAtLXNlY3JldC1pZCAke2RvY2tlckxvZ2luU2VjcmV0QXJufSAtLXF1ZXJ5IFNlY3JldFN0cmluZyAtLW91dHB1dCB0ZXh0IHwganEgLXIgLnBhc3N3b3JkKWAsXG4gICAgICAgICdlY2hvIFwiTG9nZ2luZyBpbiB0byBEb2NrZXIgSHViLi4uXCInLFxuICAgICAgICAnZWNobyAkRE9DS0VSX1BBU1NXT1JEIHwgZG9ja2VyIGxvZ2luIC0tdXNlcm5hbWUgJERPQ0tFUl9VU0VSTkFNRSAtLXBhc3N3b3JkLXN0ZGluJyxcbiAgICAgIF1cbiAgICAgIDogWydlY2hvIFwiTm8gRG9ja2VyIGNyZWRlbnRpYWxzLiBTa2lwcGluZyBEb2NrZXIgSHViIGxvZ2luLlwiJ107XG5cbiAgICBjb25zdCBidWlsZHhJbnN0YWxsQ29tbWFuZHMgPSBjYWNoZURpc2FibGVkXG4gICAgICA/IFtdXG4gICAgICA6IFtcbiAgICAgICAgJ2VjaG8gXCJTZXR0aW5nIHVwIERvY2tlciBidWlsZHggZm9yIEVDUiBsYXllciBjYWNoZS4uLlwiJyxcbiAgICAgICAgJ2RvY2tlciBidWlsZHggY3JlYXRlIC0tZHJpdmVyIGRvY2tlci1jb250YWluZXIgLS1uYW1lIGVjci1jYWNoZS1idWlsZGVyIC0tdXNlIDI+L2Rldi9udWxsIHx8IGRvY2tlciBidWlsZHggdXNlIGVjci1jYWNoZS1idWlsZGVyJyxcbiAgICAgIF07XG5cbiAgICBjb25zdCBidWlsZENvbW1hbmQgPSBjYWNoZURpc2FibGVkXG4gICAgICA/IGBkb2NrZXIgYnVpbGQgJHtkb2NrZXJGaWxlRmxhZ30gJHtidWlsZEFyZ3NTdHJpbmd9IC10ICRFQ1JfUkVQT19VUkk6JHtpbWFnZVRhZ30gJENPREVCVUlMRF9TUkNfRElSYFxuICAgICAgOiBgZG9ja2VyIGJ1aWxkeCBidWlsZCAtLXB1c2ggLS1jYWNoZS1mcm9tIHR5cGU9cmVnaXN0cnkscmVmPSRFQ1JfUkVQT19VUkk6Y2FjaGUgLS1jYWNoZS10byB0eXBlPXJlZ2lzdHJ5LHJlZj0kRUNSX1JFUE9fVVJJOmNhY2hlLG1vZGU9bWF4LGltYWdlLW1hbmlmZXN0PXRydWUgJHtkb2NrZXJGaWxlRmxhZ30gJHtidWlsZEFyZ3NTdHJpbmd9IC10ICRFQ1JfUkVQT19VUkk6JHtpbWFnZVRhZ30gJENPREVCVUlMRF9TUkNfRElSYDtcblxuICAgIGNvbnN0IGJ1aWxkU3BlY09iaiA9IHtcbiAgICAgIHZlcnNpb246ICcwLjInLFxuICAgICAgcGhhc2VzOiB7XG4gICAgICAgIGluc3RhbGw6IHtcbiAgICAgICAgICBjb21tYW5kczogW1xuICAgICAgICAgICAgJ2VjaG8gXCJCZWdpbm5pbmcgaW5zdGFsbCBwaGFzZS4uLlwiJyxcbiAgICAgICAgICAgIC4uLihpbnN0YWxsQ29tbWFuZHMgPz8gW10pLFxuICAgICAgICAgICAgLi4uYnVpbGR4SW5zdGFsbENvbW1hbmRzLFxuICAgICAgICAgIF0sXG4gICAgICAgIH0sXG4gICAgICAgIHByZV9idWlsZDoge1xuICAgICAgICAgIGNvbW1hbmRzOiBbXG4gICAgICAgICAgICAuLi4ocHJlQnVpbGRDb21tYW5kcyA/PyBbXSksXG4gICAgICAgICAgICAuLi5kb2NrZXJMb2dpbkNvbW1hbmRzLFxuICAgICAgICAgICAgJ2VjaG8gXCJSZXRyaWV2aW5nIEFXUyBBY2NvdW50IElELi4uXCInLFxuICAgICAgICAgICAgJ2V4cG9ydCBBQ0NPVU5UX0lEPSQoYXdzIHN0cyBnZXQtY2FsbGVyLWlkZW50aXR5IC0tcXVlcnkgQWNjb3VudCAtLW91dHB1dCB0ZXh0KScsXG4gICAgICAgICAgICAnZWNobyBcIkxvZ2dpbmcgaW50byBBbWF6b24gRUNSLi4uXCInLFxuICAgICAgICAgICAgJ2F3cyBlY3IgZ2V0LWxvZ2luLXBhc3N3b3JkIC0tcmVnaW9uICRBV1NfREVGQVVMVF9SRUdJT04gfCBkb2NrZXIgbG9naW4gLS11c2VybmFtZSBBV1MgLS1wYXNzd29yZC1zdGRpbiAkQUNDT1VOVF9JRC5ka3IuZWNyLiRBV1NfREVGQVVMVF9SRUdJT04uYW1hem9uYXdzLmNvbScsXG4gICAgICAgICAgXSxcbiAgICAgICAgfSxcbiAgICAgICAgYnVpbGQ6IHtcbiAgICAgICAgICBjb21tYW5kczogW1xuICAgICAgICAgICAgYGVjaG8gXCJCdWlsZGluZyBEb2NrZXIgaW1hZ2Ugd2l0aCB0YWcgJHtpbWFnZVRhZ30uLi5cImAsXG4gICAgICAgICAgICBidWlsZENvbW1hbmQsXG4gICAgICAgICAgXSxcbiAgICAgICAgfSxcbiAgICAgICAgLi4uKGNhY2hlRGlzYWJsZWQgJiYge1xuICAgICAgICAgIHBvc3RfYnVpbGQ6IHtcbiAgICAgICAgICAgIGNvbW1hbmRzOiBbXG4gICAgICAgICAgICAgIGBlY2hvIFwiUHVzaGluZyBEb2NrZXIgaW1hZ2Ugd2l0aCB0YWcgJHtpbWFnZVRhZ30uLi5cImAsXG4gICAgICAgICAgICAgIGBkb2NrZXIgcHVzaCAkRUNSX1JFUE9fVVJJOiR7aW1hZ2VUYWd9YCxcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgfSxcbiAgICAgICAgfSksXG4gICAgICB9LFxuICAgIH07XG5cbiAgICAvLyBDcmVhdGUgdGhlIENvZGVCdWlsZCBwcm9qZWN0XG4gICAgY29uc3QgY29kZUJ1aWxkUHJvamVjdCA9IG5ldyBQcm9qZWN0KHRoaXMsICdDb2RlQnVpbGRQcm9qZWN0Jywge1xuICAgICAgc291cmNlOiBTb3VyY2UuczMoe1xuICAgICAgICBidWNrZXQ6IHNvdXJjZUFzc2V0LmJ1Y2tldCxcbiAgICAgICAgcGF0aDogc291cmNlQXNzZXQuczNPYmplY3RLZXksXG4gICAgICB9KSxcbiAgICAgIGVudmlyb25tZW50OiB7XG4gICAgICAgIGJ1aWxkSW1hZ2U6IExpbnV4QnVpbGRJbWFnZS5TVEFOREFSRF83XzAsXG4gICAgICAgIHByaXZpbGVnZWQ6IHRydWUsXG4gICAgICB9LFxuICAgICAgZW52aXJvbm1lbnRWYXJpYWJsZXM6IHtcbiAgICAgICAgRUNSX1JFUE9fVVJJOiB7IHZhbHVlOiB0aGlzLmVjclJlcG9zaXRvcnkucmVwb3NpdG9yeVVyaSB9LFxuICAgICAgfSxcbiAgICAgIGJ1aWxkU3BlYzogQnVpbGRTcGVjLmZyb21PYmplY3QoYnVpbGRTcGVjT2JqKSxcbiAgICAgIC4uLihidWlsZExvZ0dyb3VwUHJvcCAmJiB7XG4gICAgICAgIGxvZ2dpbmc6IHtcbiAgICAgICAgICBjbG91ZFdhdGNoOiB7XG4gICAgICAgICAgICBsb2dHcm91cDogYnVpbGRMb2dHcm91cFByb3AsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0pLFxuICAgICAgdnBjLFxuICAgICAgc2VjdXJpdHlHcm91cHMsXG4gICAgICBzdWJuZXRTZWxlY3Rpb24sXG4gICAgfSk7XG5cbiAgICAvLyBHcmFudCBDb2RlQnVpbGQgdGhlIGFiaWxpdHkgdG8gaW50ZXJhY3Qgd2l0aCBFQ1JcbiAgICB0aGlzLmVjclJlcG9zaXRvcnkuZ3JhbnRQdWxsUHVzaChjb2RlQnVpbGRQcm9qZWN0KTtcbiAgICBjb2RlQnVpbGRQcm9qZWN0LmFkZFRvUm9sZVBvbGljeShcbiAgICAgIG5ldyBQb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBhY3Rpb25zOiBbXG4gICAgICAgICAgJ2VjcjpHZXRBdXRob3JpemF0aW9uVG9rZW4nLFxuICAgICAgICAgICdlY3I6R2V0RG93bmxvYWRVcmxGb3JMYXllcicsXG4gICAgICAgICAgJ2VjcjpCYXRjaENoZWNrTGF5ZXJBdmFpbGFiaWxpdHknLFxuICAgICAgICBdLFxuICAgICAgICByZXNvdXJjZXM6IFsnKiddLFxuICAgICAgfSksXG4gICAgKTtcbiAgICBpZiAoZG9ja2VyTG9naW5TZWNyZXRBcm4pIHtcbiAgICAgIGNvZGVCdWlsZFByb2plY3QuYWRkVG9Sb2xlUG9saWN5KFxuICAgICAgICBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgICBhY3Rpb25zOiBbJ3NlY3JldHNtYW5hZ2VyOkdldFNlY3JldFZhbHVlJ10sXG4gICAgICAgICAgcmVzb3VyY2VzOiBbZG9ja2VyTG9naW5TZWNyZXRBcm5dLFxuICAgICAgICB9KSxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gQ29uZGl0aW9uYWxseSBncmFudCBLTVMgZW5jcnlwdC9kZWNyeXB0IGlmIGEga2V5IGlzIHVzZWRcbiAgICBpZiAoZW5jcnlwdGlvbktleSkge1xuICAgICAgZW5jcnlwdGlvbktleS5ncmFudEVuY3J5cHREZWNyeXB0KGNvZGVCdWlsZFByb2plY3Qucm9sZSEpO1xuICAgIH1cblxuICAgIC8vIFJlc29sdmUgdGhlIHNlcnZpY2UgdG9rZW46IHNoYXJlZCBwcm92aWRlciBvciBwZXItaW5zdGFuY2UgTGFtYmRhc1xuICAgIGxldCBzZXJ2aWNlVG9rZW46IHN0cmluZztcbiAgICBpZiAoc2hhcmVkUHJvdmlkZXIpIHtcbiAgICAgIHNoYXJlZFByb3ZpZGVyLnJlZ2lzdGVyUHJvamVjdChjb2RlQnVpbGRQcm9qZWN0LCB0aGlzLmVjclJlcG9zaXRvcnksIGVuY3J5cHRpb25LZXkpO1xuICAgICAgc2VydmljZVRva2VuID0gc2hhcmVkUHJvdmlkZXIuc2VydmljZVRva2VuO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBvbkV2ZW50SGFuZGxlckZ1bmN0aW9uID0gbmV3IEZ1bmN0aW9uKHRoaXMsICdPbkV2ZW50SGFuZGxlckZ1bmN0aW9uJywge1xuICAgICAgICBydW50aW1lOiBSdW50aW1lLk5PREVKU18yMl9YLFxuICAgICAgICBjb2RlOiBDb2RlLmZyb21Bc3NldChwYXRoLnJlc29sdmUoX19kaXJuYW1lLCAnLi4vb25FdmVudCcpKSxcbiAgICAgICAgaGFuZGxlcjogJ29uRXZlbnQuaGFuZGxlcicsXG4gICAgICAgIHRpbWVvdXQ6IER1cmF0aW9uLm1pbnV0ZXMoMTUpLFxuICAgICAgfSk7XG4gICAgICBvbkV2ZW50SGFuZGxlckZ1bmN0aW9uLmFkZFRvUm9sZVBvbGljeShcbiAgICAgICAgbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgICAgYWN0aW9uczogWydjb2RlYnVpbGQ6U3RhcnRCdWlsZCddLFxuICAgICAgICAgIHJlc291cmNlczogW2NvZGVCdWlsZFByb2plY3QucHJvamVjdEFybl0sXG4gICAgICAgIH0pLFxuICAgICAgKTtcblxuICAgICAgY29uc3QgaXNDb21wbGV0ZUhhbmRsZXJGdW5jdGlvbiA9IG5ldyBGdW5jdGlvbih0aGlzLCAnSXNDb21wbGV0ZUhhbmRsZXJGdW5jdGlvbicsIHtcbiAgICAgICAgcnVudGltZTogUnVudGltZS5OT0RFSlNfMjJfWCxcbiAgICAgICAgY29kZTogQ29kZS5mcm9tQXNzZXQocGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgJy4uL2lzQ29tcGxldGUnKSksXG4gICAgICAgIGVudmlyb25tZW50OiB7XG4gICAgICAgICAgSU1BR0VfVEFHOiBpbWFnZVRhZyxcbiAgICAgICAgfSxcbiAgICAgICAgaGFuZGxlcjogJ2lzQ29tcGxldGUuaGFuZGxlcicsXG4gICAgICAgIHRpbWVvdXQ6IER1cmF0aW9uLm1pbnV0ZXMoMTUpLFxuICAgICAgfSk7XG4gICAgICBpc0NvbXBsZXRlSGFuZGxlckZ1bmN0aW9uLmFkZFRvUm9sZVBvbGljeShcbiAgICAgICAgbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgICAgYWN0aW9uczogW1xuICAgICAgICAgICAgJ2NvZGVidWlsZDpCYXRjaEdldEJ1aWxkcycsXG4gICAgICAgICAgICAnY29kZWJ1aWxkOkxpc3RCdWlsZHNGb3JQcm9qZWN0JyxcbiAgICAgICAgICAgICdsb2dzOkdldExvZ0V2ZW50cycsXG4gICAgICAgICAgICAnbG9nczpEZXNjcmliZUxvZ1N0cmVhbXMnLFxuICAgICAgICAgICAgJ2xvZ3M6RGVzY3JpYmVMb2dHcm91cHMnLFxuICAgICAgICAgIF0sXG4gICAgICAgICAgcmVzb3VyY2VzOiBbJyonXSxcbiAgICAgICAgfSksXG4gICAgICApO1xuXG4gICAgICBpZiAoZW5jcnlwdGlvbktleSkge1xuICAgICAgICBlbmNyeXB0aW9uS2V5LmdyYW50RW5jcnlwdERlY3J5cHQob25FdmVudEhhbmRsZXJGdW5jdGlvbik7XG4gICAgICAgIGVuY3J5cHRpb25LZXkuZ3JhbnRFbmNyeXB0RGVjcnlwdChpc0NvbXBsZXRlSGFuZGxlckZ1bmN0aW9uKTtcbiAgICAgIH1cbiAgICAgIHRoaXMuZWNyUmVwb3NpdG9yeS5ncmFudFB1bGxQdXNoKG9uRXZlbnRIYW5kbGVyRnVuY3Rpb24pO1xuICAgICAgdGhpcy5lY3JSZXBvc2l0b3J5LmdyYW50UHVsbFB1c2goaXNDb21wbGV0ZUhhbmRsZXJGdW5jdGlvbik7XG5cbiAgICAgIGNvbnN0IHByb3ZpZGVyID0gbmV3IFByb3ZpZGVyKHRoaXMsICdDdXN0b21SZXNvdXJjZVByb3ZpZGVyJywge1xuICAgICAgICBvbkV2ZW50SGFuZGxlcjogb25FdmVudEhhbmRsZXJGdW5jdGlvbixcbiAgICAgICAgaXNDb21wbGV0ZUhhbmRsZXI6IGlzQ29tcGxldGVIYW5kbGVyRnVuY3Rpb24sXG4gICAgICAgIHF1ZXJ5SW50ZXJ2YWw6IGNvbXBsZXRlbmVzc1F1ZXJ5SW50ZXJ2YWwgPz8gRHVyYXRpb24uc2Vjb25kcygzMCksXG4gICAgICB9KTtcbiAgICAgIHNlcnZpY2VUb2tlbiA9IHByb3ZpZGVyLnNlcnZpY2VUb2tlbjtcbiAgICB9XG5cbiAgICAvLyBDdXN0b20gUmVzb3VyY2UgdGhhdCB0cmlnZ2VycyB0aGUgQ29kZUJ1aWxkIGFuZCB3YWl0cyBmb3IgY29tcGxldGlvblxuICAgIGNvbnN0IGJ1aWxkVHJpZ2dlclJlc291cmNlID0gbmV3IEN1c3RvbVJlc291cmNlKHRoaXMsICdCdWlsZFRyaWdnZXJSZXNvdXJjZScsIHtcbiAgICAgIHNlcnZpY2VUb2tlbixcbiAgICAgIHByb3BlcnRpZXM6IHtcbiAgICAgICAgUHJvamVjdE5hbWU6IGNvZGVCdWlsZFByb2plY3QucHJvamVjdE5hbWUsXG4gICAgICAgIEltYWdlVGFnOiBpbWFnZVRhZyxcbiAgICAgICAgVHJpZ2dlcjogc291cmNlQXNzZXQuYXNzZXRIYXNoLFxuICAgICAgfSxcbiAgICB9KTtcbiAgICBidWlsZFRyaWdnZXJSZXNvdXJjZS5ub2RlLmFkZERlcGVuZGVuY3koY29kZUJ1aWxkUHJvamVjdCk7XG5cbiAgICAvLyBSZXRyaWV2ZSB0aGUgZmluYWwgRG9ja2VyIGltYWdlIHRhZyBmcm9tIERhdGEuSW1hZ2VUYWdcbiAgICBjb25zdCBpbWFnZVRhZ1JlZiA9IGJ1aWxkVHJpZ2dlclJlc291cmNlLmdldEF0dFN0cmluZygnSW1hZ2VUYWcnKTtcbiAgICB0aGlzLmNvbnRhaW5lckltYWdlID0gQ29udGFpbmVySW1hZ2UuZnJvbUVjclJlcG9zaXRvcnkodGhpcy5lY3JSZXBvc2l0b3J5LCBpbWFnZVRhZ1JlZik7XG4gICAgdGhpcy5kb2NrZXJJbWFnZUNvZGUgPSBEb2NrZXJJbWFnZUNvZGUuZnJvbUVjcih0aGlzLmVjclJlcG9zaXRvcnksIHtcbiAgICAgIHRhZ09yRGlnZXN0OiBpbWFnZVRhZ1JlZixcbiAgICB9KTtcbiAgfVxufVxuIl19
349
+ TokenInjectableDockerBuilder[_b] = { fqn: "token-injectable-docker-builder.TokenInjectableDockerBuilder", version: "1.11.0" };
350
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxpQ0FBaUM7QUFDakMseUJBQXlCO0FBQ3pCLDZCQUE2QjtBQUU3Qiw2Q0FBOEQ7QUFDOUQsNkRBQTRHO0FBRTVHLGlEQUFrRjtBQUNsRixpREFBcUQ7QUFDckQsaURBQXNEO0FBQ3RELGlEQUEwQztBQUMxQyx1REFBa0Y7QUFFbEYsNkRBQWtEO0FBQ2xELG1FQUF3RDtBQUN4RCwyQ0FBdUM7QUFFdkMsTUFBTSxxQkFBcUIsR0FBRyxzQ0FBc0MsQ0FBQztBQWNyRTs7Ozs7O0dBTUc7QUFDSCxNQUFhLG9DQUFxQyxTQUFRLHNCQUFTO0lBQ2pFOzs7O09BSUc7SUFDSSxNQUFNLENBQUMsV0FBVyxDQUFDLEtBQWdCLEVBQUUsS0FBaUQ7UUFDM0YsTUFBTSxLQUFLLEdBQUcsbUJBQUssQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDOUIsTUFBTSxRQUFRLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMscUJBQXFCLENBQXFELENBQUM7UUFDcEgsSUFBSSxRQUFRO1lBQUUsT0FBTyxRQUFRLENBQUM7UUFDOUIsT0FBTyxJQUFJLG9DQUFvQyxDQUFDLEtBQUssRUFBRSxxQkFBcUIsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUN2RixDQUFDO0lBUUQsWUFBb0IsS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBaUQ7UUFDakcsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUVqQixJQUFJLENBQUMsc0JBQXNCLEdBQUcsSUFBSSxxQkFBUSxDQUFDLElBQUksRUFBRSxnQkFBZ0IsRUFBRTtZQUNqRSxPQUFPLEVBQUUsb0JBQU8sQ0FBQyxXQUFXO1lBQzVCLElBQUksRUFBRSxpQkFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFBRSxZQUFZLENBQUMs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O2dCQUNsQixPQUFPLEVBQUUsV0FBVyxDQUFDLFNBQVM7YUFDL0I7U0FDRixDQUFDLENBQUM7UUFDSCxvQkFBb0IsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLGdCQUFnQixDQUFDLENBQUM7UUFFMUQseURBQXlEO1FBQ3pELE1BQU0sV0FBVyxHQUFHLG9CQUFvQixDQUFDLFlBQVksQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUNsRSxJQUFJLENBQUMsY0FBYyxHQUFHLHdCQUFjLENBQUMsaUJBQWlCLENBQUMsSUFBSSxDQUFDLGFBQWEsRUFBRSxXQUFXLENBQUMsQ0FBQztRQUN4RixJQUFJLENBQUMsZUFBZSxHQUFHLDRCQUFlLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUU7WUFDakUsV0FBVyxFQUFFLFdBQVc7U0FDekIsQ0FBQyxDQUFDO0lBQ0wsQ0FBQzs7QUEvVEgsb0VBZ1VDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgY3J5cHRvIGZyb20gJ2NyeXB0byc7XG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuXG5pbXBvcnQgeyBDdXN0b21SZXNvdXJjZSwgRHVyYXRpb24sIFN0YWNrIH0gZnJvbSAnYXdzLWNkay1saWInO1xuaW1wb3J0IHsgUHJvamVjdCwgU291cmNlLCBMaW51eEJ1aWxkSW1hZ2UsIExpbnV4QXJtQnVpbGRJbWFnZSwgQnVpbGRTcGVjIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWNvZGVidWlsZCc7XG5pbXBvcnQgeyBJVnBjLCBJU2VjdXJpdHlHcm91cCwgU3VibmV0U2VsZWN0aW9uIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWVjMic7XG5pbXBvcnQgeyBSZXBvc2l0b3J5LCBSZXBvc2l0b3J5RW5jcnlwdGlvbiwgVGFnU3RhdHVzIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWVjcic7XG5pbXBvcnQgeyBDb250YWluZXJJbWFnZSB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1lY3MnO1xuaW1wb3J0IHsgUG9saWN5U3RhdGVtZW50IH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWlhbSc7XG5pbXBvcnQgeyBLZXkgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3Mta21zJztcbmltcG9ydCB7IFJ1bnRpbWUsIENvZGUsIERvY2tlckltYWdlQ29kZSwgRnVuY3Rpb24gfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtbGFtYmRhJztcbmltcG9ydCB7IElMb2dHcm91cCB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1sb2dzJztcbmltcG9ydCB7IEFzc2V0IH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLXMzLWFzc2V0cyc7XG5pbXBvcnQgeyBQcm92aWRlciB9IGZyb20gJ2F3cy1jZGstbGliL2N1c3RvbS1yZXNvdXJjZXMnO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5cbmNvbnN0IFBST1ZJREVSX1NJTkdMRVRPTl9JRCA9ICdUb2tlbkluamVjdGFibGVEb2NrZXJCdWlsZGVyUHJvdmlkZXInO1xuXG4vKipcbiAqIE9wdGlvbnMgZm9yIGNyZWF0aW5nIGEgYFRva2VuSW5qZWN0YWJsZURvY2tlckJ1aWxkZXJQcm92aWRlcmAuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVG9rZW5JbmplY3RhYmxlRG9ja2VyQnVpbGRlclByb3ZpZGVyUHJvcHMge1xuICAvKipcbiAgICogSG93IG9mdGVuIHRoZSBwcm92aWRlciBwb2xscyBmb3IgYnVpbGQgY29tcGxldGlvbi5cbiAgICpcbiAgICogQGRlZmF1bHQgRHVyYXRpb24uc2Vjb25kcygzMClcbiAgICovXG4gIHJlYWRvbmx5IHF1ZXJ5SW50ZXJ2YWw/OiBEdXJhdGlvbjtcbn1cblxuLyoqXG4gKiBTaGFyZWQgcHJvdmlkZXIgZm9yIGBUb2tlbkluamVjdGFibGVEb2NrZXJCdWlsZGVyYCBpbnN0YW5jZXMuXG4gKlxuICogQ3JlYXRlcyB0aGUgb25FdmVudCBhbmQgaXNDb21wbGV0ZSBMYW1iZGEgZnVuY3Rpb25zIG9uY2UgcGVyIHN0YWNrLlxuICogRWFjaCBidWlsZGVyIGluc3RhbmNlIHJlZ2lzdGVycyBpdHMgQ29kZUJ1aWxkIHByb2plY3QgQVJOIHNvIHRoZVxuICogc2hhcmVkIExhbWJkYXMgaGF2ZSBwZXJtaXNzaW9uIHRvIHN0YXJ0IGJ1aWxkcyBhbmQgcmVhZCBsb2dzLlxuICovXG5leHBvcnQgY2xhc3MgVG9rZW5JbmplY3RhYmxlRG9ja2VyQnVpbGRlclByb3ZpZGVyIGV4dGVuZHMgQ29uc3RydWN0IHtcbiAgLyoqXG4gICAqIEdldCBvciBjcmVhdGUgdGhlIHNpbmdsZXRvbiBwcm92aWRlciBmb3IgdGhpcyBzdGFjay5cbiAgICogQWxsIGBUb2tlbkluamVjdGFibGVEb2NrZXJCdWlsZGVyYCBpbnN0YW5jZXMgaW4gdGhlIHNhbWUgc3RhY2tcbiAgICogc2hhcmUgYSBzaW5nbGUgcGFpciBvZiBMYW1iZGEgZnVuY3Rpb25zLlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBnZXRPckNyZWF0ZShzY29wZTogQ29uc3RydWN0LCBwcm9wcz86IFRva2VuSW5qZWN0YWJsZURvY2tlckJ1aWxkZXJQcm92aWRlclByb3BzKTogVG9rZW5JbmplY3RhYmxlRG9ja2VyQnVpbGRlclByb3ZpZGVyIHtcbiAgICBjb25zdCBzdGFjayA9IFN0YWNrLm9mKHNjb3BlKTtcbiAgICBjb25zdCBleGlzdGluZyA9IHN0YWNrLm5vZGUudHJ5RmluZENoaWxkKFBST1ZJREVSX1NJTkdMRVRPTl9JRCkgYXMgVG9rZW5JbmplY3RhYmxlRG9ja2VyQnVpbGRlclByb3ZpZGVyIHwgdW5kZWZpbmVkO1xuICAgIGlmIChleGlzdGluZykgcmV0dXJuIGV4aXN0aW5nO1xuICAgIHJldHVybiBuZXcgVG9rZW5JbmplY3RhYmxlRG9ja2VyQnVpbGRlclByb3ZpZGVyKHN0YWNrLCBQUk9WSURFUl9TSU5HTEVUT05fSUQsIHByb3BzKTtcbiAgfVxuXG4gIC8qKiBUaGUgc2VydmljZSB0b2tlbiB1c2VkIGJ5IEN1c3RvbVJlc291cmNlIGluc3RhbmNlcy4gKi9cbiAgcHVibGljIHJlYWRvbmx5IHNlcnZpY2VUb2tlbjogc3RyaW5nO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgb25FdmVudEhhbmRsZXJGdW5jdGlvbjogRnVuY3Rpb247XG4gIHByaXZhdGUgcmVhZG9ubHkgaXNDb21wbGV0ZUhhbmRsZXJGdW5jdGlvbjogRnVuY3Rpb247XG5cbiAgcHJpdmF0ZSBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wcz86IFRva2VuSW5qZWN0YWJsZURvY2tlckJ1aWxkZXJQcm92aWRlclByb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcblxuICAgIHRoaXMub25FdmVudEhhbmRsZXJGdW5jdGlvbiA9IG5ldyBGdW5jdGlvbih0aGlzLCAnT25FdmVudEhhbmRsZXInLCB7XG4gICAgICBydW50aW1lOiBSdW50aW1lLk5PREVKU18yMl9YLFxuICAgICAgY29kZTogQ29kZS5mcm9tQXNzZXQocGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgJy4uL29uRXZlbnQnKSksXG4gICAgICBoYW5kbGVyOiAnb25FdmVudC5oYW5kbGVyJyxcbiAgICAgIHRpbWVvdXQ6IER1cmF0aW9uLm1pbnV0ZXMoMTUpLFxuICAgIH0pO1xuXG4gICAgdGhpcy5pc0NvbXBsZXRlSGFuZGxlckZ1bmN0aW9uID0gbmV3IEZ1bmN0aW9uKHRoaXMsICdJc0NvbXBsZXRlSGFuZGxlcicsIHtcbiAgICAgIHJ1bnRpbWU6IFJ1bnRpbWUuTk9ERUpTXzIyX1gsXG4gICAgICBjb2RlOiBDb2RlLmZyb21Bc3NldChwYXRoLnJlc29sdmUoX19kaXJuYW1lLCAnLi4vaXNDb21wbGV0ZScpKSxcbiAgICAgIGhhbmRsZXI6ICdpc0NvbXBsZXRlLmhhbmRsZXInLFxuICAgICAgdGltZW91dDogRHVyYXRpb24ubWludXRlcygxNSksXG4gICAgfSk7XG4gICAgdGhpcy5pc0NvbXBsZXRlSGFuZGxlckZ1bmN0aW9uLmFkZFRvUm9sZVBvbGljeShcbiAgICAgIG5ldyBQb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBhY3Rpb25zOiBbXG4gICAgICAgICAgJ2NvZGVidWlsZDpCYXRjaEdldEJ1aWxkcycsXG4gICAgICAgICAgJ2NvZGVidWlsZDpMaXN0QnVpbGRzRm9yUHJvamVjdCcsXG4gICAgICAgICAgJ2xvZ3M6R2V0TG9nRXZlbnRzJyxcbiAgICAgICAgICAnbG9nczpEZXNjcmliZUxvZ1N0cmVhbXMnLFxuICAgICAgICAgICdsb2dzOkRlc2NyaWJlTG9nR3JvdXBzJyxcbiAgICAgICAgXSxcbiAgICAgICAgcmVzb3VyY2VzOiBbJyonXSxcbiAgICAgIH0pLFxuICAgICk7XG5cbiAgICBjb25zdCBwcm92aWRlciA9IG5ldyBQcm92aWRlcih0aGlzLCAnUHJvdmlkZXInLCB7XG4gICAgICBvbkV2ZW50SGFuZGxlcjogdGhpcy5vbkV2ZW50SGFuZGxlckZ1bmN0aW9uLFxuICAgICAgaXNDb21wbGV0ZUhhbmRsZXI6IHRoaXMuaXNDb21wbGV0ZUhhbmRsZXJGdW5jdGlvbixcbiAgICAgIHF1ZXJ5SW50ZXJ2YWw6IHByb3BzPy5xdWVyeUludGVydmFsID8/IER1cmF0aW9uLnNlY29uZHMoMzApLFxuICAgIH0pO1xuXG4gICAgdGhpcy5zZXJ2aWNlVG9rZW4gPSBwcm92aWRlci5zZXJ2aWNlVG9rZW47XG4gIH1cblxuICAvKipcbiAgICogR3JhbnQgdGhlIHNoYXJlZCBMYW1iZGFzIHBlcm1pc3Npb24gdG8gc3RhcnQgYnVpbGRzIGZvciBhIHNwZWNpZmljXG4gICAqIENvZGVCdWlsZCBwcm9qZWN0IGFuZCBwdWxsL3B1c2ggdG8gaXRzIEVDUiByZXBvc2l0b3J5LlxuICAgKi9cbiAgcHVibGljIHJlZ2lzdGVyUHJvamVjdChwcm9qZWN0OiBQcm9qZWN0LCBlY3JSZXBvOiBSZXBvc2l0b3J5LCBlbmNyeXB0aW9uS2V5PzogS2V5KTogdm9pZCB7XG4gICAgdGhpcy5vbkV2ZW50SGFuZGxlckZ1bmN0aW9uLmFkZFRvUm9sZVBvbGljeShcbiAgICAgIG5ldyBQb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBhY3Rpb25zOiBbJ2NvZGVidWlsZDpTdGFydEJ1aWxkJ10sXG4gICAgICAgIHJlc291cmNlczogW3Byb2plY3QucHJvamVjdEFybl0sXG4gICAgICB9KSxcbiAgICApO1xuICAgIGVjclJlcG8uZ3JhbnRQdWxsUHVzaCh0aGlzLm9uRXZlbnRIYW5kbGVyRnVuY3Rpb24pO1xuICAgIGVjclJlcG8uZ3JhbnRQdWxsUHVzaCh0aGlzLmlzQ29tcGxldGVIYW5kbGVyRnVuY3Rpb24pO1xuXG4gICAgaWYgKGVuY3J5cHRpb25LZXkpIHtcbiAgICAgIGVuY3J5cHRpb25LZXkuZ3JhbnRFbmNyeXB0RGVjcnlwdCh0aGlzLm9uRXZlbnRIYW5kbGVyRnVuY3Rpb24pO1xuICAgICAgZW5jcnlwdGlvbktleS5ncmFudEVuY3J5cHREZWNyeXB0KHRoaXMuaXNDb21wbGV0ZUhhbmRsZXJGdW5jdGlvbik7XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogUHJvcGVydGllcyBmb3IgdGhlIGBUb2tlbkluamVjdGFibGVEb2NrZXJCdWlsZGVyYCBjb25zdHJ1Y3QuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVG9rZW5JbmplY3RhYmxlRG9ja2VyQnVpbGRlclByb3BzIHtcbiAgLyoqXG4gICAqIFRoZSBwYXRoIHRvIHRoZSBkaXJlY3RvcnkgY29udGFpbmluZyB0aGUgRG9ja2VyZmlsZSBvciBzb3VyY2UgY29kZS5cbiAgICovXG4gIHJlYWRvbmx5IHBhdGg6IHN0cmluZztcblxuICAvKipcbiAgICogQnVpbGQgYXJndW1lbnRzIHRvIHBhc3MgdG8gdGhlIERvY2tlciBidWlsZCBwcm9jZXNzLlxuICAgKiBUaGVzZSBhcmUgdHJhbnNmb3JtZWQgaW50byBgLS1idWlsZC1hcmcgS0VZPVZBTFVFYCBmbGFncy5cbiAgICogQGV4YW1wbGVcbiAgICoge1xuICAgKiAgIFRPS0VOOiAnbXktc2VjcmV0LXRva2VuJyxcbiAgICogICBFTlY6ICdwcm9kdWN0aW9uJ1xuICAgKiB9XG4gICAqL1xuICByZWFkb25seSBidWlsZEFyZ3M/OiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9O1xuXG4gIC8qKlxuICAgKiBUaGUgQVJOIG9mIHRoZSBBV1MgU2VjcmV0cyBNYW5hZ2VyIHNlY3JldCBjb250YWluaW5nIERvY2tlciBsb2dpbiBjcmVkZW50aWFscy5cbiAgICogVGhpcyBzZWNyZXQgc2hvdWxkIHN0b3JlIGEgSlNPTiBvYmplY3Qgd2l0aCB0aGUgZm9sbG93aW5nIHN0cnVjdHVyZTpcbiAgICogYGBganNvblxuICAgKiB7XG4gICAqICAgXCJ1c2VybmFtZVwiOiBcIm15LWRvY2tlci11c2VybmFtZVwiLFxuICAgKiAgIFwicGFzc3dvcmRcIjogXCJteS1kb2NrZXItcGFzc3dvcmRcIlxuICAgKiB9XG4gICAqIGBgYFxuICAgKiBJZiBub3QgcHJvdmlkZWQgKG9yIG5vdCBuZWVkZWQpLCB0aGUgY29uc3RydWN0IHdpbGwgc2tpcCBEb2NrZXIgSHViIGxvZ2luLlxuICAgKlxuICAgKiAqKk5vdGUqKjogVGhlIHNlY3JldCBtdXN0IGJlIGluIHRoZSBzYW1lIHJlZ2lvbiBhcyB0aGUgc3RhY2suXG4gICAqXG4gICAqIEBleGFtcGxlICdhcm46YXdzOnNlY3JldHNtYW5hZ2VyOnVzLWVhc3QtMToxMjM0NTY3ODkwMTI6c2VjcmV0OkRvY2tlckxvZ2luU2VjcmV0J1xuICAgKi9cbiAgcmVhZG9ubHkgZG9ja2VyTG9naW5TZWNyZXRBcm4/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBWUEMgaW4gd2hpY2ggdGhlIENvZGVCdWlsZCBwcm9qZWN0IHdpbGwgYmUgZGVwbG95ZWQuXG4gICAqIElmIHByb3ZpZGVkLCB0aGUgQ29kZUJ1aWxkIHByb2plY3Qgd2lsbCBiZSBsYXVuY2hlZCB3aXRoaW4gdGhlIHNwZWNpZmllZCBWUEMuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gTm8gVlBDIGlzIGF0dGFjaGVkLCBhbmQgdGhlIENvZGVCdWlsZCBwcm9qZWN0IHdpbGwgdXNlIHB1YmxpYyBpbnRlcm5ldC5cbiAgICovXG4gIHJlYWRvbmx5IHZwYz86IElWcGM7XG5cbiAgLyoqXG4gICAqIFRoZSBzZWN1cml0eSBncm91cHMgdG8gYXR0YWNoIHRvIHRoZSBDb2RlQnVpbGQgcHJvamVjdC5cbiAgICogVGhlc2UgZGVmaW5lIHRoZSBuZXR3b3JrIGFjY2VzcyBydWxlcyBmb3IgdGhlIENvZGVCdWlsZCBwcm9qZWN0LlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vIHNlY3VyaXR5IGdyb3VwcyBhcmUgYXR0YWNoZWQuXG4gICAqL1xuICByZWFkb25seSBzZWN1cml0eUdyb3Vwcz86IElTZWN1cml0eUdyb3VwW107XG5cbiAgLyoqXG4gICAqIFRoZSBzdWJuZXQgc2VsZWN0aW9uIHRvIHNwZWNpZnkgd2hpY2ggc3VibmV0cyB0byB1c2Ugd2l0aGluIHRoZSBWUEMuXG4gICAqIEFsbG93cyB0aGUgdXNlciB0byBzZWxlY3QgcHJpdmF0ZSwgcHVibGljLCBvciBpc29sYXRlZCBzdWJuZXRzLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIEFsbCBzdWJuZXRzIGluIHRoZSBWUEMgYXJlIHVzZWQuXG4gICAqL1xuICByZWFkb25seSBzdWJuZXRTZWxlY3Rpb24/OiBTdWJuZXRTZWxlY3Rpb247XG5cbiAgLyoqXG4gICAqIEN1c3RvbSBjb21tYW5kcyB0byBydW4gZHVyaW5nIHRoZSBpbnN0YWxsIHBoYXNlIG9mIENvZGVCdWlsZC5cbiAgICpcbiAgICogKipFeGFtcGxlKio6XG4gICAqIGBgYHRzXG4gICAqIGluc3RhbGxDb21tYW5kczogW1xuICAgKiAgICdlY2hvIFwiVXBkYXRpbmcgcGFja2FnZSBsaXN0cy4uLlwiJyxcbiAgICogICAnYXB0LWdldCB1cGRhdGUgLXknLFxuICAgKiAgICdlY2hvIFwiSW5zdGFsbGluZyByZXF1aXJlZCBwYWNrYWdlcy4uLlwiJyxcbiAgICogICAnYXB0LWdldCBpbnN0YWxsIC15IGN1cmwgZG5zdXRpbHMnLFxuICAgKiBdLFxuICAgKiBgYGBcbiAgICogQGRlZmF1bHQgLSBObyBhZGRpdGlvbmFsIGluc3RhbGwgY29tbWFuZHMuXG4gICAqL1xuICByZWFkb25seSBpbnN0YWxsQ29tbWFuZHM/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogQ3VzdG9tIGNvbW1hbmRzIHRvIHJ1biBkdXJpbmcgdGhlIHByZV9idWlsZCBwaGFzZSBvZiBDb2RlQnVpbGQuXG4gICAqXG4gICAqICoqRXhhbXBsZSoqOlxuICAgKiBgYGB0c1xuICAgKiBwcmVCdWlsZENvbW1hbmRzOiBbXG4gICAqICAgJ2VjaG8gXCJGZXRjaGluZyBjb25maWd1cmF0aW9uIGZyb20gcHJpdmF0ZSBBUEkuLi5cIicsXG4gICAqICAgJ2N1cmwgLW8gY29uZmlnLmpzb24gaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20vY29uZmlnJyxcbiAgICogXSxcbiAgICogYGBgXG4gICAqIEBkZWZhdWx0IC0gTm8gYWRkaXRpb25hbCBwcmUtYnVpbGQgY29tbWFuZHMuXG4gICAqL1xuICByZWFkb25seSBwcmVCdWlsZENvbW1hbmRzPzogc3RyaW5nW107XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gZW5hYmxlIEtNUyBlbmNyeXB0aW9uIGZvciB0aGUgRUNSIHJlcG9zaXRvcnkuXG4gICAqIElmIGB0cnVlYCwgYSBLTVMga2V5IHdpbGwgYmUgY3JlYXRlZCBmb3IgZW5jcnlwdGluZyBFQ1IgaW1hZ2VzLlxuICAgKiBJZiBgZmFsc2VgLCB0aGUgcmVwb3NpdG9yeSB3aWxsIHVzZSBBRVMtMjU2IGVuY3J5cHRpb24uXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IGttc0VuY3J5cHRpb24/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBUaGUgcXVlcnkgaW50ZXJ2YWwgZm9yIGNoZWNraW5nIGlmIHRoZSBDb2RlQnVpbGQgcHJvamVjdCBoYXMgY29tcGxldGVkLlxuICAgKiBUaGlzIGRldGVybWluZXMgaG93IGZyZXF1ZW50bHkgdGhlIGN1c3RvbSByZXNvdXJjZSBwb2xscyBmb3IgYnVpbGQgY29tcGxldGlvbi5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBEdXJhdGlvbi5zZWNvbmRzKDMwKVxuICAgKi9cbiAgcmVhZG9ubHkgY29tcGxldGVuZXNzUXVlcnlJbnRlcnZhbD86IER1cmF0aW9uO1xuXG4gIC8qKlxuICAgKiBBIGxpc3Qgb2YgZmlsZSBwYXRocyBpbiB0aGUgRG9ja2VyIGRpcmVjdG9yeSB0byBleGNsdWRlIGZyb20gYnVpbGQuXG4gICAqIFdpbGwgdXNlIHBhdGhzIGluIC5kb2NrZXJpZ25vcmUgZmlsZSBpZiBwcmVzZW50LlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vIGZpbGUgcGF0aCBleGNsdXNpb25zXG4gICAqL1xuICByZWFkb25seSBleGNsdWRlPzogc3RyaW5nW107XG5cbiAgLyoqXG4gICAqIFRoZSBuYW1lIG9mIHRoZSBEb2NrZXJmaWxlIHRvIHVzZSBmb3IgdGhlIGJ1aWxkLlxuICAgKiBQYXNzZWQgYXMgYC0tZmlsZWAgdG8gYGRvY2tlciBidWlsZGAuXG4gICAqXG4gICAqIEBleGFtcGxlICdEb2NrZXJmaWxlLnByb2R1Y3Rpb24nXG4gICAqIEBkZWZhdWx0ICdEb2NrZXJmaWxlJ1xuICAgKi9cbiAgcmVhZG9ubHkgZmlsZT86IHN0cmluZztcblxuICAvKipcbiAgICogV2hlbiBgdHJ1ZWAsIGRpc2FibGVzIERvY2tlciBsYXllciBjYWNoaW5nLiBFdmVyeSBidWlsZCBydW5zIGZyb20gc2NyYXRjaC5cbiAgICogVXNlIGZvciBkZWJ1Z2dpbmcsIGNvcnJ1cHRlZCBjYWNoZSwgb3IgbWFqb3IgZGVwZW5kZW5jeSBjaGFuZ2VzLlxuICAgKlxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgcmVhZG9ubHkgY2FjaGVEaXNhYmxlZD86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIENsb3VkV2F0Y2ggbG9nIGdyb3VwIGZvciBDb2RlQnVpbGQgYnVpbGQgbG9ncy5cbiAgICogV2hlbiBwcm92aWRlZCB3aXRoIGEgUkVUQUlOIHJlbW92YWwgcG9saWN5LCBidWlsZCBsb2dzIHN1cnZpdmUgcm9sbGJhY2tzXG4gICAqIGFuZCBzdGFjayBkZWxldGlvbiBmb3IgZGVidWdnaW5nLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIENvZGVCdWlsZCBkZWZhdWx0IGxvZ2dpbmcgKGxvZ3MgYXJlIGRlbGV0ZWQgb24gcm9sbGJhY2spXG4gICAqL1xuICByZWFkb25seSBidWlsZExvZ0dyb3VwPzogSUxvZ0dyb3VwO1xuXG4gIC8qKlxuICAgKiBUYXJnZXQgcGxhdGZvcm0gZm9yIHRoZSBEb2NrZXIgaW1hZ2UuXG4gICAqXG4gICAqIFdoZW4gc2V0IHRvIGAnbGludXgvYXJtNjQnYCwgdGhlIGNvbnN0cnVjdCB1c2VzIGEgbmF0aXZlIEFSTS9HcmF2aXRvblxuICAgKiBDb2RlQnVpbGQgaW5zdGFuY2UgZm9yIGZhc3QgYnVpbGRzIHdpdGhvdXQgZW11bGF0aW9uLlxuICAgKlxuICAgKiBAZGVmYXVsdCAnbGludXgvYW1kNjQnXG4gICAqL1xuICByZWFkb25seSBwbGF0Zm9ybT86ICdsaW51eC9hbWQ2NCcgfCAnbGludXgvYXJtNjQnO1xuXG4gIC8qKlxuICAgKiBTaGFyZWQgcHJvdmlkZXIgZm9yIHRoZSBjdXN0b20gcmVzb3VyY2UgTGFtYmRhcy5cbiAgICogVXNlIGBUb2tlbkluamVjdGFibGVEb2NrZXJCdWlsZGVyUHJvdmlkZXIuZ2V0T3JDcmVhdGUodGhpcylgIHRvIGNyZWF0ZVxuICAgKiBhIHNpbmdsZXRvbiB0aGF0IGlzIHNoYXJlZCBhY3Jvc3MgYWxsIGJ1aWxkZXJzIGluIHRoZSBzYW1lIHN0YWNrLlxuICAgKlxuICAgKiBXaGVuIG9taXR0ZWQsIGVhY2ggYnVpbGRlciBjcmVhdGVzIGl0cyBvd24gTGFtYmRhcyAob3JpZ2luYWwgYmVoYXZpb3IpLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIEEgbmV3IHByb3ZpZGVyIGlzIGNyZWF0ZWQgcGVyIGJ1aWxkZXIgaW5zdGFuY2VcbiAgICovXG4gIHJlYWRvbmx5IHByb3ZpZGVyPzogVG9rZW5JbmplY3RhYmxlRG9ja2VyQnVpbGRlclByb3ZpZGVyO1xuXG4gIC8qKlxuICAgKiBFQ1IgcHVsbC10aHJvdWdoIGNhY2hlIHJlcG9zaXRvcnkgcHJlZml4ZXMgdG8gZ3JhbnQgcHVsbCBhY2Nlc3MgdG8uXG4gICAqIFVzZSB3aGVuIHlvdXIgRG9ja2VyZmlsZSByZWZlcmVuY2VzIGJhc2UgaW1hZ2VzIGZyb20gRUNSIHB1bGwtdGhyb3VnaFxuICAgKiBjYWNoZSAoZS5nLiBkb2NrZXItaHViL2xpYnJhcnkvbm9kZToyMC1zbGltLCBnaGNyL29yZy9pbWFnZTp0YWcpLlxuICAgKiBUaGUgQ29kZUJ1aWxkIHJvbGUgd2lsbCBiZSBncmFudGVkIGVjcjpCYXRjaEdldEltYWdlLCBlY3I6R2V0RG93bmxvYWRVcmxGb3JMYXllcixcbiAgICogYW5kIGVjcjpCYXRjaENoZWNrTGF5ZXJBdmFpbGFiaWxpdHkgb24gcmVwb3NpdG9yaWVzIG1hdGNoaW5nIGVhY2ggcHJlZml4LlxuICAgKlxuICAgKiBAZXhhbXBsZSBbJ2RvY2tlci1odWInLCAnZ2hjciddXG4gICAqIEBkZWZhdWx0IC0gTm8gcHVsbC10aHJvdWdoIGNhY2hlIGFjY2Vzc1xuICAgKi9cbiAgcmVhZG9ubHkgZWNyUHVsbFRocm91Z2hDYWNoZVByZWZpeGVzPzogc3RyaW5nW107XG59XG5cbi8qKlxuICogQSBDREsgY29uc3RydWN0IHRvIGJ1aWxkIGFuZCBwdXNoIERvY2tlciBpbWFnZXMgdG8gYW4gRUNSIHJlcG9zaXRvcnkgdXNpbmdcbiAqIENvZGVCdWlsZCBhbmQgTGFtYmRhIGN1c3RvbSByZXNvdXJjZXMsICoqdGhlbioqIHJldHJpZXZlIHRoZSBmaW5hbCBpbWFnZSB0YWdcbiAqIHNvIHRoYXQgRUNTL0xhbWJkYSByZWZlcmVuY2VzIHVzZSB0aGUgZXhhY3QgZGlnZXN0LlxuICovXG5leHBvcnQgY2xhc3MgVG9rZW5JbmplY3RhYmxlRG9ja2VyQnVpbGRlciBleHRlbmRzIENvbnN0cnVjdCB7XG4gIC8qKlxuICAgKiBUaGUgRUNSIHJlcG9zaXRvcnkgdGhhdCBzdG9yZXMgdGhlIHJlc3VsdGluZyBEb2NrZXIgaW1hZ2UuXG4gICAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGVjclJlcG9zaXRvcnk6IFJlcG9zaXRvcnk7XG5cbiAgLyoqXG4gICAqIEFuIEVDUy1jb21wYXRpYmxlIGNvbnRhaW5lciBpbWFnZSByZWZlcmVuY2luZyB0aGUgdGFnXG4gICAqIG9mIHRoZSBidWlsdCBEb2NrZXIgaW1hZ2UuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgY29udGFpbmVySW1hZ2U6IENvbnRhaW5lckltYWdlO1xuXG4gIC8qKlxuICAgKiBBIExhbWJkYS1jb21wYXRpYmxlIERvY2tlckltYWdlQ29kZSByZWZlcmVuY2luZyB0aGUgdGFnXG4gICAqIG9mIHRoZSBidWlsdCBEb2NrZXIgaW1hZ2UuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgZG9ja2VySW1hZ2VDb2RlOiBEb2NrZXJJbWFnZUNvZGU7XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBuZXcgYFRva2VuSW5qZWN0YWJsZURvY2tlckJ1aWxkZXJgLlxuICAgKlxuICAgKiBAcGFyYW0gc2NvcGUgVGhlIHNjb3BlIGluIHdoaWNoIHRvIGRlZmluZSB0aGlzIGNvbnN0cnVjdC5cbiAgICogQHBhcmFtIGlkIFRoZSBzY29wZWQgY29uc3RydWN0IElELlxuICAgKiBAcGFyYW0gcHJvcHMgQ29uZmlndXJhdGlvbiBmb3IgYnVpbGRpbmcgYW5kIHB1c2hpbmcgdGhlIERvY2tlciBpbWFnZS5cbiAgICovXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBUb2tlbkluamVjdGFibGVEb2NrZXJCdWlsZGVyUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgY29uc3Qge1xuICAgICAgcGF0aDogc291cmNlUGF0aCxcbiAgICAgIGJ1aWxkQXJncyxcbiAgICAgIGRvY2tlckxvZ2luU2VjcmV0QXJuLFxuICAgICAgdnBjLFxuICAgICAgc2VjdXJpdHlHcm91cHMsXG4gICAgICBzdWJuZXRTZWxlY3Rpb24sXG4gICAgICBpbnN0YWxsQ29tbWFuZHMsXG4gICAgICBwcmVCdWlsZENvbW1hbmRzLFxuICAgICAga21zRW5jcnlwdGlvbiA9IGZhbHNlLFxuICAgICAgY29tcGxldGVuZXNzUXVlcnlJbnRlcnZhbCxcbiAgICAgIGV4Y2x1ZGUsXG4gICAgICBmaWxlOiBkb2NrZXJGaWxlLFxuICAgICAgY2FjaGVEaXNhYmxlZCA9IGZhbHNlLFxuICAgICAgYnVpbGRMb2dHcm91cDogYnVpbGRMb2dHcm91cFByb3AsXG4gICAgICBwbGF0Zm9ybSA9ICdsaW51eC9hbWQ2NCcsXG4gICAgICBwcm92aWRlcjogc2hhcmVkUHJvdmlkZXIsXG4gICAgICBlY3JQdWxsVGhyb3VnaENhY2hlUHJlZml4ZXMsXG4gICAgfSA9IHByb3BzO1xuXG4gICAgLy8gR2VuZXJhdGUgYW4gZXBoZW1lcmFsIHRhZyBmb3IgQ29kZUJ1aWxkXG4gICAgY29uc3QgaW1hZ2VUYWcgPSBjcnlwdG8ucmFuZG9tVVVJRCgpO1xuXG4gICAgLy8gT3B0aW9uYWxseSBkZWZpbmUgYSBLTVMga2V5IGZvciBFQ1IgZW5jcnlwdGlvbiBpZiByZXF1ZXN0ZWRcbiAgICBsZXQgZW5jcnlwdGlvbktleTogS2V5IHwgdW5kZWZpbmVkO1xuICAgIGlmIChrbXNFbmNyeXB0aW9uKSB7XG4gICAgICBlbmNyeXB0aW9uS2V5ID0gbmV3IEtleSh0aGlzLCAnRWNyRW5jcnlwdGlvbktleScsIHtcbiAgICAgICAgZW5hYmxlS2V5Um90YXRpb246IHRydWUsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyBDcmVhdGUgYW4gRUNSIHJlcG9zaXRvcnkgKG9wdGlvbmFsbHkgd2l0aCBLTVMgZW5jcnlwdGlvbilcbiAgICB0aGlzLmVjclJlcG9zaXRvcnkgPSBuZXcgUmVwb3NpdG9yeSh0aGlzLCAnRUNSUmVwb3NpdG9yeScsIHtcbiAgICAgIGxpZmVjeWNsZVJ1bGVzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBydWxlUHJpb3JpdHk6IDEsXG4gICAgICAgICAgZGVzY3JpcHRpb246ICdSZW1vdmUgdW50YWdnZWQgaW1hZ2VzIGFmdGVyIDEgZGF5JyxcbiAgICAgICAgICB0YWdTdGF0dXM6IFRhZ1N0YXR1cy5VTlRBR0dFRCxcbiAgICAgICAgICBtYXhJbWFnZUFnZTogRHVyYXRpb24uZGF5cygxKSxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgICBlbmNyeXB0aW9uOiBrbXNFbmNyeXB0aW9uID8gUmVwb3NpdG9yeUVuY3J5cHRpb24uS01TIDogUmVwb3NpdG9yeUVuY3J5cHRpb24uQUVTXzI1NixcbiAgICAgIGVuY3J5cHRpb25LZXk6IGttc0VuY3J5cHRpb24gPyBlbmNyeXB0aW9uS2V5IDogdW5kZWZpbmVkLFxuICAgICAgaW1hZ2VTY2FuT25QdXNoOiB0cnVlLFxuICAgIH0pO1xuXG4gICAgbGV0IGVmZmVjdGl2ZUV4Y2x1ZGUgPSBleGNsdWRlO1xuICAgIGlmICghZWZmZWN0aXZlRXhjbHVkZSkge1xuICAgICAgY29uc3QgZG9ja2VyaWdub3JlUGF0aCA9IHBhdGguam9pbihzb3VyY2VQYXRoLCAnLmRvY2tlcmlnbm9yZScpO1xuICAgICAgaWYgKGZzLmV4aXN0c1N5bmMoZG9ja2VyaWdub3JlUGF0aCkpIHtcbiAgICAgICAgY29uc3QgZmlsZUNvbnRlbnQgPSBmcy5yZWFkRmlsZVN5bmMoZG9ja2VyaWdub3JlUGF0aCwgJ3V0ZjgnKTtcbiAgICAgICAgZWZmZWN0aXZlRXhjbHVkZSA9IGZpbGVDb250ZW50XG4gICAgICAgICAgLnNwbGl0KCdcXG4nKVxuICAgICAgICAgIC5tYXAoKGxpbmU6IHN0cmluZykgPT4gbGluZS50cmltKCkpXG4gICAgICAgICAgLmZpbHRlcigobGluZTogc3RyaW5nKSA9PiBsaW5lLmxlbmd0aCA+IDAgJiYgIWxpbmUuc3RhcnRzV2l0aCgnIycpKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBFbnN1cmUgdGhlIHRhcmdldCBEb2NrZXJmaWxlIGlzIG5ldmVyIGV4Y2x1ZGVkIChoYW5kbGVzIGdsb2JzIGxpa2UgXCJEb2NrZXJmaWxlKlwiKVxuICAgIGNvbnN0IGRvY2tlckZpbGVOYW1lID0gZG9ja2VyRmlsZSA/PyAnRG9ja2VyZmlsZSc7XG4gICAgaWYgKGVmZmVjdGl2ZUV4Y2x1ZGUpIHtcbiAgICAgIGVmZmVjdGl2ZUV4Y2x1ZGUgPSBlZmZlY3RpdmVFeGNsdWRlLmZpbHRlcigocGF0dGVybjogc3RyaW5nKSA9PiB7XG4gICAgICAgIGNvbnN0IGVzY2FwZWQgPSBwYXR0ZXJuLnJlcGxhY2UoL1suK14ke30oKXxbXFxdXFxcXF0vZywgJ1xcXFwkJicpO1xuICAgICAgICBjb25zdCByZWdleCA9IG5ldyBSZWdFeHAoYF4ke2VzY2FwZWQucmVwbGFjZSgvXFwqL2csICcuKicpLnJlcGxhY2UoL1xcPy9nLCAnLicpfSRgLCAnaScpO1xuICAgICAgICByZXR1cm4gIXJlZ2V4LnRlc3QoZG9ja2VyRmlsZU5hbWUpO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gV3JhcCB0aGUgc291cmNlIGZvbGRlciBhcyBhbiBTMyBhc3NldCBmb3IgQ29kZUJ1aWxkIHRvIHVzZVxuICAgIGNvbnN0IHNvdXJjZUFzc2V0ID0gbmV3IEFzc2V0KHRoaXMsICdTb3VyY2VBc3NldCcsIHtcbiAgICAgIHBhdGg6IHNvdXJjZVBhdGgsXG4gICAgICBleGNsdWRlOiBlZmZlY3RpdmVFeGNsdWRlLFxuICAgIH0pO1xuXG4gICAgLy8gQ29udmVydCBidWlsZEFyZ3MgdG8gYSBDTEktZnJpZW5kbHkgc3RyaW5nXG4gICAgY29uc3QgYnVpbGRBcmdzU3RyaW5nID0gYnVpbGRBcmdzXG4gICAgICA/IE9iamVjdC5lbnRyaWVzKGJ1aWxkQXJncylcbiAgICAgICAgLm1hcCgoW2ssIHZdKSA9PiBgLS1idWlsZC1hcmcgJHtrfT0ke3Z9YClcbiAgICAgICAgLmpvaW4oJyAnKVxuICAgICAgOiAnJztcblxuICAgIGNvbnN0IGRvY2tlckZpbGVGbGFnID0gZG9ja2VyRmlsZSA/IGAtZiAkQ09ERUJVSUxEX1NSQ19ESVIvJHtkb2NrZXJGaWxlfWAgOiAnJztcblxuICAgIC8vIE9wdGlvbmFsIERvY2tlckh1YiBsb2dpbiwgaWYgYSBzZWNyZXQgQVJOIGlzIHByb3ZpZGVkXG4gICAgY29uc3QgZG9ja2VyTG9naW5Db21tYW5kcyA9IGRvY2tlckxvZ2luU2VjcmV0QXJuXG4gICAgICA/IFtcbiAgICAgICAgJ2VjaG8gXCJSZXRyaWV2aW5nIERvY2tlciBjcmVkZW50aWFscy4uLlwiJyxcbiAgICAgICAgJ2FwdC1nZXQgdXBkYXRlIC15ICYmIGFwdC1nZXQgaW5zdGFsbCAteSBqcScsXG4gICAgICAgIGBET0NLRVJfVVNFUk5BTUU9JChhd3Mgc2VjcmV0c21hbmFnZXIgZ2V0LXNlY3JldC12YWx1ZSAtLXNlY3JldC1pZCAke2RvY2tlckxvZ2luU2VjcmV0QXJufSAtLXF1ZXJ5IFNlY3JldFN0cmluZyAtLW91dHB1dCB0ZXh0IHwganEgLXIgLnVzZXJuYW1lKWAsXG4gICAgICAgIGBET0NLRVJfUEFTU1dPUkQ9JChhd3Mgc2VjcmV0c21hbmFnZXIgZ2V0LXNlY3JldC12YWx1ZSAtLXNlY3JldC1pZCAke2RvY2tlckxvZ2luU2VjcmV0QXJufSAtLXF1ZXJ5IFNlY3JldFN0cmluZyAtLW91dHB1dCB0ZXh0IHwganEgLXIgLnBhc3N3b3JkKWAsXG4gICAgICAgICdlY2hvIFwiTG9nZ2luZyBpbiB0byBEb2NrZXIgSHViLi4uXCInLFxuICAgICAgICAnZWNobyAkRE9DS0VSX1BBU1NXT1JEIHwgZG9ja2VyIGxvZ2luIC0tdXNlcm5hbWUgJERPQ0tFUl9VU0VSTkFNRSAtLXBhc3N3b3JkLXN0ZGluJyxcbiAgICAgIF1cbiAgICAgIDogWydlY2hvIFwiTm8gRG9ja2VyIGNyZWRlbnRpYWxzLiBTa2lwcGluZyBEb2NrZXIgSHViIGxvZ2luLlwiJ107XG5cbiAgICBjb25zdCBidWlsZHhJbnN0YWxsQ29tbWFuZHMgPSBjYWNoZURpc2FibGVkXG4gICAgICA/IFtdXG4gICAgICA6IFtcbiAgICAgICAgJ2VjaG8gXCJTZXR0aW5nIHVwIERvY2tlciBidWlsZHggZm9yIEVDUiBsYXllciBjYWNoZS4uLlwiJyxcbiAgICAgICAgJ2RvY2tlciBidWlsZHggY3JlYXRlIC0tZHJpdmVyIGRvY2tlci1jb250YWluZXIgLS1uYW1lIGVjci1jYWNoZS1idWlsZGVyIC0tdXNlIDI+L2Rldi9udWxsIHx8IGRvY2tlciBidWlsZHggdXNlIGVjci1jYWNoZS1idWlsZGVyJyxcbiAgICAgIF07XG5cbiAgICBjb25zdCBwbGF0Zm9ybUZsYWcgPSBgLS1wbGF0Zm9ybSAke3BsYXRmb3JtfWA7XG5cbiAgICBjb25zdCBidWlsZENvbW1hbmQgPSBjYWNoZURpc2FibGVkXG4gICAgICA/IGBkb2NrZXIgYnVpbGQgJHtwbGF0Zm9ybUZsYWd9ICR7ZG9ja2VyRmlsZUZsYWd9ICR7YnVpbGRBcmdzU3RyaW5nfSAtdCAkRUNSX1JFUE9fVVJJOiR7aW1hZ2VUYWd9ICRDT0RFQlVJTERfU1JDX0RJUmBcbiAgICAgIDogYGRvY2tlciBidWlsZHggYnVpbGQgLS1wdXNoICR7cGxhdGZvcm1GbGFnfSAtLWNhY2hlLWZyb20gdHlwZT1yZWdpc3RyeSxyZWY9JEVDUl9SRVBPX1VSSTpjYWNoZSAtLWNhY2hlLXRvIHR5cGU9cmVnaXN0cnkscmVmPSRFQ1JfUkVQT19VUkk6Y2FjaGUsbW9kZT1tYXgsaW1hZ2UtbWFuaWZlc3Q9dHJ1ZSAke2RvY2tlckZpbGVGbGFnfSAke2J1aWxkQXJnc1N0cmluZ30gLXQgJEVDUl9SRVBPX1VSSToke2ltYWdlVGFnfSAkQ09ERUJVSUxEX1NSQ19ESVJgO1xuXG4gICAgY29uc3QgYnVpbGRTcGVjT2JqID0ge1xuICAgICAgdmVyc2lvbjogJzAuMicsXG4gICAgICBwaGFzZXM6IHtcbiAgICAgICAgaW5zdGFsbDoge1xuICAgICAgICAgIGNvbW1hbmRzOiBbXG4gICAgICAgICAgICAnZWNobyBcIkJlZ2lubmluZyBpbnN0YWxsIHBoYXNlLi4uXCInLFxuICAgICAgICAgICAgLi4uKGluc3RhbGxDb21tYW5kcyA/PyBbXSksXG4gICAgICAgICAgICAuLi5idWlsZHhJbnN0YWxsQ29tbWFuZHMsXG4gICAgICAgICAgXSxcbiAgICAgICAgfSxcbiAgICAgICAgcHJlX2J1aWxkOiB7XG4gICAgICAgICAgY29tbWFuZHM6IFtcbiAgICAgICAgICAgIC4uLihwcmVCdWlsZENvbW1hbmRzID8/IFtdKSxcbiAgICAgICAgICAgIC4uLmRvY2tlckxvZ2luQ29tbWFuZHMsXG4gICAgICAgICAgICAnZWNobyBcIlJldHJpZXZpbmcgQVdTIEFjY291bnQgSUQuLi5cIicsXG4gICAgICAgICAgICAnZXhwb3J0IEFDQ09VTlRfSUQ9JChhd3Mgc3RzIGdldC1jYWxsZXItaWRlbnRpdHkgLS1xdWVyeSBBY2NvdW50IC0tb3V0cHV0IHRleHQpJyxcbiAgICAgICAgICAgICdlY2hvIFwiTG9nZ2luZyBpbnRvIEFtYXpvbiBFQ1IuLi5cIicsXG4gICAgICAgICAgICAnYXdzIGVjciBnZXQtbG9naW4tcGFzc3dvcmQgLS1yZWdpb24gJEFXU19ERUZBVUxUX1JFR0lPTiB8IGRvY2tlciBsb2dpbiAtLXVzZXJuYW1lIEFXUyAtLXBhc3N3b3JkLXN0ZGluICRBQ0NPVU5UX0lELmRrci5lY3IuJEFXU19ERUZBVUxUX1JFR0lPTi5hbWF6b25hd3MuY29tJyxcbiAgICAgICAgICBdLFxuICAgICAgICB9LFxuICAgICAgICBidWlsZDoge1xuICAgICAgICAgIGNvbW1hbmRzOiBbXG4gICAgICAgICAgICBgZWNobyBcIkJ1aWxkaW5nIERvY2tlciBpbWFnZSB3aXRoIHRhZyAke2ltYWdlVGFnfS4uLlwiYCxcbiAgICAgICAgICAgIGJ1aWxkQ29tbWFuZCxcbiAgICAgICAgICBdLFxuICAgICAgICB9LFxuICAgICAgICAuLi4oY2FjaGVEaXNhYmxlZCAmJiB7XG4gICAgICAgICAgcG9zdF9idWlsZDoge1xuICAgICAgICAgICAgY29tbWFuZHM6IFtcbiAgICAgICAgICAgICAgYGVjaG8gXCJQdXNoaW5nIERvY2tlciBpbWFnZSB3aXRoIHRhZyAke2ltYWdlVGFnfS4uLlwiYCxcbiAgICAgICAgICAgICAgYGRvY2tlciBwdXNoICRFQ1JfUkVQT19VUkk6JHtpbWFnZVRhZ31gLFxuICAgICAgICAgICAgXSxcbiAgICAgICAgICB9LFxuICAgICAgICB9KSxcbiAgICAgIH0sXG4gICAgfTtcblxuICAgIGNvbnN0IGlzQXJtID0gcGxhdGZvcm0gPT09ICdsaW51eC9hcm02NCc7XG4gICAgY29uc3QgY29kZUJ1aWxkSW1hZ2UgPSBpc0FybVxuICAgICAgPyBMaW51eEFybUJ1aWxkSW1hZ2UuQU1BWk9OX0xJTlVYXzJfU1RBTkRBUkRfM18wXG4gICAgICA6IExpbnV4QnVpbGRJbWFnZS5TVEFOREFSRF83XzA7XG5cbiAgICAvLyBDcmVhdGUgdGhlIENvZGVCdWlsZCBwcm9qZWN0XG4gICAgY29uc3QgY29kZUJ1aWxkUHJvamVjdCA9IG5ldyBQcm9qZWN0KHRoaXMsICdDb2RlQnVpbGRQcm9qZWN0Jywge1xuICAgICAgc291cmNlOiBTb3VyY2UuczMoe1xuICAgICAgICBidWNrZXQ6IHNvdXJjZUFzc2V0LmJ1Y2tldCxcbiAgICAgICAgcGF0aDogc291cmNlQXNzZXQuczNPYmplY3RLZXksXG4gICAgICB9KSxcbiAgICAgIGVudmlyb25tZW50OiB7XG4gICAgICAgIGJ1aWxkSW1hZ2U6IGNvZGVCdWlsZEltYWdlLFxuICAgICAgICBwcml2aWxlZ2VkOiB0cnVlLFxuICAgICAgfSxcbiAgICAgIGVudmlyb25tZW50VmFyaWFibGVzOiB7XG4gICAgICAgIEVDUl9SRVBPX1VSSTogeyB2YWx1ZTogdGhpcy5lY3JSZXBvc2l0b3J5LnJlcG9zaXRvcnlVcmkgfSxcbiAgICAgIH0sXG4gICAgICBidWlsZFNwZWM6IEJ1aWxkU3BlYy5mcm9tT2JqZWN0KGJ1aWxkU3BlY09iaiksXG4gICAgICAuLi4oYnVpbGRMb2dHcm91cFByb3AgJiYge1xuICAgICAgICBsb2dnaW5nOiB7XG4gICAgICAgICAgY2xvdWRXYXRjaDoge1xuICAgICAgICAgICAgbG9nR3JvdXA6IGJ1aWxkTG9nR3JvdXBQcm9wLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9KSxcbiAgICAgIHZwYyxcbiAgICAgIHNlY3VyaXR5R3JvdXBzLFxuICAgICAgc3VibmV0U2VsZWN0aW9uLFxuICAgIH0pO1xuXG4gICAgLy8gR3JhbnQgQ29kZUJ1aWxkIHRoZSBhYmlsaXR5IHRvIGludGVyYWN0IHdpdGggRUNSXG4gICAgdGhpcy5lY3JSZXBvc2l0b3J5LmdyYW50UHVsbFB1c2goY29kZUJ1aWxkUHJvamVjdCk7XG4gICAgY29kZUJ1aWxkUHJvamVjdC5hZGRUb1JvbGVQb2xpY3koXG4gICAgICBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgYWN0aW9uczogW1xuICAgICAgICAgICdlY3I6R2V0QXV0aG9yaXphdGlvblRva2VuJyxcbiAgICAgICAgICAnZWNyOkdldERvd25sb2FkVXJsRm9yTGF5ZXInLFxuICAgICAgICAgICdlY3I6QmF0Y2hDaGVja0xheWVyQXZhaWxhYmlsaXR5JyxcbiAgICAgICAgICAnZWNyOkJhdGNoR2V0SW1hZ2UnLFxuICAgICAgICBdLFxuICAgICAgICByZXNvdXJjZXM6IFsnKiddLFxuICAgICAgfSksXG4gICAgKTtcbiAgICBpZiAoZWNyUHVsbFRocm91Z2hDYWNoZVByZWZpeGVzICYmIGVjclB1bGxUaHJvdWdoQ2FjaGVQcmVmaXhlcy5sZW5ndGggPiAwKSB7XG4gICAgICBjb25zdCBzdGFjayA9IFN0YWNrLm9mKHRoaXMpO1xuICAgICAgY29kZUJ1aWxkUHJvamVjdC5hZGRUb1JvbGVQb2xpY3koXG4gICAgICAgIG5ldyBQb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgICAgICdlY3I6QmF0Y2hHZXRJbWFnZScsXG4gICAgICAgICAgICAnZWNyOkdldERvd25sb2FkVXJsRm9yTGF5ZXInLFxuICAgICAgICAgICAgJ2VjcjpCYXRjaENoZWNrTGF5ZXJBdmFpbGFiaWxpdHknLFxuICAgICAgICAgIF0sXG4gICAgICAgICAgcmVzb3VyY2VzOiBlY3JQdWxsVGhyb3VnaENhY2hlUHJlZml4ZXMubWFwKFxuICAgICAgICAgICAgKHByZWZpeCkgPT4gYGFybjphd3M6ZWNyOiR7c3RhY2sucmVnaW9ufToke3N0YWNrLmFjY291bnR9OnJlcG9zaXRvcnkvJHtwcmVmaXh9LypgLFxuICAgICAgICAgICksXG4gICAgICAgIH0pLFxuICAgICAgKTtcbiAgICB9XG4gICAgaWYgKGRvY2tlckxvZ2luU2VjcmV0QXJuKSB7XG4gICAgICBjb2RlQnVpbGRQcm9qZWN0LmFkZFRvUm9sZVBvbGljeShcbiAgICAgICAgbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgICAgYWN0aW9uczogWydzZWNyZXRzbWFuYWdlcjpHZXRTZWNyZXRWYWx1ZSddLFxuICAgICAgICAgIHJlc291cmNlczogW2RvY2tlckxvZ2luU2VjcmV0QXJuXSxcbiAgICAgICAgfSksXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIENvbmRpdGlvbmFsbHkgZ3JhbnQgS01TIGVuY3J5cHQvZGVjcnlwdCBpZiBhIGtleSBpcyB1c2VkXG4gICAgaWYgKGVuY3J5cHRpb25LZXkpIHtcbiAgICAgIGVuY3J5cHRpb25LZXkuZ3JhbnRFbmNyeXB0RGVjcnlwdChjb2RlQnVpbGRQcm9qZWN0LnJvbGUhKTtcbiAgICB9XG5cbiAgICAvLyBSZXNvbHZlIHRoZSBzZXJ2aWNlIHRva2VuOiBzaGFyZWQgcHJvdmlkZXIgb3IgcGVyLWluc3RhbmNlIExhbWJkYXNcbiAgICBsZXQgc2VydmljZVRva2VuOiBzdHJpbmc7XG4gICAgaWYgKHNoYXJlZFByb3ZpZGVyKSB7XG4gICAgICBzaGFyZWRQcm92aWRlci5yZWdpc3RlclByb2plY3QoY29kZUJ1aWxkUHJvamVjdCwgdGhpcy5lY3JSZXBvc2l0b3J5LCBlbmNyeXB0aW9uS2V5KTtcbiAgICAgIHNlcnZpY2VUb2tlbiA9IHNoYXJlZFByb3ZpZGVyLnNlcnZpY2VUb2tlbjtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3Qgb25FdmVudEhhbmRsZXJGdW5jdGlvbiA9IG5ldyBGdW5jdGlvbih0aGlzLCAnT25FdmVudEhhbmRsZXJGdW5jdGlvbicsIHtcbiAgICAgICAgcnVudGltZTogUnVudGltZS5OT0RFSlNfMjJfWCxcbiAgICAgICAgY29kZTogQ29kZS5mcm9tQXNzZXQocGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgJy4uL29uRXZlbnQnKSksXG4gICAgICAgIGhhbmRsZXI6ICdvbkV2ZW50LmhhbmRsZXInLFxuICAgICAgICB0aW1lb3V0OiBEdXJhdGlvbi5taW51dGVzKDE1KSxcbiAgICAgIH0pO1xuICAgICAgb25FdmVudEhhbmRsZXJGdW5jdGlvbi5hZGRUb1JvbGVQb2xpY3koXG4gICAgICAgIG5ldyBQb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICAgIGFjdGlvbnM6IFsnY29kZWJ1aWxkOlN0YXJ0QnVpbGQnXSxcbiAgICAgICAgICByZXNvdXJjZXM6IFtjb2RlQnVpbGRQcm9qZWN0LnByb2plY3RBcm5dLFxuICAgICAgICB9KSxcbiAgICAgICk7XG5cbiAgICAgIGNvbnN0IGlzQ29tcGxldGVIYW5kbGVyRnVuY3Rpb24gPSBuZXcgRnVuY3Rpb24odGhpcywgJ0lzQ29tcGxldGVIYW5kbGVyRnVuY3Rpb24nLCB7XG4gICAgICAgIHJ1bnRpbWU6IFJ1bnRpbWUuTk9ERUpTXzIyX1gsXG4gICAgICAgIGNvZGU6IENvZGUuZnJvbUFzc2V0KHBhdGgucmVzb2x2ZShfX2Rpcm5hbWUsICcuLi9pc0NvbXBsZXRlJykpLFxuICAgICAgICBlbnZpcm9ubWVudDoge1xuICAgICAgICAgIElNQUdFX1RBRzogaW1hZ2VUYWcsXG4gICAgICAgIH0sXG4gICAgICAgIGhhbmRsZXI6ICdpc0NvbXBsZXRlLmhhbmRsZXInLFxuICAgICAgICB0aW1lb3V0OiBEdXJhdGlvbi5taW51dGVzKDE1KSxcbiAgICAgIH0pO1xuICAgICAgaXNDb21wbGV0ZUhhbmRsZXJGdW5jdGlvbi5hZGRUb1JvbGVQb2xpY3koXG4gICAgICAgIG5ldyBQb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgICAgICdjb2RlYnVpbGQ6QmF0Y2hHZXRCdWlsZHMnLFxuICAgICAgICAgICAgJ2NvZGVidWlsZDpMaXN0QnVpbGRzRm9yUHJvamVjdCcsXG4gICAgICAgICAgICAnbG9nczpHZXRMb2dFdmVudHMnLFxuICAgICAgICAgICAgJ2xvZ3M6RGVzY3JpYmVMb2dTdHJlYW1zJyxcbiAgICAgICAgICAgICdsb2dzOkRlc2NyaWJlTG9nR3JvdXBzJyxcbiAgICAgICAgICBdLFxuICAgICAgICAgIHJlc291cmNlczogWycqJ10sXG4gICAgICAgIH0pLFxuICAgICAgKTtcblxuICAgICAgaWYgKGVuY3J5cHRpb25LZXkpIHtcbiAgICAgICAgZW5jcnlwdGlvbktleS5ncmFudEVuY3J5cHREZWNyeXB0KG9uRXZlbnRIYW5kbGVyRnVuY3Rpb24pO1xuICAgICAgICBlbmNyeXB0aW9uS2V5LmdyYW50RW5jcnlwdERlY3J5cHQoaXNDb21wbGV0ZUhhbmRsZXJGdW5jdGlvbik7XG4gICAgICB9XG4gICAgICB0aGlzLmVjclJlcG9zaXRvcnkuZ3JhbnRQdWxsUHVzaChvbkV2ZW50SGFuZGxlckZ1bmN0aW9uKTtcbiAgICAgIHRoaXMuZWNyUmVwb3NpdG9yeS5ncmFudFB1bGxQdXNoKGlzQ29tcGxldGVIYW5kbGVyRnVuY3Rpb24pO1xuXG4gICAgICBjb25zdCBwcm92aWRlciA9IG5ldyBQcm92aWRlcih0aGlzLCAnQ3VzdG9tUmVzb3VyY2VQcm92aWRlcicsIHtcbiAgICAgICAgb25FdmVudEhhbmRsZXI6IG9uRXZlbnRIYW5kbGVyRnVuY3Rpb24sXG4gICAgICAgIGlzQ29tcGxldGVIYW5kbGVyOiBpc0NvbXBsZXRlSGFuZGxlckZ1bmN0aW9uLFxuICAgICAgICBxdWVyeUludGVydmFsOiBjb21wbGV0ZW5lc3NRdWVyeUludGVydmFsID8/IER1cmF0aW9uLnNlY29uZHMoMzApLFxuICAgICAgfSk7XG4gICAgICBzZXJ2aWNlVG9rZW4gPSBwcm92aWRlci5zZXJ2aWNlVG9rZW47XG4gICAgfVxuXG4gICAgLy8gQ3VzdG9tIFJlc291cmNlIHRoYXQgdHJpZ2dlcnMgdGhlIENvZGVCdWlsZCBhbmQgd2FpdHMgZm9yIGNvbXBsZXRpb25cbiAgICBjb25zdCBidWlsZFRyaWdnZXJSZXNvdXJjZSA9IG5ldyBDdXN0b21SZXNvdXJjZSh0aGlzLCAnQnVpbGRUcmlnZ2VyUmVzb3VyY2UnLCB7XG4gICAgICBzZXJ2aWNlVG9rZW4sXG4gICAgICBwcm9wZXJ0aWVzOiB7XG4gICAgICAgIFByb2plY3ROYW1lOiBjb2RlQnVpbGRQcm9qZWN0LnByb2plY3ROYW1lLFxuICAgICAgICBJbWFnZVRhZzogaW1hZ2VUYWcsXG4gICAgICAgIFRyaWdnZXI6IHNvdXJjZUFzc2V0LmFzc2V0SGFzaCxcbiAgICAgIH0sXG4gICAgfSk7XG4gICAgYnVpbGRUcmlnZ2VyUmVzb3VyY2Uubm9kZS5hZGREZXBlbmRlbmN5KGNvZGVCdWlsZFByb2plY3QpO1xuXG4gICAgLy8gUmV0cmlldmUgdGhlIGZpbmFsIERvY2tlciBpbWFnZSB0YWcgZnJvbSBEYXRhLkltYWdlVGFnXG4gICAgY29uc3QgaW1hZ2VUYWdSZWYgPSBidWlsZFRyaWdnZXJSZXNvdXJjZS5nZXRBdHRTdHJpbmcoJ0ltYWdlVGFnJyk7XG4gICAgdGhpcy5jb250YWluZXJJbWFnZSA9IENvbnRhaW5lckltYWdlLmZyb21FY3JSZXBvc2l0b3J5KHRoaXMuZWNyUmVwb3NpdG9yeSwgaW1hZ2VUYWdSZWYpO1xuICAgIHRoaXMuZG9ja2VySW1hZ2VDb2RlID0gRG9ja2VySW1hZ2VDb2RlLmZyb21FY3IodGhpcy5lY3JSZXBvc2l0b3J5LCB7XG4gICAgICB0YWdPckRpZ2VzdDogaW1hZ2VUYWdSZWYsXG4gICAgfSk7XG4gIH1cbn1cbiJdfQ==
package/package.json CHANGED
@@ -98,7 +98,7 @@
98
98
  "publishConfig": {
99
99
  "access": "public"
100
100
  },
101
- "version": "1.9.0",
101
+ "version": "1.11.0",
102
102
  "jest": {
103
103
  "coverageProvider": "v8",
104
104
  "testMatch": [