@mikarinneoracle/oci-cdk-code-only-preview 0.0.1 → 0.0.2
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/package.json +1 -1
- package/lib/.gen/providers/oci/identity-dynamic-group/index.d.ts +0 -166
- package/lib/.gen/providers/oci/identity-dynamic-group/index.js +0 -408
- package/lib/bin/deploy-with-build.js +0 -132
- package/lib/test/java-function/aws-cdk/bin/app.d.ts +0 -2
- package/lib/test/java-function/aws-cdk/bin/app.js +0 -51
- package/lib/test/java-function/aws-cdk/lib/function-stack.d.ts +0 -11
- package/lib/test/java-function/aws-cdk/lib/function-stack.js +0 -159
- package/lib/test/java-function/aws-cdk/lib/test-function-stack.d.ts +0 -5
- package/lib/test/java-function/aws-cdk/lib/test-function-stack.js +0 -94
- package/lib/test/java-function/oci-cdk/.gen/providers/oci/apigateway-deployment/index.d.ts +0 -5356
- package/lib/test/java-function/oci-cdk/.gen/providers/oci/apigateway-deployment/index.js +0 -14972
- package/lib/test/java-function/oci-cdk/.gen/providers/oci/apigateway-gateway/index.d.ts +0 -449
- package/lib/test/java-function/oci-cdk/.gen/providers/oci/apigateway-gateway/index.js +0 -1149
- package/lib/test/java-function/oci-cdk/.gen/providers/oci/artifacts-container-repository/index.d.ts +0 -217
- package/lib/test/java-function/oci-cdk/.gen/providers/oci/artifacts-container-repository/index.js +0 -563
- package/lib/test/java-function/oci-cdk/.gen/providers/oci/core-internet-gateway/index.d.ts +0 -176
- package/lib/test/java-function/oci-cdk/.gen/providers/oci/core-internet-gateway/index.js +0 -431
- package/lib/test/java-function/oci-cdk/.gen/providers/oci/core-route-table/index.d.ts +0 -255
- package/lib/test/java-function/oci-cdk/.gen/providers/oci/core-route-table/index.js +0 -644
- package/lib/test/java-function/oci-cdk/.gen/providers/oci/core-security-list/index.d.ts +0 -752
- package/lib/test/java-function/oci-cdk/.gen/providers/oci/core-security-list/index.js +0 -2091
- package/lib/test/java-function/oci-cdk/.gen/providers/oci/core-service-gateway/index.d.ts +0 -220
- package/lib/test/java-function/oci-cdk/.gen/providers/oci/core-service-gateway/index.js +0 -543
- package/lib/test/java-function/oci-cdk/.gen/providers/oci/core-subnet/index.d.ts +0 -251
- package/lib/test/java-function/oci-cdk/.gen/providers/oci/core-subnet/index.js +0 -612
- package/lib/test/java-function/oci-cdk/.gen/providers/oci/core-vcn/index.d.ts +0 -270
- package/lib/test/java-function/oci-cdk/.gen/providers/oci/core-vcn/index.js +0 -672
- package/lib/test/java-function/oci-cdk/.gen/providers/oci/data-oci-core-services/index.d.ts +0 -150
- package/lib/test/java-function/oci-cdk/.gen/providers/oci/data-oci-core-services/index.js +0 -386
- package/lib/test/java-function/oci-cdk/.gen/providers/oci/functions-application/index.d.ts +0 -330
- package/lib/test/java-function/oci-cdk/.gen/providers/oci/functions-application/index.js +0 -821
- package/lib/test/java-function/oci-cdk/.gen/providers/oci/functions-function/index.d.ts +0 -322
- package/lib/test/java-function/oci-cdk/.gen/providers/oci/functions-function/index.js +0 -820
- package/lib/test/java-function/oci-cdk/.gen/providers/oci/provider/index.d.ts +0 -190
- package/lib/test/java-function/oci-cdk/.gen/providers/oci/provider/index.js +0 -391
- package/lib/test/java-function/oci-cdk/.gen/providers/oci/vault-secret/index.d.ts +0 -439
- package/lib/test/java-function/oci-cdk/.gen/providers/oci/vault-secret/index.js +0 -1146
- package/lib/test/java-function/oci-cdk/bin/app.d.ts +0 -2
- package/lib/test/java-function/oci-cdk/bin/app.js +0 -34
- package/lib/test/java-function/oci-cdk/config/oci-config.d.ts +0 -68
- package/lib/test/java-function/oci-cdk/config/oci-config.js +0 -202
- package/lib/test/java-function/oci-cdk/lib/function-stack.d.ts +0 -31
- package/lib/test/java-function/oci-cdk/lib/function-stack.js +0 -549
- package/lib/test/java-function/oci-cdk/lib/test-function-stack.d.ts +0 -17
- package/lib/test/java-function/oci-cdk/lib/test-function-stack.js +0 -99
|
@@ -1,549 +0,0 @@
|
|
|
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
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.FunctionStack = void 0;
|
|
37
|
-
const cdktf_1 = require("cdktf");
|
|
38
|
-
const provider_1 = require("../.gen/providers/oci/provider");
|
|
39
|
-
const artifacts_container_repository_1 = require("../.gen/providers/oci/artifacts-container-repository");
|
|
40
|
-
const core_vcn_1 = require("../.gen/providers/oci/core-vcn");
|
|
41
|
-
const core_subnet_1 = require("../.gen/providers/oci/core-subnet");
|
|
42
|
-
const core_security_list_1 = require("../.gen/providers/oci/core-security-list");
|
|
43
|
-
const core_service_gateway_1 = require("../.gen/providers/oci/core-service-gateway");
|
|
44
|
-
const data_oci_core_services_1 = require("../.gen/providers/oci/data-oci-core-services");
|
|
45
|
-
const core_route_table_1 = require("../.gen/providers/oci/core-route-table");
|
|
46
|
-
const core_internet_gateway_1 = require("../.gen/providers/oci/core-internet-gateway");
|
|
47
|
-
const apigateway_gateway_1 = require("../.gen/providers/oci/apigateway-gateway");
|
|
48
|
-
const apigateway_deployment_1 = require("../.gen/providers/oci/apigateway-deployment");
|
|
49
|
-
const functions_application_1 = require("../.gen/providers/oci/functions-application");
|
|
50
|
-
const functions_function_1 = require("../.gen/providers/oci/functions-function");
|
|
51
|
-
const vault_secret_1 = require("../.gen/providers/oci/vault-secret");
|
|
52
|
-
const crypto = __importStar(require("crypto"));
|
|
53
|
-
const path = __importStar(require("path"));
|
|
54
|
-
class FunctionStack extends cdktf_1.TerraformStack {
|
|
55
|
-
constructor(scope, id, config) {
|
|
56
|
-
super(scope, id);
|
|
57
|
-
// -------------------------------------------------------------------------
|
|
58
|
-
// Backend & Provider
|
|
59
|
-
// -------------------------------------------------------------------------
|
|
60
|
-
if (config.backend && config.backend.type !== 'local') {
|
|
61
|
-
if (config.backend.type === 'oci') {
|
|
62
|
-
this.addOverride('terraform.backend', {
|
|
63
|
-
oci: {
|
|
64
|
-
bucket: config.backend.bucket,
|
|
65
|
-
namespace: config.namespace,
|
|
66
|
-
key: config.backend.key || `${id}/terraform.tfstate`,
|
|
67
|
-
region: config.region,
|
|
68
|
-
},
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
else if (config.backend.type === 'http') {
|
|
72
|
-
const httpBackend = {
|
|
73
|
-
address: config.backend.address,
|
|
74
|
-
update_method: config.backend.updateMethod || 'PUT',
|
|
75
|
-
};
|
|
76
|
-
if (config.backend.lockAddress)
|
|
77
|
-
httpBackend.lock_address = config.backend.lockAddress;
|
|
78
|
-
if (config.backend.unlockAddress)
|
|
79
|
-
httpBackend.unlock_address = config.backend.unlockAddress;
|
|
80
|
-
this.addOverride('terraform.backend', { http: httpBackend });
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
new provider_1.OciProvider(this, 'oci', {
|
|
84
|
-
region: config.region,
|
|
85
|
-
tenancyOcid: config.tenancyId,
|
|
86
|
-
});
|
|
87
|
-
// Add null provider using addOverride (avoids needing to generate types)
|
|
88
|
-
this.addOverride('terraform.required_providers.null', {
|
|
89
|
-
source: 'hashicorp/null',
|
|
90
|
-
version: '~> 3.0',
|
|
91
|
-
});
|
|
92
|
-
const ocirCompartmentId = config.ocirCompartmentId || config.compartmentId;
|
|
93
|
-
const ocirRepoName = config.ocirRepositoryName || config.functionName;
|
|
94
|
-
if (ocirCompartmentId.includes('root')) {
|
|
95
|
-
throw new Error('OCIR repository cannot be created in root compartment. ' +
|
|
96
|
-
'Please set OCI_OCIR_COMPARTMENT_ID to your home compartment OCID.');
|
|
97
|
-
}
|
|
98
|
-
// -------------------------------------------------------------------------
|
|
99
|
-
// OCIR Container Repository
|
|
100
|
-
// -------------------------------------------------------------------------
|
|
101
|
-
const ocirRepository = new artifacts_container_repository_1.ArtifactsContainerRepository(this, 'OcirRepository', {
|
|
102
|
-
compartmentId: ocirCompartmentId,
|
|
103
|
-
displayName: ocirRepoName,
|
|
104
|
-
isPublic: false,
|
|
105
|
-
isImmutable: false,
|
|
106
|
-
});
|
|
107
|
-
// -------------------------------------------------------------------------
|
|
108
|
-
// Build and Push Docker Image to OCIR (after repository is created)
|
|
109
|
-
// -------------------------------------------------------------------------
|
|
110
|
-
const imageUrl = `${config.region}.ocir.io/${config.namespace}/${ocirRepoName}:latest`;
|
|
111
|
-
// Get OCIR login username from env or try to get from OCI CLI
|
|
112
|
-
// Format: <tenancy-namespace>/<username> (e.g., frsxwtjslf35/oracleidentitycloudservice/user@example.com)
|
|
113
|
-
// Default will be constructed in the script if not provided
|
|
114
|
-
const ocirUsername = process.env.OCI_OCIR_USERNAME || 'AUTO_DETECT';
|
|
115
|
-
// function-code is at java-function/function-code (sibling of oci-cdk)
|
|
116
|
-
// Resolve path relative to this file's location
|
|
117
|
-
// Compiled JS is at lib/lib/function-stack.js, so __dirname is lib/lib/
|
|
118
|
-
// From lib/lib/: ../ goes to lib/, ../ goes to oci-cdk/, ../ goes to java-function/, then function-code/
|
|
119
|
-
const functionCodePath = path.resolve(__dirname, '..', '..', '..', 'function-code');
|
|
120
|
-
// Create null_resource using addOverride (since we can't generate types due to network issues)
|
|
121
|
-
// This creates a Terraform null_resource that builds and pushes the Docker image
|
|
122
|
-
const buildAndPushImageId = 'BuildAndPushImage';
|
|
123
|
-
// Use the Terraform resource reference directly (not interpolated string)
|
|
124
|
-
// depends_on expects resource references, not attribute references
|
|
125
|
-
this.addOverride(`resource.null_resource.${buildAndPushImageId}.depends_on`, [
|
|
126
|
-
'oci_artifacts_container_repository.OcirRepository',
|
|
127
|
-
]);
|
|
128
|
-
this.addOverride(`resource.null_resource.${buildAndPushImageId}.triggers`, {
|
|
129
|
-
repo_name: ocirRepoName,
|
|
130
|
-
image_url: imageUrl,
|
|
131
|
-
namespace: config.namespace,
|
|
132
|
-
region: config.region,
|
|
133
|
-
});
|
|
134
|
-
// Generate auth token and login script
|
|
135
|
-
// If OCI_AUTH_TOKEN is set, use it; otherwise generate one via OCI CLI
|
|
136
|
-
const regionPlaceholder = config.region;
|
|
137
|
-
const namespacePlaceholder = config.namespace;
|
|
138
|
-
const ocirUsernameValue = ocirUsername; // Capture value for template string
|
|
139
|
-
// Use string concatenation to avoid TypeScript parsing issues with ${} in shell scripts
|
|
140
|
-
const dollarSign = '$';
|
|
141
|
-
const dollarDollar = '$$';
|
|
142
|
-
// Use backticks for command substitution to avoid complex $() escaping
|
|
143
|
-
// In TypeScript template strings, backticks need to be escaped as \`
|
|
144
|
-
const cmdSubStart = '\`';
|
|
145
|
-
const cmdSubEnd = '\`';
|
|
146
|
-
const loginScript = process.env.OCI_AUTH_TOKEN
|
|
147
|
-
? `# Using provided OCI_AUTH_TOKEN
|
|
148
|
-
export OCIR_AUTH_TOKEN="${process.env.OCI_AUTH_TOKEN}"
|
|
149
|
-
if [ -z "${dollarDollar}OCIR_AUTH_TOKEN" ]; then
|
|
150
|
-
echo "Error: OCI_AUTH_TOKEN is empty. Please set a valid token."
|
|
151
|
-
exit 1
|
|
152
|
-
fi
|
|
153
|
-
# Use provided username or auto-detect
|
|
154
|
-
OCIR_USERNAME="${ocirUsernameValue}"
|
|
155
|
-
if [ "${dollarDollar}OCIR_USERNAME" == "AUTO_DETECT" ]; then
|
|
156
|
-
USER_OCID=${cmdSubStart}oci iam user list --query "data[0].id" --raw-output 2>/dev/null${cmdSubEnd}
|
|
157
|
-
if [ -n "${dollarDollar}USER_OCID" ] && [ "${dollarDollar}USER_OCID" != "null" ]; then
|
|
158
|
-
USER_NAME=${cmdSubStart}oci iam user get --user-id "${dollarDollar}USER_OCID" --query 'data.name' --raw-output 2>/dev/null || echo ""${cmdSubEnd}
|
|
159
|
-
if [ -n "${dollarDollar}USER_NAME" ]; then
|
|
160
|
-
OCIR_USERNAME="${namespacePlaceholder}/${dollarDollar}USER_NAME"
|
|
161
|
-
else
|
|
162
|
-
echo "Warning: Could not auto-detect username. Using default format."
|
|
163
|
-
OCIR_USERNAME="${namespacePlaceholder}/user"
|
|
164
|
-
fi
|
|
165
|
-
else
|
|
166
|
-
OCIR_USERNAME="${namespacePlaceholder}/user"
|
|
167
|
-
fi
|
|
168
|
-
fi
|
|
169
|
-
echo "${dollarDollar}OCIR_AUTH_TOKEN" | docker login ${regionPlaceholder}.ocir.io -u "${dollarDollar}OCIR_USERNAME" --password-stdin >/dev/null 2>&1 || {
|
|
170
|
-
echo "Error: Docker login failed. Check your OCI_AUTH_TOKEN and username format." >&2
|
|
171
|
-
echo "Username used: ${dollarDollar}OCIR_USERNAME" >&2
|
|
172
|
-
echo "Username format should be: <tenancy-namespace>/<username>" >&2
|
|
173
|
-
echo "Set manually: export OCI_OCIR_USERNAME=\\"${namespacePlaceholder}/your-actual-username\\"" >&2
|
|
174
|
-
exit 1
|
|
175
|
-
}`
|
|
176
|
-
: `# Generate OCIR auth token via OCI CLI and login to OCIR
|
|
177
|
-
# Try raw-request method first (uses default OCI CLI auth from config)
|
|
178
|
-
OCIR_HOST="${regionPlaceholder}.ocir.io"
|
|
179
|
-
if oci raw-request --region ${regionPlaceholder} --http-method GET --target-uri "https://${regionPlaceholder}.ocir.io/20180419/docker/token" >/dev/null 2>&1; then
|
|
180
|
-
if command -v jq >/dev/null 2>&1; then
|
|
181
|
-
oci raw-request --region ${regionPlaceholder} --http-method GET --target-uri "https://${regionPlaceholder}.ocir.io/20180419/docker/token" 2>/dev/null | jq -r .data.token 2>/dev/null | docker login -u BEARER_TOKEN --password-stdin ${regionPlaceholder}.ocir.io >/dev/null 2>&1 || {
|
|
182
|
-
echo "Error: Docker login with raw-request failed." >&2
|
|
183
|
-
exit 1
|
|
184
|
-
}
|
|
185
|
-
else
|
|
186
|
-
oci raw-request --region ${regionPlaceholder} --http-method GET --target-uri "https://${regionPlaceholder}.ocir.io/20180419/docker/token" 2>/dev/null | grep -o '"token":"[^"]*"' | cut -d'"' -f4 | docker login -u BEARER_TOKEN --password-stdin ${regionPlaceholder}.ocir.io >/dev/null 2>&1 || {
|
|
187
|
-
echo "Error: Docker login with raw-request failed." >&2
|
|
188
|
-
exit 1
|
|
189
|
-
}
|
|
190
|
-
fi
|
|
191
|
-
else
|
|
192
|
-
# Fallback to auth token method (for localhost)
|
|
193
|
-
# Get user OCID from CLI config (same approach as reference script)
|
|
194
|
-
OCI_CONFIG="${dollarDollar}{OCI_CLI_CONFIG_FILE:-${dollarDollar}HOME/.oci/config}"
|
|
195
|
-
OCI_PROFILE="${dollarDollar}{OCI_CLI_PROFILE:-DEFAULT}"
|
|
196
|
-
USER_OCID=""
|
|
197
|
-
if [ -f "${dollarDollar}OCI_CONFIG" ]; then
|
|
198
|
-
USER_OCID=${cmdSubStart}awk -v prof="[${dollarDollar}OCI_PROFILE]" '${dollarDollar}0 == prof { in_profile=1; next } /^\\[/ { in_profile=0 } in_profile && ${dollarDollar}0 ~ /^[[:space:]]*user[[:space:]]*=/ { split(${dollarDollar}0, a, "="); gsub(/^[[:space:]]+|[[:space:]]+${dollarDollar}/, "", a[2]); print a[2]; exit }' "${dollarDollar}OCI_CONFIG" 2>/dev/null || echo ""${cmdSubEnd}
|
|
199
|
-
fi
|
|
200
|
-
|
|
201
|
-
# Fallback to user list if not in config
|
|
202
|
-
if [ -z "${dollarDollar}USER_OCID" ] || [ "${dollarDollar}USER_OCID" != ocid1.* ]; then
|
|
203
|
-
USER_OCID=${cmdSubStart}oci iam user list --query "data[0].id" --raw-output 2>/dev/null || echo ""${cmdSubEnd}
|
|
204
|
-
fi
|
|
205
|
-
|
|
206
|
-
if [ -z "${dollarDollar}USER_OCID" ] || [ "${dollarDollar}USER_OCID" == "null" ] || [ "${dollarDollar}USER_OCID" != ocid1.* ]; then
|
|
207
|
-
echo "Error: Could not get user OCID. Set OCI_AUTH_TOKEN manually or ensure OCI CLI is configured." >&2
|
|
208
|
-
echo "Run: oci iam user list" >&2
|
|
209
|
-
echo "Or check your OCI config: ${dollarDollar}OCI_CONFIG" >&2
|
|
210
|
-
exit 1
|
|
211
|
-
fi
|
|
212
|
-
|
|
213
|
-
# Verify user exists before trying to create token
|
|
214
|
-
if ! oci iam user get --user-id "${dollarDollar}USER_OCID" >/dev/null 2>&1; then
|
|
215
|
-
echo "Error: User OCID '${dollarDollar}USER_OCID' not found or not accessible." >&2
|
|
216
|
-
echo "Please verify your OCI CLI configuration or set OCI_AUTH_TOKEN manually." >&2
|
|
217
|
-
exit 1
|
|
218
|
-
fi
|
|
219
|
-
|
|
220
|
-
# Get username for OCIR login
|
|
221
|
-
OCIR_USERNAME_VAR="${ocirUsernameValue}"
|
|
222
|
-
if [ "${dollarDollar}OCIR_USERNAME_VAR" == "AUTO_DETECT" ]; then
|
|
223
|
-
USER_NAME=${cmdSubStart}oci iam user get --user-id "${dollarDollar}USER_OCID" --query 'data.name' --raw-output 2>/dev/null || echo ""${cmdSubEnd}
|
|
224
|
-
if [ -z "${dollarDollar}USER_NAME" ] || [ "${dollarDollar}USER_NAME" == "null" ]; then
|
|
225
|
-
echo "Error: Could not get username for user ${dollarDollar}USER_OCID." >&2
|
|
226
|
-
echo "Please set OCI_OCIR_USERNAME manually." >&2
|
|
227
|
-
echo "Format: export OCI_OCIR_USERNAME=\\"${namespacePlaceholder}/your-username\\"" >&2
|
|
228
|
-
exit 1
|
|
229
|
-
fi
|
|
230
|
-
# Extract username part if it contains domain (e.g., "oracleidentitycloudservice/user@example.com" -> "user@example.com")
|
|
231
|
-
USER_NAME="${dollarDollar}{USER_NAME##*/}"
|
|
232
|
-
OCIR_USERNAME="${namespacePlaceholder}/oracleidentitycloudservice/${dollarDollar}USER_NAME"
|
|
233
|
-
else
|
|
234
|
-
OCIR_USERNAME="${dollarDollar}OCIR_USERNAME_VAR"
|
|
235
|
-
fi
|
|
236
|
-
|
|
237
|
-
DESC="OCIR Docker login token - ${cmdSubStart}date +%Y%m%d-%H%M%S${cmdSubEnd}"
|
|
238
|
-
TOKEN=${cmdSubStart}oci iam auth-token create --user-id "${dollarDollar}USER_OCID" --description "${dollarDollar}DESC" --query 'data.token' --raw-output 2>/dev/null || true${cmdSubEnd}
|
|
239
|
-
|
|
240
|
-
if [ -z "${dollarDollar}TOKEN" ] || [ "${dollarDollar}TOKEN" == "null" ]; then
|
|
241
|
-
echo "Error: Failed to create auth token via OCI CLI." >&2
|
|
242
|
-
echo "This might be due to:" >&2
|
|
243
|
-
echo " - Missing IAM permissions (need: manage auth-tokens)" >&2
|
|
244
|
-
echo " - User OCID '${dollarDollar}USER_OCID' is incorrect or user doesn't exist" >&2
|
|
245
|
-
echo " - OCI CLI not properly configured" >&2
|
|
246
|
-
echo "" >&2
|
|
247
|
-
echo "Solution: Set OCI_AUTH_TOKEN manually:" >&2
|
|
248
|
-
echo " 1. Get token from: https://cloud.oracle.com/identity/tokens" >&2
|
|
249
|
-
echo " 2. Export: export OCI_AUTH_TOKEN=\\"your-token\\"" >&2
|
|
250
|
-
echo " 3. Also set: export OCI_OCIR_USERNAME=\\"${dollarDollar}OCIR_USERNAME\\"" >&2
|
|
251
|
-
echo " 4. Then re-run: npm run deploy" >&2
|
|
252
|
-
exit 1
|
|
253
|
-
fi
|
|
254
|
-
|
|
255
|
-
export OCIR_AUTH_TOKEN="${dollarDollar}TOKEN"
|
|
256
|
-
echo "${dollarDollar}OCIR_AUTH_TOKEN" | docker login ${regionPlaceholder}.ocir.io -u "${dollarDollar}OCIR_USERNAME" --password-stdin >/dev/null 2>&1 || {
|
|
257
|
-
echo "Error: Docker login failed with generated token." >&2
|
|
258
|
-
echo "Username used: ${dollarDollar}OCIR_USERNAME" >&2
|
|
259
|
-
echo "Check that the username format is correct: <tenancy-namespace>/<domain>/<username>" >&2
|
|
260
|
-
echo "If incorrect, set: export OCI_OCIR_USERNAME=\\"${namespacePlaceholder}/oracleidentitycloudservice/your-username\\"" >&2
|
|
261
|
-
exit 1
|
|
262
|
-
}
|
|
263
|
-
fi`;
|
|
264
|
-
this.addOverride(`resource.null_resource.${buildAndPushImageId}.provisioner`, [
|
|
265
|
-
{
|
|
266
|
-
'local-exec': {
|
|
267
|
-
command: `cd ${functionCodePath} && docker build --platform linux/amd64 -t ${imageUrl} .`,
|
|
268
|
-
},
|
|
269
|
-
},
|
|
270
|
-
{
|
|
271
|
-
'local-exec': {
|
|
272
|
-
command: loginScript,
|
|
273
|
-
on_failure: 'continue',
|
|
274
|
-
},
|
|
275
|
-
},
|
|
276
|
-
{
|
|
277
|
-
'local-exec': {
|
|
278
|
-
command: `docker push ${imageUrl}`,
|
|
279
|
-
},
|
|
280
|
-
},
|
|
281
|
-
]);
|
|
282
|
-
// Create a reference to the null_resource for dependency tracking
|
|
283
|
-
// We'll use a TerraformData source as a proxy to reference it
|
|
284
|
-
const buildAndPushImageRef = `\${null_resource.${buildAndPushImageId}.id}`;
|
|
285
|
-
// -------------------------------------------------------------------------
|
|
286
|
-
// VCN and Subnets
|
|
287
|
-
// -------------------------------------------------------------------------
|
|
288
|
-
const vcn = new core_vcn_1.CoreVcn(this, 'Vcn', {
|
|
289
|
-
compartmentId: config.compartmentId,
|
|
290
|
-
displayName: `${id}-vcn`,
|
|
291
|
-
cidrBlocks: ['10.0.0.0/16'],
|
|
292
|
-
dnsLabel: 'appfn',
|
|
293
|
-
});
|
|
294
|
-
const publicSubnet = new core_subnet_1.CoreSubnet(this, 'PublicSubnet', {
|
|
295
|
-
compartmentId: config.compartmentId,
|
|
296
|
-
vcnId: vcn.id,
|
|
297
|
-
displayName: `${id}-public`,
|
|
298
|
-
cidrBlock: '10.0.1.0/24',
|
|
299
|
-
dnsLabel: 'public',
|
|
300
|
-
prohibitPublicIpOnVnic: false,
|
|
301
|
-
});
|
|
302
|
-
const privateSubnet = new core_subnet_1.CoreSubnet(this, 'PrivateSubnet', {
|
|
303
|
-
compartmentId: config.compartmentId,
|
|
304
|
-
vcnId: vcn.id,
|
|
305
|
-
displayName: `${id}-private`,
|
|
306
|
-
cidrBlock: '10.0.2.0/24',
|
|
307
|
-
dnsLabel: 'private',
|
|
308
|
-
prohibitPublicIpOnVnic: true,
|
|
309
|
-
});
|
|
310
|
-
// -------------------------------------------------------------------------
|
|
311
|
-
// Security List for Public Subnet (API Gateway)
|
|
312
|
-
// -------------------------------------------------------------------------
|
|
313
|
-
const publicSecurityList = new core_security_list_1.CoreSecurityList(this, 'PublicSecurityList', {
|
|
314
|
-
compartmentId: config.compartmentId,
|
|
315
|
-
vcnId: vcn.id,
|
|
316
|
-
displayName: `${id}-public-sl`,
|
|
317
|
-
ingressSecurityRules: [
|
|
318
|
-
{
|
|
319
|
-
protocol: '6', // TCP
|
|
320
|
-
source: '0.0.0.0/0',
|
|
321
|
-
description: 'Allow HTTP (80) from internet',
|
|
322
|
-
tcpOptions: {
|
|
323
|
-
min: 80,
|
|
324
|
-
max: 80,
|
|
325
|
-
},
|
|
326
|
-
},
|
|
327
|
-
{
|
|
328
|
-
protocol: '6', // TCP
|
|
329
|
-
source: '0.0.0.0/0',
|
|
330
|
-
description: 'Allow HTTPS (443) from internet',
|
|
331
|
-
tcpOptions: {
|
|
332
|
-
min: 443,
|
|
333
|
-
max: 443,
|
|
334
|
-
},
|
|
335
|
-
},
|
|
336
|
-
],
|
|
337
|
-
egressSecurityRules: [
|
|
338
|
-
{
|
|
339
|
-
protocol: 'all',
|
|
340
|
-
destination: '0.0.0.0/0',
|
|
341
|
-
description: 'Allow all outbound traffic',
|
|
342
|
-
},
|
|
343
|
-
],
|
|
344
|
-
});
|
|
345
|
-
// Associate security list with public subnet
|
|
346
|
-
publicSubnet.addOverride('security_list_ids', [publicSecurityList.id]);
|
|
347
|
-
// -------------------------------------------------------------------------
|
|
348
|
-
// Security List for Private Subnet (Function + PG in same subnet)
|
|
349
|
-
// -------------------------------------------------------------------------
|
|
350
|
-
const privateSubnetCidr = '10.0.2.0/24';
|
|
351
|
-
const privateSecurityList = new core_security_list_1.CoreSecurityList(this, 'PrivateSecurityList', {
|
|
352
|
-
compartmentId: config.compartmentId,
|
|
353
|
-
vcnId: vcn.id,
|
|
354
|
-
displayName: `${id}-private-sl`,
|
|
355
|
-
ingressSecurityRules: [
|
|
356
|
-
{
|
|
357
|
-
protocol: '6', // TCP
|
|
358
|
-
source: privateSubnetCidr,
|
|
359
|
-
description: 'TCP traffic for ports: 5432 (PostgreSQL from private subnet)',
|
|
360
|
-
tcpOptions: {
|
|
361
|
-
min: 5432,
|
|
362
|
-
max: 5432,
|
|
363
|
-
},
|
|
364
|
-
},
|
|
365
|
-
],
|
|
366
|
-
egressSecurityRules: [
|
|
367
|
-
{
|
|
368
|
-
protocol: 'all',
|
|
369
|
-
destination: '0.0.0.0/0',
|
|
370
|
-
description: 'Allow all outbound traffic',
|
|
371
|
-
},
|
|
372
|
-
],
|
|
373
|
-
});
|
|
374
|
-
// Associate security list with private subnet
|
|
375
|
-
privateSubnet.addOverride('security_list_ids', [privateSecurityList.id]);
|
|
376
|
-
// -------------------------------------------------------------------------
|
|
377
|
-
// Service Gateway (for OCIR access from private subnet)
|
|
378
|
-
// -------------------------------------------------------------------------
|
|
379
|
-
// Get Object Storage service ID (OCIR uses Object Storage)
|
|
380
|
-
// Get all services - the first service is typically "All <region> Services in Oracle Services Network"
|
|
381
|
-
// This service includes Object Storage and other OCI services
|
|
382
|
-
const allServices = new data_oci_core_services_1.DataOciCoreServices(this, 'AllServices', {});
|
|
383
|
-
const serviceGateway = new core_service_gateway_1.CoreServiceGateway(this, 'ServiceGateway', {
|
|
384
|
-
compartmentId: config.compartmentId,
|
|
385
|
-
vcnId: vcn.id,
|
|
386
|
-
displayName: `${id}-service-gateway`,
|
|
387
|
-
services: [
|
|
388
|
-
{
|
|
389
|
-
serviceId: allServices.services.get(0).id,
|
|
390
|
-
},
|
|
391
|
-
],
|
|
392
|
-
});
|
|
393
|
-
// Route table for private subnet to route Object Storage traffic via Service Gateway
|
|
394
|
-
const privateRouteTable = new core_route_table_1.CoreRouteTable(this, 'PrivateRouteTable', {
|
|
395
|
-
compartmentId: config.compartmentId,
|
|
396
|
-
vcnId: vcn.id,
|
|
397
|
-
displayName: `${id}-private-rt`,
|
|
398
|
-
routeRules: [
|
|
399
|
-
{
|
|
400
|
-
networkEntityId: serviceGateway.id,
|
|
401
|
-
destination: allServices.services.get(0).cidrBlock,
|
|
402
|
-
destinationType: 'SERVICE_CIDR_BLOCK',
|
|
403
|
-
description: 'Route Object Storage/OCIR traffic via Service Gateway',
|
|
404
|
-
},
|
|
405
|
-
],
|
|
406
|
-
});
|
|
407
|
-
// Associate route table with private subnet
|
|
408
|
-
privateSubnet.addOverride('route_table_id', privateRouteTable.id);
|
|
409
|
-
// -------------------------------------------------------------------------
|
|
410
|
-
// Internet Gateway (for public subnet internet access)
|
|
411
|
-
// -------------------------------------------------------------------------
|
|
412
|
-
const internetGateway = new core_internet_gateway_1.CoreInternetGateway(this, 'InternetGateway', {
|
|
413
|
-
compartmentId: config.compartmentId,
|
|
414
|
-
vcnId: vcn.id,
|
|
415
|
-
displayName: `${id}-igw`,
|
|
416
|
-
enabled: true,
|
|
417
|
-
});
|
|
418
|
-
// Route table for public subnet to route internet traffic via Internet Gateway
|
|
419
|
-
const publicRouteTable = new core_route_table_1.CoreRouteTable(this, 'PublicRouteTable', {
|
|
420
|
-
compartmentId: config.compartmentId,
|
|
421
|
-
vcnId: vcn.id,
|
|
422
|
-
displayName: `${id}-public-rt`,
|
|
423
|
-
routeRules: [
|
|
424
|
-
{
|
|
425
|
-
networkEntityId: internetGateway.id,
|
|
426
|
-
destination: '0.0.0.0/0',
|
|
427
|
-
destinationType: 'CIDR_BLOCK',
|
|
428
|
-
description: 'Route all internet traffic via Internet Gateway',
|
|
429
|
-
},
|
|
430
|
-
],
|
|
431
|
-
});
|
|
432
|
-
// Associate route table with public subnet
|
|
433
|
-
publicSubnet.addOverride('route_table_id', publicRouteTable.id);
|
|
434
|
-
// -------------------------------------------------------------------------
|
|
435
|
-
// PG connection: either pass PG_URL as function config, or create Vault secret and pass PG_SECRET_OCID
|
|
436
|
-
// -------------------------------------------------------------------------
|
|
437
|
-
const functionConfig = {};
|
|
438
|
-
if (config.pgUrl && config.pgUrl.trim()) {
|
|
439
|
-
if (config.vaultOcid?.trim()) {
|
|
440
|
-
// Vault path: require keyOcid and create pg-url secret
|
|
441
|
-
if (!config.keyOcid?.trim()) {
|
|
442
|
-
throw new Error('When OCI_VAULT_OCID is set, OCI_KEY_OCID is required to create the pg-url secret. ' +
|
|
443
|
-
'Set OCI_KEY_OCID to your Vault encryption Key OCID.');
|
|
444
|
-
}
|
|
445
|
-
// Append random suffix to avoid "name already exists" when a secret with the same base name exists in the Vault.
|
|
446
|
-
// Set PG_SECRET_SUFFIX env var to pin the name across synths (e.g. PG_SECRET_SUFFIX=abc12345).
|
|
447
|
-
const pgUrlSecretSuffix = process.env.PG_SECRET_SUFFIX || crypto.randomBytes(4).toString('hex');
|
|
448
|
-
const pgUrlSecretName = `${id}-pg-url-${pgUrlSecretSuffix}`;
|
|
449
|
-
const pgUrlSecret = new vault_secret_1.VaultSecret(this, 'PgUrlSecret', {
|
|
450
|
-
compartmentId: config.compartmentId,
|
|
451
|
-
vaultId: config.vaultOcid,
|
|
452
|
-
keyId: config.keyOcid,
|
|
453
|
-
secretName: pgUrlSecretName,
|
|
454
|
-
description: 'PostgreSQL connection URL for function (from PG_URL)',
|
|
455
|
-
secretContent: {
|
|
456
|
-
contentType: 'BASE64',
|
|
457
|
-
content: Buffer.from(config.pgUrl.trim(), 'utf-8').toString('base64'),
|
|
458
|
-
},
|
|
459
|
-
});
|
|
460
|
-
functionConfig.PG_SECRET_OCID = pgUrlSecret.id;
|
|
461
|
-
}
|
|
462
|
-
else {
|
|
463
|
-
// No Vault: pass PG_URL directly as function config (clear-text)
|
|
464
|
-
console.warn('[OCI Function] WARNING: PG_URL is being passed to the function as plain config (clear-text). ' +
|
|
465
|
-
'Credentials are visible in function configuration. For production, store the connection string in OCI Vault and set ' +
|
|
466
|
-
'OCI_VAULT_OCID and OCI_KEY_OCID so the stack creates a Vault secret; the function will then receive only PG_SECRET_OCID.');
|
|
467
|
-
functionConfig.PG_URL = config.pgUrl.trim();
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
else if (config.pgSecretOcid?.trim()) {
|
|
471
|
-
functionConfig.PG_SECRET_OCID = config.pgSecretOcid.trim();
|
|
472
|
-
}
|
|
473
|
-
// -------------------------------------------------------------------------
|
|
474
|
-
// API Gateway (public subnet)
|
|
475
|
-
// -------------------------------------------------------------------------
|
|
476
|
-
const apiGateway = new apigateway_gateway_1.ApigatewayGateway(this, 'ApiGateway', {
|
|
477
|
-
compartmentId: config.compartmentId,
|
|
478
|
-
subnetId: publicSubnet.id,
|
|
479
|
-
endpointType: 'PUBLIC',
|
|
480
|
-
displayName: `${id}-api-gateway`,
|
|
481
|
-
});
|
|
482
|
-
// -------------------------------------------------------------------------
|
|
483
|
-
// Functions Application (private subnet) and Function
|
|
484
|
-
// -------------------------------------------------------------------------
|
|
485
|
-
const functionApp = new functions_application_1.FunctionsApplication(this, 'FunctionApp', {
|
|
486
|
-
compartmentId: config.compartmentId,
|
|
487
|
-
displayName: config.functionAppName,
|
|
488
|
-
subnetIds: [privateSubnet.id],
|
|
489
|
-
});
|
|
490
|
-
// Function depends on image being pushed to OCIR
|
|
491
|
-
const ociFunction = new functions_function_1.FunctionsFunction(this, 'Function', {
|
|
492
|
-
applicationId: functionApp.id,
|
|
493
|
-
displayName: config.functionName,
|
|
494
|
-
image: imageUrl,
|
|
495
|
-
memoryInMbs: '256',
|
|
496
|
-
timeoutInSeconds: 30,
|
|
497
|
-
config: Object.keys(functionConfig).length > 0 ? functionConfig : undefined,
|
|
498
|
-
});
|
|
499
|
-
// Add dependency on null_resource using addOverride
|
|
500
|
-
// This ensures the image is built and pushed before the Function is created
|
|
501
|
-
ociFunction.addOverride('depends_on', [`null_resource.${buildAndPushImageId}`]);
|
|
502
|
-
// -------------------------------------------------------------------------
|
|
503
|
-
// API Gateway Deployment – route to function (only after function exists)
|
|
504
|
-
// -------------------------------------------------------------------------
|
|
505
|
-
const pathPrefix = config.apiGwPathPrefix ?? '/';
|
|
506
|
-
const routePath = config.apiGwRoutePath ?? '/{path*}';
|
|
507
|
-
const methods = config.apiGwMethods?.length ? config.apiGwMethods : ['GET', 'POST', 'OPTIONS'];
|
|
508
|
-
const apiDeployment = new apigateway_deployment_1.ApigatewayDeployment(this, 'ApiDeployment', {
|
|
509
|
-
compartmentId: config.compartmentId,
|
|
510
|
-
gatewayId: apiGateway.id,
|
|
511
|
-
pathPrefix,
|
|
512
|
-
displayName: `${id}-deployment`,
|
|
513
|
-
specification: {
|
|
514
|
-
routes: [
|
|
515
|
-
{
|
|
516
|
-
path: routePath,
|
|
517
|
-
methods,
|
|
518
|
-
backend: {
|
|
519
|
-
type: 'ORACLE_FUNCTIONS_BACKEND',
|
|
520
|
-
functionId: ociFunction.id,
|
|
521
|
-
},
|
|
522
|
-
},
|
|
523
|
-
],
|
|
524
|
-
},
|
|
525
|
-
});
|
|
526
|
-
apiDeployment.node.addDependency(ociFunction);
|
|
527
|
-
// -------------------------------------------------------------------------
|
|
528
|
-
// Outputs
|
|
529
|
-
// -------------------------------------------------------------------------
|
|
530
|
-
new cdktf_1.TerraformOutput(this, 'ocir_repository_name', {
|
|
531
|
-
value: ocirRepository.displayName,
|
|
532
|
-
description: 'OCIR repository display name',
|
|
533
|
-
});
|
|
534
|
-
new cdktf_1.TerraformOutput(this, 'api_gateway_host', {
|
|
535
|
-
value: apiGateway.hostname,
|
|
536
|
-
description: 'API Gateway hostname for invoking the function',
|
|
537
|
-
});
|
|
538
|
-
new cdktf_1.TerraformOutput(this, 'function_invoke_url', {
|
|
539
|
-
value: `https://${apiGateway.hostname}`,
|
|
540
|
-
description: 'Base URL to invoke the function (use ?action=hello|echo|info)',
|
|
541
|
-
});
|
|
542
|
-
new cdktf_1.TerraformOutput(this, 'function_id', {
|
|
543
|
-
value: ociFunction.id,
|
|
544
|
-
description: 'OCI Function OCID (for deploy-function.sh or oci fn function update)',
|
|
545
|
-
});
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
exports.FunctionStack = FunctionStack;
|
|
549
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnVuY3Rpb24tc3RhY2suanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi90ZXN0L2phdmEtZnVuY3Rpb24vb2NpLWNkay9saWIvZnVuY3Rpb24tc3RhY2sudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQ0EsaUNBQXdEO0FBQ3hELDZEQUE2RDtBQUM3RCx5R0FBb0c7QUFDcEcsNkRBQXlEO0FBQ3pELG1FQUErRDtBQUMvRCxpRkFBNEU7QUFDNUUscUZBQWdGO0FBQ2hGLHlGQUFtRjtBQUNuRiw2RUFBd0U7QUFDeEUsdUZBQWtGO0FBQ2xGLGlGQUE2RTtBQUM3RSx1RkFBbUY7QUFDbkYsdUZBQW1GO0FBQ25GLGlGQUE2RTtBQUM3RSxxRUFBaUU7QUFFakUsK0NBQWlDO0FBQ2pDLDJDQUE2QjtBQTRCN0IsTUFBYSxhQUFjLFNBQVEsc0JBQWM7SUFDL0MsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxNQUFzQjtRQUM5RCxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBRWpCLDRFQUE0RTtRQUM1RSxxQkFBcUI7UUFDckIsNEVBQTRFO1FBQzVFLElBQUksTUFBTSxDQUFDLE9BQU8sSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLElBQUksS0FBSyxPQUFPLEVBQUUsQ0FBQztZQUN0RCxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsSUFBSSxLQUFLLEtBQUssRUFBRSxDQUFDO2dCQUNsQyxJQUFJLENBQUMsV0FBVyxDQUFDLG1CQUFtQixFQUFFO29CQUNwQyxHQUFHLEVBQUU7d0JBQ0gsTUFBTSxFQUFFLE1BQU0sQ0FBQyxPQUFPLENBQUMsTUFBTTt3QkFDN0IsU0FBUyxFQUFFLE1BQU0sQ0FBQyxTQUFTO3dCQUMzQixHQUFHLEVBQUUsTUFBTSxDQUFDLE9BQU8sQ0FBQyxHQUFHLElBQUksR0FBRyxFQUFFLG9CQUFvQjt3QkFDcEQsTUFBTSxFQUFF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RUFBRSxXQUFXLENBQUMsRUFBRTt5QkFDM0I7cUJBQ0Y7aUJBQ0Y7YUFDRjtTQUNGLENBQUMsQ0FBQztRQUNILGFBQWEsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBRTlDLDRFQUE0RTtRQUM1RSxVQUFVO1FBQ1YsNEVBQTRFO1FBQzVFLElBQUksdUJBQWUsQ0FBQyxJQUFJLEVBQUUsc0JBQXNCLEVBQUU7WUFDaEQsS0FBSyxFQUFFLGNBQWMsQ0FBQyxXQUFXO1lBQ2pDLFdBQVcsRUFBRSw4QkFBOEI7U0FDNUMsQ0FBQyxDQUFDO1FBRUgsSUFBSSx1QkFBZSxDQUFDLElBQUksRUFBRSxrQkFBa0IsRUFBRTtZQUM1QyxLQUFLLEVBQUUsVUFBVSxDQUFDLFFBQVE7WUFDMUIsV0FBVyxFQUFFLGdEQUFnRDtTQUM5RCxDQUFDLENBQUM7UUFFSCxJQUFJLHVCQUFlLENBQUMsSUFBSSxFQUFFLHFCQUFxQixFQUFFO1lBQy9DLEtBQUssRUFBRSxXQUFXLFVBQVUsQ0FBQyxRQUFRLEVBQUU7WUFDdkMsV0FBVyxFQUFFLCtEQUErRDtTQUM3RSxDQUFDLENBQUM7UUFFSCxJQUFJLHVCQUFlLENBQUMsSUFBSSxFQUFFLGFBQWEsRUFBRTtZQUN2QyxLQUFLLEVBQUUsV0FBVyxDQUFDLEVBQUU7WUFDckIsV0FBVyxFQUFFLHNFQUFzRTtTQUNwRixDQUFDLENBQUM7SUFDTCxDQUFDO0NBQ0Y7QUFwaEJELHNDQW9oQkMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcbmltcG9ydCB7IFRlcnJhZm9ybVN0YWNrLCBUZXJyYWZvcm1PdXRwdXQgfSBmcm9tICdjZGt0Zic7XG5pbXBvcnQgeyBPY2lQcm92aWRlciB9IGZyb20gJy4uLy5nZW4vcHJvdmlkZXJzL29jaS9wcm92aWRlcic7XG5pbXBvcnQgeyBBcnRpZmFjdHNDb250YWluZXJSZXBvc2l0b3J5IH0gZnJvbSAnLi4vLmdlbi9wcm92aWRlcnMvb2NpL2FydGlmYWN0cy1jb250YWluZXItcmVwb3NpdG9yeSc7XG5pbXBvcnQgeyBDb3JlVmNuIH0gZnJvbSAnLi4vLmdlbi9wcm92aWRlcnMvb2NpL2NvcmUtdmNuJztcbmltcG9ydCB7IENvcmVTdWJuZXQgfSBmcm9tICcuLi8uZ2VuL3Byb3ZpZGVycy9vY2kvY29yZS1zdWJuZXQnO1xuaW1wb3J0IHsgQ29yZVNlY3VyaXR5TGlzdCB9IGZyb20gJy4uLy5nZW4vcHJvdmlkZXJzL29jaS9jb3JlLXNlY3VyaXR5LWxpc3QnO1xuaW1wb3J0IHsgQ29yZVNlcnZpY2VHYXRld2F5IH0gZnJvbSAnLi4vLmdlbi9wcm92aWRlcnMvb2NpL2NvcmUtc2VydmljZS1nYXRld2F5JztcbmltcG9ydCB7IERhdGFPY2lDb3JlU2VydmljZXMgfSBmcm9tICcuLi8uZ2VuL3Byb3ZpZGVycy9vY2kvZGF0YS1vY2ktY29yZS1zZXJ2aWNlcyc7XG5pbXBvcnQgeyBDb3JlUm91dGVUYWJsZSB9IGZyb20gJy4uLy5nZW4vcHJvdmlkZXJzL29jaS9jb3JlLXJvdXRlLXRhYmxlJztcbmltcG9ydCB7IENvcmVJbnRlcm5ldEdhdGV3YXkgfSBmcm9tICcuLi8uZ2VuL3Byb3ZpZGVycy9vY2kvY29yZS1pbnRlcm5ldC1nYXRld2F5JztcbmltcG9ydCB7IEFwaWdhdGV3YXlHYXRld2F5IH0gZnJvbSAnLi4vLmdlbi9wcm92aWRlcnMvb2NpL2FwaWdhdGV3YXktZ2F0ZXdheSc7XG5pbXBvcnQgeyBBcGlnYXRld2F5RGVwbG95bWVudCB9IGZyb20gJy4uLy5nZW4vcHJvdmlkZXJzL29jaS9hcGlnYXRld2F5LWRlcGxveW1lbnQnO1xuaW1wb3J0IHsgRnVuY3Rpb25zQXBwbGljYXRpb24gfSBmcm9tICcuLi8uZ2VuL3Byb3ZpZGVycy9vY2kvZnVuY3Rpb25zLWFwcGxpY2F0aW9uJztcbmltcG9ydCB7IEZ1bmN0aW9uc0Z1bmN0aW9uIH0gZnJvbSAnLi4vLmdlbi9wcm92aWRlcnMvb2NpL2Z1bmN0aW9ucy1mdW5jdGlvbic7XG5pbXBvcnQgeyBWYXVsdFNlY3JldCB9IGZyb20gJy4uLy5nZW4vcHJvdmlkZXJzL29jaS92YXVsdC1zZWNyZXQnO1xuaW1wb3J0IHsgT2NpQmFja2VuZENvbmZpZyB9IGZyb20gJy4uL2NvbmZpZy9vY2ktY29uZmlnJztcbmltcG9ydCAqIGFzIGNyeXB0byBmcm9tICdjcnlwdG8nO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcblxuZXhwb3J0IGludGVyZmFjZSBPY2lTdGFja0NvbmZpZyB7XG4gIGNvbXBhcnRtZW50SWQ6IHN0cmluZztcbiAgb2NpckNvbXBhcnRtZW50SWQ/OiBzdHJpbmc7XG4gIHRlbmFuY3lJZDogc3RyaW5nO1xuICByZWdpb246IHN0cmluZztcbiAgbmFtZXNwYWNlOiBzdHJpbmc7XG4gIGZ1bmN0aW9uQXBwTmFtZTogc3RyaW5nO1xuICBmdW5jdGlvbk5hbWU6IHN0cmluZztcbiAgb2NpclJlcG9zaXRvcnlOYW1lPzogc3RyaW5nO1xuICAvKiogV2hlbiBzZXQgd2l0aCB2YXVsdE9jaWQgYW5kIGtleU9jaWQsIHN0YWNrIGNyZWF0ZXMgVmF1bHQgc2VjcmV0IChwZy11cmwpIGFuZCBmdW5jdGlvbiB1c2VzIGl0LiAqL1xuICBwZ1VybD86IHN0cmluZztcbiAgLyoqIFZhdWx0IE9DSUQgKHJlcXVpcmVkIHdpdGgga2V5T2NpZCB3aGVuIHBnVXJsIGlzIHNldCBhbmQgdXNpbmcgVmF1bHQpLiAqL1xuICB2YXVsdE9jaWQ/OiBzdHJpbmc7XG4gIC8qKiBLTVMgS2V5IE9DSUQgKHJlcXVpcmVkIHdoZW4gdmF1bHRPY2lkIGlzIHNldCkuICovXG4gIGtleU9jaWQ/OiBzdHJpbmc7XG4gIC8qKiBXaGVuIHBnVXJsIGlzIG5vdCBzZXQ6IGV4aXN0aW5nIE9DSSBWYXVsdCBzZWNyZXQgT0NJRCBmb3IgUEcgKGZ1bmN0aW9uIGNvbmZpZyBrZXk6IFBHX1NFQ1JFVF9PQ0lEKS4gKi9cbiAgcGdTZWNyZXRPY2lkPzogc3RyaW5nO1xuICAvKiogQVBJIEdhdGV3YXkgZGVwbG95bWVudCBwYXRoIHByZWZpeC4gRGVmYXVsdCAnLycuICovXG4gIGFwaUd3UGF0aFByZWZpeD86IHN0cmluZztcbiAgLyoqIEFQSSBHYXRld2F5IHJvdXRlIHBhdGguIERlZmF1bHQgJy97cGF0aCp9Jy4gKi9cbiAgYXBpR3dSb3V0ZVBhdGg/OiBzdHJpbmc7XG4gIC8qKiBBUEkgR2F0ZXdheSByb3V0ZSBtZXRob2RzLiBEZWZhdWx0IFsnR0VUJywgJ1BPU1QnLCAnT1BUSU9OUyddLiAqL1xuICBhcGlHd01ldGhvZHM/OiBzdHJpbmdbXTtcbiAgYmFja2VuZD86IE9jaUJhY2tlbmRDb25maWc7XG59XG5cbmV4cG9ydCBjbGFzcyBGdW5jdGlvblN0YWNrIGV4dGVuZHMgVGVycmFmb3JtU3RhY2sge1xuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBjb25maWc6IE9jaVN0YWNrQ29uZmlnKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcblxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICAvLyBCYWNrZW5kICYgUHJvdmlkZXJcbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgaWYgKGNvbmZpZy5iYWNrZW5kICYmIGNvbmZpZy5iYWNrZW5kLnR5cGUgIT09ICdsb2NhbCcpIHtcbiAgICAgIGlmIChjb25maWcuYmFja2VuZC50eXBlID09PSAnb2NpJykge1xuICAgICAgICB0aGlzLmFkZE92ZXJyaWRlKCd0ZXJyYWZvcm0uYmFja2VuZCcsIHtcbiAgICAgICAgICBvY2k6IHtcbiAgICAgICAgICAgIGJ1Y2tldDogY29uZmlnLmJhY2tlbmQuYnVja2V0LFxuICAgICAgICAgICAgbmFtZXNwYWNlOiBjb25maWcubmFtZXNwYWNlLFxuICAgICAgICAgICAga2V5OiBjb25maWcuYmFja2VuZC5rZXkgfHwgYCR7aWR9L3RlcnJhZm9ybS50ZnN0YXRlYCxcbiAgICAgICAgICAgIHJlZ2lvbjogY29uZmlnLnJlZ2lvbixcbiAgICAgICAgICB9LFxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSBpZiAoY29uZmlnLmJhY2tlbmQudHlwZSA9PT0gJ2h0dHAnKSB7XG4gICAgICAgIGNvbnN0IGh0dHBCYWNrZW5kOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHtcbiAgICAgICAgICBhZGRyZXNzOiBjb25maWcuYmFja2VuZC5hZGRyZXNzLFxuICAgICAgICAgIHVwZGF0ZV9tZXRob2Q6IGNvbmZpZy5iYWNrZW5kLnVwZGF0ZU1ldGhvZCB8fCAnUFVUJyxcbiAgICAgICAgfTtcbiAgICAgICAgaWYgKGNvbmZpZy5iYWNrZW5kLmxvY2tBZGRyZXNzKSBodHRwQmFja2VuZC5sb2NrX2FkZHJlc3MgPSBjb25maWcuYmFja2VuZC5sb2NrQWRkcmVzcztcbiAgICAgICAgaWYgKGNvbmZpZy5iYWNrZW5kLnVubG9ja0FkZHJlc3MpIGh0dHBCYWNrZW5kLnVubG9ja19hZGRyZXNzID0gY29uZmlnLmJhY2tlbmQudW5sb2NrQWRkcmVzcztcbiAgICAgICAgdGhpcy5hZGRPdmVycmlkZSgndGVycmFmb3JtLmJhY2tlbmQnLCB7IGh0dHA6IGh0dHBCYWNrZW5kIH0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIG5ldyBPY2lQcm92aWRlcih0aGlzLCAnb2NpJywge1xuICAgICAgcmVnaW9uOiBjb25maWcucmVnaW9uLFxuICAgICAgdGVuYW5jeU9jaWQ6IGNvbmZpZy50ZW5hbmN5SWQsXG4gICAgfSk7XG5cbiAgICAvLyBBZGQgbnVsbCBwcm92aWRlciB1c2luZyBhZGRPdmVycmlkZSAoYXZvaWRzIG5lZWRpbmcgdG8gZ2VuZXJhdGUgdHlwZXMpXG4gICAgdGhpcy5hZGRPdmVycmlkZSgndGVycmFmb3JtLnJlcXVpcmVkX3Byb3ZpZGVycy5udWxsJywge1xuICAgICAgc291cmNlOiAnaGFzaGljb3JwL251bGwnLFxuICAgICAgdmVyc2lvbjogJ34+IDMuMCcsXG4gICAgfSk7XG5cbiAgICBjb25zdCBvY2lyQ29tcGFydG1lbnRJZCA9IGNvbmZpZy5vY2lyQ29tcGFydG1lbnRJZCB8fCBjb25maWcuY29tcGFydG1lbnRJZDtcbiAgICBjb25zdCBvY2lyUmVwb05hbWUgPSBjb25maWcub2NpclJlcG9zaXRvcnlOYW1lIHx8IGNvbmZpZy5mdW5jdGlvbk5hbWU7XG5cbiAgICBpZiAob2NpckNvbXBhcnRtZW50SWQuaW5jbHVkZXMoJ3Jvb3QnKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAnT0NJUiByZXBvc2l0b3J5IGNhbm5vdCBiZSBjcmVhdGVkIGluIHJvb3QgY29tcGFydG1lbnQuICcgK1xuICAgICAgICAgICdQbGVhc2Ugc2V0IE9DSV9PQ0lSX0NPTVBBUlRNRU5UX0lEIHRvIHlvdXIgaG9tZSBjb21wYXJ0bWVudCBPQ0lELidcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIC8vIE9DSVIgQ29udGFpbmVyIFJlcG9zaXRvcnlcbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgY29uc3Qgb2NpclJlcG9zaXRvcnkgPSBuZXcgQXJ0aWZhY3RzQ29udGFpbmVyUmVwb3NpdG9yeSh0aGlzLCAnT2NpclJlcG9zaXRvcnknLCB7XG4gICAgICBjb21wYXJ0bWVudElkOiBvY2lyQ29tcGFydG1lbnRJZCxcbiAgICAgIGRpc3BsYXlOYW1lOiBvY2lyUmVwb05hbWUsXG4gICAgICBpc1B1YmxpYzogZmFsc2UsXG4gICAgICBpc0ltbXV0YWJsZTogZmFsc2UsXG4gICAgfSk7XG5cbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgLy8gQnVpbGQgYW5kIFB1c2ggRG9ja2VyIEltYWdlIHRvIE9DSVIgKGFmdGVyIHJlcG9zaXRvcnkgaXMgY3JlYXRlZClcbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgY29uc3QgaW1hZ2VVcmwgPSBgJHtjb25maWcucmVnaW9ufS5vY2lyLmlvLyR7Y29uZmlnLm5hbWVzcGFjZX0vJHtvY2lyUmVwb05hbWV9OmxhdGVzdGA7XG4gICAgXG4gICAgLy8gR2V0IE9DSVIgbG9naW4gdXNlcm5hbWUgZnJvbSBlbnYgb3IgdHJ5IHRvIGdldCBmcm9tIE9DSSBDTElcbiAgICAvLyBGb3JtYXQ6IDx0ZW5hbmN5LW5hbWVzcGFjZT4vPHVzZXJuYW1lPiAoZS5nLiwgZnJzeHd0anNsZjM1L29yYWNsZWlkZW50aXR5Y2xvdWRzZXJ2aWNlL3VzZXJAZXhhbXBsZS5jb20pXG4gICAgLy8gRGVmYXVsdCB3aWxsIGJlIGNvbnN0cnVjdGVkIGluIHRoZSBzY3JpcHQgaWYgbm90IHByb3ZpZGVkXG4gICAgY29uc3Qgb2NpclVzZXJuYW1lID0gcHJvY2Vzcy5lbnYuT0NJX09DSVJfVVNFUk5BTUUgfHwgJ0FVVE9fREVURUNUJztcbiAgICBcbiAgICAvLyBmdW5jdGlvbi1jb2RlIGlzIGF0IGphdmEtZnVuY3Rpb24vZnVuY3Rpb24tY29kZSAoc2libGluZyBvZiBvY2ktY2RrKVxuICAgIC8vIFJlc29sdmUgcGF0aCByZWxhdGl2ZSB0byB0aGlzIGZpbGUncyBsb2NhdGlvblxuICAgIC8vIENvbXBpbGVkIEpTIGlzIGF0IGxpYi9saWIvZnVuY3Rpb24tc3RhY2suanMsIHNvIF9fZGlybmFtZSBpcyBsaWIvbGliL1xuICAgIC8vIEZyb20gbGliL2xpYi86IC4uLyBnb2VzIHRvIGxpYi8sIC4uLyBnb2VzIHRvIG9jaS1jZGsvLCAuLi8gZ29lcyB0byBqYXZhLWZ1bmN0aW9uLywgdGhlbiBmdW5jdGlvbi1jb2RlL1xuICAgIGNvbnN0IGZ1bmN0aW9uQ29kZVBhdGggPSBwYXRoLnJlc29sdmUoX19kaXJuYW1lLCAnLi4nLCAnLi4nLCAnLi4nLCAnZnVuY3Rpb24tY29kZScpO1xuICAgIFxuICAgIC8vIENyZWF0ZSBudWxsX3Jlc291cmNlIHVzaW5nIGFkZE92ZXJyaWRlIChzaW5jZSB3ZSBjYW4ndCBnZW5lcmF0ZSB0eXBlcyBkdWUgdG8gbmV0d29yayBpc3N1ZXMpXG4gICAgLy8gVGhpcyBjcmVhdGVzIGEgVGVycmFmb3JtIG51bGxfcmVzb3VyY2UgdGhhdCBidWlsZHMgYW5kIHB1c2hlcyB0aGUgRG9ja2VyIGltYWdlXG4gICAgY29uc3QgYnVpbGRBbmRQdXNoSW1hZ2VJZCA9ICdCdWlsZEFuZFB1c2hJbWFnZSc7XG4gICAgLy8gVXNlIHRoZSBUZXJyYWZvcm0gcmVzb3VyY2UgcmVmZXJlbmNlIGRpcmVjdGx5IChub3QgaW50ZXJwb2xhdGVkIHN0cmluZylcbiAgICAvLyBkZXBlbmRzX29uIGV4cGVjdHMgcmVzb3VyY2UgcmVmZXJlbmNlcywgbm90IGF0dHJpYnV0ZSByZWZlcmVuY2VzXG4gICAgdGhpcy5hZGRPdmVycmlkZShgcmVzb3VyY2UubnVsbF9yZXNvdXJjZS4ke2J1aWxkQW5kUHVzaEltYWdlSWR9LmRlcGVuZHNfb25gLCBbXG4gICAgICAnb2NpX2FydGlmYWN0c19jb250YWluZXJfcmVwb3NpdG9yeS5PY2lyUmVwb3NpdG9yeScsXG4gICAgXSk7XG4gICAgdGhpcy5hZGRPdmVycmlkZShgcmVzb3VyY2UubnVsbF9yZXNvdXJjZS4ke2J1aWxkQW5kUHVzaEltYWdlSWR9LnRyaWdnZXJzYCwge1xuICAgICAgcmVwb19uYW1lOiBvY2lyUmVwb05hbWUsXG4gICAgICBpbWFnZV91cmw6IGltYWdlVXJsLFxuICAgICAgbmFtZXNwYWNlOiBjb25maWcubmFtZXNwYWNlLFxuICAgICAgcmVnaW9uOiBjb25maWcucmVnaW9uLFxuICAgIH0pO1xuICAgIFxuICAgIC8vIEdlbmVyYXRlIGF1dGggdG9rZW4gYW5kIGxvZ2luIHNjcmlwdFxuICAgIC8vIElmIE9DSV9BVVRIX1RPS0VOIGlzIHNldCwgdXNlIGl0OyBvdGhlcndpc2UgZ2VuZXJhdGUgb25lIHZpYSBPQ0kgQ0xJXG4gICAgY29uc3QgcmVnaW9uUGxhY2Vob2xkZXIgPSBjb25maWcucmVnaW9uO1xuICAgIGNvbnN0IG5hbWVzcGFjZVBsYWNlaG9sZGVyID0gY29uZmlnLm5hbWVzcGFjZTtcbiAgICBjb25zdCBvY2lyVXNlcm5hbWVWYWx1ZSA9IG9jaXJVc2VybmFtZTsgLy8gQ2FwdHVyZSB2YWx1ZSBmb3IgdGVtcGxhdGUgc3RyaW5nXG4gICAgLy8gVXNlIHN0cmluZyBjb25jYXRlbmF0aW9uIHRvIGF2b2lkIFR5cGVTY3JpcHQgcGFyc2luZyBpc3N1ZXMgd2l0aCAke30gaW4gc2hlbGwgc2NyaXB0c1xuICAgIGNvbnN0IGRvbGxhclNpZ24gPSAnJCc7XG4gICAgY29uc3QgZG9sbGFyRG9sbGFyID0gJyQkJztcbiAgICAvLyBVc2UgYmFja3RpY2tzIGZvciBjb21tYW5kIHN1YnN0aXR1dGlvbiB0byBhdm9pZCBjb21wbGV4ICQoKSBlc2NhcGluZ1xuICAgIC8vIEluIFR5cGVTY3JpcHQgdGVtcGxhdGUgc3RyaW5ncywgYmFja3RpY2tzIG5lZWQgdG8gYmUgZXNjYXBlZCBhcyBcXGBcbiAgICBjb25zdCBjbWRTdWJTdGFydCA9ICdcXGAnO1xuICAgIGNvbnN0IGNtZFN1YkVuZCA9ICdcXGAnO1xuICAgIGNvbnN0IGxvZ2luU2NyaXB0ID0gcHJvY2Vzcy5lbnYuT0NJX0FVVEhfVE9LRU4gXG4gICAgICA/IGAjIFVzaW5nIHByb3ZpZGVkIE9DSV9BVVRIX1RPS0VOXG5leHBvcnQgT0NJUl9BVVRIX1RPS0VOPVwiJHtwcm9jZXNzLmVudi5PQ0lfQVVUSF9UT0tFTn1cIlxuaWYgWyAteiBcIiR7ZG9sbGFyRG9sbGFyfU9DSVJfQVVUSF9UT0tFTlwiIF07IHRoZW5cbiAgZWNobyBcIkVycm9yOiBPQ0lfQVVUSF9UT0tFTiBpcyBlbXB0eS4gUGxlYXNlIHNldCBhIHZhbGlkIHRva2VuLlwiXG4gIGV4aXQgMVxuZmlcbiMgVXNlIHByb3ZpZGVkIHVzZXJuYW1lIG9yIGF1dG8tZGV0ZWN0XG5PQ0lSX1VTRVJOQU1FPVwiJHtvY2lyVXNlcm5hbWVWYWx1ZX1cIlxuaWYgWyBcIiR7ZG9sbGFyRG9sbGFyfU9DSVJfVVNFUk5BTUVcIiA9PSBcIkFVVE9fREVURUNUXCIgXTsgdGhlblxuICBVU0VSX09DSUQ9JHtjbWRTdWJTdGFydH1vY2kgaWFtIHVzZXIgbGlzdCAtLXF1ZXJ5IFwiZGF0YVswXS5pZFwiIC0tcmF3LW91dHB1dCAyPi9kZXYvbnVsbCR7Y21kU3ViRW5kfVxuICBpZiBbIC1uIFwiJHtkb2xsYXJEb2xsYXJ9VVNFUl9PQ0lEXCIgXSAmJiBbIFwiJHtkb2xsYXJEb2xsYXJ9VVNFUl9PQ0lEXCIgIT0gXCJudWxsXCIgXTsgdGhlblxuICAgIFVTRVJfTkFNRT0ke2NtZFN1YlN0YXJ0fW9jaSBpYW0gdXNlciBnZXQgLS11c2VyLWlkIFwiJHtkb2xsYXJEb2xsYXJ9VVNFUl9PQ0lEXCIgLS1xdWVyeSAnZGF0YS5uYW1lJyAtLXJhdy1vdXRwdXQgMj4vZGV2L251bGwgfHwgZWNobyBcIlwiJHtjbWRTdWJFbmR9XG4gICAgaWYgWyAtbiBcIiR7ZG9sbGFyRG9sbGFyfVVTRVJfTkFNRVwiIF07IHRoZW5cbiAgICAgIE9DSVJfVVNFUk5BTUU9XCIke25hbWVzcGFjZVBsYWNlaG9sZGVyfS8ke2RvbGxhckRvbGxhcn1VU0VSX05BTUVcIlxuICAgIGVsc2VcbiAgICAgIGVjaG8gXCJXYXJuaW5nOiBDb3VsZCBub3QgYXV0by1kZXRlY3QgdXNlcm5hbWUuIFVzaW5nIGRlZmF1bHQgZm9ybWF0LlwiXG4gICAgICBPQ0lSX1VTRVJOQU1FPVwiJHtuYW1lc3BhY2VQbGFjZWhvbGRlcn0vdXNlclwiXG4gICAgZmlcbiAgZWxzZVxuICAgIE9DSVJfVVNFUk5BTUU9XCIke25hbWVzcGFjZVBsYWNlaG9sZGVyfS91c2VyXCJcbiAgZmlcbmZpXG5lY2hvIFwiJHtkb2xsYXJEb2xsYXJ9T0NJUl9BVVRIX1RPS0VOXCIgfCBkb2NrZXIgbG9naW4gJHtyZWdpb25QbGFjZWhvbGRlcn0ub2Npci5pbyAtdSBcIiR7ZG9sbGFyRG9sbGFyfU9DSVJfVVNFUk5BTUVcIiAtLXBhc3N3b3JkLXN0ZGluID4vZGV2L251bGwgMj4mMSB8fCB7XG4gIGVjaG8gXCJFcnJvcjogRG9ja2VyIGxvZ2luIGZhaWxlZC4gQ2hlY2sgeW91ciBPQ0lfQVVUSF9UT0tFTiBhbmQgdXNlcm5hbWUgZm9ybWF0LlwiID4mMlxuICBlY2hvIFwiVXNlcm5hbWUgdXNlZDogJHtkb2xsYXJEb2xsYXJ9T0NJUl9VU0VSTkFNRVwiID4mMlxuICBlY2hvIFwiVXNlcm5hbWUgZm9ybWF0IHNob3VsZCBiZTogPHRlbmFuY3ktbmFtZXNwYWNlPi88dXNlcm5hbWU+XCIgPiYyXG4gIGVjaG8gXCJTZXQgbWFudWFsbHk6IGV4cG9ydCBPQ0lfT0NJUl9VU0VSTkFNRT1cXFxcXCIke25hbWVzcGFjZVBsYWNlaG9sZGVyfS95b3VyLWFjdHVhbC11c2VybmFtZVxcXFxcIlwiID4mMlxuICBleGl0IDFcbn1gXG4gICAgICA6IGAjIEdlbmVyYXRlIE9DSVIgYXV0aCB0b2tlbiB2aWEgT0NJIENMSSBhbmQgbG9naW4gdG8gT0NJUlxuIyBUcnkgcmF3LXJlcXVlc3QgbWV0aG9kIGZpcnN0ICh1c2VzIGRlZmF1bHQgT0NJIENMSSBhdXRoIGZyb20gY29uZmlnKVxuT0NJUl9IT1NUPVwiJHtyZWdpb25QbGFjZWhvbGRlcn0ub2Npci5pb1wiXG5pZiBvY2kgcmF3LXJlcXVlc3QgLS1yZWdpb24gJHtyZWdpb25QbGFjZWhvbGRlcn0gLS1odHRwLW1ldGhvZCBHRVQgLS10YXJnZXQtdXJpIFwiaHR0cHM6Ly8ke3JlZ2lvblBsYWNlaG9sZGVyfS5vY2lyLmlvLzIwMTgwNDE5L2RvY2tlci90b2tlblwiID4vZGV2L251bGwgMj4mMTsgdGhlblxuICBpZiBjb21tYW5kIC12IGpxID4vZGV2L251bGwgMj4mMTsgdGhlblxuICAgIG9jaSByYXctcmVxdWVzdCAtLXJlZ2lvbiAke3JlZ2lvblBsYWNlaG9sZGVyfSAtLWh0dHAtbWV0aG9kIEdFVCAtLXRhcmdldC11cmkgXCJodHRwczovLyR7cmVnaW9uUGxhY2Vob2xkZXJ9Lm9jaXIuaW8vMjAxODA0MTkvZG9ja2VyL3Rva2VuXCIgMj4vZGV2L251bGwgfCBqcSAtciAuZGF0YS50b2tlbiAyPi9kZXYvbnVsbCB8IGRvY2tlciBsb2dpbiAtdSBCRUFSRVJfVE9LRU4gLS1wYXNzd29yZC1zdGRpbiAke3JlZ2lvblBsYWNlaG9sZGVyfS5vY2lyLmlvID4vZGV2L251bGwgMj4mMSB8fCB7XG4gICAgICBlY2hvIFwiRXJyb3I6IERvY2tlciBsb2dpbiB3aXRoIHJhdy1yZXF1ZXN0IGZhaWxlZC5cIiA+JjJcbiAgICAgIGV4aXQgMVxuICAgIH1cbiAgZWxzZVxuICAgIG9jaSByYXctcmVxdWVzdCAtLXJlZ2lvbiAke3JlZ2lvblBsYWNlaG9sZGVyfSAtLWh0dHAtbWV0aG9kIEdFVCAtLXRhcmdldC11cmkgXCJodHRwczovLyR7cmVnaW9uUGxhY2Vob2xkZXJ9Lm9jaXIuaW8vMjAxODA0MTkvZG9ja2VyL3Rva2VuXCIgMj4vZGV2L251bGwgfCBncmVwIC1vICdcInRva2VuXCI6XCJbXlwiXSpcIicgfCBjdXQgLWQnXCInIC1mNCB8IGRvY2tlciBsb2dpbiAtdSBCRUFSRVJfVE9LRU4gLS1wYXNzd29yZC1zdGRpbiAke3JlZ2lvblBsYWNlaG9sZGVyfS5vY2lyLmlvID4vZGV2L251bGwgMj4mMSB8fCB7XG4gICAgICBlY2hvIFwiRXJyb3I6IERvY2tlciBsb2dpbiB3aXRoIHJhdy1yZXF1ZXN0IGZhaWxlZC5cIiA+JjJcbiAgICAgIGV4aXQgMVxuICAgIH1cbiAgZmlcbmVsc2VcbiAgIyBGYWxsYmFjayB0byBhdXRoIHRva2VuIG1ldGhvZCAoZm9yIGxvY2FsaG9zdClcbiAgIyBHZXQgdXNlciBPQ0lEIGZyb20gQ0xJIGNvbmZpZyAoc2FtZSBhcHByb2FjaCBhcyByZWZlcmVuY2Ugc2NyaXB0KVxuICBPQ0lfQ09ORklHPVwiJHtkb2xsYXJEb2xsYXJ9e09DSV9DTElfQ09ORklHX0ZJTEU6LSR7ZG9sbGFyRG9sbGFyfUhPTUUvLm9jaS9jb25maWd9XCJcbiAgT0NJX1BST0ZJTEU9XCIke2RvbGxhckRvbGxhcn17T0NJX0NMSV9QUk9GSUxFOi1ERUZBVUxUfVwiXG4gIFVTRVJfT0NJRD1cIlwiXG4gIGlmIFsgLWYgXCIke2RvbGxhckRvbGxhcn1PQ0lfQ09ORklHXCIgXTsgdGhlblxuICAgIFVTRVJfT0NJRD0ke2NtZFN1YlN0YXJ0fWF3ayAtdiBwcm9mPVwiWyR7ZG9sbGFyRG9sbGFyfU9DSV9QUk9GSUxFXVwiICcke2RvbGxhckRvbGxhcn0wID09IHByb2YgeyBpbl9wcm9maWxlPTE7IG5leHQgfSAvXlxcXFxbLyB7IGluX3Byb2ZpbGU9MCB9IGluX3Byb2ZpbGUgJiYgJHtkb2xsYXJEb2xsYXJ9MCB+IC9eW1s6c3BhY2U6XV0qdXNlcltbOnNwYWNlOl1dKj0vIHsgc3BsaXQoJHtkb2xsYXJEb2xsYXJ9MCwgYSwgXCI9XCIpOyBnc3ViKC9eW1s6c3BhY2U6XV0rfFtbOnNwYWNlOl1dKyR7ZG9sbGFyRG9sbGFyfS8sIFwiXCIsIGFbMl0pOyBwcmludCBhWzJdOyBleGl0IH0nIFwiJHtkb2xsYXJEb2xsYXJ9T0NJX0NPTkZJR1wiIDI+L2Rldi9udWxsIHx8IGVjaG8gXCJcIiR7Y21kU3ViRW5kfVxuICBmaVxuXG4gICMgRmFsbGJhY2sgdG8gdXNlciBsaXN0IGlmIG5vdCBpbiBjb25maWdcbiAgaWYgWyAteiBcIiR7ZG9sbGFyRG9sbGFyfVVTRVJfT0NJRFwiIF0gfHwgWyBcIiR7ZG9sbGFyRG9sbGFyfVVTRVJfT0NJRFwiICE9IG9jaWQxLiogXTsgdGhlblxuICAgIFVTRVJfT0NJRD0ke2NtZFN1YlN0YXJ0fW9jaSBpYW0gdXNlciBsaXN0IC0tcXVlcnkgXCJkYXRhWzBdLmlkXCIgLS1yYXctb3V0cHV0IDI+L2Rldi9udWxsIHx8IGVjaG8gXCJcIiR7Y21kU3ViRW5kfVxuICBmaVxuXG4gIGlmIFsgLXogXCIke2RvbGxhckRvbGxhcn1VU0VSX09DSURcIiBdIHx8IFsgXCIke2RvbGxhckRvbGxhcn1VU0VSX09DSURcIiA9PSBcIm51bGxcIiBdIHx8IFsgXCIke2RvbGxhckRvbGxhcn1VU0VSX09DSURcIiAhPSBvY2lkMS4qIF07IHRoZW5cbiAgICBlY2hvIFwiRXJyb3I6IENvdWxkIG5vdCBnZXQgdXNlciBPQ0lELiBTZXQgT0NJX0FVVEhfVE9LRU4gbWFudWFsbHkgb3IgZW5zdXJlIE9DSSBDTEkgaXMgY29uZmlndXJlZC5cIiA+JjJcbiAgICBlY2hvIFwiUnVuOiBvY2kgaWFtIHVzZXIgbGlzdFwiID4mMlxuICAgIGVjaG8gXCJPciBjaGVjayB5b3VyIE9DSSBjb25maWc6ICR7ZG9sbGFyRG9sbGFyfU9DSV9DT05GSUdcIiA+JjJcbiAgICBleGl0IDFcbiAgZmlcblxuICAjIFZlcmlmeSB1c2VyIGV4aXN0cyBiZWZvcmUgdHJ5aW5nIHRvIGNyZWF0ZSB0b2tlblxuICBpZiAhIG9jaSBpYW0gdXNlciBnZXQgLS11c2VyLWlkIFwiJHtkb2xsYXJEb2xsYXJ9VVNFUl9PQ0lEXCIgPi9kZXYvbnVsbCAyPiYxOyB0aGVuXG4gICAgZWNobyBcIkVycm9yOiBVc2VyIE9DSUQgJyR7ZG9sbGFyRG9sbGFyfVVTRVJfT0NJRCcgbm90IGZvdW5kIG9yIG5vdCBhY2Nlc3NpYmxlLlwiID4mMlxuICAgIGVjaG8gXCJQbGVhc2UgdmVyaWZ5IHlvdXIgT0NJIENMSSBjb25maWd1cmF0aW9uIG9yIHNldCBPQ0lfQVVUSF9UT0tFTiBtYW51YWxseS5cIiA+JjJcbiAgICBleGl0IDFcbiAgZmlcblxuICAjIEdldCB1c2VybmFtZSBmb3IgT0NJUiBsb2dpblxuICBPQ0lSX1VTRVJOQU1FX1ZBUj1cIiR7b2NpclVzZXJuYW1lVmFsdWV9XCJcbiAgaWYgWyBcIiR7ZG9sbGFyRG9sbGFyfU9DSVJfVVNFUk5BTUVfVkFSXCIgPT0gXCJBVVRPX0RFVEVDVFwiIF07IHRoZW5cbiAgICBVU0VSX05BTUU9JHtjbWRTdWJTdGFydH1vY2kgaWFtIHVzZXIgZ2V0IC0tdXNlci1pZCBcIiR7ZG9sbGFyRG9sbGFyfVVTRVJfT0NJRFwiIC0tcXVlcnkgJ2RhdGEubmFtZScgLS1yYXctb3V0cHV0IDI+L2Rldi9udWxsIHx8IGVjaG8gXCJcIiR7Y21kU3ViRW5kfVxuICAgIGlmIFsgLXogXCIke2RvbGxhckRvbGxhcn1VU0VSX05BTUVcIiBdIHx8IFsgXCIke2RvbGxhckRvbGxhcn1VU0VSX05BTUVcIiA9PSBcIm51bGxcIiBdOyB0aGVuXG4gICAgICBlY2hvIFwiRXJyb3I6IENvdWxkIG5vdCBnZXQgdXNlcm5hbWUgZm9yIHVzZXIgJHtkb2xsYXJEb2xsYXJ9VVNFUl9PQ0lELlwiID4mMlxuICAgICAgZWNobyBcIlBsZWFzZSBzZXQgT0NJX09DSVJfVVNFUk5BTUUgbWFudWFsbHkuXCIgPiYyXG4gICAgICBlY2hvIFwiRm9ybWF0OiBleHBvcnQgT0NJX09DSVJfVVNFUk5BTUU9XFxcXFwiJHtuYW1lc3BhY2VQbGFjZWhvbGRlcn0veW91ci11c2VybmFtZVxcXFxcIlwiID4mMlxuICAgICAgZXhpdCAxXG4gICAgZmlcbiAgICAjIEV4dHJhY3QgdXNlcm5hbWUgcGFydCBpZiBpdCBjb250YWlucyBkb21haW4gKGUuZy4sIFwib3JhY2xlaWRlbnRpdHljbG91ZHNlcnZpY2UvdXNlckBleGFtcGxlLmNvbVwiIC0+IFwidXNlckBleGFtcGxlLmNvbVwiKVxuICAgIFVTRVJfTkFNRT1cIiR7ZG9sbGFyRG9sbGFyfXtVU0VSX05BTUUjIyovfVwiXG4gICAgT0NJUl9VU0VSTkFNRT1cIiR7bmFtZXNwYWNlUGxhY2Vob2xkZXJ9L29yYWNsZWlkZW50aXR5Y2xvdWRzZXJ2aWNlLyR7ZG9sbGFyRG9sbGFyfVVTRVJfTkFNRVwiXG4gIGVsc2VcbiAgICBPQ0lSX1VTRVJOQU1FPVwiJHtkb2xsYXJEb2xsYXJ9T0NJUl9VU0VSTkFNRV9WQVJcIlxuICBmaVxuXG4gIERFU0M9XCJPQ0lSIERvY2tlciBsb2dpbiB0b2tlbiAtICR7Y21kU3ViU3RhcnR9ZGF0ZSArJVklbSVkLSVIJU0lUyR7Y21kU3ViRW5kfVwiXG4gIFRPS0VOPSR7Y21kU3ViU3RhcnR9b2NpIGlhbSBhdXRoLXRva2VuIGNyZWF0ZSAtLXVzZXItaWQgXCIke2RvbGxhckRvbGxhcn1VU0VSX09DSURcIiAtLWRlc2NyaXB0aW9uIFwiJHtkb2xsYXJEb2xsYXJ9REVTQ1wiIC0tcXVlcnkgJ2RhdGEudG9rZW4nIC0tcmF3LW91dHB1dCAyPi9kZXYvbnVsbCB8fCB0cnVlJHtjbWRTdWJFbmR9XG5cbiAgaWYgWyAteiBcIiR7ZG9sbGFyRG9sbGFyfVRPS0VOXCIgXSB8fCBbIFwiJHtkb2xsYXJEb2xsYXJ9VE9LRU5cIiA9PSBcIm51bGxcIiBdOyB0aGVuXG4gICAgZWNobyBcIkVycm9yOiBGYWlsZWQgdG8gY3JlYXRlIGF1dGggdG9rZW4gdmlhIE9DSSBDTEkuXCIgPiYyXG4gICAgZWNobyBcIlRoaXMgbWlnaHQgYmUgZHVlIHRvOlwiID4mMlxuICAgIGVjaG8gXCIgIC0gTWlzc2luZyBJQU0gcGVybWlzc2lvbnMgKG5lZWQ6IG1hbmFnZSBhdXRoLXRva2VucylcIiA+JjJcbiAgICBlY2hvIFwiICAtIFVzZXIgT0NJRCAnJHtkb2xsYXJEb2xsYXJ9VVNFUl9PQ0lEJyBpcyBpbmNvcnJlY3Qgb3IgdXNlciBkb2Vzbid0IGV4aXN0XCIgPiYyXG4gICAgZWNobyBcIiAgLSBPQ0kgQ0xJIG5vdCBwcm9wZXJseSBjb25maWd1cmVkXCIgPiYyXG4gICAgZWNobyBcIlwiID4mMlxuICAgIGVjaG8gXCJTb2x1dGlvbjogU2V0IE9DSV9BVVRIX1RPS0VOIG1hbnVhbGx5OlwiID4mMlxuICAgIGVjaG8gXCIgIDEuIEdldCB0b2tlbiBmcm9tOiBodHRwczovL2Nsb3VkLm9yYWNsZS5jb20vaWRlbnRpdHkvdG9rZW5zXCIgPiYyXG4gICAgZWNobyBcIiAgMi4gRXhwb3J0OiBleHBvcnQgT0NJX0FVVEhfVE9LRU49XFxcXFwieW91ci10b2tlblxcXFxcIlwiID4mMlxuICAgIGVjaG8gXCIgIDMuIEFsc28gc2V0OiBleHBvcnQgT0NJX09DSVJfVVNFUk5BTUU9XFxcXFwiJHtkb2xsYXJEb2xsYXJ9T0NJUl9VU0VSTkFNRVxcXFxcIlwiID4mMlxuICAgIGVjaG8gXCIgIDQuIFRoZW4gcmUtcnVuOiBucG0gcnVuIGRlcGxveVwiID4mMlxuICAgIGV4aXQgMVxuICBmaVxuXG4gIGV4cG9ydCBPQ0lSX0FVVEhfVE9LRU49XCIke2RvbGxhckRvbGxhcn1UT0tFTlwiXG4gIGVjaG8gXCIke2RvbGxhckRvbGxhcn1PQ0lSX0FVVEhfVE9LRU5cIiB8IGRvY2tlciBsb2dpbiAke3JlZ2lvblBsYWNlaG9sZGVyfS5vY2lyLmlvIC11IFwiJHtkb2xsYXJEb2xsYXJ9T0NJUl9VU0VSTkFNRVwiIC0tcGFzc3dvcmQtc3RkaW4gPi9kZXYvbnVsbCAyPiYxIHx8IHtcbiAgICBlY2hvIFwiRXJyb3I6IERvY2tlciBsb2dpbiBmYWlsZWQgd2l0aCBnZW5lcmF0ZWQgdG9rZW4uXCIgPiYyXG4gICAgZWNobyBcIlVzZXJuYW1lIHVzZWQ6ICR7ZG9sbGFyRG9sbGFyfU9DSVJfVVNFUk5BTUVcIiA+JjJcbiAgICBlY2hvIFwiQ2hlY2sgdGhhdCB0aGUgdXNlcm5hbWUgZm9ybWF0IGlzIGNvcnJlY3Q6IDx0ZW5hbmN5LW5hbWVzcGFjZT4vPGRvbWFpbj4vPHVzZXJuYW1lPlwiID4mMlxuICAgIGVjaG8gXCJJZiBpbmNvcnJlY3QsIHNldDogZXhwb3J0IE9DSV9PQ0lSX1VTRVJOQU1FPVxcXFxcIiR7bmFtZXNwYWNlUGxhY2Vob2xkZXJ9L29yYWNsZWlkZW50aXR5Y2xvdWRzZXJ2aWNlL3lvdXItdXNlcm5hbWVcXFxcXCJcIiA+JjJcbiAgICBleGl0IDFcbiAgfVxuZmlgO1xuICAgIFxuICAgIHRoaXMuYWRkT3ZlcnJpZGUoYHJlc291cmNlLm51bGxfcmVzb3VyY2UuJHtidWlsZEFuZFB1c2hJbWFnZUlkfS5wcm92aXNpb25lcmAsIFtcbiAgICAgIHtcbiAgICAgICAgJ2xvY2FsLWV4ZWMnOiB7XG4gICAgICAgICAgY29tbWFuZDogYGNkICR7ZnVuY3Rpb25Db2RlUGF0aH0gJiYgZG9ja2VyIGJ1aWxkIC0tcGxhdGZvcm0gbGludXgvYW1kNjQgLXQgJHtpbWFnZVVybH0gLmAsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICAnbG9jYWwtZXhlYyc6IHtcbiAgICAgICAgICBjb21tYW5kOiBsb2dpblNjcmlwdCxcbiAgICAgICAgICBvbl9mYWlsdXJlOiAnY29udGludWUnLFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICAgIHtcbiAgICAgICAgJ2xvY2FsLWV4ZWMnOiB7XG4gICAgICAgICAgY29tbWFuZDogYGRvY2tlciBwdXNoICR7aW1hZ2VVcmx9YCxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgXSk7XG4gICAgXG4gICAgLy8gQ3JlYXRlIGEgcmVmZXJlbmNlIHRvIHRoZSBudWxsX3Jlc291cmNlIGZvciBkZXBlbmRlbmN5IHRyYWNraW5nXG4gICAgLy8gV2UnbGwgdXNlIGEgVGVycmFmb3JtRGF0YSBzb3VyY2UgYXMgYSBwcm94eSB0byByZWZlcmVuY2UgaXRcbiAgICBjb25zdCBidWlsZEFuZFB1c2hJbWFnZVJlZiA9IGBcXCR7bnVsbF9yZXNvdXJjZS4ke2J1aWxkQW5kUHVzaEltYWdlSWR9LmlkfWA7XG5cbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgLy8gVkNOIGFuZCBTdWJuZXRzXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIGNvbnN0IHZjbiA9IG5ldyBDb3JlVmNuKHRoaXMsICdWY24nLCB7XG4gICAgICBjb21wYXJ0bWVudElkOiBjb25maWcuY29tcGFydG1lbnRJZCxcbiAgICAgIGRpc3BsYXlOYW1lOiBgJHtpZH0tdmNuYCxcbiAgICAgIGNpZHJCbG9ja3M6IFsnMTAuMC4wLjAvMTYnXSxcbiAgICAgIGRuc0xhYmVsOiAnYXBwZm4nLFxuICAgIH0pO1xuXG4gICAgY29uc3QgcHVibGljU3VibmV0ID0gbmV3IENvcmVTdWJuZXQodGhpcywgJ1B1YmxpY1N1Ym5ldCcsIHtcbiAgICAgIGNvbXBhcnRtZW50SWQ6IGNvbmZpZy5jb21wYXJ0bWVudElkLFxuICAgICAgdmNuSWQ6IHZjbi5pZCxcbiAgICAgIGRpc3BsYXlOYW1lOiBgJHtpZH0tcHVibGljYCxcbiAgICAgIGNpZHJCbG9jazogJzEwLjAuMS4wLzI0JyxcbiAgICAgIGRuc0xhYmVsOiAncHVibGljJyxcbiAgICAgIHByb2hpYml0UHVibGljSXBPblZuaWM6IGZhbHNlLFxuICAgIH0pO1xuXG4gICAgY29uc3QgcHJpdmF0ZVN1Ym5ldCA9IG5ldyBDb3JlU3VibmV0KHRoaXMsICdQcml2YXRlU3VibmV0Jywge1xuICAgICAgY29tcGFydG1lbnRJZDogY29uZmlnLmNvbXBhcnRtZW50SWQsXG4gICAgICB2Y25JZDogdmNuLmlkLFxuICAgICAgZGlzcGxheU5hbWU6IGAke2lkfS1wcml2YXRlYCxcbiAgICAgIGNpZHJCbG9jazogJzEwLjAuMi4wLzI0JyxcbiAgICAgIGRuc0xhYmVsOiAncHJpdmF0ZScsXG4gICAgICBwcm9oaWJpdFB1YmxpY0lwT25WbmljOiB0cnVlLFxuICAgIH0pO1xuXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIC8vIFNlY3VyaXR5IExpc3QgZm9yIFB1YmxpYyBTdWJuZXQgKEFQSSBHYXRld2F5KVxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICBjb25zdCBwdWJsaWNTZWN1cml0eUxpc3QgPSBuZXcgQ29yZVNlY3VyaXR5TGlzdCh0aGlzLCAnUHVibGljU2VjdXJpdHlMaXN0Jywge1xuICAgICAgY29tcGFydG1lbnRJZDogY29uZmlnLmNvbXBhcnRtZW50SWQsXG4gICAgICB2Y25JZDogdmNuLmlkLFxuICAgICAgZGlzcGxheU5hbWU6IGAke2lkfS1wdWJsaWMtc2xgLFxuICAgICAgaW5ncmVzc1NlY3VyaXR5UnVsZXM6IFtcbiAgICAgICAge1xuICAgICAgICAgIHByb3RvY29sOiAnNicsIC8vIFRDUFxuICAgICAgICAgIHNvdXJjZTogJzAuMC4wLjAvMCcsXG4gICAgICAgICAgZGVzY3JpcHRpb246ICdBbGxvdyBIVFRQICg4MCkgZnJvbSBpbnRlcm5ldCcsXG4gICAgICAgICAgdGNwT3B0aW9uczoge1xuICAgICAgICAgICAgbWluOiA4MCxcbiAgICAgICAgICAgIG1heDogODAsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIHByb3RvY29sOiAnNicsIC8vIFRDUFxuICAgICAgICAgIHNvdXJjZTogJzAuMC4wLjAvMCcsXG4gICAgICAgICAgZGVzY3JpcHRpb246ICdBbGxvdyBIVFRQUyAoNDQzKSBmcm9tIGludGVybmV0JyxcbiAgICAgICAgICB0Y3BPcHRpb25zOiB7XG4gICAgICAgICAgICBtaW46IDQ0MyxcbiAgICAgICAgICAgIG1heDogNDQzLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgICAgZWdyZXNzU2VjdXJpdHlSdWxlczogW1xuICAgICAgICB7XG4gICAgICAgICAgcHJvdG9jb2w6ICdhbGwnLFxuICAgICAgICAgIGRlc3RpbmF0aW9uOiAnMC4wLjAuMC8wJyxcbiAgICAgICAgICBkZXNjcmlwdGlvbjogJ0FsbG93IGFsbCBvdXRib3VuZCB0cmFmZmljJyxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgfSk7XG5cbiAgICAvLyBBc3NvY2lhdGUgc2VjdXJpdHkgbGlzdCB3aXRoIHB1YmxpYyBzdWJuZXRcbiAgICBwdWJsaWNTdWJuZXQuYWRkT3ZlcnJpZGUoJ3NlY3VyaXR5X2xpc3RfaWRzJywgW3B1YmxpY1NlY3VyaXR5TGlzdC5pZF0pO1xuXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIC8vIFNlY3VyaXR5IExpc3QgZm9yIFByaXZhdGUgU3VibmV0IChGdW5jdGlvbiArIFBHIGluIHNhbWUgc3VibmV0KVxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICBjb25zdCBwcml2YXRlU3VibmV0Q2lkciA9ICcxMC4wLjIuMC8yNCc7XG4gICAgY29uc3QgcHJpdmF0ZVNlY3VyaXR5TGlzdCA9IG5ldyBDb3JlU2VjdXJpdHlMaXN0KHRoaXMsICdQcml2YXRlU2VjdXJpdHlMaXN0Jywge1xuICAgICAgY29tcGFydG1lbnRJZDogY29uZmlnLmNvbXBhcnRtZW50SWQsXG4gICAgICB2Y25JZDogdmNuLmlkLFxuICAgICAgZGlzcGxheU5hbWU6IGAke2lkfS1wcml2YXRlLXNsYCxcbiAgICAgIGluZ3Jlc3NTZWN1cml0eVJ1bGVzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBwcm90b2NvbDogJzYnLCAvLyBUQ1BcbiAgICAgICAgICBzb3VyY2U6IHByaXZhdGVTdWJuZXRDaWRyLFxuICAgICAgICAgIGRlc2NyaXB0aW9uOiAnVENQIHRyYWZmaWMgZm9yIHBvcnRzOiA1NDMyIChQb3N0Z3JlU1FMIGZyb20gcHJpdmF0ZSBzdWJuZXQpJyxcbiAgICAgICAgICB0Y3BPcHRpb25zOiB7XG4gICAgICAgICAgICBtaW46IDU0MzIsXG4gICAgICAgICAgICBtYXg6IDU0MzIsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgICBlZ3Jlc3NTZWN1cml0eVJ1bGVzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBwcm90b2NvbDogJ2FsbCcsXG4gICAgICAgICAgZGVzdGluYXRpb246ICcwLjAuMC4wLzAnLFxuICAgICAgICAgIGRlc2NyaXB0aW9uOiAnQWxsb3cgYWxsIG91dGJvdW5kIHRyYWZmaWMnLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9KTtcblxuICAgIC8vIEFzc29jaWF0ZSBzZWN1cml0eSBsaXN0IHdpdGggcHJpdmF0ZSBzdWJuZXRcbiAgICBwcml2YXRlU3VibmV0LmFkZE92ZXJyaWRlKCdzZWN1cml0eV9saXN0X2lkcycsIFtwcml2YXRlU2VjdXJpdHlMaXN0LmlkXSk7XG5cbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgLy8gU2VydmljZSBHYXRld2F5IChmb3IgT0NJUiBhY2Nlc3MgZnJvbSBwcml2YXRlIHN1Ym5ldClcbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgLy8gR2V0IE9iamVjdCBTdG9yYWdlIHNlcnZpY2UgSUQgKE9DSVIgdXNlcyBPYmplY3QgU3RvcmFnZSlcbiAgICAvLyBHZXQgYWxsIHNlcnZpY2VzIC0gdGhlIGZpcnN0IHNlcnZpY2UgaXMgdHlwaWNhbGx5IFwiQWxsIDxyZWdpb24+IFNlcnZpY2VzIGluIE9yYWNsZSBTZXJ2aWNlcyBOZXR3b3JrXCJcbiAgICAvLyBUaGlzIHNlcnZpY2UgaW5jbHVkZXMgT2JqZWN0IFN0b3JhZ2UgYW5kIG90aGVyIE9DSSBzZXJ2aWNlc1xuICAgIGNvbnN0IGFsbFNlcnZpY2VzID0gbmV3IERhdGFPY2lDb3JlU2VydmljZXModGhpcywgJ0FsbFNlcnZpY2VzJywge30pO1xuXG4gICAgY29uc3Qgc2VydmljZUdhdGV3YXkgPSBuZXcgQ29yZVNlcnZpY2VHYXRld2F5KHRoaXMsICdTZXJ2aWNlR2F0ZXdheScsIHtcbiAgICAgIGNvbXBhcnRtZW50SWQ6IGNvbmZpZy5jb21wYXJ0bWVudElkLFxuICAgICAgdmNuSWQ6IHZjbi5pZCxcbiAgICAgIGRpc3BsYXlOYW1lOiBgJHtpZH0tc2VydmljZS1nYXRld2F5YCxcbiAgICAgIHNlcnZpY2VzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBzZXJ2aWNlSWQ6IGFsbFNlcnZpY2VzLnNlcnZpY2VzLmdldCgwKS5pZCxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgfSk7XG5cbiAgICAvLyBSb3V0ZSB0YWJsZSBmb3IgcHJpdmF0ZSBzdWJuZXQgdG8gcm91dGUgT2JqZWN0IFN0b3JhZ2UgdHJhZmZpYyB2aWEgU2VydmljZSBHYXRld2F5XG4gICAgY29uc3QgcHJpdmF0ZVJvdXRlVGFibGUgPSBuZXcgQ29yZVJvdXRlVGFibGUodGhpcywgJ1ByaXZhdGVSb3V0ZVRhYmxlJywge1xuICAgICAgY29tcGFydG1lbnRJZDogY29uZmlnLmNvbXBhcnRtZW50SWQsXG4gICAgICB2Y25JZDogdmNuLmlkLFxuICAgICAgZGlzcGxheU5hbWU6IGAke2lkfS1wcml2YXRlLXJ0YCxcbiAgICAgIHJvdXRlUnVsZXM6IFtcbiAgICAgICAge1xuICAgICAgICAgIG5ldHdvcmtFbnRpdHlJZDogc2VydmljZUdhdGV3YXkuaWQsXG4gICAgICAgICAgZGVzdGluYXRpb246IGFsbFNlcnZpY2VzLnNlcnZpY2VzLmdldCgwKS5jaWRyQmxvY2ssXG4gICAgICAgICAgZGVzdGluYXRpb25UeXBlOiAnU0VSVklDRV9DSURSX0JMT0NLJyxcbiAgICAgICAgICBkZXNjcmlwdGlvbjogJ1JvdXRlIE9iamVjdCBTdG9yYWdlL09DSVIgdHJhZmZpYyB2aWEgU2VydmljZSBHYXRld2F5JyxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgfSk7XG5cbiAgICAvLyBBc3NvY2lhdGUgcm91dGUgdGFibGUgd2l0aCBwcml2YXRlIHN1Ym5ldFxuICAgIHByaXZhdGVTdWJuZXQuYWRkT3ZlcnJpZGUoJ3JvdXRlX3RhYmxlX2lkJywgcHJpdmF0ZVJvdXRlVGFibGUuaWQpO1xuXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIC8vIEludGVybmV0IEdhdGV3YXkgKGZvciBwdWJsaWMgc3VibmV0IGludGVybmV0IGFjY2VzcylcbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgY29uc3QgaW50ZXJuZXRHYXRld2F5ID0gbmV3IENvcmVJbnRlcm5ldEdhdGV3YXkodGhpcywgJ0ludGVybmV0R2F0ZXdheScsIHtcbiAgICAgIGNvbXBhcnRtZW50SWQ6IGNvbmZpZy5jb21wYXJ0bWVudElkLFxuICAgICAgdmNuSWQ6IHZjbi5pZCxcbiAgICAgIGRpc3BsYXlOYW1lOiBgJHtpZH0taWd3YCxcbiAgICAgIGVuYWJsZWQ6IHRydWUsXG4gICAgfSk7XG5cbiAgICAvLyBSb3V0ZSB0YWJsZSBmb3IgcHVibGljIHN1Ym5ldCB0byByb3V0ZSBpbnRlcm5ldCB0cmFmZmljIHZpYSBJbnRlcm5ldCBHYXRld2F5XG4gICAgY29uc3QgcHVibGljUm91dGVUYWJsZSA9IG5ldyBDb3JlUm91dGVUYWJsZSh0aGlzLCAnUHVibGljUm91dGVUYWJsZScsIHtcbiAgICAgIGNvbXBhcnRtZW50SWQ6IGNvbmZpZy5jb21wYXJ0bWVudElkLFxuICAgICAgdmNuSWQ6IHZjbi5pZCxcbiAgICAgIGRpc3BsYXlOYW1lOiBgJHtpZH0tcHVibGljLXJ0YCxcbiAgICAgIHJvdXRlUnVsZXM6IFtcbiAgICAgICAge1xuICAgICAgICAgIG5ldHdvcmtFbnRpdHlJZDogaW50ZXJuZXRHYXRld2F5LmlkLFxuICAgICAgICAgIGRlc3RpbmF0aW9uOiAnMC4wLjAuMC8wJyxcbiAgICAgICAgICBkZXN0aW5hdGlvblR5cGU6ICdDSURSX0JMT0NLJyxcbiAgICAgICAgICBkZXNjcmlwdGlvbjogJ1JvdXRlIGFsbCBpbnRlcm5ldCB0cmFmZmljIHZpYSBJbnRlcm5ldCBHYXRld2F5JyxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgfSk7XG5cbiAgICAvLyBBc3NvY2lhdGUgcm91dGUgdGFibGUgd2l0aCBwdWJsaWMgc3VibmV0XG4gICAgcHVibGljU3VibmV0LmFkZE92ZXJyaWRlKCdyb3V0ZV90YWJsZV9pZCcsIHB1YmxpY1JvdXRlVGFibGUuaWQpO1xuXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIC8vIFBHIGNvbm5lY3Rpb246IGVpdGhlciBwYXNzIFBHX1VSTCBhcyBmdW5jdGlvbiBjb25maWcsIG9yIGNyZWF0ZSBWYXVsdCBzZWNyZXQgYW5kIHBhc3MgUEdfU0VDUkVUX09DSURcbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgY29uc3QgZnVuY3Rpb25Db25maWc6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7fTtcbiAgICBpZiAoY29uZmlnLnBnVXJsICYmIGNvbmZpZy5wZ1VybC50cmltKCkpIHtcbiAgICAgIGlmIChjb25maWcudmF1bHRPY2lkPy50cmltKCkpIHtcbiAgICAgICAgLy8gVmF1bHQgcGF0aDogcmVxdWlyZSBrZXlPY2lkIGFuZCBjcmVhdGUgcGctdXJsIHNlY3JldFxuICAgICAgICBpZiAoIWNvbmZpZy5rZXlPY2lkPy50cmltKCkpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICAnV2hlbiBPQ0lfVkFVTFRfT0NJRCBpcyBzZXQsIE9DSV9LRVlfT0NJRCBpcyByZXF1aXJlZCB0byBjcmVhdGUgdGhlIHBnLXVybCBzZWNyZXQuICcgK1xuICAgICAgICAgICAgJ1NldCBPQ0lfS0VZX09DSUQgdG8geW91ciBWYXVsdCBlbmNyeXB0aW9uIEtleSBPQ0lELidcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIC8vIEFwcGVuZCByYW5kb20gc3VmZml4IHRvIGF2b2lkIFwibmFtZSBhbHJlYWR5IGV4aXN0c1wiIHdoZW4gYSBzZWNyZXQgd2l0aCB0aGUgc2FtZSBiYXNlIG5hbWUgZXhpc3RzIGluIHRoZSBWYXVsdC5cbiAgICAgICAgLy8gU2V0IFBHX1NFQ1JFVF9TVUZGSVggZW52IHZhciB0byBwaW4gdGhlIG5hbWUgYWNyb3NzIHN5bnRocyAoZS5nLiBQR19TRUNSRVRfU1VGRklYPWFiYzEyMzQ1KS5cbiAgICAgICAgY29uc3QgcGdVcmxTZWNyZXRTdWZmaXggPVxuICAgICAgICAgIHByb2Nlc3MuZW52LlBHX1NFQ1JFVF9TVUZGSVggfHwgY3J5cHRvLnJhbmRvbUJ5dGVzKDQpLnRvU3RyaW5nKCdoZXgnKTtcbiAgICAgICAgY29uc3QgcGdVcmxTZWNyZXROYW1lID0gYCR7aWR9LXBnLXVybC0ke3BnVXJsU2VjcmV0U3VmZml4fWA7XG4gICAgICAgIGNvbnN0IHBnVXJsU2VjcmV0ID0gbmV3IFZhdWx0U2VjcmV0KHRoaXMsICdQZ1VybFNlY3JldCcsIHtcbiAgICAgICAgICBjb21wYXJ0bWVudElkOiBjb25maWcuY29tcGFydG1lbnRJZCxcbiAgICAgICAgICB2YXVsdElkOiBjb25maWcudmF1bHRPY2lkLFxuICAgICAgICAgIGtleUlkOiBjb25maWcua2V5T2NpZCxcbiAgICAgICAgICBzZWNyZXROYW1lOiBwZ1VybFNlY3JldE5hbWUsXG4gICAgICAgICAgZGVzY3JpcHRpb246ICdQb3N0Z3JlU1FMIGNvbm5lY3Rpb24gVVJMIGZvciBmdW5jdGlvbiAoZnJvbSBQR19VUkwpJyxcbiAgICAgICAgICBzZWNyZXRDb250ZW50OiB7XG4gICAgICAgICAgICBjb250ZW50VHlwZTogJ0JBU0U2NCcsXG4gICAgICAgICAgICBjb250ZW50OiBCdWZmZXIuZnJvbShjb25maWcucGdVcmwudHJpbSgpLCAndXRmLTgnKS50b1N0cmluZygnYmFzZTY0JyksXG4gICAgICAgICAgfSxcbiAgICAgICAgfSk7XG4gICAgICAgIGZ1bmN0aW9uQ29uZmlnLlBHX1NFQ1JFVF9PQ0lEID0gcGdVcmxTZWNyZXQuaWQ7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBObyBWYXVsdDogcGFzcyBQR19VUkwgZGlyZWN0bHkgYXMgZnVuY3Rpb24gY29uZmlnIChjbGVhci10ZXh0KVxuICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgJ1tPQ0kgRnVuY3Rpb25dIFdBUk5JTkc6IFBHX1VSTCBpcyBiZWluZyBwYXNzZWQgdG8gdGhlIGZ1bmN0aW9uIGFzIHBsYWluIGNvbmZpZyAoY2xlYXItdGV4dCkuICcgK1xuICAgICAgICAgICdDcmVkZW50aWFscyBhcmUgdmlzaWJsZSBpbiBmdW5jdGlvbiBjb25maWd1cmF0aW9uLiBGb3IgcHJvZHVjdGlvbiwgc3RvcmUgdGhlIGNvbm5lY3Rpb24gc3RyaW5nIGluIE9DSSBWYXVsdCBhbmQgc2V0ICcgK1xuICAgICAgICAgICdPQ0lfVkFVTFRfT0NJRCBhbmQgT0NJX0tFWV9PQ0lEIHNvIHRoZSBzdGFjayBjcmVhdGVzIGEgVmF1bHQgc2VjcmV0OyB0aGUgZnVuY3Rpb24gd2lsbCB0aGVuIHJlY2VpdmUgb25seSBQR19TRUNSRVRfT0NJRC4nXG4gICAgICAgICk7XG4gICAgICAgIGZ1bmN0aW9uQ29uZmlnLlBHX1VSTCA9IGNvbmZpZy5wZ1VybC50cmltKCk7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChjb25maWcucGdTZWNyZXRPY2lkPy50cmltKCkpIHtcbiAgICAgIGZ1bmN0aW9uQ29uZmlnLlBHX1NFQ1JFVF9PQ0lEID0gY29uZmlnLnBnU2VjcmV0T2NpZC50cmltKCk7XG4gICAgfVxuXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIC8vIEFQSSBHYXRld2F5IChwdWJsaWMgc3VibmV0KVxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICBjb25zdCBhcGlHYXRld2F5ID0gbmV3IEFwaWdhdGV3YXlHYXRld2F5KHRoaXMsICdBcGlHYXRld2F5Jywge1xuICAgICAgY29tcGFydG1lbnRJZDogY29uZmlnLmNvbXBhcnRtZW50SWQsXG4gICAgICBzdWJuZXRJZDogcHVibGljU3VibmV0LmlkLFxuICAgICAgZW5kcG9pbnRUeXBlOiAnUFVCTElDJyxcbiAgICAgIGRpc3BsYXlOYW1lOiBgJHtpZH0tYXBpLWdhdGV3YXlgLFxuICAgIH0pO1xuXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIC8vIEZ1bmN0aW9ucyBBcHBsaWNhdGlvbiAocHJpdmF0ZSBzdWJuZXQpIGFuZCBGdW5jdGlvblxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICBjb25zdCBmdW5jdGlvbkFwcCA9IG5ldyBGdW5jdGlvbnNBcHBsaWNhdGlvbih0aGlzLCAnRnVuY3Rpb25BcHAnLCB7XG4gICAgICBjb21wYXJ0bWVudElkOiBjb25maWcuY29tcGFydG1lbnRJZCxcbiAgICAgIGRpc3BsYXlOYW1lOiBjb25maWcuZnVuY3Rpb25BcHBOYW1lLFxuICAgICAgc3VibmV0SWRzOiBbcHJpdmF0ZVN1Ym5ldC5pZF0sXG4gICAgfSk7XG5cbiAgICAvLyBGdW5jdGlvbiBkZXBlbmRzIG9uIGltYWdlIGJlaW5nIHB1c2hlZCB0byBPQ0lSXG4gICAgY29uc3Qgb2NpRnVuY3Rpb24gPSBuZXcgRnVuY3Rpb25zRnVuY3Rpb24odGhpcywgJ0Z1bmN0aW9uJywge1xuICAgICAgYXBwbGljYXRpb25JZDogZnVuY3Rpb25BcHAuaWQsXG4gICAgICBkaXNwbGF5TmFtZTogY29uZmlnLmZ1bmN0aW9uTmFtZSxcbiAgICAgIGltYWdlOiBpbWFnZVVybCxcbiAgICAgIG1lbW9yeUluTWJzOiAnMjU2JyxcbiAgICAgIHRpbWVvdXRJblNlY29uZHM6IDMwLFxuICAgICAgY29uZmlnOiBPYmplY3Qua2V5cyhmdW5jdGlvbkNvbmZpZykubGVuZ3RoID4gMCA/IGZ1bmN0aW9uQ29uZmlnIDogdW5kZWZpbmVkLFxuICAgIH0pO1xuICAgIC8vIEFkZCBkZXBlbmRlbmN5IG9uIG51bGxfcmVzb3VyY2UgdXNpbmcgYWRkT3ZlcnJpZGVcbiAgICAvLyBUaGlzIGVuc3VyZXMgdGhlIGltYWdlIGlzIGJ1aWx0IGFuZCBwdXNoZWQgYmVmb3JlIHRoZSBGdW5jdGlvbiBpcyBjcmVhdGVkXG4gICAgb2NpRnVuY3Rpb24uYWRkT3ZlcnJpZGUoJ2RlcGVuZHNfb24nLCBbYG51bGxfcmVzb3VyY2UuJHtidWlsZEFuZFB1c2hJbWFnZUlkfWBdKTtcblxuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgICAvLyBBUEkgR2F0ZXdheSBEZXBsb3ltZW50IOKAkyByb3V0ZSB0byBmdW5jdGlvbiAob25seSBhZnRlciBmdW5jdGlvbiBleGlzdHMpXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIGNvbnN0IHBhdGhQcmVmaXggPSBjb25maWcuYXBpR3dQYXRoUHJlZml4ID8/ICcvJztcbiAgICBjb25zdCByb3V0ZVBhdGggPSBjb25maWcuYXBpR3dSb3V0ZVBhdGggPz8gJy97cGF0aCp9JztcbiAgICBjb25zdCBtZXRob2RzID0gY29uZmlnLmFwaUd3TWV0aG9kcz8ubGVuZ3RoID8gY29uZmlnLmFwaUd3TWV0aG9kcyA6IFsnR0VUJywgJ1BPU1QnLCAnT1BUSU9OUyddO1xuXG4gICAgY29uc3QgYXBpRGVwbG95bWVudCA9IG5ldyBBcGlnYXRld2F5RGVwbG95bWVudCh0aGlzLCAnQXBpRGVwbG95bWVudCcsIHtcbiAgICAgIGNvbXBhcnRtZW50SWQ6IGNvbmZpZy5jb21wYXJ0bWVudElkLFxuICAgICAgZ2F0ZXdheUlkOiBhcGlHYXRld2F5LmlkLFxuICAgICAgcGF0aFByZWZpeCxcbiAgICAgIGRpc3BsYXlOYW1lOiBgJHtpZH0tZGVwbG95bWVudGAsXG4gICAgICBzcGVjaWZpY2F0aW9uOiB7XG4gICAgICAgIHJvdXRlczogW1xuICAgICAgICAgIHtcbiAgICAgICAgICAgIHBhdGg6IHJvdXRlUGF0aCxcbiAgICAgICAgICAgIG1ldGhvZHMsXG4gICAgICAgICAgICBiYWNrZW5kOiB7XG4gICAgICAgICAgICAgIHR5cGU6ICdPUkFDTEVfRlVOQ1RJT05TX0JBQ0tFTkQnLFxuICAgICAgICAgICAgICBmdW5jdGlvbklkOiBvY2lGdW5jdGlvbi5pZCxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSxcbiAgICAgICAgXSxcbiAgICAgIH0sXG4gICAgfSk7XG4gICAgYXBpRGVwbG95bWVudC5ub2RlLmFkZERlcGVuZGVuY3kob2NpRnVuY3Rpb24pO1xuXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIC8vIE91dHB1dHNcbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgbmV3IFRlcnJhZm9ybU91dHB1dCh0aGlzLCAnb2Npcl9yZXBvc2l0b3J5X25hbWUnLCB7XG4gICAgICB2YWx1ZTogb2NpclJlcG9zaXRvcnkuZGlzcGxheU5hbWUsXG4gICAgICBkZXNjcmlwdGlvbjogJ09DSVIgcmVwb3NpdG9yeSBkaXNwbGF5IG5hbWUnLFxuICAgIH0pO1xuXG4gICAgbmV3IFRlcnJhZm9ybU91dHB1dCh0aGlzLCAnYXBpX2dhdGV3YXlfaG9zdCcsIHtcbiAgICAgIHZhbHVlOiBhcGlHYXRld2F5Lmhvc3RuYW1lLFxuICAgICAgZGVzY3JpcHRpb246ICdBUEkgR2F0ZXdheSBob3N0bmFtZSBmb3IgaW52b2tpbmcgdGhlIGZ1bmN0aW9uJyxcbiAgICB9KTtcblxuICAgIG5ldyBUZXJyYWZvcm1PdXRwdXQodGhpcywgJ2Z1bmN0aW9uX2ludm9rZV91cmwnLCB7XG4gICAgICB2YWx1ZTogYGh0dHBzOi8vJHthcGlHYXRld2F5Lmhvc3RuYW1lfWAsXG4gICAgICBkZXNjcmlwdGlvbjogJ0Jhc2UgVVJMIHRvIGludm9rZSB0aGUgZnVuY3Rpb24gKHVzZSA/YWN0aW9uPWhlbGxvfGVjaG98aW5mbyknLFxuICAgIH0pO1xuXG4gICAgbmV3IFRlcnJhZm9ybU91dHB1dCh0aGlzLCAnZnVuY3Rpb25faWQnLCB7XG4gICAgICB2YWx1ZTogb2NpRnVuY3Rpb24uaWQsXG4gICAgICBkZXNjcmlwdGlvbjogJ09DSSBGdW5jdGlvbiBPQ0lEIChmb3IgZGVwbG95LWZ1bmN0aW9uLnNoIG9yIG9jaSBmbiBmdW5jdGlvbiB1cGRhdGUpJyxcbiAgICB9KTtcbiAgfVxufVxuIl19
|