@pipeline-builder/pipeline-data 4.3.11 → 4.3.12
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/api/managed-toolchain.d.ts +199 -0
- package/lib/api/managed-toolchain.js +445 -0
- package/lib/api/reporting/ingest.js +52 -12
- package/lib/api/reporting/toolchain-runs.d.ts +162 -0
- package/lib/api/reporting/toolchain-runs.js +268 -0
- package/lib/api/reporting/types.d.ts +17 -1
- package/lib/api/reporting/types.js +1 -1
- package/lib/api/version-references.d.ts +2 -24
- package/lib/api/version-references.js +46 -7
- package/lib/database/drizzle-schema.d.ts +650 -0
- package/lib/database/drizzle-schema.js +11 -1
- package/lib/database/index.d.ts +1 -1
- package/lib/database/index.js +2 -2
- package/lib/database/schema/ecosystem.d.ts +55 -0
- package/lib/database/schema/ecosystem.js +13 -2
- package/lib/database/schema/pipeline.d.ts +19 -0
- package/lib/database/schema/pipeline.js +17 -1
- package/lib/database/schema/toolchain.d.ts +643 -0
- package/lib/database/schema/toolchain.js +102 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +5 -1
- package/lib/testing/exports.json +39 -0
- package/package.json +2 -2
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* THE resolver for the managed toolchain (docs/plans/bootstrap-image-versioning.md
|
|
5
|
+
* §2). `pipeline-bootstrap@V` and `cdk-synth@V` are two SYSTEM-ORG plugin rows
|
|
6
|
+
* that share one release version `V`; every path that can resolve a managed
|
|
7
|
+
* name answers from here and nothing else may:
|
|
8
|
+
*
|
|
9
|
+
* release pin given → that release, if it EXISTS (yanked / deprecated /
|
|
10
|
+
* never-promoted still resolve, with a warning; deleted ⇒ 404)
|
|
11
|
+
* else org default → the NEAREST `org_toolchain_default` walking caller → … → root
|
|
12
|
+
* else canary → the NEAREST `toolchain_rollout` membership, served only
|
|
13
|
+
* while it passes the scan + metadata guards
|
|
14
|
+
* else platform → `toolchain_platform_default`
|
|
15
|
+
* else → 409 TOOLCHAIN_NO_DEFAULT (never "highest version", D11)
|
|
16
|
+
*
|
|
17
|
+
* - Reads are ELEVATED (`runWithTenantContext({ isSuperAdmin: true })`, as
|
|
18
|
+
* `versionReferences` does) and touch SYSTEM-ORG plugin rows only: the owner
|
|
19
|
+
* rank of `pluginResolutionOrderBy` is never consulted, so a same-named row in
|
|
20
|
+
* any other org is never a candidate.
|
|
21
|
+
* - Eligibility (D15) is a SET-time rule ({@link isEligibleRelease}); at resolve
|
|
22
|
+
* time a pin / org default only has to exist.
|
|
23
|
+
* - Both halves always come from ONE release (`TOOLCHAIN_PAIR_MISMATCH` otherwise).
|
|
24
|
+
* - The answer carries `resolvedVia` and nothing about any other org: no
|
|
25
|
+
* rollout membership, no ancestor's settings.
|
|
26
|
+
*/
|
|
27
|
+
import { AppError, compareSemver, createLogger, envInt, ErrorCode, fetchParentOrgId, getStatusForErrorCode, isSystemOrgId, MANAGED_TOOLCHAIN_PLUGINS, MAX_ORG_DEPTH, SYSTEM_ORG_ID, TOOLCHAIN_RELEASE_VERSION_PATTERN, toolchainFromMetadata, toOrgIdString, } from '@pipeline-builder/api-core';
|
|
28
|
+
import { and, eq, inArray, isNull, sql } from 'drizzle-orm';
|
|
29
|
+
import { schema } from '../database/drizzle-schema.js';
|
|
30
|
+
import { runWithTenantContext, withTenantTx } from '../database/tenancy.js';
|
|
31
|
+
const logger = createLogger('managed-toolchain');
|
|
32
|
+
/** A resolver refusal: `code` is TOOLCHAIN_NO_DEFAULT, NOT_FOUND, TOOLCHAIN_PAIR_MISMATCH or VALIDATION_ERROR. */
|
|
33
|
+
export class ManagedToolchainError extends AppError {
|
|
34
|
+
constructor(code, message, details) {
|
|
35
|
+
super(getStatusForErrorCode(code), code, message, details);
|
|
36
|
+
this.name = 'ManagedToolchainError';
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** Whether `version` is a release version (`MAJOR.MINOR.PATCH`). */
|
|
40
|
+
export function isToolchainReleaseVersion(version) {
|
|
41
|
+
return typeof version === 'string' && TOOLCHAIN_RELEASE_VERSION_PATTERN.test(version);
|
|
42
|
+
}
|
|
43
|
+
const BOOTSTRAP = 'pipeline-bootstrap';
|
|
44
|
+
const SYNTH = 'cdk-synth';
|
|
45
|
+
/** The release row and both SYSTEM-ORG halves of `releaseVersion` (deleted rows excluded). */
|
|
46
|
+
export async function loadReleaseHalves(db, releaseVersion) {
|
|
47
|
+
const [releases, rows] = await Promise.all([
|
|
48
|
+
db.select().from(schema.toolchainRelease).where(eq(schema.toolchainRelease.releaseVersion, releaseVersion)),
|
|
49
|
+
db.select().from(schema.plugin).where(and(sql `lower(${schema.plugin.orgId}) = ${SYSTEM_ORG_ID}`, inArray(schema.plugin.name, [...MANAGED_TOOLCHAIN_PLUGINS]), eq(schema.plugin.version, releaseVersion), isNull(schema.plugin.deletedAt))),
|
|
50
|
+
]);
|
|
51
|
+
const plugins = rows;
|
|
52
|
+
return {
|
|
53
|
+
releaseVersion,
|
|
54
|
+
release: releases[0] ?? null,
|
|
55
|
+
bootstrap: plugins.find((p) => p.name === BOOTSTRAP) ?? null,
|
|
56
|
+
synth: plugins.find((p) => p.name === SYNTH) ?? null,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/** The NEAREST row of `table` (keyed by `org_id`) on `chain` (own org first). */
|
|
60
|
+
async function nearestOnChain(db, table, chain) {
|
|
61
|
+
if (chain.length === 0)
|
|
62
|
+
return null;
|
|
63
|
+
const rows = await db.select({ orgId: table.orgId, releaseVersion: table.releaseVersion })
|
|
64
|
+
.from(table)
|
|
65
|
+
.where(inArray(sql `lower(${table.orgId})`, [...chain]));
|
|
66
|
+
let best = null;
|
|
67
|
+
for (const r of rows) {
|
|
68
|
+
const depth = chain.indexOf(r.orgId.toLowerCase());
|
|
69
|
+
if (depth >= 0 && (!best || depth < best.depth))
|
|
70
|
+
best = { depth, releaseVersion: r.releaseVersion };
|
|
71
|
+
}
|
|
72
|
+
return best;
|
|
73
|
+
}
|
|
74
|
+
async function currentPlatformDefault(db) {
|
|
75
|
+
const rows = await db.select({ releaseVersion: schema.toolchainPlatformDefault.releaseVersion })
|
|
76
|
+
.from(schema.toolchainPlatformDefault).limit(1);
|
|
77
|
+
return rows[0]?.releaseVersion ?? null;
|
|
78
|
+
}
|
|
79
|
+
/** Whether `releaseVersion` has ever been (or is) the platform default. */
|
|
80
|
+
async function wasPlatformDefault(db, releaseVersion) {
|
|
81
|
+
const [history, current] = await Promise.all([
|
|
82
|
+
db.select({ id: schema.toolchainDefaultHistory.id }).from(schema.toolchainDefaultHistory)
|
|
83
|
+
.where(eq(schema.toolchainDefaultHistory.releaseVersion, releaseVersion)).limit(1),
|
|
84
|
+
currentPlatformDefault(db),
|
|
85
|
+
]);
|
|
86
|
+
return history.length > 0 || current === releaseVersion;
|
|
87
|
+
}
|
|
88
|
+
/** Whether ANY org has an org default or a canary membership (else no walk is needed). */
|
|
89
|
+
async function anyOrgSettings(db) {
|
|
90
|
+
const [defaults, rollout] = await Promise.all([
|
|
91
|
+
db.select({ orgId: schema.orgToolchainDefault.orgId }).from(schema.orgToolchainDefault).limit(1),
|
|
92
|
+
db.select({ orgId: schema.toolchainRollout.orgId }).from(schema.toolchainRollout).limit(1),
|
|
93
|
+
]);
|
|
94
|
+
return defaults.length > 0 || rollout.length > 0;
|
|
95
|
+
}
|
|
96
|
+
// -----------------------------------------------------------------------------
|
|
97
|
+
// The org chain (caller → … → root)
|
|
98
|
+
// -----------------------------------------------------------------------------
|
|
99
|
+
/**
|
|
100
|
+
* The caller's chain, own org first, lowercased: `[self, parent, …, root]`.
|
|
101
|
+
* The same parent walk as `org-reachability.ts` (platform's
|
|
102
|
+
* `GET /organization/:id/parent`), cycle-safe and capped at `MAX_ORG_DEPTH` like
|
|
103
|
+
* `reporting-retention.ts` — but FAIL-CLOSED: a lookup failure, a cycle or an
|
|
104
|
+
* over-deep chain throws rather than resolving the wrong org's toolchain.
|
|
105
|
+
*/
|
|
106
|
+
export async function toolchainOrgChain(orgId, getParent) {
|
|
107
|
+
const self = orgId.toLowerCase();
|
|
108
|
+
const chain = [self];
|
|
109
|
+
if (isSystemOrgId(self))
|
|
110
|
+
return chain;
|
|
111
|
+
let current = self;
|
|
112
|
+
for (let depth = 0; depth < MAX_ORG_DEPTH; depth++) {
|
|
113
|
+
const parent = toOrgIdString(await getParent(current))?.toLowerCase();
|
|
114
|
+
if (!parent || parent === current)
|
|
115
|
+
return chain;
|
|
116
|
+
if (chain.includes(parent)) {
|
|
117
|
+
throw new ManagedToolchainError(ErrorCode.INTERNAL_ERROR, 'The organization hierarchy has a cycle; the toolchain release cannot be resolved.', { orgId: self });
|
|
118
|
+
}
|
|
119
|
+
chain.push(parent);
|
|
120
|
+
current = parent;
|
|
121
|
+
}
|
|
122
|
+
throw new ManagedToolchainError(ErrorCode.INTERNAL_ERROR, `The organization hierarchy is deeper than ${MAX_ORG_DEPTH}; the toolchain release cannot be resolved.`, { orgId: self });
|
|
123
|
+
}
|
|
124
|
+
/** Parent lookups are cached briefly: one synth makes several lookups for the same org. */
|
|
125
|
+
const PARENT_CACHE_TTL_MS = 30_000;
|
|
126
|
+
const PARENT_CACHE_MAX = 5_000;
|
|
127
|
+
const parentCache = new Map();
|
|
128
|
+
async function platformParent(orgId) {
|
|
129
|
+
const hit = parentCache.get(orgId);
|
|
130
|
+
if (hit && Date.now() - hit.at < PARENT_CACHE_TTL_MS)
|
|
131
|
+
return hit.parent;
|
|
132
|
+
// A system-scoped service token; a non-2xx THROWS (fail-closed, see toolchainOrgChain).
|
|
133
|
+
const parent = await fetchParentOrgId(orgId, { authOrgId: SYSTEM_ORG_ID, throwOnHttpError: true, timeout: 5_000 });
|
|
134
|
+
if (parentCache.size >= PARENT_CACHE_MAX)
|
|
135
|
+
parentCache.clear();
|
|
136
|
+
parentCache.set(orgId, { parent, at: Date.now() });
|
|
137
|
+
return parent;
|
|
138
|
+
}
|
|
139
|
+
/** Test hook: drop cached parent lookups. */
|
|
140
|
+
export function clearToolchainParentCacheForTests() {
|
|
141
|
+
parentCache.clear();
|
|
142
|
+
}
|
|
143
|
+
const productionDeps = {
|
|
144
|
+
read: (fn) => runWithTenantContext({ isSuperAdmin: true }, () => withTenantTx((tx) => fn(tx))),
|
|
145
|
+
getParent: platformParent,
|
|
146
|
+
};
|
|
147
|
+
let defaultDeps = productionDeps;
|
|
148
|
+
/** Test hook: replace the resolver's reads and hierarchy (null restores production). */
|
|
149
|
+
export function setManagedToolchainDepsForTests(deps) {
|
|
150
|
+
defaultDeps = deps ?? productionDeps;
|
|
151
|
+
}
|
|
152
|
+
const isYanked = (p) => p.yankedAt !== null || p.lifecycle === 'yanked';
|
|
153
|
+
const isDeprecated = (p) => p.deprecatedAt !== null || p.lifecycle === 'deprecated';
|
|
154
|
+
/** Whether both halves are present (the release EXISTS). */
|
|
155
|
+
export function releaseExists(h) {
|
|
156
|
+
return h.release !== null && h.bootstrap !== null && h.synth !== null;
|
|
157
|
+
}
|
|
158
|
+
export function releaseLifecycleProblems(h) {
|
|
159
|
+
if (!releaseExists(h))
|
|
160
|
+
return ['missing'];
|
|
161
|
+
const halves = [h.bootstrap, h.synth];
|
|
162
|
+
const out = [];
|
|
163
|
+
if (halves.some((p) => !p.isActive))
|
|
164
|
+
out.push('inactive');
|
|
165
|
+
if (halves.some(isYanked))
|
|
166
|
+
out.push('yanked');
|
|
167
|
+
if (halves.some(isDeprecated))
|
|
168
|
+
out.push('deprecated');
|
|
169
|
+
return out;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* The bootstrap half's toolchain metadata (`pipelineManager`, `awsCdk`, …), or
|
|
173
|
+
* null when it carries no complete, valid one. Upload persists it on the row's
|
|
174
|
+
* `metadata` as flat `toolchain.<field>` keys (api-core `toolchainMetadata`).
|
|
175
|
+
*/
|
|
176
|
+
export function bootstrapToolchainOf(row) {
|
|
177
|
+
return row ? toolchainFromMetadata(row.metadata) : null;
|
|
178
|
+
}
|
|
179
|
+
/** `PLUGIN_VULN_MAX_FINDINGS` (default 0): the fixable-Critical floor a release must be within. */
|
|
180
|
+
function vulnFloor() {
|
|
181
|
+
return envInt('PLUGIN_VULN_MAX_FINDINGS', 0, { min: 0 });
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* The §8 candidate guards (pair, scan, metadata) a release fails, as their
|
|
185
|
+
* error codes — empty when it passes. The canary gate and concurrency are the
|
|
186
|
+
* platform-default service's; a canary is served only while this is empty.
|
|
187
|
+
*/
|
|
188
|
+
export function toolchainCandidateProblems(h) {
|
|
189
|
+
if (!releaseExists(h) || releaseLifecycleProblems(h).length > 0)
|
|
190
|
+
return [ErrorCode.TOOLCHAIN_GUARD_PAIR_INCOMPLETE];
|
|
191
|
+
const out = [];
|
|
192
|
+
const halves = [h.bootstrap, h.synth];
|
|
193
|
+
if (halves.some((p) => !p.scannedAt))
|
|
194
|
+
out.push(ErrorCode.TOOLCHAIN_GUARD_UNSCANNED);
|
|
195
|
+
else if (halves.some((p) => (p.vulnCriticalFixable ?? 0) > vulnFloor()))
|
|
196
|
+
out.push(ErrorCode.TOOLCHAIN_GUARD_VULN_FLOOR);
|
|
197
|
+
if (!bootstrapToolchainOf(h.bootstrap))
|
|
198
|
+
out.push(ErrorCode.TOOLCHAIN_GUARD_METADATA);
|
|
199
|
+
return out;
|
|
200
|
+
}
|
|
201
|
+
/** Warnings for a release that EXISTS but is no longer (or never was) eligible. */
|
|
202
|
+
function standingWarnings(h, promoted, via) {
|
|
203
|
+
const ref = `Toolchain release ${h.releaseVersion}`;
|
|
204
|
+
const out = [];
|
|
205
|
+
const yanked = [h.bootstrap, h.synth].find(isYanked);
|
|
206
|
+
if (yanked) {
|
|
207
|
+
out.push({
|
|
208
|
+
code: 'TOOLCHAIN_RELEASE_YANKED',
|
|
209
|
+
severity: 'warning',
|
|
210
|
+
message: `${ref} is yanked${yanked.yankReason ? `: ${yanked.yankReason}` : ''}. It resolves only because it is selected exactly; move to a supported release.`,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
const deprecated = [h.bootstrap, h.synth].find(isDeprecated);
|
|
214
|
+
if (deprecated) {
|
|
215
|
+
out.push({
|
|
216
|
+
code: 'TOOLCHAIN_RELEASE_DEPRECATED',
|
|
217
|
+
severity: 'warning',
|
|
218
|
+
message: `${ref} is deprecated${deprecated.deprecationMessage ? `: ${deprecated.deprecationMessage}` : ''}.`,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
if ([h.bootstrap, h.synth].some((p) => !p.isActive)) {
|
|
222
|
+
out.push({ code: 'TOOLCHAIN_RELEASE_INACTIVE', severity: 'warning', message: `${ref} is inactive; move to a supported release.` });
|
|
223
|
+
}
|
|
224
|
+
if (!promoted && (via === 'pin' || via === 'org-default')) {
|
|
225
|
+
out.push({
|
|
226
|
+
code: 'TOOLCHAIN_RELEASE_NOT_PROMOTED',
|
|
227
|
+
severity: 'warning',
|
|
228
|
+
message: `${ref} was never the platform default and is not in a canary for your organization; it resolves only because it is selected exactly.`,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
return out;
|
|
232
|
+
}
|
|
233
|
+
// -----------------------------------------------------------------------------
|
|
234
|
+
// Resolution
|
|
235
|
+
// -----------------------------------------------------------------------------
|
|
236
|
+
function pairOf(h, via) {
|
|
237
|
+
if (!releaseExists(h)) {
|
|
238
|
+
// A default (platform or org) whose halves are gone is a broken invariant
|
|
239
|
+
// (in-use protection counts defaults): refused, never served.
|
|
240
|
+
throw new ManagedToolchainError(ErrorCode.TOOLCHAIN_PAIR_MISMATCH, `Toolchain release ${h.releaseVersion} (${via}) is incomplete; it is never served.`, {
|
|
241
|
+
releaseVersion: h.releaseVersion,
|
|
242
|
+
missing: [...(h.bootstrap ? [] : [BOOTSTRAP]), ...(h.synth ? [] : [SYNTH]), ...(h.release ? [] : ['toolchain_release'])],
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
if (h.bootstrap.version !== h.releaseVersion || h.synth.version !== h.releaseVersion) {
|
|
246
|
+
throw new ManagedToolchainError(ErrorCode.TOOLCHAIN_PAIR_MISMATCH, `Toolchain halves disagree (${BOOTSTRAP}@${h.bootstrap.version}, ${SYNTH}@${h.synth.version}); never served.`, {
|
|
247
|
+
releaseVersion: h.releaseVersion,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
return { bootstrap: h.bootstrap, synth: h.synth };
|
|
251
|
+
}
|
|
252
|
+
/** The resolution inside one elevated read, over a known chain. */
|
|
253
|
+
async function resolveOnChain(db, chain, releasePin) {
|
|
254
|
+
const canary = await nearestOnChain(db, schema.toolchainRollout, chain);
|
|
255
|
+
const answer = async (h, via) => {
|
|
256
|
+
const pair = pairOf(h, via);
|
|
257
|
+
const promoted = via === 'pin' || via === 'org-default'
|
|
258
|
+
? (await wasPlatformDefault(db, h.releaseVersion)) || canary?.releaseVersion === h.releaseVersion
|
|
259
|
+
: true;
|
|
260
|
+
return { releaseVersion: h.releaseVersion, resolvedVia: via, ...pair, warnings: standingWarnings({ ...h, ...pair }, promoted, via) };
|
|
261
|
+
};
|
|
262
|
+
if (releasePin !== undefined) {
|
|
263
|
+
if (!isToolchainReleaseVersion(releasePin)) {
|
|
264
|
+
throw new ManagedToolchainError(ErrorCode.VALIDATION_ERROR, 'releasePin must be a release version (MAJOR.MINOR.PATCH, e.g. 1.4.2).', { releasePin });
|
|
265
|
+
}
|
|
266
|
+
const h = await loadReleaseHalves(db, releasePin);
|
|
267
|
+
if (!releaseExists(h)) {
|
|
268
|
+
throw new ManagedToolchainError(ErrorCode.NOT_FOUND, `Toolchain release ${releasePin} does not exist (or was deleted). Pin an eligible release, or remove toolchain.release to follow your organization's default.`, {
|
|
269
|
+
reason: 'toolchain_release_not_found', releaseVersion: releasePin,
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
return answer(h, 'pin');
|
|
273
|
+
}
|
|
274
|
+
const orgDefault = await nearestOnChain(db, schema.orgToolchainDefault, chain);
|
|
275
|
+
if (orgDefault)
|
|
276
|
+
return answer(await loadReleaseHalves(db, orgDefault.releaseVersion), 'org-default');
|
|
277
|
+
if (canary) {
|
|
278
|
+
const h = await loadReleaseHalves(db, canary.releaseVersion);
|
|
279
|
+
const problems = toolchainCandidateProblems(h);
|
|
280
|
+
if (problems.length === 0)
|
|
281
|
+
return answer(h, 'canary');
|
|
282
|
+
// Members fall through to the platform default. Logged, never returned:
|
|
283
|
+
// the answer must not reveal canary membership.
|
|
284
|
+
logger.warn('Canary toolchain release fails its guards; serving the platform default', { releaseVersion: canary.releaseVersion, problems });
|
|
285
|
+
}
|
|
286
|
+
const platform = await currentPlatformDefault(db);
|
|
287
|
+
if (!platform) {
|
|
288
|
+
throw new ManagedToolchainError(ErrorCode.TOOLCHAIN_NO_DEFAULT, 'No platform default toolchain release is set. An operator must set one (init-platform does this on a fresh install).');
|
|
289
|
+
}
|
|
290
|
+
return answer(await loadReleaseHalves(db, platform), 'default');
|
|
291
|
+
}
|
|
292
|
+
/** {@link resolveManagedToolchain} with injected reads and hierarchy (tests). */
|
|
293
|
+
export async function resolveManagedToolchainWith(deps, caller, opts = {}) {
|
|
294
|
+
const self = caller.orgId.toLowerCase();
|
|
295
|
+
// Walk the hierarchy only when some org has a setting (and outside the transaction).
|
|
296
|
+
const walk = await deps.read((db) => anyOrgSettings(db));
|
|
297
|
+
const chain = walk ? await toolchainOrgChain(self, deps.getParent) : [self];
|
|
298
|
+
return deps.read((db) => resolveOnChain(db, chain, opts.releasePin));
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Resolve the managed toolchain release for `caller` (see the module doc).
|
|
302
|
+
* Throws {@link ManagedToolchainError}: TOOLCHAIN_NO_DEFAULT (409, no platform
|
|
303
|
+
* default), NOT_FOUND (404, a missing / deleted pin), TOOLCHAIN_PAIR_MISMATCH
|
|
304
|
+
* (500), VALIDATION_ERROR (400, a malformed pin).
|
|
305
|
+
*/
|
|
306
|
+
export function resolveManagedToolchain(caller, opts = {}) {
|
|
307
|
+
return resolveManagedToolchainWith(defaultDeps, caller, opts);
|
|
308
|
+
}
|
|
309
|
+
/** {@link isEligibleRelease} with injected reads and hierarchy (tests). */
|
|
310
|
+
export async function isEligibleReleaseWith(deps, orgId, releaseVersion) {
|
|
311
|
+
if (!isToolchainReleaseVersion(releaseVersion))
|
|
312
|
+
return false;
|
|
313
|
+
const self = orgId.toLowerCase();
|
|
314
|
+
const halves = await deps.read((db) => loadReleaseHalves(db, releaseVersion));
|
|
315
|
+
if (releaseLifecycleProblems(halves).length > 0)
|
|
316
|
+
return false;
|
|
317
|
+
if (await deps.read((db) => wasPlatformDefault(db, releaseVersion)))
|
|
318
|
+
return true;
|
|
319
|
+
const walk = await deps.read((db) => anyOrgSettings(db));
|
|
320
|
+
if (!walk)
|
|
321
|
+
return false;
|
|
322
|
+
const chain = await toolchainOrgChain(self, deps.getParent);
|
|
323
|
+
const canary = await deps.read((db) => nearestOnChain(db, schema.toolchainRollout, chain));
|
|
324
|
+
return canary?.releaseVersion === releaseVersion;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* D15: whether `orgId` may SET `releaseVersion` as a pipeline pin or its org
|
|
328
|
+
* default — both halves live (active, unyanked, not deprecated) AND either it
|
|
329
|
+
* has been the platform default or it is the caller's canary (nearest
|
|
330
|
+
* membership on its chain).
|
|
331
|
+
*/
|
|
332
|
+
export function isEligibleRelease(orgId, releaseVersion) {
|
|
333
|
+
return isEligibleReleaseWith(defaultDeps, orgId, releaseVersion);
|
|
334
|
+
}
|
|
335
|
+
/** {@link readOrgToolchainOverview} with injected reads and hierarchy (tests). */
|
|
336
|
+
export async function readOrgToolchainOverviewWith(deps, orgId) {
|
|
337
|
+
const self = orgId.toLowerCase();
|
|
338
|
+
const walk = await deps.read((db) => anyOrgSettings(db));
|
|
339
|
+
const chain = walk ? await toolchainOrgChain(self, deps.getParent) : [self];
|
|
340
|
+
return deps.read(async (db) => {
|
|
341
|
+
const rows = await db.select().from(schema.orgToolchainDefault)
|
|
342
|
+
.where(inArray(sql `lower(${schema.orgToolchainDefault.orgId})`, chain));
|
|
343
|
+
const depthOf = (r) => chain.indexOf(r.orgId.toLowerCase());
|
|
344
|
+
const ownDefault = rows.find((r) => depthOf(r) === 0) ?? null;
|
|
345
|
+
const nearest = rows.filter((r) => depthOf(r) >= 0).sort((a, b) => depthOf(a) - depthOf(b))[0] ?? null;
|
|
346
|
+
const [canary, platformDefault, resolution] = await Promise.all([
|
|
347
|
+
nearestOnChain(db, schema.toolchainRollout, chain),
|
|
348
|
+
currentPlatformDefault(db),
|
|
349
|
+
resolveOnChain(db, chain),
|
|
350
|
+
]);
|
|
351
|
+
return {
|
|
352
|
+
chain,
|
|
353
|
+
effective: { releaseVersion: resolution.releaseVersion, resolvedVia: resolution.resolvedVia, warnings: resolution.warnings },
|
|
354
|
+
ownDefault,
|
|
355
|
+
inheritedFrom: !ownDefault && nearest ? { orgId: nearest.orgId, releaseVersion: nearest.releaseVersion } : null,
|
|
356
|
+
canaryRelease: canary?.releaseVersion ?? null,
|
|
357
|
+
platformDefault,
|
|
358
|
+
};
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* The caller org's toolchain overview (elevated reads, the same chain walk and
|
|
363
|
+
* precedence as {@link resolveManagedToolchain}). Throws what the resolver
|
|
364
|
+
* throws — TOOLCHAIN_NO_DEFAULT (409) when nothing resolves at all.
|
|
365
|
+
*/
|
|
366
|
+
export function readOrgToolchainOverview(orgId) {
|
|
367
|
+
return readOrgToolchainOverviewWith(defaultDeps, orgId);
|
|
368
|
+
}
|
|
369
|
+
/** {@link listEligibleReleases} with injected reads and hierarchy (tests). */
|
|
370
|
+
export async function listEligibleReleasesWith(deps, orgId) {
|
|
371
|
+
const self = orgId.toLowerCase();
|
|
372
|
+
const walk = await deps.read((db) => anyOrgSettings(db));
|
|
373
|
+
const chain = walk ? await toolchainOrgChain(self, deps.getParent) : [self];
|
|
374
|
+
return deps.read(async (db) => {
|
|
375
|
+
const [releases, rows, history, platformDefault, canary] = await Promise.all([
|
|
376
|
+
db.select().from(schema.toolchainRelease),
|
|
377
|
+
db.select().from(schema.plugin).where(and(sql `lower(${schema.plugin.orgId}) = ${SYSTEM_ORG_ID}`, inArray(schema.plugin.name, [...MANAGED_TOOLCHAIN_PLUGINS]), isNull(schema.plugin.deletedAt))),
|
|
378
|
+
db.select({ releaseVersion: schema.toolchainDefaultHistory.releaseVersion }).from(schema.toolchainDefaultHistory),
|
|
379
|
+
currentPlatformDefault(db),
|
|
380
|
+
nearestOnChain(db, schema.toolchainRollout, chain),
|
|
381
|
+
]);
|
|
382
|
+
const promoted = new Set(history.map((h) => h.releaseVersion));
|
|
383
|
+
if (platformDefault)
|
|
384
|
+
promoted.add(platformDefault);
|
|
385
|
+
const out = [];
|
|
386
|
+
for (const release of releases) {
|
|
387
|
+
const v = release.releaseVersion;
|
|
388
|
+
const halves = {
|
|
389
|
+
releaseVersion: v,
|
|
390
|
+
release,
|
|
391
|
+
bootstrap: rows.find((p) => p.name === BOOTSTRAP && p.version === v) ?? null,
|
|
392
|
+
synth: rows.find((p) => p.name === SYNTH && p.version === v) ?? null,
|
|
393
|
+
};
|
|
394
|
+
if (!releaseExists(halves) || releaseLifecycleProblems(halves).length > 0)
|
|
395
|
+
continue;
|
|
396
|
+
const isCanary = canary?.releaseVersion === v;
|
|
397
|
+
if (!promoted.has(v) && !isCanary)
|
|
398
|
+
continue;
|
|
399
|
+
out.push({ releaseVersion: v, release, bootstrap: halves.bootstrap, synth: halves.synth, isPlatformDefault: platformDefault === v, isCanary });
|
|
400
|
+
}
|
|
401
|
+
out.sort((a, b) => compareSemver(b.releaseVersion, a.releaseVersion));
|
|
402
|
+
return { platformDefault, releases: out };
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Every release `orgId` may SET as a pipeline pin or its org default (D15, the
|
|
407
|
+
* same rule as {@link isEligibleRelease}), newest first. Never another org's
|
|
408
|
+
* data: a canary appears only when it is the caller's own (nearest) membership.
|
|
409
|
+
*/
|
|
410
|
+
export function listEligibleReleases(orgId) {
|
|
411
|
+
return listEligibleReleasesWith(defaultDeps, orgId);
|
|
412
|
+
}
|
|
413
|
+
// -----------------------------------------------------------------------------
|
|
414
|
+
// Caller helpers
|
|
415
|
+
// -----------------------------------------------------------------------------
|
|
416
|
+
/** The resolver's error as the refusal shape step resolution reports (contract check, declared side, facts). */
|
|
417
|
+
export function managedToolchainRefusal(err) {
|
|
418
|
+
switch (err.code) {
|
|
419
|
+
case ErrorCode.NOT_FOUND:
|
|
420
|
+
return { code: 'NOT_FOUND', reason: 'toolchain_release_not_found', message: err.message, ...(err.details ? { details: err.details } : {}) };
|
|
421
|
+
case ErrorCode.VALIDATION_ERROR:
|
|
422
|
+
return { code: 'NOT_FOUND', reason: 'toolchain_release_invalid', message: err.message, ...(err.details ? { details: err.details } : {}) };
|
|
423
|
+
case ErrorCode.TOOLCHAIN_NO_DEFAULT:
|
|
424
|
+
return { code: 'PLUGIN_UNAVAILABLE', reason: 'toolchain_no_default', message: err.message };
|
|
425
|
+
default:
|
|
426
|
+
return { code: 'PLUGIN_UNAVAILABLE', reason: 'toolchain_unresolved', message: err.message, ...(err.details ? { details: err.details } : {}) };
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Resolve ONE managed half for a step: the plugin row plus the resolution, or
|
|
431
|
+
* the refusal. Any non-resolver error (a database or hierarchy failure)
|
|
432
|
+
* propagates.
|
|
433
|
+
*/
|
|
434
|
+
export async function resolveManagedToolchainHalf(caller, name, opts = {}) {
|
|
435
|
+
try {
|
|
436
|
+
const resolution = await resolveManagedToolchain(caller, opts);
|
|
437
|
+
return { plugin: name === BOOTSTRAP ? resolution.bootstrap : resolution.synth, resolution };
|
|
438
|
+
}
|
|
439
|
+
catch (err) {
|
|
440
|
+
if (err instanceof ManagedToolchainError)
|
|
441
|
+
return { refusal: managedToolchainRefusal(err), error: err };
|
|
442
|
+
throw err;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFuYWdlZC10b29sY2hhaW4uanMiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hcGkvbWFuYWdlZC10b29sY2hhaW4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0Qzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F1Qkc7QUFFSCxPQUFPLEVBQ0wsUUFBUSxFQUFFLGFBQWEsRUFBRSxZQUFZLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxnQkFBZ0IsRUFBRSxxQkFBcUIsRUFBRSxhQUFhLEVBQ2hILHlCQUF5QixFQUFFLGFBQWEsRUFBRSxhQUFhLEVBQUUsaUNBQWlDLEVBQUUscUJBQXFCLEVBQUUsYUFBYSxHQUVqSSxNQUFNLDRCQUE0QixDQUFDO0FBQ3BDLE9BQU8sRUFBRSxHQUFHLEVBQUUsRUFBRSxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRzVELE9BQU8sRUFBRSxNQUFNLEVBQWdFLE1BQU0sK0JBQStCLENBQUM7QUFDckgsT0FBTyxFQUFFLG9CQUFvQixFQUFFLFlBQVksRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBRTVFLE1BQU0sTUFBTSxHQUFHLFlBQVksQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO0FBeUJqRCxrSEFBa0g7QUFDbEgsTUFBTSxPQUFPLHFCQUFzQixTQUFRLFFBQVE7SUFDakQsWUFBWSxJQUFlLEVBQUUsT0FBZSxFQUFFLE9BQWlDO1FBQzdFLEtBQUssQ0FBQyxxQkFBcUIsQ0FBQyxJQUFJLENBQUMsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQzNELElBQUksQ0FBQyxJQUFJLEdBQUcsdUJBQXVCLENBQUM7SUFDdEMsQ0FBQztDQUNGO0FBT0Qsb0VBQW9FO0FBQ3BFLE1BQU0sVUFBVSx5QkFBeUIsQ0FBQyxPQUFnQjtJQUN4RCxPQUFPLE9BQU8sT0FBTyxLQUFLLFFBQVEsSUFBSSxpQ0FBaUMsQ0FBQyxJQUFJ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R0FBRyxDQUFDO0lBQ1osQ0FBQztBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuLyoqXG4gKiBUSEUgcmVzb2x2ZXIgZm9yIHRoZSBtYW5hZ2VkIHRvb2xjaGFpbiAoZG9jcy9wbGFucy9ib290c3RyYXAtaW1hZ2UtdmVyc2lvbmluZy5tZFxuICogwqcyKS4gYHBpcGVsaW5lLWJvb3RzdHJhcEBWYCBhbmQgYGNkay1zeW50aEBWYCBhcmUgdHdvIFNZU1RFTS1PUkcgcGx1Z2luIHJvd3NcbiAqIHRoYXQgc2hhcmUgb25lIHJlbGVhc2UgdmVyc2lvbiBgVmA7IGV2ZXJ5IHBhdGggdGhhdCBjYW4gcmVzb2x2ZSBhIG1hbmFnZWRcbiAqIG5hbWUgYW5zd2VycyBmcm9tIGhlcmUgYW5kIG5vdGhpbmcgZWxzZSBtYXk6XG4gKlxuICogICByZWxlYXNlIHBpbiBnaXZlbiDihpIgdGhhdCByZWxlYXNlLCBpZiBpdCBFWElTVFMgKHlhbmtlZCAvIGRlcHJlY2F0ZWQgL1xuICogICAgICAgICAgICAgICAgICAgICAgIG5ldmVyLXByb21vdGVkIHN0aWxsIHJlc29sdmUsIHdpdGggYSB3YXJuaW5nOyBkZWxldGVkIOKHkiA0MDQpXG4gKiAgIGVsc2Ugb3JnIGRlZmF1bHQgIOKGkiB0aGUgTkVBUkVTVCBgb3JnX3Rvb2xjaGFpbl9kZWZhdWx0YCB3YWxraW5nIGNhbGxlciDihpIg4oCmIOKGkiByb290XG4gKiAgIGVsc2UgY2FuYXJ5ICAgICAgIOKGkiB0aGUgTkVBUkVTVCBgdG9vbGNoYWluX3JvbGxvdXRgIG1lbWJlcnNoaXAsIHNlcnZlZCBvbmx5XG4gKiAgICAgICAgICAgICAgICAgICAgICAgd2hpbGUgaXQgcGFzc2VzIHRoZSBzY2FuICsgbWV0YWRhdGEgZ3VhcmRzXG4gKiAgIGVsc2UgcGxhdGZvcm0gICAgIOKGkiBgdG9vbGNoYWluX3BsYXRmb3JtX2RlZmF1bHRgXG4gKiAgIGVsc2UgICAgICAgICAgICAgIOKGkiA0MDkgVE9PTENIQUlOX05PX0RFRkFVTFQgKG5ldmVyIFwiaGlnaGVzdCB2ZXJzaW9uXCIsIEQxMSlcbiAqXG4gKiAtIFJlYWRzIGFyZSBFTEVWQVRFRCAoYHJ1bldpdGhUZW5hbnRDb250ZXh0KHsgaXNTdXBlckFkbWluOiB0cnVlIH0pYCwgYXNcbiAqICAgYHZlcnNpb25SZWZlcmVuY2VzYCBkb2VzKSBhbmQgdG91Y2ggU1lTVEVNLU9SRyBwbHVnaW4gcm93cyBvbmx5OiB0aGUgb3duZXJcbiAqICAgcmFuayBvZiBgcGx1Z2luUmVzb2x1dGlvbk9yZGVyQnlgIGlzIG5ldmVyIGNvbnN1bHRlZCwgc28gYSBzYW1lLW5hbWVkIHJvdyBpblxuICogICBhbnkgb3RoZXIgb3JnIGlzIG5ldmVyIGEgY2FuZGlkYXRlLlxuICogLSBFbGlnaWJpbGl0eSAoRDE1KSBpcyBhIFNFVC10aW1lIHJ1bGUgKHtAbGluayBpc0VsaWdpYmxlUmVsZWFzZX0pOyBhdCByZXNvbHZlXG4gKiAgIHRpbWUgYSBwaW4gLyBvcmcgZGVmYXVsdCBvbmx5IGhhcyB0byBleGlzdC5cbiAqIC0gQm90aCBoYWx2ZXMgYWx3YXlzIGNvbWUgZnJvbSBPTkUgcmVsZWFzZSAoYFRPT0xDSEFJTl9QQUlSX01JU01BVENIYCBvdGhlcndpc2UpLlxuICogLSBUaGUgYW5zd2VyIGNhcnJpZXMgYHJlc29sdmVkVmlhYCBhbmQgbm90aGluZyBhYm91dCBhbnkgb3RoZXIgb3JnOiBub1xuICogICByb2xsb3V0IG1lbWJlcnNoaXAsIG5vIGFuY2VzdG9yJ3Mgc2V0dGluZ3MuXG4gKi9cblxuaW1wb3J0IHtcbiAgQXBwRXJyb3IsIGNvbXBhcmVTZW12ZXIsIGNyZWF0ZUxvZ2dlciwgZW52SW50LCBFcnJvckNvZGUsIGZldGNoUGFyZW50T3JnSWQsIGdldFN0YXR1c0ZvckVycm9yQ29kZSwgaXNTeXN0ZW1PcmdJZCxcbiAgTUFOQUdFRF9UT09MQ0hBSU5fUExVR0lOUywgTUFYX09SR19ERVBUSCwgU1lTVEVNX09SR19JRCwgVE9PTENIQUlOX1JFTEVBU0VfVkVSU0lPTl9QQVRURVJOLCB0b29sY2hhaW5Gcm9tTWV0YWRhdGEsIHRvT3JnSWRTdHJpbmcsXG4gIHR5cGUgR2V0UGFyZW50T3JnSWQsIHR5cGUgTWFuYWdlZFRvb2xjaGFpblBsdWdpbiwgdHlwZSBQbHVnaW5Ub29sY2hhaW4sXG59IGZyb20gJ0BwaXBlbGluZS1idWlsZGVyL2FwaS1jb3JlJztcbmltcG9ydCB7IGFuZCwgZXEsIGluQXJyYXksIGlzTnVsbCwgc3FsIH0gZnJvbSAnZHJpenpsZS1vcm0nO1xuaW1wb3J0IHR5cGUgeyBDcnVkVHggfSBmcm9tICcuL2NydWQtc2VydmljZS5qcyc7XG5pbXBvcnQgdHlwZSB7IFJlc29sdXRpb25SZWZ1c2FsIH0gZnJvbSAnLi9wbHVnaW4tcmVzb2x1dGlvbi5qcyc7XG5pbXBvcnQgeyBzY2hlbWEsIHR5cGUgT3JnVG9vbGNoYWluRGVmYXVsdCwgdHlwZSBQbHVnaW4sIHR5cGUgVG9vbGNoYWluUmVsZWFzZSB9IGZyb20gJy4uL2RhdGFiYXNlL2RyaXp6bGUtc2NoZW1hLmpzJztcbmltcG9ydCB7IHJ1bldpdGhUZW5hbnRDb250ZXh0LCB3aXRoVGVuYW50VHggfSBmcm9tICcuLi9kYXRhYmFzZS90ZW5hbmN5LmpzJztcblxuY29uc3QgbG9nZ2VyID0gY3JlYXRlTG9nZ2VyKCdtYW5hZ2VkLXRvb2xjaGFpbicpO1xuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gUHVibGljIHNoYXBlc1xuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuLyoqIEhvdyBhIHJlc29sdXRpb24gY2hvc2UgaXRzIHJlbGVhc2UuIE5ldmVyIG5hbWVzIHRoZSBvcmcgaXQgY2FtZSBmcm9tLiAqL1xuZXhwb3J0IHR5cGUgVG9vbGNoYWluUmVzb2x2ZWRWaWEgPSAncGluJyB8ICdvcmctZGVmYXVsdCcgfCAnY2FuYXJ5JyB8ICdkZWZhdWx0JztcblxuLyoqIEEgbm9uLWZhdGFsIG5vdGUgb24gYSByZXNvbHZlZCByZWxlYXNlIChzeW50aCBwcmludHMgaXQpLiAqL1xuZXhwb3J0IGludGVyZmFjZSBNYW5hZ2VkVG9vbGNoYWluV2FybmluZyB7XG4gIGNvZGU6IHN0cmluZztcbiAgbWVzc2FnZTogc3RyaW5nO1xuICBzZXZlcml0eTogJ2luZm8nIHwgJ3dhcm5pbmcnIHwgJ2Vycm9yJztcbn1cblxuLyoqIE9uZSByZWxlYXNlLCBib3RoIGhhbHZlcy4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTWFuYWdlZFRvb2xjaGFpblJlc29sdXRpb24ge1xuICByZWxlYXNlVmVyc2lvbjogc3RyaW5nO1xuICByZXNvbHZlZFZpYTogVG9vbGNoYWluUmVzb2x2ZWRWaWE7XG4gIGJvb3RzdHJhcDogUGx1Z2luO1xuICBzeW50aDogUGx1Z2luO1xuICB3YXJuaW5nczogTWFuYWdlZFRvb2xjaGFpbldhcm5pbmdbXTtcbn1cblxuLyoqIEEgcmVzb2x2ZXIgcmVmdXNhbDogYGNvZGVgIGlzIFRPT0xDSEFJTl9OT19ERUZBVUxULCBOT1RfRk9VTkQsIFRPT0xDSEFJTl9QQUlSX01JU01BVENIIG9yIFZBTElEQVRJT05fRVJST1IuICovXG5leHBvcnQgY2xhc3MgTWFuYWdlZFRvb2xjaGFpbkVycm9yIGV4dGVuZHMgQXBwRXJyb3Ige1xuICBjb25zdHJ1Y3Rvcihjb2RlOiBFcnJvckNvZGUsIG1lc3NhZ2U6IHN0cmluZywgZGV0YWlscz86IFJlY29yZDxzdHJpbmcsIHVua25vd24+KSB7XG4gICAgc3VwZXIoZ2V0U3RhdHVzRm9yRXJyb3JDb2RlKGNvZGUpLCBjb2RlLCBtZXNzYWdlLCBkZXRhaWxzKTtcbiAgICB0aGlzLm5hbWUgPSAnTWFuYWdlZFRvb2xjaGFpbkVycm9yJztcbiAgfVxufVxuXG4vKiogVGhlIGNhbGxlciBhIHJlc29sdXRpb24gcnVucyBmb3IuICovXG5leHBvcnQgaW50ZXJmYWNlIE1hbmFnZWRUb29sY2hhaW5DYWxsZXIge1xuICBvcmdJZDogc3RyaW5nO1xufVxuXG4vKiogV2hldGhlciBgdmVyc2lvbmAgaXMgYSByZWxlYXNlIHZlcnNpb24gKGBNQUpPUi5NSU5PUi5QQVRDSGApLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzVG9vbGNoYWluUmVsZWFzZVZlcnNpb24odmVyc2lvbjogdW5rbm93bik6IHZlcnNpb24gaXMgc3RyaW5nIHtcbiAgcmV0dXJuIHR5cGVvZiB2ZXJzaW9uID09PSAnc3RyaW5nJyAmJiBUT09MQ0hBSU5fUkVMRUFTRV9WRVJTSU9OX1BBVFRFUk4udGVzdCh2ZXJzaW9uKTtcbn1cblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIERhdGEgYWNjZXNzIChzeXN0ZW0tb3JnIHJvd3MsIGVsZXZhdGVkKVxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuLyoqIFdoYXQgdGhlIHJlc29sdmVyIHJlYWRzIHdpdGg6IGEgZHJpenpsZSB0cmFuc2FjdGlvbiAob3IgYW55IGRyaXp6bGUgZGF0YWJhc2UgaW4gdGVzdHMpLiAqL1xuZXhwb3J0IHR5cGUgVG9vbGNoYWluRGIgPSBQaWNrPENydWRUeCwgJ3NlbGVjdCc+O1xuXG4vKiogSG93IHRoZSByZXNvbHZlciByZWFkcyBhbmQgd2Fsa3MgdGhlIG9yZyB0cmVlIChpbmplY3RhYmxlIGZvciB0ZXN0cykuICovXG5leHBvcnQgaW50ZXJmYWNlIE1hbmFnZWRUb29sY2hhaW5EZXBzIHtcbiAgLyoqIFJ1biBgZm5gIHdpdGggRUxFVkFURUQgcmVhZHMuICovXG4gIHJlYWQ8VD4oZm46IChkYjogVG9vbGNoYWluRGIpID0+IFByb21pc2U8VD4pOiBQcm9taXNlPFQ+O1xuICAvKiogQW4gb3JnJ3MgZGlyZWN0IHBhcmVudCwgb3IgdW5kZWZpbmVkIGZvciBhIHJvb3QuIFRocm93cyB3aGVuIGl0IGNhbid0IHRlbGwuICovXG4gIGdldFBhcmVudDogR2V0UGFyZW50T3JnSWQ7XG59XG5cbi8qKiBCb3RoIGhhbHZlcyBvZiBvbmUgcmVsZWFzZSBhcyBzdG9yZWQsIHdpdGggdGhlIHJlbGVhc2Ugcm93LiAqL1xuZXhwb3J0IGludGVyZmFjZSBSZWxlYXNlSGFsdmVzIHtcbiAgcmVsZWFzZVZlcnNpb246IHN0cmluZztcbiAgcmVsZWFzZTogVG9vbGNoYWluUmVsZWFzZSB8IG51bGw7XG4gIGJvb3RzdHJhcDogUGx1Z2luIHwgbnVsbDtcbiAgc3ludGg6IFBsdWdpbiB8IG51bGw7XG59XG5cbmNvbnN0IEJPT1RTVFJBUDogTWFuYWdlZFRvb2xjaGFpblBsdWdpbiA9ICdwaXBlbGluZS1ib290c3RyYXAnO1xuY29uc3QgU1lOVEg6IE1hbmFnZWRUb29sY2hhaW5QbHVnaW4gPSAnY2RrLXN5bnRoJztcblxuLyoqIFRoZSByZWxlYXNlIHJvdyBhbmQgYm90aCBTWVNURU0tT1JHIGhhbHZlcyBvZiBgcmVsZWFzZVZlcnNpb25gIChkZWxldGVkIHJvd3MgZXhjbHVkZWQpLiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGxvYWRSZWxlYXNlSGFsdmVzKGRiOiBUb29sY2hhaW5EYiwgcmVsZWFzZVZlcnNpb246IHN0cmluZyk6IFByb21pc2U8UmVsZWFzZUhhbHZlcz4ge1xuICBjb25zdCBbcmVsZWFzZXMsIHJvd3NdID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgIGRiLnNlbGVjdCgpLmZyb20oc2NoZW1hLnRvb2xjaGFpblJlbGVhc2UpLndoZXJlKGVxKHNjaGVtYS50b29sY2hhaW5SZWxlYXNlLnJlbGVhc2VWZXJzaW9uLCByZWxlYXNlVmVyc2lvbikpLFxuICAgIGRiLnNlbGVjdCgpLmZyb20oc2NoZW1hLnBsdWdpbikud2hlcmUoYW5kKFxuICAgICAgc3FsYGxvd2VyKCR7c2NoZW1hLnBsdWdpbi5vcmdJZH0pID0gJHtTWVNURU1fT1JHX0lEfWAsXG4gICAgICBpbkFycmF5KHNjaGVtYS5wbHVnaW4ubmFtZSwgWy4uLk1BTkFHRURfVE9PTENIQUlOX1BMVUdJTlNdKSxcbiAgICAgIGVxKHNjaGVtYS5wbHVnaW4udmVyc2lvbiwgcmVsZWFzZVZlcnNpb24pLFxuICAgICAgaXNOdWxsKHNjaGVtYS5wbHVnaW4uZGVsZXRlZEF0KSxcbiAgICApKSxcbiAgXSk7XG4gIGNvbnN0IHBsdWdpbnMgPSByb3dzIGFzIFBsdWdpbltdO1xuICByZXR1cm4ge1xuICAgIHJlbGVhc2VWZXJzaW9uLFxuICAgIHJlbGVhc2U6IChyZWxlYXNlcyBhcyBUb29sY2hhaW5SZWxlYXNlW10pWzBdID8/IG51bGwsXG4gICAgYm9vdHN0cmFwOiBwbHVnaW5zLmZpbmQoKHApID0+IHAubmFtZSA9PT0gQk9PVFNUUkFQKSA/PyBudWxsLFxuICAgIHN5bnRoOiBwbHVnaW5zLmZpbmQoKHApID0+IHAubmFtZSA9PT0gU1lOVEgpID8/IG51bGwsXG4gIH07XG59XG5cbi8qKiBBIHNldHRpbmcgZm91bmQgb24gdGhlIGNhbGxlcidzIGNoYWluOiB3aGljaCBjaGFpbiBpbmRleCwgYW5kIGl0cyByZWxlYXNlLiAqL1xuaW50ZXJmYWNlIENoYWluU2V0dGluZyB7IGRlcHRoOiBudW1iZXI7IHJlbGVhc2VWZXJzaW9uOiBzdHJpbmcgfVxuXG4vKiogVGhlIE5FQVJFU1Qgcm93IG9mIGB0YWJsZWAgKGtleWVkIGJ5IGBvcmdfaWRgKSBvbiBgY2hhaW5gIChvd24gb3JnIGZpcnN0KS4gKi9cbmFzeW5jIGZ1bmN0aW9uIG5lYXJlc3RPbkNoYWluKFxuICBkYjogVG9vbGNoYWluRGIsXG4gIHRhYmxlOiB0eXBlb2Ygc2NoZW1hLm9yZ1Rvb2xjaGFpbkRlZmF1bHQgfCB0eXBlb2Ygc2NoZW1hLnRvb2xjaGFpblJvbGxvdXQsXG4gIGNoYWluOiByZWFkb25seSBzdHJpbmdbXSxcbik6IFByb21pc2U8Q2hhaW5TZXR0aW5nIHwgbnVsbD4ge1xuICBpZiAoY2hhaW4ubGVuZ3RoID09PSAwKSByZXR1cm4gbnVsbDtcbiAgY29uc3Qgcm93cyA9IGF3YWl0IGRiLnNlbGVjdCh7IG9yZ0lkOiB0YWJsZS5vcmdJZCwgcmVsZWFzZVZlcnNpb246IHRhYmxlLnJlbGVhc2VWZXJzaW9uIH0pXG4gICAgLmZyb20odGFibGUpXG4gICAgLndoZXJlKGluQXJyYXkoc3FsPHN0cmluZz5gbG93ZXIoJHt0YWJsZS5vcmdJZH0pYCwgWy4uLmNoYWluXSkpIGFzIEFycmF5PHsgb3JnSWQ6IHN0cmluZzsgcmVsZWFzZVZlcnNpb246IHN0cmluZyB9PjtcbiAgbGV0IGJlc3Q6IENoYWluU2V0dGluZyB8IG51bGwgPSBudWxsO1xuICBmb3IgKGNvbnN0IHIgb2Ygcm93cykge1xuICAgIGNvbnN0IGRlcHRoID0gY2hhaW4uaW5kZXhPZihyLm9yZ0lkLnRvTG93ZXJDYXNlKCkpO1xuICAgIGlmIChkZXB0aCA+PSAwICYmICghYmVzdCB8fCBkZXB0aCA8IGJlc3QuZGVwdGgpKSBiZXN0ID0geyBkZXB0aCwgcmVsZWFzZVZlcnNpb246IHIucmVsZWFzZVZlcnNpb24gfTtcbiAgfVxuICByZXR1cm4gYmVzdDtcbn1cblxuYXN5bmMgZnVuY3Rpb24gY3VycmVudFBsYXRmb3JtRGVmYXVsdChkYjogVG9vbGNoYWluRGIpOiBQcm9taXNlPHN0cmluZyB8IG51bGw+IHtcbiAgY29uc3Qgcm93cyA9IGF3YWl0IGRiLnNlbGVjdCh7IHJlbGVhc2VWZXJzaW9uOiBzY2hlbWEudG9vbGNoYWluUGxhdGZvcm1EZWZhdWx0LnJlbGVhc2VWZXJzaW9uIH0pXG4gICAgLmZyb20oc2NoZW1hLnRvb2xjaGFpblBsYXRmb3JtRGVmYXVsdCkubGltaXQoMSkgYXMgQXJyYXk8eyByZWxlYXNlVmVyc2lvbjogc3RyaW5nIH0+O1xuICByZXR1cm4gcm93c1swXT8ucmVsZWFzZVZlcnNpb24gPz8gbnVsbDtcbn1cblxuLyoqIFdoZXRoZXIgYHJlbGVhc2VWZXJzaW9uYCBoYXMgZXZlciBiZWVuIChvciBpcykgdGhlIHBsYXRmb3JtIGRlZmF1bHQuICovXG5hc3luYyBmdW5jdGlvbiB3YXNQbGF0Zm9ybURlZmF1bHQoZGI6IFRvb2xjaGFpbkRiLCByZWxlYXNlVmVyc2lvbjogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gIGNvbnN0IFtoaXN0b3J5LCBjdXJyZW50XSA9IGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICBkYi5zZWxlY3QoeyBpZDogc2NoZW1hLnRvb2xjaGFpbkRlZmF1bHRIaXN0b3J5LmlkIH0pLmZyb20oc2NoZW1hLnRvb2xjaGFpbkRlZmF1bHRIaXN0b3J5KVxuICAgICAgLndoZXJlKGVxKHNjaGVtYS50b29sY2hhaW5EZWZhdWx0SGlzdG9yeS5yZWxlYXNlVmVyc2lvbiwgcmVsZWFzZVZlcnNpb24pKS5saW1pdCgxKSxcbiAgICBjdXJyZW50UGxhdGZvcm1EZWZhdWx0KGRiKSxcbiAgXSk7XG4gIHJldHVybiAoaGlzdG9yeSBhcyB1bmtub3duW10pLmxlbmd0aCA+IDAgfHwgY3VycmVudCA9PT0gcmVsZWFzZVZlcnNpb247XG59XG5cbi8qKiBXaGV0aGVyIEFOWSBvcmcgaGFzIGFuIG9yZyBkZWZhdWx0IG9yIGEgY2FuYXJ5IG1lbWJlcnNoaXAgKGVsc2Ugbm8gd2FsayBpcyBuZWVkZWQpLiAqL1xuYXN5bmMgZnVuY3Rpb24gYW55T3JnU2V0dGluZ3MoZGI6IFRvb2xjaGFpbkRiKTogUHJvbWlzZTxib29sZWFuPiB7XG4gIGNvbnN0IFtkZWZhdWx0cywgcm9sbG91dF0gPSBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgZGIuc2VsZWN0KHsgb3JnSWQ6IHNjaGVtYS5vcmdUb29sY2hhaW5EZWZhdWx0Lm9yZ0lkIH0pLmZyb20oc2NoZW1hLm9yZ1Rvb2xjaGFpbkRlZmF1bHQpLmxpbWl0KDEpLFxuICAgIGRiLnNlbGVjdCh7IG9yZ0lkOiBzY2hlbWEudG9vbGNoYWluUm9sbG91dC5vcmdJZCB9KS5mcm9tKHNjaGVtYS50b29sY2hhaW5Sb2xsb3V0KS5saW1pdCgxKSxcbiAgXSk7XG4gIHJldHVybiAoZGVmYXVsdHMgYXMgdW5rbm93bltdKS5sZW5ndGggPiAwIHx8IChyb2xsb3V0IGFzIHVua25vd25bXSkubGVuZ3RoID4gMDtcbn1cblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIFRoZSBvcmcgY2hhaW4gKGNhbGxlciDihpIg4oCmIOKGkiByb290KVxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuLyoqXG4gKiBUaGUgY2FsbGVyJ3MgY2hhaW4sIG93biBvcmcgZmlyc3QsIGxvd2VyY2FzZWQ6IGBbc2VsZiwgcGFyZW50LCDigKYsIHJvb3RdYC5cbiAqIFRoZSBzYW1lIHBhcmVudCB3YWxrIGFzIGBvcmctcmVhY2hhYmlsaXR5LnRzYCAocGxhdGZvcm0nc1xuICogYEdFVCAvb3JnYW5pemF0aW9uLzppZC9wYXJlbnRgKSwgY3ljbGUtc2FmZSBhbmQgY2FwcGVkIGF0IGBNQVhfT1JHX0RFUFRIYCBsaWtlXG4gKiBgcmVwb3J0aW5nLXJldGVudGlvbi50c2Ag4oCUIGJ1dCBGQUlMLUNMT1NFRDogYSBsb29rdXAgZmFpbHVyZSwgYSBjeWNsZSBvciBhblxuICogb3Zlci1kZWVwIGNoYWluIHRocm93cyByYXRoZXIgdGhhbiByZXNvbHZpbmcgdGhlIHdyb25nIG9yZydzIHRvb2xjaGFpbi5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHRvb2xjaGFpbk9yZ0NoYWluKG9yZ0lkOiBzdHJpbmcsIGdldFBhcmVudDogR2V0UGFyZW50T3JnSWQpOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gIGNvbnN0IHNlbGYgPSBvcmdJZC50b0xvd2VyQ2FzZSgpO1xuICBjb25zdCBjaGFpbiA9IFtzZWxmXTtcbiAgaWYgKGlzU3lzdGVtT3JnSWQoc2VsZikpIHJldHVybiBjaGFpbjtcbiAgbGV0IGN1cnJlbnQgPSBzZWxmO1xuICBmb3IgKGxldCBkZXB0aCA9IDA7IGRlcHRoIDwgTUFYX09SR19ERVBUSDsgZGVwdGgrKykge1xuICAgIGNvbnN0IHBhcmVudCA9IHRvT3JnSWRTdHJpbmcoYXdhaXQgZ2V0UGFyZW50KGN1cnJlbnQpKT8udG9Mb3dlckNhc2UoKTtcbiAgICBpZiAoIXBhcmVudCB8fCBwYXJlbnQgPT09IGN1cnJlbnQpIHJldHVybiBjaGFpbjtcbiAgICBpZiAoY2hhaW4uaW5jbHVkZXMocGFyZW50KSkge1xuICAgICAgdGhyb3cgbmV3IE1hbmFnZWRUb29sY2hhaW5FcnJvcihFcnJvckNvZGUuSU5URVJOQUxfRVJST1IsICdUaGUgb3JnYW5pemF0aW9uIGhpZXJhcmNoeSBoYXMgYSBjeWNsZTsgdGhlIHRvb2xjaGFpbiByZWxlYXNlIGNhbm5vdCBiZSByZXNvbHZlZC4nLCB7IG9yZ0lkOiBzZWxmIH0pO1xuICAgIH1cbiAgICBjaGFpbi5wdXNoKHBhcmVudCk7XG4gICAgY3VycmVudCA9IHBhcmVudDtcbiAgfVxuICB0aHJvdyBuZXcgTWFuYWdlZFRvb2xjaGFpbkVycm9yKEVycm9yQ29kZS5JTlRFUk5BTF9FUlJPUiwgYFRoZSBvcmdhbml6YXRpb24gaGllcmFyY2h5IGlzIGRlZXBlciB0aGFuICR7TUFYX09SR19ERVBUSH07IHRoZSB0b29sY2hhaW4gcmVsZWFzZSBjYW5ub3QgYmUgcmVzb2x2ZWQuYCwgeyBvcmdJZDogc2VsZiB9KTtcbn1cblxuLyoqIFBhcmVudCBsb29rdXBzIGFyZSBjYWNoZWQgYnJpZWZseTogb25lIHN5bnRoIG1ha2VzIHNldmVyYWwgbG9va3VwcyBmb3IgdGhlIHNhbWUgb3JnLiAqL1xuY29uc3QgUEFSRU5UX0NBQ0hFX1RUTF9NUyA9IDMwXzAwMDtcbmNvbnN0IFBBUkVOVF9DQUNIRV9NQVggPSA1XzAwMDtcbmNvbnN0IHBhcmVudENhY2hlID0gbmV3IE1hcDxzdHJpbmcsIHsgcGFyZW50OiBzdHJpbmcgfCB1bmRlZmluZWQ7IGF0OiBudW1iZXIgfT4oKTtcblxuYXN5bmMgZnVuY3Rpb24gcGxhdGZvcm1QYXJlbnQob3JnSWQ6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nIHwgdW5kZWZpbmVkPiB7XG4gIGNvbnN0IGhpdCA9IHBhcmVudENhY2hlLmdldChvcmdJZCk7XG4gIGlmIChoaXQgJiYgRGF0ZS5ub3coKSAtIGhpdC5hdCA8IFBBUkVOVF9DQUNIRV9UVExfTVMpIHJldHVybiBoaXQucGFyZW50O1xuICAvLyBBIHN5c3RlbS1zY29wZWQgc2VydmljZSB0b2tlbjsgYSBub24tMnh4IFRIUk9XUyAoZmFpbC1jbG9zZWQsIHNlZSB0b29sY2hhaW5PcmdDaGFpbikuXG4gIGNvbnN0IHBhcmVudCA9IGF3YWl0IGZldGNoUGFyZW50T3JnSWQob3JnSWQsIHsgYXV0aE9yZ0lkOiBTWVNURU1fT1JHX0lELCB0aHJvd09uSHR0cEVycm9yOiB0cnVlLCB0aW1lb3V0OiA1XzAwMCB9KTtcbiAgaWYgKHBhcmVudENhY2hlLnNpemUgPj0gUEFSRU5UX0NBQ0hFX01BWCkgcGFyZW50Q2FjaGUuY2xlYXIoKTtcbiAgcGFyZW50Q2FjaGUuc2V0KG9yZ0lkLCB7IHBhcmVudCwgYXQ6IERhdGUubm93KCkgfSk7XG4gIHJldHVybiBwYXJlbnQ7XG59XG5cbi8qKiBUZXN0IGhvb2s6IGRyb3AgY2FjaGVkIHBhcmVudCBsb29rdXBzLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNsZWFyVG9vbGNoYWluUGFyZW50Q2FjaGVGb3JUZXN0cygpOiB2b2lkIHtcbiAgcGFyZW50Q2FjaGUuY2xlYXIoKTtcbn1cblxuY29uc3QgcHJvZHVjdGlvbkRlcHM6IE1hbmFnZWRUb29sY2hhaW5EZXBzID0ge1xuICByZWFkOiAoZm4pID0+IHJ1bldpdGhUZW5hbnRDb250ZXh0KHsgaXNTdXBlckFkbWluOiB0cnVlIH0sICgpID0+IHdpdGhUZW5hbnRUeCgodHgpID0+IGZuKHR4KSkpLFxuICBnZXRQYXJlbnQ6IHBsYXRmb3JtUGFyZW50LFxufTtcbmxldCBkZWZhdWx0RGVwczogTWFuYWdlZFRvb2xjaGFpbkRlcHMgPSBwcm9kdWN0aW9uRGVwcztcblxuLyoqIFRlc3QgaG9vazogcmVwbGFjZSB0aGUgcmVzb2x2ZXIncyByZWFkcyBhbmQgaGllcmFyY2h5IChudWxsIHJlc3RvcmVzIHByb2R1Y3Rpb24pLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNldE1hbmFnZWRUb29sY2hhaW5EZXBzRm9yVGVzdHMoZGVwczogTWFuYWdlZFRvb2xjaGFpbkRlcHMgfCBudWxsKTogdm9pZCB7XG4gIGRlZmF1bHREZXBzID0gZGVwcyA/PyBwcm9kdWN0aW9uRGVwcztcbn1cblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIExpZmVjeWNsZSwgZWxpZ2liaWxpdHkgYW5kIHRoZSBjYW5hcnkgZ3VhcmRzXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4vKiogV2h5IGEgc3RvcmVkIHJlbGVhc2UgaXMgbm90IExJVkUgKGVtcHR5ID0gbGl2ZTogYm90aCBoYWx2ZXMgcHJlc2VudCwgYWN0aXZlLCB1bnlhbmtlZCwgbm90IGRlcHJlY2F0ZWQpLiAqL1xuZXhwb3J0IHR5cGUgUmVsZWFzZUxpZmVjeWNsZVByb2JsZW0gPSAnbWlzc2luZycgfCAnaW5hY3RpdmUnIHwgJ3lhbmtlZCcgfCAnZGVwcmVjYXRlZCc7XG5cbmNvbnN0IGlzWWFua2VkID0gKHA6IFBsdWdpbikgPT4gcC55YW5rZWRBdCAhPT0gbnVsbCB8fCBwLmxpZmVjeWNsZSA9PT0gJ3lhbmtlZCc7XG5jb25zdCBpc0RlcHJlY2F0ZWQgPSAocDogUGx1Z2luKSA9PiBwLmRlcHJlY2F0ZWRBdCAhPT0gbnVsbCB8fCBwLmxpZmVjeWNsZSA9PT0gJ2RlcHJlY2F0ZWQnO1xuXG4vKiogV2hldGhlciBib3RoIGhhbHZlcyBhcmUgcHJlc2VudCAodGhlIHJlbGVhc2UgRVhJU1RTKS4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWxlYXNlRXhpc3RzKGg6IFJlbGVhc2VIYWx2ZXMpOiBoIGlzIFJlbGVhc2VIYWx2ZXMgJiB7IGJvb3RzdHJhcDogUGx1Z2luOyBzeW50aDogUGx1Z2luIH0ge1xuICByZXR1cm4gaC5yZWxlYXNlICE9PSBudWxsICYmIGguYm9vdHN0cmFwICE9PSBudWxsICYmIGguc3ludGggIT09IG51bGw7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZWxlYXNlTGlmZWN5Y2xlUHJvYmxlbXMoaDogUmVsZWFzZUhhbHZlcyk6IFJlbGVhc2VMaWZlY3ljbGVQcm9ibGVtW10ge1xuICBpZiAoIXJlbGVhc2VFeGlzdHMoaCkpIHJldHVybiBbJ21pc3NpbmcnXTtcbiAgY29uc3QgaGFsdmVzID0gW2guYm9vdHN0cmFwLCBoLnN5bnRoXTtcbiAgY29uc3Qgb3V0OiBSZWxlYXNlTGlmZWN5Y2xlUHJvYmxlbVtdID0gW107XG4gIGlmIChoYWx2ZXMuc29tZSgocCkgPT4gIXAuaXNBY3RpdmUpKSBvdXQucHVzaCgnaW5hY3RpdmUnKTtcbiAgaWYgKGhhbHZlcy5zb21lKGlzWWFua2VkKSkgb3V0LnB1c2goJ3lhbmtlZCcpO1xuICBpZiAoaGFsdmVzLnNvbWUoaXNEZXByZWNhdGVkKSkgb3V0LnB1c2goJ2RlcHJlY2F0ZWQnKTtcbiAgcmV0dXJuIG91dDtcbn1cblxuLyoqXG4gKiBUaGUgYm9vdHN0cmFwIGhhbGYncyB0b29sY2hhaW4gbWV0YWRhdGEgKGBwaXBlbGluZU1hbmFnZXJgLCBgYXdzQ2RrYCwg4oCmKSwgb3JcbiAqIG51bGwgd2hlbiBpdCBjYXJyaWVzIG5vIGNvbXBsZXRlLCB2YWxpZCBvbmUuIFVwbG9hZCBwZXJzaXN0cyBpdCBvbiB0aGUgcm93J3NcbiAqIGBtZXRhZGF0YWAgYXMgZmxhdCBgdG9vbGNoYWluLjxmaWVsZD5gIGtleXMgKGFwaS1jb3JlIGB0b29sY2hhaW5NZXRhZGF0YWApLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYm9vdHN0cmFwVG9vbGNoYWluT2Yocm93OiBQbHVnaW4gfCBudWxsIHwgdW5kZWZpbmVkKTogUGx1Z2luVG9vbGNoYWluIHwgbnVsbCB7XG4gIHJldHVybiByb3cgPyB0b29sY2hhaW5Gcm9tTWV0YWRhdGEocm93Lm1ldGFkYXRhKSA6IG51bGw7XG59XG5cbi8qKiBgUExVR0lOX1ZVTE5fTUFYX0ZJTkRJTkdTYCAoZGVmYXVsdCAwKTogdGhlIGZpeGFibGUtQ3JpdGljYWwgZmxvb3IgYSByZWxlYXNlIG11c3QgYmUgd2l0aGluLiAqL1xuZnVuY3Rpb24gdnVsbkZsb29yKCk6IG51bWJlciB7XG4gIHJldHVybiBlbnZJbnQoJ1BMVUdJTl9WVUxOX01BWF9GSU5ESU5HUycsIDAsIHsgbWluOiAwIH0pO1xufVxuXG4vKipcbiAqIFRoZSDCpzggY2FuZGlkYXRlIGd1YXJkcyAocGFpciwgc2NhbiwgbWV0YWRhdGEpIGEgcmVsZWFzZSBmYWlscywgYXMgdGhlaXJcbiAqIGVycm9yIGNvZGVzIOKAlCBlbXB0eSB3aGVuIGl0IHBhc3Nlcy4gVGhlIGNhbmFyeSBnYXRlIGFuZCBjb25jdXJyZW5jeSBhcmUgdGhlXG4gKiBwbGF0Zm9ybS1kZWZhdWx0IHNlcnZpY2UnczsgYSBjYW5hcnkgaXMgc2VydmVkIG9ubHkgd2hpbGUgdGhpcyBpcyBlbXB0eS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRvb2xjaGFpbkNhbmRpZGF0ZVByb2JsZW1zKGg6IFJlbGVhc2VIYWx2ZXMpOiBFcnJvckNvZGVbXSB7XG4gIGlmICghcmVsZWFzZUV4aXN0cyhoKSB8fCByZWxlYXNlTGlmZWN5Y2xlUHJvYmxlbXMoaCkubGVuZ3RoID4gMCkgcmV0dXJuIFtFcnJvckNvZGUuVE9PTENIQUlOX0dVQVJEX1BBSVJfSU5DT01QTEVURV07XG4gIGNvbnN0IG91dDogRXJyb3JDb2RlW10gPSBbXTtcbiAgY29uc3QgaGFsdmVzID0gW2guYm9vdHN0cmFwLCBoLnN5bnRoXTtcbiAgaWYgKGhhbHZlcy5zb21lKChwKSA9PiAhcC5zY2FubmVkQXQpKSBvdXQucHVzaChFcnJvckNvZGUuVE9PTENIQUlOX0dVQVJEX1VOU0NBTk5FRCk7XG4gIGVsc2UgaWYgKGhhbHZlcy5zb21lKChwKSA9PiAocC52dWxuQ3JpdGljYWxGaXhhYmxlID8/IDApID4gdnVsbkZsb29yKCkpKSBvdXQucHVzaChFcnJvckNvZGUuVE9PTENIQUlOX0dVQVJEX1ZVTE5fRkxPT1IpO1xuICBpZiAoIWJvb3RzdHJhcFRvb2xjaGFpbk9mKGguYm9vdHN0cmFwKSkgb3V0LnB1c2goRXJyb3JDb2RlLlRPT0xDSEFJTl9HVUFSRF9NRVRBREFUQSk7XG4gIHJldHVybiBvdXQ7XG59XG5cbi8qKiBXYXJuaW5ncyBmb3IgYSByZWxlYXNlIHRoYXQgRVhJU1RTIGJ1dCBpcyBubyBsb25nZXIgKG9yIG5ldmVyIHdhcykgZWxpZ2libGUuICovXG5mdW5jdGlvbiBzdGFuZGluZ1dhcm5pbmdzKGg6IFJlbGVhc2VIYWx2ZXMgJiB7IGJvb3RzdHJhcDogUGx1Z2luOyBzeW50aDogUGx1Z2luIH0sIHByb21vdGVkOiBib29sZWFuLCB2aWE6IFRvb2xjaGFpblJlc29sdmVkVmlhKTogTWFuYWdlZFRvb2xjaGFpbldhcm5pbmdbXSB7XG4gIGNvbnN0IHJlZiA9IGBUb29sY2hhaW4gcmVsZWFzZSAke2gucmVsZWFzZVZlcnNpb259YDtcbiAgY29uc3Qgb3V0OiBNYW5hZ2VkVG9vbGNoYWluV2FybmluZ1tdID0gW107XG4gIGNvbnN0IHlhbmtlZCA9IFtoLmJvb3RzdHJhcCwgaC5zeW50aF0uZmluZChpc1lhbmtlZCk7XG4gIGlmICh5YW5rZWQpIHtcbiAgICBvdXQucHVzaCh7XG4gICAgICBjb2RlOiAnVE9PTENIQUlOX1JFTEVBU0VfWUFOS0VEJyxcbiAgICAgIHNldmVyaXR5OiAnd2FybmluZycsXG4gICAgICBtZXNzYWdlOiBgJHtyZWZ9IGlzIHlhbmtlZCR7eWFua2VkLnlhbmtSZWFzb24gPyBgOiAke3lhbmtlZC55YW5rUmVhc29ufWAgOiAnJ30uIEl0IHJlc29sdmVzIG9ubHkgYmVjYXVzZSBpdCBpcyBzZWxlY3RlZCBleGFjdGx5OyBtb3ZlIHRvIGEgc3VwcG9ydGVkIHJlbGVhc2UuYCxcbiAgICB9KTtcbiAgfVxuICBjb25zdCBkZXByZWNhdGVkID0gW2guYm9vdHN0cmFwLCBoLnN5bnRoXS5maW5kKGlzRGVwcmVjYXRlZCk7XG4gIGlmIChkZXByZWNhdGVkKSB7XG4gICAgb3V0LnB1c2goe1xuICAgICAgY29kZTogJ1RPT0xDSEFJTl9SRUxFQVNFX0RFUFJFQ0FURUQnLFxuICAgICAgc2V2ZXJpdHk6ICd3YXJuaW5nJyxcbiAgICAgIG1lc3NhZ2U6IGAke3JlZn0gaXMgZGVwcmVjYXRlZCR7ZGVwcmVjYXRlZC5kZXByZWNhdGlvbk1lc3NhZ2UgPyBgOiAke2RlcHJlY2F0ZWQuZGVwcmVjYXRpb25NZXNzYWdlfWAgOiAnJ30uYCxcbiAgICB9KTtcbiAgfVxuICBpZiAoW2guYm9vdHN0cmFwLCBoLnN5bnRoXS5zb21lKChwKSA9PiAhcC5pc0FjdGl2ZSkpIHtcbiAgICBvdXQucHVzaCh7IGNvZGU6ICdUT09MQ0hBSU5fUkVMRUFTRV9JTkFDVElWRScsIHNldmVyaXR5OiAnd2FybmluZycsIG1lc3NhZ2U6IGAke3JlZn0gaXMgaW5hY3RpdmU7IG1vdmUgdG8gYSBzdXBwb3J0ZWQgcmVsZWFzZS5gIH0pO1xuICB9XG4gIGlmICghcHJvbW90ZWQgJiYgKHZpYSA9PT0gJ3BpbicgfHwgdmlhID09PSAnb3JnLWRlZmF1bHQnKSkge1xuICAgIG91dC5wdXNoKHtcbiAgICAgIGNvZGU6ICdUT09MQ0hBSU5fUkVMRUFTRV9OT1RfUFJPTU9URUQnLFxuICAgICAgc2V2ZXJpdHk6ICd3YXJuaW5nJyxcbiAgICAgIG1lc3NhZ2U6IGAke3JlZn0gd2FzIG5ldmVyIHRoZSBwbGF0Zm9ybSBkZWZhdWx0IGFuZCBpcyBub3QgaW4gYSBjYW5hcnkgZm9yIHlvdXIgb3JnYW5pemF0aW9uOyBpdCByZXNvbHZlcyBvbmx5IGJlY2F1c2UgaXQgaXMgc2VsZWN0ZWQgZXhhY3RseS5gLFxuICAgIH0pO1xuICB9XG4gIHJldHVybiBvdXQ7XG59XG5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyBSZXNvbHV0aW9uXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5mdW5jdGlvbiBwYWlyT2YoaDogUmVsZWFzZUhhbHZlcywgdmlhOiBUb29sY2hhaW5SZXNvbHZlZFZpYSk6IHsgYm9vdHN0cmFwOiBQbHVnaW47IHN5bnRoOiBQbHVnaW4gfSB7XG4gIGlmICghcmVsZWFzZUV4aXN0cyhoKSkge1xuICAgIC8vIEEgZGVmYXVsdCAocGxhdGZvcm0gb3Igb3JnKSB3aG9zZSBoYWx2ZXMgYXJlIGdvbmUgaXMgYSBicm9rZW4gaW52YXJpYW50XG4gICAgLy8gKGluLXVzZSBwcm90ZWN0aW9uIGNvdW50cyBkZWZhdWx0cyk6IHJlZnVzZWQsIG5ldmVyIHNlcnZlZC5cbiAgICB0aHJvdyBuZXcgTWFuYWdlZFRvb2xjaGFpbkVycm9yKEVycm9yQ29kZS5UT09MQ0hBSU5fUEFJUl9NSVNNQVRDSCwgYFRvb2xjaGFpbiByZWxlYXNlICR7aC5yZWxlYXNlVmVyc2lvbn0gKCR7dmlhfSkgaXMgaW5jb21wbGV0ZTsgaXQgaXMgbmV2ZXIgc2VydmVkLmAsIHtcbiAgICAgIHJlbGVhc2VWZXJzaW9uOiBoLnJlbGVhc2VWZXJzaW9uLFxuICAgICAgbWlzc2luZzogWy4uLihoLmJvb3RzdHJhcCA/IFtdIDogW0JPT1RTVFJBUF0pLCAuLi4oaC5zeW50aCA/IFtdIDogW1NZTlRIXSksIC4uLihoLnJlbGVhc2UgPyBbXSA6IFsndG9vbGNoYWluX3JlbGVhc2UnXSldLFxuICAgIH0pO1xuICB9XG4gIGlmIChoLmJvb3RzdHJhcC52ZXJzaW9uICE9PSBoLnJlbGVhc2VWZXJzaW9uIHx8IGguc3ludGgudmVyc2lvbiAhPT0gaC5yZWxlYXNlVmVyc2lvbikge1xuICAgIHRocm93IG5ldyBNYW5hZ2VkVG9vbGNoYWluRXJyb3IoRXJyb3JDb2RlLlRPT0xDSEFJTl9QQUlSX01JU01BVENILCBgVG9vbGNoYWluIGhhbHZlcyBkaXNhZ3JlZSAoJHtCT09UU1RSQVB9QCR7aC5ib290c3RyYXAudmVyc2lvbn0sICR7U1lOVEh9QCR7aC5zeW50aC52ZXJzaW9ufSk7IG5ldmVyIHNlcnZlZC5gLCB7XG4gICAgICByZWxlYXNlVmVyc2lvbjogaC5yZWxlYXNlVmVyc2lvbixcbiAgICB9KTtcbiAgfVxuICByZXR1cm4geyBib290c3RyYXA6IGguYm9vdHN0cmFwLCBzeW50aDogaC5zeW50aCB9O1xufVxuXG4vKiogVGhlIHJlc29sdXRpb24gaW5zaWRlIG9uZSBlbGV2YXRlZCByZWFkLCBvdmVyIGEga25vd24gY2hhaW4uICovXG5hc3luYyBmdW5jdGlvbiByZXNvbHZlT25DaGFpbihkYjogVG9vbGNoYWluRGIsIGNoYWluOiByZWFkb25seSBzdHJpbmdbXSwgcmVsZWFzZVBpbj86IHN0cmluZyk6IFByb21pc2U8TWFuYWdlZFRvb2xjaGFpblJlc29sdXRpb24+IHtcbiAgY29uc3QgY2FuYXJ5ID0gYXdhaXQgbmVhcmVzdE9uQ2hhaW4oZGIsIHNjaGVtYS50b29sY2hhaW5Sb2xsb3V0LCBjaGFpbik7XG4gIGNvbnN0IGFuc3dlciA9IGFzeW5jIChoOiBSZWxlYXNlSGFsdmVzLCB2aWE6IFRvb2xjaGFpblJlc29sdmVkVmlhKTogUHJvbWlzZTxNYW5hZ2VkVG9vbGNoYWluUmVzb2x1dGlvbj4gPT4ge1xuICAgIGNvbnN0IHBhaXIgPSBwYWlyT2YoaCwgdmlhKTtcbiAgICBjb25zdCBwcm9tb3RlZCA9IHZpYSA9PT0gJ3BpbicgfHwgdmlhID09PSAnb3JnLWRlZmF1bHQnXG4gICAgICA/IChhd2FpdCB3YXNQbGF0Zm9ybURlZmF1bHQoZGIsIGgucmVsZWFzZVZlcnNpb24pKSB8fCBjYW5hcnk/LnJlbGVhc2VWZXJzaW9uID09PSBoLnJlbGVhc2VWZXJzaW9uXG4gICAgICA6IHRydWU7XG4gICAgcmV0dXJuIHsgcmVsZWFzZVZlcnNpb246IGgucmVsZWFzZVZlcnNpb24sIHJlc29sdmVkVmlhOiB2aWEsIC4uLnBhaXIsIHdhcm5pbmdzOiBzdGFuZGluZ1dhcm5pbmdzKHsgLi4uaCwgLi4ucGFpciB9LCBwcm9tb3RlZCwgdmlhKSB9O1xuICB9O1xuXG4gIGlmIChyZWxlYXNlUGluICE9PSB1bmRlZmluZWQpIHtcbiAgICBpZiAoIWlzVG9vbGNoYWluUmVsZWFzZVZlcnNpb24ocmVsZWFzZVBpbikpIHtcbiAgICAgIHRocm93IG5ldyBNYW5hZ2VkVG9vbGNoYWluRXJyb3IoRXJyb3JDb2RlLlZBTElEQVRJT05fRVJST1IsICdyZWxlYXNlUGluIG11c3QgYmUgYSByZWxlYXNlIHZlcnNpb24gKE1BSk9SLk1JTk9SLlBBVENILCBlLmcuIDEuNC4yKS4nLCB7IHJlbGVhc2VQaW4gfSk7XG4gICAgfVxuICAgIGNvbnN0IGggPSBhd2FpdCBsb2FkUmVsZWFzZUhhbHZlcyhkYiwgcmVsZWFzZVBpbik7XG4gICAgaWYgKCFyZWxlYXNlRXhpc3RzKGgpKSB7XG4gICAgICB0aHJvdyBuZXcgTWFuYWdlZFRvb2xjaGFpbkVycm9yKEVycm9yQ29kZS5OT1RfRk9VTkQsIGBUb29sY2hhaW4gcmVsZWFzZSAke3JlbGVhc2VQaW59IGRvZXMgbm90IGV4aXN0IChvciB3YXMgZGVsZXRlZCkuIFBpbiBhbiBlbGlnaWJsZSByZWxlYXNlLCBvciByZW1vdmUgdG9vbGNoYWluLnJlbGVhc2UgdG8gZm9sbG93IHlvdXIgb3JnYW5pemF0aW9uJ3MgZGVmYXVsdC5gLCB7XG4gICAgICAgIHJlYXNvbjogJ3Rvb2xjaGFpbl9yZWxlYXNlX25vdF9mb3VuZCcsIHJlbGVhc2VWZXJzaW9uOiByZWxlYXNlUGluLFxuICAgICAgfSk7XG4gICAgfVxuICAgIHJldHVybiBhbnN3ZXIoaCwgJ3BpbicpO1xuICB9XG5cbiAgY29uc3Qgb3JnRGVmYXVsdCA9IGF3YWl0IG5lYXJlc3RPbkNoYWluKGRiLCBzY2hlbWEub3JnVG9vbGNoYWluRGVmYXVsdCwgY2hhaW4pO1xuICBpZiAob3JnRGVmYXVsdCkgcmV0dXJuIGFuc3dlcihhd2FpdCBsb2FkUmVsZWFzZUhhbHZlcyhkYiwgb3JnRGVmYXVsdC5yZWxlYXNlVmVyc2lvbiksICdvcmctZGVmYXVsdCcpO1xuXG4gIGlmIChjYW5hcnkpIHtcbiAgICBjb25zdCBoID0gYXdhaXQgbG9hZFJlbGVhc2VIYWx2ZXMoZGIsIGNhbmFyeS5yZWxlYXNlVmVyc2lvbik7XG4gICAgY29uc3QgcHJvYmxlbXMgPSB0b29sY2hhaW5DYW5kaWRhdGVQcm9ibGVtcyhoKTtcbiAgICBpZiAocHJvYmxlbXMubGVuZ3RoID09PSAwKSByZXR1cm4gYW5zd2VyKGgsICdjYW5hcnknKTtcbiAgICAvLyBNZW1iZXJzIGZhbGwgdGhyb3VnaCB0byB0aGUgcGxhdGZvcm0gZGVmYXVsdC4gTG9nZ2VkLCBuZXZlciByZXR1cm5lZDpcbiAgICAvLyB0aGUgYW5zd2VyIG11c3Qgbm90IHJldmVhbCBjYW5hcnkgbWVtYmVyc2hpcC5cbiAgICBsb2dnZXIud2FybignQ2FuYXJ5IHRvb2xjaGFpbiByZWxlYXNlIGZhaWxzIGl0cyBndWFyZHM7IHNlcnZpbmcgdGhlIHBsYXRmb3JtIGRlZmF1bHQnLCB7IHJlbGVhc2VWZXJzaW9uOiBjYW5hcnkucmVsZWFzZVZlcnNpb24sIHByb2JsZW1zIH0pO1xuICB9XG5cbiAgY29uc3QgcGxhdGZvcm0gPSBhd2FpdCBjdXJyZW50UGxhdGZvcm1EZWZhdWx0KGRiKTtcbiAgaWYgKCFwbGF0Zm9ybSkge1xuICAgIHRocm93IG5ldyBNYW5hZ2VkVG9vbGNoYWluRXJyb3IoRXJyb3JDb2RlLlRPT0xDSEFJTl9OT19ERUZBVUxULCAnTm8gcGxhdGZvcm0gZGVmYXVsdCB0b29sY2hhaW4gcmVsZWFzZSBpcyBzZXQuIEFuIG9wZXJhdG9yIG11c3Qgc2V0IG9uZSAoaW5pdC1wbGF0Zm9ybSBkb2VzIHRoaXMgb24gYSBmcmVzaCBpbnN0YWxsKS4nKTtcbiAgfVxuICByZXR1cm4gYW5zd2VyKGF3YWl0IGxvYWRSZWxlYXNlSGFsdmVzKGRiLCBwbGF0Zm9ybSksICdkZWZhdWx0Jyk7XG59XG5cbi8qKiB7QGxpbmsgcmVzb2x2ZU1hbmFnZWRUb29sY2hhaW59IHdpdGggaW5qZWN0ZWQgcmVhZHMgYW5kIGhpZXJhcmNoeSAodGVzdHMpLiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlc29sdmVNYW5hZ2VkVG9vbGNoYWluV2l0aChcbiAgZGVwczogTWFuYWdlZFRvb2xjaGFpbkRlcHMsXG4gIGNhbGxlcjogTWFuYWdlZFRvb2xjaGFpbkNhbGxlcixcbiAgb3B0czogeyByZWxlYXNlUGluPzogc3RyaW5nIH0gPSB7fSxcbik6IFByb21pc2U8TWFuYWdlZFRvb2xjaGFpblJlc29sdXRpb24+IHtcbiAgY29uc3Qgc2VsZiA9IGNhbGxlci5vcmdJZC50b0xvd2VyQ2FzZSgpO1xuICAvLyBXYWxrIHRoZSBoaWVyYXJjaHkgb25seSB3aGVuIHNvbWUgb3JnIGhhcyBhIHNldHRpbmcgKGFuZCBvdXRzaWRlIHRoZSB0cmFuc2FjdGlvbikuXG4gIGNvbnN0IHdhbGsgPSBhd2FpdCBkZXBzLnJlYWQoKGRiKSA9PiBhbnlPcmdTZXR0aW5ncyhkYikpO1xuICBjb25zdCBjaGFpbiA9IHdhbGsgPyBhd2FpdCB0b29sY2hhaW5PcmdDaGFpbihzZWxmLCBkZXBzLmdldFBhcmVudCkgOiBbc2VsZl07XG4gIHJldHVybiBkZXBzLnJlYWQoKGRiKSA9PiByZXNvbHZlT25DaGFpbihkYiwgY2hhaW4sIG9wdHMucmVsZWFzZVBpbikpO1xufVxuXG4vKipcbiAqIFJlc29sdmUgdGhlIG1hbmFnZWQgdG9vbGNoYWluIHJlbGVhc2UgZm9yIGBjYWxsZXJgIChzZWUgdGhlIG1vZHVsZSBkb2MpLlxuICogVGhyb3dzIHtAbGluayBNYW5hZ2VkVG9vbGNoYWluRXJyb3J9OiBUT09MQ0hBSU5fTk9fREVGQVVMVCAoNDA5LCBubyBwbGF0Zm9ybVxuICogZGVmYXVsdCksIE5PVF9GT1VORCAoNDA0LCBhIG1pc3NpbmcgLyBkZWxldGVkIHBpbiksIFRPT0xDSEFJTl9QQUlSX01JU01BVENIXG4gKiAoNTAwKSwgVkFMSURBVElPTl9FUlJPUiAoNDAwLCBhIG1hbGZvcm1lZCBwaW4pLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZU1hbmFnZWRUb29sY2hhaW4oY2FsbGVyOiBNYW5hZ2VkVG9vbGNoYWluQ2FsbGVyLCBvcHRzOiB7IHJlbGVhc2VQaW4/OiBzdHJpbmcgfSA9IHt9KTogUHJvbWlzZTxNYW5hZ2VkVG9vbGNoYWluUmVzb2x1dGlvbj4ge1xuICByZXR1cm4gcmVzb2x2ZU1hbmFnZWRUb29sY2hhaW5XaXRoKGRlZmF1bHREZXBzLCBjYWxsZXIsIG9wdHMpO1xufVxuXG4vKioge0BsaW5rIGlzRWxpZ2libGVSZWxlYXNlfSB3aXRoIGluamVjdGVkIHJlYWRzIGFuZCBoaWVyYXJjaHkgKHRlc3RzKS4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBpc0VsaWdpYmxlUmVsZWFzZVdpdGgoZGVwczogTWFuYWdlZFRvb2xjaGFpbkRlcHMsIG9yZ0lkOiBzdHJpbmcsIHJlbGVhc2VWZXJzaW9uOiBzdHJpbmcpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgaWYgKCFpc1Rvb2xjaGFpblJlbGVhc2VWZXJzaW9uKHJlbGVhc2VWZXJzaW9uKSkgcmV0dXJuIGZhbHNlO1xuICBjb25zdCBzZWxmID0gb3JnSWQudG9Mb3dlckNhc2UoKTtcbiAgY29uc3QgaGFsdmVzID0gYXdhaXQgZGVwcy5yZWFkKChkYikgPT4gbG9hZFJlbGVhc2VIYWx2ZXMoZGIsIHJlbGVhc2VWZXJzaW9uKSk7XG4gIGlmIChyZWxlYXNlTGlmZWN5Y2xlUHJvYmxlbXMoaGFsdmVzKS5sZW5ndGggPiAwKSByZXR1cm4gZmFsc2U7XG4gIGlmIChhd2FpdCBkZXBzLnJlYWQoKGRiKSA9PiB3YXNQbGF0Zm9ybURlZmF1bHQoZGIsIHJlbGVhc2VWZXJzaW9uKSkpIHJldHVybiB0cnVlO1xuICBjb25zdCB3YWxrID0gYXdhaXQgZGVwcy5yZWFkKChkYikgPT4gYW55T3JnU2V0dGluZ3MoZGIpKTtcbiAgaWYgKCF3YWxrKSByZXR1cm4gZmFsc2U7XG4gIGNvbnN0IGNoYWluID0gYXdhaXQgdG9vbGNoYWluT3JnQ2hhaW4oc2VsZiwgZGVwcy5nZXRQYXJlbnQpO1xuICBjb25zdCBjYW5hcnkgPSBhd2FpdCBkZXBzLnJlYWQoKGRiKSA9PiBuZWFyZXN0T25DaGFpbihkYiwgc2NoZW1hLnRvb2xjaGFpblJvbGxvdXQsIGNoYWluKSk7XG4gIHJldHVybiBjYW5hcnk/LnJlbGVhc2VWZXJzaW9uID09PSByZWxlYXNlVmVyc2lvbjtcbn1cblxuLyoqXG4gKiBEMTU6IHdoZXRoZXIgYG9yZ0lkYCBtYXkgU0VUIGByZWxlYXNlVmVyc2lvbmAgYXMgYSBwaXBlbGluZSBwaW4gb3IgaXRzIG9yZ1xuICogZGVmYXVsdCDigJQgYm90aCBoYWx2ZXMgbGl2ZSAoYWN0aXZlLCB1bnlhbmtlZCwgbm90IGRlcHJlY2F0ZWQpIEFORCBlaXRoZXIgaXRcbiAqIGhhcyBiZWVuIHRoZSBwbGF0Zm9ybSBkZWZhdWx0IG9yIGl0IGlzIHRoZSBjYWxsZXIncyBjYW5hcnkgKG5lYXJlc3RcbiAqIG1lbWJlcnNoaXAgb24gaXRzIGNoYWluKS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzRWxpZ2libGVSZWxlYXNlKG9yZ0lkOiBzdHJpbmcsIHJlbGVhc2VWZXJzaW9uOiBzdHJpbmcpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgcmV0dXJuIGlzRWxpZ2libGVSZWxlYXNlV2l0aChkZWZhdWx0RGVwcywgb3JnSWQsIHJlbGVhc2VWZXJzaW9uKTtcbn1cblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIFRoZSBvcmcncyBvd24gcGljdHVyZTogdGhlIG9yZy1kZWZhdWx0IHBhbmVsIGFuZCB0aGUgZWxpZ2libGUtcmVsZWFzZSBsaXN0XG4vLyAoZG9jcy9wbGFucy9ib290c3RyYXAtaW1hZ2UtdmVyc2lvbmluZy5tZCDCpzUsIFBoYXNlIDQsIEQxNSlcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbi8qKlxuICogV2hhdCB0aGUgb3JnLWRlZmF1bHQgcGFuZWwgc2hvd3MgYSBjYWxsZXIgYWJvdXQgSVRTIE9XTiBvcmc6IG5ldmVyIGFub3RoZXJcbiAqIG9yZydzIGNob2ljZSwgYW5kIG9mIHRoZSBhbmNlc3RvcnMgb25seSB3aGljaCBvbmUncyBkZWZhdWx0IGFwcGxpZXMuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgT3JnVG9vbGNoYWluT3ZlcnZpZXcge1xuICAvKiogVGhlIGNhbGxlcidzIGNoYWluLCBvd24gb3JnIGZpcnN0IChsb3dlcmNhc2VkKS4gKi9cbiAgY2hhaW46IHN0cmluZ1tdO1xuICAvKiogV2hhdCB0aGUgb3JnJ3MgVU5QSU5ORUQgcGlwZWxpbmVzIHJlc29sdmUgdG8gbm93LiAqL1xuICBlZmZlY3RpdmU6IHsgcmVsZWFzZVZlcnNpb246IHN0cmluZzsgcmVzb2x2ZWRWaWE6IFRvb2xjaGFpblJlc29sdmVkVmlhOyB3YXJuaW5nczogTWFuYWdlZFRvb2xjaGFpbldhcm5pbmdbXSB9O1xuICAvKiogVGhlIGNhbGxlciBvcmcncyBvd24gYG9yZ190b29sY2hhaW5fZGVmYXVsdGAgcm93LCBpZiBpdCBzZXQgb25lLiAqL1xuICBvd25EZWZhdWx0OiBPcmdUb29sY2hhaW5EZWZhdWx0IHwgbnVsbDtcbiAgLyoqIFRoZSBhbmNlc3RvciB3aG9zZSBvcmcgZGVmYXVsdCBhcHBsaWVzLCB3aGVuIHRoZSBvcmcgc2V0IG5vbmUgb2YgaXRzIG93bi4gKi9cbiAgaW5oZXJpdGVkRnJvbTogeyBvcmdJZDogc3RyaW5nOyByZWxlYXNlVmVyc2lvbjogc3RyaW5nIH0gfCBudWxsO1xuICAvKiogVGhlIGNhbGxlcidzIGNhbmFyeSByZWxlYXNlIChpdHMgTkVBUkVTVCBtZW1iZXJzaGlwIG9uIHRoZSBjaGFpbiksIG9yIG51bGwuICovXG4gIGNhbmFyeVJlbGVhc2U6IHN0cmluZyB8IG51bGw7XG4gIHBsYXRmb3JtRGVmYXVsdDogc3RyaW5nIHwgbnVsbDtcbn1cblxuLyoqIHtAbGluayByZWFkT3JnVG9vbGNoYWluT3ZlcnZpZXd9IHdpdGggaW5qZWN0ZWQgcmVhZHMgYW5kIGhpZXJhcmNoeSAodGVzdHMpLiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlYWRPcmdUb29sY2hhaW5PdmVydmlld1dpdGgoZGVwczogTWFuYWdlZFRvb2xjaGFpbkRlcHMsIG9yZ0lkOiBzdHJpbmcpOiBQcm9taXNlPE9yZ1Rvb2xjaGFpbk92ZXJ2aWV3PiB7XG4gIGNvbnN0IHNlbGYgPSBvcmdJZC50b0xvd2VyQ2FzZSgpO1xuICBjb25zdCB3YWxrID0gYXdhaXQgZGVwcy5yZWFkKChkYikgPT4gYW55T3JnU2V0dGluZ3MoZGIpKTtcbiAgY29uc3QgY2hhaW4gPSB3YWxrID8gYXdhaXQgdG9vbGNoYWluT3JnQ2hhaW4oc2VsZiwgZGVwcy5nZXRQYXJlbnQpIDogW3NlbGZdO1xuICByZXR1cm4gZGVwcy5yZWFkKGFzeW5jIChkYikgPT4ge1xuICAgIGNvbnN0IHJvd3MgPSBhd2FpdCBkYi5zZWxlY3QoKS5mcm9tKHNjaGVtYS5vcmdUb29sY2hhaW5EZWZhdWx0KVxuICAgICAgLndoZXJlKGluQXJyYXkoc3FsPHN0cmluZz5gbG93ZXIoJHtzY2hlbWEub3JnVG9vbGNoYWluRGVmYXVsdC5vcmdJZH0pYCwgY2hhaW4pKSBhcyBPcmdUb29sY2hhaW5EZWZhdWx0W107XG4gICAgY29uc3QgZGVwdGhPZiA9IChyOiBPcmdUb29sY2hhaW5EZWZhdWx0KSA9PiBjaGFpbi5pbmRleE9mKHIub3JnSWQudG9Mb3dlckNhc2UoKSk7XG4gICAgY29uc3Qgb3duRGVmYXVsdCA9IHJvd3MuZmluZCgocikgPT4gZGVwdGhPZihyKSA9PT0gMCkgPz8gbnVsbDtcbiAgICBjb25zdCBuZWFyZXN0ID0gcm93cy5maWx0ZXIoKHIpID0+IGRlcHRoT2YocikgPj0gMCkuc29ydCgoYSwgYikgPT4gZGVwdGhPZihhKSAtIGRlcHRoT2YoYikpWzBdID8/IG51bGw7XG4gICAgY29uc3QgW2NhbmFyeSwgcGxhdGZvcm1EZWZhdWx0LCByZXNvbHV0aW9uXSA9IGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgIG5lYXJlc3RPbkNoYWluKGRiLCBzY2hlbWEudG9vbGNoYWluUm9sbG91dCwgY2hhaW4pLFxuICAgICAgY3VycmVudFBsYXRmb3JtRGVmYXVsdChkYiksXG4gICAgICByZXNvbHZlT25DaGFpbihkYiwgY2hhaW4pLFxuICAgIF0pO1xuICAgIHJldHVybiB7XG4gICAgICBjaGFpbixcbiAgICAgIGVmZmVjdGl2ZTogeyByZWxlYXNlVmVyc2lvbjogcmVzb2x1dGlvbi5yZWxlYXNlVmVyc2lvbiwgcmVzb2x2ZWRWaWE6IHJlc29sdXRpb24ucmVzb2x2ZWRWaWEsIHdhcm5pbmdzOiByZXNvbHV0aW9uLndhcm5pbmdzIH0sXG4gICAgICBvd25EZWZhdWx0LFxuICAgICAgaW5oZXJpdGVkRnJvbTogIW93bkRlZmF1bHQgJiYgbmVhcmVzdCA/IHsgb3JnSWQ6IG5lYXJlc3Qub3JnSWQsIHJlbGVhc2VWZXJzaW9uOiBuZWFyZXN0LnJlbGVhc2VWZXJzaW9uIH0gOiBudWxsLFxuICAgICAgY2FuYXJ5UmVsZWFzZTogY2FuYXJ5Py5yZWxlYXNlVmVyc2lvbiA/PyBudWxsLFxuICAgICAgcGxhdGZvcm1EZWZhdWx0LFxuICAgIH07XG4gIH0pO1xufVxuXG4vKipcbiAqIFRoZSBjYWxsZXIgb3JnJ3MgdG9vbGNoYWluIG92ZXJ2aWV3IChlbGV2YXRlZCByZWFkcywgdGhlIHNhbWUgY2hhaW4gd2FsayBhbmRcbiAqIHByZWNlZGVuY2UgYXMge0BsaW5rIHJlc29sdmVNYW5hZ2VkVG9vbGNoYWlufSkuIFRocm93cyB3aGF0IHRoZSByZXNvbHZlclxuICogdGhyb3dzIOKAlCBUT09MQ0hBSU5fTk9fREVGQVVMVCAoNDA5KSB3aGVuIG5vdGhpbmcgcmVzb2x2ZXMgYXQgYWxsLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVhZE9yZ1Rvb2xjaGFpbk92ZXJ2aWV3KG9yZ0lkOiBzdHJpbmcpOiBQcm9taXNlPE9yZ1Rvb2xjaGFpbk92ZXJ2aWV3PiB7XG4gIHJldHVybiByZWFkT3JnVG9vbGNoYWluT3ZlcnZpZXdXaXRoKGRlZmF1bHREZXBzLCBvcmdJZCk7XG59XG5cbi8qKiBPbmUgcmVsZWFzZSB0aGUgY2FsbGVyIG1heSBwaW4gb3Igc2V0IChEMTUpLCB3aXRoIHdoYXQgdGhlIHNlbGVjdG9ycyBzaG93LiAqL1xuZXhwb3J0IGludGVyZmFjZSBFbGlnaWJsZVRvb2xjaGFpblJlbGVhc2Uge1xuICByZWxlYXNlVmVyc2lvbjogc3RyaW5nO1xuICByZWxlYXNlOiBUb29sY2hhaW5SZWxlYXNlO1xuICBib290c3RyYXA6IFBsdWdpbjtcbiAgc3ludGg6IFBsdWdpbjtcbiAgLyoqIFRIRSBwbGF0Zm9ybSBkZWZhdWx0IG5vdy4gKi9cbiAgaXNQbGF0Zm9ybURlZmF1bHQ6IGJvb2xlYW47XG4gIC8qKiBUaGUgY2FsbGVyJ3MgY2FuYXJ5IHJlbGVhc2UgKG5lYXJlc3QgbWVtYmVyc2hpcCkuICovXG4gIGlzQ2FuYXJ5OiBib29sZWFuO1xufVxuXG4vKioge0BsaW5rIGxpc3RFbGlnaWJsZVJlbGVhc2VzfSB3aXRoIGluamVjdGVkIHJlYWRzIGFuZCBoaWVyYXJjaHkgKHRlc3RzKS4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBsaXN0RWxpZ2libGVSZWxlYXNlc1dpdGgoZGVwczogTWFuYWdlZFRvb2xjaGFpbkRlcHMsIG9yZ0lkOiBzdHJpbmcpOiBQcm9taXNlPHsgcGxhdGZvcm1EZWZhdWx0OiBzdHJpbmcgfCBudWxsOyByZWxlYXNlczogRWxpZ2libGVUb29sY2hhaW5SZWxlYXNlW10gfT4ge1xuICBjb25zdCBzZWxmID0gb3JnSWQudG9Mb3dlckNhc2UoKTtcbiAgY29uc3Qgd2FsayA9IGF3YWl0IGRlcHMucmVhZCgoZGIpID0+IGFueU9yZ1NldHRpbmdzKGRiKSk7XG4gIGNvbnN0IGNoYWluID0gd2FsayA/IGF3YWl0IHRvb2xjaGFpbk9yZ0NoYWluKHNlbGYsIGRlcHMuZ2V0UGFyZW50KSA6IFtzZWxmXTtcbiAgcmV0dXJuIGRlcHMucmVhZChhc3luYyAoZGIpID0+IHtcbiAgICBjb25zdCBbcmVsZWFzZXMsIHJvd3MsIGhpc3RvcnksIHBsYXRmb3JtRGVmYXVsdCwgY2FuYXJ5XSA9IGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgIGRiLnNlbGVjdCgpLmZyb20oc2NoZW1hLnRvb2xjaGFpblJlbGVhc2UpIGFzIFByb21pc2U8VG9vbGNoYWluUmVsZWFzZVtdPixcbiAgICAgIGRiLnNlbGVjdCgpLmZyb20oc2NoZW1hLnBsdWdpbikud2hlcmUoYW5kKFxuICAgICAgICBzcWxgbG93ZXIoJHtzY2hlbWEucGx1Z2luLm9yZ0lkfSkgPSAke1NZU1RFTV9PUkdfSUR9YCxcbiAgICAgICAgaW5BcnJheShzY2hlbWEucGx1Z2luLm5hbWUsIFsuLi5NQU5BR0VEX1RPT0xDSEFJTl9QTFVHSU5TXSksXG4gICAgICAgIGlzTnVsbChzY2hlbWEucGx1Z2luLmRlbGV0ZWRBdCksXG4gICAgICApKSBhcyBQcm9taXNlPFBsdWdpbltdPixcbiAgICAgIGRiLnNlbGVjdCh7IHJlbGVhc2VWZXJzaW9uOiBzY2hlbWEudG9vbGNoYWluRGVmYXVsdEhpc3RvcnkucmVsZWFzZVZlcnNpb24gfSkuZnJvbShzY2hlbWEudG9vbGNoYWluRGVmYXVsdEhpc3RvcnkpIGFzIFByb21pc2U8QXJyYXk8eyByZWxlYXNlVmVyc2lvbjogc3RyaW5nIH0+PixcbiAgICAgIGN1cnJlbnRQbGF0Zm9ybURlZmF1bHQoZGIpLFxuICAgICAgbmVhcmVzdE9uQ2hhaW4oZGIsIHNjaGVtYS50b29sY2hhaW5Sb2xsb3V0LCBjaGFpbiksXG4gICAgXSk7XG4gICAgY29uc3QgcHJvbW90ZWQgPSBuZXcgU2V0KGhpc3RvcnkubWFwKChoKSA9PiBoLnJlbGVhc2VWZXJzaW9uKSk7XG4gICAgaWYgKHBsYXRmb3JtRGVmYXVsdCkgcHJvbW90ZWQuYWRkKHBsYXRmb3JtRGVmYXVsdCk7XG4gICAgY29uc3Qgb3V0OiBFbGlnaWJsZVRvb2xjaGFpblJlbGVhc2VbXSA9IFtdO1xuICAgIGZvciAoY29uc3QgcmVsZWFzZSBvZiByZWxlYXNlcykge1xuICAgICAgY29uc3QgdiA9IHJlbGVhc2UucmVsZWFzZVZlcnNpb247XG4gICAgICBjb25zdCBoYWx2ZXM6IFJlbGVhc2VIYWx2ZXMgPSB7XG4gICAgICAgIHJlbGVhc2VWZXJzaW9uOiB2LFxuICAgICAgICByZWxlYXNlLFxuICAgICAgICBib290c3RyYXA6IHJvd3MuZmluZCgocCkgPT4gcC5uYW1lID09PSBCT09UU1RSQVAgJiYgcC52ZXJzaW9uID09PSB2KSA/PyBudWxsLFxuICAgICAgICBzeW50aDogcm93cy5maW5kKChwKSA9PiBwLm5hbWUgPT09IFNZTlRIICYmIHAudmVyc2lvbiA9PT0gdikgPz8gbnVsbCxcbiAgICAgIH07XG4gICAgICBpZiAoIXJlbGVhc2VFeGlzdHMoaGFsdmVzKSB8fCByZWxlYXNlTGlmZWN5Y2xlUHJvYmxlbXMoaGFsdmVzKS5sZW5ndGggPiAwKSBjb250aW51ZTtcbiAgICAgIGNvbnN0IGlzQ2FuYXJ5ID0gY2FuYXJ5Py5yZWxlYXNlVmVyc2lvbiA9PT0gdjtcbiAgICAgIGlmICghcHJvbW90ZWQuaGFzKHYpICYmICFpc0NhbmFyeSkgY29udGludWU7XG4gICAgICBvdXQucHVzaCh7IHJlbGVhc2VWZXJzaW9uOiB2LCByZWxlYXNlLCBib290c3RyYXA6IGhhbHZlcy5ib290c3RyYXAsIHN5bnRoOiBoYWx2ZXMuc3ludGgsIGlzUGxhdGZvcm1EZWZhdWx0OiBwbGF0Zm9ybURlZmF1bHQgPT09IHYsIGlzQ2FuYXJ5IH0pO1xuICAgIH1cbiAgICBvdXQuc29ydCgoYSwgYikgPT4gY29tcGFyZVNlbXZlcihiLnJlbGVhc2VWZXJzaW9uLCBhLnJlbGVhc2VWZXJzaW9uKSk7XG4gICAgcmV0dXJuIHsgcGxhdGZvcm1EZWZhdWx0LCByZWxlYXNlczogb3V0IH07XG4gIH0pO1xufVxuXG4vKipcbiAqIEV2ZXJ5IHJlbGVhc2UgYG9yZ0lkYCBtYXkgU0VUIGFzIGEgcGlwZWxpbmUgcGluIG9yIGl0cyBvcmcgZGVmYXVsdCAoRDE1LCB0aGVcbiAqIHNhbWUgcnVsZSBhcyB7QGxpbmsgaXNFbGlnaWJsZVJlbGVhc2V9KSwgbmV3ZXN0IGZpcnN0LiBOZXZlciBhbm90aGVyIG9yZydzXG4gKiBkYXRhOiBhIGNhbmFyeSBhcHBlYXJzIG9ubHkgd2hlbiBpdCBpcyB0aGUgY2FsbGVyJ3Mgb3duIChuZWFyZXN0KSBtZW1iZXJzaGlwLlxuICovXG5leHBvcnQgZnVuY3Rpb24gbGlzdEVsaWdpYmxlUmVsZWFzZXMob3JnSWQ6IHN0cmluZyk6IFByb21pc2U8eyBwbGF0Zm9ybURlZmF1bHQ6IHN0cmluZyB8IG51bGw7IHJlbGVhc2VzOiBFbGlnaWJsZVRvb2xjaGFpblJlbGVhc2VbXSB9PiB7XG4gIHJldHVybiBsaXN0RWxpZ2libGVSZWxlYXNlc1dpdGgoZGVmYXVsdERlcHMsIG9yZ0lkKTtcbn1cblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIENhbGxlciBoZWxwZXJzXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4vKiogVGhlIHJlc29sdmVyJ3MgZXJyb3IgYXMgdGhlIHJlZnVzYWwgc2hhcGUgc3RlcCByZXNvbHV0aW9uIHJlcG9ydHMgKGNvbnRyYWN0IGNoZWNrLCBkZWNsYXJlZCBzaWRlLCBmYWN0cykuICovXG5leHBvcnQgZnVuY3Rpb24gbWFuYWdlZFRvb2xjaGFpblJlZnVzYWwoZXJyOiBNYW5hZ2VkVG9vbGNoYWluRXJyb3IpOiBSZXNvbHV0aW9uUmVmdXNhbCB7XG4gIHN3aXRjaCAoZXJyLmNvZGUpIHtcbiAgICBjYXNlIEVycm9yQ29kZS5OT1RfRk9VTkQ6XG4gICAgICByZXR1cm4geyBjb2RlOiAnTk9UX0ZPVU5EJywgcmVhc29uOiAndG9vbGNoYWluX3JlbGVhc2Vfbm90X2ZvdW5kJywgbWVzc2FnZTogZXJyLm1lc3NhZ2UsIC4uLihlcnIuZGV0YWlscyA/IHsgZGV0YWlsczogZXJyLmRldGFpbHMgfSA6IHt9KSB9O1xuICAgIGNhc2UgRXJyb3JDb2RlLlZBTElEQVRJT05fRVJST1I6XG4gICAgICByZXR1cm4geyBjb2RlOiAnTk9UX0ZPVU5EJywgcmVhc29uOiAndG9vbGNoYWluX3JlbGVhc2VfaW52YWxpZCcsIG1lc3NhZ2U6IGVyci5tZXNzYWdlLCAuLi4oZXJyLmRldGFpbHMgPyB7IGRldGFpbHM6IGVyci5kZXRhaWxzIH0gOiB7fSkgfTtcbiAgICBjYXNlIEVycm9yQ29kZS5UT09MQ0hBSU5fTk9fREVGQVVMVDpcbiAgICAgIHJldHVybiB7IGNvZGU6ICdQTFVHSU5fVU5BVkFJTEFCTEUnLCByZWFzb246ICd0b29sY2hhaW5fbm9fZGVmYXVsdCcsIG1lc3NhZ2U6IGVyci5tZXNzYWdlIH07XG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiB7IGNvZGU6ICdQTFVHSU5fVU5BVkFJTEFCTEUnLCByZWFzb246ICd0b29sY2hhaW5fdW5yZXNvbHZlZCcsIG1lc3NhZ2U6IGVyci5tZXNzYWdlLCAuLi4oZXJyLmRldGFpbHMgPyB7IGRldGFpbHM6IGVyci5kZXRhaWxzIH0gOiB7fSkgfTtcbiAgfVxufVxuXG4vKipcbiAqIFJlc29sdmUgT05FIG1hbmFnZWQgaGFsZiBmb3IgYSBzdGVwOiB0aGUgcGx1Z2luIHJvdyBwbHVzIHRoZSByZXNvbHV0aW9uLCBvclxuICogdGhlIHJlZnVzYWwuIEFueSBub24tcmVzb2x2ZXIgZXJyb3IgKGEgZGF0YWJhc2Ugb3IgaGllcmFyY2h5IGZhaWx1cmUpXG4gKiBwcm9wYWdhdGVzLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVzb2x2ZU1hbmFnZWRUb29sY2hhaW5IYWxmKFxuICBjYWxsZXI6IE1hbmFnZWRUb29sY2hhaW5DYWxsZXIsXG4gIG5hbWU6IE1hbmFnZWRUb29sY2hhaW5QbHVnaW4sXG4gIG9wdHM6IHsgcmVsZWFzZVBpbj86IHN0cmluZyB9ID0ge30sXG4pOiBQcm9taXNlPHsgcGx1Z2luOiBQbHVnaW47IHJlc29sdXRpb246IE1hbmFnZWRUb29sY2hhaW5SZXNvbHV0aW9uIH0gfCB7IHJlZnVzYWw6IFJlc29sdXRpb25SZWZ1c2FsOyBlcnJvcjogTWFuYWdlZFRvb2xjaGFpbkVycm9yIH0+IHtcbiAgdHJ5IHtcbiAgICBjb25zdCByZXNvbHV0aW9uID0gYXdhaXQgcmVzb2x2ZU1hbmFnZWRUb29sY2hhaW4oY2FsbGVyLCBvcHRzKTtcbiAgICByZXR1cm4geyBwbHVnaW46IG5hbWUgPT09IEJPT1RTVFJBUCA/IHJlc29sdXRpb24uYm9vdHN0cmFwIDogcmVzb2x1dGlvbi5zeW50aCwgcmVzb2x1dGlvbiB9O1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICBpZiAoZXJyIGluc3RhbmNlb2YgTWFuYWdlZFRvb2xjaGFpbkVycm9yKSByZXR1cm4geyByZWZ1c2FsOiBtYW5hZ2VkVG9vbGNoYWluUmVmdXNhbChlcnIpLCBlcnJvcjogZXJyIH07XG4gICAgdGhyb3cgZXJyO1xuICB9XG59XG4iXX0=
|