@pipeline-builder/pipeline-core 0.0.1

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.
Files changed (84) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +69 -0
  3. package/lib/cdk.d.ts +38 -0
  4. package/lib/cdk.js +44 -0
  5. package/lib/config/app-config.d.ts +109 -0
  6. package/lib/config/app-config.js +197 -0
  7. package/lib/config/aws-config-cdk.d.ts +49 -0
  8. package/lib/config/aws-config-cdk.js +65 -0
  9. package/lib/config/billing-config.d.ts +24 -0
  10. package/lib/config/billing-config.js +497 -0
  11. package/lib/config/config-types.d.ts +346 -0
  12. package/lib/config/config-types.js +4 -0
  13. package/lib/config/entitlements.d.ts +23 -0
  14. package/lib/config/entitlements.js +46 -0
  15. package/lib/config/handler-constants.d.ts +10 -0
  16. package/lib/config/handler-constants.js +39 -0
  17. package/lib/config/infrastructure-config.d.ts +66 -0
  18. package/lib/config/infrastructure-config.js +197 -0
  19. package/lib/config/server-config.d.ts +53 -0
  20. package/lib/config/server-config.js +175 -0
  21. package/lib/config/service-client.d.ts +13 -0
  22. package/lib/config/service-client.js +20 -0
  23. package/lib/core/artifact-manager.d.ts +62 -0
  24. package/lib/core/artifact-manager.js +83 -0
  25. package/lib/core/id-generator.d.ts +50 -0
  26. package/lib/core/id-generator.js +50 -0
  27. package/lib/core/metadata-builder.d.ts +48 -0
  28. package/lib/core/metadata-builder.js +278 -0
  29. package/lib/core/metadata-helpers.d.ts +31 -0
  30. package/lib/core/metadata-helpers.js +55 -0
  31. package/lib/core/network-types.d.ts +200 -0
  32. package/lib/core/network-types.js +4 -0
  33. package/lib/core/network.d.ts +33 -0
  34. package/lib/core/network.js +112 -0
  35. package/lib/core/pipeline-helpers.d.ts +61 -0
  36. package/lib/core/pipeline-helpers.js +563 -0
  37. package/lib/core/pipeline-types.d.ts +118 -0
  38. package/lib/core/pipeline-types.js +131 -0
  39. package/lib/core/role-types.d.ts +254 -0
  40. package/lib/core/role-types.js +4 -0
  41. package/lib/core/role.d.ts +14 -0
  42. package/lib/core/role.js +117 -0
  43. package/lib/core/security-group-types.d.ts +84 -0
  44. package/lib/core/security-group-types.js +4 -0
  45. package/lib/core/security-group.d.ts +14 -0
  46. package/lib/core/security-group.js +33 -0
  47. package/lib/handlers/plugin-lookup-handler.d.ts +32 -0
  48. package/lib/handlers/plugin-lookup-handler.js +292 -0
  49. package/lib/handlers/pnpm-lock.yaml +12 -0
  50. package/lib/index.d.ts +45 -0
  51. package/lib/index.js +53 -0
  52. package/lib/pipeline/pipeline-builder.d.ts +123 -0
  53. package/lib/pipeline/pipeline-builder.js +476 -0
  54. package/lib/pipeline/pipeline-configuration.d.ts +81 -0
  55. package/lib/pipeline/pipeline-configuration.js +214 -0
  56. package/lib/pipeline/plugin-lookup.d.ts +131 -0
  57. package/lib/pipeline/plugin-lookup.js +316 -0
  58. package/lib/pipeline/plugin-spec.d.ts +138 -0
  59. package/lib/pipeline/plugin-spec.js +4 -0
  60. package/lib/pipeline/source-builder.d.ts +62 -0
  61. package/lib/pipeline/source-builder.js +164 -0
  62. package/lib/pipeline/source-types.d.ts +221 -0
  63. package/lib/pipeline/source-types.js +4 -0
  64. package/lib/pipeline/stage-builder.d.ts +78 -0
  65. package/lib/pipeline/stage-builder.js +129 -0
  66. package/lib/pipeline/step-types.d.ts +222 -0
  67. package/lib/pipeline/step-types.js +4 -0
  68. package/lib/template/evaluator.d.ts +42 -0
  69. package/lib/template/evaluator.js +164 -0
  70. package/lib/template/index.d.ts +34 -0
  71. package/lib/template/index.js +118 -0
  72. package/lib/template/metrics.d.ts +10 -0
  73. package/lib/template/metrics.js +43 -0
  74. package/lib/template/plugin-resolver.d.ts +8 -0
  75. package/lib/template/plugin-resolver.js +48 -0
  76. package/lib/template/tokenizer.d.ts +49 -0
  77. package/lib/template/tokenizer.js +233 -0
  78. package/lib/template/topo-sort.d.ts +17 -0
  79. package/lib/template/topo-sort.js +88 -0
  80. package/lib/template/validate.d.ts +45 -0
  81. package/lib/template/validate.js +96 -0
  82. package/lib/template/walker.d.ts +34 -0
  83. package/lib/template/walker.js +83 -0
  84. package/package.json +184 -0
@@ -0,0 +1,563 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { createLogger, SYSTEM_ORG_ID } from '@pipeline-builder/api-core';
4
+ import { Duration, SecretValue, Stack } from 'aws-cdk-lib';
5
+ import { BuildEnvironmentVariableType, BuildSpec, ComputeType as CDKComputeType, LinuxBuildImage } from 'aws-cdk-lib/aws-codebuild';
6
+ import { Secret } from 'aws-cdk-lib/aws-secretsmanager';
7
+ import { CodeBuildStep, ManualApprovalStep, ShellStep } from 'aws-cdk-lib/pipelines';
8
+ import { metadataForShellStep, metadataForCodeBuildStep, metadataForBuildEnvironment, networkConfigFromMetadata } from './metadata-builder.js';
9
+ import { extractMetadataEnv, merge } from './metadata-helpers.js';
10
+ import { resolveNetwork } from './network.js';
11
+ import { PluginType, ComputeType } from './pipeline-types.js';
12
+ import { Config, CoreConstants } from '../config/app-config.js';
13
+ import { resolvePluginTemplates } from '../template/plugin-resolver.js';
14
+ const log = createLogger('pipeline-helpers');
15
+ /**
16
+ * Build environment variables from plugin config, merged metadata, and custom env.
17
+ *
18
+ * Merge order (last wins):
19
+ * 1. plugin.env — plugin default env vars (lowest priority)
20
+ * 2. non-namespaced metadata keys — e.g. PYTHON_VERSION, WORKDIR
21
+ * 3. customEnv — per-step custom env vars (highest priority)
22
+ */
23
+ const BOOTSTRAP_CMD = 'export WORKDIR=${WORKDIR:-./}; cd ${WORKDIR}';
24
+ function buildEnv(plugin, metadata, customEnv) {
25
+ return {
26
+ ...(plugin.env ?? {}),
27
+ ...extractMetadataEnv(metadata),
28
+ ...(customEnv ?? {}),
29
+ };
30
+ }
31
+ /**
32
+ * Wrap build commands based on failure behavior.
33
+ * - 'fail' (default): No wrapping — commands fail the pipeline naturally.
34
+ * - 'warn': Run commands with `set +e`, capture failures, log warnings, continue.
35
+ * - 'ignore': Append `|| true` to each command — failures are silently swallowed.
36
+ *
37
+ * Only applied to build commands, not install commands (install failures should always stop the build).
38
+ */
39
+ function wrapCommandsForFailureBehavior(commands, behavior) {
40
+ if (!behavior || behavior === 'fail')
41
+ return commands;
42
+ if (behavior === 'ignore') {
43
+ return commands.map(cmd => `${cmd} || true`);
44
+ }
45
+ // 'warn': run all commands, capture failures, but don't stop
46
+ return [
47
+ 'set +e',
48
+ '_STEP_EXIT=0',
49
+ ...commands.map(cmd => `${cmd} || { echo "WARNING: Command failed with exit code $?"; _STEP_EXIT=1; }`),
50
+ 'set -e',
51
+ 'if [ "$_STEP_EXIT" -ne 0 ]; then echo "WARNING: One or more commands in this step failed"; fi',
52
+ ];
53
+ }
54
+ /**
55
+ * Build bootstrap-prefixed install and build commands from plugin config.
56
+ * Each command list is prepended with a WORKDIR bootstrap that defaults to './'.
57
+ * When custom commands are provided, they are injected before/after the plugin's commands.
58
+ * Build commands are optionally wrapped by failureBehavior logic.
59
+ */
60
+ function buildCommands(plugin, custom, failureBehavior) {
61
+ const userCommands = [
62
+ ...(custom?.preCommands ?? []),
63
+ ...(plugin.commands?.length ? plugin.commands : []),
64
+ ...(custom?.postCommands ?? []),
65
+ ];
66
+ return {
67
+ installCommands: [
68
+ BOOTSTRAP_CMD,
69
+ ...(custom?.preInstallCommands ?? []),
70
+ ...(plugin.installCommands ?? []),
71
+ ...(custom?.postInstallCommands ?? []),
72
+ ],
73
+ commands: [BOOTSTRAP_CMD, ...wrapCommandsForFailureBehavior(userCommands, failureBehavior)],
74
+ };
75
+ }
76
+ /**
77
+ * Convert a plain env record to CodeBuild's environmentVariables format (PLAINTEXT).
78
+ */
79
+ function toCodeBuildEnvVars(env) {
80
+ return Object.fromEntries(Object.entries(env).map(([name, value]) => [name, { value }]));
81
+ }
82
+ /**
83
+ * Build SECRETS_MANAGER-type environment variables from plugin secret declarations.
84
+ * Uses naming convention: pipeline-builder/{orgId}/{secretName}
85
+ * Each org manages these secrets in their own AWS Secrets Manager.
86
+ */
87
+ const VALID_SECRET_NAME = /^[a-zA-Z0-9/_+=.@-]+$/;
88
+ function toSecretEnvVars(secrets, orgId) {
89
+ return Object.fromEntries(secrets.map(({ name }) => {
90
+ const secretPath = CoreConstants.secretPath(orgId, name);
91
+ if (!VALID_SECRET_NAME.test(secretPath)) {
92
+ throw new Error(`Secret path "${secretPath}" contains invalid characters for AWS Secrets Manager`);
93
+ }
94
+ return [
95
+ name,
96
+ {
97
+ value: secretPath,
98
+ type: BuildEnvironmentVariableType.SECRETS_MANAGER,
99
+ },
100
+ ];
101
+ }));
102
+ }
103
+ /**
104
+ * In-cluster / local registry hostnames that AWS CodeBuild (out-of-cluster)
105
+ * cannot resolve. Baking one of these into a CodeBuild image URI guarantees a
106
+ * `BUILD_CONTAINER_UNABLE_TO_PULL_IMAGE` failure at build time, so we fail the
107
+ * synth fast instead — with a message that says how to fix it.
108
+ */
109
+ const UNREACHABLE_PULL_HOSTS = new Set(['registry', 'localhost', '127.0.0.1', '::1', '0.0.0.0']);
110
+ /** Kubernetes / mDNS suffixes that only resolve inside the cluster/LAN. */
111
+ const UNREACHABLE_HOST_SUFFIXES = ['.svc', '.svc.cluster.local', '.local'];
112
+ /**
113
+ * Reduce a registry host value to its bare hostname for the reachability check:
114
+ * strip IPv6 brackets and any `:port` suffix (an operator may put host+port in
115
+ * one field), so `registry:5000` / `[::1]:5000` are still recognized.
116
+ */
117
+ function bareHostname(rawHost) {
118
+ let h = rawHost.trim().toLowerCase();
119
+ if (h.startsWith('[')) {
120
+ const end = h.indexOf(']');
121
+ if (end !== -1)
122
+ return h.slice(1, end); // [::1]:5000 -> ::1
123
+ }
124
+ // Strip a trailing :port only for non-IPv6 values (IPv6 contains '::' or >1 ':').
125
+ if (h.includes(':') && (h.match(/:/g)?.length ?? 0) === 1)
126
+ h = h.split(':')[0];
127
+ return h;
128
+ }
129
+ /** True when CodeBuild (out-of-cluster) could not resolve this registry host. */
130
+ function isUnreachablePullHost(rawHost) {
131
+ const h = bareHostname(rawHost);
132
+ if (h === '')
133
+ return true; // no host → malformed URI
134
+ if (UNREACHABLE_PULL_HOSTS.has(h))
135
+ return true;
136
+ return UNREACHABLE_HOST_SUFFIXES.some((s) => h.endsWith(s));
137
+ }
138
+ /**
139
+ * Resolve the external (out-of-cluster) registry pull host + `:port` suffix for
140
+ * a CodeBuild image URI, and fail fast if it resolved to an in-cluster/local
141
+ * default that CodeBuild can't reach.
142
+ *
143
+ * Prefers `pullHost`/`pullPort` (the public endpoint CodeBuild can resolve) and
144
+ * falls back to `host`/`port` for single-host deploys. pipeline-manager bakes
145
+ * the right pull host into the synth automatically from the platform URL it
146
+ * deploys against (`props.registry`); this guard catches the case where neither
147
+ * that nor `IMAGE_REGISTRY_PULL_HOST`/`PLATFORM_BASE_URL` was supplied.
148
+ *
149
+ * Escape hatch: `ALLOW_INCLUSTER_PULL_HOST=true` (e.g. CodeBuild in a VPC whose
150
+ * private DNS genuinely resolves the in-cluster name).
151
+ */
152
+ function resolveExternalPullTarget(registry) {
153
+ const host = registry.pullHost || registry.host || '';
154
+ const port = registry.pullPort ?? registry.port;
155
+ if (process.env.ALLOW_INCLUSTER_PULL_HOST !== 'true' && isUnreachablePullHost(host)) {
156
+ throw new Error(`Registry pull host resolved to '${host}', which AWS CodeBuild cannot reach — it is the ` +
157
+ 'in-cluster/local default. The synthesized pipeline would fail at build time with ' +
158
+ 'BUILD_CONTAINER_UNABLE_TO_PULL_IMAGE. Set the platform\'s public host via ' +
159
+ 'IMAGE_REGISTRY_PULL_HOST or PLATFORM_BASE_URL before deploying — pipeline-manager bakes ' +
160
+ 'this in automatically from the platform URL it deploys against. ' +
161
+ 'Set ALLOW_INCLUSTER_PULL_HOST=true to bypass (in-VPC private DNS).');
162
+ }
163
+ const portPart = port && port !== 80 && port !== 443 ? `:${port}` : '';
164
+ return { host, portPart };
165
+ }
166
+ /**
167
+ * Resolve the CodeBuild image to use for a plugin.
168
+ *
169
+ * Strategy:
170
+ * 1. If the plugin sets `aws:cdk:codebuild:buildenvironment:buildImage`
171
+ * explicitly in metadata, the metadata-builder passthrough handles it
172
+ * (via `metadataForBuildEnvironment`). This function returns
173
+ * `undefined` and the metadata wins.
174
+ * 2. Otherwise, if the plugin has a `name`+`version` AND the registry
175
+ * config is populated, build a `LinuxBuildImage.fromDockerRegistry()`
176
+ * image pointing at `<registry-host>:<port>/<ns>/<name>:<version>`
177
+ * where `<ns>` is `system` or `org-<orgId>`. CodeBuild authenticates by
178
+ * sending the per-org platform Secret as Basic auth to
179
+ * `pipeline-image-registry`'s `/token` endpoint; the JWT in `password`
180
+ * resolves to a registry token scoped to the org.
181
+ * 3. If `metadata_only`, return `undefined` so CodeBuild uses its default
182
+ * (`standard:7.0`).
183
+ *
184
+ * `scope` and `orgId` are required: the per-org platform Secret is named
185
+ * `pipeline-builder/<orgId>/platform`, and `Secret.fromSecretNameV2()`
186
+ * needs a Construct to anchor the imported secret to.
187
+ */
188
+ export function resolvePluginImage(scope, plugin, orgId) {
189
+ // `metadata_only` plugins legitimately have no image — their work runs
190
+ // in the default CodeBuild image. Quiet skip.
191
+ if (plugin.buildType === 'metadata_only')
192
+ return undefined;
193
+ // build_image / prebuilt plugins must have name + version (DB constraint
194
+ // makes both NOT NULL). Defensive check in case a malformed row slips in.
195
+ if (!plugin.name || !plugin.version) {
196
+ log.warn(`Plugin "${plugin.name}" has buildType=${plugin.buildType} but missing name/version — ` +
197
+ 'CodeBuild will run on aws/codebuild/standard:8.0 and won\'t have the plugin\'s baked tools.');
198
+ return undefined;
199
+ }
200
+ let registry;
201
+ try {
202
+ registry = Config.get('registry');
203
+ }
204
+ catch {
205
+ // Config namespace not loaded (e.g., unit tests without full config).
206
+ log.warn(`Plugin "${plugin.name}:${plugin.version}" needs the registry config but it's not loaded — ` +
207
+ 'CodeBuild will fall back to aws/codebuild/standard:8.0. ' +
208
+ 'Set IMAGE_REGISTRY_HOST + IMAGE_REGISTRY_PORT in pipeline-manager\'s environment.');
209
+ return undefined;
210
+ }
211
+ if (!registry?.host) {
212
+ log.warn(`Plugin "${plugin.name}:${plugin.version}" needs IMAGE_REGISTRY_HOST but it's empty — ` +
213
+ 'CodeBuild will fall back to aws/codebuild/standard:8.0. ' +
214
+ 'Set IMAGE_REGISTRY_HOST in pipeline-manager\'s environment to use the plugin image.');
215
+ return undefined;
216
+ }
217
+ if (!scope) {
218
+ log.warn(`Plugin "${plugin.name}" image resolution skipped: no construct scope provided`);
219
+ return undefined;
220
+ }
221
+ // Per-org auth requires orgId — the Secret is named per org.
222
+ if (!orgId) {
223
+ log.warn(`Plugin "${plugin.name}" image resolution skipped: orgId is required to ` +
224
+ 'resolve the per-org platform Secret used for CodeBuild Basic auth.');
225
+ return undefined;
226
+ }
227
+ // Compose the image URI. Namespace by ownership:
228
+ // - Plugins owned by the system org → `system/<name>:<version>`.
229
+ // pipeline-image-registry's token service grants pull on `system/*`
230
+ // to any authenticated org user (read-only catalog of shared plugins).
231
+ // - Plugins owned by a tenant org → `org-<orgId>/<name>:<version>`.
232
+ // The token service grants pull,push only to members of that org.
233
+ // The plugin's own `orgId` (not the caller's) decides the namespace —
234
+ // tenant pipelines pulling shared system plugins still get the `system/`
235
+ // path because that's where the image actually lives.
236
+ // Use the external pull host/port: this image URI is consumed by AWS
237
+ // CodeBuild (out-of-cluster), which can't resolve the in-cluster
238
+ // `registry:5000` ClusterIP. Fall back to `host`/`port` for single-host /
239
+ // in-cluster-only deploys where no separate pull host is configured.
240
+ const { host: pullHost, portPart } = resolveExternalPullTarget(registry);
241
+ // Must match the PUSH side (api/plugin pluginUri) exactly, or a system
242
+ // plugin's image is pushed to `system/…` but this synth pulls from
243
+ // `org-<objectid>/…` → build-time pull failure. `SYSTEM_ORG_ID` is the
244
+ // well-known ObjectId (NOT the string 'system').
245
+ const namespace = plugin.orgId === SYSTEM_ORG_ID ? 'system' : `org-${plugin.orgId}`;
246
+ const imageUri = `${pullHost}${portPart}/${namespace}/${plugin.name}:${plugin.version}`;
247
+ // CodeBuild reads `pipeline-builder/<orgId>/platform` and sends its
248
+ // `username`/`password` fields as HTTP Basic to the registry. The
249
+ // registry challenges with a Bearer realm pointing at
250
+ // pipeline-image-registry's `/token` endpoint; the Docker client forwards
251
+ // those creds, the password is verified as a platform JWT, and a registry
252
+ // token scoped to the org is issued.
253
+ //
254
+ // Same Secret is read by the plugin-lookup Lambda (via the `password`
255
+ // field) — one Secret serves both flows.
256
+ const stack = Stack.of(scope);
257
+ const secretName = CoreConstants.secretPath(orgId, 'platform');
258
+ // CDK construct IDs allow only [A-Za-z0-9_-]; sanitize the secret name.
259
+ const secretConstructId = `PlatformCreds_${secretName.replace(/[^A-Za-z0-9_-]/g, '_')}`;
260
+ const credentialsSecret = stack.node.tryFindChild(secretConstructId)
261
+ ?? Secret.fromSecretNameV2(stack, secretConstructId, secretName);
262
+ return LinuxBuildImage.fromDockerRegistry(imageUri, {
263
+ secretsManagerCredentials: credentialsSecret,
264
+ });
265
+ }
266
+ /**
267
+ * Resolve the fallback CodeBuild image for steps without a plugin-baked one.
268
+ *
269
+ * Reads `aws.codeBuild.defaultImage` (env: `CODEBUILD_DEFAULT_IMAGE`).
270
+ * Default: `pipeline-bootstrap:1.0` — the local tag built by
271
+ * `deploy/codebuild/bootstrap/Dockerfile`.
272
+ *
273
+ * - AWS curated image (`aws/codebuild/*`): use the matching `LinuxBuildImage`
274
+ * constant so CDK emits `imagePullCredentialsType: CODEBUILD`. Using
275
+ * `fromDockerRegistry()` here would set SERVICE_ROLE credentials, which
276
+ * CFN rejects with "cannot use a CodeBuild curated image with
277
+ * imagePullCredentialsType SERVICE_ROLE".
278
+ * - Bare tag (no `/`): auto-prefixed to
279
+ * `<registry-host>:<port>/library/<tag>` using the registry config,
280
+ * with the per-org platform Secret as Basic auth — same path
281
+ * `resolvePluginImage()` uses for plugin images. Needs `scope` + `orgId`.
282
+ * - Fully-qualified registry URI (contains `/`): used as-is, no auth wired.
283
+ * - Missing registry config or scope/orgId → falls back to
284
+ * `aws/codebuild/standard:8.0` (as a CURATED image, see above), with a
285
+ * warning so synth degrades gracefully on partially configured envs.
286
+ */
287
+ const STANDARD_8_0 = 'aws/codebuild/standard:8.0';
288
+ /**
289
+ * aws-cdk-lib 2.258 has no `LinuxBuildImage.STANDARD_8_0` static yet, so the
290
+ * curated 8.0 fallback resolves via `fromCodeBuildImageId` (still CODEBUILD creds).
291
+ */
292
+ const fallbackBuildImage = () => LinuxBuildImage.fromCodeBuildImageId(STANDARD_8_0);
293
+ /**
294
+ * Map AWS curated `aws/codebuild/*` image strings to the matching
295
+ * `LinuxBuildImage` static. Extend when newer standard images ship.
296
+ * Returns `undefined` for non-curated strings — caller should use
297
+ * `fromDockerRegistry()` for those.
298
+ */
299
+ function curatedLinuxBuildImage(imageId) {
300
+ if (!imageId.startsWith('aws/codebuild/'))
301
+ return undefined;
302
+ switch (imageId) {
303
+ case 'aws/codebuild/standard:6.0': return LinuxBuildImage.STANDARD_6_0;
304
+ case 'aws/codebuild/standard:5.0': return LinuxBuildImage.STANDARD_5_0;
305
+ // Newer codenamed images route through fromCodeBuildImageId, which
306
+ // CDK also marks as CODEBUILD credentials (curated).
307
+ default: return LinuxBuildImage.fromCodeBuildImageId(imageId);
308
+ }
309
+ }
310
+ export function resolveDefaultBuildImage(scope, orgId) {
311
+ let configured;
312
+ try {
313
+ configured = Config.get('aws').codeBuild.defaultImage;
314
+ }
315
+ catch {
316
+ configured = STANDARD_8_0;
317
+ }
318
+ // AWS curated image → CODEBUILD credentials. MUST go through the
319
+ // LinuxBuildImage constants, not fromDockerRegistry().
320
+ const curated = curatedLinuxBuildImage(configured);
321
+ if (curated)
322
+ return curated;
323
+ // Fully-qualified URI — operator owns it. No registry/Secret wiring.
324
+ if (configured.includes('/')) {
325
+ return LinuxBuildImage.fromDockerRegistry(configured);
326
+ }
327
+ // Bare tag → auto-prefix with the platform registry, mirroring
328
+ // resolvePluginImage(). Bail to the curated standard:8.0 fallback
329
+ // (with a warning) at each missing prerequisite so synth degrades
330
+ // gracefully on partially configured environments instead of failing.
331
+ let registry;
332
+ try {
333
+ registry = Config.get('registry');
334
+ }
335
+ catch {
336
+ log.warn(`CODEBUILD_DEFAULT_IMAGE='${configured}' is a bare tag but registry config not loaded — ` +
337
+ `falling back to ${STANDARD_8_0}. Set IMAGE_REGISTRY_HOST + IMAGE_REGISTRY_PORT.`);
338
+ return fallbackBuildImage();
339
+ }
340
+ if (!registry?.host) {
341
+ log.warn(`CODEBUILD_DEFAULT_IMAGE='${configured}' is a bare tag but IMAGE_REGISTRY_HOST is empty — ` +
342
+ `falling back to ${STANDARD_8_0}.`);
343
+ return fallbackBuildImage();
344
+ }
345
+ if (!scope || !orgId) {
346
+ log.warn(`CODEBUILD_DEFAULT_IMAGE='${configured}' needs scope+orgId for Secret auth — ` +
347
+ `falling back to ${STANDARD_8_0}. (Caller did not supply them.)`);
348
+ return fallbackBuildImage();
349
+ }
350
+ // Use the external pull host/port (not the in-cluster host) — this URI is
351
+ // consumed by AWS CodeBuild, which can't resolve the `registry:5000` ClusterIP.
352
+ const { host: pullHost, portPart } = resolveExternalPullTarget(registry);
353
+ const imageUri = `${pullHost}${portPart}/library/${configured}`;
354
+ // Same Secret as resolvePluginImage — per-org platform Secret, CodeBuild
355
+ // sends it as Basic auth, image-registry verifies the JWT in `password`.
356
+ const stack = Stack.of(scope);
357
+ const secretName = CoreConstants.secretPath(orgId, 'platform');
358
+ const secretConstructId = `PlatformCreds_${secretName.replace(/[^A-Za-z0-9_-]/g, '_')}`;
359
+ const credentialsSecret = stack.node.tryFindChild(secretConstructId)
360
+ ?? Secret.fromSecretNameV2(stack, secretConstructId, secretName);
361
+ return LinuxBuildImage.fromDockerRegistry(imageUri, {
362
+ secretsManagerCredentials: credentialsSecret,
363
+ });
364
+ }
365
+ /**
366
+ * Create a CodeBuild step or Shell step based on plugin configuration.
367
+ *
368
+ * Metadata merge order (last wins):
369
+ * 1. Plugin metadata (from plugin.metadata in database) — the plugin
370
+ * author's baked-in defaults
371
+ * 2. Step-level metadata (from options.metadata) — the pipeline author's
372
+ * per-step overrides, which are more specific and must win
373
+ *
374
+ * Environment merge order (last wins):
375
+ * 1. Plugin env vars (from plugin.env)
376
+ * 2. Custom env vars (from options.env)
377
+ * 3. WORKDIR from merged metadata
378
+ *
379
+ * CDK prop spread order (last wins):
380
+ * programmatic defaults (input, commands, env, network) → metadata overrides
381
+ *
382
+ * This means metadata keys like `aws:cdk:pipelines:codebuildstep:commands`
383
+ * will override the plugin-derived commands when explicitly set.
384
+ */
385
+ export function createCodeBuildStep(options) {
386
+ const { id, input, metadata, network, scope, preInstallCommands, postInstallCommands, preCommands, postCommands, env: customEnv, additionalInputs, timeout, failureBehavior, artifactManager, stageName, stageAlias, pluginAlias, orgId, pipelineScope, } = options;
387
+ // Resolve {{ ... }} templates in plugin spec fields against the pipeline scope.
388
+ // Every call goes through the resolver — plugins without template tokens are
389
+ // a no-op fast path inside resolvePluginTemplates().
390
+ const plugin = resolvePluginTemplates(options.plugin, pipelineScope);
391
+ // Per-step metadata (the pipeline author's overrides, e.g. JAVA_VERSION=25)
392
+ // must win over the plugin's catalog `metadata` defaults, so it goes LAST.
393
+ // Reversing these silently dropped per-step overrides for any plugin that
394
+ // ships non-empty catalog metadata (plugins that carry defaults under `env`
395
+ // instead — like java-corretto — were unaffected, which masked this).
396
+ const merged = merge(plugin.metadata ?? {}, metadata ?? {});
397
+ // ManualApprovalStep: no commands, env, compute, or network — just id + optional comment
398
+ if (plugin.pluginType === PluginType.MANUAL_APPROVAL_STEP) {
399
+ return new ManualApprovalStep(id, {
400
+ comment: typeof merged.APPROVAL_COMMENT === 'string' ? merged.APPROVAL_COMMENT : undefined,
401
+ });
402
+ }
403
+ log.debug('[CreateCodeBuildStep] Building step with merged metadata');
404
+ // Warn about required secrets without orgId (can't resolve)
405
+ const requiredSecrets = plugin.secrets?.filter(s => s.required) ?? [];
406
+ if (requiredSecrets.length > 0 && !orgId) {
407
+ log.warn(`Plugin "${plugin.name}" declares ${requiredSecrets.length} required secret(s) but no orgId is available. ` +
408
+ `Secrets will not be injected: ${requiredSecrets.map(s => s.name).join(', ')}`);
409
+ }
410
+ // Resolve plugin secrets as SECRETS_MANAGER env vars — only REQUIRED ones.
411
+ // CodeBuild treats a SECRETS_MANAGER env var as MANDATORY: it fails the build
412
+ // at DOWNLOAD_SOURCE ("ResourceNotFoundException: can't find the specified
413
+ // secret") if the secret is absent. Auto-wiring an OPTIONAL secret
414
+ // (`required: false`, e.g. NVD_API_KEY / SEMGREP_APP_TOKEN) the operator hasn't
415
+ // created would therefore break every build — the exact opposite of "optional".
416
+ // Optional secrets are left for the plugin to read only where the operator has
417
+ // provisioned them (out-of-band env/secret), not force-injected here.
418
+ const secretEnvVars = (requiredSecrets.length && orgId)
419
+ ? toSecretEnvVars(requiredSecrets, orgId)
420
+ : {};
421
+ const env = buildEnv(plugin, merged, customEnv);
422
+ // CodePipeline resolved variables — must be in CodeBuildStep.env (action-level),
423
+ // not buildEnvironment.environmentVariables (project-level)
424
+ const actionEnv = {
425
+ PIPELINE_EXECUTION_ID: '#{codepipeline.PipelineExecutionId}',
426
+ };
427
+ const outputDir = plugin.primaryOutputDirectory;
428
+ const ensureOutputDir = (outputDir && !outputDir.includes('*'))
429
+ ? [`mkdir -p "${outputDir}" && touch "${outputDir}/.gitkeep"`]
430
+ : [];
431
+ const { installCommands, commands } = buildCommands(plugin, {
432
+ preInstallCommands: [...ensureOutputDir, ...(preInstallCommands ?? [])],
433
+ postInstallCommands,
434
+ preCommands,
435
+ postCommands,
436
+ }, failureBehavior);
437
+ const programmatic = { input, installCommands, commands };
438
+ // Resolve the plugin's runtime image. CodeBuild defaults to
439
+ // `aws/codebuild/standard:7.0` when no `buildImage` is set — that's the
440
+ // AWS-managed Ubuntu image and DOES NOT have any plugin-baked tools
441
+ // (pipeline-manager, snyk, terraform, etc.). Wiring the plugin's image
442
+ // here means CodeBuild pulls from our private registry and the tools
443
+ // installed in the plugin's Dockerfile are actually available.
444
+ const pluginBuildImage = resolvePluginImage(scope, plugin, orgId);
445
+ // ShellStep branch.
446
+ // ShellStep itself doesn't accept `buildEnvironment`/`buildImage`. CDK
447
+ // pipelines wraps ShellSteps in a default CodeBuild action that runs on
448
+ // `aws/codebuild/standard:7.0` — which won't have the plugin's tools.
449
+ //
450
+ // So when a SHELL_STEP plugin DOES have an image (because its author
451
+ // baked tools into a Dockerfile), we PROMOTE it to a CodeBuildStep with
452
+ // the resolved image. The plugin author's intent ("use my baked tools")
453
+ // is preserved without forcing them to change pluginType.
454
+ //
455
+ // When the plugin has no image (or registry isn't configured), we keep
456
+ // the original ShellStep — it's lighter weight and the default
457
+ // CodeBuild image is fine.
458
+ if (plugin.pluginType === PluginType.SHELL_STEP) {
459
+ if (!pluginBuildImage) {
460
+ return new ShellStep(id, {
461
+ ...programmatic,
462
+ env: { ...env, ...actionEnv },
463
+ ...metadataForShellStep(merged),
464
+ });
465
+ }
466
+ log.debug(`[CreateCodeBuildStep] SHELL_STEP plugin "${plugin.name}" has a registry image — promoting to CodeBuildStep so the plugin image is actually used`);
467
+ // Fall through to the CodeBuildStep path below.
468
+ }
469
+ const computeType = getComputeType(plugin.computeType ?? options.defaultComputeType ?? 'SMALL');
470
+ // Step network: explicit step config wins, else this step's `ec2:network` metadata.
471
+ const resolvedNetwork = network ?? networkConfigFromMetadata(merged);
472
+ const networkProps = resolvedNetwork
473
+ ? resolveNetwork(scope, options.uniqueId, resolvedNetwork)
474
+ : {};
475
+ // Metadata spread last so it can override programmatic defaults.
476
+ // NOTE: Caching is supported via two metadata paths:
477
+ // 1. MetadataKeys.CACHE ('aws:cdk:pipelines:codebuildstep:cache') — passed directly
478
+ // as the CodeBuildStep `cache` prop (expects a codebuild.Cache object).
479
+ // 2. MetadataKeys.PARTIAL_BUILD_SPEC ('aws:cdk:pipelines:codebuildstep:partialbuildspec')
480
+ // — passed as `partialBuildSpec`, which can include a `cache:` section for
481
+ // S3 or local caching (e.g., BuildSpec.fromObject({ cache: { paths: [...] } })).
482
+ // Per-step buildEnvironment overrides from metadata (aws:cdk:codebuild:buildenvironment:*).
483
+ // A metadata-provided computeType is a raw passthrough, so normalize it through
484
+ // getComputeType — otherwise a friendly value like "LARGE" reaches CodeBuild verbatim
485
+ // and fails with "Invalid compute type provided" (it needs BUILD_GENERAL1_LARGE).
486
+ const rawMetaBuildEnv = metadataForBuildEnvironment(merged);
487
+ const metaBuildEnv = typeof rawMetaBuildEnv.computeType === 'string'
488
+ ? { ...rawMetaBuildEnv, computeType: getComputeType(rawMetaBuildEnv.computeType) }
489
+ : rawMetaBuildEnv;
490
+ const step = new CodeBuildStep(id, {
491
+ ...programmatic,
492
+ ...networkProps,
493
+ ...(additionalInputs && { additionalInputs }),
494
+ ...(timeout && { timeout: Duration.minutes(timeout) }),
495
+ env: actionEnv,
496
+ primaryOutputDirectory: plugin.primaryOutputDirectory ?? undefined,
497
+ // Pin the buildspec shell to POSIX /bin/sh so execution is identical to
498
+ // CodeBuild's default and portable across minimal base images (no bash
499
+ // dependency). Plugin specs are authored POSIX-clean to match — no bash-only
500
+ // `[[ ]]`, arrays, `read -ra <<<`, or `source`/`nvm use`/`sdk use`. A
501
+ // plugin-supplied partialBuildSpec (none today) would override this via the
502
+ // metadata spread below and must then set `env.shell` itself.
503
+ partialBuildSpec: BuildSpec.fromObject({ env: { shell: '/bin/sh' } }),
504
+ buildEnvironment: {
505
+ computeType,
506
+ buildImage: pluginBuildImage ?? resolveDefaultBuildImage(scope, orgId),
507
+ environmentVariables: {
508
+ ...toCodeBuildEnvVars(env),
509
+ ...secretEnvVars,
510
+ },
511
+ ...metaBuildEnv,
512
+ },
513
+ ...metadataForCodeBuildStep(merged),
514
+ });
515
+ // Register with artifact manager if primaryOutputDirectory is set
516
+ if (plugin.primaryOutputDirectory && artifactManager && stageName) {
517
+ const artifactKey = {
518
+ stageName,
519
+ stageAlias: stageAlias ?? `${stageName}-alias`,
520
+ pluginName: plugin.name,
521
+ pluginAlias: pluginAlias ?? `${plugin.name}-alias`,
522
+ outputDirectory: plugin.primaryOutputDirectory,
523
+ };
524
+ artifactManager.add(artifactKey, step);
525
+ }
526
+ return step;
527
+ }
528
+ /**
529
+ * Convert string or ComputeType enum to CDK ComputeType
530
+ */
531
+ export function getComputeType(input = 'SMALL') {
532
+ // If already a CDK ComputeType, return as-is
533
+ if (typeof input !== 'string') {
534
+ return input;
535
+ }
536
+ // Already a native CodeBuild ComputeType (e.g. "BUILD_GENERAL1_LARGE")? Accept as-is
537
+ // so both friendly (LARGE) and native values round-trip without falling back to SMALL.
538
+ if (Object.values(CDKComputeType).includes(input)) {
539
+ return input;
540
+ }
541
+ const normalized = input.toUpperCase();
542
+ const mapping = {
543
+ [ComputeType.SMALL]: CDKComputeType.SMALL,
544
+ [ComputeType.MEDIUM]: CDKComputeType.MEDIUM,
545
+ [ComputeType.LARGE]: CDKComputeType.LARGE,
546
+ [ComputeType.X2_LARGE]: CDKComputeType.X2_LARGE,
547
+ };
548
+ const result = mapping[normalized];
549
+ if (!result) {
550
+ log.warn(`Unknown compute type "${input}", falling back to SMALL`);
551
+ return CDKComputeType.SMALL;
552
+ }
553
+ return result;
554
+ }
555
+ /**
556
+ * Unwrap a SecretValue | string into a plain string.
557
+ * When a SecretValue is provided (e.g. from Secrets Manager), calls unsafeUnwrap()
558
+ * to extract the underlying value.
559
+ */
560
+ export function unwrapSecret(value) {
561
+ return typeof value === 'string' ? value : value.unsafeUnwrap();
562
+ }
563
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGlwZWxpbmUtaGVscGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb3JlL3BpcGVsaW5lLWhlbHBlcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0QyxPQUFPLEVBQUUsWUFBWSxFQUFFLGFBQWEsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBRXpFLE9BQU8sRUFBRSxRQUFRLEVBQUUsV0FBVyxFQUFFLEtBQUssRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUMzRCxPQUFPLEVBQUUsNEJBQTRCLEVBQUUsU0FBUyxFQUFFLFdBQVcsSUFBSSxjQUFjLEVBQUUsZUFBZSxFQUFvQixNQUFNLDJCQUEyQixDQUFDO0FBQ3RKLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUN4RCxPQUFPLEVBQUUsYUFBYSxFQUFFLGtCQUFrQixFQUFFLFNBQVMsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBR3JGLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSx3QkFBd0IsRUFBRSwyQkFBMkIsRUFBRSx5QkFBeUIsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQy9JLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxLQUFLLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUNsRSxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQzlDLE9BQU8sRUFBRSxVQUFVLEVBQUUsV0FBVyxFQUFxQixNQUFNLHFCQUFxQixDQUFDO0FBQ2pGLE9BQU8sRUFBRSxNQUFNLEVBQUUsYUFBYSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFFaEUsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFFeEUsTUFBTSxHQUFHLEdBQUcsWUFBWSxDQUFDLGtCQUFrQixDQUFDLENBQUM7QUFFN0M7Ozs7Ozs7R0FPRztBQUNILE1BQU0sYUFBYSxHQUFHLDhDQUE4QyxDQUFDO0FBRXJFLFNBQVMs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QyxLQUFLLENBQUMsRUFBRSxjQUFjLENBQUMsS0FBSztRQUN6QyxDQUFDLFdBQVcsQ0FBQyxRQUFRLENBQUMsRUFBRSxjQUFjLENBQUMsUUFBUTtLQUNoRCxDQUFDO0lBRUYsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQ25DLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUNaLEdBQUcsQ0FBQyxJQUFJLENBQUMseUJBQXlCLEtBQUssMEJBQTBCLENBQUMsQ0FBQztRQUNuRSxPQUFPLGNBQWMsQ0FBQyxLQUFLLENBQUM7SUFDOUIsQ0FBQztJQUNELE9BQU8sTUFBTSxDQUFDO0FBQ2hCLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsTUFBTSxVQUFVLFlBQVksQ0FBQyxLQUEyQjtJQUN0RCxPQUFPLE9BQU8sS0FBSyxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUFFLENBQUM7QUFDbEUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgeyBjcmVhdGVMb2dnZXIsIFNZU1RFTV9PUkdfSUQgfSBmcm9tICdAcGlwZWxpbmUtYnVpbGRlci9hcGktY29yZSc7XG5pbXBvcnQgdHlwZSB7IFBsdWdpbiB9IGZyb20gJ0BwaXBlbGluZS1idWlsZGVyL3BpcGVsaW5lLWRhdGEnO1xuaW1wb3J0IHsgRHVyYXRpb24sIFNlY3JldFZhbHVlLCBTdGFjayB9IGZyb20gJ2F3cy1jZGstbGliJztcbmltcG9ydCB7IEJ1aWxkRW52aXJvbm1lbnRWYXJpYWJsZVR5cGUsIEJ1aWxkU3BlYywgQ29tcHV0ZVR5cGUgYXMgQ0RLQ29tcHV0ZVR5cGUsIExpbnV4QnVpbGRJbWFnZSwgdHlwZSBJQnVpbGRJbWFnZSB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1jb2RlYnVpbGQnO1xuaW1wb3J0IHsgU2VjcmV0IH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLXNlY3JldHNtYW5hZ2VyJztcbmltcG9ydCB7IENvZGVCdWlsZFN0ZXAsIE1hbnVhbEFwcHJvdmFsU3RlcCwgU2hlbGxTdGVwIH0gZnJvbSAnYXdzLWNkay1saWIvcGlwZWxpbmVzJztcbmltcG9ydCB0eXBlIHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgdHlwZSB7IEFydGlmYWN0S2V5IH0gZnJvbSAnLi9hcnRpZmFjdC1tYW5hZ2VyLmpzJztcbmltcG9ydCB7IG1ldGFkYXRhRm9yU2hlbGxTdGVwLCBtZXRhZGF0YUZvckNvZGVCdWlsZFN0ZXAsIG1ldGFkYXRhRm9yQnVpbGRFbnZpcm9ubWVudCwgbmV0d29ya0NvbmZpZ0Zyb21NZXRhZGF0YSB9IGZyb20gJy4vbWV0YWRhdGEtYnVpbGRlci5qcyc7XG5pbXBvcnQgeyBleHRyYWN0TWV0YWRhdGFFbnYsIG1lcmdlIH0gZnJvbSAnLi9tZXRhZGF0YS1oZWxwZXJzLmpzJztcbmltcG9ydCB7IHJlc29sdmVOZXR3b3JrIH0gZnJvbSAnLi9uZXR3b3JrLmpzJztcbmltcG9ydCB7IFBsdWdpblR5cGUsIENvbXB1dGVUeXBlLCB0eXBlIE1ldGFEYXRhVHlwZSB9IGZyb20gJy4vcGlwZWxpbmUtdHlwZXMuanMnO1xuaW1wb3J0IHsgQ29uZmlnLCBDb3JlQ29uc3RhbnRzIH0gZnJvbSAnLi4vY29uZmlnL2FwcC1jb25maWcuanMnO1xuaW1wb3J0IHR5cGUgeyBDb2RlQnVpbGRTdGVwT3B0aW9ucywgU3RlcEN1c3RvbWl6YXRpb24gfSBmcm9tICcuLi9waXBlbGluZS9zdGVwLXR5cGVzLmpzJztcbmltcG9ydCB7IHJlc29sdmVQbHVnaW5UZW1wbGF0ZXMgfSBmcm9tICcuLi90ZW1wbGF0ZS9wbHVnaW4tcmVzb2x2ZXIuanMnO1xuXG5jb25zdCBsb2cgPSBjcmVhdGVMb2dnZXIoJ3BpcGVsaW5lLWhlbHBlcnMnKTtcblxuLyoqXG4gKiBCdWlsZCBlbnZpcm9ubWVudCB2YXJpYWJsZXMgZnJvbSBwbHVnaW4gY29uZmlnLCBtZXJnZWQgbWV0YWRhdGEsIGFuZCBjdXN0b20gZW52LlxuICpcbiAqIE1lcmdlIG9yZGVyIChsYXN0IHdpbnMpOlxuICogICAxLiBwbHVnaW4uZW52IOKAlCBwbHVnaW4gZGVmYXVsdCBlbnYgdmFycyAobG93ZXN0IHByaW9yaXR5KVxuICogICAyLiBub24tbmFtZXNwYWNlZCBtZXRhZGF0YSBrZXlzIOKAlCBlLmcuIFBZVEhPTl9WRVJTSU9OLCBXT1JLRElSXG4gKiAgIDMuIGN1c3RvbUVudiDigJQgcGVyLXN0ZXAgY3VzdG9tIGVudiB2YXJzIChoaWdoZXN0IHByaW9yaXR5KVxuICovXG5jb25zdCBCT09UU1RSQVBfQ01EID0gJ2V4cG9ydCBXT1JLRElSPSR7V09SS0RJUjotLi99OyBjZCAke1dPUktESVJ9JztcblxuZnVuY3Rpb24gYnVpbGRFbnYocGx1Z2luOiBQbHVnaW4sIG1ldGFkYXRhOiBNZXRhRGF0YVR5cGUsIGN1c3RvbUVudj86IFJlY29yZDxzdHJpbmcsIHN0cmluZz4pOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IHtcbiAgcmV0dXJuIHtcbiAgICAuLi4ocGx1Z2luLmVudiA/PyB7fSksXG4gICAgLi4uZXh0cmFjdE1ldGFkYXRhRW52KG1ldGFkYXRhKSxcbiAgICAuLi4oY3VzdG9tRW52ID8/IHt9KSxcbiAgfTtcbn1cblxuLyoqXG4gKiBXcmFwIGJ1aWxkIGNvbW1hbmRzIGJhc2VkIG9uIGZhaWx1cmUgYmVoYXZpb3IuXG4gKiAtICdmYWlsJyAoZGVmYXVsdCk6IE5vIHdyYXBwaW5nIOKAlCBjb21tYW5kcyBmYWlsIHRoZSBwaXBlbGluZSBuYXR1cmFsbHkuXG4gKiAtICd3YXJuJzogUnVuIGNvbW1hbmRzIHdpdGggYHNldCArZWAsIGNhcHR1cmUgZmFpbHVyZXMsIGxvZyB3YXJuaW5ncywgY29udGludWUuXG4gKiAtICdpZ25vcmUnOiBBcHBlbmQgYHx8IHRydWVgIHRvIGVhY2ggY29tbWFuZCDigJQgZmFpbHVyZXMgYXJlIHNpbGVudGx5IHN3YWxsb3dlZC5cbiAqXG4gKiBPbmx5IGFwcGxpZWQgdG8gYnVpbGQgY29tbWFuZHMsIG5vdCBpbnN0YWxsIGNvbW1hbmRzIChpbnN0YWxsIGZhaWx1cmVzIHNob3VsZCBhbHdheXMgc3RvcCB0aGUgYnVpbGQpLlxuICovXG5mdW5jdGlvbiB3cmFwQ29tbWFuZHNGb3JGYWlsdXJlQmVoYXZpb3IoY29tbWFuZHM6IHN0cmluZ1tdLCBiZWhhdmlvcj86ICdmYWlsJyB8ICd3YXJuJyB8ICdpZ25vcmUnKTogc3RyaW5nW10ge1xuICBpZiAoIWJlaGF2aW9yIHx8IGJlaGF2aW9yID09PSAnZmFpbCcpIHJldHVybiBjb21tYW5kcztcblxuICBpZiAoYmVoYXZpb3IgPT09ICdpZ25vcmUnKSB7XG4gICAgcmV0dXJuIGNvbW1hbmRzLm1hcChjbWQgPT4gYCR7Y21kfSB8fCB0cnVlYCk7XG4gIH1cblxuICAvLyAnd2Fybic6IHJ1biBhbGwgY29tbWFuZHMsIGNhcHR1cmUgZmFpbHVyZXMsIGJ1dCBkb24ndCBzdG9wXG4gIHJldHVybiBbXG4gICAgJ3NldCArZScsXG4gICAgJ19TVEVQX0VYSVQ9MCcsXG4gICAgLi4uY29tbWFuZHMubWFwKGNtZCA9PiBgJHtjbWR9IHx8IHsgZWNobyBcIldBUk5JTkc6IENvbW1hbmQgZmFpbGVkIHdpdGggZXhpdCBjb2RlICQ/XCI7IF9TVEVQX0VYSVQ9MTsgfWApLFxuICAgICdzZXQgLWUnLFxuICAgICdpZiBbIFwiJF9TVEVQX0VYSVRcIiAtbmUgMCBdOyB0aGVuIGVjaG8gXCJXQVJOSU5HOiBPbmUgb3IgbW9yZSBjb21tYW5kcyBpbiB0aGlzIHN0ZXAgZmFpbGVkXCI7IGZpJyxcbiAgXTtcbn1cblxuLyoqXG4gKiBCdWlsZCBib290c3RyYXAtcHJlZml4ZWQgaW5zdGFsbCBhbmQgYnVpbGQgY29tbWFuZHMgZnJvbSBwbHVnaW4gY29uZmlnLlxuICogRWFjaCBjb21tYW5kIGxpc3QgaXMgcHJlcGVuZGVkIHdpdGggYSBXT1JLRElSIGJvb3RzdHJhcCB0aGF0IGRlZmF1bHRzIHRvICcuLycuXG4gKiBXaGVuIGN1c3RvbSBjb21tYW5kcyBhcmUgcHJvdmlkZWQsIHRoZXkgYXJlIGluamVjdGVkIGJlZm9yZS9hZnRlciB0aGUgcGx1Z2luJ3MgY29tbWFuZHMuXG4gKiBCdWlsZCBjb21tYW5kcyBhcmUgb3B0aW9uYWxseSB3cmFwcGVkIGJ5IGZhaWx1cmVCZWhhdmlvciBsb2dpYy5cbiAqL1xuZnVuY3Rpb24gYnVpbGRDb21tYW5kcyhwbHVnaW46IFBsdWdpbiwgY3VzdG9tPzogU3RlcEN1c3RvbWl6YXRpb24sIGZhaWx1cmVCZWhhdmlvcj86ICdmYWlsJyB8ICd3YXJuJyB8ICdpZ25vcmUnKTogeyBpbnN0YWxsQ29tbWFuZHM6IHN0cmluZ1tdOyBjb21tYW5kczogc3RyaW5nW10gfSB7XG4gIGNvbnN0IHVzZXJDb21tYW5kcyA9IFtcbiAgICAuLi4oY3VzdG9tPy5wcmVDb21tYW5kcyA/PyBbXSksXG4gICAgLi4uKHBsdWdpbi5jb21tYW5kcz8ubGVuZ3RoID8gcGx1Z2luLmNvbW1hbmRzIDogW10pLFxuICAgIC4uLihjdXN0b20/LnBvc3RDb21tYW5kcyA/PyBbXSksXG4gIF07XG5cbiAgcmV0dXJuIHtcbiAgICBpbnN0YWxsQ29tbWFuZHM6IFtcbiAgICAgIEJPT1RTVFJBUF9DTUQsXG4gICAgICAuLi4oY3VzdG9tPy5wcmVJbnN0YWxsQ29tbWFuZHMgPz8gW10pLFxuICAgICAgLi4uKHBsdWdpbi5pbnN0YWxsQ29tbWFuZHMgPz8gW10pLFxuICAgICAgLi4uKGN1c3RvbT8ucG9zdEluc3RhbGxDb21tYW5kcyA/PyBbXSksXG4gICAgXSxcbiAgICBjb21tYW5kczogW0JPT1RTVFJBUF9DTUQsIC4uLndyYXBDb21tYW5kc0ZvckZhaWx1cmVCZWhhdmlvcih1c2VyQ29tbWFuZHMsIGZhaWx1cmVCZWhhdmlvcildLFxuICB9O1xufVxuXG4vKipcbiAqIENvbnZlcnQgYSBwbGFpbiBlbnYgcmVjb3JkIHRvIENvZGVCdWlsZCdzIGVudmlyb25tZW50VmFyaWFibGVzIGZvcm1hdCAoUExBSU5URVhUKS5cbiAqL1xuZnVuY3Rpb24gdG9Db2RlQnVpbGRFbnZWYXJzKGVudjogUmVjb3JkPHN0cmluZywgc3RyaW5nPik6IFJlY29yZDxzdHJpbmcsIHsgdmFsdWU6IHN0cmluZyB9PiB7XG4gIHJldHVybiBPYmplY3QuZnJvbUVudHJpZXMoXG4gICAgT2JqZWN0LmVudHJpZXMoZW52KS5tYXAoKFtuYW1lLCB2YWx1ZV0pID0+IFtuYW1lLCB7IHZhbHVlIH1dKSxcbiAgKTtcbn1cblxuLyoqXG4gKiBCdWlsZCBTRUNSRVRTX01BTkFHRVItdHlwZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgZnJvbSBwbHVnaW4gc2VjcmV0IGRlY2xhcmF0aW9ucy5cbiAqIFVzZXMgbmFtaW5nIGNvbnZlbnRpb246IHBpcGVsaW5lLWJ1aWxkZXIve29yZ0lkfS97c2VjcmV0TmFtZX1cbiAqIEVhY2ggb3JnIG1hbmFnZXMgdGhlc2Ugc2VjcmV0cyBpbiB0aGVpciBvd24gQVdTIFNlY3JldHMgTWFuYWdlci5cbiAqL1xuY29uc3QgVkFMSURfU0VDUkVUX05BTUUgPSAvXlthLXpBLVowLTkvXys9LkAtXSskLztcblxuZnVuY3Rpb24gdG9TZWNyZXRFbnZWYXJzKFxuICBzZWNyZXRzOiBBcnJheTx7IG5hbWU6IHN0cmluZzsgcmVxdWlyZWQ6IGJvb2xlYW4gfT4sXG4gIG9yZ0lkOiBzdHJpbmcsXG4pOiBSZWNvcmQ8c3RyaW5nLCB7IHZhbHVlOiBzdHJpbmc7IHR5cGU6IEJ1aWxkRW52aXJvbm1lbnRWYXJpYWJsZVR5cGUgfT4ge1xuICByZXR1cm4gT2JqZWN0LmZyb21FbnRyaWVzKFxuICAgIHNlY3JldHMubWFwKCh7IG5hbWUgfSkgPT4ge1xuICAgICAgY29uc3Qgc2VjcmV0UGF0aCA9IENvcmVDb25zdGFudHMuc2VjcmV0UGF0aChvcmdJZCwgbmFtZSk7XG4gICAgICBpZiAoIVZBTElEX1NFQ1JFVF9OQU1FLnRlc3Qoc2VjcmV0UGF0aCkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBTZWNyZXQgcGF0aCBcIiR7c2VjcmV0UGF0aH1cIiBjb250YWlucyBpbnZhbGlkIGNoYXJhY3RlcnMgZm9yIEFXUyBTZWNyZXRzIE1hbmFnZXJgKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBbXG4gICAgICAgIG5hbWUsXG4gICAgICAgIHtcbiAgICAgICAgICB2YWx1ZTogc2VjcmV0UGF0aCxcbiAgICAgICAgICB0eXBlOiBCdWlsZEVudmlyb25tZW50VmFyaWFibGVUeXBlLlNFQ1JFVFNfTUFOQUdFUixcbiAgICAgICAgfSxcbiAgICAgIF07XG4gICAgfSksXG4gICk7XG59XG5cbi8qKlxuICogSW4tY2x1c3RlciAvIGxvY2FsIHJlZ2lzdHJ5IGhvc3RuYW1lcyB0aGF0IEFXUyBDb2RlQnVpbGQgKG91dC1vZi1jbHVzdGVyKVxuICogY2Fubm90IHJlc29sdmUuIEJha2luZyBvbmUgb2YgdGhlc2UgaW50byBhIENvZGVCdWlsZCBpbWFnZSBVUkkgZ3VhcmFudGVlcyBhXG4gKiBgQlVJTERfQ09OVEFJTkVSX1VOQUJMRV9UT19QVUxMX0lNQUdFYCBmYWlsdXJlIGF0IGJ1aWxkIHRpbWUsIHNvIHdlIGZhaWwgdGhlXG4gKiBzeW50aCBmYXN0IGluc3RlYWQg4oCUIHdpdGggYSBtZXNzYWdlIHRoYXQgc2F5cyBob3cgdG8gZml4IGl0LlxuICovXG5jb25zdCBVTlJFQUNIQUJMRV9QVUxMX0hPU1RTID0gbmV3IFNldChbJ3JlZ2lzdHJ5JywgJ2xvY2FsaG9zdCcsICcxMjcuMC4wLjEnLCAnOjoxJywgJzAuMC4wLjAnXSk7XG5cbi8qKiBLdWJlcm5ldGVzIC8gbUROUyBzdWZmaXhlcyB0aGF0IG9ubHkgcmVzb2x2ZSBpbnNpZGUgdGhlIGNsdXN0ZXIvTEFOLiAqL1xuY29uc3QgVU5SRUFDSEFCTEVfSE9TVF9TVUZGSVhFUyA9IFsnLnN2YycsICcuc3ZjLmNsdXN0ZXIubG9jYWwnLCAnLmxvY2FsJ107XG5cbi8qKlxuICogUmVkdWNlIGEgcmVnaXN0cnkgaG9zdCB2YWx1ZSB0byBpdHMgYmFyZSBob3N0bmFtZSBmb3IgdGhlIHJlYWNoYWJpbGl0eSBjaGVjazpcbiAqIHN0cmlwIElQdjYgYnJhY2tldHMgYW5kIGFueSBgOnBvcnRgIHN1ZmZpeCAoYW4gb3BlcmF0b3IgbWF5IHB1dCBob3N0K3BvcnQgaW5cbiAqIG9uZSBmaWVsZCksIHNvIGByZWdpc3RyeTo1MDAwYCAvIGBbOjoxXTo1MDAwYCBhcmUgc3RpbGwgcmVjb2duaXplZC5cbiAqL1xuZnVuY3Rpb24gYmFyZUhvc3RuYW1lKHJhd0hvc3Q6IHN0cmluZyk6IHN0cmluZyB7XG4gIGxldCBoID0gcmF3SG9zdC50cmltKCkudG9Mb3dlckNhc2UoKTtcbiAgaWYgKGguc3RhcnRzV2l0aCgnWycpKSB7XG4gICAgY29uc3QgZW5kID0gaC5pbmRleE9mKCddJyk7XG4gICAgaWYgKGVuZCAhPT0gLTEpIHJldHVybiBoLnNsaWNlKDEsIGVuZCk7IC8vIFs6OjFdOjUwMDAgLT4gOjoxXG4gIH1cbiAgLy8gU3RyaXAgYSB0cmFpbGluZyA6cG9ydCBvbmx5IGZvciBub24tSVB2NiB2YWx1ZXMgKElQdjYgY29udGFpbnMgJzo6JyBvciA+MSAnOicpLlxuICBpZiAoaC5pbmNsdWRlcygnOicpICYmIChoLm1hdGNoKC86L2cpPy5sZW5ndGggPz8gMCkgPT09IDEpIGggPSBoLnNwbGl0KCc6JylbMF07XG4gIHJldHVybiBoO1xufVxuXG4vKiogVHJ1ZSB3aGVuIENvZGVCdWlsZCAob3V0LW9mLWNsdXN0ZXIpIGNvdWxkIG5vdCByZXNvbHZlIHRoaXMgcmVnaXN0cnkgaG9zdC4gKi9cbmZ1bmN0aW9uIGlzVW5yZWFjaGFibGVQdWxsSG9zdChyYXdIb3N0OiBzdHJpbmcpOiBib29sZWFuIHtcbiAgY29uc3QgaCA9IGJhcmVIb3N0bmFtZShyYXdIb3N0KTtcbiAgaWYgKGggPT09ICcnKSByZXR1cm4gdHJ1ZTsgLy8gbm8gaG9zdCDihpIgbWFsZm9ybWVkIFVSSVxuICBpZiAoVU5SRUFDSEFCTEVfUFVMTF9IT1NUUy5oYXMoaCkpIHJldHVybiB0cnVlO1xuICByZXR1cm4gVU5SRUFDSEFCTEVfSE9TVF9TVUZGSVhFUy5zb21lKChzKSA9PiBoLmVuZHNXaXRoKHMpKTtcbn1cblxuLyoqXG4gKiBSZXNvbHZlIHRoZSBleHRlcm5hbCAob3V0LW9mLWNsdXN0ZXIpIHJlZ2lzdHJ5IHB1bGwgaG9zdCArIGA6cG9ydGAgc3VmZml4IGZvclxuICogYSBDb2RlQnVpbGQgaW1hZ2UgVVJJLCBhbmQgZmFpbCBmYXN0IGlmIGl0IHJlc29sdmVkIHRvIGFuIGluLWNsdXN0ZXIvbG9jYWxcbiAqIGRlZmF1bHQgdGhhdCBDb2RlQnVpbGQgY2FuJ3QgcmVhY2guXG4gKlxuICogUHJlZmVycyBgcHVsbEhvc3RgL2BwdWxsUG9ydGAgKHRoZSBwdWJsaWMgZW5kcG9pbnQgQ29kZUJ1aWxkIGNhbiByZXNvbHZlKSBhbmRcbiAqIGZhbGxzIGJhY2sgdG8gYGhvc3RgL2Bwb3J0YCBmb3Igc2luZ2xlLWhvc3QgZGVwbG95cy4gcGlwZWxpbmUtbWFuYWdlciBiYWtlc1xuICogdGhlIHJpZ2h0IHB1bGwgaG9zdCBpbnRvIHRoZSBzeW50aCBhdXRvbWF0aWNhbGx5IGZyb20gdGhlIHBsYXRmb3JtIFVSTCBpdFxuICogZGVwbG95cyBhZ2FpbnN0IChgcHJvcHMucmVnaXN0cnlgKTsgdGhpcyBndWFyZCBjYXRjaGVzIHRoZSBjYXNlIHdoZXJlIG5laXRoZXJcbiAqIHRoYXQgbm9yIGBJTUFHRV9SRUdJU1RSWV9QVUxMX0hPU1RgL2BQTEFURk9STV9CQVNFX1VSTGAgd2FzIHN1cHBsaWVkLlxuICpcbiAqIEVzY2FwZSBoYXRjaDogYEFMTE9XX0lOQ0xVU1RFUl9QVUxMX0hPU1Q9dHJ1ZWAgKGUuZy4gQ29kZUJ1aWxkIGluIGEgVlBDIHdob3NlXG4gKiBwcml2YXRlIEROUyBnZW51aW5lbHkgcmVzb2x2ZXMgdGhlIGluLWNsdXN0ZXIgbmFtZSkuXG4gKi9cbmZ1bmN0aW9uIHJlc29sdmVFeHRlcm5hbFB1bGxUYXJnZXQoXG4gIHJlZ2lzdHJ5OiB7IGhvc3Q/OiBzdHJpbmc7IHBvcnQ/OiBudW1iZXI7IHB1bGxIb3N0Pzogc3RyaW5nOyBwdWxsUG9ydD86IG51bWJlciB9LFxuKTogeyBob3N0OiBzdHJpbmc7IHBvcnRQYXJ0OiBzdHJpbmcgfSB7XG4gIGNvbnN0IGhvc3QgPSByZWdpc3RyeS5wdWxsSG9zdCB8fCByZWdpc3RyeS5ob3N0IHx8ICcnO1xuICBjb25zdCBwb3J0ID0gcmVnaXN0cnkucHVsbFBvcnQgPz8gcmVnaXN0cnkucG9ydDtcbiAgaWYgKHByb2Nlc3MuZW52LkFMTE9XX0lOQ0xVU1RFUl9QVUxMX0hPU1QgIT09ICd0cnVlJyAmJiBpc1VucmVhY2hhYmxlUHVsbEhvc3QoaG9zdCkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgUmVnaXN0cnkgcHVsbCBob3N0IHJlc29sdmVkIHRvICcke2hvc3R9Jywgd2hpY2ggQVdTIENvZGVCdWlsZCBjYW5ub3QgcmVhY2gg4oCUIGl0IGlzIHRoZSBgICtcbiAgICAgICdpbi1jbHVzdGVyL2xvY2FsIGRlZmF1bHQuIFRoZSBzeW50aGVzaXplZCBwaXBlbGluZSB3b3VsZCBmYWlsIGF0IGJ1aWxkIHRpbWUgd2l0aCAnICtcbiAgICAgICdCVUlMRF9DT05UQUlORVJfVU5BQkxFX1RPX1BVTExfSU1BR0UuIFNldCB0aGUgcGxhdGZvcm1cXCdzIHB1YmxpYyBob3N0IHZpYSAnICtcbiAgICAgICdJTUFHRV9SRUdJU1RSWV9QVUxMX0hPU1Qgb3IgUExBVEZPUk1fQkFTRV9VUkwgYmVmb3JlIGRlcGxveWluZyDigJQgcGlwZWxpbmUtbWFuYWdlciBiYWtlcyAnICtcbiAgICAgICd0aGlzIGluIGF1dG9tYXRpY2FsbHkgZnJvbSB0aGUgcGxhdGZvcm0gVVJMIGl0IGRlcGxveXMgYWdhaW5zdC4gJyArXG4gICAgICAnU2V0IEFMTE9XX0lOQ0xVU1RFUl9QVUxMX0hPU1Q9dHJ1ZSB0byBieXBhc3MgKGluLVZQQyBwcml2YXRlIEROUykuJyxcbiAgICApO1xuICB9XG4gIGNvbnN0IHBvcnRQYXJ0ID0gcG9ydCAmJiBwb3J0ICE9PSA4MCAmJiBwb3J0ICE9PSA0NDMgPyBgOiR7cG9ydH1gIDogJyc7XG4gIHJldHVybiB7IGhvc3QsIHBvcnRQYXJ0IH07XG59XG5cbi8qKlxuICogUmVzb2x2ZSB0aGUgQ29kZUJ1aWxkIGltYWdlIHRvIHVzZSBmb3IgYSBwbHVnaW4uXG4gKlxuICogU3RyYXRlZ3k6XG4gKiAgIDEuIElmIHRoZSBwbHVnaW4gc2V0cyBgYXdzOmNkazpjb2RlYnVpbGQ6YnVpbGRlbnZpcm9ubWVudDpidWlsZEltYWdlYFxuICogICAgICBleHBsaWNpdGx5IGluIG1ldGFkYXRhLCB0aGUgbWV0YWRhdGEtYnVpbGRlciBwYXNzdGhyb3VnaCBoYW5kbGVzIGl0XG4gKiAgICAgICh2aWEgYG1ldGFkYXRhRm9yQnVpbGRFbnZpcm9ubWVudGApLiBUaGlzIGZ1bmN0aW9uIHJldHVybnNcbiAqICAgICAgYHVuZGVmaW5lZGAgYW5kIHRoZSBtZXRhZGF0YSB3aW5zLlxuICogICAyLiBPdGhlcndpc2UsIGlmIHRoZSBwbHVnaW4gaGFzIGEgYG5hbWVgK2B2ZXJzaW9uYCBBTkQgdGhlIHJlZ2lzdHJ5XG4gKiAgICAgIGNvbmZpZyBpcyBwb3B1bGF0ZWQsIGJ1aWxkIGEgYExpbnV4QnVpbGRJbWFnZS5mcm9tRG9ja2VyUmVnaXN0cnkoKWBcbiAqICAgICAgaW1hZ2UgcG9pbnRpbmcgYXQgYDxyZWdpc3RyeS1ob3N0Pjo8cG9ydD4vPG5zPi88bmFtZT46PHZlcnNpb24+YFxuICogICAgICB3aGVyZSBgPG5zPmAgaXMgYHN5c3RlbWAgb3IgYG9yZy08b3JnSWQ+YC4gQ29kZUJ1aWxkIGF1dGhlbnRpY2F0ZXMgYnlcbiAqICAgICAgc2VuZGluZyB0aGUgcGVyLW9yZyBwbGF0Zm9ybSBTZWNyZXQgYXMgQmFzaWMgYXV0aCB0b1xuICogICAgICBgcGlwZWxpbmUtaW1hZ2UtcmVnaXN0cnlgJ3MgYC90b2tlbmAgZW5kcG9pbnQ7IHRoZSBKV1QgaW4gYHBhc3N3b3JkYFxuICogICAgICByZXNvbHZlcyB0byBhIHJlZ2lzdHJ5IHRva2VuIHNjb3BlZCB0byB0aGUgb3JnLlxuICogICAzLiBJZiBgbWV0YWRhdGFfb25seWAsIHJldHVybiBgdW5kZWZpbmVkYCBzbyBDb2RlQnVpbGQgdXNlcyBpdHMgZGVmYXVsdFxuICogICAgICAoYHN0YW5kYXJkOjcuMGApLlxuICpcbiAqIGBzY29wZWAgYW5kIGBvcmdJZGAgYXJlIHJlcXVpcmVkOiB0aGUgcGVyLW9yZyBwbGF0Zm9ybSBTZWNyZXQgaXMgbmFtZWRcbiAqIGBwaXBlbGluZS1idWlsZGVyLzxvcmdJZD4vcGxhdGZvcm1gLCBhbmQgYFNlY3JldC5mcm9tU2VjcmV0TmFtZVYyKClgXG4gKiBuZWVkcyBhIENvbnN0cnVjdCB0byBhbmNob3IgdGhlIGltcG9ydGVkIHNlY3JldCB0by5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVQbHVnaW5JbWFnZShzY29wZTogQ29uc3RydWN0IHwgdW5kZWZpbmVkLCBwbHVnaW46IFBsdWdpbiwgb3JnSWQ/OiBzdHJpbmcpOiBJQnVpbGRJbWFnZSB8IHVuZGVmaW5lZCB7XG4gIC8vIGBtZXRhZGF0YV9vbmx5YCBwbHVnaW5zIGxlZ2l0aW1hdGVseSBoYXZlIG5vIGltYWdlIOKAlCB0aGVpciB3b3JrIHJ1bnNcbiAgLy8gaW4gdGhlIGRlZmF1bHQgQ29kZUJ1aWxkIGltYWdlLiBRdWlldCBza2lwLlxuICBpZiAocGx1Z2luLmJ1aWxkVHlwZSA9PT0gJ21ldGFkYXRhX29ubHknKSByZXR1cm4gdW5kZWZpbmVkO1xuXG4gIC8vIGJ1aWxkX2ltYWdlIC8gcHJlYnVpbHQgcGx1Z2lucyBtdXN0IGhhdmUgbmFtZSArIHZlcnNpb24gKERCIGNvbnN0cmFpbnRcbiAgLy8gbWFrZXMgYm90aCBOT1QgTlVMTCkuIERlZmVuc2l2ZSBjaGVjayBpbiBjYXNlIGEgbWFsZm9ybWVkIHJvdyBzbGlwcyBpbi5cbiAgaWYgKCFwbHVnaW4ubmFtZSB8fCAhcGx1Z2luLnZlcnNpb24pIHtcbiAgICBsb2cud2FybihcbiAgICAgIGBQbHVnaW4gXCIke3BsdWdpbi5uYW1lfVwiIGhhcyBidWlsZFR5cGU9JHtwbHVnaW4uYnVpbGRUeXBlfSBidXQgbWlzc2luZyBuYW1lL3ZlcnNpb24g4oCUIGAgK1xuICAgICAgJ0NvZGVCdWlsZCB3aWxsIHJ1biBvbiBhd3MvY29kZWJ1aWxkL3N0YW5kYXJkOjguMCBhbmQgd29uXFwndCBoYXZlIHRoZSBwbHVnaW5cXCdzIGJha2VkIHRvb2xzLicsXG4gICAgKTtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG5cbiAgbGV0IHJlZ2lzdHJ5O1xuICB0cnkge1xuICAgIHJlZ2lzdHJ5ID0gQ29uZmlnLmdldCgncmVnaXN0cnknKTtcbiAgfSBjYXRjaCB7XG4gICAgLy8gQ29uZmlnIG5hbWVzcGFjZSBub3QgbG9hZGVkIChlLmcuLCB1bml0IHRlc3RzIHdpdGhvdXQgZnVsbCBjb25maWcpLlxuICAgIGxvZy53YXJuKFxuICAgICAgYFBsdWdpbiBcIiR7cGx1Z2luLm5hbWV9OiR7cGx1Z2luLnZlcnNpb259XCIgbmVlZHMgdGhlIHJlZ2lzdHJ5IGNvbmZpZyBidXQgaXQncyBub3QgbG9hZGVkIOKAlCBgICtcbiAgICAgICdDb2RlQnVpbGQgd2lsbCBmYWxsIGJhY2sgdG8gYXdzL2NvZGVidWlsZC9zdGFuZGFyZDo4LjAuICcgK1xuICAgICAgJ1NldCBJTUFHRV9SRUdJU1RSWV9IT1NUICsgSU1BR0VfUkVHSVNUUllfUE9SVCBpbiBwaXBlbGluZS1tYW5hZ2VyXFwncyBlbnZpcm9ubWVudC4nLFxuICAgICk7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIGlmICghcmVnaXN0cnk/Lmhvc3QpIHtcbiAgICBsb2cud2FybihcbiAgICAgIGBQbHVnaW4gXCIke3BsdWdpbi5uYW1lfToke3BsdWdpbi52ZXJzaW9ufVwiIG5lZWRzIElNQUdFX1JFR0lTVFJZX0hPU1QgYnV0IGl0J3MgZW1wdHkg4oCUIGAgK1xuICAgICAgJ0NvZGVCdWlsZCB3aWxsIGZhbGwgYmFjayB0byBhd3MvY29kZWJ1aWxkL3N0YW5kYXJkOjguMC4gJyArXG4gICAgICAnU2V0IElNQUdFX1JFR0lTVFJZX0hPU1QgaW4gcGlwZWxpbmUtbWFuYWdlclxcJ3MgZW52aXJvbm1lbnQgdG8gdXNlIHRoZSBwbHVnaW4gaW1hZ2UuJyxcbiAgICApO1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbiAgaWYgKCFzY29wZSkge1xuICAgIGxvZy53YXJuKGBQbHVnaW4gXCIke3BsdWdpbi5uYW1lfVwiIGltYWdlIHJlc29sdXRpb24gc2tpcHBlZDogbm8gY29uc3RydWN0IHNjb3BlIHByb3ZpZGVkYCk7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8vIFBlci1vcmcgYXV0aCByZXF1aXJlcyBvcmdJZCDigJQgdGhlIFNlY3JldCBpcyBuYW1lZCBwZXIgb3JnLlxuICBpZiAoIW9yZ0lkKSB7XG4gICAgbG9nLndhcm4oXG4gICAgICBgUGx1Z2luIFwiJHtwbHVnaW4ubmFtZX1cIiBpbWFnZSByZXNvbHV0aW9uIHNraXBwZWQ6IG9yZ0lkIGlzIHJlcXVpcmVkIHRvIGAgK1xuICAgICAgJ3Jlc29sdmUgdGhlIHBlci1vcmcgcGxhdGZvcm0gU2VjcmV0IHVzZWQgZm9yIENvZGVCdWlsZCBCYXNpYyBhdXRoLicsXG4gICAgKTtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG5cbiAgLy8gQ29tcG9zZSB0aGUgaW1hZ2UgVVJJLiBOYW1lc3BhY2UgYnkgb3duZXJzaGlwOlxuICAvLyAgIC0gUGx1Z2lucyBvd25lZCBieSB0aGUgc3lzdGVtIG9yZyDihpIgYHN5c3RlbS88bmFtZT46PHZlcnNpb24+YC5cbiAgLy8gICAgIHBpcGVsaW5lLWltYWdlLXJlZ2lzdHJ5J3MgdG9rZW4gc2VydmljZSBncmFudHMgcHVsbCBvbiBgc3lzdGVtLypgXG4gIC8vICAgICB0byBhbnkgYXV0aGVudGljYXRlZCBvcmcgdXNlciAocmVhZC1vbmx5IGNhdGFsb2cgb2Ygc2hhcmVkIHBsdWdpbnMpLlxuICAvLyAgIC0gUGx1Z2lucyBvd25lZCBieSBhIHRlbmFudCBvcmcg4oaSIGBvcmctPG9yZ0lkPi88bmFtZT46PHZlcnNpb24+YC5cbiAgLy8gICAgIFRoZSB0b2tlbiBzZXJ2aWNlIGdyYW50cyBwdWxsLHB1c2ggb25seSB0byBtZW1iZXJzIG9mIHRoYXQgb3JnLlxuICAvLyBUaGUgcGx1Z2luJ3Mgb3duIGBvcmdJZGAgKG5vdCB0aGUgY2FsbGVyJ3MpIGRlY2lkZXMgdGhlIG5hbWVzcGFjZSDigJRcbiAgLy8gdGVuYW50IHBpcGVsaW5lcyBwdWxsaW5nIHNoYXJlZCBzeXN0ZW0gcGx1Z2lucyBzdGlsbCBnZXQgdGhlIGBzeXN0ZW0vYFxuICAvLyBwYXRoIGJlY2F1c2UgdGhhdCdzIHdoZXJlIHRoZSBpbWFnZSBhY3R1YWxseSBsaXZlcy5cbiAgLy8gVXNlIHRoZSBleHRlcm5hbCBwdWxsIGhvc3QvcG9ydDogdGhpcyBpbWFnZSBVUkkgaXMgY29uc3VtZWQgYnkgQVdTXG4gIC8vIENvZGVCdWlsZCAob3V0LW9mLWNsdXN0ZXIpLCB3aGljaCBjYW4ndCByZXNvbHZlIHRoZSBpbi1jbHVzdGVyXG4gIC8vIGByZWdpc3RyeTo1MDAwYCBDbHVzdGVySVAuIEZhbGwgYmFjayB0byBgaG9zdGAvYHBvcnRgIGZvciBzaW5nbGUtaG9zdCAvXG4gIC8vIGluLWNsdXN0ZXItb25seSBkZXBsb3lzIHdoZXJlIG5vIHNlcGFyYXRlIHB1bGwgaG9zdCBpcyBjb25maWd1cmVkLlxuICBjb25zdCB7IGhvc3Q6IHB1bGxIb3N0LCBwb3J0UGFydCB9ID0gcmVzb2x2ZUV4dGVybmFsUHVsbFRhcmdldChyZWdpc3RyeSk7XG4gIC8vIE11c3QgbWF0Y2ggdGhlIFBVU0ggc2lkZSAoYXBpL3BsdWdpbiBwbHVnaW5VcmkpIGV4YWN0bHksIG9yIGEgc3lzdGVtXG4gIC8vIHBsdWdpbidzIGltYWdlIGlzIHB1c2hlZCB0byBgc3lzdGVtL+KApmAgYnV0IHRoaXMgc3ludGggcHVsbHMgZnJvbVxuICAvLyBgb3JnLTxvYmplY3RpZD4v4oCmYCDihpIgYnVpbGQtdGltZSBwdWxsIGZhaWx1cmUuIGBTWVNURU1fT1JHX0lEYCBpcyB0aGVcbiAgLy8gd2VsbC1rbm93biBPYmplY3RJZCAoTk9UIHRoZSBzdHJpbmcgJ3N5c3RlbScpLlxuICBjb25zdCBuYW1lc3BhY2UgPSBwbHVnaW4ub3JnSWQgPT09IFNZU1RFTV9PUkdfSUQgPyAnc3lzdGVtJyA6IGBvcmctJHtwbHVnaW4ub3JnSWR9YDtcbiAgY29uc3QgaW1hZ2VVcmkgPSBgJHtwdWxsSG9zdH0ke3BvcnRQYXJ0fS8ke25hbWVzcGFjZX0vJHtwbHVnaW4ubmFtZX06JHtwbHVnaW4udmVyc2lvbn1gO1xuXG4gIC8vIENvZGVCdWlsZCByZWFkcyBgcGlwZWxpbmUtYnVpbGRlci88b3JnSWQ+L3BsYXRmb3JtYCBhbmQgc2VuZHMgaXRzXG4gIC8vIGB1c2VybmFtZWAvYHBhc3N3b3JkYCBmaWVsZHMgYXMgSFRUUCBCYXNpYyB0byB0aGUgcmVnaXN0cnkuIFRoZVxuICAvLyByZWdpc3RyeSBjaGFsbGVuZ2VzIHdpdGggYSBCZWFyZXIgcmVhbG0gcG9pbnRpbmcgYXRcbiAgLy8gcGlwZWxpbmUtaW1hZ2UtcmVnaXN0cnkncyBgL3Rva2VuYCBlbmRwb2ludDsgdGhlIERvY2tlciBjbGllbnQgZm9yd2FyZHNcbiAgLy8gdGhvc2UgY3JlZHMsIHRoZSBwYXNzd29yZCBpcyB2ZXJpZmllZCBhcyBhIHBsYXRmb3JtIEpXVCwgYW5kIGEgcmVnaXN0cnlcbiAgLy8gdG9rZW4gc2NvcGVkIHRvIHRoZSBvcmcgaXMgaXNzdWVkLlxuICAvL1xuICAvLyBTYW1lIFNlY3JldCBpcyByZWFkIGJ5IHRoZSBwbHVnaW4tbG9va3VwIExhbWJkYSAodmlhIHRoZSBgcGFzc3dvcmRgXG4gIC8vIGZpZWxkKSDigJQgb25lIFNlY3JldCBzZXJ2ZXMgYm90aCBmbG93cy5cbiAgY29uc3Qgc3RhY2sgPSBTdGFjay5vZihzY29wZSk7XG4gIGNvbnN0IHNlY3JldE5hbWUgPSBDb3JlQ29uc3RhbnRzLnNlY3JldFBhdGgob3JnSWQsICdwbGF0Zm9ybScpO1xuICAvLyBDREsgY29uc3RydWN0IElEcyBhbGxvdyBvbmx5IFtBLVphLXowLTlfLV07IHNhbml0aXplIHRoZSBzZWNyZXQgbmFtZS5cbiAgY29uc3Qgc2VjcmV0Q29uc3RydWN0SWQgPSBgUGxhdGZvcm1DcmVkc18ke3NlY3JldE5hbWUucmVwbGFjZSgvW15BLVphLXowLTlfLV0vZywgJ18nKX1gO1xuICBjb25zdCBjcmVkZW50aWFsc1NlY3JldCA9IChzdGFjay5ub2RlLnRyeUZpbmRDaGlsZChzZWNyZXRDb25zdHJ1Y3RJZCkgYXMgU2VjcmV0IHwgdW5kZWZpbmVkKVxuICAgID8/IFNlY3JldC5mcm9tU2VjcmV0TmFtZVYyKHN0YWNrLCBzZWNyZXRDb25zdHJ1Y3RJZCwgc2VjcmV0TmFtZSk7XG5cbiAgcmV0dXJuIExpbnV4QnVpbGRJbWFnZS5mcm9tRG9ja2VyUmVnaXN0cnkoaW1hZ2VVcmksIHtcbiAgICBzZWNyZXRzTWFuYWdlckNyZWRlbnRpYWxzOiBjcmVkZW50aWFsc1NlY3JldCxcbiAgfSk7XG59XG5cbi8qKlxuICogUmVzb2x2ZSB0aGUgZmFsbGJhY2sgQ29kZUJ1aWxkIGltYWdlIGZvciBzdGVwcyB3aXRob3V0IGEgcGx1Z2luLWJha2VkIG9uZS5cbiAqXG4gKiBSZWFkcyBgYXdzLmNvZGVCdWlsZC5kZWZhdWx0SW1hZ2VgIChlbnY6IGBDT0RFQlVJTERfREVGQVVMVF9JTUFHRWApLlxuICogRGVmYXVsdDogYHBpcGVsaW5lLWJvb3RzdHJhcDoxLjBgIOKAlCB0aGUgbG9jYWwgdGFnIGJ1aWx0IGJ5XG4gKiBgZGVwbG95L2NvZGVidWlsZC9ib290c3RyYXAvRG9ja2VyZmlsZWAuXG4gKlxuICogLSBBV1MgY3VyYXRlZCBpbWFnZSAoYGF3cy9jb2RlYnVpbGQvKmApOiB1c2UgdGhlIG1hdGNoaW5nIGBMaW51eEJ1aWxkSW1hZ2VgXG4gKiAgIGNvbnN0YW50IHNvIENESyBlbWl0cyBgaW1hZ2VQdWxsQ3JlZGVudGlhbHNUeXBlOiBDT0RFQlVJTERgLiBVc2luZ1xuICogICBgZnJvbURvY2tlclJlZ2lzdHJ5KClgIGhlcmUgd291bGQgc2V0IFNFUlZJQ0VfUk9MRSBjcmVkZW50aWFscywgd2hpY2hcbiAqICAgQ0ZOIHJlamVjdHMgd2l0aCBcImNhbm5vdCB1c2UgYSBDb2RlQnVpbGQgY3VyYXRlZCBpbWFnZSB3aXRoXG4gKiAgIGltYWdlUHVsbENyZWRlbnRpYWxzVHlwZSBTRVJWSUNFX1JPTEVcIi5cbiAqIC0gQmFyZSB0YWcgKG5vIGAvYCk6IGF1dG8tcHJlZml4ZWQgdG9cbiAqICAgYDxyZWdpc3RyeS1ob3N0Pjo8cG9ydD4vbGlicmFyeS88dGFnPmAgdXNpbmcgdGhlIHJlZ2lzdHJ5IGNvbmZpZyxcbiAqICAgd2l0aCB0aGUgcGVyLW9yZyBwbGF0Zm9ybSBTZWNyZXQgYXMgQmFzaWMgYXV0aCDigJQgc2FtZSBwYXRoXG4gKiAgIGByZXNvbHZlUGx1Z2luSW1hZ2UoKWAgdXNlcyBmb3IgcGx1Z2luIGltYWdlcy4gTmVlZHMgYHNjb3BlYCArIGBvcmdJZGAuXG4gKiAtIEZ1bGx5LXF1YWxpZmllZCByZWdpc3RyeSBVUkkgKGNvbnRhaW5zIGAvYCk6IHVzZWQgYXMtaXMsIG5vIGF1dGggd2lyZWQuXG4gKiAtIE1pc3NpbmcgcmVnaXN0cnkgY29uZmlnIG9yIHNjb3BlL29yZ0lkIOKGkiBmYWxscyBiYWNrIHRvXG4gKiAgIGBhd3MvY29kZWJ1aWxkL3N0YW5kYXJkOjguMGAgKGFzIGEgQ1VSQVRFRCBpbWFnZSwgc2VlIGFib3ZlKSwgd2l0aCBhXG4gKiAgIHdhcm5pbmcgc28gc3ludGggZGVncmFkZXMgZ3JhY2VmdWxseSBvbiBwYXJ0aWFsbHkgY29uZmlndXJlZCBlbnZzLlxuICovXG5jb25zdCBTVEFOREFSRF84XzAgPSAnYXdzL2NvZGVidWlsZC9zdGFuZGFyZDo4LjAnO1xuXG4vKipcbiAqIGF3cy1jZGstbGliIDIuMjU4IGhhcyBubyBgTGludXhCdWlsZEltYWdlLlNUQU5EQVJEXzhfMGAgc3RhdGljIHlldCwgc28gdGhlXG4gKiBjdXJhdGVkIDguMCBmYWxsYmFjayByZXNvbHZlcyB2aWEgYGZyb21Db2RlQnVpbGRJbWFnZUlkYCAoc3RpbGwgQ09ERUJVSUxEIGNyZWRzKS5cbiAqL1xuY29uc3QgZmFsbGJhY2tCdWlsZEltYWdlID0gKCk6IElCdWlsZEltYWdlID0+IExpbnV4QnVpbGRJbWFnZS5mcm9tQ29kZUJ1aWxkSW1hZ2VJZChTVEFOREFSRF84XzApO1xuXG4vKipcbiAqIE1hcCBBV1MgY3VyYXRlZCBgYXdzL2NvZGVidWlsZC8qYCBpbWFnZSBzdHJpbmdzIHRvIHRoZSBtYXRjaGluZ1xuICogYExpbnV4QnVpbGRJbWFnZWAgc3RhdGljLiBFeHRlbmQgd2hlbiBuZXdlciBzdGFuZGFyZCBpbWFnZXMgc2hpcC5cbiAqIFJldHVybnMgYHVuZGVmaW5lZGAgZm9yIG5vbi1jdXJhdGVkIHN0cmluZ3Mg4oCUIGNhbGxlciBzaG91bGQgdXNlXG4gKiBgZnJvbURvY2tlclJlZ2lzdHJ5KClgIGZvciB0aG9zZS5cbiAqL1xuZnVuY3Rpb24gY3VyYXRlZExpbnV4QnVpbGRJbWFnZShpbWFnZUlkOiBzdHJpbmcpOiBJQnVpbGRJbWFnZSB8IHVuZGVmaW5lZCB7XG4gIGlmICghaW1hZ2VJZC5zdGFydHNXaXRoKCdhd3MvY29kZWJ1aWxkLycpKSByZXR1cm4gdW5kZWZpbmVkO1xuICBzd2l0Y2ggKGltYWdlSWQpIHtcbiAgICBjYXNlICdhd3MvY29kZWJ1aWxkL3N0YW5kYXJkOjYuMCc6IHJldHVybiBMaW51eEJ1aWxkSW1hZ2UuU1RBTkRBUkRfNl8wO1xuICAgIGNhc2UgJ2F3cy9jb2RlYnVpbGQvc3RhbmRhcmQ6NS4wJzogcmV0dXJuIExpbnV4QnVpbGRJbWFnZS5TVEFOREFSRF81XzA7XG4gICAgLy8gTmV3ZXIgY29kZW5hbWVkIGltYWdlcyByb3V0ZSB0aHJvdWdoIGZyb21Db2RlQnVpbGRJbWFnZUlkLCB3aGljaFxuICAgIC8vIENESyBhbHNvIG1hcmtzIGFzIENPREVCVUlMRCBjcmVkZW50aWFscyAoY3VyYXRlZCkuXG4gICAgZGVmYXVsdDogcmV0dXJuIExpbnV4QnVpbGRJbWFnZS5mcm9tQ29kZUJ1aWxkSW1hZ2VJZChpbWFnZUlkKTtcbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZURlZmF1bHRCdWlsZEltYWdlKHNjb3BlPzogQ29uc3RydWN0LCBvcmdJZD86IHN0cmluZyk6IElCdWlsZEltYWdlIHtcbiAgbGV0IGNvbmZpZ3VyZWQ6IHN0cmluZztcbiAgdHJ5IHtcbiAgICBjb25maWd1cmVkID0gQ29uZmlnLmdldCgnYXdzJykuY29kZUJ1aWxkLmRlZmF1bHRJbWFnZTtcbiAgfSBjYXRjaCB7XG4gICAgY29uZmlndXJlZCA9IFNUQU5EQVJEXzhfMDtcbiAgfVxuXG4gIC8vIEFXUyBjdXJhdGVkIGltYWdlIOKGkiBDT0RFQlVJTEQgY3JlZGVudGlhbHMuIE1VU1QgZ28gdGhyb3VnaCB0aGVcbiAgLy8gTGludXhCdWlsZEltYWdlIGNvbnN0YW50cywgbm90IGZyb21Eb2NrZXJSZWdpc3RyeSgpLlxuICBjb25zdCBjdXJhdGVkID0gY3VyYXRlZExpbnV4QnVpbGRJbWFnZShjb25maWd1cmVkKTtcbiAgaWYgKGN1cmF0ZWQpIHJldHVybiBjdXJhdGVkO1xuXG4gIC8vIEZ1bGx5LXF1YWxpZmllZCBVUkkg4oCUIG9wZXJhdG9yIG93bnMgaXQuIE5vIHJlZ2lzdHJ5L1NlY3JldCB3aXJpbmcuXG4gIGlmIChjb25maWd1cmVkLmluY2x1ZGVzKCcvJykpIHtcbiAgICByZXR1cm4gTGludXhCdWlsZEltYWdlLmZyb21Eb2NrZXJSZWdpc3RyeShjb25maWd1cmVkKTtcbiAgfVxuXG4gIC8vIEJhcmUgdGFnIOKGkiBhdXRvLXByZWZpeCB3aXRoIHRoZSBwbGF0Zm9ybSByZWdpc3RyeSwgbWlycm9yaW5nXG4gIC8vIHJlc29sdmVQbHVnaW5JbWFnZSgpLiBCYWlsIHRvIHRoZSBjdXJhdGVkIHN0YW5kYXJkOjguMCBmYWxsYmFja1xuICAvLyAod2l0aCBhIHdhcm5pbmcpIGF0IGVhY2ggbWlzc2luZyBwcmVyZXF1aXNpdGUgc28gc3ludGggZGVncmFkZXNcbiAgLy8gZ3JhY2VmdWxseSBvbiBwYXJ0aWFsbHkgY29uZmlndXJlZCBlbnZpcm9ubWVudHMgaW5zdGVhZCBvZiBmYWlsaW5nLlxuICBsZXQgcmVnaXN0cnk7XG4gIHRyeSB7XG4gICAgcmVnaXN0cnkgPSBDb25maWcuZ2V0KCdyZWdpc3RyeScpO1xuICB9IGNhdGNoIHtcbiAgICBsb2cud2FybihcbiAgICAgIGBDT0RFQlVJTERfREVGQVVMVF9JTUFHRT0nJHtjb25maWd1cmVkfScgaXMgYSBiYXJlIHRhZyBidXQgcmVnaXN0cnkgY29uZmlnIG5vdCBsb2FkZWQg4oCUIGAgK1xuICAgICAgYGZhbGxpbmcgYmFjayB0byAke1NUQU5EQVJEXzhfMH0uIFNldCBJTUFHRV9SRUdJU1RSWV9IT1NUICsgSU1BR0VfUkVHSVNUUllfUE9SVC5gLFxuICAgICk7XG4gICAgcmV0dXJuIGZhbGxiYWNrQnVpbGRJbWFnZSgpO1xuICB9XG4gIGlmICghcmVnaXN0cnk/Lmhvc3QpIHtcbiAgICBsb2cud2FybihcbiAgICAgIGBDT0RFQlVJTERfREVGQVVMVF9JTUFHRT0nJHtjb25maWd1cmVkfScgaXMgYSBiYXJlIHRhZyBidXQgSU1BR0VfUkVHSVNUUllfSE9TVCBpcyBlbXB0eSDigJQgYCArXG4gICAgICBgZmFsbGluZyBiYWNrIHRvICR7U1RBTkRBUkRfOF8wfS5gLFxuICAgICk7XG4gICAgcmV0dXJuIGZhbGxiYWNrQnVpbGRJbWFnZSgpO1xuICB9XG4gIGlmICghc2NvcGUgfHwgIW9yZ0lkKSB7XG4gICAgbG9nLndhcm4oXG4gICAgICBgQ09ERUJVSUxEX0RFRkFVTFRfSU1BR0U9JyR7Y29uZmlndXJlZH0nIG5lZWRzIHNjb3BlK29yZ0lkIGZvciBTZWNyZXQgYXV0aCDigJQgYCArXG4gICAgICBgZmFsbGluZyBiYWNrIHRvICR7U1RBTkRBUkRfOF8wfS4gKENhbGxlciBkaWQgbm90IHN1cHBseSB0aGVtLilgLFxuICAgICk7XG4gICAgcmV0dXJuIGZhbGxiYWNrQnVpbGRJbWFnZSgpO1xuICB9XG5cbiAgLy8gVXNlIHRoZSBleHRlcm5hbCBwdWxsIGhvc3QvcG9ydCAobm90IHRoZSBpbi1jbHVzdGVyIGhvc3QpIOKAlCB0aGlzIFVSSSBpc1xuICAvLyBjb25zdW1lZCBieSBBV1MgQ29kZUJ1aWxkLCB3aGljaCBjYW4ndCByZXNvbHZlIHRoZSBgcmVnaXN0cnk6NTAwMGAgQ2x1c3RlcklQLlxuICBjb25zdCB7IGhvc3Q6IHB1bGxIb3N0LCBwb3J0UGFydCB9ID0gcmVzb2x2ZUV4dGVybmFsUHVsbFRhcmdldChyZWdpc3RyeSk7XG4gIGNvbnN0IGltYWdlVXJpID0gYCR7cHVsbEhvc3R9JHtwb3J0UGFydH0vbGlicmFyeS8ke2NvbmZpZ3VyZWR9YDtcblxuICAvLyBTYW1lIFNlY3JldCBhcyByZXNvbHZlUGx1Z2luSW1hZ2Ug4oCUIHBlci1vcmcgcGxhdGZvcm0gU2VjcmV0LCBDb2RlQnVpbGRcbiAgLy8gc2VuZHMgaXQgYXMgQmFzaWMgYXV0aCwgaW1hZ2UtcmVnaXN0cnkgdmVyaWZpZXMgdGhlIEpXVCBpbiBgcGFzc3dvcmRgLlxuICBjb25zdCBzdGFjayA9IFN0YWNrLm9mKHNjb3BlKTtcbiAgY29uc3Qgc2VjcmV0TmFtZSA9IENvcmVDb25zdGFudHMuc2VjcmV0UGF0aChvcmdJZCwgJ3BsYXRmb3JtJyk7XG4gIGNvbnN0IHNlY3JldENvbnN0cnVjdElkID0gYFBsYXRmb3JtQ3JlZHNfJHtzZWNyZXROYW1lLnJlcGxhY2UoL1teQS1aYS16MC05Xy1dL2csICdfJyl9YDtcbiAgY29uc3QgY3JlZGVudGlhbHNTZWNyZXQgPSAoc3RhY2subm9kZS50cnlGaW5kQ2hpbGQoc2VjcmV0Q29uc3RydWN0SWQpIGFzIFNlY3JldCB8IHVuZGVmaW5lZClcbiAgICA/PyBTZWNyZXQuZnJvbVNlY3JldE5hbWVWMihzdGFjaywgc2VjcmV0Q29uc3RydWN0SWQsIHNlY3JldE5hbWUpO1xuXG4gIHJldHVybiBMaW51eEJ1aWxkSW1hZ2UuZnJvbURvY2tlclJlZ2lzdHJ5KGltYWdlVXJpLCB7XG4gICAgc2VjcmV0c01hbmFnZXJDcmVkZW50aWFsczogY3JlZGVudGlhbHNTZWNyZXQsXG4gIH0pO1xufVxuXG4vKipcbiAqIENyZWF0ZSBhIENvZGVCdWlsZCBzdGVwIG9yIFNoZWxsIHN0ZXAgYmFzZWQgb24gcGx1Z2luIGNvbmZpZ3VyYXRpb24uXG4gKlxuICogTWV0YWRhdGEgbWVyZ2Ugb3JkZXIgKGxhc3Qgd2lucyk6XG4gKiAgIDEuIFBsdWdpbiBtZXRhZGF0YSAoZnJvbSBwbHVnaW4ubWV0YWRhdGEgaW4gZGF0YWJhc2UpIOKAlCB0aGUgcGx1Z2luXG4gKiAgICAgIGF1dGhvcidzIGJha2VkLWluIGRlZmF1bHRzXG4gKiAgIDIuIFN0ZXAtbGV2ZWwgbWV0YWRhdGEgKGZyb20gb3B0aW9ucy5tZXRhZGF0YSkg4oCUIHRoZSBwaXBlbGluZSBhdXRob3Inc1xuICogICAgICBwZXItc3RlcCBvdmVycmlkZXMsIHdoaWNoIGFyZSBtb3JlIHNwZWNpZmljIGFuZCBtdXN0IHdpblxuICpcbiAqIEVudmlyb25tZW50IG1lcmdlIG9yZGVyIChsYXN0IHdpbnMpOlxuICogICAxLiBQbHVnaW4gZW52IHZhcnMgKGZyb20gcGx1Z2luLmVudilcbiAqICAgMi4gQ3VzdG9tIGVudiB2YXJzIChmcm9tIG9wdGlvbnMuZW52KVxuICogICAzLiBXT1JLRElSIGZyb20gbWVyZ2VkIG1ldGFkYXRhXG4gKlxuICogQ0RLIHByb3Agc3ByZWFkIG9yZGVyIChsYXN0IHdpbnMpOlxuICogICBwcm9ncmFtbWF0aWMgZGVmYXVsdHMgKGlucHV0LCBjb21tYW5kcywgZW52LCBuZXR3b3JrKSDihpIgbWV0YWRhdGEgb3ZlcnJpZGVzXG4gKlxuICogVGhpcyBtZWFucyBtZXRhZGF0YSBrZXlzIGxpa2UgYGF3czpjZGs6cGlwZWxpbmVzOmNvZGVidWlsZHN0ZXA6Y29tbWFuZHNgXG4gKiB3aWxsIG92ZXJyaWRlIHRoZSBwbHVnaW4tZGVyaXZlZCBjb21tYW5kcyB3aGVuIGV4cGxpY2l0bHkgc2V0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlQ29kZUJ1aWxkU3RlcChvcHRpb25zOiBDb2RlQnVpbGRTdGVwT3B0aW9ucyk6IFNoZWxsU3RlcCB8IENvZGVCdWlsZFN0ZXAgfCBNYW51YWxBcHByb3ZhbFN0ZXAge1xuICBjb25zdCB7XG4gICAgaWQsIGlucHV0LCBtZXRhZGF0YSwgbmV0d29yaywgc2NvcGUsXG4gICAgcHJlSW5zdGFsbENvbW1hbmRzLCBwb3N0SW5zdGFsbENvbW1hbmRzLCBwcmVDb21tYW5kcywgcG9zdENvbW1hbmRzLFxuICAgIGVudjogY3VzdG9tRW52LCBhZGRpdGlvbmFsSW5wdXRzLCB0aW1lb3V0LCBmYWlsdXJlQmVoYXZpb3IsXG4gICAgYXJ0aWZhY3RNYW5hZ2VyLCBzdGFnZU5hbWUsIHN0YWdlQWxpYXMsIHBsdWdpbkFsaWFzLCBvcmdJZCwgcGlwZWxpbmVTY29wZSxcbiAgfSA9IG9wdGlvbnM7XG5cbiAgLy8gUmVzb2x2ZSB7eyAuLi4gfX0gdGVtcGxhdGVzIGluIHBsdWdpbiBzcGVjIGZpZWxkcyBhZ2FpbnN0IHRoZSBwaXBlbGluZSBzY29wZS5cbiAgLy8gRXZlcnkgY2FsbCBnb2VzIHRocm91Z2ggdGhlIHJlc29sdmVyIOKAlCBwbHVnaW5zIHdpdGhvdXQgdGVtcGxhdGUgdG9rZW5zIGFyZVxuICAvLyBhIG5vLW9wIGZhc3QgcGF0aCBpbnNpZGUgcmVzb2x2ZVBsdWdpblRlbXBsYXRlcygpLlxuICBjb25zdCBwbHVnaW4gPSByZXNvbHZlUGx1Z2luVGVtcGxhdGVzKG9wdGlvbnMucGx1Z2luLCBwaXBlbGluZVNjb3BlKTtcblxuICAvLyBQZXItc3RlcCBtZXRhZGF0YSAodGhlIHBpcGVsaW5lIGF1dGhvcidzIG92ZXJyaWRlcywgZS5nLiBKQVZBX1ZFUlNJT049MjUpXG4gIC8vIG11c3Qgd2luIG92ZXIgdGhlIHBsdWdpbidzIGNhdGFsb2cgYG1ldGFkYXRhYCBkZWZhdWx0cywgc28gaXQgZ29lcyBMQVNULlxuICAvLyBSZXZlcnNpbmcgdGhlc2Ugc2lsZW50bHkgZHJvcHBlZCBwZXItc3RlcCBvdmVycmlkZXMgZm9yIGFueSBwbHVnaW4gdGhhdFxuICAvLyBzaGlwcyBub24tZW1wdHkgY2F0YWxvZyBtZXRhZGF0YSAocGx1Z2lucyB0aGF0IGNhcnJ5IGRlZmF1bHRzIHVuZGVyIGBlbnZgXG4gIC8vIGluc3RlYWQg4oCUIGxpa2UgamF2YS1jb3JyZXR0byDigJQgd2VyZSB1bmFmZmVjdGVkLCB3aGljaCBtYXNrZWQgdGhpcykuXG4gIGNvbnN0IG1lcmdlZCA9IG1lcmdlKHBsdWdpbi5tZXRhZGF0YSA/PyB7fSwgbWV0YWRhdGEgPz8ge30pO1xuXG4gIC8vIE1hbnVhbEFwcHJvdmFsU3RlcDogbm8gY29tbWFuZHMsIGVudiwgY29tcHV0ZSwgb3IgbmV0d29yayDigJQganVzdCBpZCArIG9wdGlvbmFsIGNvbW1lbnRcbiAgaWYgKHBsdWdpbi5wbHVnaW5UeXBlID09PSBQbHVnaW5UeXBlLk1BTlVBTF9BUFBST1ZBTF9TVEVQKSB7XG4gICAgcmV0dXJuIG5ldyBNYW51YWxBcHByb3ZhbFN0ZXAoaWQsIHtcbiAgICAgIGNvbW1lbnQ6IHR5cGVvZiBtZXJnZWQuQVBQUk9WQUxfQ09NTUVOVCA9PT0gJ3N0cmluZycgPyBtZXJnZWQuQVBQUk9WQUxfQ09NTUVOVCA6IHVuZGVmaW5lZCxcbiAgICB9KTtcbiAgfVxuXG4gIGxvZy5kZWJ1ZygnW0NyZWF0ZUNvZGVCdWlsZFN0ZXBdIEJ1aWxkaW5nIHN0ZXAgd2l0aCBtZXJnZWQgbWV0YWRhdGEnKTtcblxuICAvLyBXYXJuIGFib3V0IHJlcXVpcmVkIHNlY3JldHMgd2l0aG91dCBvcmdJZCAoY2FuJ3QgcmVzb2x2ZSlcbiAgY29uc3QgcmVxdWlyZWRTZWNyZXRzID0gcGx1Z2luLnNlY3JldHM/LmZpbHRlcihzID0+IHMucmVxdWlyZWQpID8/IFtdO1xuICBpZiAocmVxdWlyZWRTZWNyZXRzLmxlbmd0aCA+IDAgJiYgIW9yZ0lkKSB7XG4gICAgbG9nLndhcm4oXG4gICAgICBgUGx1Z2luIFwiJHtwbHVnaW4ubmFtZX1cIiBkZWNsYXJlcyAke3JlcXVpcmVkU2VjcmV0cy5sZW5ndGh9IHJlcXVpcmVkIHNlY3JldChzKSBidXQgbm8gb3JnSWQgaXMgYXZhaWxhYmxlLiBgICtcbiAgICAgIGBTZWNyZXRzIHdpbGwgbm90IGJlIGluamVjdGVkOiAke3JlcXVpcmVkU2VjcmV0cy5tYXAocyA9PiBzLm5hbWUpLmpvaW4oJywgJyl9YCxcbiAgICApO1xuICB9XG5cbiAgLy8gUmVzb2x2ZSBwbHVnaW4gc2VjcmV0cyBhcyBTRUNSRVRTX01BTkFHRVIgZW52IHZhcnMg4oCUIG9ubHkgUkVRVUlSRUQgb25lcy5cbiAgLy8gQ29kZUJ1aWxkIHRyZWF0cyBhIFNFQ1JFVFNfTUFOQUdFUiBlbnYgdmFyIGFzIE1BTkRBVE9SWTogaXQgZmFpbHMgdGhlIGJ1aWxkXG4gIC8vIGF0IERPV05MT0FEX1NPVVJDRSAoXCJSZXNvdXJjZU5vdEZvdW5kRXhjZXB0aW9uOiBjYW4ndCBmaW5kIHRoZSBzcGVjaWZpZWRcbiAgLy8gc2VjcmV0XCIpIGlmIHRoZSBzZWNyZXQgaXMgYWJzZW50LiBBdXRvLXdpcmluZyBhbiBPUFRJT05BTCBzZWNyZXRcbiAgLy8gKGByZXF1aXJlZDogZmFsc2VgLCBlLmcuIE5WRF9BUElfS0VZIC8gU0VNR1JFUF9BUFBfVE9LRU4pIHRoZSBvcGVyYXRvciBoYXNuJ3RcbiAgLy8gY3JlYXRlZCB3b3VsZCB0aGVyZWZvcmUgYnJlYWsgZXZlcnkgYnVpbGQg4oCUIHRoZSBleGFjdCBvcHBvc2l0ZSBvZiBcIm9wdGlvbmFsXCIuXG4gIC8vIE9wdGlvbmFsIHNlY3JldHMgYXJlIGxlZnQgZm9yIHRoZSBwbHVnaW4gdG8gcmVhZCBvbmx5IHdoZXJlIHRoZSBvcGVyYXRvciBoYXNcbiAgLy8gcHJvdmlzaW9uZWQgdGhlbSAob3V0LW9mLWJhbmQgZW52L3NlY3JldCksIG5vdCBmb3JjZS1pbmplY3RlZCBoZXJlLlxuICBjb25zdCBzZWNyZXRFbnZWYXJzID0gKHJlcXVpcmVkU2VjcmV0cy5sZW5ndGggJiYgb3JnSWQpXG4gICAgPyB0b1NlY3JldEVudlZhcnMocmVxdWlyZWRTZWNyZXRzLCBvcmdJZClcbiAgICA6IHt9O1xuXG4gIGNvbnN0IGVudiA9IGJ1aWxkRW52KHBsdWdpbiwgbWVyZ2VkLCBjdXN0b21FbnYpO1xuXG4gIC8vIENvZGVQaXBlbGluZSByZXNvbHZlZCB2YXJpYWJsZXMg4oCUIG11c3QgYmUgaW4gQ29kZUJ1aWxkU3RlcC5lbnYgKGFjdGlvbi1sZXZlbCksXG4gIC8vIG5vdCBidWlsZEVudmlyb25tZW50LmVudmlyb25tZW50VmFyaWFibGVzIChwcm9qZWN0LWxldmVsKVxuICBjb25zdCBhY3Rpb25FbnY6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgUElQRUxJTkVfRVhFQ1VUSU9OX0lEOiAnI3tjb2RlcGlwZWxpbmUuUGlwZWxpbmVFeGVjdXRpb25JZH0nLFxuICB9O1xuXG4gIGNvbnN0IG91dHB1dERpciA9IHBsdWdpbi5wcmltYXJ5T3V0cHV0RGlyZWN0b3J5O1xuICBjb25zdCBlbnN1cmVPdXRwdXREaXIgPSAob3V0cHV0RGlyICYmICFvdXRwdXREaXIuaW5jbHVkZXMoJyonKSlcbiAgICA/IFtgbWtkaXIgLXAgXCIke291dHB1dERpcn1cIiAmJiB0b3VjaCBcIiR7b3V0cHV0RGlyfS8uZ2l0a2VlcFwiYF1cbiAgICA6IFtdO1xuXG4gIGNvbnN0IHsgaW5zdGFsbENvbW1hbmRzLCBjb21tYW5kcyB9ID0gYnVpbGRDb21tYW5kcyhwbHVnaW4sIHtcbiAgICBwcmVJbnN0YWxsQ29tbWFuZHM6IFsuLi5lbnN1cmVPdXRwdXREaXIsIC4uLihwcmVJbnN0YWxsQ29tbWFuZHMgPz8gW10pXSxcbiAgICBwb3N0SW5zdGFsbENvbW1hbmRzLFxuICAgIHByZUNvbW1hbmRzLFxuICAgIHBvc3RDb21tYW5kcyxcbiAgfSwgZmFpbHVyZUJlaGF2aW9yKTtcblxuICBjb25zdCBwcm9ncmFtbWF0aWMgPSB7IGlucHV0LCBpbnN0YWxsQ29tbWFuZHMsIGNvbW1hbmRzIH07XG5cbiAgLy8gUmVzb2x2ZSB0aGUgcGx1Z2luJ3MgcnVudGltZSBpbWFnZS4gQ29kZUJ1aWxkIGRlZmF1bHRzIHRvXG4gIC8vIGBhd3MvY29kZWJ1aWxkL3N0YW5kYXJkOjcuMGAgd2hlbiBubyBgYnVpbGRJbWFnZWAgaXMgc2V0IOKAlCB0aGF0J3MgdGhlXG4gIC8vIEFXUy1tYW5hZ2VkIFVidW50dSBpbWFnZSBhbmQgRE9FUyBOT1QgaGF2ZSBhbnkgcGx1Z2luLWJha2VkIHRvb2xzXG4gIC8vIChwaXBlbGluZS1tYW5hZ2VyLCBzbnlrLCB0ZXJyYWZvcm0sIGV0Yy4pLiBXaXJpbmcgdGhlIHBsdWdpbidzIGltYWdlXG4gIC8vIGhlcmUgbWVhbnMgQ29kZUJ1aWxkIHB1bGxzIGZyb20gb3VyIHByaXZhdGUgcmVnaXN0cnkgYW5kIHRoZSB0b29sc1xuICAvLyBpbnN0YWxsZWQgaW4gdGhlIHBsdWdpbidzIERvY2tlcmZpbGUgYXJlIGFjdHVhbGx5IGF2YWlsYWJsZS5cbiAgY29uc3QgcGx1Z2luQnVpbGRJbWFnZSA9IHJlc29sdmVQbHVnaW5JbWFnZShzY29wZSwgcGx1Z2luLCBvcmdJZCk7XG5cbiAgLy8gU2hlbGxTdGVwIGJyYW5jaC5cbiAgLy8gU2hlbGxTdGVwIGl0c2VsZiBkb2Vzbid0IGFjY2VwdCBgYnVpbGRFbnZpcm9ubWVudGAvYGJ1aWxkSW1hZ2VgLiBDREtcbiAgLy8gcGlwZWxpbmVzIHdyYXBzIFNoZWxsU3RlcHMgaW4gYSBkZWZhdWx0IENvZGVCdWlsZCBhY3Rpb24gdGhhdCBydW5zIG9uXG4gIC8vIGBhd3MvY29kZWJ1aWxkL3N0YW5kYXJkOjcuMGAg4oCUIHdoaWNoIHdvbid0IGhhdmUgdGhlIHBsdWdpbidzIHRvb2xzLlxuICAvL1xuICAvLyBTbyB3aGVuIGEgU0hFTExfU1RFUCBwbHVnaW4gRE9FUyBoYXZlIGFuIGltYWdlIChiZWNhdXNlIGl0cyBhdXRob3JcbiAgLy8gYmFrZWQgdG9vbHMgaW50byBhIERvY2tlcmZpbGUpLCB3ZSBQUk9NT1RFIGl0IHRvIGEgQ29kZUJ1aWxkU3RlcCB3aXRoXG4gIC8vIHRoZSByZXNvbHZlZCBpbWFnZS4gVGhlIHBsdWdpbiBhdXRob3IncyBpbnRlbnQgKFwidXNlIG15IGJha2VkIHRvb2xzXCIpXG4gIC8vIGlzIHByZXNlcnZlZCB3aXRob3V0IGZvcmNpbmcgdGhlbSB0byBjaGFuZ2UgcGx1Z2luVHlwZS5cbiAgLy9cbiAgLy8gV2hlbiB0aGUgcGx1Z2luIGhhcyBubyBpbWFnZSAob3IgcmVnaXN0cnkgaXNuJ3QgY29uZmlndXJlZCksIHdlIGtlZXBcbiAgLy8gdGhlIG9yaWdpbmFsIFNoZWxsU3RlcCDigJQgaXQncyBsaWdodGVyIHdlaWdodCBhbmQgdGhlIGRlZmF1bHRcbiAgLy8gQ29kZUJ1aWxkIGltYWdlIGlzIGZpbmUuXG4gIGlmIChwbHVnaW4ucGx1Z2luVHlwZSA9PT0gUGx1Z2luVHlwZS5TSEVMTF9TVEVQKSB7XG4gICAgaWYgKCFwbHVnaW5CdWlsZEltYWdlKSB7XG4gICAgICByZXR1cm4gbmV3IFNoZWxsU3RlcChpZCwge1xuICAgICAgICAuLi5wcm9ncmFtbWF0aWMsXG4gICAgICAgIGVudjogeyAuLi5lbnYsIC4uLmFjdGlvbkVudiB9LFxuICAgICAgICAuLi5tZXRhZGF0YUZvclNoZWxsU3RlcChtZXJnZWQpLFxuICAgICAgfSk7XG4gICAgfVxuICAgIGxvZy5kZWJ1ZyhgW0NyZWF0ZUNvZGVCdWlsZFN0ZXBdIFNIRUxMX1NURVAgcGx1Z2luIFwiJHtwbHVnaW4ubmFtZX1cIiBoYXMgYSByZWdpc3RyeSBpbWFnZSDigJQgcHJvbW90aW5nIHRvIENvZGVCdWlsZFN0ZXAgc28gdGhlIHBsdWdpbiBpbWFnZSBpcyBhY3R1YWxseSB1c2VkYCk7XG4gICAgLy8gRmFsbCB0aHJvdWdoIHRvIHRoZSBDb2RlQnVpbGRTdGVwIHBhdGggYmVsb3cuXG4gIH1cblxuICBjb25zdCBjb21wdXRlVHlwZSA9IGdldENvbXB1dGVUeXBlKFxuICAgIHBsdWdpbi5jb21wdXRlVHlwZSA/PyBvcHRpb25zLmRlZmF1bHRDb21wdXRlVHlwZSA/PyAnU01BTEwnLFxuICApO1xuXG4gIC8vIFN0ZXAgbmV0d29yazogZXhwbGljaXQgc3RlcCBjb25maWcgd2lucywgZWxzZSB0aGlzIHN0ZXAncyBgZWMyOm5ldHdvcmtgIG1ldGFkYXRhLlxuICBjb25zdCByZXNvbHZlZE5ldHdvcmsgPSBuZXR3b3JrID8/IG5ldHdvcmtDb25maWdGcm9tTWV0YWRhdGEobWVyZ2VkKTtcbiAgY29uc3QgbmV0d29ya1Byb3BzID0gcmVzb2x2ZWROZXR3b3JrXG4gICAgPyByZXNvbHZlTmV0d29yayhzY29wZSwgb3B0aW9ucy51bmlxdWVJZCwgcmVzb2x2ZWROZXR3b3JrKVxuICAgIDoge307XG5cbiAgLy8gTWV0YWRhdGEgc3ByZWFkIGxhc3Qgc28gaXQgY2FuIG92ZXJyaWRlIHByb2dyYW1tYXRpYyBkZWZhdWx0cy5cbiAgLy8gTk9URTogQ2FjaGluZyBpcyBzdXBwb3J0ZWQgdmlhIHR3byBtZXRhZGF0YSBwYXRoczpcbiAgLy8gICAxLiBNZXRhZGF0YUtleXMuQ0FDSEUgKCdhd3M6Y2RrOnBpcGVsaW5lczpjb2RlYnVpbGRzdGVwOmNhY2hlJykg4oCUIHBhc3NlZCBkaXJlY3RseVxuICAvLyAgICAgIGFzIHRoZSBDb2RlQnVpbGRTdGVwIGBjYWNoZWAgcHJvcCAoZXhwZWN0cyBhIGNvZGVidWlsZC5DYWNoZSBvYmplY3QpLlxuICAvLyAgIDIuIE1ldGFkYXRhS2V5cy5QQVJUSUFMX0JVSUxEX1NQRUMgKCdhd3M6Y2RrOnBpcGVsaW5lczpjb2RlYnVpbGRzdGVwOnBhcnRpYWxidWlsZHNwZWMnKVxuICAvLyAgICAgIOKAlCBwYXNzZWQgYXMgYHBhcnRpYWxCdWlsZFNwZWNgLCB3aGljaCBjYW4gaW5jbHVkZSBhIGBjYWNoZTpgIHNlY3Rpb24gZm9yXG4gIC8vICAgICAgUzMgb3IgbG9jYWwgY2FjaGluZyAoZS5nLiwgQnVpbGRTcGVjLmZyb21PYmplY3QoeyBjYWNoZTogeyBwYXRoczogWy4uLl0gfSB9KSkuXG4gIC8vIFBlci1zdGVwIGJ1aWxkRW52aXJvbm1lbnQgb3ZlcnJpZGVzIGZyb20gbWV0YWRhdGEgKGF3czpjZGs6Y29kZWJ1aWxkOmJ1aWxkZW52aXJvbm1lbnQ6KikuXG4gIC8vIEEgbWV0YWRhdGEtcHJvdmlkZWQgY29tcHV0ZVR5cGUgaXMgYSByYXcgcGFzc3Rocm91Z2gsIHNvIG5vcm1hbGl6ZSBpdCB0aHJvdWdoXG4gIC8vIGdldENvbXB1dGVUeXBlIOKAlCBvdGhlcndpc2UgYSBmcmllbmRseSB2YWx1ZSBsaWtlIFwiTEFSR0VcIiByZWFjaGVzIENvZGVCdWlsZCB2ZXJiYXRpbVxuICAvLyBhbmQgZmFpbHMgd2l0aCBcIkludmFsaWQgY29tcHV0ZSB0eXBlIHByb3ZpZGVkXCIgKGl0IG5lZWRzIEJVSUxEX0dFTkVSQUwxX0xBUkdFKS5cbiAgY29uc3QgcmF3TWV0YUJ1aWxkRW52ID0gbWV0YWRhdGFGb3JCdWlsZEVudmlyb25tZW50KG1lcmdlZCk7XG4gIGNvbnN0IG1ldGFCdWlsZEVudiA9IHR5cGVvZiByYXdNZXRhQnVpbGRFbnYuY29tcHV0ZVR5cGUgPT09ICdzdHJpbmcnXG4gICAgPyB7IC4uLnJhd01ldGFCdWlsZEVudiwgY29tcHV0ZVR5cGU6IGdldENvbXB1dGVUeXBlKHJhd01ldGFCdWlsZEVudi5jb21wdXRlVHlwZSkgfVxuICAgIDogcmF3TWV0YUJ1aWxkRW52O1xuXG4gIGNvbnN0IHN0ZXAgPSBuZXcgQ29kZUJ1aWxkU3RlcChpZCwge1xuICAgIC4uLnByb2dyYW1tYXRpYyxcbiAgICAuLi5uZXR3b3JrUHJvcHMsXG4gICAgLi4uKGFkZGl0aW9uYWxJbnB1dHMgJiYgeyBhZGRpdGlvbmFsSW5wdXRzIH0pLFxuICAgIC4uLih0aW1lb3V0ICYmIHsgdGltZW91dDogRHVyYXRpb24ubWludXRlcyh0aW1lb3V0KSB9KSxcbiAgICBlbnY6IGFjdGlvbkVudixcbiAgICBwcmltYXJ5T3V0cHV0RGlyZWN0b3J5OiBwbHVnaW4ucHJpbWFyeU91dHB1dERpcmVjdG9yeSA/PyB1bmRlZmluZWQsXG4gICAgLy8gUGluIHRoZSBidWlsZHNwZWMgc2hlbGwgdG8gUE9TSVggL2Jpbi9zaCBzbyBleGVjdXRpb24gaXMgaWRlbnRpY2FsIHRvXG4gICAgLy8gQ29kZUJ1aWxkJ3MgZGVmYXVsdCBhbmQgcG9ydGFibGUgYWNyb3NzIG1pbmltYWwgYmFzZSBpbWFnZXMgKG5vIGJhc2hcbiAgICAvLyBkZXBlbmRlbmN5KS4gUGx1Z2luIHNwZWNzIGFyZSBhdXRob3JlZCBQT1NJWC1jbGVhbiB0byBtYXRjaCDigJQgbm8gYmFzaC1vbmx5XG4gICAgLy8gYFtbIF1dYCwgYXJyYXlzLCBgcmVhZCAtcmEgPDw8YCwgb3IgYHNvdXJjZWAvYG52bSB1c2VgL2BzZGsgdXNlYC4gQVxuICAgIC8vIHBsdWdpbi1zdXBwbGllZCBwYXJ0aWFsQnVpbGRTcGVjIChub25lIHRvZGF5KSB3b3VsZCBvdmVycmlkZSB0aGlzIHZpYSB0aGVcbiAgICAvLyBtZXRhZGF0YSBzcHJlYWQgYmVsb3cgYW5kIG11c3QgdGhlbiBzZXQgYGVudi5zaGVsbGAgaXRzZWxmLlxuICAgIHBhcnRpYWxCdWlsZFNwZWM6IEJ1aWxkU3BlYy5mcm9tT2JqZWN0KHsgZW52OiB7IHNoZWxsOiAnL2Jpbi9zaCcgfSB9KSxcbiAgICBidWlsZEVudmlyb25tZW50OiB7XG4gICAgICBjb21wdXRlVHlwZSxcbiAgICAgIGJ1aWxkSW1hZ2U6IHBsdWdpbkJ1aWxkSW1hZ2UgPz8gcmVzb2x2ZURlZmF1bHRCdWlsZEltYWdlKHNjb3BlLCBvcmdJZCksXG4gICAgICBlbnZpcm9ubWVudFZhcmlhYmxlczoge1xuICAgICAgICAuLi50b0NvZGVCdWlsZEVudlZhcnMoZW52KSxcbiAgICAgICAgLi4uc2VjcmV0RW52VmFycyxcbiAgICAgIH0sXG4gICAgICAuLi5tZXRhQnVpbGRFbnYsXG4gICAgfSxcbiAgICAuLi5tZXRhZGF0YUZvckNvZGVCdWlsZFN0ZXAobWVyZ2VkKSxcbiAgfSk7XG5cbiAgLy8gUmVnaXN0ZXIgd2l0aCBhcnRpZmFjdCBtYW5hZ2VyIGlmIHByaW1hcnlPdXRwdXREaXJlY3RvcnkgaXMgc2V0XG4gIGlmIChwbHVnaW4ucHJpbWFyeU91dHB1dERpcmVjdG9yeSAmJiBhcnRpZmFjdE1hbmFnZXIgJiYgc3RhZ2VOYW1lKSB7XG4gICAgY29uc3QgYXJ0aWZhY3RLZXk6IEFydGlmYWN0S2V5ID0ge1xuICAgICAgc3RhZ2VOYW1lLFxuICAgICAgc3RhZ2VBbGlhczogc3RhZ2VBbGlhcyA/PyBgJHtzdGFnZU5hbWV9LWFsaWFzYCxcbiAgICAgIHBsdWdpbk5hbWU6IHBsdWdpbi5uYW1lLFxuICAgICAgcGx1Z2luQWxpYXM6IHBsdWdpbkFsaWFzID8/IGAke3BsdWdpbi5uYW1lfS1hbGlhc2AsXG4gICAgICBvdXRwdXREaXJlY3Rvcnk6IHBsdWdpbi5wcmltYXJ5T3V0cHV0RGlyZWN0b3J5LFxuICAgIH07XG4gICAgYXJ0aWZhY3RNYW5hZ2VyLmFkZChhcnRpZmFjdEtleSwgc3RlcCk7XG4gIH1cblxuICByZXR1cm4gc3RlcDtcbn1cblxuLyoqXG4gKiBDb252ZXJ0IHN0cmluZyBvciBDb21wdXRlVHlwZSBlbnVtIHRvIENESyBDb21wdXRlVHlwZVxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0Q29tcHV0ZVR5cGUoaW5wdXQ6IHN0cmluZyB8IENES0NvbXB1dGVUeXBlID0gJ1NNQUxMJyk6IENES0NvbXB1dGVUeXBlIHtcbiAgLy8gSWYgYWxyZWFkeSBhIENESyBDb21wdXRlVHlwZSwgcmV0dXJuIGFzLWlzXG4gIGlmICh0eXBlb2YgaW5wdXQgIT09ICdzdHJpbmcnKSB7XG4gICAgcmV0dXJuIGlucHV0O1xuICB9XG5cbiAgLy8gQWxyZWFkeSBhIG5hdGl2ZSBDb2RlQnVpbGQgQ29tcHV0ZVR5cGUgKGUuZy4gXCJCVUlMRF9HRU5FUkFMMV9MQVJHRVwiKT8gQWNjZXB0IGFzLWlzXG4gIC8vIHNvIGJvdGggZnJpZW5kbHkgKExBUkdFKSBhbmQgbmF0aXZlIHZhbHVlcyByb3VuZC10cmlwIHdpdGhvdXQgZmFsbGluZyBiYWNrIHRvIFNNQUxMLlxuICBpZiAoKE9iamVjdC52YWx1ZXMoQ0RLQ29tcHV0ZVR5cGUpIGFzIHN0cmluZ1tdKS5pbmNsdWRlcyhpbnB1dCkpIHtcbiAgICByZXR1cm4gaW5wdXQgYXMgQ0RLQ29tcHV0ZVR5cGU7XG4gIH1cblxuICBjb25zdCBub3JtYWxpemVkID0gaW5wdXQudG9VcHBlckNhc2UoKSBhcyBDb21wdXRlVHlwZTtcblxuICBjb25zdCBtYXBwaW5nOiBSZWNvcmQ8Q29tcHV0ZVR5cGUsIENES0NvbXB1dGVUeXBlPiA9IHtcbiAgICBbQ29tcHV0ZVR5cGUuU01BTExdOiBDREtDb21wdXRlVHlwZS5TTUFMTCxcbiAgICBbQ29tcHV0ZVR5cGUuTUVESVVNXTogQ0RLQ29tcHV0ZVR5cGUuTUVESVVNLFxuICAgIFtDb21wdXRlVHlwZS5MQVJHRV06IENES0NvbXB1dGVUeXBlLkxBUkdFLFxuICAgIFtDb21wdXRlVHlwZS5YMl9MQVJHRV06IENES0NvbXB1dGVUeXBlLlgyX0xBUkdFLFxuICB9O1xuXG4gIGNvbnN0IHJlc3VsdCA9IG1hcHBpbmdbbm9ybWFsaXplZF07XG4gIGlmICghcmVzdWx0KSB7XG4gICAgbG9nLndhcm4oYFVua25vd24gY29tcHV0ZSB0eXBlIFwiJHtpbnB1dH1cIiwgZmFsbGluZyBiYWNrIHRvIFNNQUxMYCk7XG4gICAgcmV0dXJuIENES0NvbXB1dGVUeXBlLlNNQUxMO1xuICB9XG4gIHJldHVybiByZXN1bHQ7XG59XG5cbi8qKlxuICogVW53cmFwIGEgU2VjcmV0VmFsdWUgfCBzdHJpbmcgaW50byBhIHBsYWluIHN0cmluZy5cbiAqIFdoZW4gYSBTZWNyZXRWYWx1ZSBpcyBwcm92aWRlZCAoZS5nLiBmcm9tIFNlY3JldHMgTWFuYWdlciksIGNhbGxzIHVuc2FmZVVud3JhcCgpXG4gKiB0byBleHRyYWN0IHRoZSB1bmRlcmx5aW5nIHZhbHVlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdW53cmFwU2VjcmV0KHZhbHVlOiBTZWNyZXRWYWx1ZSB8IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnID8gdmFsdWUgOiB2YWx1ZS51bnNhZmVVbndyYXAoKTtcbn1cbiJdfQ==