@orcabus/platform-cdk-constructs 0.0.6 → 0.0.7-alpha.4
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 +858 -6
- package/api-gateway/api-gateway.js +22 -4
- package/deployment-stack-pipeline/pipeline.js +6 -4
- package/dynamodb/config.d.ts +3 -0
- package/dynamodb/config.js +7 -0
- package/dynamodb/index.d.ts +27 -0
- package/dynamodb/index.js +106 -0
- package/ecs/config.d.ts +4 -0
- package/ecs/config.js +8 -0
- package/ecs/index.d.ts +46 -0
- package/ecs/index.js +103 -0
- package/index.d.ts +5 -2
- package/index.js +47 -5
- package/index.ts +16 -2
- package/lambda/build_python/Dockerfile +60 -0
- package/lambda/config.d.ts +11 -0
- package/lambda/config.js +19 -0
- package/lambda/index.d.ts +59 -0
- package/lambda/index.js +242 -0
- package/lambda/layers/mart_tools/poetry.lock +303 -0
- package/lambda/layers/mart_tools/pyproject.toml +27 -0
- package/lambda/layers/mart_tools/src/mart_tools/__init__.py +0 -0
- package/lambda/layers/mart_tools/src/mart_tools/mart/__init__.py +8 -0
- package/lambda/layers/mart_tools/src/mart_tools/mart/aws_helpers.py +79 -0
- package/lambda/layers/mart_tools/src/mart_tools/mart/dataframe_helpers.py +29 -0
- package/lambda/layers/mart_tools/src/mart_tools/mart/globals.py +5 -0
- package/lambda/layers/mart_tools/src/mart_tools/mart/models.py +71 -0
- package/lambda/layers/orcabus_api_tools/poetry.lock +273 -0
- package/lambda/layers/orcabus_api_tools/pyproject.toml +27 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/__init__.py +0 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/fastq/__init__.py +172 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/fastq/create_helpers.py +47 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/fastq/globals.py +13 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/fastq/job_helpers.py +53 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/fastq/models.py +253 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/fastq/query_helpers.py +248 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/fastq/update_helpers.py +221 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/fastq/workflow_helpers.py +25 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/fastq_unarchiving/__init__.py +92 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/fastq_unarchiving/create_helpers.py +27 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/fastq_unarchiving/globals.py +21 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/fastq_unarchiving/models.py +51 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/fastq_unarchiving/query_helpers.py +52 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/fastq_unarchiving/update_helpers.py +45 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/filemanager/__init__.py +98 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/filemanager/errors.py +45 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/filemanager/file_helpers.py +341 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/filemanager/globals.py +70 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/filemanager/models.py +59 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/mart/__init__.py +8 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/mart/aws_helpers.py +79 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/mart/dataframe_helpers.py +29 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/mart/globals.py +5 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/mart/models.py +71 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/metadata/__init__.py +250 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/metadata/contact_helpers.py +109 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/metadata/errors.py +104 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/metadata/globals.py +16 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/metadata/individual_helpers.py +139 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/metadata/library_helpers.py +196 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/metadata/lims_helpers.py +36 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/metadata/models.py +112 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/metadata/project_helpers.py +129 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/metadata/sample_helpers.py +132 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/metadata/subject_helpers.py +151 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/sequence/__init__.py +15 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/sequence/globals.py +2 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/sequence/models.py +44 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/sequence/sequence_helpers.py +62 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/utils/__init__.py +0 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/utils/aws_helpers.py +123 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/utils/miscell.py +17 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/utils/requests_helpers.py +163 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/workflow/__init__.py +0 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/workflow/errors.py +37 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/workflow/metadata_helpers.py +28 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/workflow/models.py +85 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/workflow/payload_helpers.py +64 -0
- package/lambda/layers/orcabus_api_tools/src/orcabus_api_tools/workflow/workflow_run_helpers.py +80 -0
- package/package.json +13 -7
- package/typedoc.json +3 -0
- package/utils/index.d.ts +3 -0
- package/utils/index.js +50 -1
package/index.ts
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
export * as deploymentPipeline from "./deployment-stack-pipeline";
|
|
1
|
+
// Get stage name
|
|
3
2
|
export * as utils from "./utils";
|
|
3
|
+
|
|
4
|
+
// Deployment pipeline constructs
|
|
5
|
+
export * as deploymentPipeline from "./deployment-stack-pipeline";
|
|
6
|
+
|
|
7
|
+
// Api Gateway constructs
|
|
8
|
+
export * as apigateway from "./api-gateway";
|
|
9
|
+
|
|
10
|
+
// DynamoDB Constructs
|
|
11
|
+
export * as dynamodb from "./dynamodb";
|
|
12
|
+
|
|
13
|
+
// ECS / Fargate Constructs
|
|
14
|
+
export * as ecs from "./ecs";
|
|
15
|
+
|
|
16
|
+
// Lambda Constructs
|
|
17
|
+
export * as lambda from "./lambda";
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# NOTES -
|
|
2
|
+
# THIS IS FROM https://github.com/aws/aws-cdk/blob/main/packages/%40aws-cdk/aws-lambda-python-alpha/lib/Dockerfile
|
|
3
|
+
# We have made the following changes:
|
|
4
|
+
# 1. Added the installation of 'uv'
|
|
5
|
+
# 2. Addded in the UV_CACHE_DIR environment variable
|
|
6
|
+
# 3. Replaced 'pip' with 'uv pip' in the main code chunk
|
|
7
|
+
# 4. Replaced /usr/app/venv/pip with uv pip shell script wrapper
|
|
8
|
+
# The correct AWS SAM build image based on the runtime of the function will be
|
|
9
|
+
# passed as build arg. The default allows to do `docker build .` when testing.
|
|
10
|
+
ARG IMAGE=public.ecr.aws/sam/build-python3.12:latest
|
|
11
|
+
FROM $IMAGE
|
|
12
|
+
|
|
13
|
+
ARG TARGETPLATFORM
|
|
14
|
+
ARG PIP_INDEX_URL
|
|
15
|
+
ARG PIP_EXTRA_INDEX_URL
|
|
16
|
+
ARG HTTPS_PROXY
|
|
17
|
+
ARG POETRY_VERSION=1.5.1
|
|
18
|
+
|
|
19
|
+
# ADDITION: Install uv
|
|
20
|
+
RUN curl -LsSf https://astral.sh/uv/install.sh | XDG_CONFIG_HOME=/tmp UV_INSTALL_DIR=/usr/bin sh
|
|
21
|
+
|
|
22
|
+
# Add virtualenv path
|
|
23
|
+
ENV PATH="/usr/app/venv/bin:$PATH"
|
|
24
|
+
|
|
25
|
+
# set the pip cache location
|
|
26
|
+
ENV PIP_CACHE_DIR=/tmp/pip-cache
|
|
27
|
+
|
|
28
|
+
# set the poetry cache
|
|
29
|
+
ENV POETRY_CACHE_DIR=/tmp/poetry-cache
|
|
30
|
+
|
|
31
|
+
# ADDITION: set the uv cache
|
|
32
|
+
ENV UV_CACHE_DIR=/tmp/uv-cache
|
|
33
|
+
|
|
34
|
+
# ADDITION: Replace 'pip' with uv pip in the following chunk
|
|
35
|
+
RUN \
|
|
36
|
+
# create a new virtualenv for python to use
|
|
37
|
+
# so that it isn't using root
|
|
38
|
+
python -m venv /usr/app/venv && \
|
|
39
|
+
# Create a new location for the pip cache
|
|
40
|
+
mkdir /tmp/pip-cache && \
|
|
41
|
+
# Ensure all users can write to pip cache
|
|
42
|
+
chmod -R 777 /tmp/pip-cache && \
|
|
43
|
+
# Upgrade pip (required by cryptography v3.4 and above, which is a dependency of poetry)
|
|
44
|
+
uv pip install --upgrade pip && \
|
|
45
|
+
# Create a new location for the poetry cache
|
|
46
|
+
mkdir /tmp/poetry-cache && \
|
|
47
|
+
# Ensure all users can write to poetry cache
|
|
48
|
+
chmod -R 777 /tmp/poetry-cache && \
|
|
49
|
+
# Ensure all users can write to uv cache
|
|
50
|
+
chmod -R 777 /tmp/uv-cache && \
|
|
51
|
+
# Install pipenv and poetry
|
|
52
|
+
uv pip install poetry==$POETRY_VERSION && \
|
|
53
|
+
# Ensure no temporary files remain in the caches
|
|
54
|
+
rm -rf /tmp/pip-cache/* /tmp/poetry-cache/* /tmp/uv-cache/*
|
|
55
|
+
|
|
56
|
+
# ADDITION: Replace /usr/app/venv/pip with uv pip
|
|
57
|
+
RUN printf '#!/usr/bin/env bash \nuv pip $@\n' > /usr/app/venv/bin/pip && \
|
|
58
|
+
printf '#!/usr/bin/env bash \nuv pip $@\n' > /usr/app/venv/bin/pip3
|
|
59
|
+
|
|
60
|
+
CMD [ "python" ]
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { StageName } from "../utils";
|
|
2
|
+
export declare const DEFAULT_ORCABUS_TOKEN_SECRET_ID = "orcabus/token-service-jwt";
|
|
3
|
+
export declare const DEFAULT_HOSTNAME_SSM_PARAMETER = "/hosted_zone/umccr/name";
|
|
4
|
+
export declare const MART_ENV_VARS: {
|
|
5
|
+
athenaWorkgroupName: string;
|
|
6
|
+
athenaDatasourceName: string;
|
|
7
|
+
athenaDatabaseName: string;
|
|
8
|
+
};
|
|
9
|
+
export declare const MART_S3_BUCKET: Record<StageName, string>;
|
|
10
|
+
export declare const MART_S3_PREFIX = "athena-query-results/";
|
|
11
|
+
export declare const MART_LAMBDA_FUNCTION_NAME = "orcavault";
|
package/lambda/config.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MART_LAMBDA_FUNCTION_NAME = exports.MART_S3_PREFIX = exports.MART_S3_BUCKET = exports.MART_ENV_VARS = exports.DEFAULT_HOSTNAME_SSM_PARAMETER = exports.DEFAULT_ORCABUS_TOKEN_SECRET_ID = void 0;
|
|
4
|
+
const utils_1 = require("../utils");
|
|
5
|
+
exports.DEFAULT_ORCABUS_TOKEN_SECRET_ID = 'orcabus/token-service-jwt';
|
|
6
|
+
exports.DEFAULT_HOSTNAME_SSM_PARAMETER = '/hosted_zone/umccr/name';
|
|
7
|
+
exports.MART_ENV_VARS = {
|
|
8
|
+
athenaWorkgroupName: 'orcahouse',
|
|
9
|
+
athenaDatasourceName: 'orcavault',
|
|
10
|
+
athenaDatabaseName: 'mart'
|
|
11
|
+
};
|
|
12
|
+
exports.MART_S3_BUCKET = {
|
|
13
|
+
BETA: `data-sharing-artifacts-${utils_1.accountIdAlias.BETA}-${utils_1.region}`,
|
|
14
|
+
GAMMA: `data-sharing-artifacts-${utils_1.accountIdAlias.GAMMA}-${utils_1.region}`,
|
|
15
|
+
PROD: `data-sharing-artifacts-${utils_1.accountIdAlias.PROD}-${utils_1.region}`
|
|
16
|
+
};
|
|
17
|
+
exports.MART_S3_PREFIX = 'athena-query-results/';
|
|
18
|
+
exports.MART_LAMBDA_FUNCTION_NAME = 'orcavault';
|
|
19
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiY29uZmlnLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLG9DQUEyRDtBQUU5QyxRQUFBLCtCQUErQixHQUFJLDJCQUEyQixDQUFBO0FBQzlELFFBQUEsOEJBQThCLEdBQUcseUJBQXlCLENBQUE7QUFFMUQsUUFBQSxhQUFhLEdBQUc7SUFDekIsbUJBQW1CLEVBQUUsV0FBVztJQUNoQyxvQkFBb0IsRUFBRSxXQUFXO0lBQ2pDLGtCQUFrQixFQUFFLE1BQU07Q0FDN0IsQ0FBQTtBQUVZLFFBQUEsY0FBYyxHQUE4QjtJQUNyRCxJQUFJLEVBQUUsMEJBQTBCLHNCQUFjLENBQUMsSUFBSSxJQUFJLGNBQU0sRUFBRTtJQUMvRCxLQUFLLEVBQUUsMEJBQTBCLHNCQUFjLENBQUMsS0FBSyxJQUFJLGNBQU0sRUFBRTtJQUNqRSxJQUFJLEVBQUUsMEJBQTBCLHNCQUFjLENBQUMsSUFBSSxJQUFJLGNBQU0sRUFBRTtDQUNsRSxDQUFBO0FBQ1ksUUFBQSxjQUFjLEdBQUcsdUJBQXVCLENBQUE7QUFDeEMsUUFBQSx5QkFBeUIsR0FBRyxXQUFXLENBQUEiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge2FjY291bnRJZEFsaWFzLCByZWdpb24sIFN0YWdlTmFtZX0gZnJvbSBcIi4uL3V0aWxzXCI7XG5cbmV4cG9ydCBjb25zdCBERUZBVUxUX09SQ0FCVVNfVE9LRU5fU0VDUkVUX0lEID0gICdvcmNhYnVzL3Rva2VuLXNlcnZpY2Utand0J1xuZXhwb3J0IGNvbnN0IERFRkFVTFRfSE9TVE5BTUVfU1NNX1BBUkFNRVRFUiA9ICcvaG9zdGVkX3pvbmUvdW1jY3IvbmFtZSdcblxuZXhwb3J0IGNvbnN0IE1BUlRfRU5WX1ZBUlMgPSB7XG4gICAgYXRoZW5hV29ya2dyb3VwTmFtZTogJ29yY2Fob3VzZScsXG4gICAgYXRoZW5hRGF0YXNvdXJjZU5hbWU6ICdvcmNhdmF1bHQnLFxuICAgIGF0aGVuYURhdGFiYXNlTmFtZTogJ21hcnQnXG59XG5cbmV4cG9ydCBjb25zdCBNQVJUX1MzX0JVQ0tFVDogUmVjb3JkPFN0YWdlTmFtZSwgc3RyaW5nPiA9IHtcbiAgICBCRVRBOiBgZGF0YS1zaGFyaW5nLWFydGlmYWN0cy0ke2FjY291bnRJZEFsaWFzLkJFVEF9LSR7cmVnaW9ufWAsXG4gICAgR0FNTUE6IGBkYXRhLXNoYXJpbmctYXJ0aWZhY3RzLSR7YWNjb3VudElkQWxpYXMuR0FNTUF9LSR7cmVnaW9ufWAsXG4gICAgUFJPRDogYGRhdGEtc2hhcmluZy1hcnRpZmFjdHMtJHthY2NvdW50SWRBbGlhcy5QUk9EfS0ke3JlZ2lvbn1gXG59XG5leHBvcnQgY29uc3QgTUFSVF9TM19QUkVGSVggPSAnYXRoZW5hLXF1ZXJ5LXJlc3VsdHMvJ1xuZXhwb3J0IGNvbnN0IE1BUlRfTEFNQkRBX0ZVTkNUSU9OX05BTUUgPSAnb3JjYXZhdWx0J1xuIl19
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { PythonFunction, PythonFunctionProps } from "@aws-cdk/aws-lambda-python-alpha";
|
|
2
|
+
import { Construct } from "constructs";
|
|
3
|
+
export interface OrcabusResourcesProps {
|
|
4
|
+
/**
|
|
5
|
+
* Provide the orcabusTokenSecretId, otherwise it will default to @DEFAULT_ORCABUS_TOKEN_SECRET_ID
|
|
6
|
+
*/
|
|
7
|
+
readonly orcabusTokenSecretId?: string;
|
|
8
|
+
/**
|
|
9
|
+
* Provide the hostnameSsmParameterName, otherwise it will default to @DEFAULT_HOSTNAME_SSM_PARAMETER
|
|
10
|
+
*/
|
|
11
|
+
readonly hostnameSsmParameterName?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface MartEnvironmentVariables {
|
|
14
|
+
/**
|
|
15
|
+
* Provide the athenaWorkgroupName, otherwise it will default to @MART_ENV_VARS.ATHENA_WORKGROUP_NAME
|
|
16
|
+
*/
|
|
17
|
+
readonly athenaWorkgroupName?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Provide the athenaDatasourceName, otherwise it will default to @MART_ENV_VARS.athenaDatasourceName
|
|
20
|
+
*/
|
|
21
|
+
readonly athenaDatasourceName?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Provide the athenaDatabaseName, otherwise it will default to @MART_ENV_VARS.ATHENA_DATABASE_NAME
|
|
24
|
+
*/
|
|
25
|
+
readonly athenaDatabaseName?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface PythonUvFunctionProps extends PythonFunctionProps {
|
|
28
|
+
/**
|
|
29
|
+
* Whether or not to include the orcabus api tools layer in the lambda function build
|
|
30
|
+
*/
|
|
31
|
+
readonly includeOrcabusApiToolsLayer?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Whether or not to include the mart layer in the lambda function build
|
|
34
|
+
* Note that the mart layer is a little heavier than the orcabus api tools layer
|
|
35
|
+
* Since we require pandas to be installed
|
|
36
|
+
*/
|
|
37
|
+
readonly includeMartLayer?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Provide the orcabusTokenResources, optional, otherwise it will default to
|
|
40
|
+
* @DEFAULT_ORCABUS_TOKEN_SECRET_ID and @DEFAULT_HOSTNAME_SSM_PARAMETER
|
|
41
|
+
* for the secret and SSM parameter respectively
|
|
42
|
+
*/
|
|
43
|
+
readonly orcabusTokenResources?: OrcabusResourcesProps;
|
|
44
|
+
/**
|
|
45
|
+
* Provide the martEnvironmentVariables, optional, otherwise it will default to
|
|
46
|
+
* @MART_ENV_VARS.ATHENA_WORKGROUP_NAME, @MART_ENV_VARS.ATHENA_DATASOURCE_NAME
|
|
47
|
+
* and @MART_ENV_VARS.ATHENA_DATABASE_NAME for the athena workgroup, datasource and database respectively
|
|
48
|
+
*/
|
|
49
|
+
readonly martEnvironmentVariables?: MartEnvironmentVariables;
|
|
50
|
+
}
|
|
51
|
+
export declare class PythonUvFunction extends PythonFunction {
|
|
52
|
+
private static orcabusApiToolsLayer;
|
|
53
|
+
private static martLayer;
|
|
54
|
+
constructor(scope: Construct, id: string, props: PythonUvFunctionProps);
|
|
55
|
+
private buildOrcabusApiToolsLayer;
|
|
56
|
+
private buildMartToolsLayer;
|
|
57
|
+
private setOrcabusResources;
|
|
58
|
+
private setAthenaResources;
|
|
59
|
+
}
|
package/lambda/index.js
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.PythonUvFunction = void 0;
|
|
40
|
+
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
|
|
41
|
+
const aws_lambda_python_alpha_1 = require("@aws-cdk/aws-lambda-python-alpha");
|
|
42
|
+
const lambda = __importStar(require("aws-cdk-lib/aws-lambda"));
|
|
43
|
+
const secretsManager = __importStar(require("aws-cdk-lib/aws-secretsmanager"));
|
|
44
|
+
const ssm = __importStar(require("aws-cdk-lib/aws-ssm"));
|
|
45
|
+
const iam = __importStar(require("aws-cdk-lib/aws-iam"));
|
|
46
|
+
const s3 = __importStar(require("aws-cdk-lib/aws-s3"));
|
|
47
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
48
|
+
const path_1 = __importDefault(require("path"));
|
|
49
|
+
const aws_lambda_1 = require("aws-cdk-lib/aws-lambda");
|
|
50
|
+
const config_1 = require("./config");
|
|
51
|
+
const utils_1 = require("../utils");
|
|
52
|
+
function getPythonUvDockerImage() {
|
|
53
|
+
return aws_cdk_lib_1.DockerImage.fromBuild(path_1.default.join(__dirname, 'build_python'));
|
|
54
|
+
}
|
|
55
|
+
class PythonUvFunction extends aws_lambda_python_alpha_1.PythonFunction {
|
|
56
|
+
static [JSII_RTTI_SYMBOL_1] = { fqn: "@orcabus/platform-cdk-constructs.lambda.PythonUvFunction", version: "0.0.7-alpha.4" };
|
|
57
|
+
// Class constructs, to be used for caching the layers
|
|
58
|
+
// This means that if there are multiple lambdas throughout the stack
|
|
59
|
+
// They will all use the same layer
|
|
60
|
+
static orcabusApiToolsLayer;
|
|
61
|
+
static martLayer;
|
|
62
|
+
constructor(scope, id, props) {
|
|
63
|
+
const uvProps = {
|
|
64
|
+
...props,
|
|
65
|
+
bundling: {
|
|
66
|
+
...props.bundling,
|
|
67
|
+
buildArgs: {
|
|
68
|
+
...props.bundling?.buildArgs,
|
|
69
|
+
// Add TARGETPLATFORM to build args if it's not already set
|
|
70
|
+
TARGETPLATFORM: props.bundling?.buildArgs?.TARGETPLATFORM ?? lambda.Architecture.ARM_64.dockerPlatform,
|
|
71
|
+
},
|
|
72
|
+
image: getPythonUvDockerImage(),
|
|
73
|
+
commandHooks: {
|
|
74
|
+
// @ts-ignore
|
|
75
|
+
beforeBundling(inputDir, outputDir) {
|
|
76
|
+
return [];
|
|
77
|
+
},
|
|
78
|
+
// @ts-ignore
|
|
79
|
+
afterBundling(inputDir, outputDir) {
|
|
80
|
+
return [`rm -rf ${outputDir}/pandas/tests`];
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
paramsAndSecrets: props.paramsAndSecrets ??
|
|
85
|
+
aws_lambda_1.ParamsAndSecretsLayerVersion.fromVersion(aws_lambda_1.ParamsAndSecretsVersions.V1_0_103, {
|
|
86
|
+
cacheEnabled: true,
|
|
87
|
+
cacheSize: 300,
|
|
88
|
+
logLevel: aws_lambda_1.ParamsAndSecretsLogLevel.DEBUG,
|
|
89
|
+
}),
|
|
90
|
+
};
|
|
91
|
+
super(scope, id, uvProps);
|
|
92
|
+
if (props.includeOrcabusApiToolsLayer) {
|
|
93
|
+
/* Set the environment variables for the Orcabus resources */
|
|
94
|
+
this.setOrcabusResources(props.orcabusTokenResources ?? {});
|
|
95
|
+
/* Build the orcabus Api tools layer */
|
|
96
|
+
this.buildOrcabusApiToolsLayer();
|
|
97
|
+
this.addLayers(PythonUvFunction.orcabusApiToolsLayer);
|
|
98
|
+
}
|
|
99
|
+
if (props.includeMartLayer) {
|
|
100
|
+
/* Set the environment variables for the mart resources */
|
|
101
|
+
this.setAthenaResources(props.martEnvironmentVariables ?? {});
|
|
102
|
+
/* Build the mart layer */
|
|
103
|
+
this.buildMartToolsLayer();
|
|
104
|
+
this.addLayers(PythonUvFunction.martLayer);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
buildOrcabusApiToolsLayer() {
|
|
108
|
+
// Only build orcabus api layer if it doesn't exist
|
|
109
|
+
if (!PythonUvFunction.orcabusApiToolsLayer) {
|
|
110
|
+
PythonUvFunction.orcabusApiToolsLayer = new aws_lambda_python_alpha_1.PythonLayerVersion(this, 'orcabusApiToolsLayer', {
|
|
111
|
+
layerVersionName: 'orcabusApiToolsLayer',
|
|
112
|
+
entry: path_1.default.join(__dirname, 'layers/orcabus_api_tools'),
|
|
113
|
+
compatibleRuntimes: [lambda.Runtime.PYTHON_3_12],
|
|
114
|
+
compatibleArchitectures: [lambda.Architecture.ARM_64],
|
|
115
|
+
license: 'GPL3',
|
|
116
|
+
description: 'orcabusApiToolsLayer',
|
|
117
|
+
bundling: {
|
|
118
|
+
image: getPythonUvDockerImage(),
|
|
119
|
+
commandHooks: {
|
|
120
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
121
|
+
beforeBundling(inputDir, outputDir) {
|
|
122
|
+
return [];
|
|
123
|
+
},
|
|
124
|
+
afterBundling(inputDir, outputDir) {
|
|
125
|
+
return [
|
|
126
|
+
`pip install ${inputDir} --target ${outputDir}`,
|
|
127
|
+
`find ${outputDir} -name 'pandas' -exec rm -rf {}/tests/ \\;`,
|
|
128
|
+
];
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
buildMartToolsLayer() {
|
|
136
|
+
// Only build the layer if it doesn't exist
|
|
137
|
+
if (!PythonUvFunction.martLayer) {
|
|
138
|
+
PythonUvFunction.martLayer = new aws_lambda_python_alpha_1.PythonLayerVersion(this, 'martToolsLayer', {
|
|
139
|
+
layerVersionName: 'martToolsLayer',
|
|
140
|
+
entry: path_1.default.join(__dirname, 'layers/mart_tools'),
|
|
141
|
+
compatibleRuntimes: [lambda.Runtime.PYTHON_3_12],
|
|
142
|
+
compatibleArchitectures: [lambda.Architecture.ARM_64],
|
|
143
|
+
license: 'GPL3',
|
|
144
|
+
description: 'martToolsLayer',
|
|
145
|
+
bundling: {
|
|
146
|
+
image: getPythonUvDockerImage(),
|
|
147
|
+
commandHooks: {
|
|
148
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
149
|
+
beforeBundling(inputDir, outputDir) {
|
|
150
|
+
return [];
|
|
151
|
+
},
|
|
152
|
+
afterBundling(inputDir, outputDir) {
|
|
153
|
+
return [
|
|
154
|
+
`pip install ${inputDir} --target ${outputDir}`,
|
|
155
|
+
`find ${outputDir} -name 'pandas' -exec rm -rf {}/tests/ \\;`,
|
|
156
|
+
];
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
setOrcabusResources(props) {
|
|
164
|
+
// Set secret object
|
|
165
|
+
const orcabusTokenSecretId = secretsManager.Secret.fromSecretNameV2(this, 'orcabusTokenSecretId', props.orcabusTokenSecretId ?? config_1.DEFAULT_ORCABUS_TOKEN_SECRET_ID);
|
|
166
|
+
const hostnameSsmParameterName = ssm.StringParameter.fromStringParameterName(this, 'hostnameSsmParameterName', props.hostnameSsmParameterName ?? config_1.DEFAULT_HOSTNAME_SSM_PARAMETER);
|
|
167
|
+
// Add permissions for the secret and SSM parameter
|
|
168
|
+
// To the current version
|
|
169
|
+
orcabusTokenSecretId.grantRead(this.currentVersion);
|
|
170
|
+
hostnameSsmParameterName.grantRead(this.currentVersion);
|
|
171
|
+
// Add environment variables
|
|
172
|
+
this.addEnvironment('ORCABUS_TOKEN_SECRET_ID', orcabusTokenSecretId.secretName);
|
|
173
|
+
this.addEnvironment('HOSTNAME_SSM_PARAMETER_NAME', hostnameSsmParameterName.parameterName);
|
|
174
|
+
}
|
|
175
|
+
setAthenaResources(props) {
|
|
176
|
+
// Resolve the stage name by performing a reverse lookup using cdk.Aws.ACCOUNT_ID on accountIdAlias
|
|
177
|
+
const stageName = (0, utils_1.resolveStageName)();
|
|
178
|
+
const athenaS3Bucket = s3.Bucket.fromBucketName(this, 'athenaS3Bucket', config_1.MART_S3_BUCKET[stageName]);
|
|
179
|
+
const athenaFunctionName = lambda.Function.fromFunctionName(this, 'lambdaFunctionName', config_1.MART_LAMBDA_FUNCTION_NAME);
|
|
180
|
+
// Add env vars
|
|
181
|
+
// Iterate over kv pairs of MART_ENV_VARS
|
|
182
|
+
for (const [key, value] of Object.entries(config_1.MART_ENV_VARS)) {
|
|
183
|
+
// After
|
|
184
|
+
if (props[key] !== undefined) {
|
|
185
|
+
this.addEnvironment(key, props[key]);
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
this.addEnvironment(key, value);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// Permissions
|
|
192
|
+
this.currentVersion.addToRolePolicy(
|
|
193
|
+
// From https://docs.aws.amazon.com/athena/latest/ug/example-policies-workgroup.html
|
|
194
|
+
new iam.PolicyStatement({
|
|
195
|
+
actions: [
|
|
196
|
+
// Workgroup lists
|
|
197
|
+
'athena:ListEngineVersions',
|
|
198
|
+
'athena:ListWorkGroups',
|
|
199
|
+
'athena:ListDataCatalogs',
|
|
200
|
+
'athena:ListDatabases',
|
|
201
|
+
'athena:GetDatabase',
|
|
202
|
+
'athena:ListTableMetadata',
|
|
203
|
+
'athena:GetTableMetadata',
|
|
204
|
+
'athena:GetDataCatalog',
|
|
205
|
+
],
|
|
206
|
+
resources: [`arn:aws:athena:${utils_1.region}:${utils_1.accountIdAlias[stageName]}:*`],
|
|
207
|
+
}));
|
|
208
|
+
this.currentVersion.addToRolePolicy(
|
|
209
|
+
// From https://docs.aws.amazon.com/athena/latest/ug/example-policies-workgroup.html
|
|
210
|
+
new iam.PolicyStatement({
|
|
211
|
+
actions: [
|
|
212
|
+
// Workgroup executions
|
|
213
|
+
'athena:BatchGetQueryExecution',
|
|
214
|
+
'athena:GetQueryExecution',
|
|
215
|
+
'athena:ListQueryExecutions',
|
|
216
|
+
'athena:StartQueryExecution',
|
|
217
|
+
'athena:StopQueryExecution',
|
|
218
|
+
'athena:GetQueryResults',
|
|
219
|
+
'athena:GetQueryResultsStream',
|
|
220
|
+
'athena:CreateNamedQuery',
|
|
221
|
+
'athena:GetNamedQuery',
|
|
222
|
+
'athena:BatchGetNamedQuery',
|
|
223
|
+
'athena:ListNamedQueries',
|
|
224
|
+
'athena:DeleteNamedQuery',
|
|
225
|
+
'athena:CreatePreparedStatement',
|
|
226
|
+
'athena:GetPreparedStatement',
|
|
227
|
+
'athena:ListPreparedStatements',
|
|
228
|
+
'athena:UpdatePreparedStatement',
|
|
229
|
+
'athena:DeletePreparedStatement',
|
|
230
|
+
],
|
|
231
|
+
resources: [
|
|
232
|
+
`arn:aws:athena:${utils_1.region}:${utils_1.accountIdAlias[stageName]}:workgroup/${config_1.MART_ENV_VARS.athenaWorkgroupName}`,
|
|
233
|
+
],
|
|
234
|
+
}));
|
|
235
|
+
// Add read access to the S3 bucket
|
|
236
|
+
athenaS3Bucket.grantReadWrite(this.currentVersion, `${config_1.MART_S3_PREFIX}*`);
|
|
237
|
+
// Add invoke access to the lambda function
|
|
238
|
+
athenaFunctionName.grantInvoke(this.currentVersion);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
exports.PythonUvFunction = PythonUvFunction;
|
|
242
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsOEVBQXlHO0FBRXpHLCtEQUFpRDtBQUNqRCwrRUFBaUU7QUFDakUseURBQTJDO0FBQzNDLHlEQUEyQztBQUMzQyx1REFBeUM7QUFDekMsNkNBQXdDO0FBRXhDLGdEQUF3QjtBQUV4Qix1REFJZ0M7QUFDaEMscUNBTWtCO0FBQ2xCLG9DQUFrRTtBQUdsRSxTQUFTLHNCQUFzQjtJQUMzQixPQUFPLHlCQUFXLENBQUMsU0FBUyxDQUFDLGNBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLGNBQWMsQ0FBQyxDQUFDLENBQUM7QUFDdkUsQ0FBQztBQTRERCxNQUFhLGdCQUFpQixTQUFRLHdDQUFjOztJQUNoRCxzREFBc0Q7SUFDdEQscUVBQXFFO0lBQ3JFLG1DQUFtQztJQUMzQixNQUFNLENBQUMsb0JBQW9CLENBQXVCO0lBQ2xELE1BQU0sQ0FBQyxTQUFTLENBQXVCO0lBRS9DLFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBNEI7UUFDbEUsTUFBTSxPQUFPLEdBQUc7WUFDWixHQUFHLEtBQUs7WUFDUixRQUFRLEVBQUU7Z0JBQ04sR0FBRyxLQUFLLENBQUMsUUFBUTtnQkFDakIsU0FBUyxFQUFFO29CQUNQLEdBQUcsS0FBSyxDQUFDLFFBQVEsRUFBRSxTQUFTO29CQUM1QiwyREFBMkQ7b0JBQzNELGNBQWMsRUFDVixLQUFLLENBQUMsUUFBUSxFQUFFLFNBQVMsRUFBRSxjQUFjLElBQUksTUFBTSxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUMsY0FBYztpQkFDN0Y7Z0JBQ0QsS0FBSyxFQUFFLHNCQUFzQixFQUFFO2dCQUMvQixZQUFZLEVBQUU7b0JBQ1YsYUFBYTtvQkFDYixjQUFjLENBQUMsUUFBZ0IsRUFBRSxTQUFpQjt3QkFDOUMsT0FBTyxFQUFFLENB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QUNELFNBQVMsRUFBRSxDQUFDLGtCQUFrQixjQUFNLElBQUksc0JBQWMsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDO1NBQ3pFLENBQUMsQ0FDTCxDQUFDO1FBRUYsSUFBSSxDQUFDLGNBQWMsQ0FBQyxlQUFlO1FBQy9CLG9GQUFvRjtRQUNwRixJQUFJLEdBQUcsQ0FBQyxlQUFlLENBQUM7WUFDcEIsT0FBTyxFQUFFO2dCQUNMLHVCQUF1QjtnQkFDdkIsK0JBQStCO2dCQUMvQiwwQkFBMEI7Z0JBQzFCLDRCQUE0QjtnQkFDNUIsNEJBQTRCO2dCQUM1QiwyQkFBMkI7Z0JBQzNCLHdCQUF3QjtnQkFDeEIsOEJBQThCO2dCQUM5Qix5QkFBeUI7Z0JBQ3pCLHNCQUFzQjtnQkFDdEIsMkJBQTJCO2dCQUMzQix5QkFBeUI7Z0JBQ3pCLHlCQUF5QjtnQkFDekIsZ0NBQWdDO2dCQUNoQyw2QkFBNkI7Z0JBQzdCLCtCQUErQjtnQkFDL0IsZ0NBQWdDO2dCQUNoQyxnQ0FBZ0M7YUFDbkM7WUFDRCxTQUFTLEVBQUU7Z0JBQ1Asa0JBQWtCLGNBQU0sSUFBSSxzQkFBYyxDQUFDLFNBQVMsQ0FBQyxjQUFjLHNCQUFhLENBQUMsbUJBQW1CLEVBQUU7YUFDekc7U0FDSixDQUFDLENBQ0wsQ0FBQztRQUVGLG1DQUFtQztRQUNuQyxjQUFjLENBQUMsY0FBYyxDQUN6QixJQUFJLENBQUMsY0FBYyxFQUNuQixHQUFHLHVCQUFjLEdBQUcsQ0FDdkIsQ0FBQTtRQUVELDJDQUEyQztRQUMzQyxrQkFBa0IsQ0FBQyxXQUFXLENBQzFCLElBQUksQ0FBQyxjQUFjLENBQ3RCLENBQUE7SUFDTCxDQUFDOztBQXRPTCw0Q0F1T0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1B5dGhvbkZ1bmN0aW9uLCBQeXRob25GdW5jdGlvblByb3BzLCBQeXRob25MYXllclZlcnNpb259IGZyb20gXCJAYXdzLWNkay9hd3MtbGFtYmRhLXB5dGhvbi1hbHBoYVwiO1xuaW1wb3J0IHtDb25zdHJ1Y3R9IGZyb20gXCJjb25zdHJ1Y3RzXCI7XG5pbXBvcnQgKiBhcyBsYW1iZGEgZnJvbSBcImF3cy1jZGstbGliL2F3cy1sYW1iZGFcIjtcbmltcG9ydCAqIGFzIHNlY3JldHNNYW5hZ2VyIGZyb20gXCJhd3MtY2RrLWxpYi9hd3Mtc2VjcmV0c21hbmFnZXJcIjtcbmltcG9ydCAqIGFzIHNzbSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLXNzbVwiO1xuaW1wb3J0ICogYXMgaWFtIGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtaWFtXCI7XG5pbXBvcnQgKiBhcyBzMyBmcm9tIFwiYXdzLWNkay1saWIvYXdzLXMzXCI7XG5pbXBvcnQge0RvY2tlckltYWdlfSBmcm9tICdhd3MtY2RrLWxpYic7XG5cbmltcG9ydCBwYXRoIGZyb20gXCJwYXRoXCI7XG5cbmltcG9ydCB7XG4gICAgUGFyYW1zQW5kU2VjcmV0c0xheWVyVmVyc2lvbixcbiAgICBQYXJhbXNBbmRTZWNyZXRzTG9nTGV2ZWwsXG4gICAgUGFyYW1zQW5kU2VjcmV0c1ZlcnNpb25zLFxufSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtbGFtYmRhJztcbmltcG9ydCB7XG4gICAgREVGQVVMVF9IT1NUTkFNRV9TU01fUEFSQU1FVEVSLFxuICAgIERFRkFVTFRfT1JDQUJVU19UT0tFTl9TRUNSRVRfSUQsXG4gICAgTUFSVF9FTlZfVkFSUywgTUFSVF9MQU1CREFfRlVOQ1RJT05fTkFNRSxcbiAgICBNQVJUX1MzX0JVQ0tFVCxcbiAgICBNQVJUX1MzX1BSRUZJWFxufSBmcm9tIFwiLi9jb25maWdcIjtcbmltcG9ydCB7YWNjb3VudElkQWxpYXMsIHJlZ2lvbiwgcmVzb2x2ZVN0YWdlTmFtZX0gZnJvbSBcIi4uL3V0aWxzXCI7XG5cblxuZnVuY3Rpb24gZ2V0UHl0aG9uVXZEb2NrZXJJbWFnZSgpOiBEb2NrZXJJbWFnZSB7XG4gICAgcmV0dXJuIERvY2tlckltYWdlLmZyb21CdWlsZChwYXRoLmpvaW4oX19kaXJuYW1lLCAnYnVpbGRfcHl0aG9uJykpO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIE9yY2FidXNSZXNvdXJjZXNQcm9wcyB7XG4gICAgLyoqXG4gICAgICogUHJvdmlkZSB0aGUgb3JjYWJ1c1Rva2VuU2VjcmV0SWQsIG90aGVyd2lzZSBpdCB3aWxsIGRlZmF1bHQgdG8gQERFRkFVTFRfT1JDQUJVU19UT0tFTl9TRUNSRVRfSURcbiAgICAgKi9cbiAgICByZWFkb25seSBvcmNhYnVzVG9rZW5TZWNyZXRJZD86IHN0cmluZ1xuXG4gICAgLyoqXG4gICAgICogUHJvdmlkZSB0aGUgaG9zdG5hbWVTc21QYXJhbWV0ZXJOYW1lLCBvdGhlcndpc2UgaXQgd2lsbCBkZWZhdWx0IHRvIEBERUZBVUxUX0hPU1ROQU1FX1NTTV9QQVJBTUVURVJcbiAgICAgKi9cbiAgICByZWFkb25seSBob3N0bmFtZVNzbVBhcmFtZXRlck5hbWU/OiBzdHJpbmdcbn1cblxuZXhwb3J0IGludGVyZmFjZSBNYXJ0RW52aXJvbm1lbnRWYXJpYWJsZXMge1xuICAgIC8qKlxuICAgICAqIFByb3ZpZGUgdGhlIGF0aGVuYVdvcmtncm91cE5hbWUsIG90aGVyd2lzZSBpdCB3aWxsIGRlZmF1bHQgdG8gQE1BUlRfRU5WX1ZBUlMuQVRIRU5BX1dPUktHUk9VUF9OQU1FXG4gICAgICovXG4gICAgcmVhZG9ubHkgYXRoZW5hV29ya2dyb3VwTmFtZT86IHN0cmluZ1xuXG4gICAgLyoqXG4gICAgICogUHJvdmlkZSB0aGUgYXRoZW5hRGF0YXNvdXJjZU5hbWUsIG90aGVyd2lzZSBpdCB3aWxsIGRlZmF1bHQgdG8gQE1BUlRfRU5WX1ZBUlMuYXRoZW5hRGF0YXNvdXJjZU5hbWVcbiAgICAgKi9cbiAgICByZWFkb25seSBhdGhlbmFEYXRhc291cmNlTmFtZT86IHN0cmluZ1xuXG4gICAgLyoqXG4gICAgICogUHJvdmlkZSB0aGUgYXRoZW5hRGF0YWJhc2VOYW1lLCBvdGhlcndpc2UgaXQgd2lsbCBkZWZhdWx0IHRvIEBNQVJUX0VOVl9WQVJTLkFUSEVOQV9EQVRBQkFTRV9OQU1FXG4gICAgICovXG4gICAgcmVhZG9ubHkgYXRoZW5hRGF0YWJhc2VOYW1lPzogc3RyaW5nXG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUHl0aG9uVXZGdW5jdGlvblByb3BzIGV4dGVuZHMgUHl0aG9uRnVuY3Rpb25Qcm9wcyB7XG4gICAgLyoqXG4gICAgICogV2hldGhlciBvciBub3QgdG8gaW5jbHVkZSB0aGUgb3JjYWJ1cyBhcGkgdG9vbHMgbGF5ZXIgaW4gdGhlIGxhbWJkYSBmdW5jdGlvbiBidWlsZFxuICAgICAqL1xuICAgIHJlYWRvbmx5IGluY2x1ZGVPcmNhYnVzQXBpVG9vbHNMYXllcj86IGJvb2xlYW5cblxuICAgIC8qKlxuICAgICAqIFdoZXRoZXIgb3Igbm90IHRvIGluY2x1ZGUgdGhlIG1hcnQgbGF5ZXIgaW4gdGhlIGxhbWJkYSBmdW5jdGlvbiBidWlsZFxuICAgICAqIE5vdGUgdGhhdCB0aGUgbWFydCBsYXllciBpcyBhIGxpdHRsZSBoZWF2aWVyIHRoYW4gdGhlIG9yY2FidXMgYXBpIHRvb2xzIGxheWVyXG4gICAgICogU2luY2Ugd2UgcmVxdWlyZSBwYW5kYXMgdG8gYmUgaW5zdGFsbGVkXG4gICAgICovXG4gICAgcmVhZG9ubHkgaW5jbHVkZU1hcnRMYXllcj86IGJvb2xlYW5cblxuICAgIC8qKlxuICAgICAqIFByb3ZpZGUgdGhlIG9yY2FidXNUb2tlblJlc291cmNlcywgb3B0aW9uYWwsIG90aGVyd2lzZSBpdCB3aWxsIGRlZmF1bHQgdG9cbiAgICAgKiBAREVGQVVMVF9PUkNBQlVTX1RPS0VOX1NFQ1JFVF9JRCBhbmQgQERFRkFVTFRfSE9TVE5BTUVfU1NNX1BBUkFNRVRFUlxuICAgICAqIGZvciB0aGUgc2VjcmV0IGFuZCBTU00gcGFyYW1ldGVyIHJlc3BlY3RpdmVseVxuICAgICAqL1xuICAgIHJlYWRvbmx5IG9yY2FidXNUb2tlblJlc291cmNlcz86IE9yY2FidXNSZXNvdXJjZXNQcm9wc1xuXG4gICAgLyoqXG4gICAgICogUHJvdmlkZSB0aGUgbWFydEVudmlyb25tZW50VmFyaWFibGVzLCBvcHRpb25hbCwgb3RoZXJ3aXNlIGl0IHdpbGwgZGVmYXVsdCB0b1xuICAgICAqIEBNQVJUX0VOVl9WQVJTLkFUSEVOQV9XT1JLR1JPVVBfTkFNRSwgQE1BUlRfRU5WX1ZBUlMuQVRIRU5BX0RBVEFTT1VSQ0VfTkFNRVxuICAgICAqIGFuZCBATUFSVF9FTlZfVkFSUy5BVEhFTkFfREFUQUJBU0VfTkFNRSBmb3IgdGhlIGF0aGVuYSB3b3JrZ3JvdXAsIGRhdGFzb3VyY2UgYW5kIGRhdGFiYXNlIHJlc3BlY3RpdmVseVxuICAgICAqL1xuICAgIHJlYWRvbmx5IG1hcnRFbnZpcm9ubWVudFZhcmlhYmxlcz86IE1hcnRFbnZpcm9ubWVudFZhcmlhYmxlc1xufVxuXG5cbmV4cG9ydCBjbGFzcyBQeXRob25VdkZ1bmN0aW9uIGV4dGVuZHMgUHl0aG9uRnVuY3Rpb24ge1xuICAgIC8vIENsYXNzIGNvbnN0cnVjdHMsIHRvIGJlIHVzZWQgZm9yIGNhY2hpbmcgdGhlIGxheWVyc1xuICAgIC8vIFRoaXMgbWVhbnMgdGhhdCBpZiB0aGVyZSBhcmUgbXVsdGlwbGUgbGFtYmRhcyB0aHJvdWdob3V0IHRoZSBzdGFja1xuICAgIC8vIFRoZXkgd2lsbCBhbGwgdXNlIHRoZSBzYW1lIGxheWVyXG4gICAgcHJpdmF0ZSBzdGF0aWMgb3JjYWJ1c0FwaVRvb2xzTGF5ZXI6IGxhbWJkYS5JTGF5ZXJWZXJzaW9uO1xuICAgIHByaXZhdGUgc3RhdGljIG1hcnRMYXllcjogbGFtYmRhLklMYXllclZlcnNpb247XG5cbiAgICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogUHl0aG9uVXZGdW5jdGlvblByb3BzKSB7XG4gICAgICAgIGNvbnN0IHV2UHJvcHMgPSB7XG4gICAgICAgICAgICAuLi5wcm9wcyxcbiAgICAgICAgICAgIGJ1bmRsaW5nOiB7XG4gICAgICAgICAgICAgICAgLi4ucHJvcHMuYnVuZGxpbmcsXG4gICAgICAgICAgICAgICAgYnVpbGRBcmdzOiB7XG4gICAgICAgICAgICAgICAgICAgIC4uLnByb3BzLmJ1bmRsaW5nPy5idWlsZEFyZ3MsXG4gICAgICAgICAgICAgICAgICAgIC8vIEFkZCBUQVJHRVRQTEFURk9STSB0byBidWlsZCBhcmdzIGlmIGl0J3Mgbm90IGFscmVhZHkgc2V0XG4gICAgICAgICAgICAgICAgICAgIFRBUkdFVFBMQVRGT1JNOlxuICAgICAgICAgICAgICAgICAgICAgICAgcHJvcHMuYnVuZGxpbmc/LmJ1aWxkQXJncz8uVEFSR0VUUExBVEZPUk0gPz8gbGFtYmRhLkFyY2hpdGVjdHVyZS5BUk1fNjQuZG9ja2VyUGxhdGZvcm0sXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBpbWFnZTogZ2V0UHl0aG9uVXZEb2NrZXJJbWFnZSgpLFxuICAgICAgICAgICAgICAgIGNvbW1hbmRIb29rczoge1xuICAgICAgICAgICAgICAgICAgICAvLyBAdHMtaWdub3JlXG4gICAgICAgICAgICAgICAgICAgIGJlZm9yZUJ1bmRsaW5nKGlucHV0RGlyOiBzdHJpbmcsIG91dHB1dERpcjogc3RyaW5nKTogc3RyaW5nW10ge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAvLyBAdHMtaWdub3JlXG4gICAgICAgICAgICAgICAgICAgIGFmdGVyQnVuZGxpbmcoaW5wdXREaXI6IHN0cmluZywgb3V0cHV0RGlyOiBzdHJpbmcpOiBzdHJpbmdbXSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gW2BybSAtcmYgJHtvdXRwdXREaXJ9L3BhbmRhcy90ZXN0c2BdO1xuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgcGFyYW1zQW5kU2VjcmV0czpcbiAgICAgICAgICAgICAgICBwcm9wcy5wYXJhbXNBbmRTZWNyZXRzID8/XG4gICAgICAgICAgICAgICAgUGFyYW1zQW5kU2VjcmV0c0xheWVyVmVyc2lvbi5mcm9tVmVyc2lvbihQYXJhbXNBbmRTZWNyZXRzVmVyc2lvbnMuVjFfMF8xMDMsIHtcbiAgICAgICAgICAgICAgICAgICAgY2FjaGVFbmFibGVkOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICBjYWNoZVNpemU6IDMwMCxcbiAgICAgICAgICAgICAgICAgICAgbG9nTGV2ZWw6IFBhcmFtc0FuZFNlY3JldHNMb2dMZXZlbC5ERUJVRyxcbiAgICAgICAgICAgICAgICB9KSxcbiAgICAgICAgfTtcbiAgICAgICAgc3VwZXIoc2NvcGUsIGlkLCB1dlByb3BzKTtcblxuICAgICAgICBpZiAocHJvcHMuaW5jbHVkZU9yY2FidXNBcGlUb29sc0xheWVyKSB7XG4gICAgICAgICAgICAvKiBTZXQgdGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyBmb3IgdGhlIE9yY2FidXMgcmVzb3VyY2VzICovXG4gICAgICAgICAgICB0aGlzLnNldE9yY2FidXNSZXNvdXJjZXMocHJvcHMub3JjYWJ1c1Rva2VuUmVzb3VyY2VzID8/IHt9KVxuXG4gICAgICAgICAgICAvKiBCdWlsZCB0aGUgb3JjYWJ1cyBBcGkgdG9vbHMgbGF5ZXIgKi9cbiAgICAgICAgICAgIHRoaXMuYnVpbGRPcmNhYnVzQXBpVG9vbHNMYXllcigpXG4gICAgICAgICAgICB0aGlzLmFkZExheWVycyhQeXRob25VdkZ1bmN0aW9uLm9yY2FidXNBcGlUb29sc0xheWVyKVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHByb3BzLmluY2x1ZGVNYXJ0TGF5ZXIpIHtcbiAgICAgICAgICAgIC8qIFNldCB0aGUgZW52aXJvbm1lbnQgdmFyaWFibGVzIGZvciB0aGUgbWFydCByZXNvdXJjZXMgKi9cbiAgICAgICAgICAgIHRoaXMuc2V0QXRoZW5hUmVzb3VyY2VzKHByb3BzLm1hcnRFbnZpcm9ubWVudFZhcmlhYmxlcyA/PyB7fSlcblxuICAgICAgICAgICAgLyogQnVpbGQgdGhlIG1hcnQgbGF5ZXIgKi9cbiAgICAgICAgICAgIHRoaXMuYnVpbGRNYXJ0VG9vbHNMYXllcigpXG4gICAgICAgICAgICB0aGlzLmFkZExheWVycyhQeXRob25VdkZ1bmN0aW9uLm1hcnRMYXllcilcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgYnVpbGRPcmNhYnVzQXBpVG9vbHNMYXllcigpIHtcbiAgICAgICAgLy8gT25seSBidWlsZCBvcmNhYnVzIGFwaSBsYXllciBpZiBpdCBkb2Vzbid0IGV4aXN0XG4gICAgICAgIGlmICghUHl0aG9uVXZGdW5jdGlvbi5vcmNhYnVzQXBpVG9vbHNMYXllcikge1xuICAgICAgICAgICAgUHl0aG9uVXZGdW5jdGlvbi5vcmNhYnVzQXBpVG9vbHNMYXllciA9IG5ldyBQeXRob25MYXllclZlcnNpb24odGhpcywgJ29yY2FidXNBcGlUb29sc0xheWVyJywge1xuICAgICAgICAgICAgICAgIGxheWVyVmVyc2lvbk5hbWU6ICdvcmNhYnVzQXBpVG9vbHNMYXllcicsXG4gICAgICAgICAgICAgICAgZW50cnk6IHBhdGguam9pbihfX2Rpcm5hbWUsICdsYXllcnMvb3JjYWJ1c19hcGlfdG9vbHMnKSxcbiAgICAgICAgICAgICAgICBjb21wYXRpYmxlUnVudGltZXM6IFtsYW1iZGEuUnVudGltZS5QWVRIT05fM18xMl0sXG4gICAgICAgICAgICAgICAgY29tcGF0aWJsZUFyY2hpdGVjdHVyZXM6IFtsYW1iZGEuQXJjaGl0ZWN0dXJlLkFSTV82NF0sXG4gICAgICAgICAgICAgICAgbGljZW5zZTogJ0dQTDMnLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiAnb3JjYWJ1c0FwaVRvb2xzTGF5ZXInLFxuICAgICAgICAgICAgICAgIGJ1bmRsaW5nOiB7XG4gICAgICAgICAgICAgICAgICAgIGltYWdlOiBnZXRQeXRob25VdkRvY2tlckltYWdlKCksXG4gICAgICAgICAgICAgICAgICAgIGNvbW1hbmRIb29rczoge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFyc1xuICAgICAgICAgICAgICAgICAgICAgICAgYmVmb3JlQnVuZGxpbmcoaW5wdXREaXI6IHN0cmluZywgb3V0cHV0RGlyOiBzdHJpbmcpOiBzdHJpbmdbXSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGFmdGVyQnVuZGxpbmcoaW5wdXREaXI6IHN0cmluZywgb3V0cHV0RGlyOiBzdHJpbmcpOiBzdHJpbmdbXSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYHBpcCBpbnN0YWxsICR7aW5wdXREaXJ9IC0tdGFyZ2V0ICR7b3V0cHV0RGlyfWAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBmaW5kICR7b3V0cHV0RGlyfSAtbmFtZSAncGFuZGFzJyAtZXhlYyBybSAtcmYge30vdGVzdHMvIFxcXFw7YCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGJ1aWxkTWFydFRvb2xzTGF5ZXIoKSB7XG4gICAgICAgIC8vIE9ubHkgYnVpbGQgdGhlIGxheWVyIGlmIGl0IGRvZXNuJ3QgZXhpc3RcbiAgICAgICAgaWYgKCFQeXRob25VdkZ1bmN0aW9uLm1hcnRMYXllcikge1xuICAgICAgICAgICAgUHl0aG9uVXZGdW5jdGlvbi5tYXJ0TGF5ZXIgPSBuZXcgUHl0aG9uTGF5ZXJWZXJzaW9uKHRoaXMsICdtYXJ0VG9vbHNMYXllcicsIHtcbiAgICAgICAgICAgICAgICBsYXllclZlcnNpb25OYW1lOiAnbWFydFRvb2xzTGF5ZXInLFxuICAgICAgICAgICAgICAgIGVudHJ5OiBwYXRoLmpvaW4oX19kaXJuYW1lLCAnbGF5ZXJzL21hcnRfdG9vbHMnKSxcbiAgICAgICAgICAgICAgICBjb21wYXRpYmxlUnVudGltZXM6IFtsYW1iZGEuUnVudGltZS5QWVRIT05fM18xMl0sXG4gICAgICAgICAgICAgICAgY29tcGF0aWJsZUFyY2hpdGVjdHVyZXM6IFtsYW1iZGEuQXJjaGl0ZWN0dXJlLkFSTV82NF0sXG4gICAgICAgICAgICAgICAgbGljZW5zZTogJ0dQTDMnLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiAnbWFydFRvb2xzTGF5ZXInLFxuICAgICAgICAgICAgICAgIGJ1bmRsaW5nOiB7XG4gICAgICAgICAgICAgICAgICAgIGltYWdlOiBnZXRQeXRob25VdkRvY2tlckltYWdlKCksXG4gICAgICAgICAgICAgICAgICAgIGNvbW1hbmRIb29rczoge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFyc1xuICAgICAgICAgICAgICAgICAgICAgICAgYmVmb3JlQnVuZGxpbmcoaW5wdXREaXI6IHN0cmluZywgb3V0cHV0RGlyOiBzdHJpbmcpOiBzdHJpbmdbXSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGFmdGVyQnVuZGxpbmcoaW5wdXREaXI6IHN0cmluZywgb3V0cHV0RGlyOiBzdHJpbmcpOiBzdHJpbmdbXSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYHBpcCBpbnN0YWxsICR7aW5wdXREaXJ9IC0tdGFyZ2V0ICR7b3V0cHV0RGlyfWAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBmaW5kICR7b3V0cHV0RGlyfSAtbmFtZSAncGFuZGFzJyAtZXhlYyBybSAtcmYge30vdGVzdHMvIFxcXFw7YCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgIH1cblxuICAgIHByaXZhdGUgc2V0T3JjYWJ1c1Jlc291cmNlcyhcbiAgICAgICAgcHJvcHM6IE9yY2FidXNSZXNvdXJjZXNQcm9wc1xuICAgICkge1xuICAgICAgICAvLyBTZXQgc2VjcmV0IG9iamVjdFxuICAgICAgICBjb25zdCBvcmNhYnVzVG9rZW5TZWNyZXRJZCA9IHNlY3JldHNNYW5hZ2VyLlNlY3JldC5mcm9tU2VjcmV0TmFtZVYyKFxuICAgICAgICAgICAgdGhpcywgJ29yY2FidXNUb2tlblNlY3JldElkJyxcbiAgICAgICAgICAgIHByb3BzLm9yY2FidXNUb2tlblNlY3JldElkID8/IERFRkFVTFRfT1JDQUJVU19UT0tFTl9TRUNSRVRfSURcbiAgICAgICAgKTtcbiAgICAgICAgY29uc3QgaG9zdG5hbWVTc21QYXJhbWV0ZXJOYW1lID0gc3NtLlN0cmluZ1BhcmFtZXRlci5mcm9tU3RyaW5nUGFyYW1ldGVyTmFtZShcbiAgICAgICAgICAgIHRoaXMsICdob3N0bmFtZVNzbVBhcmFtZXRlck5hbWUnLFxuICAgICAgICAgICAgcHJvcHMuaG9zdG5hbWVTc21QYXJhbWV0ZXJOYW1lID8/IERFRkFVTFRfSE9TVE5BTUVfU1NNX1BBUkFNRVRFUixcbiAgICAgICAgKVxuXG4gICAgICAgIC8vIEFkZCBwZXJtaXNzaW9ucyBmb3IgdGhlIHNlY3JldCBhbmQgU1NNIHBhcmFtZXRlclxuICAgICAgICAvLyBUbyB0aGUgY3VycmVudCB2ZXJzaW9uXG4gICAgICAgIG9yY2FidXNUb2tlblNlY3JldElkLmdyYW50UmVhZCh0aGlzLmN1cnJlbnRWZXJzaW9uKTtcbiAgICAgICAgaG9zdG5hbWVTc21QYXJhbWV0ZXJOYW1lLmdyYW50UmVhZCh0aGlzLmN1cnJlbnRWZXJzaW9uKVxuXG4gICAgICAgIC8vIEFkZCBlbnZpcm9ubWVudCB2YXJpYWJsZXNcbiAgICAgICAgdGhpcy5hZGRFbnZpcm9ubWVudChcbiAgICAgICAgICAgICdPUkNBQlVTX1RPS0VOX1NFQ1JFVF9JRCcsIG9yY2FidXNUb2tlblNlY3JldElkLnNlY3JldE5hbWUsXG4gICAgICAgIClcbiAgICAgICAgdGhpcy5hZGRFbnZpcm9ubWVudChcbiAgICAgICAgICAgICdIT1NUTkFNRV9TU01fUEFSQU1FVEVSX05BTUUnLCBob3N0bmFtZVNzbVBhcmFtZXRlck5hbWUucGFyYW1ldGVyTmFtZSxcbiAgICAgICAgKVxuICAgIH1cblxuXG4gICAgcHJpdmF0ZSBzZXRBdGhlbmFSZXNvdXJjZXMoXG4gICAgICAgIHByb3BzOiBNYXJ0RW52aXJvbm1lbnRWYXJpYWJsZXNcbiAgICApIHtcbiAgICAgICAgLy8gUmVzb2x2ZSB0aGUgc3RhZ2UgbmFtZSBieSBwZXJmb3JtaW5nIGEgcmV2ZXJzZSBsb29rdXAgdXNpbmcgY2RrLkF3cy5BQ0NPVU5UX0lEIG9uIGFjY291bnRJZEFsaWFzXG4gICAgICAgIGNvbnN0IHN0YWdlTmFtZSA9IHJlc29sdmVTdGFnZU5hbWUoKVxuXG4gICAgICAgIGNvbnN0IGF0aGVuYVMzQnVja2V0ID0gczMuQnVja2V0LmZyb21CdWNrZXROYW1lKFxuICAgICAgICAgICAgdGhpcywgJ2F0aGVuYVMzQnVja2V0JyxcbiAgICAgICAgICAgIE1BUlRfUzNfQlVDS0VUW3N0YWdlTmFtZV1cbiAgICAgICAgKVxuXG4gICAgICAgIGNvbnN0IGF0aGVuYUZ1bmN0aW9uTmFtZSA9IGxhbWJkYS5GdW5jdGlvbi5mcm9tRnVuY3Rpb25OYW1lKFxuICAgICAgICAgICAgdGhpcywgJ2xhbWJkYUZ1bmN0aW9uTmFtZScsIE1BUlRfTEFNQkRBX0ZVTkNUSU9OX05BTUVcbiAgICAgICAgKVxuXG4gICAgICAgIC8vIEFkZCBlbnYgdmFyc1xuICAgICAgICAvLyBJdGVyYXRlIG92ZXIga3YgcGFpcnMgb2YgTUFSVF9FTlZfVkFSU1xuICAgICAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhNQVJUX0VOVl9WQVJTKSkge1xuICAgICAgICAgICAgLy8gQWZ0ZXJcbiAgICAgICAgICAgIGlmIChwcm9wc1trZXkgYXMga2V5b2YgTWFydEVudmlyb25tZW50VmFyaWFibGVzXSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5hZGRFbnZpcm9ubWVudChrZXksIHByb3BzW2tleSBhcyBrZXlvZiBNYXJ0RW52aXJvbm1lbnRWYXJpYWJsZXNdISk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMuYWRkRW52aXJvbm1lbnQoa2V5LCB2YWx1ZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBQZXJtaXNzaW9uc1xuICAgICAgICB0aGlzLmN1cnJlbnRWZXJzaW9uLmFkZFRvUm9sZVBvbGljeShcbiAgICAgICAgICAgIC8vIEZyb20gaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL2F0aGVuYS9sYXRlc3QvdWcvZXhhbXBsZS1wb2xpY2llcy13b3JrZ3JvdXAuaHRtbFxuICAgICAgICAgICAgbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICAgICAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgICAgICAgICAgICAgLy8gV29ya2dyb3VwIGxpc3RzXG4gICAgICAgICAgICAgICAgICAgICdhdGhlbmE6TGlzdEVuZ2luZVZlcnNpb25zJyxcbiAgICAgICAgICAgICAgICAgICAgJ2F0aGVuYTpMaXN0V29ya0dyb3VwcycsXG4gICAgICAgICAgICAgICAgICAgICdhdGhlbmE6TGlzdERhdGFDYXRhbG9ncycsXG4gICAgICAgICAgICAgICAgICAgICdhdGhlbmE6TGlzdERhdGFiYXNlcycsXG4gICAgICAgICAgICAgICAgICAgICdhdGhlbmE6R2V0RGF0YWJhc2UnLFxuICAgICAgICAgICAgICAgICAgICAnYXRoZW5hOkxpc3RUYWJsZU1ldGFkYXRhJyxcbiAgICAgICAgICAgICAgICAgICAgJ2F0aGVuYTpHZXRUYWJsZU1ldGFkYXRhJyxcbiAgICAgICAgICAgICAgICAgICAgJ2F0aGVuYTpHZXREYXRhQ2F0YWxvZycsXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICByZXNvdXJjZXM6IFtgYXJuOmF3czphdGhlbmE6JHtyZWdpb259OiR7YWNjb3VudElkQWxpYXNbc3RhZ2VOYW1lXX06KmBdLFxuICAgICAgICAgICAgfSlcbiAgICAgICAgKTtcblxuICAgICAgICB0aGlzLmN1cnJlbnRWZXJzaW9uLmFkZFRvUm9sZVBvbGljeShcbiAgICAgICAgICAgIC8vIEZyb20gaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL2F0aGVuYS9sYXRlc3QvdWcvZXhhbXBsZS1wb2xpY2llcy13b3JrZ3JvdXAuaHRtbFxuICAgICAgICAgICAgbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICAgICAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgICAgICAgICAgICAgLy8gV29ya2dyb3VwIGV4ZWN1dGlvbnNcbiAgICAgICAgICAgICAgICAgICAgJ2F0aGVuYTpCYXRjaEdldFF1ZXJ5RXhlY3V0aW9uJyxcbiAgICAgICAgICAgICAgICAgICAgJ2F0aGVuYTpHZXRRdWVyeUV4ZWN1dGlvbicsXG4gICAgICAgICAgICAgICAgICAgICdhdGhlbmE6TGlzdFF1ZXJ5RXhlY3V0aW9ucycsXG4gICAgICAgICAgICAgICAgICAgICdhdGhlbmE6U3RhcnRRdWVyeUV4ZWN1dGlvbicsXG4gICAgICAgICAgICAgICAgICAgICdhdGhlbmE6U3RvcFF1ZXJ5RXhlY3V0aW9uJyxcbiAgICAgICAgICAgICAgICAgICAgJ2F0aGVuYTpHZXRRdWVyeVJlc3VsdHMnLFxuICAgICAgICAgICAgICAgICAgICAnYXRoZW5hOkdldFF1ZXJ5UmVzdWx0c1N0cmVhbScsXG4gICAgICAgICAgICAgICAgICAgICdhdGhlbmE6Q3JlYXRlTmFtZWRRdWVyeScsXG4gICAgICAgICAgICAgICAgICAgICdhdGhlbmE6R2V0TmFtZWRRdWVyeScsXG4gICAgICAgICAgICAgICAgICAgICdhdGhlbmE6QmF0Y2hHZXROYW1lZFF1ZXJ5JyxcbiAgICAgICAgICAgICAgICAgICAgJ2F0aGVuYTpMaXN0TmFtZWRRdWVyaWVzJyxcbiAgICAgICAgICAgICAgICAgICAgJ2F0aGVuYTpEZWxldGVOYW1lZFF1ZXJ5JyxcbiAgICAgICAgICAgICAgICAgICAgJ2F0aGVuYTpDcmVhdGVQcmVwYXJlZFN0YXRlbWVudCcsXG4gICAgICAgICAgICAgICAgICAgICdhdGhlbmE6R2V0UHJlcGFyZWRTdGF0ZW1lbnQnLFxuICAgICAgICAgICAgICAgICAgICAnYXRoZW5hOkxpc3RQcmVwYXJlZFN0YXRlbWVudHMnLFxuICAgICAgICAgICAgICAgICAgICAnYXRoZW5hOlVwZGF0ZVByZXBhcmVkU3RhdGVtZW50JyxcbiAgICAgICAgICAgICAgICAgICAgJ2F0aGVuYTpEZWxldGVQcmVwYXJlZFN0YXRlbWVudCcsXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICByZXNvdXJjZXM6IFtcbiAgICAgICAgICAgICAgICAgICAgYGFybjphd3M6YXRoZW5hOiR7cmVnaW9ufToke2FjY291bnRJZEFsaWFzW3N0YWdlTmFtZV19Ondvcmtncm91cC8ke01BUlRfRU5WX1ZBUlMuYXRoZW5hV29ya2dyb3VwTmFtZX1gLFxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICB9KVxuICAgICAgICApO1xuXG4gICAgICAgIC8vIEFkZCByZWFkIGFjY2VzcyB0byB0aGUgUzMgYnVja2V0XG4gICAgICAgIGF0aGVuYVMzQnVja2V0LmdyYW50UmVhZFdyaXRlKFxuICAgICAgICAgICAgdGhpcy5jdXJyZW50VmVyc2lvbixcbiAgICAgICAgICAgIGAke01BUlRfUzNfUFJFRklYfSpgXG4gICAgICAgIClcblxuICAgICAgICAvLyBBZGQgaW52b2tlIGFjY2VzcyB0byB0aGUgbGFtYmRhIGZ1bmN0aW9uXG4gICAgICAgIGF0aGVuYUZ1bmN0aW9uTmFtZS5ncmFudEludm9rZShcbiAgICAgICAgICAgIHRoaXMuY3VycmVudFZlcnNpb25cbiAgICAgICAgKVxuICAgIH1cbn1cblxuXG5cblxuIl19
|