@pipeline-builder/pipeline-events 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.
package/lib/index.js ADDED
@@ -0,0 +1,834 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { GetSecretValueCommand, SecretsManagerClient } from '@aws-sdk/client-secrets-manager';
4
+ let codepipelineMod;
5
+ async function loadCodePipeline() {
6
+ if (!codepipelineMod)
7
+ codepipelineMod = (await import('@aws-sdk/client-codepipeline'));
8
+ return codepipelineMod;
9
+ }
10
+ // Variable-specifier loader for SDK clients that are NOT static devDependencies of
11
+ // this package (present only in the Lambda runtime / jest mocks). Passing the
12
+ // specifier as a `string` keeps `tsc` from resolving the module at build time.
13
+ async function loadSdk(pkg) {
14
+ return (await import(pkg));
15
+ }
16
+ /**
17
+ * Pipeline event ingestion Lambda handler.
18
+ *
19
+ * Receives CodePipeline/CodeBuild events from SQS (sourced by EventBridge),
20
+ * parses them into a normalized format, and POSTs them to the reporting service
21
+ * via PLATFORM_BASE_URL.
22
+ *
23
+ * Authentication:
24
+ * - PLATFORM_TOKEN env var (preferred — no Secrets Manager call)
25
+ * - PLATFORM_SECRET_NAME env var → reads the JWT (password) from Secrets Manager
26
+ *
27
+ * Environment variables:
28
+ * - PLATFORM_BASE_URL — Base URL of the platform
29
+ * - PLATFORM_TOKEN — JWT token (set directly, or)
30
+ * - PLATFORM_SECRET_NAME — Secrets Manager secret containing { password: <JWT> }
31
+ * - EVENT_DLQ_ARN — (optional) override for the dead-letter queue ARN used by the
32
+ * self-healing redrive; defaults to `<main-queue-arn>-dlq` derived from the SQS
33
+ * trigger's eventSourceARN.
34
+ */
35
+ const log = {
36
+ info: (msg, data) => console.log(JSON.stringify({ level: 'INFO', message: msg, data, ts: new Date().toISOString() })),
37
+ warn: (msg, data) => console.log(JSON.stringify({ level: 'WARN', message: msg, data, ts: new Date().toISOString() })),
38
+ error: (msg, data) => console.error(JSON.stringify({ level: 'ERROR', message: msg, data, ts: new Date().toISOString() })),
39
+ };
40
+ // ── Tag resolution: pb.pipeline-id + pb.deploys ──────────
41
+ // Pipelines are tagged at CDK synth with:
42
+ // pb.pipeline-id = <platform pipelineId>
43
+ // pb.deploys = <stage>:<env> pairs joined by '+', e.g.
44
+ // "Deploy-stg:staging+Deploy-prod:production"
45
+ // We resolve those tags from the live CodePipeline (region-aware). The ARN/account
46
+ // never leave AWS, so there's no masking. Cached per ARN (warm-container) to avoid
47
+ // hammering the ListTags API.
48
+ //
49
+ // Requires the Lambda execution role to allow `codepipeline:ListTagsForResource`.
50
+ // AccessDenied is a config error (alert loudly); a missing pb.pipeline-id tag is
51
+ // treated as "not yet registered" (skip).
52
+ const PIPELINE_ID_TAG = 'pb.pipeline-id';
53
+ const DEPLOYS_TAG = 'pb.deploys';
54
+ // Canonical per-pipeline org tag (applied at synth by pipeline-core). It is the
55
+ // RESOLVED org for every event of this pipeline — used to key the per-org GitHub
56
+ // token and to attribute ingest-health. orgId is a platform id, never an AWS
57
+ // account id, so it is safe to read/forward.
58
+ const ORG_ID_TAG = 'OrgId';
59
+ const clientsByRegion = new Map();
60
+ // pipelineId=null is a negative cache (resolved-but-untagged); `ts` lets negatives
61
+ // expire so a pipeline tagged AFTER its first event becomes resolvable without
62
+ // recycling the warm container. Positive results stay cached for the lifetime.
63
+ const resolvedByArn = new Map();
64
+ const NEG_CACHE_TTL_MS = 5 * 60 * 1000;
65
+ /** Cap on commit/ref/environment fields — the ingest contract allows max 255. */
66
+ const MAX_ATTR = 255;
67
+ /**
68
+ * Parse the `pb.deploys` tag value into a stage→environment map. The value is
69
+ * `<stage>:<env>` pairs joined by `+` (CodePipeline-tag-safe; no JSON). A stage
70
+ * present here is a deploy; its mapped environment is what the forwarder stamps on
71
+ * that stage's STAGE/ACTION events (DORA deploy attribution). Malformed pairs are
72
+ * skipped defensively.
73
+ */
74
+ function parseDeploys(value) {
75
+ const map = new Map();
76
+ if (!value)
77
+ return map;
78
+ for (const pair of value.split('+')) {
79
+ const idx = pair.indexOf(':');
80
+ if (idx <= 0)
81
+ continue;
82
+ const stage = pair.slice(0, idx).trim();
83
+ const env = pair.slice(idx + 1).trim();
84
+ if (stage && env)
85
+ map.set(stage, env.slice(0, MAX_ATTR));
86
+ }
87
+ return map;
88
+ }
89
+ async function pipelineClient(region) {
90
+ let client = clientsByRegion.get(region);
91
+ if (!client) {
92
+ const { CodePipelineClient } = await loadCodePipeline();
93
+ client = new CodePipelineClient({ region });
94
+ clientsByRegion.set(region, client);
95
+ }
96
+ return client;
97
+ }
98
+ /**
99
+ * Resolve a CodePipeline's tags → the platform pipelineId (pb.pipeline-id) plus the
100
+ * deploy-stage→environment map (pb.deploys). `pipelineId` is null when the pipeline
101
+ * has no pb.pipeline-id tag (unregistered). Throws on AccessDenied so a missing IAM
102
+ * grant surfaces loudly instead of silently dropping every event.
103
+ */
104
+ async function resolvePipeline(arn, region) {
105
+ const cached = resolvedByArn.get(arn);
106
+ // Serve a positive hit for the container lifetime; serve a negative hit only
107
+ // until it expires (then re-resolve, in case the pipeline was since tagged).
108
+ if (cached && (cached.pipelineId !== null || Date.now() - cached.ts < NEG_CACHE_TTL_MS)) {
109
+ return { pipelineId: cached.pipelineId, orgId: cached.orgId, deploys: cached.deploys };
110
+ }
111
+ try {
112
+ const client = await pipelineClient(region);
113
+ const { ListTagsForResourceCommand } = await loadCodePipeline();
114
+ const out = await client.send(new ListTagsForResourceCommand({ resourceArn: arn }));
115
+ const pipelineId = out.tags?.find(t => t.key === PIPELINE_ID_TAG)?.value ?? null;
116
+ const orgId = out.tags?.find(t => t.key === ORG_ID_TAG)?.value ?? null;
117
+ const deploys = parseDeploys(out.tags?.find(t => t.key === DEPLOYS_TAG)?.value);
118
+ if (!pipelineId)
119
+ log.warn('Pipeline missing pb.pipeline-id tag — skipping (register it?)', { arn });
120
+ resolvedByArn.set(arn, { pipelineId, orgId, deploys, ts: Date.now() });
121
+ return { pipelineId, orgId, deploys };
122
+ }
123
+ catch (err) {
124
+ const name = err?.name;
125
+ if (name === 'AccessDeniedException') {
126
+ // Don't cache — this is a fixable misconfig, not a property of the pipeline.
127
+ log.error('AccessDenied calling codepipeline:ListTagsForResource — grant it to the Lambda role', { arn, error: name });
128
+ throw err;
129
+ }
130
+ // Transient/infra errors (throttling, timeouts, 5xx) MUST propagate so the SQS
131
+ // batch is retried rather than silently dropping the event — an event dropped
132
+ // BEFORE it reaches the ingest is lost permanently (the ingest's partial-unique
133
+ // index only dedupes events that were actually POSTed). Only swallow when the
134
+ // failure is a definitive answer that this ARN has no usable tag.
135
+ const e = err;
136
+ const status = e.$metadata?.httpStatusCode;
137
+ const retryable = e.$retryable != null
138
+ || (typeof status === 'number' && status >= 500)
139
+ || /throttl|timeout|toomanyrequests|serviceunavailable|econnreset|networkingerror/i.test(name ?? '');
140
+ if (retryable) {
141
+ log.error('Transient error resolving pb.pipeline-id tag — will retry the batch', { arn, error: name ?? String(err) });
142
+ throw err;
143
+ }
144
+ log.error('Failed to resolve pb.pipeline-id tag', { arn, error: name ?? String(err) });
145
+ return { pipelineId: null, orgId: null, deploys: new Map() };
146
+ }
147
+ }
148
+ // ─── Auth ───────────────────────────────────────────────
149
+ let cachedToken = null;
150
+ async function getAuthToken() {
151
+ if (cachedToken)
152
+ return cachedToken;
153
+ // Path 1: PLATFORM_TOKEN env var (no Secrets Manager call)
154
+ if (process.env.PLATFORM_TOKEN) {
155
+ cachedToken = process.env.PLATFORM_TOKEN;
156
+ log.info('Using PLATFORM_TOKEN from environment');
157
+ return cachedToken;
158
+ }
159
+ // Path 2: PLATFORM_SECRET_NAME → read from Secrets Manager
160
+ const secretName = process.env.PLATFORM_SECRET_NAME;
161
+ if (!secretName) {
162
+ throw new Error('PLATFORM_TOKEN or PLATFORM_SECRET_NAME environment variable is required');
163
+ }
164
+ log.info(`Fetching token from Secrets Manager: ${secretName}`);
165
+ const client = new SecretsManagerClient({});
166
+ const response = await client.send(new GetSecretValueCommand({ SecretId: secretName }));
167
+ if (!response.SecretString)
168
+ throw new Error(`Secret "${secretName}" is empty`);
169
+ const secret = JSON.parse(response.SecretString);
170
+ // infra store-token writes the JWT in `password` (the canonical field — also used by
171
+ // CodeBuild secretsManagerCredentials, the plugin-lookup Lambda, and token-renew).
172
+ const token = secret.password;
173
+ if (!token) {
174
+ throw new Error('Secret missing JWT (password) — run "pipeline-manager infra store-token" to generate');
175
+ }
176
+ cachedToken = token;
177
+ log.info('Using stored JWT token from Secrets Manager');
178
+ return cachedToken;
179
+ }
180
+ // Per-(pipeline,sha) resolved result — computed once, reused across the many events
181
+ // (PIPELINE/STAGE/ACTION) that share a source revision and across redeliveries.
182
+ const commitResultCache = new Map();
183
+ // Last sha we successfully resolved per pipeline — the exclusive lower bound for the
184
+ // next range ("commits since the last deploy"). In-memory only: a cold start resets
185
+ // it, so the first post-cold event resolves as a single commit (expected, defensive).
186
+ const lastShaByPipeline = new Map();
187
+ // Per-sha CodeCommit metadata cache (date + first-parent) for range walks.
188
+ const commitMetaCache = new Map();
189
+ // SCM rate-limit cooldown: after a 403/429 we stop calling the SCM for a while.
190
+ let scmCooldownUntil = 0;
191
+ const SCM_COOLDOWN_MS = 2 * 60 * 1000;
192
+ // Cap the CodeCommit first-parent walk so a long range can't blow the Lambda timeout.
193
+ const MAX_COMMIT_WALK = 50;
194
+ // Per-request timeout for external SCM calls (defensive against slow/hung hosts).
195
+ const SCM_FETCH_TIMEOUT_MS = 3000;
196
+ // The forwarder is a fleet Lambda: one warm container resolves events for MANY
197
+ // orgs, so the GitHub token MUST be keyed by the event's resolved org (not a single
198
+ // container-global token). Each org's token lives at `<prefix>/<orgId>/github-token`,
199
+ // derived from PLATFORM_SECRET_NAME (`<prefix>/<containerOrg>/platform`). null caches
200
+ // a definitive miss (no secret / read failed) → unauthenticated best-effort.
201
+ const githubTokenByOrg = new Map();
202
+ /**
203
+ * Derive a specific org's github-token secret name from PLATFORM_SECRET_NAME
204
+ * (`<prefix>/<containerOrg>/platform`). With an `orgId` we swap the org segment
205
+ * (`<prefix>/<orgId>/github-token`); without one (pipeline carried no OrgId tag) we
206
+ * fall back to the container's own sibling secret. Returns undefined when
207
+ * PLATFORM_SECRET_NAME isn't the expected `.../platform` shape.
208
+ */
209
+ function githubTokenSecretName(orgId) {
210
+ const name = process.env.PLATFORM_SECRET_NAME;
211
+ if (!name || !name.endsWith('/platform'))
212
+ return undefined;
213
+ const base = name.slice(0, -'/platform'.length); // <prefix>/<containerOrg>
214
+ if (orgId) {
215
+ const slash = base.lastIndexOf('/');
216
+ const prefix = slash > 0 ? base.slice(0, slash) : base;
217
+ return `${prefix}/${orgId}/github-token`;
218
+ }
219
+ return `${base}/github-token`;
220
+ }
221
+ /** Read (and cache, per org) the org github token; null → unauthenticated best-effort. */
222
+ async function getGitHubToken(orgId) {
223
+ const key = orgId ?? '';
224
+ const cached = githubTokenByOrg.get(key);
225
+ if (cached !== undefined)
226
+ return cached;
227
+ const secretName = githubTokenSecretName(orgId);
228
+ if (!secretName) {
229
+ githubTokenByOrg.set(key, null);
230
+ return null;
231
+ }
232
+ let token;
233
+ try {
234
+ const client = new SecretsManagerClient({});
235
+ const res = await client.send(new GetSecretValueCommand({ SecretId: secretName }));
236
+ // The github-token secret is a RAW token string (not JSON — CDK resolves it via
237
+ // the default SecretString with no key).
238
+ token = res.SecretString && res.SecretString.length > 0 ? res.SecretString.trim() : null;
239
+ }
240
+ catch (err) {
241
+ log.warn('No github-token secret — GitHub commit resolution will be unauthenticated', { orgId, error: err?.name });
242
+ token = null;
243
+ }
244
+ githubTokenByOrg.set(key, token);
245
+ return token;
246
+ }
247
+ async function fetchWithTimeout(url, opts) {
248
+ const controller = new AbortController();
249
+ const timer = setTimeout(() => controller.abort(), SCM_FETCH_TIMEOUT_MS);
250
+ try {
251
+ return await fetch(url, { ...opts, signal: controller.signal });
252
+ }
253
+ finally {
254
+ clearTimeout(timer);
255
+ }
256
+ }
257
+ /** Normalize a commit date to ISO 8601. Accepts ISO strings and CodeCommit's
258
+ * "<epoch-seconds> +ZZZZ" form. Returns undefined when unparseable. */
259
+ function toIso(value) {
260
+ if (typeof value !== 'string' || value.length === 0)
261
+ return undefined;
262
+ const epoch = /^(\d{9,})\b/.exec(value.trim());
263
+ if (epoch) {
264
+ const d = new Date(Number(epoch[1]) * 1000);
265
+ return Number.isNaN(d.getTime()) ? undefined : d.toISOString();
266
+ }
267
+ const d = new Date(value);
268
+ return Number.isNaN(d.getTime()) ? undefined : d.toISOString();
269
+ }
270
+ /** Classify a source-revision URL into a provider + repo coordinates. */
271
+ function classifySource(url) {
272
+ if (!url)
273
+ return { provider: 'unknown' };
274
+ try {
275
+ const u = new URL(url);
276
+ const host = u.hostname.toLowerCase();
277
+ if (host === 'github.com' || host.endsWith('.github.com')) {
278
+ const parts = u.pathname.split('/').filter(Boolean);
279
+ if (parts.length >= 2)
280
+ return { provider: 'github', owner: parts[0], repo: parts[1].replace(/\.git$/, '') };
281
+ }
282
+ if (host === 'bitbucket.org') {
283
+ const parts = u.pathname.split('/').filter(Boolean);
284
+ if (parts.length >= 2)
285
+ return { provider: 'bitbucket', owner: parts[0], repo: parts[1].replace(/\.git$/, '') };
286
+ }
287
+ if (u.pathname.toLowerCase().includes('codecommit') || u.hash.toLowerCase().includes('codecommit') || u.pathname.includes('/repositories/')) {
288
+ const m = /repositor(?:y|ies)\/([^/#?]+)/.exec(u.pathname + u.hash);
289
+ if (m)
290
+ return { provider: 'codecommit', repositoryName: decodeURIComponent(m[1]) };
291
+ }
292
+ }
293
+ catch {
294
+ // not a URL → unknown
295
+ }
296
+ return { provider: 'unknown' };
297
+ }
298
+ let codecommitClientsByRegion;
299
+ let codecommitMod;
300
+ async function codeCommitClient(region) {
301
+ if (!codecommitMod)
302
+ codecommitMod = await loadSdk('@aws-sdk/client-codecommit');
303
+ if (!codecommitClientsByRegion)
304
+ codecommitClientsByRegion = new Map();
305
+ let client = codecommitClientsByRegion.get(region);
306
+ if (!client) {
307
+ client = new codecommitMod.CodeCommitClient({ region });
308
+ codecommitClientsByRegion.set(region, client);
309
+ }
310
+ return client;
311
+ }
312
+ /** Fetch (cached) a single CodeCommit commit's date + first parents via GetCommit. */
313
+ async function codeCommitMeta(region, repositoryName, commitId) {
314
+ const cached = commitMetaCache.get(commitId);
315
+ if (cached)
316
+ return cached;
317
+ if (!codecommitMod)
318
+ codecommitMod = await loadSdk('@aws-sdk/client-codecommit');
319
+ const client = await codeCommitClient(region);
320
+ const out = await client.send(new codecommitMod.GetCommitCommand({ repositoryName, commitId }));
321
+ const commit = out.commit;
322
+ const meta = { date: toIso(commit?.committer?.date ?? commit?.author?.date), parents: commit?.parents };
323
+ commitMetaCache.set(commitId, meta);
324
+ return meta;
325
+ }
326
+ async function resolveCodeCommit(region, repositoryName, sha, sinceSha) {
327
+ let cur = sha;
328
+ let count = 0;
329
+ let oldest;
330
+ let truncated = false;
331
+ for (let i = 0;; i++) {
332
+ if (!cur)
333
+ break; // reached history root — the whole range is covered
334
+ if (sinceSha && cur === sinceSha)
335
+ break; // reached the exclusive lower bound
336
+ if (i >= MAX_COMMIT_WALK) {
337
+ truncated = true;
338
+ break;
339
+ } // hit the cap before the boundary
340
+ const meta = await codeCommitMeta(region, repositoryName, cur);
341
+ if (!meta?.date)
342
+ break;
343
+ count++;
344
+ oldest = meta.date;
345
+ if (!sinceSha)
346
+ break; // no range → single commit
347
+ cur = meta.parents?.[0];
348
+ }
349
+ // A truncated walk yields a commit NEWER than the true oldest-unshipped commit,
350
+ // which would UNDERSTATE lead time — omit the fields entirely rather than report a
351
+ // wrong (too-small) value. Reporting falls back to `unknown`.
352
+ if (truncated)
353
+ return {};
354
+ return oldest ? { commitTimestamp: oldest, commitCount: count } : {};
355
+ }
356
+ async function resolveGitHub(owner, repo, sha, sinceSha, orgId) {
357
+ const token = await getGitHubToken(orgId);
358
+ const headers = {
359
+ 'Accept': 'application/vnd.github+json',
360
+ 'User-Agent': 'pipeline-builder-forwarder',
361
+ 'X-GitHub-Api-Version': '2022-11-28',
362
+ };
363
+ if (token)
364
+ headers.Authorization = `Bearer ${token}`;
365
+ const rateLimited = (r) => r.status === 403 || r.status === 429;
366
+ if (sinceSha) {
367
+ const r = await fetchWithTimeout(`https://api.github.com/repos/${owner}/${repo}/compare/${sinceSha}...${sha}`, { headers });
368
+ if (rateLimited(r)) {
369
+ scmCooldownUntil = Date.now() + SCM_COOLDOWN_MS;
370
+ return {};
371
+ }
372
+ if (r.ok) {
373
+ const j = await r.json();
374
+ const commits = Array.isArray(j.commits) ? j.commits : [];
375
+ if (commits.length > 0) {
376
+ const oldest = toIso(commits[0]?.commit?.committer?.date ?? commits[0]?.commit?.author?.date);
377
+ if (oldest)
378
+ return { commitTimestamp: oldest, commitCount: commits.length };
379
+ }
380
+ }
381
+ // fall through to single-commit resolution
382
+ }
383
+ const r2 = await fetchWithTimeout(`https://api.github.com/repos/${owner}/${repo}/commits/${sha}`, { headers });
384
+ if (rateLimited(r2)) {
385
+ scmCooldownUntil = Date.now() + SCM_COOLDOWN_MS;
386
+ return {};
387
+ }
388
+ if (r2.ok) {
389
+ const j = await r2.json();
390
+ const d = toIso(j.commit?.committer?.date ?? j.commit?.author?.date);
391
+ if (d)
392
+ return { commitTimestamp: d, commitCount: 1 };
393
+ }
394
+ return {};
395
+ }
396
+ async function resolveBitbucket(owner, repo, sha) {
397
+ const r = await fetchWithTimeout(`https://api.bitbucket.org/2.0/repositories/${owner}/${repo}/commit/${sha}`, {
398
+ headers: { 'User-Agent': 'pipeline-builder-forwarder', 'Accept': 'application/json' },
399
+ });
400
+ if (r.status === 429) {
401
+ scmCooldownUntil = Date.now() + SCM_COOLDOWN_MS;
402
+ return {};
403
+ }
404
+ if (r.ok) {
405
+ const j = await r.json();
406
+ const d = toIso(j.date);
407
+ if (d)
408
+ return { commitTimestamp: d, commitCount: 1 };
409
+ }
410
+ return {};
411
+ }
412
+ /**
413
+ * Resolve `commitTimestamp` + `commitCount` for a source/deploy event, in-account,
414
+ * best-effort. Computed once per (pipelineId, sha); advances the pipeline's range
415
+ * boundary only on success. Never throws — returns {} on any failure.
416
+ */
417
+ async function resolveCommitInfo(pipelineId, orgId, region, src) {
418
+ if (src.provider === 'unknown')
419
+ return {};
420
+ const rkey = `${pipelineId}|${src.sha}`;
421
+ const cached = commitResultCache.get(rkey);
422
+ if (cached)
423
+ return cached;
424
+ const prev = lastShaByPipeline.get(pipelineId);
425
+ const sinceSha = prev && prev !== src.sha ? prev : undefined;
426
+ let info = {};
427
+ try {
428
+ if (src.provider === 'codecommit' && src.repositoryName) {
429
+ info = await resolveCodeCommit(region, src.repositoryName, src.sha, sinceSha);
430
+ }
431
+ else if (src.provider === 'github' && src.owner && src.repo) {
432
+ if (Date.now() >= scmCooldownUntil)
433
+ info = await resolveGitHub(src.owner, src.repo, src.sha, sinceSha, orgId);
434
+ }
435
+ else if (src.provider === 'bitbucket' && src.owner && src.repo) {
436
+ if (Date.now() >= scmCooldownUntil)
437
+ info = await resolveBitbucket(src.owner, src.repo, src.sha);
438
+ }
439
+ }
440
+ catch (err) {
441
+ log.warn('Commit resolution failed (omitting commitTimestamp/commitCount)', { provider: src.provider, error: err?.name ?? String(err) });
442
+ info = {};
443
+ }
444
+ commitResultCache.set(rkey, info);
445
+ if (info.commitTimestamp)
446
+ lastShaByPipeline.set(pipelineId, src.sha);
447
+ return info;
448
+ }
449
+ /** Cap on the stored failure summary — CodeBuild/Deploy summaries can be long. */
450
+ const MAX_ERROR_MESSAGE = 4000;
451
+ /** First non-empty string among the candidates, capped to the ingest max. */
452
+ function firstAttr(...vals) {
453
+ for (const v of vals) {
454
+ if (typeof v === 'string' && v.length > 0)
455
+ return v.slice(0, MAX_ATTR);
456
+ }
457
+ return undefined;
458
+ }
459
+ /**
460
+ * Best-effort extraction of the source commit id + ref (and the revision URL, used
461
+ * only in-account to classify the source type for commit-range resolution) from a
462
+ * CodePipeline event detail. CodePipeline surfaces the source revision under a few
463
+ * shapes depending on the event type / source-action; we check the known ones and
464
+ * leave the fields undefined when none are present (NULL downstream). Never pulls an
465
+ * ARN/account id: only revision/branch/url string fields are read; the revisionUrl
466
+ * is consumed in-account (source classification) and never forwarded on its own.
467
+ */
468
+ function extractCommit(detail) {
469
+ // `source-revisions` (kebab, EventBridge) / `sourceRevisions` (camel) — first entry.
470
+ const revs = (detail['source-revisions'] ?? detail.sourceRevisions);
471
+ const firstRev = Array.isArray(revs) ? revs[0] : undefined;
472
+ // On source actions the revision id can also ride on `execution-result`.
473
+ const execResult = detail['execution-result'];
474
+ const commitSha = firstAttr(detail.commitId, detail.revisionId, firstRev?.revisionId, execResult?.revisionId);
475
+ const commitRef = firstAttr(detail.commitRef, detail.branch, detail.sourceBranch, firstRev?.branchName, firstRev?.branch);
476
+ const revisionUrl = typeof firstRev?.revisionUrl === 'string' ? firstRev.revisionUrl : undefined;
477
+ return { ...(commitSha && { commitSha }), ...(commitRef && { commitRef }), ...(revisionUrl && { revisionUrl }) };
478
+ }
479
+ function classifyEvent(detailType) {
480
+ if (detailType.includes('Pipeline Execution'))
481
+ return { eventType: 'PIPELINE', eventSource: 'codepipeline' };
482
+ if (detailType.includes('Stage Execution'))
483
+ return { eventType: 'STAGE', eventSource: 'codepipeline' };
484
+ if (detailType.includes('Action Execution'))
485
+ return { eventType: 'ACTION', eventSource: 'codepipeline' };
486
+ // CodeBuild "Build State" events identify a build *project*, not a pipeline, so
487
+ // parseRecord drops them on the `eventSource !== 'codepipeline'` check below —
488
+ // the 'BUILD' eventType is never persisted here (plugin BUILD events are
489
+ // recorded directly by the plugin service). The 'codebuild' source is what
490
+ // routes the drop; keep this branch only for that.
491
+ if (detailType.includes('Build State'))
492
+ return { eventType: 'BUILD', eventSource: 'codebuild' };
493
+ return { eventType: 'PIPELINE', eventSource: 'codepipeline' };
494
+ }
495
+ /** Parse + resolve one record to a reportable event, or null to skip it. */
496
+ async function parseRecord(record) {
497
+ let event;
498
+ // A malformed body is a dead message (retrying won't help) — log + skip it so
499
+ // it can't fail the whole batch. Resolution errors below (e.g. AccessDenied)
500
+ // are NOT caught here: those are transient/infra and must propagate to retry.
501
+ try {
502
+ event = JSON.parse(record.body);
503
+ }
504
+ catch (err) {
505
+ log.warn('Skipping SQS record with unparseable body', { messageId: record.messageId, error: String(err) });
506
+ return null;
507
+ }
508
+ const { eventType, eventSource } = classifyEvent(event['detail-type']);
509
+ const detail = { ...event.detail };
510
+ // The raw account never needs to leave AWS now — drop it from the payload.
511
+ delete detail.account;
512
+ // CodeBuild "Build State" events identify a build *project*, not a pipeline,
513
+ // and a project can be shared across pipelines — there's no clean 1:1 mapping
514
+ // to a pipeline id, so skip them.
515
+ if (eventSource !== 'codepipeline') {
516
+ log.warn('Skipping non-CodePipeline event (no pipeline tag to resolve)', { detailType: event['detail-type'] });
517
+ return null;
518
+ }
519
+ const pipelineName = detail.pipeline;
520
+ if (!pipelineName) {
521
+ log.warn('CodePipeline event missing pipeline name — skipping');
522
+ return null;
523
+ }
524
+ // Resolve the pipeline's pb.pipeline-id (= platform pipelineId) + pb.deploys map.
525
+ // The ARN is only a transient handle for the tag lookup; it is never stored.
526
+ const arn = `arn:aws:codepipeline:${event.region}:${event.account}:${pipelineName}`;
527
+ const { pipelineId, orgId, deploys } = await resolvePipeline(arn, event.region);
528
+ if (!pipelineId)
529
+ return null; // untagged / unregistered → skip
530
+ const startedAt = detail['start-time'] || event.time;
531
+ const state = detail.state;
532
+ let durationMs;
533
+ let completedAt;
534
+ if (['SUCCEEDED', 'FAILED', 'CANCELED', 'STOPPED'].includes(state)) {
535
+ completedAt = event.time;
536
+ if (startedAt && completedAt) {
537
+ const ms = new Date(completedAt).getTime() - new Date(startedAt).getTime();
538
+ if (ms >= 0)
539
+ durationMs = ms;
540
+ }
541
+ }
542
+ // Promote the failure reason to a typed field. On Action events AWS puts the
543
+ // human-readable summary (and a log URL + error-code, which stay in `detail`)
544
+ // under `execution-result`.
545
+ const result = detail['execution-result'];
546
+ const summary = result?.['external-execution-summary'];
547
+ const errorMessage = typeof summary === 'string' && summary.length > 0
548
+ ? summary.slice(0, MAX_ERROR_MESSAGE)
549
+ : undefined;
550
+ // DORA deploy attribution — all optional: omitted (undefined) when the
551
+ // event/pipeline doesn't carry them.
552
+ const { commitSha, commitRef, revisionUrl } = extractCommit(detail);
553
+ const executionId = detail['execution-id'];
554
+ const stageName = detail.stage;
555
+ const actionName = detail.action;
556
+ // Environment (⇒ isDeploy) is set ONLY when this event's stage is listed in the
557
+ // pipeline's pb.deploys tag. PIPELINE events have no stage → never a deploy.
558
+ const environment = stageName ? deploys.get(stageName) : undefined;
559
+ // Phase 4 — resolve the commit range (oldest-unshipped timestamp + count) for any
560
+ // event carrying a commit. Best-effort/in-account; omitted on any failure.
561
+ // GATED on `DORA_ENABLED` (set by `setup-events --with-dora`): DORA lead time is an
562
+ // advanced_reporting add-on, so orgs without it skip the SCM/secret cost entirely —
563
+ // standard reporting (commitSha + all other fields) still forwards regardless.
564
+ let commitTimestamp;
565
+ let commitCount;
566
+ if (commitSha && process.env.DORA_ENABLED === 'true') {
567
+ const src = classifySource(revisionUrl);
568
+ const info = await resolveCommitInfo(pipelineId, orgId, event.region, { sha: commitSha, ...src });
569
+ commitTimestamp = info.commitTimestamp;
570
+ commitCount = info.commitCount;
571
+ }
572
+ return {
573
+ orgId,
574
+ pipelineId,
575
+ eventSource,
576
+ eventType,
577
+ status: state,
578
+ executionId,
579
+ stageName,
580
+ actionName,
581
+ errorMessage,
582
+ startedAt,
583
+ completedAt,
584
+ durationMs,
585
+ ...(commitSha && { commitSha }),
586
+ ...(commitRef && { commitRef }),
587
+ ...(commitTimestamp && { commitTimestamp }),
588
+ ...(commitCount && { commitCount }),
589
+ ...(environment && { environment }),
590
+ detail,
591
+ };
592
+ }
593
+ let sqsMod;
594
+ let sqsClientsByRegion;
595
+ async function sqsClient(region) {
596
+ if (!sqsMod)
597
+ sqsMod = await loadSdk('@aws-sdk/client-sqs');
598
+ if (!sqsClientsByRegion)
599
+ sqsClientsByRegion = new Map();
600
+ let client = sqsClientsByRegion.get(region);
601
+ if (!client) {
602
+ client = new sqsMod.SQSClient({ region });
603
+ sqsClientsByRegion.set(region, client);
604
+ }
605
+ return client;
606
+ }
607
+ // Delivery-health counters are attributed PER RESOLVED ORG (the forwarder is a fleet
608
+ // Lambda serving many orgs; a single global counter would mis-attribute one org's
609
+ // throughput to another). Keyed by orgId ('' bucket = pipeline with no OrgId tag).
610
+ // The DLQ depth (`dropped`) is genuinely fleet-global — one shared DLQ — so it is a
611
+ // single snapshot posted alongside each org's health, documented as the shared depth.
612
+ const forwardedByOrg = new Map();
613
+ const lastEventAtByOrg = new Map();
614
+ let lastHealthAt = 0;
615
+ let lastRedriveAt = 0;
616
+ const HEALTH_THROTTLE_MS = 60 * 1000;
617
+ const REDRIVE_THROTTLE_MS = 5 * 60 * 1000;
618
+ // Poison-message ceiling: if the oldest DLQ message is older than this, we STOP
619
+ // redriving it (DLQ→main→fail→DLQ would loop forever). Such messages are left for an
620
+ // alarm / manual inspection instead of churning the fleet indefinitely.
621
+ const MAX_DLQ_REDRIVE_AGE_SEC = 6 * 60 * 60; // 6 hours
622
+ /** Parse the SQS trigger ARN and derive the main + DLQ ARNs and the DLQ URL. */
623
+ function deriveQueues(mainQueueArn) {
624
+ if (!mainQueueArn)
625
+ return undefined;
626
+ // arn:aws:sqs:{region}:{account}:{name}
627
+ const parts = mainQueueArn.split(':');
628
+ if (parts.length < 6 || parts[2] !== 'sqs')
629
+ return undefined;
630
+ const [, , , region, account, name] = parts;
631
+ const dlqArn = process.env.EVENT_DLQ_ARN || `arn:aws:sqs:${region}:${account}:${name}-dlq`;
632
+ const dlqName = dlqArn.split(':').pop() ?? `${name}-dlq`;
633
+ const dlqUrl = `https://sqs.${region}.amazonaws.com/${account}/${dlqName}`;
634
+ return { region, mainArn: mainQueueArn, dlqArn, dlqUrl };
635
+ }
636
+ /** Snapshot the DLQ depth + the age (seconds) of its oldest message (for the
637
+ * poison-message redrive ceiling). Missing/NaN attributes fall back to 0. */
638
+ async function dlqStats(region, dlqUrl) {
639
+ if (!sqsMod)
640
+ sqsMod = await loadSdk('@aws-sdk/client-sqs');
641
+ const client = await sqsClient(region);
642
+ const out = await client.send(new sqsMod.GetQueueAttributesCommand({
643
+ QueueUrl: dlqUrl,
644
+ AttributeNames: ['ApproximateNumberOfMessages', 'ApproximateAgeOfOldestMessage'],
645
+ }));
646
+ const n = Number(out.Attributes?.ApproximateNumberOfMessages ?? '0');
647
+ const age = Number(out.Attributes?.ApproximateAgeOfOldestMessage ?? '0');
648
+ return {
649
+ depth: Number.isFinite(n) ? n : 0,
650
+ oldestAgeSec: Number.isFinite(age) ? age : 0,
651
+ };
652
+ }
653
+ async function hasActiveMoveTask(region, dlqArn) {
654
+ if (!sqsMod)
655
+ sqsMod = await loadSdk('@aws-sdk/client-sqs');
656
+ const client = await sqsClient(region);
657
+ const out = await client.send(new sqsMod.ListMessageMoveTasksCommand({ SourceArn: dlqArn }));
658
+ return (out.Results ?? []).some(t => t.Status === 'RUNNING');
659
+ }
660
+ async function startMoveTask(region, dlqArn, mainArn) {
661
+ if (!sqsMod)
662
+ sqsMod = await loadSdk('@aws-sdk/client-sqs');
663
+ const client = await sqsClient(region);
664
+ await client.send(new sqsMod.StartMessageMoveTaskCommand({ SourceArn: dlqArn, DestinationArn: mainArn }));
665
+ }
666
+ /** POST one org's ingest-health signal. Returns true only on a confirmed 2xx so the
667
+ * caller resets that org's `forwarded` counter ONLY when the signal was accepted
668
+ * (a dropped/failed POST must not silently zero the accumulated count). */
669
+ async function postIngestHealth(baseUrl, body) {
670
+ try {
671
+ const token = await getAuthToken();
672
+ const res = await fetch(`${baseUrl}/api/reports/ingest-health`, {
673
+ method: 'POST',
674
+ headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
675
+ body: JSON.stringify(body),
676
+ });
677
+ if (!res.ok) {
678
+ log.warn('ingest-health POST returned non-2xx (ignored)', { status: res.status, orgId: body.orgId });
679
+ return false;
680
+ }
681
+ return true;
682
+ }
683
+ catch (err) {
684
+ log.warn('ingest-health POST failed (ignored)', { error: String(err), orgId: body.orgId });
685
+ return false;
686
+ }
687
+ }
688
+ /**
689
+ * Throttled, best-effort post-success work: emit per-org ingest-health and self-heal
690
+ * the DLQ. Never throws. `forwarded`/`lastEventAt` accumulate PER ORG across batches
691
+ * between health posts; `dropped` is the shared fleet DLQ depth snapshot. A per-org
692
+ * counter is zeroed only after that org's health POST is confirmed 2xx.
693
+ */
694
+ async function reportHealthAndRedrive(baseUrl, mainQueueArn) {
695
+ const now = Date.now();
696
+ if (now - lastHealthAt < HEALTH_THROTTLE_MS)
697
+ return;
698
+ lastHealthAt = now;
699
+ try {
700
+ const q = deriveQueues(mainQueueArn);
701
+ let depth = 0;
702
+ let oldestAgeSec = 0;
703
+ if (q) {
704
+ try {
705
+ const stats = await dlqStats(q.region, q.dlqUrl);
706
+ depth = stats.depth;
707
+ oldestAgeSec = stats.oldestAgeSec;
708
+ }
709
+ catch (err) {
710
+ log.warn('DLQ stats check failed (ignored)', { error: err?.name ?? String(err) });
711
+ }
712
+ }
713
+ // Post one health signal per resolved org, attributing its own forwarded count +
714
+ // last event time. `dropped` (the shared fleet DLQ depth) rides along on each.
715
+ // Snapshot the keys first so we don't mutate the map while iterating.
716
+ const orgKeys = new Set([...forwardedByOrg.keys(), ...lastEventAtByOrg.keys()]);
717
+ if (orgKeys.size === 0)
718
+ orgKeys.add(''); // nothing forwarded yet → still report depth
719
+ for (const key of orgKeys) {
720
+ const forwarded = forwardedByOrg.get(key) ?? 0;
721
+ const lastEventAt = lastEventAtByOrg.get(key);
722
+ const ok = await postIngestHealth(baseUrl, {
723
+ ...(key ? { orgId: key } : {}),
724
+ forwarded,
725
+ dropped: depth,
726
+ lastEventAt,
727
+ });
728
+ // Reset the forwarded counter ONLY on a confirmed 2xx — a failed/dropped POST
729
+ // keeps the count so the next tick re-reports it instead of losing it.
730
+ if (ok)
731
+ forwardedByOrg.set(key, 0);
732
+ }
733
+ if (q && depth > 0 && now - lastRedriveAt >= REDRIVE_THROTTLE_MS) {
734
+ // Poison-message ceiling: never redrive a DLQ whose oldest message has aged
735
+ // past the ceiling — that message keeps failing and would loop DLQ→main→DLQ.
736
+ if (oldestAgeSec > MAX_DLQ_REDRIVE_AGE_SEC) {
737
+ log.warn('DLQ oldest message exceeds poison-age ceiling — skipping redrive (needs manual attention)', {
738
+ dlqArn: q.dlqArn, dropped: depth, oldestAgeSec, ceilingSec: MAX_DLQ_REDRIVE_AGE_SEC,
739
+ });
740
+ }
741
+ else {
742
+ try {
743
+ if (!(await hasActiveMoveTask(q.region, q.dlqArn))) {
744
+ lastRedriveAt = now;
745
+ await startMoveTask(q.region, q.dlqArn, q.mainArn);
746
+ log.info('Started self-healing DLQ→main redrive', { dlqArn: q.dlqArn, dropped: depth, oldestAgeSec });
747
+ }
748
+ }
749
+ catch (err) {
750
+ log.warn('DLQ redrive failed (ignored)', { error: err?.name ?? String(err) });
751
+ }
752
+ }
753
+ }
754
+ }
755
+ catch (err) {
756
+ log.warn('health/redrive step failed (ignored)', { error: String(err) });
757
+ }
758
+ }
759
+ // ─── Handler ────────────────────────────────────────────
760
+ export const handler = async (event) => {
761
+ const baseUrl = process.env.PLATFORM_BASE_URL;
762
+ if (!baseUrl)
763
+ throw new Error('PLATFORM_BASE_URL environment variable is required');
764
+ // Parse + resolve all records (tag + commit lookups run concurrently); drop
765
+ // intentional skips (null). A malformed record BODY is handled inside parseRecord
766
+ // (logged + skipped) so one bad message can't fail the whole batch — while genuine
767
+ // infra errors (e.g. AccessDenied on the tag lookup) still propagate so a missing
768
+ // IAM grant surfaces and SQS retries the batch.
769
+ const events = (await Promise.all(event.Records.map(parseRecord)))
770
+ .filter((e) => e !== null);
771
+ if (events.length === 0) {
772
+ log.info('No resolvable CodePipeline events in batch');
773
+ return;
774
+ }
775
+ // POST batch to reporting service. On a 401/403 the cached JWT has likely
776
+ // expired — drop it, re-fetch, and retry ONCE so an expired token doesn't
777
+ // permanently brick a warm container. `orgId` is INTERNAL (token/health keying) —
778
+ // strip it here so it never rides the wire; the ingest resolves org from the
779
+ // pipeline registry, not the body.
780
+ const payloadEvents = events.map(({ orgId: _orgId, ...rest }) => rest);
781
+ const post = (token) => fetch(`${baseUrl}/api/reports/events`, {
782
+ method: 'POST',
783
+ headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
784
+ body: JSON.stringify({ events: payloadEvents }),
785
+ });
786
+ let res = await post(await getAuthToken());
787
+ if (res.status === 401 || res.status === 403) {
788
+ log.warn('Reporting API auth failed; refreshing token and retrying once', { status: res.status });
789
+ cachedToken = null;
790
+ res = await post(await getAuthToken());
791
+ }
792
+ if (!res.ok) {
793
+ const body = await res.text().catch(() => '');
794
+ log.error(`Reporting API returned ${res.status}`, { body });
795
+ throw new Error(`Reporting API failed: ${res.status}`);
796
+ }
797
+ // The insert already succeeded (2xx). The parsed body is only used for a log
798
+ // line, so a non-JSON/empty body must not throw and fail the whole batch —
799
+ // that would trigger an SQS redelivery and re-POST (duplicate) already-inserted
800
+ // events. The ingest's partial-unique index dedupes, but avoid the churn anyway.
801
+ const result = await res.json().catch(() => ({}));
802
+ log.info(`Ingested ${events.length} events`, { inserted: result.data });
803
+ // Accumulate delivery-health counters PER RESOLVED ORG, then run the throttled
804
+ // post-success health + self-healing DLQ redrive (best-effort, never fails batch).
805
+ for (const e of events) {
806
+ const key = e.orgId ?? '';
807
+ forwardedByOrg.set(key, (forwardedByOrg.get(key) ?? 0) + 1);
808
+ const at = e.completedAt || e.startedAt;
809
+ if (at) {
810
+ const prev = lastEventAtByOrg.get(key);
811
+ if (!prev || at > prev)
812
+ lastEventAtByOrg.set(key, at);
813
+ }
814
+ }
815
+ await reportHealthAndRedrive(baseUrl, event.Records[0]?.eventSourceARN);
816
+ };
817
+ /**
818
+ * @internal Test-only: reset all module-level caches/throttle state so tests are
819
+ * isolated from one another. Stripped from the published .d.ts (stripInternal).
820
+ */
821
+ export function _resetForTests() {
822
+ resolvedByArn.clear();
823
+ commitResultCache.clear();
824
+ lastShaByPipeline.clear();
825
+ commitMetaCache.clear();
826
+ scmCooldownUntil = 0;
827
+ githubTokenByOrg.clear();
828
+ forwardedByOrg.clear();
829
+ lastEventAtByOrg.clear();
830
+ lastHealthAt = 0;
831
+ lastRedriveAt = 0;
832
+ cachedToken = null;
833
+ }
834
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0QyxPQUFPLEVBQUUscUJBQXFCLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQWtCOUYsSUFBSSxlQUErQyxDQUFDO0FBQ3BELEtBQUssVUFBVSxnQkFBZ0I7SUFDN0IsSUFBSSxDQUFDLGVBQWU7UUFBRSxlQUFlLEdBQUcsQ0FBQyxNQUFNLE1BQU0sQ0FBQyw4QkFBOEIsQ0FBQyxDQUFrQyxDQUFDO0lBQ3hILE9BQU8sZUFBZSxDQUFDO0FBQ3pCLENBQUM7QUFFRCxtRkFBbUY7QUFDbkYsOEVBQThFO0FBQzlFLCtFQUErRTtBQUMvRSxLQUFLLFVBQVUsT0FBTyxDQUFJLEdBQVc7SUFDbkMsT0FBTyxDQUFDLE1BQU0sTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFNLENBQUM7QUFDbEMsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FrQkc7QUFFSCxNQUFNLEdBQUcsR0FBRztJQUNWLElBQUksRUFBRSxDQUFDLEdBQVcsRUFBRSxJQUFjLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFLElBQUksSUFBSSxFQUFFLENBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ3ZJLElBQUksRUFBRSxDQUFDLEdBQVcsRUFBRSxJQUFjLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFLElBQUksSUFBSSxFQUFFLENBQUMsV0FBVyxF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RyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQzVELE1BQU0sRUFBRSxHQUFHLENBQUMsQ0FBQyxXQUFXLElBQUksQ0FBQyxDQUFDLFNBQVMsQ0FBQztRQUN4QyxJQUFJLEVBQUUsRUFBRSxDQUFDO1lBQ1AsTUFBTSxJQUFJLEdBQUcsZ0JBQWdCLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ3ZDLElBQUksQ0FBQyxJQUFJLElBQUksRUFBRSxHQUFHLElBQUk7Z0JBQUUsZ0JBQWdCLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUN4RCxDQUFDO0lBQ0gsQ0FBQztJQUNELE1BQU0sc0JBQXNCLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsY0FBYyxDQUFDLENBQUM7QUFDMUUsQ0FBQyxDQUFDO0FBRUY7OztHQUdHO0FBQ0gsTUFBTSxVQUFVLGNBQWM7SUFDNUIsYUFBYSxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ3RCLGlCQUFpQixDQUFDLEtBQUssRUFBRSxDQUFDO0lBQzFCLGlCQUFpQixDQUFDLEtBQUssRUFBRSxDQUFDO0lBQzFCLGVBQWUsQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUN4QixnQkFBZ0IsR0FBRyxDQUFDLENBQUM7SUFDckIsZ0JBQWdCLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDekIsY0FBYyxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ3ZCLGdCQUFnQixDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ3pCLFlBQVksR0FBRyxDQUFDLENBQUM7SUFDakIsYUFBYSxHQUFHLENBQUMsQ0FBQztJQUNsQixXQUFXLEdBQUcsSUFBSSxDQUFDO0FBQ3JCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuaW1wb3J0IHsgR2V0U2VjcmV0VmFsdWVDb21tYW5kLCBTZWNyZXRzTWFuYWdlckNsaWVudCB9IGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1zZWNyZXRzLW1hbmFnZXInO1xuaW1wb3J0IHR5cGUgeyBTUVNFdmVudCwgU1FTUmVjb3JkIH0gZnJvbSAnYXdzLWxhbWJkYSc7XG5cbi8vIEFXUyBMYW1iZGEncyBOb2RlIHJ1bnRpbWUgYnVuZGxlcyBAYXdzLXNkayB2Mywgc28gdGhlIENvZGVQaXBlbGluZS9Db2RlQ29tbWl0L1NRU1xuLy8gY2xpZW50cyBhcmUgbG9hZGVkIGxhemlseSB2aWEgZHluYW1pYyBpbXBvcnQoKSDigJQgYSBzdGF0aWMgd29ya3NwYWNlIGRlcGVuZGVuY3kgb25cbi8vIHRoZW0gd291bGQgcGVydHVyYiB0aGUgc2hhcmVkIEBhd3Mtc2RrIHZlcnNpb24gdHJlZSBhbmQgYnJlYWsgb3RoZXIgcGFja2FnZXMnXG4vLyB0eXBpbmdzLiBUaGUgZHluYW1pYyBpbXBvcnQga2VlcHMgdGhlbSBvdXQgb2YgdGhlIHN0YXRpYyBncmFwaCB3aGlsZSBzdGF5aW5nXG4vLyBFU00tY29ycmVjdCAobm8gYHJlcXVpcmVgIGluIGEgdHlwZTptb2R1bGUgcGFja2FnZSkgYW5kIG1vY2thYmxlLiBNaW5pbWFsIGxvY2FsXG4vLyB0eXBlcyBrZWVwIHRoZSBjYWxsIHNpdGVzIHR5cGUtY2hlY2tlZC4gYEBhd3Mtc2RrL2NsaWVudC1jb2RlY29tbWl0YCBhbmRcbi8vIGBAYXdzLXNkay9jbGllbnQtc3FzYCBhcmUgTk9UIGRldkRlcGVuZGVuY2llcyBvZiB0aGlzIHBhY2thZ2UgKHRoZXkgcmVzb2x2ZSBvbmx5XG4vLyBpbnNpZGUgdGhlIExhbWJkYSBydW50aW1lIC8gamVzdCBtb2NrcyksIHNvIHRoZXkgYXJlIGltcG9ydGVkIHRocm91Z2ggYVxuLy8gdmFyaWFibGUtc3BlY2lmaWVyIGhlbHBlciBiZWxvdyBzbyBgdHNjYCBkb2VzIG5vdCB0cnkgdG8gcmVzb2x2ZSB0aGVtLlxuaW50ZXJmYWNlIExpc3RUYWdzT3V0cHV0IHsgdGFncz86IEFycmF5PHsga2V5Pzogc3RyaW5nOyB2YWx1ZT86IHN0cmluZyB9PiB9XG5pbnRlcmZhY2UgQ29kZVBpcGVsaW5lQ2xpZW50TGlrZSB7IHNlbmQoY29tbWFuZDogdW5rbm93bik6IFByb21pc2U8TGlzdFRhZ3NPdXRwdXQ+IH1cbmludGVyZmFjZSBDb2RlUGlwZWxpbmVNb2R1bGUge1xuICBDb2RlUGlwZWxpbmVDbGllbnQ6IG5ldyAoY29uZmlnOiB7IHJlZ2lvbjogc3RyaW5nIH0pID0+IENvZGVQaXBlbGluZUNsaWVudExpa2U7XG4gIExpc3RUYWdzRm9yUmVzb3VyY2VDb21tYW5kOiBuZXcgKGlucHV0OiB7IHJlc291cmNlQXJuOiBzdHJpbmcgfSkgPT4gdW5rbm93bjtcbn1cbmxldCBjb2RlcGlwZWxpbmVNb2Q6IENvZGVQaXBlbGluZU1vZHVsZSB8IHVuZGVmaW5lZDtcbmFzeW5jIGZ1bmN0aW9uIGxvYWRDb2RlUGlwZWxpbmUoKTogUHJvbWlzZTxDb2RlUGlwZWxpbmVNb2R1bGU+IHtcbiAgaWYgKCFjb2RlcGlwZWxpbmVNb2QpIGNvZGVwaXBlbGluZU1vZCA9IChhd2FpdCBpbXBvcnQoJ0Bhd3Mtc2RrL2NsaWVudC1jb2RlcGlwZWxpbmUnKSkgYXMgdW5rbm93biBhcyBDb2RlUGlwZWxpbmVNb2R1bGU7XG4gIHJldHVybiBjb2RlcGlwZWxpbmVNb2Q7XG59XG5cbi8vIFZhcmlhYmxlLXNwZWNpZmllciBsb2FkZXIgZm9yIFNESyBjbGllbnRzIHRoYXQgYXJlIE5PVCBzdGF0aWMgZGV2RGVwZW5kZW5jaWVzIG9mXG4vLyB0aGlzIHBhY2thZ2UgKHByZXNlbnQgb25seSBpbiB0aGUgTGFtYmRhIHJ1bnRpbWUgLyBqZXN0IG1vY2tzKS4gUGFzc2luZyB0aGVcbi8vIHNwZWNpZmllciBhcyBhIGBzdHJpbmdgIGtlZXBzIGB0c2NgIGZyb20gcmVzb2x2aW5nIHRoZSBtb2R1bGUgYXQgYnVpbGQgdGltZS5cbmFzeW5jIGZ1bmN0aW9uIGxvYWRTZGs8VD4ocGtnOiBzdHJpbmcpOiBQcm9taXNlPFQ+IHtcbiAgcmV0dXJuIChhd2FpdCBpbXBvcnQocGtnKSkgYXMgVDtcbn1cblxuLyoqXG4gKiBQaXBlbGluZSBldmVudCBpbmdlc3Rpb24gTGFtYmRhIGhhbmRsZXIuXG4gKlxuICogUmVjZWl2ZXMgQ29kZVBpcGVsaW5lL0NvZGVCdWlsZCBldmVudHMgZnJvbSBTUVMgKHNvdXJjZWQgYnkgRXZlbnRCcmlkZ2UpLFxuICogcGFyc2VzIHRoZW0gaW50byBhIG5vcm1hbGl6ZWQgZm9ybWF0LCBhbmQgUE9TVHMgdGhlbSB0byB0aGUgcmVwb3J0aW5nIHNlcnZpY2VcbiAqIHZpYSBQTEFURk9STV9CQVNFX1VSTC5cbiAqXG4gKiBBdXRoZW50aWNhdGlvbjpcbiAqIC0gUExBVEZPUk1fVE9LRU4gZW52IHZhciAocHJlZmVycmVkIOKAlCBubyBTZWNyZXRzIE1hbmFnZXIgY2FsbClcbiAqIC0gUExBVEZPUk1fU0VDUkVUX05BTUUgZW52IHZhciDihpIgcmVhZHMgdGhlIEpXVCAocGFzc3dvcmQpIGZyb20gU2VjcmV0cyBNYW5hZ2VyXG4gKlxuICogRW52aXJvbm1lbnQgdmFyaWFibGVzOlxuICogLSBQTEFURk9STV9CQVNFX1VSTCDigJQgQmFzZSBVUkwgb2YgdGhlIHBsYXRmb3JtXG4gKiAtIFBMQVRGT1JNX1RPS0VOIOKAlCBKV1QgdG9rZW4gKHNldCBkaXJlY3RseSwgb3IpXG4gKiAtIFBMQVRGT1JNX1NFQ1JFVF9OQU1FIOKAlCBTZWNyZXRzIE1hbmFnZXIgc2VjcmV0IGNvbnRhaW5pbmcgeyBwYXNzd29yZDogPEpXVD4gfVxuICogLSBFVkVOVF9ETFFfQVJOIOKAlCAob3B0aW9uYWwpIG92ZXJyaWRlIGZvciB0aGUgZGVhZC1sZXR0ZXIgcXVldWUgQVJOIHVzZWQgYnkgdGhlXG4gKiAgIHNlbGYtaGVhbGluZyByZWRyaXZlOyBkZWZhdWx0cyB0byBgPG1haW4tcXVldWUtYXJuPi1kbHFgIGRlcml2ZWQgZnJvbSB0aGUgU1FTXG4gKiAgIHRyaWdnZXIncyBldmVudFNvdXJjZUFSTi5cbiAqL1xuXG5jb25zdCBsb2cgPSB7XG4gIGluZm86IChtc2c6IHN0cmluZywgZGF0YT86IHVua25vd24pID0+IGNvbnNvbGUubG9nKEpTT04uc3RyaW5naWZ5KHsgbGV2ZWw6ICdJTkZPJywgbWVzc2FnZTogbXNnLCBkYXRhLCB0czogbmV3IERhdGUoKS50b0lTT1N0cmluZygpIH0pKSxcbiAgd2FybjogKG1zZzogc3RyaW5nLCBkYXRhPzogdW5rbm93bikgPT4gY29uc29sZS5sb2coSlNPTi5zdHJpbmdpZnkoeyBsZXZlbDogJ1dBUk4nLCBtZXNzYWdlOiBtc2csIGRhdGEsIHRzOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCkgfSkpLFxuICBlcnJvcjogKG1zZzogc3RyaW5nLCBkYXRhPzogdW5rbm93bikgPT4gY29uc29sZS5lcnJvcihKU09OLnN0cmluZ2lmeSh7IGxldmVsOiAnRVJST1InLCBtZXNzYWdlOiBtc2csIGRhdGEsIHRzOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCkgfSkpLFxufTtcblxuLy8g4pSA4pSAIFRhZyByZXNvbHV0aW9uOiBwYi5waXBlbGluZS1pZCArIHBiLmRlcGxveXMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4vLyBQaXBlbGluZXMgYXJlIHRhZ2dlZCBhdCBDREsgc3ludGggd2l0aDpcbi8vICAgcGIucGlwZWxpbmUtaWQgPSA8cGxhdGZvcm0gcGlwZWxpbmVJZD5cbi8vICAgcGIuZGVwbG95cyAgICAgPSA8c3RhZ2U+OjxlbnY+IHBhaXJzIGpvaW5lZCBieSAnKycsIGUuZy5cbi8vICAgICAgICAgICAgICAgICAgICBcIkRlcGxveS1zdGc6c3RhZ2luZytEZXBsb3ktcHJvZDpwcm9kdWN0aW9uXCJcbi8vIFdlIHJlc29sdmUgdGhvc2UgdGFncyBmcm9tIHRoZSBsaXZlIENvZGVQaXBlbGluZSAocmVnaW9uLWF3YXJlKS4gVGhlIEFSTi9hY2NvdW50XG4vLyBuZXZlciBsZWF2ZSBBV1MsIHNvIHRoZXJlJ3Mgbm8gbWFza2luZy4gQ2FjaGVkIHBlciBBUk4gKHdhcm0tY29udGFpbmVyKSB0byBhdm9pZFxuLy8gaGFtbWVyaW5nIHRoZSBMaXN0VGFncyBBUEkuXG4vL1xuLy8gUmVxdWlyZXMgdGhlIExhbWJkYSBleGVjdXRpb24gcm9sZSB0byBhbGxvdyBgY29kZXBpcGVsaW5lOkxpc3RUYWdzRm9yUmVzb3VyY2VgLlxuLy8gQWNjZXNzRGVuaWVkIGlzIGEgY29uZmlnIGVycm9yIChhbGVydCBsb3VkbHkpOyBhIG1pc3NpbmcgcGIucGlwZWxpbmUtaWQgdGFnIGlzXG4vLyB0cmVhdGVkIGFzIFwibm90IHlldCByZWdpc3RlcmVkXCIgKHNraXApLlxuXG5jb25zdCBQSVBFTElORV9JRF9UQUcgPSAncGIucGlwZWxpbmUtaWQnO1xuY29uc3QgREVQTE9ZU19UQUcgPSAncGIuZGVwbG95cyc7XG4vLyBDYW5vbmljYWwgcGVyLXBpcGVsaW5lIG9yZyB0YWcgKGFwcGxpZWQgYXQgc3ludGggYnkgcGlwZWxpbmUtY29yZSkuIEl0IGlzIHRoZVxuLy8gUkVTT0xWRUQgb3JnIGZvciBldmVyeSBldmVudCBvZiB0aGlzIHBpcGVsaW5lIOKAlCB1c2VkIHRvIGtleSB0aGUgcGVyLW9yZyBHaXRIdWJcbi8vIHRva2VuIGFuZCB0byBhdHRyaWJ1dGUgaW5nZXN0LWhlYWx0aC4gb3JnSWQgaXMgYSBwbGF0Zm9ybSBpZCwgbmV2ZXIgYW4gQVdTXG4vLyBhY2NvdW50IGlkLCBzbyBpdCBpcyBzYWZlIHRvIHJlYWQvZm9yd2FyZC5cbmNvbnN0IE9SR19JRF9UQUcgPSAnT3JnSWQnO1xuY29uc3QgY2xpZW50c0J5UmVnaW9uID0gbmV3IE1hcDxzdHJpbmcsIENvZGVQaXBlbGluZUNsaWVudExpa2U+KCk7XG4vLyBwaXBlbGluZUlkPW51bGwgaXMgYSBuZWdhdGl2ZSBjYWNoZSAocmVzb2x2ZWQtYnV0LXVudGFnZ2VkKTsgYHRzYCBsZXRzIG5lZ2F0aXZlc1xuLy8gZXhwaXJlIHNvIGEgcGlwZWxpbmUgdGFnZ2VkIEFGVEVSIGl0cyBmaXJzdCBldmVudCBiZWNvbWVzIHJlc29sdmFibGUgd2l0aG91dFxuLy8gcmVjeWNsaW5nIHRoZSB3YXJtIGNvbnRhaW5lci4gUG9zaXRpdmUgcmVzdWx0cyBzdGF5IGNhY2hlZCBmb3IgdGhlIGxpZmV0aW1lLlxuY29uc3QgcmVzb2x2ZWRCeUFybiA9IG5ldyBNYXA8c3RyaW5nLCB7IHBpcGVsaW5lSWQ6IHN0cmluZyB8IG51bGw7IG9yZ0lkOiBzdHJpbmcgfCBudWxsOyBkZXBsb3lzOiBNYXA8c3RyaW5nLCBzdHJpbmc+OyB0czogbnVtYmVyIH0+KCk7XG5jb25zdCBORUdfQ0FDSEVfVFRMX01TID0gNSAqIDYwICogMTAwMDtcblxuLyoqIFJlc29sdmVkIHBpcGVsaW5lIG1ldGFkYXRhIHJlYWQgZnJvbSB0aGUgQ29kZVBpcGVsaW5lIHJlc291cmNlIHRhZ3MuICovXG5pbnRlcmZhY2UgUmVzb2x2ZWRQaXBlbGluZSB7XG4gIC8qKiBQbGF0Zm9ybSBwaXBlbGluZUlkIChwYi5waXBlbGluZS1pZCB0YWcpOyBudWxsIHdoZW4gdW50YWdnZWQvdW5yZWdpc3RlcmVkLiAqL1xuICBwaXBlbGluZUlkOiBzdHJpbmcgfCBudWxsO1xuICAvKiogUGxhdGZvcm0gb3JnSWQgKE9yZ0lkIHRhZyk7IG51bGwgd2hlbiB0aGUgcGlwZWxpbmUgY2FycmllcyBubyBvcmcgdGFnLiAqL1xuICBvcmdJZDogc3RyaW5nIHwgbnVsbDtcbiAgLyoqIE1hcCBvZiBkZXBsb3ktc3RhZ2UgbmFtZSDihpIgZW52aXJvbm1lbnQgKHBhcnNlZCBmcm9tIHBiLmRlcGxveXMpLiBFbXB0eSB3aGVuIG5vbmUuICovXG4gIGRlcGxveXM6IE1hcDxzdHJpbmcsIHN0cmluZz47XG59XG5cbi8qKiBDYXAgb24gY29tbWl0L3JlZi9lbnZpcm9ubWVudCBmaWVsZHMg4oCUIHRoZSBpbmdlc3QgY29udHJhY3QgYWxsb3dzIG1heCAyNTUuICovXG5jb25zdCBNQVhfQVRUUiA9IDI1NTtcblxuLyoqXG4gKiBQYXJzZSB0aGUgYHBiLmRlcGxveXNgIHRhZyB2YWx1ZSBpbnRvIGEgc3RhZ2XihpJlbnZpcm9ubWVudCBtYXAuIFRoZSB2YWx1ZSBpc1xuICogYDxzdGFnZT46PGVudj5gIHBhaXJzIGpvaW5lZCBieSBgK2AgKENvZGVQaXBlbGluZS10YWctc2FmZTsgbm8gSlNPTikuIEEgc3RhZ2VcbiAqIHByZXNlbnQgaGVyZSBpcyBhIGRlcGxveTsgaXRzIG1hcHBlZCBlbnZpcm9ubWVudCBpcyB3aGF0IHRoZSBmb3J3YXJkZXIgc3RhbXBzIG9uXG4gKiB0aGF0IHN0YWdlJ3MgU1RBR0UvQUNUSU9OIGV2ZW50cyAoRE9SQSBkZXBsb3kgYXR0cmlidXRpb24pLiBNYWxmb3JtZWQgcGFpcnMgYXJlXG4gKiBza2lwcGVkIGRlZmVuc2l2ZWx5LlxuICovXG5mdW5jdGlvbiBwYXJzZURlcGxveXModmFsdWU6IHN0cmluZyB8IHVuZGVmaW5lZCk6IE1hcDxzdHJpbmcsIHN0cmluZz4ge1xuICBjb25zdCBtYXAgPSBuZXcgTWFwPHN0cmluZywgc3RyaW5nPigpO1xuICBpZiAoIXZhbHVlKSByZXR1cm4gbWFwO1xuICBmb3IgKGNvbnN0IHBhaXIgb2YgdmFsdWUuc3BsaXQoJysnKSkge1xuICAgIGNvbnN0IGlkeCA9IHBhaXIuaW5kZXhPZignOicpO1xuICAgIGlmIChpZHggPD0gMCkgY29udGludWU7XG4gICAgY29uc3Qgc3RhZ2UgPSBwYWlyLnNsaWNlKDAsIGlkeCkudHJpbSgpO1xuICAgIGNvbnN0IGVudiA9IHBhaXIuc2xpY2UoaWR4ICsgMSkudHJpbSgpO1xuICAgIGlmIChzdGFnZSAmJiBlbnYpIG1hcC5zZXQoc3RhZ2UsIGVudi5zbGljZSgwLCBNQVhfQVRUUikpO1xuICB9XG4gIHJldHVybiBtYXA7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHBpcGVsaW5lQ2xpZW50KHJlZ2lvbjogc3RyaW5nKTogUHJvbWlzZTxDb2RlUGlwZWxpbmVDbGllbnRMaWtlPiB7XG4gIGxldCBjbGllbnQgPSBjbGllbnRzQnlSZWdpb24uZ2V0KHJlZ2lvbik7XG4gIGlmICghY2xpZW50KSB7XG4gICAgY29uc3QgeyBDb2RlUGlwZWxpbmVDbGllbnQgfSA9IGF3YWl0IGxvYWRDb2RlUGlwZWxpbmUoKTtcbiAgICBjbGllbnQgPSBuZXcgQ29kZVBpcGVsaW5lQ2xpZW50KHsgcmVnaW9uIH0pO1xuICAgIGNsaWVudHNCeVJlZ2lvbi5zZXQocmVnaW9uLCBjbGllbnQpO1xuICB9XG4gIHJldHVybiBjbGllbnQ7XG59XG5cbi8qKlxuICogUmVzb2x2ZSBhIENvZGVQaXBlbGluZSdzIHRhZ3Mg4oaSIHRoZSBwbGF0Zm9ybSBwaXBlbGluZUlkIChwYi5waXBlbGluZS1pZCkgcGx1cyB0aGVcbiAqIGRlcGxveS1zdGFnZeKGkmVudmlyb25tZW50IG1hcCAocGIuZGVwbG95cykuIGBwaXBlbGluZUlkYCBpcyBudWxsIHdoZW4gdGhlIHBpcGVsaW5lXG4gKiBoYXMgbm8gcGIucGlwZWxpbmUtaWQgdGFnICh1bnJlZ2lzdGVyZWQpLiBUaHJvd3Mgb24gQWNjZXNzRGVuaWVkIHNvIGEgbWlzc2luZyBJQU1cbiAqIGdyYW50IHN1cmZhY2VzIGxvdWRseSBpbnN0ZWFkIG9mIHNpbGVudGx5IGRyb3BwaW5nIGV2ZXJ5IGV2ZW50LlxuICovXG5hc3luYyBmdW5jdGlvbiByZXNvbHZlUGlwZWxpbmUoYXJuOiBzdHJpbmcsIHJlZ2lvbjogc3RyaW5nKTogUHJvbWlzZTxSZXNvbHZlZFBpcGVsaW5lPiB7XG4gIGNvbnN0IGNhY2hlZCA9IHJlc29sdmVkQnlBcm4uZ2V0KGFybik7XG4gIC8vIFNlcnZlIGEgcG9zaXRpdmUgaGl0IGZvciB0aGUgY29udGFpbmVyIGxpZmV0aW1lOyBzZXJ2ZSBhIG5lZ2F0aXZlIGhpdCBvbmx5XG4gIC8vIHVudGlsIGl0IGV4cGlyZXMgKHRoZW4gcmUtcmVzb2x2ZSwgaW4gY2FzZSB0aGUgcGlwZWxpbmUgd2FzIHNpbmNlIHRhZ2dlZCkuXG4gIGlmIChjYWNoZWQgJiYgKGNhY2hlZC5waXBlbGluZUlkICE9PSBudWxsIHx8IERhdGUubm93KCkgLSBjYWNoZWQudHMgPCBORUdfQ0FDSEVfVFRMX01TKSkge1xuICAgIHJldHVybiB7IHBpcGVsaW5lSWQ6IGNhY2hlZC5waXBlbGluZUlkLCBvcmdJZDogY2FjaGVkLm9yZ0lkLCBkZXBsb3lzOiBjYWNoZWQuZGVwbG95cyB9O1xuICB9XG4gIHRyeSB7XG4gICAgY29uc3QgY2xpZW50ID0gYXdhaXQgcGlwZWxpbmVDbGllbnQocmVnaW9uKTtcbiAgICBjb25zdCB7IExpc3RUYWdzRm9yUmVzb3VyY2VDb21tYW5kIH0gPSBhd2FpdCBsb2FkQ29kZVBpcGVsaW5lKCk7XG4gICAgY29uc3Qgb3V0ID0gYXdhaXQgY2xpZW50LnNlbmQobmV3IExpc3RUYWdzRm9yUmVzb3VyY2VDb21tYW5kKHsgcmVzb3VyY2VBcm46IGFybiB9KSk7XG4gICAgY29uc3QgcGlwZWxpbmVJZCA9IG91dC50YWdzPy5maW5kKHQgPT4gdC5rZXkgPT09IFBJUEVMSU5FX0lEX1RBRyk/LnZhbHVlID8/IG51bGw7XG4gICAgY29uc3Qgb3JnSWQgPSBvdXQudGFncz8uZmluZCh0ID0+IHQua2V5ID09PSBPUkdfSURfVEFHKT8udmFsdWUgPz8gbnVsbDtcbiAgICBjb25zdCBkZXBsb3lzID0gcGFyc2VEZXBsb3lzKG91dC50YWdzPy5maW5kKHQgPT4gdC5rZXkgPT09IERFUExPWVNfVEFHKT8udmFsdWUpO1xuICAgIGlmICghcGlwZWxpbmVJZCkgbG9nLndhcm4oJ1BpcGVsaW5lIG1pc3NpbmcgcGIucGlwZWxpbmUtaWQgdGFnIOKAlCBza2lwcGluZyAocmVnaXN0ZXIgaXQ/KScsIHsgYXJuIH0pO1xuICAgIHJlc29sdmVkQnlBcm4uc2V0KGFybiwgeyBwaXBlbGluZUlkLCBvcmdJZCwgZGVwbG95cywgdHM6IERhdGUubm93KCkgfSk7XG4gICAgcmV0dXJuIHsgcGlwZWxpbmVJZCwgb3JnSWQsIGRlcGxveXMgfTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgY29uc3QgbmFtZSA9IChlcnIgYXMgeyBuYW1lPzogc3RyaW5nIH0pPy5uYW1lO1xuICAgIGlmIChuYW1lID09PSAnQWNjZXNzRGVuaWVkRXhjZXB0aW9uJykge1xuICAgICAgLy8gRG9uJ3QgY2FjaGUg4oCUIHRoaXMgaXMgYSBmaXhhYmxlIG1pc2NvbmZpZywgbm90IGEgcHJvcGVydHkgb2YgdGhlIHBpcGVsaW5lLlxuICAgICAgbG9nLmVycm9yKCdBY2Nlc3NEZW5pZWQgY2FsbGluZyBjb2RlcGlwZWxpbmU6TGlzdFRhZ3NGb3JSZXNvdXJjZSDigJQgZ3JhbnQgaXQgdG8gdGhlIExhbWJkYSByb2xlJywgeyBhcm4sIGVycm9yOiBuYW1lIH0pO1xuICAgICAgdGhyb3cgZXJyO1xuICAgIH1cbiAgICAvLyBUcmFuc2llbnQvaW5mcmEgZXJyb3JzICh0aHJvdHRsaW5nLCB0aW1lb3V0cywgNXh4KSBNVVNUIHByb3BhZ2F0ZSBzbyB0aGUgU1FTXG4gICAgLy8gYmF0Y2ggaXMgcmV0cmllZCByYXRoZXIgdGhhbiBzaWxlbnRseSBkcm9wcGluZyB0aGUgZXZlbnQg4oCUIGFuIGV2ZW50IGRyb3BwZWRcbiAgICAvLyBCRUZPUkUgaXQgcmVhY2hlcyB0aGUgaW5nZXN0IGlzIGxvc3QgcGVybWFuZW50bHkgKHRoZSBpbmdlc3QncyBwYXJ0aWFsLXVuaXF1ZVxuICAgIC8vIGluZGV4IG9ubHkgZGVkdXBlcyBldmVudHMgdGhhdCB3ZXJlIGFjdHVhbGx5IFBPU1RlZCkuIE9ubHkgc3dhbGxvdyB3aGVuIHRoZVxuICAgIC8vIGZhaWx1cmUgaXMgYSBkZWZpbml0aXZlIGFuc3dlciB0aGF0IHRoaXMgQVJOIGhhcyBubyB1c2FibGUgdGFnLlxuICAgIGNvbnN0IGUgPSBlcnIgYXMgeyBuYW1lPzogc3RyaW5nOyAkcmV0cnlhYmxlPzogdW5rbm93bjsgJG1ldGFkYXRhPzogeyBodHRwU3RhdHVzQ29kZT86IG51bWJlciB9IH07XG4gICAgY29uc3Qgc3RhdHVzID0gZS4kbWV0YWRhdGE/Lmh0dHBTdGF0dXNDb2RlO1xuICAgIGNvbnN0IHJldHJ5YWJsZSA9IGUuJHJldHJ5YWJsZSAhPSBudWxsXG4gICAgICB8fCAodHlwZW9mIHN0YXR1cyA9PT0gJ251bWJlcicgJiYgc3RhdHVzID49IDUwMClcbiAgICAgIHx8IC90aHJvdHRsfHRpbWVvdXR8dG9vbWFueXJlcXVlc3RzfHNlcnZpY2V1bmF2YWlsYWJsZXxlY29ubnJlc2V0fG5ldHdvcmtpbmdlcnJvci9pLnRlc3QobmFtZSA/PyAnJyk7XG4gICAgaWYgKHJldHJ5YWJsZSkge1xuICAgICAgbG9nLmVycm9yKCdUcmFuc2llbnQgZXJyb3IgcmVzb2x2aW5nIHBiLnBpcGVsaW5lLWlkIHRhZyDigJQgd2lsbCByZXRyeSB0aGUgYmF0Y2gnLCB7IGFybiwgZXJyb3I6IG5hbWUgPz8gU3RyaW5nKGVycikgfSk7XG4gICAgICB0aHJvdyBlcnI7XG4gICAgfVxuICAgIGxvZy5lcnJvcignRmFpbGVkIHRvIHJlc29sdmUgcGIucGlwZWxpbmUtaWQgdGFnJywgeyBhcm4sIGVycm9yOiBuYW1lID8/IFN0cmluZyhlcnIpIH0pO1xuICAgIHJldHVybiB7IHBpcGVsaW5lSWQ6IG51bGwsIG9yZ0lkOiBudWxsLCBkZXBsb3lzOiBuZXcgTWFwKCkgfTtcbiAgfVxufVxuXG4vLyDilIDilIDilIAgQXV0aCDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxubGV0IGNhY2hlZFRva2VuOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcblxuYXN5bmMgZnVuY3Rpb24gZ2V0QXV0aFRva2VuKCk6IFByb21pc2U8c3RyaW5nPiB7XG4gIGlmIChjYWNoZWRUb2tlbikgcmV0dXJuIGNhY2hlZFRva2VuO1xuXG4gIC8vIFBhdGggMTogUExBVEZPUk1fVE9LRU4gZW52IHZhciAobm8gU2VjcmV0cyBNYW5hZ2VyIGNhbGwpXG4gIGlmIChwcm9jZXNzLmVudi5QTEFURk9STV9UT0tFTikge1xuICAgIGNhY2hlZFRva2VuID0gcHJvY2Vzcy5lbnYuUExBVEZPUk1fVE9LRU47XG4gICAgbG9nLmluZm8oJ1VzaW5nIFBMQVRGT1JNX1RPS0VOIGZyb20gZW52aXJvbm1lbnQnKTtcbiAgICByZXR1cm4gY2FjaGVkVG9rZW47XG4gIH1cblxuICAvLyBQYXRoIDI6IFBMQVRGT1JNX1NFQ1JFVF9OQU1FIOKGkiByZWFkIGZyb20gU2VjcmV0cyBNYW5hZ2VyXG4gIGNvbnN0IHNlY3JldE5hbWUgPSBwcm9jZXNzLmVudi5QTEFURk9STV9TRUNSRVRfTkFNRTtcbiAgaWYgKCFzZWNyZXROYW1lKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdQTEFURk9STV9UT0tFTiBvciBQTEFURk9STV9TRUNSRVRfTkFNRSBlbnZpcm9ubWVudCB2YXJpYWJsZSBpcyByZXF1aXJlZCcpO1xuICB9XG5cbiAgbG9nLmluZm8oYEZldGNoaW5nIHRva2VuIGZyb20gU2VjcmV0cyBNYW5hZ2VyOiAke3NlY3JldE5hbWV9YCk7XG4gIGNvbnN0IGNsaWVudCA9IG5ldyBTZWNyZXRzTWFuYWdlckNsaWVudCh7fSk7XG4gIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgY2xpZW50LnNlbmQobmV3IEdldFNlY3JldFZhbHVlQ29tbWFuZCh7IFNlY3JldElkOiBzZWNyZXROYW1lIH0pKTtcblxuICBpZiAoIXJlc3BvbnNlLlNlY3JldFN0cmluZykgdGhyb3cgbmV3IEVycm9yKGBTZWNyZXQgXCIke3NlY3JldE5hbWV9XCIgaXMgZW1wdHlgKTtcblxuICBjb25zdCBzZWNyZXQgPSBKU09OLnBhcnNlKHJlc3BvbnNlLlNlY3JldFN0cmluZykgYXMgUmVjb3JkPHN0cmluZywgc3RyaW5nPjtcbiAgLy8gaW5mcmEgc3RvcmUtdG9rZW4gd3JpdGVzIHRoZSBKV1QgaW4gYHBhc3N3b3JkYCAodGhlIGNhbm9uaWNhbCBmaWVsZCDigJQgYWxzbyB1c2VkIGJ5XG4gIC8vIENvZGVCdWlsZCBzZWNyZXRzTWFuYWdlckNyZWRlbnRpYWxzLCB0aGUgcGx1Z2luLWxvb2t1cCBMYW1iZGEsIGFuZCB0b2tlbi1yZW5ldykuXG4gIGNvbnN0IHRva2VuID0gc2VjcmV0LnBhc3N3b3JkO1xuICBpZiAoIXRva2VuKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdTZWNyZXQgbWlzc2luZyBKV1QgKHBhc3N3b3JkKSDigJQgcnVuIFwicGlwZWxpbmUtbWFuYWdlciBpbmZyYSBzdG9yZS10b2tlblwiIHRvIGdlbmVyYXRlJyk7XG4gIH1cblxuICBjYWNoZWRUb2tlbiA9IHRva2VuO1xuICBsb2cuaW5mbygnVXNpbmcgc3RvcmVkIEpXVCB0b2tlbiBmcm9tIFNlY3JldHMgTWFuYWdlcicpO1xuICByZXR1cm4gY2FjaGVkVG9rZW47XG59XG5cbi8vIOKUgOKUgOKUgCBQaGFzZSA0OiBpbi1hY2NvdW50IGNvbW1pdC1yYW5nZSByZXNvbHV0aW9uIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuLy8gRm9yIGEgc291cmNlL2RlcGxveSBldmVudCBjYXJyeWluZyBhIGNvbW1pdFNoYSB3ZSByZXNvbHZlIHRoZSBjb21taXQgdGltZXN0YW1wXG4vLyAoYW5kIGhvdyBtYW55IGNvbW1pdHMgc2hpcHBlZCkgZm9yIHRoZSByYW5nZSBzaW5jZSB0aGUgbGFzdCByZXNvbHZlZCBzaGEgb2YgdGhlXG4vLyBzYW1lIHBpcGVsaW5lIOKAlCBlbnRpcmVseSBJTi1BQ0NPVU5ULCBwZXIgc291cmNlIHR5cGU6XG4vLyAgIOKAoiBDb2RlQ29tbWl0ICDihpIgQVdTIFNESyBHZXRDb21taXQgKHdhbGsgZmlyc3QtcGFyZW50cyBiYWNrIHRvIHRoZSBib3VuZGFyeSkuXG4vLyAgIOKAoiBHaXRIdWIvQ29kZUNvbm5lY3Rpb25zLUdpdEh1YiDihpIgR2l0SHViIFJFU1QgY29tcGFyZS9jb21taXRzIEFQSS4gQXV0aGVudGljYXRlZFxuLy8gICAgIHdpdGggdGhlIG9yZydzIGBwaXBlbGluZS1idWlsZGVyL3tvcmdJZH0vZ2l0aHViLXRva2VuYCBzZWNyZXQgd2hlbiBwcmVzZW50XG4vLyAgICAgKGRlcml2ZWQgZnJvbSBQTEFURk9STV9TRUNSRVRfTkFNRSksIG90aGVyd2lzZSBiZXN0LWVmZm9ydCB1bmF1dGhlbnRpY2F0ZWQuXG4vLyAgIOKAoiBCaXRidWNrZXQgICDihpIgQml0YnVja2V0IFJFU1QgY29tbWl0IEFQSSAoc2luZ2xlLWNvbW1pdDsgcmFuZ2Ugd2FsayBvbWl0dGVkKS5cbi8vIFRoZSBvbGRlc3QgdW5zaGlwcGVkIGNvbW1pdCdzIHRpbWVzdGFtcCDihpIgYGNvbW1pdFRpbWVzdGFtcGA7IHRoZSBudW1iZXIgb2YgY29tbWl0c1xuLy8gaW4gdGhlIHJhbmdlIOKGkiBgY29tbWl0Q291bnRgLiBFdmVyeXRoaW5nIGhlcmUgaXMgQkVTVC1FRkZPUlQ6IG9uIGFueSBmYWlsdXJlIHRoZVxuLy8gZmllbGRzIGFyZSBzaW1wbHkgb21pdHRlZCAocmVwb3J0aW5nIGZhbGxzIGJhY2sgdG8gYHVua25vd25gKS4gSXQgbXVzdCBORVZFUiBmYWlsXG4vLyB0aGUgYmF0Y2guXG4vL1xuLy8gSUFNIHJlcXVpcmVkIGJ5IHRoaXMgcGF0aCAoZG9jdW1lbnQgb25seSDigJQgZ3JhbnRlZCBvbiB0aGUgZXZlbnRzIHN0YWNrKTpcbi8vICAg4oCiIGNvZGVjb21taXQ6R2V0Q29tbWl0ICAgICAgICAgICAgKENvZGVDb21taXQgc291cmNlcylcbi8vICAg4oCiIHNlY3JldHNtYW5hZ2VyOkdldFNlY3JldFZhbHVlIG9uIGBwaXBlbGluZS1idWlsZGVyLyovZ2l0aHViLXRva2VuYCAodG9rZW4gU0NNIHNvdXJjZXMpXG5cbnR5cGUgU291cmNlUHJvdmlkZXIgPSAnZ2l0aHViJyB8ICdiaXRidWNrZXQnIHwgJ2NvZGVjb21taXQnIHwgJ3Vua25vd24nO1xuaW50ZXJmYWNlIFNvdXJjZVJlZiB7XG4gIHNoYTogc3RyaW5nO1xuICBwcm92aWRlcjogU291cmNlUHJvdmlkZXI7XG4gIG93bmVyPzogc3RyaW5nO1xuICByZXBvPzogc3RyaW5nO1xuICByZXBvc2l0b3J5TmFtZT86IHN0cmluZztcbn1cbmludGVyZmFjZSBDb21taXRJbmZvIHsgY29tbWl0VGltZXN0YW1wPzogc3RyaW5nOyBjb21taXRDb3VudD86IG51bWJlciB9XG5cbi8vIFBlci0ocGlwZWxpbmUsc2hhKSByZXNvbHZlZCByZXN1bHQg4oCUIGNvbXB1dGVkIG9uY2UsIHJldXNlZCBhY3Jvc3MgdGhlIG1hbnkgZXZlbnRzXG4vLyAoUElQRUxJTkUvU1RBR0UvQUNUSU9OKSB0aGF0IHNoYXJlIGEgc291cmNlIHJldmlzaW9uIGFuZCBhY3Jvc3MgcmVkZWxpdmVyaWVzLlxuY29uc3QgY29tbWl0UmVzdWx0Q2FjaGUgPSBuZXcgTWFwPHN0cmluZywgQ29tbWl0SW5mbz4oKTtcbi8vIExhc3Qgc2hhIHdlIHN1Y2Nlc3NmdWxseSByZXNvbHZlZCBwZXIgcGlwZWxpbmUg4oCUIHRoZSBleGNsdXNpdmUgbG93ZXIgYm91bmQgZm9yIHRoZVxuLy8gbmV4dCByYW5nZSAoXCJjb21taXRzIHNpbmNlIHRoZSBsYXN0IGRlcGxveVwiKS4gSW4tbWVtb3J5IG9ubHk6IGEgY29sZCBzdGFydCByZXNldHNcbi8vIGl0LCBzbyB0aGUgZmlyc3QgcG9zdC1jb2xkIGV2ZW50IHJlc29sdmVzIGFzIGEgc2luZ2xlIGNvbW1pdCAoZXhwZWN0ZWQsIGRlZmVuc2l2ZSkuXG5jb25zdCBsYXN0U2hhQnlQaXBlbGluZSA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmc+KCk7XG4vLyBQZXItc2hhIENvZGVDb21taXQgbWV0YWRhdGEgY2FjaGUgKGRhdGUgKyBmaXJzdC1wYXJlbnQpIGZvciByYW5nZSB3YWxrcy5cbmNvbnN0IGNvbW1pdE1ldGFDYWNoZSA9IG5ldyBNYXA8c3RyaW5nLCB7IGRhdGU/OiBzdHJpbmc7IHBhcmVudHM/OiBzdHJpbmdbXSB9PigpO1xuLy8gU0NNIHJhdGUtbGltaXQgY29vbGRvd246IGFmdGVyIGEgNDAzLzQyOSB3ZSBzdG9wIGNhbGxpbmcgdGhlIFNDTSBmb3IgYSB3aGlsZS5cbmxldCBzY21Db29sZG93blVudGlsID0gMDtcbmNvbnN0IFNDTV9DT09MRE9XTl9NUyA9IDIgKiA2MCAqIDEwMDA7XG4vLyBDYXAgdGhlIENvZGVDb21taXQgZmlyc3QtcGFyZW50IHdhbGsgc28gYSBsb25nIHJhbmdlIGNhbid0IGJsb3cgdGhlIExhbWJkYSB0aW1lb3V0LlxuY29uc3QgTUFYX0NPTU1JVF9XQUxLID0gNTA7XG4vLyBQZXItcmVxdWVzdCB0aW1lb3V0IGZvciBleHRlcm5hbCBTQ00gY2FsbHMgKGRlZmVuc2l2ZSBhZ2FpbnN0IHNsb3cvaHVuZyBob3N0cykuXG5jb25zdCBTQ01fRkVUQ0hfVElNRU9VVF9NUyA9IDMwMDA7XG5cbi8vIFRoZSBmb3J3YXJkZXIgaXMgYSBmbGVldCBMYW1iZGE6IG9uZSB3YXJtIGNvbnRhaW5lciByZXNvbHZlcyBldmVudHMgZm9yIE1BTllcbi8vIG9yZ3MsIHNvIHRoZSBHaXRIdWIgdG9rZW4gTVVTVCBiZSBrZXllZCBieSB0aGUgZXZlbnQncyByZXNvbHZlZCBvcmcgKG5vdCBhIHNpbmdsZVxuLy8gY29udGFpbmVyLWdsb2JhbCB0b2tlbikuIEVhY2ggb3JnJ3MgdG9rZW4gbGl2ZXMgYXQgYDxwcmVmaXg+LzxvcmdJZD4vZ2l0aHViLXRva2VuYCxcbi8vIGRlcml2ZWQgZnJvbSBQTEFURk9STV9TRUNSRVRfTkFNRSAoYDxwcmVmaXg+Lzxjb250YWluZXJPcmc+L3BsYXRmb3JtYCkuIG51bGwgY2FjaGVzXG4vLyBhIGRlZmluaXRpdmUgbWlzcyAobm8gc2VjcmV0IC8gcmVhZCBmYWlsZWQpIOKGkiB1bmF1dGhlbnRpY2F0ZWQgYmVzdC1lZmZvcnQuXG5jb25zdCBnaXRodWJUb2tlbkJ5T3JnID0gbmV3IE1hcDxzdHJpbmcsIHN0cmluZyB8IG51bGw+KCk7XG5cbi8qKlxuICogRGVyaXZlIGEgc3BlY2lmaWMgb3JnJ3MgZ2l0aHViLXRva2VuIHNlY3JldCBuYW1lIGZyb20gUExBVEZPUk1fU0VDUkVUX05BTUVcbiAqIChgPHByZWZpeD4vPGNvbnRhaW5lck9yZz4vcGxhdGZvcm1gKS4gV2l0aCBhbiBgb3JnSWRgIHdlIHN3YXAgdGhlIG9yZyBzZWdtZW50XG4gKiAoYDxwcmVmaXg+LzxvcmdJZD4vZ2l0aHViLXRva2VuYCk7IHdpdGhvdXQgb25lIChwaXBlbGluZSBjYXJyaWVkIG5vIE9yZ0lkIHRhZykgd2VcbiAqIGZhbGwgYmFjayB0byB0aGUgY29udGFpbmVyJ3Mgb3duIHNpYmxpbmcgc2VjcmV0LiBSZXR1cm5zIHVuZGVmaW5lZCB3aGVuXG4gKiBQTEFURk9STV9TRUNSRVRfTkFNRSBpc24ndCB0aGUgZXhwZWN0ZWQgYC4uLi9wbGF0Zm9ybWAgc2hhcGUuXG4gKi9cbmZ1bmN0aW9uIGdpdGh1YlRva2VuU2VjcmV0TmFtZShvcmdJZDogc3RyaW5nIHwgbnVsbCk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IG5hbWUgPSBwcm9jZXNzLmVudi5QTEFURk9STV9TRUNSRVRfTkFNRTtcbiAgaWYgKCFuYW1lIHx8ICFuYW1lLmVuZHNXaXRoKCcvcGxhdGZvcm0nKSkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgY29uc3QgYmFzZSA9IG5hbWUuc2xpY2UoMCwgLScvcGxhdGZvcm0nLmxlbmd0aCk7IC8vIDxwcmVmaXg+Lzxjb250YWluZXJPcmc+XG4gIGlmIChvcmdJZCkge1xuICAgIGNvbnN0IHNsYXNoID0gYmFzZS5sYXN0SW5kZXhPZignLycpO1xuICAgIGNvbnN0IHByZWZpeCA9IHNsYXNoID4gMCA/IGJhc2Uuc2xpY2UoMCwgc2xhc2gpIDogYmFzZTtcbiAgICByZXR1cm4gYCR7cHJlZml4fS8ke29yZ0lkfS9naXRodWItdG9rZW5gO1xuICB9XG4gIHJldHVybiBgJHtiYXNlfS9naXRodWItdG9rZW5gO1xufVxuXG4vKiogUmVhZCAoYW5kIGNhY2hlLCBwZXIgb3JnKSB0aGUgb3JnIGdpdGh1YiB0b2tlbjsgbnVsbCDihpIgdW5hdXRoZW50aWNhdGVkIGJlc3QtZWZmb3J0LiAqL1xuYXN5bmMgZnVuY3Rpb24gZ2V0R2l0SHViVG9rZW4ob3JnSWQ6IHN0cmluZyB8IG51bGwpOiBQcm9taXNlPHN0cmluZyB8IG51bGw+IHtcbiAgY29uc3Qga2V5ID0gb3JnSWQgPz8gJyc7XG4gIGNvbnN0IGNhY2hlZCA9IGdpdGh1YlRva2VuQnlPcmcuZ2V0KGtleSk7XG4gIGlmIChjYWNoZWQgIT09IHVuZGVmaW5lZCkgcmV0dXJuIGNhY2hlZDtcbiAgY29uc3Qgc2VjcmV0TmFtZSA9IGdpdGh1YlRva2VuU2VjcmV0TmFtZShvcmdJZCk7XG4gIGlmICghc2VjcmV0TmFtZSkgeyBnaXRodWJUb2tlbkJ5T3JnLnNldChrZXksIG51bGwpOyByZXR1cm4gbnVsbDsgfVxuICBsZXQgdG9rZW46IHN0cmluZyB8IG51bGw7XG4gIHRyeSB7XG4gICAgY29uc3QgY2xpZW50ID0gbmV3IFNlY3JldHNNYW5hZ2VyQ2xpZW50KHt9KTtcbiAgICBjb25zdCByZXMgPSBhd2FpdCBjbGllbnQuc2VuZChuZXcgR2V0U2VjcmV0VmFsdWVDb21tYW5kKHsgU2VjcmV0SWQ6IHNlY3JldE5hbWUgfSkpO1xuICAgIC8vIFRoZSBnaXRodWItdG9rZW4gc2VjcmV0IGlzIGEgUkFXIHRva2VuIHN0cmluZyAobm90IEpTT04g4oCUIENESyByZXNvbHZlcyBpdCB2aWFcbiAgICAvLyB0aGUgZGVmYXVsdCBTZWNyZXRTdHJpbmcgd2l0aCBubyBrZXkpLlxuICAgIHRva2VuID0gcmVzLlNlY3JldFN0cmluZyAmJiByZXMuU2VjcmV0U3RyaW5nLmxlbmd0aCA+IDAgPyByZXMuU2VjcmV0U3RyaW5nLnRyaW0oKSA6IG51bGw7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGxvZy53YXJuKCdObyBnaXRodWItdG9rZW4gc2VjcmV0IOKAlCBHaXRIdWIgY29tbWl0IHJlc29sdXRpb24gd2lsbCBiZSB1bmF1dGhlbnRpY2F0ZWQnLCB7IG9yZ0lkLCBlcnJvcjogKGVyciBhcyB7IG5hbWU/OiBzdHJpbmcgfSk/Lm5hbWUgfSk7XG4gICAgdG9rZW4gPSBudWxsO1xuICB9XG4gIGdpdGh1YlRva2VuQnlPcmcuc2V0KGtleSwgdG9rZW4pO1xuICByZXR1cm4gdG9rZW47XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGZldGNoV2l0aFRpbWVvdXQodXJsOiBzdHJpbmcsIG9wdHM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogUHJvbWlzZTxSZXNwb25zZT4ge1xuICBjb25zdCBjb250cm9sbGVyID0gbmV3IEFib3J0Q29udHJvbGxlcigpO1xuICBjb25zdCB0aW1lciA9IHNldFRpbWVvdXQoKCkgPT4gY29udHJvbGxlci5hYm9ydCgpLCBTQ01fRkVUQ0hfVElNRU9VVF9NUyk7XG4gIHRyeSB7XG4gICAgcmV0dXJuIGF3YWl0IGZldGNoKHVybCwgeyAuLi5vcHRzLCBzaWduYWw6IGNvbnRyb2xsZXIuc2lnbmFsIH0pO1xuICB9IGZpbmFsbHkge1xuICAgIGNsZWFyVGltZW91dCh0aW1lcik7XG4gIH1cbn1cblxuLyoqIE5vcm1hbGl6ZSBhIGNvbW1pdCBkYXRlIHRvIElTTyA4NjAxLiBBY2NlcHRzIElTTyBzdHJpbmdzIGFuZCBDb2RlQ29tbWl0J3NcbiAqICBcIjxlcG9jaC1zZWNvbmRzPiArWlpaWlwiIGZvcm0uIFJldHVybnMgdW5kZWZpbmVkIHdoZW4gdW5wYXJzZWFibGUuICovXG5mdW5jdGlvbiB0b0lzbyh2YWx1ZTogdW5rbm93bik6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGlmICh0eXBlb2YgdmFsdWUgIT09ICdzdHJpbmcnIHx8IHZhbHVlLmxlbmd0aCA9PT0gMCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgY29uc3QgZXBvY2ggPSAvXihcXGR7OSx9KVxcYi8uZXhlYyh2YWx1ZS50cmltKCkpO1xuICBpZiAoZXBvY2gpIHtcbiAgICBjb25zdCBkID0gbmV3IERhdGUoTnVtYmVyKGVwb2NoWzFdKSAqIDEwMDApO1xuICAgIHJldHVybiBOdW1iZXIuaXNOYU4oZC5nZXRUaW1lKCkpID8gdW5kZWZpbmVkIDogZC50b0lTT1N0cmluZygpO1xuICB9XG4gIGNvbnN0IGQgPSBuZXcgRGF0ZSh2YWx1ZSk7XG4gIHJldHVybiBOdW1iZXIuaXNOYU4oZC5nZXRUaW1lKCkpID8gdW5kZWZpbmVkIDogZC50b0lTT1N0cmluZygpO1xufVxuXG4vKiogQ2xhc3NpZnkgYSBzb3VyY2UtcmV2aXNpb24gVVJMIGludG8gYSBwcm92aWRlciArIHJlcG8gY29vcmRpbmF0ZXMuICovXG5mdW5jdGlvbiBjbGFzc2lmeVNvdXJjZSh1cmw6IHN0cmluZyB8IHVuZGVmaW5lZCk6IE9taXQ8U291cmNlUmVmLCAnc2hhJz4ge1xuICBpZiAoIXVybCkgcmV0dXJuIHsgcHJvdmlkZXI6ICd1bmtub3duJyB9O1xuICB0cnkge1xuICAgIGNvbnN0IHUgPSBuZXcgVVJMKHVybCk7XG4gICAgY29uc3QgaG9zdCA9IHUuaG9zdG5hbWUudG9Mb3dlckNhc2UoKTtcbiAgICBpZiAoaG9zdCA9PT0gJ2dpdGh1Yi5jb20nIHx8IGhvc3QuZW5kc1dpdGgoJy5naXRodWIuY29tJykpIHtcbiAgICAgIGNvbnN0IHBhcnRzID0gdS5wYXRobmFtZS5zcGxpdCgnLycpLmZpbHRlcihCb29sZWFuKTtcbiAgICAgIGlmIChwYXJ0cy5sZW5ndGggPj0gMikgcmV0dXJuIHsgcHJvdmlkZXI6ICdnaXRodWInLCBvd25lcjogcGFydHNbMF0sIHJlcG86IHBhcnRzWzFdLnJlcGxhY2UoL1xcLmdpdCQvLCAnJykgfTtcbiAgICB9XG4gICAgaWYgKGhvc3QgPT09ICdiaXRidWNrZXQub3JnJykge1xuICAgICAgY29uc3QgcGFydHMgPSB1LnBhdGhuYW1lLnNwbGl0KCcvJykuZmlsdGVyKEJvb2xlYW4pO1xuICAgICAgaWYgKHBhcnRzLmxlbmd0aCA+PSAyKSByZXR1cm4geyBwcm92aWRlcjogJ2JpdGJ1Y2tldCcsIG93bmVyOiBwYXJ0c1swXSwgcmVwbzogcGFydHNbMV0ucmVwbGFjZSgvXFwuZ2l0JC8sICcnKSB9O1xuICAgIH1cbiAgICBpZiAodS5wYXRobmFtZS50b0xvd2VyQ2FzZSgpLmluY2x1ZGVzKCdjb2RlY29tbWl0JykgfHwgdS5oYXNoLnRvTG93ZXJDYXNlKCkuaW5jbHVkZXMoJ2NvZGVjb21taXQnKSB8fCB1LnBhdGhuYW1lLmluY2x1ZGVzKCcvcmVwb3NpdG9yaWVzLycpKSB7XG4gICAgICBjb25zdCBtID0gL3JlcG9zaXRvcig/Onl8aWVzKVxcLyhbXi8jP10rKS8uZXhlYyh1LnBhdGhuYW1lICsgdS5oYXNoKTtcbiAgICAgIGlmIChtKSByZXR1cm4geyBwcm92aWRlcjogJ2NvZGVjb21taXQnLCByZXBvc2l0b3J5TmFtZTogZGVjb2RlVVJJQ29tcG9uZW50KG1bMV0pIH07XG4gICAgfVxuICB9IGNhdGNoIHtcbiAgICAvLyBub3QgYSBVUkwg4oaSIHVua25vd25cbiAgfVxuICByZXR1cm4geyBwcm92aWRlcjogJ3Vua25vd24nIH07XG59XG5cbmxldCBjb2RlY29tbWl0Q2xpZW50c0J5UmVnaW9uOiBNYXA8c3RyaW5nLCB7IHNlbmQoY29tbWFuZDogdW5rbm93bik6IFByb21pc2U8dW5rbm93bj4gfT4gfCB1bmRlZmluZWQ7XG5pbnRlcmZhY2UgQ29kZUNvbW1pdE1vZHVsZSB7XG4gIENvZGVDb21taXRDbGllbnQ6IG5ldyAoY29uZmlnOiB7IHJlZ2lvbjogc3RyaW5nIH0pID0+IHsgc2VuZChjb21tYW5kOiB1bmtub3duKTogUHJvbWlzZTx1bmtub3duPiB9O1xuICBHZXRDb21taXRDb21tYW5kOiBuZXcgKGlucHV0OiB7IHJlcG9zaXRvcnlOYW1lOiBzdHJpbmc7IGNvbW1pdElkOiBzdHJpbmcgfSkgPT4gdW5rbm93bjtcbn1cbmxldCBjb2RlY29tbWl0TW9kOiBDb2RlQ29tbWl0TW9kdWxlIHwgdW5kZWZpbmVkO1xuYXN5bmMgZnVuY3Rpb24gY29kZUNvbW1pdENsaWVudChyZWdpb246IHN0cmluZyk6IFByb21pc2U8eyBzZW5kKGNvbW1hbmQ6IHVua25vd24pOiBQcm9taXNlPHVua25vd24+IH0+IHtcbiAgaWYgKCFjb2RlY29tbWl0TW9kKSBjb2RlY29tbWl0TW9kID0gYXdhaXQgbG9hZFNkazxDb2RlQ29tbWl0TW9kdWxlPignQGF3cy1zZGsvY2xpZW50LWNvZGVjb21taXQnKTtcbiAgaWYgKCFjb2RlY29tbWl0Q2xpZW50c0J5UmVnaW9uKSBjb2RlY29tbWl0Q2xpZW50c0J5UmVnaW9uID0gbmV3IE1hcCgpO1xuICBsZXQgY2xpZW50ID0gY29kZWNvbW1pdENsaWVudHNCeVJlZ2lvbi5nZXQocmVnaW9uKTtcbiAgaWYgKCFjbGllbnQpIHtcbiAgICBjbGllbnQgPSBuZXcgY29kZWNvbW1pdE1vZC5Db2RlQ29tbWl0Q2xpZW50KHsgcmVnaW9uIH0pO1xuICAgIGNvZGVjb21taXRDbGllbnRzQnlSZWdpb24uc2V0KHJlZ2lvbiwgY2xpZW50KTtcbiAgfVxuICByZXR1cm4gY2xpZW50O1xufVxuXG4vKiogRmV0Y2ggKGNhY2hlZCkgYSBzaW5nbGUgQ29kZUNvbW1pdCBjb21taXQncyBkYXRlICsgZmlyc3QgcGFyZW50cyB2aWEgR2V0Q29tbWl0LiAqL1xuYXN5bmMgZnVuY3Rpb24gY29kZUNvbW1pdE1ldGEocmVnaW9uOiBzdHJpbmcsIHJlcG9zaXRvcnlOYW1lOiBzdHJpbmcsIGNvbW1pdElkOiBzdHJpbmcpOiBQcm9taXNlPHsgZGF0ZT86IHN0cmluZzsgcGFyZW50cz86IHN0cmluZ1tdIH0gfCB1bmRlZmluZWQ+IHtcbiAgY29uc3QgY2FjaGVkID0gY29tbWl0TWV0YUNhY2hlLmdldChjb21taXRJZCk7XG4gIGlmIChjYWNoZWQpIHJldHVybiBjYWNoZWQ7XG4gIGlmICghY29kZWNvbW1pdE1vZCkgY29kZWNvbW1pdE1vZCA9IGF3YWl0IGxvYWRTZGs8Q29kZUNvbW1pdE1vZHVsZT4oJ0Bhd3Mtc2RrL2NsaWVudC1jb2RlY29tbWl0Jyk7XG4gIGNvbnN0IGNsaWVudCA9IGF3YWl0IGNvZGVDb21taXRDbGllbnQocmVnaW9uKTtcbiAgY29uc3Qgb3V0ID0gYXdhaXQgY2xpZW50LnNlbmQobmV3IGNvZGVjb21taXRNb2QuR2V0Q29tbWl0Q29tbWFuZCh7IHJlcG9zaXRvcnlOYW1lLCBjb21taXRJZCB9KSkgYXMge1xuICAgIGNvbW1pdD86IHsgY29tbWl0dGVyPzogeyBkYXRlPzogc3RyaW5nIH07IGF1dGhvcj86IHsgZGF0ZT86IHN0cmluZyB9OyBwYXJlbnRzPzogc3RyaW5nW10gfTtcbiAgfTtcbiAgY29uc3QgY29tbWl0ID0gb3V0LmNvbW1pdDtcbiAgY29uc3QgbWV0YSA9IHsgZGF0ZTogdG9Jc28oY29tbWl0Py5jb21taXR0ZXI/LmRhdGUgPz8gY29tbWl0Py5hdXRob3I/LmRhdGUpLCBwYXJlbnRzOiBjb21taXQ/LnBhcmVudHMgfTtcbiAgY29tbWl0TWV0YUNhY2hlLnNldChjb21taXRJZCwgbWV0YSk7XG4gIHJldHVybiBtZXRhO1xufVxuXG5hc3luYyBmdW5jdGlvbiByZXNvbHZlQ29kZUNvbW1pdChyZWdpb246IHN0cmluZywgcmVwb3NpdG9yeU5hbWU6IHN0cmluZywgc2hhOiBzdHJpbmcsIHNpbmNlU2hhPzogc3RyaW5nKTogUHJvbWlzZTxDb21taXRJbmZvPiB7XG4gIGxldCBjdXI6IHN0cmluZyB8IHVuZGVmaW5lZCA9IHNoYTtcbiAgbGV0IGNvdW50ID0gMDtcbiAgbGV0IG9sZGVzdDogc3RyaW5nIHwgdW5kZWZpbmVkO1xuICBsZXQgdHJ1bmNhdGVkID0gZmFsc2U7XG4gIGZvciAobGV0IGkgPSAwOyA7IGkrKykge1xuICAgIGlmICghY3VyKSBicmVhazsgLy8gcmVhY2hlZCBoaXN0b3J5IHJvb3Qg4oCUIHRoZSB3aG9sZSByYW5nZSBpcyBjb3ZlcmVkXG4gICAgaWYgKHNpbmNlU2hhICYmIGN1ciA9PT0gc2luY2VTaGEpIGJyZWFrOyAvLyByZWFjaGVkIHRoZSBleGNsdXNpdmUgbG93ZXIgYm91bmRcbiAgICBpZiAoaSA+PSBNQVhfQ09NTUlUX1dBTEspIHsgdHJ1bmNhdGVkID0gdHJ1ZTsgYnJlYWs7IH0gLy8gaGl0IHRoZSBjYXAgYmVmb3JlIHRoZSBib3VuZGFyeVxuICAgIGNvbnN0IG1ldGEgPSBhd2FpdCBjb2RlQ29tbWl0TWV0YShyZWdpb24sIHJlcG9zaXRvcnlOYW1lLCBjdXIpO1xuICAgIGlmICghbWV0YT8uZGF0ZSkgYnJlYWs7XG4gICAgY291bnQrKztcbiAgICBvbGRlc3QgPSBtZXRhLmRhdGU7XG4gICAgaWYgKCFzaW5jZVNoYSkgYnJlYWs7IC8vIG5vIHJhbmdlIOKGkiBzaW5nbGUgY29tbWl0XG4gICAgY3VyID0gbWV0YS5wYXJlbnRzPy5bMF07XG4gIH1cbiAgLy8gQSB0cnVuY2F0ZWQgd2FsayB5aWVsZHMgYSBjb21taXQgTkVXRVIgdGhhbiB0aGUgdHJ1ZSBvbGRlc3QtdW5zaGlwcGVkIGNvbW1pdCxcbiAgLy8gd2hpY2ggd291bGQgVU5ERVJTVEFURSBsZWFkIHRpbWUg4oCUIG9taXQgdGhlIGZpZWxkcyBlbnRpcmVseSByYXRoZXIgdGhhbiByZXBvcnQgYVxuICAvLyB3cm9uZyAodG9vLXNtYWxsKSB2YWx1ZS4gUmVwb3J0aW5nIGZhbGxzIGJhY2sgdG8gYHVua25vd25gLlxuICBpZiAodHJ1bmNhdGVkKSByZXR1cm4ge307XG4gIHJldHVybiBvbGRlc3QgPyB7IGNvbW1pdFRpbWVzdGFtcDogb2xkZXN0LCBjb21taXRDb3VudDogY291bnQgfSA6IHt9O1xufVxuXG5hc3luYyBmdW5jdGlvbiByZXNvbHZlR2l0SHViKG93bmVyOiBzdHJpbmcsIHJlcG86IHN0cmluZywgc2hhOiBzdHJpbmcsIHNpbmNlU2hhOiBzdHJpbmcgfCB1bmRlZmluZWQsIG9yZ0lkOiBzdHJpbmcgfCBudWxsKTogUHJvbWlzZTxDb21taXRJbmZvPiB7XG4gIGNvbnN0IHRva2VuID0gYXdhaXQgZ2V0R2l0SHViVG9rZW4ob3JnSWQpO1xuICBjb25zdCBoZWFkZXJzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge1xuICAgICdBY2NlcHQnOiAnYXBwbGljYXRpb24vdm5kLmdpdGh1Yitqc29uJyxcbiAgICAnVXNlci1BZ2VudCc6ICdwaXBlbGluZS1idWlsZGVyLWZvcndhcmRlcicsXG4gICAgJ1gtR2l0SHViLUFwaS1WZXJzaW9uJzogJzIwMjItMTEtMjgnLFxuICB9O1xuICBpZiAodG9rZW4pIGhlYWRlcnMuQXV0aG9yaXphdGlvbiA9IGBCZWFyZXIgJHt0b2tlbn1gO1xuICBjb25zdCByYXRlTGltaXRlZCA9IChyOiBSZXNwb25zZSkgPT4gci5zdGF0dXMgPT09IDQwMyB8fCByLnN0YXR1cyA9PT0gNDI5O1xuXG4gIGlmIChzaW5jZVNoYSkge1xuICAgIGNvbnN0IHIgPSBhd2FpdCBmZXRjaFdpdGhUaW1lb3V0KGBodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zLyR7b3duZXJ9LyR7cmVwb30vY29tcGFyZS8ke3NpbmNlU2hhfS4uLiR7c2hhfWAsIHsgaGVhZGVycyB9KTtcbiAgICBpZiAocmF0ZUxpbWl0ZWQocikpIHsgc2NtQ29vbGRvd25VbnRpbCA9IERhdGUubm93KCkgKyBTQ01fQ09PTERPV05fTVM7IHJldHVybiB7fTsgfVxuICAgIGlmIChyLm9rKSB7XG4gICAgICBjb25zdCBqID0gYXdhaXQgci5qc29uKCkgYXMgeyBjb21taXRzPzogQXJyYXk8eyBjb21taXQ/OiB7IGNvbW1pdHRlcj86IHsgZGF0ZT86IHN0cmluZyB9OyBhdXRob3I/OiB7IGRhdGU/OiBzdHJpbmcgfSB9IH0+IH07XG4gICAgICBjb25zdCBjb21taXRzID0gQXJyYXkuaXNBcnJheShqLmNvbW1pdHMpID8gai5jb21taXRzIDogW107XG4gICAgICBpZiAoY29tbWl0cy5sZW5ndGggPiAwKSB7XG4gICAgICAgIGNvbnN0IG9sZGVzdCA9IHRvSXNvKGNvbW1pdHNbMF0/LmNvbW1pdD8uY29tbWl0dGVyPy5kYXRlID8/IGNvbW1pdHNbMF0/LmNvbW1pdD8uYXV0aG9yPy5kYXRlKTtcbiAgICAgICAgaWYgKG9sZGVzdCkgcmV0dXJuIHsgY29tbWl0VGltZXN0YW1wOiBvbGRlc3QsIGNvbW1pdENvdW50OiBjb21taXRzLmxlbmd0aCB9O1xuICAgICAgfVxuICAgIH1cbiAgICAvLyBmYWxsIHRocm91Z2ggdG8gc2luZ2xlLWNvbW1pdCByZXNvbHV0aW9uXG4gIH1cbiAgY29uc3QgcjIgPSBhd2FpdCBmZXRjaFdpdGhUaW1lb3V0KGBodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zLyR7b3duZXJ9LyR7cmVwb30vY29tbWl0cy8ke3NoYX1gLCB7IGhlYWRlcnMgfSk7XG4gIGlmIChyYXRlTGltaXRlZChyMikpIHsgc2NtQ29vbGRvd25VbnRpbCA9IERhdGUubm93KCkgKyBTQ01fQ09PTERPV05fTVM7IHJldHVybiB7fTsgfVxuICBpZiAocjIub2spIHtcbiAgICBjb25zdCBqID0gYXdhaXQgcjIuanNvbigpIGFzIHsgY29tbWl0PzogeyBjb21taXR0ZXI/OiB7IGRhdGU/OiBzdHJpbmcgfTsgYXV0aG9yPzogeyBkYXRlPzogc3RyaW5nIH0gfSB9O1xuICAgIGNvbnN0IGQgPSB0b0lzbyhqLmNvbW1pdD8uY29tbWl0dGVyPy5kYXRlID8/IGouY29tbWl0Py5hdXRob3I/LmRhdGUpO1xuICAgIGlmIChkKSByZXR1cm4geyBjb21taXRUaW1lc3RhbXA6IGQsIGNvbW1pdENvdW50OiAxIH07XG4gIH1cbiAgcmV0dXJuIHt9O1xufVxuXG5hc3luYyBmdW5jdGlvbiByZXNvbHZlQml0YnVja2V0KG93bmVyOiBzdHJpbmcsIHJlcG86IHN0cmluZywgc2hhOiBzdHJpbmcpOiBQcm9taXNlPENvbW1pdEluZm8+IHtcbiAgY29uc3QgciA9IGF3YWl0IGZldGNoV2l0aFRpbWVvdXQoYGh0dHBzOi8vYXBpLmJpdGJ1Y2tldC5vcmcvMi4wL3JlcG9zaXRvcmllcy8ke293bmVyfS8ke3JlcG99L2NvbW1pdC8ke3NoYX1gLCB7XG4gICAgaGVhZGVyczogeyAnVXNlci1BZ2VudCc6ICdwaXBlbGluZS1idWlsZGVyLWZvcndhcmRlcicsICdBY2NlcHQnOiAnYXBwbGljYXRpb24vanNvbicgfSxcbiAgfSk7XG4gIGlmIChyLnN0YXR1cyA9PT0gNDI5KSB7IHNjbUNvb2xkb3duVW50aWwgPSBEYXRlLm5vdygpICsgU0NNX0NPT0xET1dOX01TOyByZXR1cm4ge307IH1cbiAgaWYgKHIub2spIHtcbiAgICBjb25zdCBqID0gYXdhaXQgci5qc29uKCkgYXMgeyBkYXRlPzogc3RyaW5nIH07XG4gICAgY29uc3QgZCA9IHRvSXNvKGouZGF0ZSk7XG4gICAgaWYgKGQpIHJldHVybiB7IGNvbW1pdFRpbWVzdGFtcDogZCwgY29tbWl0Q291bnQ6IDEgfTtcbiAgfVxuICByZXR1cm4ge307XG59XG5cbi8qKlxuICogUmVzb2x2ZSBgY29tbWl0VGltZXN0YW1wYCArIGBjb21taXRDb3VudGAgZm9yIGEgc291cmNlL2RlcGxveSBldmVudCwgaW4tYWNjb3VudCxcbiAqIGJlc3QtZWZmb3J0LiBDb21wdXRlZCBvbmNlIHBlciAocGlwZWxpbmVJZCwgc2hhKTsgYWR2YW5jZXMgdGhlIHBpcGVsaW5lJ3MgcmFuZ2VcbiAqIGJvdW5kYXJ5IG9ubHkgb24gc3VjY2Vzcy4gTmV2ZXIgdGhyb3dzIOKAlCByZXR1cm5zIHt9IG9uIGFueSBmYWlsdXJlLlxuICovXG5hc3luYyBmdW5jdGlvbiByZXNvbHZlQ29tbWl0SW5mbyhwaXBlbGluZUlkOiBzdHJpbmcsIG9yZ0lkOiBzdHJpbmcgfCBudWxsLCByZWdpb246IHN0cmluZywgc3JjOiBTb3VyY2VSZWYpOiBQcm9taXNlPENvbW1pdEluZm8+IHtcbiAgaWYgKHNyYy5wcm92aWRlciA9PT0gJ3Vua25vd24nKSByZXR1cm4ge307XG4gIGNvbnN0IHJrZXkgPSBgJHtwaXBlbGluZUlkfXwke3NyYy5zaGF9YDtcbiAgY29uc3QgY2FjaGVkID0gY29tbWl0UmVzdWx0Q2FjaGUuZ2V0KHJrZXkpO1xuICBpZiAoY2FjaGVkKSByZXR1cm4gY2FjaGVkO1xuXG4gIGNvbnN0IHByZXYgPSBsYXN0U2hhQnlQaXBlbGluZS5nZXQocGlwZWxpbmVJZCk7XG4gIGNvbnN0IHNpbmNlU2hhID0gcHJldiAmJiBwcmV2ICE9PSBzcmMuc2hhID8gcHJldiA6IHVuZGVmaW5lZDtcblxuICBsZXQgaW5mbzogQ29tbWl0SW5mbyA9IHt9O1xuICB0cnkge1xuICAgIGlmIChzcmMucHJvdmlkZXIgPT09ICdjb2RlY29tbWl0JyAmJiBzcmMucmVwb3NpdG9yeU5hbWUpIHtcbiAgICAgIGluZm8gPSBhd2FpdCByZXNvbHZlQ29kZUNvbW1pdChyZWdpb24sIHNyYy5yZXBvc2l0b3J5TmFtZSwgc3JjLnNoYSwgc2luY2VTaGEpO1xuICAgIH0gZWxzZSBpZiAoc3JjLnByb3ZpZGVyID09PSAnZ2l0aHViJyAmJiBzcmMub3duZXIgJiYgc3JjLnJlcG8pIHtcbiAgICAgIGlmIChEYXRlLm5vdygpID49IHNjbUNvb2xkb3duVW50aWwpIGluZm8gPSBhd2FpdCByZXNvbHZlR2l0SHViKHNyYy5vd25lciwgc3JjLnJlcG8sIHNyYy5zaGEsIHNpbmNlU2hhLCBvcmdJZCk7XG4gICAgfSBlbHNlIGlmIChzcmMucHJvdmlkZXIgPT09ICdiaXRidWNrZXQnICYmIHNyYy5vd25lciAmJiBzcmMucmVwbykge1xuICAgICAgaWYgKERhdGUubm93KCkgPj0gc2NtQ29vbGRvd25VbnRpbCkgaW5mbyA9IGF3YWl0IHJlc29sdmVCaXRidWNrZXQoc3JjLm93bmVyLCBzcmMucmVwbywgc3JjLnNoYSk7XG4gICAgfVxuICB9IGNhdGNoIChlcnIpIHtcbiAgICBsb2cud2FybignQ29tbWl0IHJlc29sdXRpb24gZmFpbGVkIChvbWl0dGluZyBjb21taXRUaW1lc3RhbXAvY29tbWl0Q291bnQpJywgeyBwcm92aWRlcjogc3JjLnByb3ZpZGVyLCBlcnJvcjogKGVyciBhcyB7IG5hbWU/OiBzdHJpbmcgfSk/Lm5hbWUgPz8gU3RyaW5nKGVycikgfSk7XG4gICAgaW5mbyA9IHt9O1xuICB9XG5cbiAgY29tbWl0UmVzdWx0Q2FjaGUuc2V0KHJrZXksIGluZm8pO1xuICBpZiAoaW5mby5jb21taXRUaW1lc3RhbXApIGxhc3RTaGFCeVBpcGVsaW5lLnNldChwaXBlbGluZUlkLCBzcmMuc2hhKTtcbiAgcmV0dXJuIGluZm87XG59XG5cbi8vIOKUgOKUgOKUgCBFdmVudCBQYXJzaW5nIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG5pbnRlcmZhY2UgUGFyc2VkRXZlbnQge1xuICAvKipcbiAgICogUmVzb2x2ZWQgcGxhdGZvcm0gb3JnSWQgKGZyb20gdGhlIHBpcGVsaW5lJ3MgT3JnSWQgdGFnOyBudWxsIHdoZW4gdW50YWdnZWQpLlxuICAgKiBJTlRFUk5BTCDigJQgdXNlZCBvbmx5IHRvIGtleSB0aGUgcGVyLW9yZyBHaXRIdWIgdG9rZW4gYW5kIHRvIGF0dHJpYnV0ZVxuICAgKiBpbmdlc3QtaGVhbHRoLiBTdHJpcHBlZCBmcm9tIHRoZSBwYXlsb2FkIFBPU1RlZCB0byAvcmVwb3J0cy9ldmVudHMgKHdoaWNoXG4gICAqIHJlc29sdmVzIG9yZyBmcm9tIHRoZSBwaXBlbGluZSByZWdpc3RyeSwgbm90IHRoZSBib2R5KS5cbiAgICovXG4gIG9yZ0lkOiBzdHJpbmcgfCBudWxsO1xuICBwaXBlbGluZUlkOiBzdHJpbmc7XG4gIGV2ZW50U291cmNlOiBzdHJpbmc7XG4gIGV2ZW50VHlwZTogc3RyaW5nO1xuICBzdGF0dXM6IHN0cmluZztcbiAgZXhlY3V0aW9uSWQ/OiBzdHJpbmc7XG4gIHN0YWdlTmFtZT86IHN0cmluZztcbiAgYWN0aW9uTmFtZT86IHN0cmluZztcbiAgLyoqIEh1bWFuLXJlYWRhYmxlIGZhaWx1cmUgcmVhc29uLCBmcm9tIGFuIEFjdGlvbiBldmVudCdzXG4gICAqICBgZXhlY3V0aW9uLXJlc3VsdC5leHRlcm5hbC1leGVjdXRpb24tc3VtbWFyeWAuIFRoZSBsb2cgVVJMICsgZXJyb3ItY29kZVxuICAgKiAgc3RheSBpbiBgZGV0YWlsYCBmb3IgZHJpbGwtZG93bi4gKi9cbiAgZXJyb3JNZXNzYWdlPzogc3RyaW5nO1xuICBzdGFydGVkQXQ/OiBzdHJpbmc7XG4gIGNvbXBsZXRlZEF0Pzogc3RyaW5nO1xuICBkdXJhdGlvbk1zPzogbnVtYmVyO1xuICAvKiogU291cmNlIGNvbW1pdCBpZCAoRE9SQSBkZXBsb3kgYXR0cmlidXRpb24pLiBVbmRlZmluZWQgd2hlbiB0aGUgZXZlbnRcbiAgICogIGNhcnJpZXMgbm8gc291cmNlIHJldmlzaW9uIOKAlCBzdG9yZWQgTlVMTCBkb3duc3RyZWFtLiAqL1xuICBjb21taXRTaGE/OiBzdHJpbmc7XG4gIC8qKiBTb3VyY2UgYnJhbmNoL3JlZiAoRE9SQSBkZXBsb3kgYXR0cmlidXRpb24pLiBVbmRlZmluZWQgd2hlbiB1bmF2YWlsYWJsZS4gKi9cbiAgY29tbWl0UmVmPzogc3RyaW5nO1xuICAvKiogT2xkZXN0LXVuc2hpcHBlZCBjb21taXQgdGltZXN0YW1wIChJU08gODYwMSkgZm9yIHRoZSByYW5nZSBzaW5jZSB0aGUgbGFzdFxuICAgKiAgZGVwbG95IOKAlCByZXNvbHZlZCBpbi1hY2NvdW50IChQaGFzZSA0KS4gVW5kZWZpbmVkIHdoZW4gdW5yZXNvbHZhYmxlLiAqL1xuICBjb21taXRUaW1lc3RhbXA/OiBzdHJpbmc7XG4gIC8qKiBOdW1iZXIgb2YgY29tbWl0cyBpbiB0aGUgcmVzb2x2ZWQgcmFuZ2UgKOKJpTEpLiBVbmRlZmluZWQgd2hlbiB1bnJlc29sdmFibGUuICovXG4gIGNvbW1pdENvdW50PzogbnVtYmVyO1xuICAvKiogRGVwbG95IGVudmlyb25tZW50IOKAlCBzZXQgb25seSB3aGVuIHRoZSBldmVudCdzIHN0YWdlIGlzIGxpc3RlZCBpbiB0aGVcbiAgICogIHBpcGVsaW5lJ3MgYHBiLmRlcGxveXNgIHRhZy4gVW5kZWZpbmVkIG90aGVyd2lzZSAo4oeSIG5vdCBhIGRlcGxveSkuICovXG4gIGVudmlyb25tZW50Pzogc3RyaW5nO1xuICBkZXRhaWw6IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xufVxuXG4vKiogQ2FwIG9uIHRoZSBzdG9yZWQgZmFpbHVyZSBzdW1tYXJ5IOKAlCBDb2RlQnVpbGQvRGVwbG95IHN1bW1hcmllcyBjYW4gYmUgbG9uZy4gKi9cbmNvbnN0IE1BWF9FUlJPUl9NRVNTQUdFID0gNDAwMDtcblxuLyoqIEZpcnN0IG5vbi1lbXB0eSBzdHJpbmcgYW1vbmcgdGhlIGNhbmRpZGF0ZXMsIGNhcHBlZCB0byB0aGUgaW5nZXN0IG1heC4gKi9cbmZ1bmN0aW9uIGZpcnN0QXR0ciguLi52YWxzOiB1bmtub3duW10pOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBmb3IgKGNvbnN0IHYgb2YgdmFscykge1xuICAgIGlmICh0eXBlb2YgdiA9PT0gJ3N0cmluZycgJiYgdi5sZW5ndGggPiAwKSByZXR1cm4gdi5zbGljZSgwLCBNQVhfQVRUUik7XG4gIH1cbiAgcmV0dXJuIHVuZGVmaW5lZDtcbn1cblxuLyoqXG4gKiBCZXN0LWVmZm9ydCBleHRyYWN0aW9uIG9mIHRoZSBzb3VyY2UgY29tbWl0IGlkICsgcmVmIChhbmQgdGhlIHJldmlzaW9uIFVSTCwgdXNlZFxuICogb25seSBpbi1hY2NvdW50IHRvIGNsYXNzaWZ5IHRoZSBzb3VyY2UgdHlwZSBmb3IgY29tbWl0LXJhbmdlIHJlc29sdXRpb24pIGZyb20gYVxuICogQ29kZVBpcGVsaW5lIGV2ZW50IGRldGFpbC4gQ29kZVBpcGVsaW5lIHN1cmZhY2VzIHRoZSBzb3VyY2UgcmV2aXNpb24gdW5kZXIgYSBmZXdcbiAqIHNoYXBlcyBkZXBlbmRpbmcgb24gdGhlIGV2ZW50IHR5cGUgLyBzb3VyY2UtYWN0aW9uOyB3ZSBjaGVjayB0aGUga25vd24gb25lcyBhbmRcbiAqIGxlYXZlIHRoZSBmaWVsZHMgdW5kZWZpbmVkIHdoZW4gbm9uZSBhcmUgcHJlc2VudCAoTlVMTCBkb3duc3RyZWFtKS4gTmV2ZXIgcHVsbHMgYW5cbiAqIEFSTi9hY2NvdW50IGlkOiBvbmx5IHJldmlzaW9uL2JyYW5jaC91cmwgc3RyaW5nIGZpZWxkcyBhcmUgcmVhZDsgdGhlIHJldmlzaW9uVXJsXG4gKiBpcyBjb25zdW1lZCBpbi1hY2NvdW50IChzb3VyY2UgY2xhc3NpZmljYXRpb24pIGFuZCBuZXZlciBmb3J3YXJkZWQgb24gaXRzIG93bi5cbiAqL1xuZnVuY3Rpb24gZXh0cmFjdENvbW1pdChkZXRhaWw6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogeyBjb21taXRTaGE/OiBzdHJpbmc7IGNvbW1pdFJlZj86IHN0cmluZzsgcmV2aXNpb25Vcmw/OiBzdHJpbmcgfSB7XG4gIC8vIGBzb3VyY2UtcmV2aXNpb25zYCAoa2ViYWIsIEV2ZW50QnJpZGdlKSAvIGBzb3VyY2VSZXZpc2lvbnNgIChjYW1lbCkg4oCUIGZpcnN0IGVudHJ5LlxuICBjb25zdCByZXZzID0gKGRldGFpbFsnc291cmNlLXJldmlzaW9ucyddID8/IGRldGFpbC5zb3VyY2VSZXZpc2lvbnMpIGFzXG4gICAgfCBBcnJheTxSZWNvcmQ8c3RyaW5nLCB1bmtub3duPj4gfCB1bmRlZmluZWQ7XG4gIGNvbnN0IGZpcnN0UmV2ID0gQXJyYXkuaXNBcnJheShyZXZzKSA/IHJldnNbMF0gOiB1bmRlZmluZWQ7XG4gIC8vIE9uIHNvdXJjZSBhY3Rpb25zIHRoZSByZXZpc2lvbiBpZCBjYW4gYWxzbyByaWRlIG9uIGBleGVjdXRpb24tcmVzdWx0YC5cbiAgY29uc3QgZXhlY1Jlc3VsdCA9IGRldGFpbFsnZXhlY3V0aW9uLXJlc3VsdCddIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+IHwgdW5kZWZpbmVkO1xuXG4gIGNvbnN0IGNvbW1pdFNoYSA9IGZpcnN0QXR0cihcbiAgICBkZXRhaWwuY29tbWl0SWQsXG4gICAgZGV0YWlsLnJldmlzaW9uSWQsXG4gICAgZmlyc3RSZXY/LnJldmlzaW9uSWQsXG4gICAgZXhlY1Jlc3VsdD8ucmV2aXNpb25JZCxcbiAgKTtcbiAgY29uc3QgY29tbWl0UmVmID0gZmlyc3RBdHRyKFxuICAgIGRldGFpbC5jb21taXRSZWYsXG4gICAgZGV0YWlsLmJyYW5jaCxcbiAgICBkZXRhaWwuc291cmNlQnJhbmNoLFxuICAgIGZpcnN0UmV2Py5icmFuY2hOYW1lLFxuICAgIGZpcnN0UmV2Py5icmFuY2gsXG4gICk7XG4gIGNvbnN0IHJldmlzaW9uVXJsID0gdHlwZW9mIGZpcnN0UmV2Py5yZXZpc2lvblVybCA9PT0gJ3N0cmluZycgPyBmaXJzdFJldi5yZXZpc2lvblVybCA6IHVuZGVmaW5lZDtcblxuICByZXR1cm4geyAuLi4oY29tbWl0U2hhICYmIHsgY29tbWl0U2hhIH0pLCAuLi4oY29tbWl0UmVmICYmIHsgY29tbWl0UmVmIH0pLCAuLi4ocmV2aXNpb25VcmwgJiYgeyByZXZpc2lvblVybCB9KSB9O1xufVxuXG5mdW5jdGlvbiBjbGFzc2lmeUV2ZW50KGRldGFpbFR5cGU6IHN0cmluZyk6IHsgZXZlbnRUeXBlOiBzdHJpbmc7IGV2ZW50U291cmNlOiBzdHJpbmcgfSB7XG4gIGlmIChkZXRhaWxUeXBlLmluY2x1ZGVzKCdQaXBlbGluZSBFeGVjdXRpb24nKSkgcmV0dXJuIHsgZXZlbnRUeXBlOiAnUElQRUxJTkUnLCBldmVudFNvdXJjZTogJ2NvZGVwaXBlbGluZScgfTtcbiAgaWYgKGRldGFpbFR5cGUuaW5jbHVkZXMoJ1N0YWdlIEV4ZWN1dGlvbicpKSByZXR1cm4geyBldmVudFR5cGU6ICdTVEFHRScsIGV2ZW50U291cmNlOiAnY29kZXBpcGVsaW5lJyB9O1xuICBpZiAoZGV0YWlsVHlwZS5pbmNsdWRlcygnQWN0aW9uIEV4ZWN1dGlvbicpKSByZXR1cm4geyBldmVudFR5cGU6ICdBQ1RJT04nLCBldmVudFNvdXJjZTogJ2NvZGVwaXBlbGluZScgfTtcbiAgLy8gQ29kZUJ1aWxkIFwiQnVpbGQgU3RhdGVcIiBldmVudHMgaWRlbnRpZnkgYSBidWlsZCAqcHJvamVjdCosIG5vdCBhIHBpcGVsaW5lLCBzb1xuICAvLyBwYXJzZVJlY29yZCBkcm9wcyB0aGVtIG9uIHRoZSBgZXZlbnRTb3VyY2UgIT09ICdjb2RlcGlwZWxpbmUnYCBjaGVjayBiZWxvdyDigJRcbiAgLy8gdGhlICdCVUlMRCcgZXZlbnRUeXBlIGlzIG5ldmVyIHBlcnNpc3RlZCBoZXJlIChwbHVnaW4gQlVJTEQgZXZlbnRzIGFyZVxuICAvLyByZWNvcmRlZCBkaXJlY3RseSBieSB0aGUgcGx1Z2luIHNlcnZpY2UpLiBUaGUgJ2NvZGVidWlsZCcgc291cmNlIGlzIHdoYXRcbiAgLy8gcm91dGVzIHRoZSBkcm9wOyBrZWVwIHRoaXMgYnJhbmNoIG9ubHkgZm9yIHRoYXQuXG4gIGlmIChkZXRhaWxUeXBlLmluY2x1ZGVzKCdCdWlsZCBTdGF0ZScpKSByZXR1cm4geyBldmVudFR5cGU6ICdCVUlMRCcsIGV2ZW50U291cmNlOiAnY29kZWJ1aWxkJyB9O1xuICByZXR1cm4geyBldmVudFR5cGU6ICdQSVBFTElORScsIGV2ZW50U291cmNlOiAnY29kZXBpcGVsaW5lJyB9O1xufVxuXG4vKiogUGFyc2UgKyByZXNvbHZlIG9uZSByZWNvcmQgdG8gYSByZXBvcnRhYmxlIGV2ZW50LCBvciBudWxsIHRvIHNraXAgaXQuICovXG5hc3luYyBmdW5jdGlvbiBwYXJzZVJlY29yZChyZWNvcmQ6IFNRU1JlY29yZCk6IFByb21pc2U8UGFyc2VkRXZlbnQgfCBudWxsPiB7XG4gIGxldCBldmVudDoge1xuICAgICdkZXRhaWwtdHlwZSc6IHN0cmluZztcbiAgICAnc291cmNlJzogc3RyaW5nO1xuICAgICdkZXRhaWwnOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgICAndGltZSc6IHN0cmluZztcbiAgICAncmVnaW9uJzogc3RyaW5nO1xuICAgICdhY2NvdW50Jzogc3RyaW5nO1xuICB9O1xuICAvLyBBIG1hbGZvcm1lZCBib2R5IGlzIGEgZGVhZCBtZXNzYWdlIChyZXRyeWluZyB3b24ndCBoZWxwKSDigJQgbG9nICsgc2tpcCBpdCBzb1xuICAvLyBpdCBjYW4ndCBmYWlsIHRoZSB3aG9sZSBiYXRjaC4gUmVzb2x1dGlvbiBlcnJvcnMgYmVsb3cgKGUuZy4gQWNjZXNzRGVuaWVkKVxuICAvLyBhcmUgTk9UIGNhdWdodCBoZXJlOiB0aG9zZSBhcmUgdHJhbnNpZW50L2luZnJhIGFuZCBtdXN0IHByb3BhZ2F0ZSB0byByZXRyeS5cbiAgdHJ5IHtcbiAgICBldmVudCA9IEpTT04ucGFyc2UocmVjb3JkLmJvZHkpO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICBsb2cud2FybignU2tpcHBpbmcgU1FTIHJlY29yZCB3aXRoIHVucGFyc2VhYmxlIGJvZHknLCB7IG1lc3NhZ2VJZDogcmVjb3JkLm1lc3NhZ2VJZCwgZXJyb3I6IFN0cmluZyhlcnIpIH0pO1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgY29uc3QgeyBldmVudFR5cGUsIGV2ZW50U291cmNlIH0gPSBjbGFzc2lmeUV2ZW50KGV2ZW50WydkZXRhaWwtdHlwZSddKTtcbiAgY29uc3QgZGV0YWlsID0geyAuLi5ldmVudC5kZXRhaWwgfTtcbiAgLy8gVGhlIHJhdyBhY2NvdW50IG5ldmVyIG5lZWRzIHRvIGxlYXZlIEFXUyBub3cg4oCUIGRyb3AgaXQgZnJvbSB0aGUgcGF5bG9hZC5cbiAgZGVsZXRlIGRldGFpbC5hY2NvdW50O1xuXG4gIC8vIENvZGVCdWlsZCBcIkJ1aWxkIFN0YXRlXCIgZXZlbnRzIGlkZW50aWZ5IGEgYnVpbGQgKnByb2plY3QqLCBub3QgYSBwaXBlbGluZSxcbiAgLy8gYW5kIGEgcHJvamVjdCBjYW4gYmUgc2hhcmVkIGFjcm9zcyBwaXBlbGluZXMg4oCUIHRoZXJlJ3Mgbm8gY2xlYW4gMToxIG1hcHBpbmdcbiAgLy8gdG8gYSBwaXBlbGluZSBpZCwgc28gc2tpcCB0aGVtLlxuICBpZiAoZXZlbnRTb3VyY2UgIT09ICdjb2RlcGlwZWxpbmUnKSB7XG4gICAgbG9nLndhcm4oJ1NraXBwaW5nIG5vbi1Db2RlUGlwZWxpbmUgZXZlbnQgKG5vIHBpcGVsaW5lIHRhZyB0byByZXNvbHZlKScsIHsgZGV0YWlsVHlwZTogZXZlbnRbJ2RldGFpbC10eXBlJ10gfSk7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBjb25zdCBwaXBlbGluZU5hbWUgPSBkZXRhaWwucGlwZWxpbmUgYXMgc3RyaW5nIHwgdW5kZWZpbmVkO1xuICBpZiAoIXBpcGVsaW5lTmFtZSkge1xuICAgIGxvZy53YXJuKCdDb2RlUGlwZWxpbmUgZXZlbnQgbWlzc2luZyBwaXBlbGluZSBuYW1lIOKAlCBza2lwcGluZycpO1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLy8gUmVzb2x2ZSB0aGUgcGlwZWxpbmUncyBwYi5waXBlbGluZS1pZCAoPSBwbGF0Zm9ybSBwaXBlbGluZUlkKSArIHBiLmRlcGxveXMgbWFwLlxuICAvLyBUaGUgQVJOIGlzIG9ubHkgYSB0cmFuc2llbnQgaGFuZGxlIGZvciB0aGUgdGFnIGxvb2t1cDsgaXQgaXMgbmV2ZXIgc3RvcmVkLlxuICBjb25zdCBhcm4gPSBgYXJuOmF3czpjb2RlcGlwZWxpbmU6JHtldmVudC5yZWdpb259OiR7ZXZlbnQuYWNjb3VudH06JHtwaXBlbGluZU5hbWV9YDtcbiAgY29uc3QgeyBwaXBlbGluZUlkLCBvcmdJZCwgZGVwbG95cyB9ID0gYXdhaXQgcmVzb2x2ZVBpcGVsaW5lKGFybiwgZXZlbnQucmVnaW9uKTtcbiAgaWYgKCFwaXBlbGluZUlkKSByZXR1cm4gbnVsbDsgLy8gdW50YWdnZWQgLyB1bnJlZ2lzdGVyZWQg4oaSIHNraXBcblxuICBjb25zdCBzdGFydGVkQXQgPSAoZGV0YWlsWydzdGFydC10aW1lJ10gYXMgc3RyaW5nKSB8fCBldmVudC50aW1lO1xuICBjb25zdCBzdGF0ZSA9IGRldGFpbC5zdGF0ZSBhcyBzdHJpbmc7XG5cbiAgbGV0IGR1cmF0aW9uTXM6IG51bWJlciB8IHVuZGVmaW5lZDtcbiAgbGV0IGNvbXBsZXRlZEF0OiBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cbiAgaWYgKFsnU1VDQ0VFREVEJywgJ0ZBSUxFRCcsICdDQU5DRUxFRCcsICdTVE9QUEVEJ10uaW5jbHVkZXMoc3RhdGUpKSB7XG4gICAgY29tcGxldGVkQXQgPSBldmVudC50aW1lO1xuICAgIGlmIChzdGFydGVkQXQgJiYgY29tcGxldGVkQXQpIHtcbiAgICAgIGNvbnN0IG1zID0gbmV3IERhdGUoY29tcGxldGVkQXQpLmdldFRpbWUoKSAtIG5ldyBEYXRlKHN0YXJ0ZWRBdCkuZ2V0VGltZSgpO1xuICAgICAgaWYgKG1zID49IDApIGR1cmF0aW9uTXMgPSBtcztcbiAgICB9XG4gIH1cblxuICAvLyBQcm9tb3RlIHRoZSBmYWlsdXJlIHJlYXNvbiB0byBhIHR5cGVkIGZpZWxkLiBPbiBBY3Rpb24gZXZlbnRzIEFXUyBwdXRzIHRoZVxuICAvLyBodW1hbi1yZWFkYWJsZSBzdW1tYXJ5IChhbmQgYSBsb2cgVVJMICsgZXJyb3ItY29kZSwgd2hpY2ggc3RheSBpbiBgZGV0YWlsYClcbiAgLy8gdW5kZXIgYGV4ZWN1dGlvbi1yZXN1bHRgLlxuICBjb25zdCByZXN1bHQgPSBkZXRhaWxbJ2V4ZWN1dGlvbi1yZXN1bHQnXSBhcyB7ICdleHRlcm5hbC1leGVjdXRpb24tc3VtbWFyeSc/OiB1bmtub3duIH0gfCB1bmRlZmluZWQ7XG4gIGNvbnN0IHN1bW1hcnkgPSByZXN1bHQ/LlsnZXh0ZXJuYWwtZXhlY3V0aW9uLXN1bW1hcnknXTtcbiAgY29uc3QgZXJyb3JNZXNzYWdlID0gdHlwZW9mIHN1bW1hcnkgPT09ICdzdHJpbmcnICYmIHN1bW1hcnkubGVuZ3RoID4gMFxuICAgID8gc3VtbWFyeS5zbGljZSgwLCBNQVhfRVJST1JfTUVTU0FHRSlcbiAgICA6IHVuZGVmaW5lZDtcblxuICAvLyBET1JBIGRlcGxveSBhdHRyaWJ1dGlvbiDigJQgYWxsIG9wdGlvbmFsOiBvbWl0dGVkICh1bmRlZmluZWQpIHdoZW4gdGhlXG4gIC8vIGV2ZW50L3BpcGVsaW5lIGRvZXNuJ3QgY2FycnkgdGhlbS5cbiAgY29uc3QgeyBjb21taXRTaGEsIGNvbW1pdFJlZiwgcmV2aXNpb25VcmwgfSA9IGV4dHJhY3RDb21taXQoZGV0YWlsKTtcblxuICBjb25zdCBleGVjdXRpb25JZCA9IGRldGFpbFsnZXhlY3V0aW9uLWlkJ10gYXMgc3RyaW5nIHwgdW5kZWZpbmVkO1xuICBjb25zdCBzdGFnZU5hbWUgPSBkZXRhaWwuc3RhZ2UgYXMgc3RyaW5nIHwgdW5kZWZpbmVkO1xuICBjb25zdCBhY3Rpb25OYW1lID0gZGV0YWlsLmFjdGlvbiBhcyBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cbiAgLy8gRW52aXJvbm1lbnQgKOKHkiBpc0RlcGxveSkgaXMgc2V0IE9OTFkgd2hlbiB0aGlzIGV2ZW50J3Mgc3RhZ2UgaXMgbGlzdGVkIGluIHRoZVxuICAvLyBwaXBlbGluZSdzIHBiLmRlcGxveXMgdGFnLiBQSVBFTElORSBldmVudHMgaGF2ZSBubyBzdGFnZSDihpIgbmV2ZXIgYSBkZXBsb3kuXG4gIGNvbnN0IGVudmlyb25tZW50ID0gc3RhZ2VOYW1lID8gZGVwbG95cy5nZXQoc3RhZ2VOYW1lKSA6IHVuZGVmaW5lZDtcblxuICAvLyBQaGFzZSA0IOKAlCByZXNvbHZlIHRoZSBjb21taXQgcmFuZ2UgKG9sZGVzdC11bnNoaXBwZWQgdGltZXN0YW1wICsgY291bnQpIGZvciBhbnlcbiAgLy8gZXZlbnQgY2FycnlpbmcgYSBjb21taXQuIEJlc3QtZWZmb3J0L2luLWFjY291bnQ7IG9taXR0ZWQgb24gYW55IGZhaWx1cmUuXG4gIC8vIEdBVEVEIG9uIGBET1JBX0VOQUJMRURgIChzZXQgYnkgYHNldHVwLWV2ZW50cyAtLXdpdGgtZG9yYWApOiBET1JBIGxlYWQgdGltZSBpcyBhblxuICAvLyBhZHZhbmNlZF9yZXBvcnRpbmcgYWRkLW9uLCBzbyBvcmdzIHdpdGhvdXQgaXQgc2tpcCB0aGUgU0NNL3NlY3JldCBjb3N0IGVudGlyZWx5IOKAlFxuICAvLyBzdGFuZGFyZCByZXBvcnRpbmcgKGNvbW1pdFNoYSArIGFsbCBvdGhlciBmaWVsZHMpIHN0aWxsIGZvcndhcmRzIHJlZ2FyZGxlc3MuXG4gIGxldCBjb21taXRUaW1lc3RhbXA6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgbGV0IGNvbW1pdENvdW50OiBudW1iZXIgfCB1bmRlZmluZWQ7XG4gIGlmIChjb21taXRTaGEgJiYgcHJvY2Vzcy5lbnYuRE9SQV9FTkFCTEVEID09PSAndHJ1ZScpIHtcbiAgICBjb25zdCBzcmMgPSBjbGFzc2lmeVNvdXJjZShyZXZpc2lvblVybCk7XG4gICAgY29uc3QgaW5mbyA9IGF3YWl0IHJlc29sdmVDb21taXRJbmZvKHBpcGVsaW5lSWQsIG9yZ0lkLCBldmVudC5yZWdpb24sIHsgc2hhOiBjb21taXRTaGEsIC4uLnNyYyB9KTtcbiAgICBjb21taXRUaW1lc3RhbXAgPSBpbmZvLmNvbW1pdFRpbWVzdGFtcDtcbiAgICBjb21taXRDb3VudCA9IGluZm8uY29tbWl0Q291bnQ7XG4gIH1cblxuICByZXR1cm4ge1xuICAgIG9yZ0lkLFxuICAgIHBpcGVsaW5lSWQsXG4gICAgZXZlbnRTb3VyY2UsXG4gICAgZXZlbnRUeXBlLFxuICAgIHN0YXR1czogc3RhdGUsXG4gICAgZXhlY3V0aW9uSWQsXG4gICAgc3RhZ2VOYW1lLFxuICAgIGFjdGlvbk5hbWUsXG4gICAgZXJyb3JNZXNzYWdlLFxuICAgIHN0YXJ0ZWRBdCxcbiAgICBjb21wbGV0ZWRBdCxcbiAgICBkdXJhdGlvbk1zLFxuICAgIC4uLihjb21taXRTaGEgJiYgeyBjb21taXRTaGEgfSksXG4gICAgLi4uKGNvbW1pdFJlZiAmJiB7IGNvbW1pdFJlZiB9KSxcbiAgICAuLi4oY29tbWl0VGltZXN0YW1wICYmIHsgY29tbWl0VGltZXN0YW1wIH0pLFxuICAgIC4uLihjb21taXRDb3VudCAmJiB7IGNvbW1pdENvdW50IH0pLFxuICAgIC4uLihlbnZpcm9ubWVudCAmJiB7IGVudmlyb25tZW50IH0pLFxuICAgIGRldGFpbCxcbiAgfTtcbn1cblxuLy8g4pSA4pSA4pSAIFBoYXNlIDM6IGRlbGl2ZXJ5IGhlYWx0aCArIHNlbGYtaGVhbGluZyBETFEgcmVkcml2ZSDilIBcbi8vIEFmdGVyIGEgU1VDQ0VTU0ZVTCBiYXRjaCBQT1NUIHdlICh0aHJvdHRsZWQsIGJlc3QtZWZmb3J0KTpcbi8vICAgMS4gUE9TVCBhbiBpbmdlc3QtaGVhbHRoIHNpZ25hbCB0byAvYXBpL3JlcG9ydHMvaW5nZXN0LWhlYWx0aCBzbyB0aGUgUmVwb3J0cyBVSVxuLy8gICAgICBjYW4gc2hvdyBmbG93aW5nIC8gc3RhbGUgLyBkcm9wcGluZy5cbi8vICAgMi4gSWYgdGhlIERMUSBpcyBub24tZW1wdHksIG5vIG1vdmUgdGFzayBpcyBhbHJlYWR5IHJ1bm5pbmcsIEFORCB0aGUgb2xkZXN0IERMUVxuLy8gICAgICBtZXNzYWdlIGlzIHlvdW5nZXIgdGhhbiB0aGUgcG9pc29uLWFnZSBjZWlsaW5nLCBraWNrIG9mZiBhbiBTUVNcbi8vICAgICAgTWVzc2FnZU1vdmVUYXNrIChETFEg4oaSIG1haW4gcXVldWUpIHNvIHJldHJ5YWJsZSBmYWlsdXJlcyBzZWxmLWhlYWwgd2l0aG91dCBhXG4vLyAgICAgIG5ldyBBV1Mgc2VydmljZS4gVGhlIHJlcG9ydGluZyBpbmdlc3QncyBwYXJ0aWFsLXVuaXF1ZSBpbmRleCBkZWR1cGVzIGFueVxuLy8gICAgICByZWRlbGl2ZXJlZCBldmVudCwgc28gYSByZWRyaXZlIGNhbid0IGRvdWJsZS1jb3VudC5cbi8vIEd1YXJkczogb25seSBvbiBzdWNjZXNzLCBvbmUtYXQtYS10aW1lIChMaXN0TWVzc2FnZU1vdmVUYXNrcyksIGEgcG9pc29uLWFnZSBjZWlsaW5nXG4vLyAoc28gYSBtZXNzYWdlIHRoYXQgYWx3YXlzIGZhaWxzIGNhbid0IGxvb3AgRExR4oaSbWFpbuKGkkRMUSBmb3JldmVyKSwgYW5kIHRocm90dGxlZCB2aWFcbi8vIG1vZHVsZSB0aW1lc3RhbXBzLiBORVZFUiB0aHJvd3Mg4oCUIGEgZmFpbHVyZSBoZXJlIG11c3Qgbm90IGZhaWwgdGhlIGJhdGNoLlxuLy9cbi8vIElBTSByZXF1aXJlZCAoZG9jdW1lbnQgb25seSDigJQgZ3JhbnRlZCBvbiB0aGUgZXZlbnRzIHN0YWNrKTpcbi8vICAgc3FzOkdldFF1ZXVlQXR0cmlidXRlcywgc3FzOkxpc3RNZXNzYWdlTW92ZVRhc2tzLCBzcXM6U3RhcnRNZXNzYWdlTW92ZVRhc2sgKG9uIHRoZSBETFEpXG5cbmludGVyZmFjZSBTcXNDbGllbnRMaWtlIHsgc2VuZChjb21tYW5kOiB1bmtub3duKTogUHJvbWlzZTx1bmtub3duPiB9XG5pbnRlcmZhY2UgU3FzTW9kdWxlIHtcbiAgU1FTQ2xpZW50OiBuZXcgKGNvbmZpZzogeyByZWdpb246IHN0cmluZyB9KSA9PiBTcXNDbGllbnRMaWtlO1xuICBHZXRRdWV1ZUF0dHJpYnV0ZXNDb21tYW5kOiBuZXcgKGlucHV0OiB7IFF1ZXVlVXJsOiBzdHJpbmc7IEF0dHJpYnV0ZU5hbWVzOiBzdHJpbmdbXSB9KSA9PiB1bmtub3duO1xuICBMaXN0TWVzc2FnZU1vdmVUYXNrc0NvbW1hbmQ6IG5ldyAoaW5wdXQ6IHsgU291cmNlQXJuOiBzdHJpbmcgfSkgPT4gdW5rbm93bjtcbiAgU3RhcnRNZXNzYWdlTW92ZVRhc2tDb21tYW5kOiBuZXcgKGlucHV0OiB7IFNvdXJjZUFybjogc3RyaW5nOyBEZXN0aW5hdGlvbkFybj86IHN0cmluZyB9KSA9PiB1bmtub3duO1xufVxubGV0IHNxc01vZDogU3FzTW9kdWxlIHwgdW5kZWZpbmVkO1xubGV0IHNxc0NsaWVudHNCeVJlZ2lvbjogTWFwPHN0cmluZywgU3FzQ2xpZW50TGlrZT4gfCB1bmRlZmluZWQ7XG5hc3luYyBmdW5jdGlvbiBzcXNDbGllbnQocmVnaW9uOiBzdHJpbmcpOiBQcm9taXNlPFNxc0NsaWVudExpa2U+IHtcbiAgaWYgKCFzcXNNb2QpIHNxc01vZCA9IGF3YWl0IGxvYWRTZGs8U3FzTW9kdWxlPignQGF3cy1zZGsvY2xpZW50LXNxcycpO1xuICBpZiAoIXNxc0NsaWVudHNCeVJlZ2lvbikgc3FzQ2xpZW50c0J5UmVnaW9uID0gbmV3IE1hcCgpO1xuICBsZXQgY2xpZW50ID0gc3FzQ2xpZW50c0J5UmVnaW9uLmdldChyZWdpb24pO1xuICBpZiAoIWNsaWVudCkge1xuICAgIGNsaWVudCA9IG5ldyBzcXNNb2QuU1FTQ2xpZW50KHsgcmVnaW9uIH0pO1xuICAgIHNxc0NsaWVudHNCeVJlZ2lvbi5zZXQocmVnaW9uLCBjbGllbnQpO1xuICB9XG4gIHJldHVybiBjbGllbnQ7XG59XG5cbi8vIERlbGl2ZXJ5LWhlYWx0aCBjb3VudGVycyBhcmUgYXR0cmlidXRlZCBQRVIgUkVTT0xWRUQgT1JHICh0aGUgZm9yd2FyZGVyIGlzIGEgZmxlZXRcbi8vIExhbWJkYSBzZXJ2aW5nIG1hbnkgb3JnczsgYSBzaW5nbGUgZ2xvYmFsIGNvdW50ZXIgd291bGQgbWlzLWF0dHJpYnV0ZSBvbmUgb3JnJ3Ncbi8vIHRocm91Z2hwdXQgdG8gYW5vdGhlcikuIEtleWVkIGJ5IG9yZ0lkICgnJyBidWNrZXQgPSBwaXBlbGluZSB3aXRoIG5vIE9yZ0lkIHRhZykuXG4vLyBUaGUgRExRIGRlcHRoIChgZHJvcHBlZGApIGlzIGdlbnVpbmVseSBmbGVldC1nbG9iYWwg4oCUIG9uZSBzaGFyZWQgRExRIOKAlCBzbyBpdCBpcyBhXG4vLyBzaW5nbGUgc25hcHNob3QgcG9zdGVkIGFsb25nc2lkZSBlYWNoIG9yZydzIGhlYWx0aCwgZG9jdW1lbnRlZCBhcyB0aGUgc2hhcmVkIGRlcHRoLlxuY29uc3QgZm9yd2FyZGVkQnlPcmcgPSBuZXcgTWFwPHN0cmluZywgbnVtYmVyPigpO1xuY29uc3QgbGFzdEV2ZW50QXRCeU9yZyA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmc+KCk7XG5sZXQgbGFzdEhlYWx0aEF0ID0gMDtcbmxldCBsYXN0UmVkcml2ZUF0ID0gMDtcbmNvbnN0IEhFQUxUSF9USFJPVFRMRV9NUyA9IDYwICogMTAwMDtcbmNvbnN0IFJFRFJJVkVfVEhST1RUTEVfTVMgPSA1ICogNjAgKiAxMDAwO1xuLy8gUG9pc29uLW1lc3NhZ2UgY2VpbGluZzogaWYgdGhlIG9sZGVzdCBETFEgbWVzc2FnZSBpcyBvbGRlciB0aGFuIHRoaXMsIHdlIFNUT1Bcbi8vIHJlZHJpdmluZyBpdCAoRExR4oaSbWFpbuKGkmZhaWzihpJETFEgd291bGQgbG9vcCBmb3JldmVyKS4gU3VjaCBtZXNzYWdlcyBhcmUgbGVmdCBmb3IgYW5cbi8vIGFsYXJtIC8gbWFudWFsIGluc3BlY3Rpb24gaW5zdGVhZCBvZiBjaHVybmluZyB0aGUgZmxlZXQgaW5kZWZpbml0ZWx5LlxuY29uc3QgTUFYX0RMUV9SRURSSVZFX0FHRV9TRUMgPSA2ICogNjAgKiA2MDsgLy8gNiBob3Vyc1xuXG4vKiogUGFyc2UgdGhlIFNRUyB0cmlnZ2VyIEFSTiBhbmQgZGVyaXZlIHRoZSBtYWluICsgRExRIEFSTnMgYW5kIHRoZSBETFEgVVJMLiAqL1xuZnVuY3Rpb24gZGVyaXZlUXVldWVzKG1haW5RdWV1ZUFybjogc3RyaW5nIHwgdW5kZWZpbmVkKTogeyByZWdpb246IHN0cmluZzsgbWFpbkFybjogc3RyaW5nOyBkbHFBcm46IHN0cmluZzsgZGxxVXJsOiBzdHJpbmcgfSB8IHVuZGVmaW5lZCB7XG4gIGlmICghbWFpblF1ZXVlQXJuKSByZXR1cm4gdW5kZWZpbmVkO1xuICAvLyBhcm46YXdzOnNxczp7cmVnaW9ufTp7YWNjb3VudH06e25hbWV9XG4gIGNvbnN0IHBhcnRzID0gbWFpblF1ZXVlQXJuLnNwbGl0KCc6Jyk7XG4gIGlmIChwYXJ0cy5sZW5ndGggPCA2IHx8IHBhcnRzWzJdICE9PSAnc3FzJykgcmV0dXJuIHVuZGVmaW5lZDtcbiAgY29uc3QgWywgLCAsIHJlZ2lvbiwgYWNjb3VudCwgbmFtZV0gPSBwYXJ0cztcbiAgY29uc3QgZGxxQXJuID0gcHJvY2Vzcy5lbnYuRVZFTlRfRExRX0FSTiB8fCBgYXJuOmF3czpzcXM6JHtyZWdpb259OiR7YWNjb3VudH06JHtuYW1lfS1kbHFgO1xuICBjb25zdCBkbHFOYW1lID0gZGxxQXJuLnNwbGl0KCc6JykucG9wKCkgPz8gYCR7bmFtZX0tZGxxYDtcbiAgY29uc3QgZGxxVXJsID0gYGh0dHBzOi8vc3FzLiR7cmVnaW9ufS5hbWF6b25hd3MuY29tLyR7YWNjb3VudH0vJHtkbHFOYW1lfWA7XG4gIHJldHVybiB7IHJlZ2lvbiwgbWFpbkFybjogbWFpblF1ZXVlQXJuLCBkbHFBcm4sIGRscVVybCB9O1xufVxuXG4vKiogU25hcHNob3QgdGhlIERMUSBkZXB0aCArIHRoZSBhZ2UgKHNlY29uZHMpIG9mIGl0cyBvbGRlc3QgbWVzc2FnZSAoZm9yIHRoZVxuICogIHBvaXNvbi1tZXNzYWdlIHJlZHJpdmUgY2VpbGluZykuIE1pc3NpbmcvTmFOIGF0dHJpYnV0ZXMgZmFsbCBiYWNrIHRvIDAuICovXG5hc3luYyBmdW5jdGlvbiBkbHFTdGF0cyhyZWdpb246IHN0cmluZywgZGxxVXJsOiBzdHJpbmcpOiBQcm9taXNlPHsgZGVwdGg6IG51bWJlcjsgb2xkZXN0QWdlU2VjOiBudW1iZXIgfT4ge1xuICBpZiAoIXNxc01vZCkgc3FzTW9kID0gYXdhaXQgbG9hZFNkazxTcXNNb2R1bGU+KCdAYXdzLXNkay9jbGllbnQtc3FzJyk7XG4gIGNvbnN0IGNsaWVudCA9IGF3YWl0IHNxc0NsaWVudChyZWdpb24pO1xuICBjb25zdCBvdXQgPSBhd2FpdCBjbGllbnQuc2VuZChuZXcgc3FzTW9kLkdldFF1ZXVlQXR0cmlidXRlc0NvbW1hbmQoe1xuICAgIFF1ZXVlVXJsOiBkbHFVcmwsXG4gICAgQXR0cmlidXRlTmFtZXM6IFsnQXBwcm94aW1hdGVOdW1iZXJPZk1lc3NhZ2VzJywgJ0FwcHJveGltYXRlQWdlT2ZPbGRlc3RNZXNzYWdlJ10sXG4gIH0pKSBhcyB7IEF0dHJpYnV0ZXM/OiB7IEFwcHJveGltYXRlTnVtYmVyT2ZNZXNzYWdlcz86IHN0cmluZzsgQXBwcm94aW1hdGVBZ2VPZk9sZGVzdE1lc3NhZ2U/OiBzdHJpbmcgfSB9O1xuICBjb25zdCBuID0gTnVtYmVyKG91dC5BdHRyaWJ1dGVzPy5BcHByb3hpbWF0ZU51bWJlck9mTWVzc2FnZXMgPz8gJzAnKTtcbiAgY29uc3QgYWdlID0gTnVtYmVyKG91dC5BdHRyaWJ1dGVzPy5BcHByb3hpbWF0ZUFnZU9mT2xkZXN0TWVzc2FnZSA/PyAnMCcpO1xuICByZXR1cm4ge1xuICAgIGRlcHRoOiBOdW1iZXIuaXNGaW5pdGUobikgPyBuIDogMCxcbiAgICBvbGRlc3RBZ2VTZWM6IE51bWJlci5pc0Zpbml0ZShhZ2UpID8gYWdlIDogMCxcbiAgfTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gaGFzQWN0aXZlTW92ZVRhc2socmVnaW9uOiBzdHJpbmcsIGRscUFybjogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gIGlmICghc3FzTW9kKSBzcXNNb2QgPSBhd2FpdCBsb2FkU2RrPFNxc01vZHVsZT4oJ0Bhd3Mtc2RrL2NsaWVudC1zcXMnKTtcbiAgY29uc3QgY2xpZW50ID0gYXdhaXQgc3FzQ2xpZW50KHJlZ2lvbik7XG4gIGNvbnN0IG91dCA9IGF3YWl0IGNsaWVudC5zZW5kKG5ldyBzcXNNb2QuTGlzdE1lc3NhZ2VNb3ZlVGFza3NDb21tYW5kKHsgU291cmNlQXJuOiBkbHFBcm4gfSkpIGFzIHtcbiAgICBSZXN1bHRzPzogQXJyYXk8eyBTdGF0dXM/OiBzdHJpbmcgfT47XG4gIH07XG4gIHJldHVybiAob3V0LlJlc3VsdHMgPz8gW10pLnNvbWUodCA9PiB0LlN0YXR1cyA9PT0gJ1JVTk5JTkcnKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gc3RhcnRNb3ZlVGFzayhyZWdpb246IHN0cmluZywgZGxxQXJuOiBzdHJpbmcsIG1haW5Bcm46IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICBpZiAoIXNxc01vZCkgc3FzTW9kID0gYXdhaXQgbG9hZFNkazxTcXNNb2R1bGU+KCdAYXdzLXNkay9jbGllbnQtc3FzJyk7XG4gIGNvbnN0IGNsaWVudCA9IGF3YWl0IHNxc0NsaWVudChyZWdpb24pO1xuICBhd2FpdCBjbGllbnQuc2VuZChuZXcgc3FzTW9kLlN0YXJ0TWVzc2FnZU1vdmVUYXNrQ29tbWFuZCh7IFNvdXJjZUFybjogZGxxQXJuLCBEZXN0aW5hdGlvbkFybjogbWFpbkFybiB9KSk7XG59XG5cbi8qKiBQT1NUIG9uZSBvcmcncyBpbmdlc3QtaGVhbHRoIHNpZ25hbC4gUmV0dXJucyB0cnVlIG9ubHkgb24gYSBjb25maXJtZWQgMnh4IHNvIHRoZVxuICogIGNhbGxlciByZXNldHMgdGhhdCBvcmcncyBgZm9yd2FyZGVkYCBjb3VudGVyIE9OTFkgd2hlbiB0aGUgc2lnbmFsIHdhcyBhY2NlcHRlZFxuICogIChhIGRyb3BwZWQvZmFpbGVkIFBPU1QgbXVzdCBub3Qgc2lsZW50bHkgemVybyB0aGUgYWNjdW11bGF0ZWQgY291bnQpLiAqL1xuYXN5bmMgZnVuY3Rpb24gcG9zdEluZ2VzdEhlYWx0aChiYXNlVXJsOiBzdHJpbmcsIGJvZHk6IHsgb3JnSWQ/OiBzdHJpbmc7IGZvcndhcmRlZDogbnVtYmVyOyBkcm9wcGVkOiBudW1iZXI7IGxhc3RFdmVudEF0Pzogc3RyaW5nIH0pOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgdHJ5IHtcbiAgICBjb25zdCB0b2tlbiA9IGF3YWl0IGdldEF1dGhUb2tlbigpO1xuICAgIGNvbnN0IHJlcyA9IGF3YWl0IGZldGNoKGAke2Jhc2VVcmx9L2FwaS9yZXBvcnRzL2luZ2VzdC1oZWFsdGhgLCB7XG4gICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgIGhlYWRlcnM6IHsgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJywgJ0F1dGhvcml6YXRpb24nOiBgQmVhcmVyICR7dG9rZW59YCB9LFxuICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoYm9keSksXG4gICAgfSk7XG4gICAgaWYgKCFyZXMub2spIHtcbiAgICAgIGxvZy53YXJuKCdpbmdlc3QtaGVhbHRoIFBPU1QgcmV0dXJuZWQgbm9uLTJ4eCAoaWdub3JlZCknLCB7IHN0YXR1czogcmVzLnN0YXR1cywgb3JnSWQ6IGJvZHkub3JnSWQgfSk7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICBsb2cud2FybignaW5nZXN0LWhlYWx0aCBQT1NUIGZhaWxlZCAoaWdub3JlZCknLCB7IGVycm9yOiBTdHJpbmcoZXJyKSwgb3JnSWQ6IGJvZHkub3JnSWQgfSk7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG59XG5cbi8qKlxuICogVGhyb3R0bGVkLCBiZXN0LWVmZm9ydCBwb3N0LXN1Y2Nlc3Mgd29yazogZW1pdCBwZXItb3JnIGluZ2VzdC1oZWFsdGggYW5kIHNlbGYtaGVhbFxuICogdGhlIERMUS4gTmV2ZXIgdGhyb3dzLiBgZm9yd2FyZGVkYC9gbGFzdEV2ZW50QXRgIGFjY3VtdWxhdGUgUEVSIE9SRyBhY3Jvc3MgYmF0Y2hlc1xuICogYmV0d2VlbiBoZWFsdGggcG9zdHM7IGBkcm9wcGVkYCBpcyB0aGUgc2hhcmVkIGZsZWV0IERMUSBkZXB0aCBzbmFwc2hvdC4gQSBwZXItb3JnXG4gKiBjb3VudGVyIGlzIHplcm9lZCBvbmx5IGFmdGVyIHRoYXQgb3JnJ3MgaGVhbHRoIFBPU1QgaXMgY29uZmlybWVkIDJ4eC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gcmVwb3J0SGVhbHRoQW5kUmVkcml2ZShiYXNlVXJsOiBzdHJpbmcsIG1haW5RdWV1ZUFybjogc3RyaW5nIHwgdW5kZWZpbmVkKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XG4gIGlmIChub3cgLSBsYXN0SGVhbHRoQXQgPCBIRUFMVEhfVEhST1RUTEVfTVMpIHJldHVybjtcbiAgbGFzdEhlYWx0aEF0ID0gbm93O1xuICB0cnkge1xuICAgIGNvbnN0IHEgPSBkZXJpdmVRdWV1ZXMobWFpblF1ZXVlQXJuKTtcbiAgICBsZXQgZGVwdGggPSAwO1xuICAgIGxldCBvbGRlc3RBZ2VTZWMgPSAwO1xuICAgIGlmIChxKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBzdGF0cyA9IGF3YWl0IGRscVN0YXRzKHEucmVnaW9uLCBxLmRscVVybCk7XG4gICAgICAgIGRlcHRoID0gc3RhdHMuZGVwdGg7XG4gICAgICAgIG9sZGVzdEFnZVNlYyA9IHN0YXRzLm9sZGVzdEFnZVNlYztcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBsb2cud2FybignRExRIHN0YXRzIGNoZWNrIGZhaWxlZCAoaWdub3JlZCknLCB7IGVycm9yOiAoZXJyIGFzIHsgbmFtZT86IHN0cmluZyB9KT8ubmFtZSA/PyBTdHJpbmcoZXJyKSB9KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBQb3N0IG9uZSBoZWFsdGggc2lnbmFsIHBlciByZXNvbHZlZCBvcmcsIGF0dHJpYnV0aW5nIGl0cyBvd24gZm9yd2FyZGVkIGNvdW50ICtcbiAgICAvLyBsYXN0IGV2ZW50IHRpbWUuIGBkcm9wcGVkYCAodGhlIHNoYXJlZCBmbGVldCBETFEgZGVwdGgpIHJpZGVzIGFsb25nIG9uIGVhY2guXG4gICAgLy8gU25hcHNob3QgdGhlIGtleXMgZmlyc3Qgc28gd2UgZG9uJ3QgbXV0YXRlIHRoZSBtYXAgd2hpbGUgaXRlcmF0aW5nLlxuICAgIGNvbnN0IG9yZ0tleXMgPSBuZXcgU2V0KFsuLi5mb3J3YXJkZWRCeU9yZy5rZXlzKCksIC4uLmxhc3RFdmVudEF0QnlPcmcua2V5cygpXSk7XG4gICAgaWYgKG9yZ0tleXMuc2l6ZSA9PT0gMCkgb3JnS2V5cy5hZGQoJycpOyAvLyBub3RoaW5nIGZvcndhcmRlZCB5ZXQg4oaSIHN0aWxsIHJlcG9ydCBkZXB0aFxuICAgIGZvciAoY29uc3Qga2V5IG9mIG9yZ0tleXMpIHtcbiAgICAgIGNvbnN0IGZvcndhcmRlZCA9IGZvcndhcmRlZEJ5T3JnLmdldChrZXkpID8/IDA7XG4gICAgICBjb25zdCBsYXN0RXZlbnRBdCA9IGxhc3RFdmVudEF0QnlPcmcuZ2V0KGtleSk7XG4gICAgICBjb25zdCBvayA9IGF3YWl0IHBvc3RJbmdlc3RIZWFsdGgoYmFzZVVybCwge1xuICAgICAgICAuLi4oa2V5ID8geyBvcmdJZDoga2V5IH0gOiB7fSksXG4gICAgICAgIGZvcndhcmRlZCxcbiAgICAgICAgZHJvcHBlZDogZGVwdGgsXG4gICAgICAgIGxhc3RFdmVudEF0LFxuICAgICAgfSk7XG4gICAgICAvLyBSZXNldCB0aGUgZm9yd2FyZGVkIGNvdW50ZXIgT05MWSBvbiBhIGNvbmZpcm1lZCAyeHgg4oCUIGEgZmFpbGVkL2Ryb3BwZWQgUE9TVFxuICAgICAgLy8ga2VlcHMgdGhlIGNvdW50IHNvIHRoZSBuZXh0IHRpY2sgcmUtcmVwb3J0cyBpdCBpbnN0ZWFkIG9mIGxvc2luZyBpdC5cbiAgICAgIGlmIChvaykgZm9yd2FyZGVkQnlPcmcuc2V0KGtleSwgMCk7XG4gICAgfVxuXG4gICAgaWYgKHEgJiYgZGVwdGggPiAwICYmIG5vdyAtIGxhc3RSZWRyaXZlQXQgPj0gUkVEUklWRV9USFJPVFRMRV9NUykge1xuICAgICAgLy8gUG9pc29uLW1lc3NhZ2UgY2VpbGluZzogbmV2ZXIgcmVkcml2ZSBhIERMUSB3aG9zZSBvbGRlc3QgbWVzc2FnZSBoYXMgYWdlZFxuICAgICAgLy8gcGFzdCB0aGUgY2VpbGluZyDigJQgdGhhdCBtZXNzYWdlIGtlZXBzIGZhaWxpbmcgYW5kIHdvdWxkIGxvb3AgRExR4oaSbWFpbuKGkkRMUS5cbiAgICAgIGlmIChvbGRlc3RBZ2VTZWMgPiBNQVhfRExRX1JFRFJJVkVfQUdFX1NFQykge1xuICAgICAgICBsb2cud2FybignRExRIG9sZGVzdCBtZXNzYWdlIGV4Y2VlZHMgcG9pc29uLWFnZSBjZWlsaW5nIOKAlCBza2lwcGluZyByZWRyaXZlIChuZWVkcyBtYW51YWwgYXR0ZW50aW9uKScsIHtcbiAgICAgICAgICBkbHFBcm46IHEuZGxxQXJuLCBkcm9wcGVkOiBkZXB0aCwgb2xkZXN0QWdlU2VjLCBjZWlsaW5nU2VjOiBNQVhfRExRX1JFRFJJVkVfQUdFX1NFQyxcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGlmICghKGF3YWl0IGhhc0FjdGl2ZU1vdmVUYXNrKHEucmVnaW9uLCBxLmRscUFybikpKSB7XG4gICAgICAgICAgICBsYXN0UmVkcml2ZUF0ID0gbm93O1xuICAgICAgICAgICAgYXdhaXQgc3RhcnRNb3ZlVGFzayhxLnJlZ2lvbiwgcS5kbHFBcm4sIHEubWFpbkFybik7XG4gICAgICAgICAgICBsb2cuaW5mbygnU3RhcnRlZCBzZWxmLWhlYWxpbmcgRExR4oaSbWFpbiByZWRyaXZlJywgeyBkbHFBcm46IHEuZGxxQXJuLCBkcm9wcGVkOiBkZXB0aCwgb2xkZXN0QWdlU2VjIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgbG9nLndhcm4oJ0RMUSByZWRyaXZlIGZhaWxlZCAoaWdub3JlZCknLCB7IGVycm9yOiAoZXJyIGFzIHsgbmFtZT86IHN0cmluZyB9KT8ubmFtZSA/PyBTdHJpbmcoZXJyKSB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgbG9nLndhcm4oJ2hlYWx0aC9yZWRyaXZlIHN0ZXAgZmFpbGVkIChpZ25vcmVkKScsIHsgZXJyb3I6IFN0cmluZyhlcnIpIH0pO1xuICB9XG59XG5cbi8vIOKUgOKUgOKUgCBIYW5kbGVyIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG5leHBvcnQgY29uc3QgaGFuZGxlciA9IGFzeW5jIChldmVudDogU1FTRXZlbnQpOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgY29uc3QgYmFzZVVybCA9IHByb2Nlc3MuZW52LlBMQVRGT1JNX0JBU0VfVVJMO1xuICBpZiAoIWJhc2VVcmwpIHRocm93IG5ldyBFcnJvcignUExBVEZPUk1fQkFTRV9VUkwgZW52aXJvbm1lbnQgdmFyaWFibGUgaXMgcmVxdWlyZWQnKTtcblxuICAvLyBQYXJzZSArIHJlc29sdmUgYWxsIHJlY29yZHMgKHRhZyArIGNvbW1pdCBsb29rdXBzIHJ1biBjb25jdXJyZW50bHkpOyBkcm9wXG4gIC8vIGludGVudGlvbmFsIHNraXBzIChudWxsKS4gQSBtYWxmb3JtZWQgcmVjb3JkIEJPRFkgaXMgaGFuZGxlZCBpbnNpZGUgcGFyc2VSZWNvcmRcbiAgLy8gKGxvZ2dlZCArIHNraXBwZWQpIHNvIG9uZSBiYWQgbWVzc2FnZSBjYW4ndCBmYWlsIHRoZSB3aG9sZSBiYXRjaCDigJQgd2hpbGUgZ2VudWluZVxuICAvLyBpbmZyYSBlcnJvcnMgKGUuZy4gQWNjZXNzRGVuaWVkIG9uIHRoZSB0YWcgbG9va3VwKSBzdGlsbCBwcm9wYWdhdGUgc28gYSBtaXNzaW5nXG4gIC8vIElBTSBncmFudCBzdXJmYWNlcyBhbmQgU1FTIHJldHJpZXMgdGhlIGJhdGNoLlxuICBjb25zdCBldmVudHMgPSAoYXdhaXQgUHJvbWlzZS5hbGwoZXZlbnQuUmVjb3Jkcy5tYXAocGFyc2VSZWNvcmQpKSlcbiAgICAuZmlsdGVyKChlKTogZSBpcyBQYXJzZWRFdmVudCA9PiBlICE9PSBudWxsKTtcbiAgaWYgKGV2ZW50cy5sZW5ndGggPT09IDApIHtcbiAgICBsb2cuaW5mbygnTm8gcmVzb2x2YWJsZSBDb2RlUGlwZWxpbmUgZXZlbnRzIGluIGJhdGNoJyk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgLy8gUE9TVCBiYXRjaCB0byByZXBvcnRpbmcgc2VydmljZS4gT24gYSA0MDEvNDAzIHRoZSBjYWNoZWQgSldUIGhhcyBsaWtlbHlcbiAgLy8gZXhwaXJlZCDigJQgZHJvcCBpdCwgcmUtZmV0Y2gsIGFuZCByZXRyeSBPTkNFIHNvIGFuIGV4cGlyZWQgdG9rZW4gZG9lc24ndFxuICAvLyBwZXJtYW5lbnRseSBicmljayBhIHdhcm0gY29udGFpbmVyLiBgb3JnSWRgIGlzIElOVEVSTkFMICh0b2tlbi9oZWFsdGgga2V5aW5nKSDigJRcbiAgLy8gc3RyaXAgaXQgaGVyZSBzbyBpdCBuZXZlciByaWRlcyB0aGUgd2lyZTsgdGhlIGluZ2VzdCByZXNvbHZlcyBvcmcgZnJvbSB0aGVcbiAgLy8gcGlwZWxpbmUgcmVnaXN0cnksIG5vdCB0aGUgYm9keS5cbiAgY29uc3QgcGF5bG9hZEV2ZW50cyA9IGV2ZW50cy5tYXAoKHsgb3JnSWQ6IF9vcmdJZCwgLi4ucmVzdCB9KSA9PiByZXN0KTtcbiAgY29uc3QgcG9zdCA9ICh0b2tlbjogc3RyaW5nKSA9PiBmZXRjaChgJHtiYXNlVXJsfS9hcGkvcmVwb3J0cy9ldmVudHNgLCB7XG4gICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgaGVhZGVyczogeyAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLCAnQXV0aG9yaXphdGlvbic6IGBCZWFyZXIgJHt0b2tlbn1gIH0sXG4gICAgYm9keTogSlNPTi5zdHJpbmdpZnkoeyBldmVudHM6IHBheWxvYWRFdmVudHMgfSksXG4gIH0pO1xuICBsZXQgcmVzID0gYXdhaXQgcG9zdChhd2FpdCBnZXRBdXRoVG9rZW4oKSk7XG4gIGlmIChyZXMuc3RhdHVzID09PSA0MDEgfHwgcmVzLnN0YXR1cyA9PT0gNDAzKSB7XG4gICAgbG9nLndhcm4oJ1JlcG9ydGluZyBBUEkgYXV0aCBmYWlsZWQ7IHJlZnJlc2hpbmcgdG9rZW4gYW5kIHJldHJ5aW5nIG9uY2UnLCB7IHN0YXR1czogcmVzLnN0YXR1cyB9KTtcbiAgICBjYWNoZWRUb2tlbiA9IG51bGw7XG4gICAgcmVzID0gYXdhaXQgcG9zdChhd2FpdCBnZXRBdXRoVG9rZW4oKSk7XG4gIH1cblxuICBpZiAoIXJlcy5vaykge1xuICAgIGNvbnN0IGJvZHkgPSBhd2FpdCByZXMudGV4dCgpLmNhdGNoKCgpID0+ICcnKTtcbiAgICBsb2cuZXJyb3IoYFJlcG9ydGluZyBBUEkgcmV0dXJuZWQgJHtyZXMuc3RhdHVzfWAsIHsgYm9keSB9KTtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYFJlcG9ydGluZyBBUEkgZmFpbGVkOiAke3Jlcy5zdGF0dXN9YCk7XG4gIH1cblxuICAvLyBUaGUgaW5zZXJ0IGFscmVhZHkgc3VjY2VlZGVkICgyeHgpLiBUaGUgcGFyc2VkIGJvZHkgaXMgb25seSB1c2VkIGZvciBhIGxvZ1xuICAvLyBsaW5lLCBzbyBhIG5vbi1KU09OL2VtcHR5IGJvZHkgbXVzdCBub3QgdGhyb3cgYW5kIGZhaWwgdGhlIHdob2xlIGJhdGNoIOKAlFxuICAvLyB0aGF0IHdvdWxkIHRyaWdnZXIgYW4gU1FTIHJlZGVsaXZlcnkgYW5kIHJlLVBPU1QgKGR1cGxpY2F0ZSkgYWxyZWFkeS1pbnNlcnRlZFxuICAvLyBldmVudHMuIFRoZSBpbmdlc3QncyBwYXJ0aWFsLXVuaXF1ZSBpbmRleCBkZWR1cGVzLCBidXQgYXZvaWQgdGhlIGNodXJuIGFueXdheS5cbiAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcmVzLmpzb24oKS5jYXRjaCgoKSA9PiAoe30pKSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgbG9nLmluZm8oYEluZ2VzdGVkICR7ZXZlbnRzLmxlbmd0aH0gZXZlbnRzYCwgeyBpbnNlcnRlZDogcmVzdWx0LmRhdGEgfSk7XG5cbiAgLy8gQWNjdW11bGF0ZSBkZWxpdmVyeS1oZWFsdGggY291bnRlcnMgUEVSIFJFU09MVkVEIE9SRywgdGhlbiBydW4gdGhlIHRocm90dGxlZFxuICAvLyBwb3N0LXN1Y2Nlc3MgaGVhbHRoICsgc2VsZi1oZWFsaW5nIERMUSByZWRyaXZlIChiZXN0LWVmZm9ydCwgbmV2ZXIgZmFpbHMgYmF0Y2gpLlxuICBmb3IgKGNvbnN0IGUgb2YgZXZlbnRzKSB7XG4gICAgY29uc3Qga2V5ID0gZS5vcmdJZCA/PyAnJztcbiAgICBmb3J3YXJkZWRCeU9yZy5zZXQoa2V5LCAoZm9yd2FyZGVkQnlPcmcuZ2V0KGtleSkgPz8gMCkgKyAxKTtcbiAgICBjb25zdCBhdCA9IGUuY29tcGxldGVkQXQgfHwgZS5zdGFydGVkQXQ7XG4gICAgaWYgKGF0KSB7XG4gICAgICBjb25zdCBwcmV2ID0gbGFzdEV2ZW50QXRCeU9yZy5nZXQoa2V5KTtcbiAgICAgIGlmICghcHJldiB8fCBhdCA+IHByZXYpIGxhc3RFdmVudEF0QnlPcmcuc2V0KGtleSwgYXQpO1xuICAgIH1cbiAgfVxuICBhd2FpdCByZXBvcnRIZWFsdGhBbmRSZWRyaXZlKGJhc2VVcmwsIGV2ZW50LlJlY29yZHNbMF0/LmV2ZW50U291cmNlQVJOKTtcbn07XG5cbi8qKlxuICogQGludGVybmFsIFRlc3Qtb25seTogcmVzZXQgYWxsIG1vZHVsZS1sZXZlbCBjYWNoZXMvdGhyb3R0bGUgc3RhdGUgc28gdGVzdHMgYXJlXG4gKiBpc29sYXRlZCBmcm9tIG9uZSBhbm90aGVyLiBTdHJpcHBlZCBmcm9tIHRoZSBwdWJsaXNoZWQgLmQudHMgKHN0cmlwSW50ZXJuYWwpLlxuICovXG5leHBvcnQgZnVuY3Rpb24gX3Jlc2V0Rm9yVGVzdHMoKTogdm9pZCB7XG4gIHJlc29sdmVkQnlBcm4uY2xlYXIoKTtcbiAgY29tbWl0UmVzdWx0Q2FjaGUuY2xlYXIoKTtcbiAgbGFzdFNoYUJ5UGlwZWxpbmUuY2xlYXIoKTtcbiAgY29tbWl0TWV0YUNhY2hlLmNsZWFyKCk7XG4gIHNjbUNvb2xkb3duVW50aWwgPSAwO1xuICBnaXRodWJUb2tlbkJ5T3JnLmNsZWFyKCk7XG4gIGZvcndhcmRlZEJ5T3JnLmNsZWFyKCk7XG4gIGxhc3RFdmVudEF0QnlPcmcuY2xlYXIoKTtcbiAgbGFzdEhlYWx0aEF0ID0gMDtcbiAgbGFzdFJlZHJpdmVBdCA9IDA7XG4gIGNhY2hlZFRva2VuID0gbnVsbDtcbn1cbiJdfQ==