@pipeline-builder/pipeline-data 4.3.11 → 4.3.13
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 +195 -0
- package/lib/api/managed-toolchain.js +443 -0
- package/lib/api/public-directory.d.ts +4 -15
- package/lib/api/public-directory.js +1 -31
- package/lib/api/reporting/ingest.js +52 -12
- package/lib/api/reporting/stakeholder/compose.d.ts +3 -2
- package/lib/api/reporting/stakeholder/compose.js +1 -1
- package/lib/api/reporting/stakeholder/period.d.ts +5 -4
- package/lib/api/reporting/stakeholder/period.js +1 -1
- package/lib/api/reporting/stakeholder/sections.d.ts +4 -4
- package/lib/api/reporting/stakeholder/sections.js +1 -1
- package/lib/api/reporting/stakeholder/store.d.ts +3 -2
- package/lib/api/reporting/stakeholder/store.js +1 -1
- package/lib/api/reporting/toolchain-runs.d.ts +156 -0
- package/lib/api/reporting/toolchain-runs.js +267 -0
- package/lib/api/reporting/types.d.ts +20 -3
- package/lib/api/reporting/types.js +1 -1
- package/lib/api/support-cases.d.ts +50 -24
- package/lib/api/support-cases.js +96 -37
- package/lib/api/version-references.d.ts +2 -24
- package/lib/api/version-references.js +46 -7
- package/lib/core/query-filters.d.ts +6 -6
- package/lib/core/query-filters.js +1 -1
- package/lib/database/drizzle-schema.d.ts +698 -41
- 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/alert.js +4 -4
- package/lib/database/schema/compliance.d.ts +29 -40
- package/lib/database/schema/compliance.js +10 -14
- package/lib/database/schema/ecosystem.d.ts +72 -0
- package/lib/database/schema/ecosystem.js +18 -2
- package/lib/database/schema/pipeline.d.ts +19 -0
- package/lib/database/schema/pipeline.js +17 -1
- package/lib/database/schema/reporting-stakeholder.d.ts +2 -1
- package/lib/database/schema/reporting-stakeholder.js +2 -27
- package/lib/database/schema/toolchain.d.ts +643 -0
- package/lib/database/schema/toolchain.js +102 -0
- package/lib/index.d.ts +4 -2
- package/lib/index.js +7 -3
- package/lib/testing/exports.json +39 -2
- package/package.json +2 -2
|
@@ -0,0 +1,443 @@
|
|
|
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, 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: BOOTSTRAP, synth: SYNTH } = MANAGED_TOOLCHAIN;
|
|
44
|
+
/** The release row and both SYSTEM-ORG halves of `releaseVersion` (deleted rows excluded). */
|
|
45
|
+
export async function loadReleaseHalves(db, releaseVersion) {
|
|
46
|
+
const [releases, rows] = await Promise.all([
|
|
47
|
+
db.select().from(schema.toolchainRelease).where(eq(schema.toolchainRelease.releaseVersion, releaseVersion)),
|
|
48
|
+
db.select().from(schema.plugin).where(and(eq(schema.plugin.orgId, SYSTEM_ORG_ID), inArray(schema.plugin.name, [...MANAGED_TOOLCHAIN_PLUGINS]), eq(schema.plugin.version, releaseVersion), isNull(schema.plugin.deletedAt))),
|
|
49
|
+
]);
|
|
50
|
+
const plugins = rows;
|
|
51
|
+
return {
|
|
52
|
+
releaseVersion,
|
|
53
|
+
release: releases[0] ?? null,
|
|
54
|
+
bootstrap: plugins.find((p) => p.name === BOOTSTRAP) ?? null,
|
|
55
|
+
synth: plugins.find((p) => p.name === SYNTH) ?? null,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/** The NEAREST row of `table` (keyed by `org_id`) on `chain` (own org first). */
|
|
59
|
+
async function nearestOnChain(db, table, chain) {
|
|
60
|
+
if (chain.length === 0)
|
|
61
|
+
return null;
|
|
62
|
+
const rows = await db.select({ orgId: table.orgId, releaseVersion: table.releaseVersion })
|
|
63
|
+
.from(table)
|
|
64
|
+
.where(inArray(sql `lower(${table.orgId})`, [...chain]));
|
|
65
|
+
let best = null;
|
|
66
|
+
for (const r of rows) {
|
|
67
|
+
const depth = chain.indexOf(r.orgId.toLowerCase());
|
|
68
|
+
if (depth >= 0 && (!best || depth < best.depth))
|
|
69
|
+
best = { depth, releaseVersion: r.releaseVersion };
|
|
70
|
+
}
|
|
71
|
+
return best;
|
|
72
|
+
}
|
|
73
|
+
async function currentPlatformDefault(db) {
|
|
74
|
+
const rows = await db.select({ releaseVersion: schema.toolchainPlatformDefault.releaseVersion })
|
|
75
|
+
.from(schema.toolchainPlatformDefault).limit(1);
|
|
76
|
+
return rows[0]?.releaseVersion ?? null;
|
|
77
|
+
}
|
|
78
|
+
/** Whether `releaseVersion` has ever been (or is) the platform default. */
|
|
79
|
+
async function wasPlatformDefault(db, releaseVersion) {
|
|
80
|
+
const [history, current] = await Promise.all([
|
|
81
|
+
db.select({ id: schema.toolchainDefaultHistory.id }).from(schema.toolchainDefaultHistory)
|
|
82
|
+
.where(eq(schema.toolchainDefaultHistory.releaseVersion, releaseVersion)).limit(1),
|
|
83
|
+
currentPlatformDefault(db),
|
|
84
|
+
]);
|
|
85
|
+
return history.length > 0 || current === releaseVersion;
|
|
86
|
+
}
|
|
87
|
+
/** Whether ANY org has an org default or a canary membership (else no walk is needed). */
|
|
88
|
+
async function anyOrgSettings(db) {
|
|
89
|
+
const [defaults, rollout] = await Promise.all([
|
|
90
|
+
db.select({ orgId: schema.orgToolchainDefault.orgId }).from(schema.orgToolchainDefault).limit(1),
|
|
91
|
+
db.select({ orgId: schema.toolchainRollout.orgId }).from(schema.toolchainRollout).limit(1),
|
|
92
|
+
]);
|
|
93
|
+
return defaults.length > 0 || rollout.length > 0;
|
|
94
|
+
}
|
|
95
|
+
// -----------------------------------------------------------------------------
|
|
96
|
+
// The org chain (caller → … → root)
|
|
97
|
+
// -----------------------------------------------------------------------------
|
|
98
|
+
/**
|
|
99
|
+
* The caller's chain, own org first, lowercased: `[self, parent, …, root]`.
|
|
100
|
+
* The same parent walk as `org-reachability.ts` (platform's
|
|
101
|
+
* `GET /organization/:id/parent`), cycle-safe and capped at `MAX_ORG_DEPTH` like
|
|
102
|
+
* `reporting-retention.ts` — but FAIL-CLOSED: a lookup failure, a cycle or an
|
|
103
|
+
* over-deep chain throws rather than resolving the wrong org's toolchain.
|
|
104
|
+
*/
|
|
105
|
+
export async function toolchainOrgChain(orgId, getParent) {
|
|
106
|
+
const self = orgId.toLowerCase();
|
|
107
|
+
const chain = [self];
|
|
108
|
+
if (isSystemOrgId(self))
|
|
109
|
+
return chain;
|
|
110
|
+
let current = self;
|
|
111
|
+
for (let depth = 0; depth < MAX_ORG_DEPTH; depth++) {
|
|
112
|
+
const parent = toOrgIdString(await getParent(current))?.toLowerCase();
|
|
113
|
+
if (!parent || parent === current)
|
|
114
|
+
return chain;
|
|
115
|
+
if (chain.includes(parent)) {
|
|
116
|
+
throw new ManagedToolchainError(ErrorCode.INTERNAL_ERROR, 'The organization hierarchy has a cycle; the toolchain release cannot be resolved.', { orgId: self });
|
|
117
|
+
}
|
|
118
|
+
chain.push(parent);
|
|
119
|
+
current = parent;
|
|
120
|
+
}
|
|
121
|
+
throw new ManagedToolchainError(ErrorCode.INTERNAL_ERROR, `The organization hierarchy is deeper than ${MAX_ORG_DEPTH}; the toolchain release cannot be resolved.`, { orgId: self });
|
|
122
|
+
}
|
|
123
|
+
/** Parent lookups are cached briefly: one synth makes several lookups for the same org. */
|
|
124
|
+
const PARENT_CACHE_TTL_MS = 30_000;
|
|
125
|
+
const PARENT_CACHE_MAX = 5_000;
|
|
126
|
+
const parentCache = new Map();
|
|
127
|
+
async function platformParent(orgId) {
|
|
128
|
+
const hit = parentCache.get(orgId);
|
|
129
|
+
if (hit && Date.now() - hit.at < PARENT_CACHE_TTL_MS)
|
|
130
|
+
return hit.parent;
|
|
131
|
+
// A system-scoped service token; a non-2xx THROWS (fail-closed, see toolchainOrgChain).
|
|
132
|
+
const parent = await fetchParentOrgId(orgId, { authOrgId: SYSTEM_ORG_ID, throwOnHttpError: true, timeout: 5_000 });
|
|
133
|
+
if (parentCache.size >= PARENT_CACHE_MAX)
|
|
134
|
+
parentCache.clear();
|
|
135
|
+
parentCache.set(orgId, { parent, at: Date.now() });
|
|
136
|
+
return parent;
|
|
137
|
+
}
|
|
138
|
+
const productionDeps = {
|
|
139
|
+
read: (fn) => runWithTenantContext({ isSuperAdmin: true }, () => withTenantTx((tx) => fn(tx))),
|
|
140
|
+
getParent: platformParent,
|
|
141
|
+
};
|
|
142
|
+
let defaultDeps = productionDeps;
|
|
143
|
+
/** Test hook: replace the resolver's reads and hierarchy (null restores production). */
|
|
144
|
+
export function setManagedToolchainDepsForTests(deps) {
|
|
145
|
+
defaultDeps = deps ?? productionDeps;
|
|
146
|
+
}
|
|
147
|
+
const isYanked = (p) => p.yankedAt !== null || p.lifecycle === 'yanked';
|
|
148
|
+
const isDeprecated = (p) => p.deprecatedAt !== null || p.lifecycle === 'deprecated';
|
|
149
|
+
/** Whether both halves are present (the release EXISTS). */
|
|
150
|
+
export function releaseExists(h) {
|
|
151
|
+
return h.release !== null && h.bootstrap !== null && h.synth !== null;
|
|
152
|
+
}
|
|
153
|
+
export function releaseLifecycleProblems(h) {
|
|
154
|
+
if (!releaseExists(h))
|
|
155
|
+
return ['missing'];
|
|
156
|
+
const halves = [h.bootstrap, h.synth];
|
|
157
|
+
const out = [];
|
|
158
|
+
if (halves.some((p) => !p.isActive))
|
|
159
|
+
out.push('inactive');
|
|
160
|
+
if (halves.some(isYanked))
|
|
161
|
+
out.push('yanked');
|
|
162
|
+
if (halves.some(isDeprecated))
|
|
163
|
+
out.push('deprecated');
|
|
164
|
+
return out;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* The bootstrap half's toolchain metadata (`pipelineManager`, `awsCdk`, …), or
|
|
168
|
+
* null when it carries no complete, valid one. Upload persists it on the row's
|
|
169
|
+
* `metadata` as flat `toolchain.<field>` keys (api-core `toolchainMetadata`).
|
|
170
|
+
*/
|
|
171
|
+
export function bootstrapToolchainOf(row) {
|
|
172
|
+
return row ? toolchainFromMetadata(row.metadata) : null;
|
|
173
|
+
}
|
|
174
|
+
/** `PLUGIN_VULN_MAX_FINDINGS` (default 0): the fixable-Critical floor a release must be within. */
|
|
175
|
+
function vulnFloor() {
|
|
176
|
+
return envInt('PLUGIN_VULN_MAX_FINDINGS', 0, { min: 0 });
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* The §8 candidate guards (pair, scan, metadata) a release fails, as their
|
|
180
|
+
* error codes — empty when it passes. The canary gate and concurrency are the
|
|
181
|
+
* platform-default service's; a canary is served only while this is empty.
|
|
182
|
+
*/
|
|
183
|
+
export function toolchainCandidateProblems(h) {
|
|
184
|
+
if (!releaseExists(h) || releaseLifecycleProblems(h).length > 0)
|
|
185
|
+
return [ErrorCode.TOOLCHAIN_GUARD_PAIR_INCOMPLETE];
|
|
186
|
+
const out = [];
|
|
187
|
+
const halves = [h.bootstrap, h.synth];
|
|
188
|
+
if (halves.some((p) => !p.scannedAt))
|
|
189
|
+
out.push(ErrorCode.TOOLCHAIN_GUARD_UNSCANNED);
|
|
190
|
+
else if (halves.some((p) => (p.vulnCriticalFixable ?? 0) > vulnFloor()))
|
|
191
|
+
out.push(ErrorCode.TOOLCHAIN_GUARD_VULN_FLOOR);
|
|
192
|
+
if (!bootstrapToolchainOf(h.bootstrap))
|
|
193
|
+
out.push(ErrorCode.TOOLCHAIN_GUARD_METADATA);
|
|
194
|
+
return out;
|
|
195
|
+
}
|
|
196
|
+
/** Warnings for a release that EXISTS but is no longer (or never was) eligible. */
|
|
197
|
+
function standingWarnings(h, promoted, via) {
|
|
198
|
+
const ref = `Toolchain release ${h.releaseVersion}`;
|
|
199
|
+
const out = [];
|
|
200
|
+
const yanked = [h.bootstrap, h.synth].find(isYanked);
|
|
201
|
+
if (yanked) {
|
|
202
|
+
out.push({
|
|
203
|
+
code: 'TOOLCHAIN_RELEASE_YANKED',
|
|
204
|
+
severity: 'warning',
|
|
205
|
+
message: `${ref} is yanked${yanked.yankReason ? `: ${yanked.yankReason}` : ''}. It resolves only because it is selected exactly; move to a supported release.`,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
const deprecated = [h.bootstrap, h.synth].find(isDeprecated);
|
|
209
|
+
if (deprecated) {
|
|
210
|
+
out.push({
|
|
211
|
+
code: 'TOOLCHAIN_RELEASE_DEPRECATED',
|
|
212
|
+
severity: 'warning',
|
|
213
|
+
message: `${ref} is deprecated${deprecated.deprecationMessage ? `: ${deprecated.deprecationMessage}` : ''}.`,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
if ([h.bootstrap, h.synth].some((p) => !p.isActive)) {
|
|
217
|
+
out.push({ code: 'TOOLCHAIN_RELEASE_INACTIVE', severity: 'warning', message: `${ref} is inactive; move to a supported release.` });
|
|
218
|
+
}
|
|
219
|
+
if (!promoted && (via === 'pin' || via === 'org-default')) {
|
|
220
|
+
out.push({
|
|
221
|
+
code: 'TOOLCHAIN_RELEASE_NOT_PROMOTED',
|
|
222
|
+
severity: 'warning',
|
|
223
|
+
message: `${ref} was never the platform default and is not in a canary for your organization; it resolves only because it is selected exactly.`,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
return out;
|
|
227
|
+
}
|
|
228
|
+
// -----------------------------------------------------------------------------
|
|
229
|
+
// Resolution
|
|
230
|
+
// -----------------------------------------------------------------------------
|
|
231
|
+
function pairOf(h, via) {
|
|
232
|
+
if (!releaseExists(h)) {
|
|
233
|
+
// A default (platform or org) whose halves are gone is a broken invariant
|
|
234
|
+
// (in-use protection counts defaults): refused, never served.
|
|
235
|
+
throw new ManagedToolchainError(ErrorCode.TOOLCHAIN_PAIR_MISMATCH, `Toolchain release ${h.releaseVersion} (${via}) is incomplete; it is never served.`, {
|
|
236
|
+
releaseVersion: h.releaseVersion,
|
|
237
|
+
missing: [...(h.bootstrap ? [] : [BOOTSTRAP]), ...(h.synth ? [] : [SYNTH]), ...(h.release ? [] : ['toolchain_release'])],
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
if (h.bootstrap.version !== h.releaseVersion || h.synth.version !== h.releaseVersion) {
|
|
241
|
+
throw new ManagedToolchainError(ErrorCode.TOOLCHAIN_PAIR_MISMATCH, `Toolchain halves disagree (${BOOTSTRAP}@${h.bootstrap.version}, ${SYNTH}@${h.synth.version}); never served.`, {
|
|
242
|
+
releaseVersion: h.releaseVersion,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
return { bootstrap: h.bootstrap, synth: h.synth };
|
|
246
|
+
}
|
|
247
|
+
/** The resolution inside one elevated read, over a known chain. */
|
|
248
|
+
async function resolveOnChain(db, chain, releasePin) {
|
|
249
|
+
const canary = await nearestOnChain(db, schema.toolchainRollout, chain);
|
|
250
|
+
const answer = async (h, via) => {
|
|
251
|
+
const pair = pairOf(h, via);
|
|
252
|
+
const promoted = via === 'pin' || via === 'org-default'
|
|
253
|
+
? (await wasPlatformDefault(db, h.releaseVersion)) || canary?.releaseVersion === h.releaseVersion
|
|
254
|
+
: true;
|
|
255
|
+
return { releaseVersion: h.releaseVersion, resolvedVia: via, ...pair, warnings: standingWarnings({ ...h, ...pair }, promoted, via) };
|
|
256
|
+
};
|
|
257
|
+
if (releasePin !== undefined) {
|
|
258
|
+
if (!isToolchainReleaseVersion(releasePin)) {
|
|
259
|
+
throw new ManagedToolchainError(ErrorCode.VALIDATION_ERROR, 'releasePin must be a release version (MAJOR.MINOR.PATCH, e.g. 1.4.2).', { releasePin });
|
|
260
|
+
}
|
|
261
|
+
const h = await loadReleaseHalves(db, releasePin);
|
|
262
|
+
if (!releaseExists(h)) {
|
|
263
|
+
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.`, {
|
|
264
|
+
reason: 'toolchain_release_not_found', releaseVersion: releasePin,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
return answer(h, 'pin');
|
|
268
|
+
}
|
|
269
|
+
const orgDefault = await nearestOnChain(db, schema.orgToolchainDefault, chain);
|
|
270
|
+
if (orgDefault)
|
|
271
|
+
return answer(await loadReleaseHalves(db, orgDefault.releaseVersion), 'org-default');
|
|
272
|
+
if (canary) {
|
|
273
|
+
const h = await loadReleaseHalves(db, canary.releaseVersion);
|
|
274
|
+
const problems = toolchainCandidateProblems(h);
|
|
275
|
+
if (problems.length === 0)
|
|
276
|
+
return answer(h, 'canary');
|
|
277
|
+
// Members fall through to the platform default. Logged, never returned:
|
|
278
|
+
// the answer must not reveal canary membership.
|
|
279
|
+
logger.warn('Canary toolchain release fails its guards; serving the platform default', { releaseVersion: canary.releaseVersion, problems });
|
|
280
|
+
}
|
|
281
|
+
const platform = await currentPlatformDefault(db);
|
|
282
|
+
if (!platform) {
|
|
283
|
+
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).');
|
|
284
|
+
}
|
|
285
|
+
return answer(await loadReleaseHalves(db, platform), 'default');
|
|
286
|
+
}
|
|
287
|
+
/** {@link resolveManagedToolchain} with injected reads and hierarchy (tests). */
|
|
288
|
+
export async function resolveManagedToolchainWith(deps, caller, opts = {}) {
|
|
289
|
+
const self = caller.orgId.toLowerCase();
|
|
290
|
+
// Walk the hierarchy only when some org has a setting (and outside the transaction).
|
|
291
|
+
const walk = await deps.read((db) => anyOrgSettings(db));
|
|
292
|
+
const chain = walk ? await toolchainOrgChain(self, deps.getParent) : [self];
|
|
293
|
+
return deps.read((db) => resolveOnChain(db, chain, opts.releasePin));
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Resolve the managed toolchain release for `caller` (see the module doc).
|
|
297
|
+
* Throws {@link ManagedToolchainError}: TOOLCHAIN_NO_DEFAULT (409, no platform
|
|
298
|
+
* default), NOT_FOUND (404, a missing / deleted pin), TOOLCHAIN_PAIR_MISMATCH
|
|
299
|
+
* (500), VALIDATION_ERROR (400, a malformed pin).
|
|
300
|
+
*/
|
|
301
|
+
export function resolveManagedToolchain(caller, opts = {}) {
|
|
302
|
+
return resolveManagedToolchainWith(defaultDeps, caller, opts);
|
|
303
|
+
}
|
|
304
|
+
/** {@link isEligibleRelease} with injected reads and hierarchy (tests). */
|
|
305
|
+
export async function isEligibleReleaseWith(deps, orgId, releaseVersion) {
|
|
306
|
+
if (!isToolchainReleaseVersion(releaseVersion))
|
|
307
|
+
return false;
|
|
308
|
+
const self = orgId.toLowerCase();
|
|
309
|
+
const halves = await deps.read((db) => loadReleaseHalves(db, releaseVersion));
|
|
310
|
+
if (releaseLifecycleProblems(halves).length > 0)
|
|
311
|
+
return false;
|
|
312
|
+
if (await deps.read((db) => wasPlatformDefault(db, releaseVersion)))
|
|
313
|
+
return true;
|
|
314
|
+
const walk = await deps.read((db) => anyOrgSettings(db));
|
|
315
|
+
if (!walk)
|
|
316
|
+
return false;
|
|
317
|
+
const chain = await toolchainOrgChain(self, deps.getParent);
|
|
318
|
+
const canary = await deps.read((db) => nearestOnChain(db, schema.toolchainRollout, chain));
|
|
319
|
+
return canary?.releaseVersion === releaseVersion;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* D15: whether `orgId` may SET `releaseVersion` as a pipeline pin or its org
|
|
323
|
+
* default — both halves live (active, unyanked, not deprecated) AND either it
|
|
324
|
+
* has been the platform default or it is the caller's canary (nearest
|
|
325
|
+
* membership on its chain).
|
|
326
|
+
*/
|
|
327
|
+
export function isEligibleRelease(orgId, releaseVersion) {
|
|
328
|
+
return isEligibleReleaseWith(defaultDeps, orgId, releaseVersion);
|
|
329
|
+
}
|
|
330
|
+
/** {@link readOrgToolchainOverview} with injected reads and hierarchy (tests). */
|
|
331
|
+
export async function readOrgToolchainOverviewWith(deps, orgId) {
|
|
332
|
+
const self = orgId.toLowerCase();
|
|
333
|
+
const walk = await deps.read((db) => anyOrgSettings(db));
|
|
334
|
+
const chain = walk ? await toolchainOrgChain(self, deps.getParent) : [self];
|
|
335
|
+
return deps.read(async (db) => {
|
|
336
|
+
const rows = await db.select().from(schema.orgToolchainDefault)
|
|
337
|
+
.where(inArray(sql `lower(${schema.orgToolchainDefault.orgId})`, chain));
|
|
338
|
+
const depthOf = (r) => chain.indexOf(r.orgId.toLowerCase());
|
|
339
|
+
const ownDefault = rows.find((r) => depthOf(r) === 0) ?? null;
|
|
340
|
+
const nearest = rows.filter((r) => depthOf(r) >= 0).sort((a, b) => depthOf(a) - depthOf(b))[0] ?? null;
|
|
341
|
+
const [canary, platformDefault, resolution] = await Promise.all([
|
|
342
|
+
nearestOnChain(db, schema.toolchainRollout, chain),
|
|
343
|
+
currentPlatformDefault(db),
|
|
344
|
+
resolveOnChain(db, chain),
|
|
345
|
+
]);
|
|
346
|
+
return {
|
|
347
|
+
chain,
|
|
348
|
+
effective: { releaseVersion: resolution.releaseVersion, resolvedVia: resolution.resolvedVia, warnings: resolution.warnings },
|
|
349
|
+
ownDefault,
|
|
350
|
+
inheritedFrom: !ownDefault && nearest ? { orgId: nearest.orgId, releaseVersion: nearest.releaseVersion } : null,
|
|
351
|
+
canaryRelease: canary?.releaseVersion ?? null,
|
|
352
|
+
platformDefault,
|
|
353
|
+
};
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* The caller org's toolchain overview (elevated reads, the same chain walk and
|
|
358
|
+
* precedence as {@link resolveManagedToolchain}). Throws what the resolver
|
|
359
|
+
* throws — TOOLCHAIN_NO_DEFAULT (409) when nothing resolves at all.
|
|
360
|
+
*/
|
|
361
|
+
export function readOrgToolchainOverview(orgId) {
|
|
362
|
+
return readOrgToolchainOverviewWith(defaultDeps, orgId);
|
|
363
|
+
}
|
|
364
|
+
/** {@link listEligibleReleases} with injected reads and hierarchy (tests). */
|
|
365
|
+
export async function listEligibleReleasesWith(deps, orgId) {
|
|
366
|
+
const self = orgId.toLowerCase();
|
|
367
|
+
const walk = await deps.read((db) => anyOrgSettings(db));
|
|
368
|
+
const chain = walk ? await toolchainOrgChain(self, deps.getParent) : [self];
|
|
369
|
+
return deps.read(async (db) => {
|
|
370
|
+
const [releases, rows, history, platformDefault, canary] = await Promise.all([
|
|
371
|
+
db.select().from(schema.toolchainRelease),
|
|
372
|
+
db.select().from(schema.plugin).where(and(eq(schema.plugin.orgId, SYSTEM_ORG_ID), inArray(schema.plugin.name, [...MANAGED_TOOLCHAIN_PLUGINS]), isNull(schema.plugin.deletedAt))),
|
|
373
|
+
db.select({ releaseVersion: schema.toolchainDefaultHistory.releaseVersion }).from(schema.toolchainDefaultHistory),
|
|
374
|
+
currentPlatformDefault(db),
|
|
375
|
+
nearestOnChain(db, schema.toolchainRollout, chain),
|
|
376
|
+
]);
|
|
377
|
+
const promoted = new Set(history.map((h) => h.releaseVersion));
|
|
378
|
+
if (platformDefault)
|
|
379
|
+
promoted.add(platformDefault);
|
|
380
|
+
const out = [];
|
|
381
|
+
for (const release of releases) {
|
|
382
|
+
const v = release.releaseVersion;
|
|
383
|
+
const halves = {
|
|
384
|
+
releaseVersion: v,
|
|
385
|
+
release,
|
|
386
|
+
bootstrap: rows.find((p) => p.name === BOOTSTRAP && p.version === v) ?? null,
|
|
387
|
+
synth: rows.find((p) => p.name === SYNTH && p.version === v) ?? null,
|
|
388
|
+
};
|
|
389
|
+
if (!releaseExists(halves) || releaseLifecycleProblems(halves).length > 0)
|
|
390
|
+
continue;
|
|
391
|
+
const isCanary = canary?.releaseVersion === v;
|
|
392
|
+
if (!promoted.has(v) && !isCanary)
|
|
393
|
+
continue;
|
|
394
|
+
out.push({ releaseVersion: v, release, bootstrap: halves.bootstrap, synth: halves.synth, isPlatformDefault: platformDefault === v, isCanary });
|
|
395
|
+
}
|
|
396
|
+
out.sort((a, b) => compareSemver(b.releaseVersion, a.releaseVersion));
|
|
397
|
+
return { platformDefault, releases: out };
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Every release `orgId` may SET as a pipeline pin or its org default (D15, the
|
|
402
|
+
* same rule as {@link isEligibleRelease}), newest first. Never another org's
|
|
403
|
+
* data: a canary appears only when it is the caller's own (nearest) membership.
|
|
404
|
+
*/
|
|
405
|
+
export function listEligibleReleases(orgId) {
|
|
406
|
+
return listEligibleReleasesWith(defaultDeps, orgId);
|
|
407
|
+
}
|
|
408
|
+
// -----------------------------------------------------------------------------
|
|
409
|
+
// Caller helpers
|
|
410
|
+
// -----------------------------------------------------------------------------
|
|
411
|
+
/**
|
|
412
|
+
* Each resolver refusal code's step-resolution refusal (anything else is
|
|
413
|
+
* `toolchain_unresolved`). `details` rides along except for NO_DEFAULT, which
|
|
414
|
+
* carries none worth showing.
|
|
415
|
+
*/
|
|
416
|
+
const REFUSAL_BY_CODE = {
|
|
417
|
+
[ErrorCode.NOT_FOUND]: { code: 'NOT_FOUND', reason: 'toolchain_release_not_found', details: true },
|
|
418
|
+
[ErrorCode.VALIDATION_ERROR]: { code: 'NOT_FOUND', reason: 'toolchain_release_invalid', details: true },
|
|
419
|
+
[ErrorCode.TOOLCHAIN_NO_DEFAULT]: { code: 'PLUGIN_UNAVAILABLE', reason: 'toolchain_no_default', details: false },
|
|
420
|
+
};
|
|
421
|
+
const UNRESOLVED_REFUSAL = { code: 'PLUGIN_UNAVAILABLE', reason: 'toolchain_unresolved', details: true };
|
|
422
|
+
/** The resolver's error as the refusal shape step resolution reports (contract check, declared side, facts). */
|
|
423
|
+
export function managedToolchainRefusal(err) {
|
|
424
|
+
const r = REFUSAL_BY_CODE[err.code] ?? UNRESOLVED_REFUSAL;
|
|
425
|
+
return { code: r.code, reason: r.reason, message: err.message, ...(r.details && err.details ? { details: err.details } : {}) };
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Resolve ONE managed half for a step: the plugin row plus the resolution, or
|
|
429
|
+
* the refusal. Any non-resolver error (a database or hierarchy failure)
|
|
430
|
+
* propagates.
|
|
431
|
+
*/
|
|
432
|
+
export async function resolveManagedToolchainHalf(caller, name, opts = {}) {
|
|
433
|
+
try {
|
|
434
|
+
const resolution = await resolveManagedToolchain(caller, opts);
|
|
435
|
+
return { plugin: name === BOOTSTRAP ? resolution.bootstrap : resolution.synth, resolution };
|
|
436
|
+
}
|
|
437
|
+
catch (err) {
|
|
438
|
+
if (err instanceof ManagedToolchainError)
|
|
439
|
+
return { refusal: managedToolchainRefusal(err), error: err };
|
|
440
|
+
throw err;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFuYWdlZC10b29sY2hhaW4uanMiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hcGkvbWFuYWdlZC10b29sY2hhaW4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0Qzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F1Qkc7QUFFSCxPQUFPLEVBQ0wsUUFBUSxFQUFFLGFBQWEsRUFBRSxZQUFZLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxnQkFBZ0IsRUFBRSxxQkFBcUIsRUFBRSxhQUFhLEVBQ2hILGlCQUFpQixFQUFFLHlCQUF5QixFQUFFLGFBQWEsRUFBRSxhQUFhLEVBQUUsaUNBQWlDLEVBQUUscUJBQXFCLEVBQUUsYUFBYSxHQUVwSixNQUFNLDRCQUE0QixDQUFDO0FBQ3BDLE9BQU8sRUFBRSxHQUFHLEVBQUUsRUFBRSxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRzVELE9BQU8sRUFBRSxNQUFNLEVBQWdFLE1BQU0sK0JBQStCLENBQUM7QUFDckgsT0FBTyxFQUFFLG9CQUFvQixFQUFFLFlBQVksRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBRTVFLE1BQU0sTUFBTSxHQUFHLFlBQVksQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO0FBc0JqRCxrSEFBa0g7QUFDbEgsTUFBTSxPQUFPLHFCQUFzQixTQUFRLFFBQVE7SUFDakQsWUFBWSxJQUFlLEVBQUUsT0FBZSxFQUFFLE9BQWlDO1FBQzdFLEtBQUssQ0FBQyxxQkFBcUIsQ0FBQyxJQUFJLENBQUMsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQzNELElBQUksQ0FBQyxJQUFJLEdBQUcsdUJBQXVCLENBQUM7SUFDdEMsQ0FBQztDQUNGO0FBT0Qsb0VBQW9FO0FBQ3BFLE1BQU0sVUFBVSx5QkFBeUIsQ0FBQyxPQUFnQjtJQUN4RCxPQUFPLE9BQU8sT0FBTyxLQUFLLFFBQVEsSUFBSSxpQ0FB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QixDQUFDLEdBQTBCO0lBQ2hFLE1BQU0sQ0FBQyxHQUFHLGVBQWUsQ0FBQyxHQUFHLENBQUMsSUFBaUIsQ0FBQyxJQUFJLGtCQUFrQixDQUFDO0lBQ3ZFLE9BQU8sRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLElBQUksRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxPQUFPLEVBQUUsR0FBRyxDQUFDLE9BQU8sRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDLE9BQU8sSUFBSSxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLE9BQU8sRUFBRSxHQUFHLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7QUFDakksQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLDJCQUEyQixDQUMvQyxNQUE4QixFQUM5QixJQUE0QixFQUM1QixJQUFJLEdBQTRCLEVBQUU7SUFFbEMsSUFBSSxDQUFDO1FBQ0gsTUFBTSxVQUFVLEdBQUcsTUFBTSx1QkFBdUIsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDL0QsT0FBTyxFQUFFLE1BQU0sRUFBRSxJQUFJLEtBQUssU0FBUyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsS0FBSyxFQUFFLFVBQVUsRUFBRSxDQUFDO0lBQzlGLENBQUM7SUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO1FBQ2IsSUFBSSxHQUFHLFlBQVkscUJBQXFCO1lBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSx1QkFBdUIsQ0FBQyxHQUFHLENBQUMsRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFLENBQUM7UUFDdkcsTUFBTSxHQUFHLENBQUM7SUFDWixDQUFDO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG4vKipcbiAqIFRIRSByZXNvbHZlciBmb3IgdGhlIG1hbmFnZWQgdG9vbGNoYWluIChkb2NzL3BsYW5zL2Jvb3RzdHJhcC1pbWFnZS12ZXJzaW9uaW5nLm1kXG4gKiDCpzIpLiBgcGlwZWxpbmUtYm9vdHN0cmFwQFZgIGFuZCBgY2RrLXN5bnRoQFZgIGFyZSB0d28gU1lTVEVNLU9SRyBwbHVnaW4gcm93c1xuICogdGhhdCBzaGFyZSBvbmUgcmVsZWFzZSB2ZXJzaW9uIGBWYDsgZXZlcnkgcGF0aCB0aGF0IGNhbiByZXNvbHZlIGEgbWFuYWdlZFxuICogbmFtZSBhbnN3ZXJzIGZyb20gaGVyZSBhbmQgbm90aGluZyBlbHNlIG1heTpcbiAqXG4gKiAgIHJlbGVhc2UgcGluIGdpdmVuIOKGkiB0aGF0IHJlbGVhc2UsIGlmIGl0IEVYSVNUUyAoeWFua2VkIC8gZGVwcmVjYXRlZCAvXG4gKiAgICAgICAgICAgICAgICAgICAgICAgbmV2ZXItcHJvbW90ZWQgc3RpbGwgcmVzb2x2ZSwgd2l0aCBhIHdhcm5pbmc7IGRlbGV0ZWQg4oeSIDQwNClcbiAqICAgZWxzZSBvcmcgZGVmYXVsdCAg4oaSIHRoZSBORUFSRVNUIGBvcmdfdG9vbGNoYWluX2RlZmF1bHRgIHdhbGtpbmcgY2FsbGVyIOKGkiDigKYg4oaSIHJvb3RcbiAqICAgZWxzZSBjYW5hcnkgICAgICAg4oaSIHRoZSBORUFSRVNUIGB0b29sY2hhaW5fcm9sbG91dGAgbWVtYmVyc2hpcCwgc2VydmVkIG9ubHlcbiAqICAgICAgICAgICAgICAgICAgICAgICB3aGlsZSBpdCBwYXNzZXMgdGhlIHNjYW4gKyBtZXRhZGF0YSBndWFyZHNcbiAqICAgZWxzZSBwbGF0Zm9ybSAgICAg4oaSIGB0b29sY2hhaW5fcGxhdGZvcm1fZGVmYXVsdGBcbiAqICAgZWxzZSAgICAgICAgICAgICAg4oaSIDQwOSBUT09MQ0hBSU5fTk9fREVGQVVMVCAobmV2ZXIgXCJoaWdoZXN0IHZlcnNpb25cIiwgRDExKVxuICpcbiAqIC0gUmVhZHMgYXJlIEVMRVZBVEVEIChgcnVuV2l0aFRlbmFudENvbnRleHQoeyBpc1N1cGVyQWRtaW46IHRydWUgfSlgLCBhc1xuICogICBgdmVyc2lvblJlZmVyZW5jZXNgIGRvZXMpIGFuZCB0b3VjaCBTWVNURU0tT1JHIHBsdWdpbiByb3dzIG9ubHk6IHRoZSBvd25lclxuICogICByYW5rIG9mIGBwbHVnaW5SZXNvbHV0aW9uT3JkZXJCeWAgaXMgbmV2ZXIgY29uc3VsdGVkLCBzbyBhIHNhbWUtbmFtZWQgcm93IGluXG4gKiAgIGFueSBvdGhlciBvcmcgaXMgbmV2ZXIgYSBjYW5kaWRhdGUuXG4gKiAtIEVsaWdpYmlsaXR5IChEMTUpIGlzIGEgU0VULXRpbWUgcnVsZSAoe0BsaW5rIGlzRWxpZ2libGVSZWxlYXNlfSk7IGF0IHJlc29sdmVcbiAqICAgdGltZSBhIHBpbiAvIG9yZyBkZWZhdWx0IG9ubHkgaGFzIHRvIGV4aXN0LlxuICogLSBCb3RoIGhhbHZlcyBhbHdheXMgY29tZSBmcm9tIE9ORSByZWxlYXNlIChgVE9PTENIQUlOX1BBSVJfTUlTTUFUQ0hgIG90aGVyd2lzZSkuXG4gKiAtIFRoZSBhbnN3ZXIgY2FycmllcyBgcmVzb2x2ZWRWaWFgIGFuZCBub3RoaW5nIGFib3V0IGFueSBvdGhlciBvcmc6IG5vXG4gKiAgIHJvbGxvdXQgbWVtYmVyc2hpcCwgbm8gYW5jZXN0b3IncyBzZXR0aW5ncy5cbiAqL1xuXG5pbXBvcnQge1xuICBBcHBFcnJvciwgY29tcGFyZVNlbXZlciwgY3JlYXRlTG9nZ2VyLCBlbnZJbnQsIEVycm9yQ29kZSwgZmV0Y2hQYXJlbnRPcmdJZCwgZ2V0U3RhdHVzRm9yRXJyb3JDb2RlLCBpc1N5c3RlbU9yZ0lkLFxuICBNQU5BR0VEX1RPT0xDSEFJTiwgTUFOQUdFRF9UT09MQ0hBSU5fUExVR0lOUywgTUFYX09SR19ERVBUSCwgU1lTVEVNX09SR19JRCwgVE9PTENIQUlOX1JFTEVBU0VfVkVSU0lPTl9QQVRURVJOLCB0b29sY2hhaW5Gcm9tTWV0YWRhdGEsIHRvT3JnSWRTdHJpbmcsXG4gIHR5cGUgR2V0UGFyZW50T3JnSWQsIHR5cGUgTWFuYWdlZFRvb2xjaGFpblBsdWdpbiwgdHlwZSBQbHVnaW5Ub29sY2hhaW4sIHR5cGUgVG9vbGNoYWluUmVzb2x2ZWRWaWEsXG59IGZyb20gJ0BwaXBlbGluZS1idWlsZGVyL2FwaS1jb3JlJztcbmltcG9ydCB7IGFuZCwgZXEsIGluQXJyYXksIGlzTnVsbCwgc3FsIH0gZnJvbSAnZHJpenpsZS1vcm0nO1xuaW1wb3J0IHR5cGUgeyBDcnVkVHggfSBmcm9tICcuL2NydWQtc2VydmljZS5qcyc7XG5pbXBvcnQgdHlwZSB7IFJlc29sdXRpb25SZWZ1c2FsIH0gZnJvbSAnLi9wbHVnaW4tcmVzb2x1dGlvbi5qcyc7XG5pbXBvcnQgeyBzY2hlbWEsIHR5cGUgT3JnVG9vbGNoYWluRGVmYXVsdCwgdHlwZSBQbHVnaW4sIHR5cGUgVG9vbGNoYWluUmVsZWFzZSB9IGZyb20gJy4uL2RhdGFiYXNlL2RyaXp6bGUtc2NoZW1hLmpzJztcbmltcG9ydCB7IHJ1bldpdGhUZW5hbnRDb250ZXh0LCB3aXRoVGVuYW50VHggfSBmcm9tICcuLi9kYXRhYmFzZS90ZW5hbmN5LmpzJztcblxuY29uc3QgbG9nZ2VyID0gY3JlYXRlTG9nZ2VyKCdtYW5hZ2VkLXRvb2xjaGFpbicpO1xuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gUHVibGljIHNoYXBlc1xuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuLyoqIEEgbm9uLWZhdGFsIG5vdGUgb24gYSByZXNvbHZlZCByZWxlYXNlIChzeW50aCBwcmludHMgaXQpLiAqL1xuZXhwb3J0IGludGVyZmFjZSBNYW5hZ2VkVG9vbGNoYWluV2FybmluZyB7XG4gIGNvZGU6IHN0cmluZztcbiAgbWVzc2FnZTogc3RyaW5nO1xuICBzZXZlcml0eTogJ2luZm8nIHwgJ3dhcm5pbmcnIHwgJ2Vycm9yJztcbn1cblxuLyoqIE9uZSByZWxlYXNlLCBib3RoIGhhbHZlcy4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTWFuYWdlZFRvb2xjaGFpblJlc29sdXRpb24ge1xuICByZWxlYXNlVmVyc2lvbjogc3RyaW5nO1xuICByZXNvbHZlZFZpYTogVG9vbGNoYWluUmVzb2x2ZWRWaWE7XG4gIGJvb3RzdHJhcDogUGx1Z2luO1xuICBzeW50aDogUGx1Z2luO1xuICB3YXJuaW5nczogTWFuYWdlZFRvb2xjaGFpbldhcm5pbmdbXTtcbn1cblxuLyoqIEEgcmVzb2x2ZXIgcmVmdXNhbDogYGNvZGVgIGlzIFRPT0xDSEFJTl9OT19ERUZBVUxULCBOT1RfRk9VTkQsIFRPT0xDSEFJTl9QQUlSX01JU01BVENIIG9yIFZBTElEQVRJT05fRVJST1IuICovXG5leHBvcnQgY2xhc3MgTWFuYWdlZFRvb2xjaGFpbkVycm9yIGV4dGVuZHMgQXBwRXJyb3Ige1xuICBjb25zdHJ1Y3Rvcihjb2RlOiBFcnJvckNvZGUsIG1lc3NhZ2U6IHN0cmluZywgZGV0YWlscz86IFJlY29yZDxzdHJpbmcsIHVua25vd24+KSB7XG4gICAgc3VwZXIoZ2V0U3RhdHVzRm9yRXJyb3JDb2RlKGNvZGUpLCBjb2RlLCBtZXNzYWdlLCBkZXRhaWxzKTtcbiAgICB0aGlzLm5hbWUgPSAnTWFuYWdlZFRvb2xjaGFpbkVycm9yJztcbiAgfVxufVxuXG4vKiogVGhlIGNhbGxlciBhIHJlc29sdXRpb24gcnVucyBmb3IuICovXG5leHBvcnQgaW50ZXJmYWNlIE1hbmFnZWRUb29sY2hhaW5DYWxsZXIge1xuICBvcmdJZDogc3RyaW5nO1xufVxuXG4vKiogV2hldGhlciBgdmVyc2lvbmAgaXMgYSByZWxlYXNlIHZlcnNpb24gKGBNQUpPUi5NSU5PUi5QQVRDSGApLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzVG9vbGNoYWluUmVsZWFzZVZlcnNpb24odmVyc2lvbjogdW5rbm93bik6IHZlcnNpb24gaXMgc3RyaW5nIHtcbiAgcmV0dXJuIHR5cGVvZiB2ZXJzaW9uID09PSAnc3RyaW5nJyAmJiBUT09MQ0hBSU5fUkVMRUFTRV9WRVJTSU9OX1BBVFRFUk4udGVzdCh2ZXJzaW9uKTtcbn1cblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIERhdGEgYWNjZXNzIChzeXN0ZW0tb3JnIHJvd3MsIGVsZXZhdGVkKVxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuLyoqIFdoYXQgdGhlIHJlc29sdmVyIHJlYWRzIHdpdGg6IGEgZHJpenpsZSB0cmFuc2FjdGlvbiAob3IgYW55IGRyaXp6bGUgZGF0YWJhc2UgaW4gdGVzdHMpLiAqL1xuZXhwb3J0IHR5cGUgVG9vbGNoYWluRGIgPSBQaWNrPENydWRUeCwgJ3NlbGVjdCc+O1xuXG4vKiogSG93IHRoZSByZXNvbHZlciByZWFkcyBhbmQgd2Fsa3MgdGhlIG9yZyB0cmVlIChpbmplY3RhYmxlIGZvciB0ZXN0cykuICovXG5leHBvcnQgaW50ZXJmYWNlIE1hbmFnZWRUb29sY2hhaW5EZXBzIHtcbiAgLyoqIFJ1biBgZm5gIHdpdGggRUxFVkFURUQgcmVhZHMuICovXG4gIHJlYWQ8VD4oZm46IChkYjogVG9vbGNoYWluRGIpID0+IFByb21pc2U8VD4pOiBQcm9taXNlPFQ+O1xuICAvKiogQW4gb3JnJ3MgZGlyZWN0IHBhcmVudCwgb3IgdW5kZWZpbmVkIGZvciBhIHJvb3QuIFRocm93cyB3aGVuIGl0IGNhbid0IHRlbGwuICovXG4gIGdldFBhcmVudDogR2V0UGFyZW50T3JnSWQ7XG59XG5cbi8qKiBCb3RoIGhhbHZlcyBvZiBvbmUgcmVsZWFzZSBhcyBzdG9yZWQsIHdpdGggdGhlIHJlbGVhc2Ugcm93LiAqL1xuZXhwb3J0IGludGVyZmFjZSBSZWxlYXNlSGFsdmVzIHtcbiAgcmVsZWFzZVZlcnNpb246IHN0cmluZztcbiAgcmVsZWFzZTogVG9vbGNoYWluUmVsZWFzZSB8IG51bGw7XG4gIGJvb3RzdHJhcDogUGx1Z2luIHwgbnVsbDtcbiAgc3ludGg6IFBsdWdpbiB8IG51bGw7XG59XG5cbmNvbnN0IHsgYm9vdHN0cmFwOiBCT09UU1RSQVAsIHN5bnRoOiBTWU5USCB9ID0gTUFOQUdFRF9UT09MQ0hBSU47XG5cbi8qKiBUaGUgcmVsZWFzZSByb3cgYW5kIGJvdGggU1lTVEVNLU9SRyBoYWx2ZXMgb2YgYHJlbGVhc2VWZXJzaW9uYCAoZGVsZXRlZCByb3dzIGV4Y2x1ZGVkKS4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBsb2FkUmVsZWFzZUhhbHZlcyhkYjogVG9vbGNoYWluRGIsIHJlbGVhc2VWZXJzaW9uOiBzdHJpbmcpOiBQcm9taXNlPFJlbGVhc2VIYWx2ZXM+IHtcbiAgY29uc3QgW3JlbGVhc2VzLCByb3dzXSA9IGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICBkYi5zZWxlY3QoKS5mcm9tKHNjaGVtYS50b29sY2hhaW5SZWxlYXNlKS53aGVyZShlcShzY2hlbWEudG9vbGNoYWluUmVsZWFzZS5yZWxlYXNlVmVyc2lvbiwgcmVsZWFzZVZlcnNpb24pKSxcbiAgICBkYi5zZWxlY3QoKS5mcm9tKHNjaGVtYS5wbHVnaW4pLndoZXJlKGFuZChcbiAgICAgIGVxKHNjaGVtYS5wbHVnaW4ub3JnSWQsIFNZU1RFTV9PUkdfSUQpLFxuICAgICAgaW5BcnJheShzY2hlbWEucGx1Z2luLm5hbWUsIFsuLi5NQU5BR0VEX1RPT0xDSEFJTl9QTFVHSU5TXSksXG4gICAgICBlcShzY2hlbWEucGx1Z2luLnZlcnNpb24sIHJlbGVhc2VWZXJzaW9uKSxcbiAgICAgIGlzTnVsbChzY2hlbWEucGx1Z2luLmRlbGV0ZWRBdCksXG4gICAgKSksXG4gIF0pO1xuICBjb25zdCBwbHVnaW5zID0gcm93cyBhcyBQbHVnaW5bXTtcbiAgcmV0dXJuIHtcbiAgICByZWxlYXNlVmVyc2lvbixcbiAgICByZWxlYXNlOiAocmVsZWFzZXMgYXMgVG9vbGNoYWluUmVsZWFzZVtdKVswXSA/PyBudWxsLFxuICAgIGJvb3RzdHJhcDogcGx1Z2lucy5maW5kKChwKSA9PiBwLm5hbWUgPT09IEJPT1RTVFJBUCkgPz8gbnVsbCxcbiAgICBzeW50aDogcGx1Z2lucy5maW5kKChwKSA9PiBwLm5hbWUgPT09IFNZTlRIKSA/PyBudWxsLFxuICB9O1xufVxuXG4vKiogQSBzZXR0aW5nIGZvdW5kIG9uIHRoZSBjYWxsZXIncyBjaGFpbjogd2hpY2ggY2hhaW4gaW5kZXgsIGFuZCBpdHMgcmVsZWFzZS4gKi9cbmludGVyZmFjZSBDaGFpblNldHRpbmcgeyBkZXB0aDogbnVtYmVyOyByZWxlYXNlVmVyc2lvbjogc3RyaW5nIH1cblxuLyoqIFRoZSBORUFSRVNUIHJvdyBvZiBgdGFibGVgIChrZXllZCBieSBgb3JnX2lkYCkgb24gYGNoYWluYCAob3duIG9yZyBmaXJzdCkuICovXG5hc3luYyBmdW5jdGlvbiBuZWFyZXN0T25DaGFpbihcbiAgZGI6IFRvb2xjaGFpbkRiLFxuICB0YWJsZTogdHlwZW9mIHNjaGVtYS5vcmdUb29sY2hhaW5EZWZhdWx0IHwgdHlwZW9mIHNjaGVtYS50b29sY2hhaW5Sb2xsb3V0LFxuICBjaGFpbjogcmVhZG9ubHkgc3RyaW5nW10sXG4pOiBQcm9taXNlPENoYWluU2V0dGluZyB8IG51bGw+IHtcbiAgaWYgKGNoYWluLmxlbmd0aCA9PT0gMCkgcmV0dXJuIG51bGw7XG4gIGNvbnN0IHJvd3MgPSBhd2FpdCBkYi5zZWxlY3QoeyBvcmdJZDogdGFibGUub3JnSWQsIHJlbGVhc2VWZXJzaW9uOiB0YWJsZS5yZWxlYXNlVmVyc2lvbiB9KVxuICAgIC5mcm9tKHRhYmxlKVxuICAgIC53aGVyZShpbkFycmF5KHNxbDxzdHJpbmc+YGxvd2VyKCR7dGFibGUub3JnSWR9KWAsIFsuLi5jaGFpbl0pKSBhcyBBcnJheTx7IG9yZ0lkOiBzdHJpbmc7IHJlbGVhc2VWZXJzaW9uOiBzdHJpbmcgfT47XG4gIGxldCBiZXN0OiBDaGFpblNldHRpbmcgfCBudWxsID0gbnVsbDtcbiAgZm9yIChjb25zdCByIG9mIHJvd3MpIHtcbiAgICBjb25zdCBkZXB0aCA9IGNoYWluLmluZGV4T2Yoci5vcmdJZC50b0xvd2VyQ2FzZSgpKTtcbiAgICBpZiAoZGVwdGggPj0gMCAmJiAoIWJlc3QgfHwgZGVwdGggPCBiZXN0LmRlcHRoKSkgYmVzdCA9IHsgZGVwdGgsIHJlbGVhc2VWZXJzaW9uOiByLnJlbGVhc2VWZXJzaW9uIH07XG4gIH1cbiAgcmV0dXJuIGJlc3Q7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGN1cnJlbnRQbGF0Zm9ybURlZmF1bHQoZGI6IFRvb2xjaGFpbkRiKTogUHJvbWlzZTxzdHJpbmcgfCBudWxsPiB7XG4gIGNvbnN0IHJvd3MgPSBhd2FpdCBkYi5zZWxlY3QoeyByZWxlYXNlVmVyc2lvbjogc2NoZW1hLnRvb2xjaGFpblBsYXRmb3JtRGVmYXVsdC5yZWxlYXNlVmVyc2lvbiB9KVxuICAgIC5mcm9tKHNjaGVtYS50b29sY2hhaW5QbGF0Zm9ybURlZmF1bHQpLmxpbWl0KDEpIGFzIEFycmF5PHsgcmVsZWFzZVZlcnNpb246IHN0cmluZyB9PjtcbiAgcmV0dXJuIHJvd3NbMF0/LnJlbGVhc2VWZXJzaW9uID8/IG51bGw7XG59XG5cbi8qKiBXaGV0aGVyIGByZWxlYXNlVmVyc2lvbmAgaGFzIGV2ZXIgYmVlbiAob3IgaXMpIHRoZSBwbGF0Zm9ybSBkZWZhdWx0LiAqL1xuYXN5bmMgZnVuY3Rpb24gd2FzUGxhdGZvcm1EZWZhdWx0KGRiOiBUb29sY2hhaW5EYiwgcmVsZWFzZVZlcnNpb246IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICBjb25zdCBbaGlzdG9yeSwgY3VycmVudF0gPSBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgZGIuc2VsZWN0KHsgaWQ6IHNjaGVtYS50b29sY2hhaW5EZWZhdWx0SGlzdG9yeS5pZCB9KS5mcm9tKHNjaGVtYS50b29sY2hhaW5EZWZhdWx0SGlzdG9yeSlcbiAgICAgIC53aGVyZShlcShzY2hlbWEudG9vbGNoYWluRGVmYXVsdEhpc3RvcnkucmVsZWFzZVZlcnNpb24sIHJlbGVhc2VWZXJzaW9uKSkubGltaXQoMSksXG4gICAgY3VycmVudFBsYXRmb3JtRGVmYXVsdChkYiksXG4gIF0pO1xuICByZXR1cm4gKGhpc3RvcnkgYXMgdW5rbm93bltdKS5sZW5ndGggPiAwIHx8IGN1cnJlbnQgPT09IHJlbGVhc2VWZXJzaW9uO1xufVxuXG4vKiogV2hldGhlciBBTlkgb3JnIGhhcyBhbiBvcmcgZGVmYXVsdCBvciBhIGNhbmFyeSBtZW1iZXJzaGlwIChlbHNlIG5vIHdhbGsgaXMgbmVlZGVkKS4gKi9cbmFzeW5jIGZ1bmN0aW9uIGFueU9yZ1NldHRpbmdzKGRiOiBUb29sY2hhaW5EYik6IFByb21pc2U8Ym9vbGVhbj4ge1xuICBjb25zdCBbZGVmYXVsdHMsIHJvbGxvdXRdID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgIGRiLnNlbGVjdCh7IG9yZ0lkOiBzY2hlbWEub3JnVG9vbGNoYWluRGVmYXVsdC5vcmdJZCB9KS5mcm9tKHNjaGVtYS5vcmdUb29sY2hhaW5EZWZhdWx0KS5saW1pdCgxKSxcbiAgICBkYi5zZWxlY3QoeyBvcmdJZDogc2NoZW1hLnRvb2xjaGFpblJvbGxvdXQub3JnSWQgfSkuZnJvbShzY2hlbWEudG9vbGNoYWluUm9sbG91dCkubGltaXQoMSksXG4gIF0pO1xuICByZXR1cm4gKGRlZmF1bHRzIGFzIHVua25vd25bXSkubGVuZ3RoID4gMCB8fCAocm9sbG91dCBhcyB1bmtub3duW10pLmxlbmd0aCA+IDA7XG59XG5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyBUaGUgb3JnIGNoYWluIChjYWxsZXIg4oaSIOKApiDihpIgcm9vdClcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbi8qKlxuICogVGhlIGNhbGxlcidzIGNoYWluLCBvd24gb3JnIGZpcnN0LCBsb3dlcmNhc2VkOiBgW3NlbGYsIHBhcmVudCwg4oCmLCByb290XWAuXG4gKiBUaGUgc2FtZSBwYXJlbnQgd2FsayBhcyBgb3JnLXJlYWNoYWJpbGl0eS50c2AgKHBsYXRmb3JtJ3NcbiAqIGBHRVQgL29yZ2FuaXphdGlvbi86aWQvcGFyZW50YCksIGN5Y2xlLXNhZmUgYW5kIGNhcHBlZCBhdCBgTUFYX09SR19ERVBUSGAgbGlrZVxuICogYHJlcG9ydGluZy1yZXRlbnRpb24udHNgIOKAlCBidXQgRkFJTC1DTE9TRUQ6IGEgbG9va3VwIGZhaWx1cmUsIGEgY3ljbGUgb3IgYW5cbiAqIG92ZXItZGVlcCBjaGFpbiB0aHJvd3MgcmF0aGVyIHRoYW4gcmVzb2x2aW5nIHRoZSB3cm9uZyBvcmcncyB0b29sY2hhaW4uXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB0b29sY2hhaW5PcmdDaGFpbihvcmdJZDogc3RyaW5nLCBnZXRQYXJlbnQ6IEdldFBhcmVudE9yZ0lkKTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICBjb25zdCBzZWxmID0gb3JnSWQudG9Mb3dlckNhc2UoKTtcbiAgY29uc3QgY2hhaW4gPSBbc2VsZl07XG4gIGlmIChpc1N5c3RlbU9yZ0lkKHNlbGYpKSByZXR1cm4gY2hhaW47XG4gIGxldCBjdXJyZW50ID0gc2VsZjtcbiAgZm9yIChsZXQgZGVwdGggPSAwOyBkZXB0aCA8IE1BWF9PUkdfREVQVEg7IGRlcHRoKyspIHtcbiAgICBjb25zdCBwYXJlbnQgPSB0b09yZ0lkU3RyaW5nKGF3YWl0IGdldFBhcmVudChjdXJyZW50KSk/LnRvTG93ZXJDYXNlKCk7XG4gICAgaWYgKCFwYXJlbnQgfHwgcGFyZW50ID09PSBjdXJyZW50KSByZXR1cm4gY2hhaW47XG4gICAgaWYgKGNoYWluLmluY2x1ZGVzKHBhcmVudCkpIHtcbiAgICAgIHRocm93IG5ldyBNYW5hZ2VkVG9vbGNoYWluRXJyb3IoRXJyb3JDb2RlLklOVEVSTkFMX0VSUk9SLCAnVGhlIG9yZ2FuaXphdGlvbiBoaWVyYXJjaHkgaGFzIGEgY3ljbGU7IHRoZSB0b29sY2hhaW4gcmVsZWFzZSBjYW5ub3QgYmUgcmVzb2x2ZWQuJywgeyBvcmdJZDogc2VsZiB9KTtcbiAgICB9XG4gICAgY2hhaW4ucHVzaChwYXJlbnQpO1xuICAgIGN1cnJlbnQgPSBwYXJlbnQ7XG4gIH1cbiAgdGhyb3cgbmV3IE1hbmFnZWRUb29sY2hhaW5FcnJvcihFcnJvckNvZGUuSU5URVJOQUxfRVJST1IsIGBUaGUgb3JnYW5pemF0aW9uIGhpZXJhcmNoeSBpcyBkZWVwZXIgdGhhbiAke01BWF9PUkdfREVQVEh9OyB0aGUgdG9vbGNoYWluIHJlbGVhc2UgY2Fubm90IGJlIHJlc29sdmVkLmAsIHsgb3JnSWQ6IHNlbGYgfSk7XG59XG5cbi8qKiBQYXJlbnQgbG9va3VwcyBhcmUgY2FjaGVkIGJyaWVmbHk6IG9uZSBzeW50aCBtYWtlcyBzZXZlcmFsIGxvb2t1cHMgZm9yIHRoZSBzYW1lIG9yZy4gKi9cbmNvbnN0IFBBUkVOVF9DQUNIRV9UVExfTVMgPSAzMF8wMDA7XG5jb25zdCBQQVJFTlRfQ0FDSEVfTUFYID0gNV8wMDA7XG5jb25zdCBwYXJlbnRDYWNoZSA9IG5ldyBNYXA8c3RyaW5nLCB7IHBhcmVudDogc3RyaW5nIHwgdW5kZWZpbmVkOyBhdDogbnVtYmVyIH0+KCk7XG5cbmFzeW5jIGZ1bmN0aW9uIHBsYXRmb3JtUGFyZW50KG9yZ0lkOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZyB8IHVuZGVmaW5lZD4ge1xuICBjb25zdCBoaXQgPSBwYXJlbnRDYWNoZS5nZXQob3JnSWQpO1xuICBpZiAoaGl0ICYmIERhdGUubm93KCkgLSBoaXQuYXQgPCBQQVJFTlRfQ0FDSEVfVFRMX01TKSByZXR1cm4gaGl0LnBhcmVudDtcbiAgLy8gQSBzeXN0ZW0tc2NvcGVkIHNlcnZpY2UgdG9rZW47IGEgbm9uLTJ4eCBUSFJPV1MgKGZhaWwtY2xvc2VkLCBzZWUgdG9vbGNoYWluT3JnQ2hhaW4pLlxuICBjb25zdCBwYXJlbnQgPSBhd2FpdCBmZXRjaFBhcmVudE9yZ0lkKG9yZ0lkLCB7IGF1dGhPcmdJZDogU1lTVEVNX09SR19JRCwgdGhyb3dPbkh0dHBFcnJvcjogdHJ1ZSwgdGltZW91dDogNV8wMDAgfSk7XG4gIGlmIChwYXJlbnRDYWNoZS5zaXplID49IFBBUkVOVF9DQUNIRV9NQVgpIHBhcmVudENhY2hlLmNsZWFyKCk7XG4gIHBhcmVudENhY2hlLnNldChvcmdJZCwgeyBwYXJlbnQsIGF0OiBEYXRlLm5vdygpIH0pO1xuICByZXR1cm4gcGFyZW50O1xufVxuXG5jb25zdCBwcm9kdWN0aW9uRGVwczogTWFuYWdlZFRvb2xjaGFpbkRlcHMgPSB7XG4gIHJlYWQ6IChmbikgPT4gcnVuV2l0aFRlbmFudENvbnRleHQoeyBpc1N1cGVyQWRtaW46IHRydWUgfSwgKCkgPT4gd2l0aFRlbmFudFR4KCh0eCkgPT4gZm4odHgpKSksXG4gIGdldFBhcmVudDogcGxhdGZvcm1QYXJlbnQsXG59O1xubGV0IGRlZmF1bHREZXBzOiBNYW5hZ2VkVG9vbGNoYWluRGVwcyA9IHByb2R1Y3Rpb25EZXBzO1xuXG4vKiogVGVzdCBob29rOiByZXBsYWNlIHRoZSByZXNvbHZlcidzIHJlYWRzIGFuZCBoaWVyYXJjaHkgKG51bGwgcmVzdG9yZXMgcHJvZHVjdGlvbikuICovXG5leHBvcnQgZnVuY3Rpb24gc2V0TWFuYWdlZFRvb2xjaGFpbkRlcHNGb3JUZXN0cyhkZXBzOiBNYW5hZ2VkVG9vbGNoYWluRGVwcyB8IG51bGwpOiB2b2lkIHtcbiAgZGVmYXVsdERlcHMgPSBkZXBzID8/IHByb2R1Y3Rpb25EZXBzO1xufVxuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gTGlmZWN5Y2xlLCBlbGlnaWJpbGl0eSBhbmQgdGhlIGNhbmFyeSBndWFyZHNcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbi8qKiBXaHkgYSBzdG9yZWQgcmVsZWFzZSBpcyBub3QgTElWRSAoZW1wdHkgPSBsaXZlOiBib3RoIGhhbHZlcyBwcmVzZW50LCBhY3RpdmUsIHVueWFua2VkLCBub3QgZGVwcmVjYXRlZCkuICovXG5leHBvcnQgdHlwZSBSZWxlYXNlTGlmZWN5Y2xlUHJvYmxlbSA9ICdtaXNzaW5nJyB8ICdpbmFjdGl2ZScgfCAneWFua2VkJyB8ICdkZXByZWNhdGVkJztcblxuY29uc3QgaXNZYW5rZWQgPSAocDogUGx1Z2luKSA9PiBwLnlhbmtlZEF0ICE9PSBudWxsIHx8IHAubGlmZWN5Y2xlID09PSAneWFua2VkJztcbmNvbnN0IGlzRGVwcmVjYXRlZCA9IChwOiBQbHVnaW4pID0+IHAuZGVwcmVjYXRlZEF0ICE9PSBudWxsIHx8IHAubGlmZWN5Y2xlID09PSAnZGVwcmVjYXRlZCc7XG5cbi8qKiBXaGV0aGVyIGJvdGggaGFsdmVzIGFyZSBwcmVzZW50ICh0aGUgcmVsZWFzZSBFWElTVFMpLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlbGVhc2VFeGlzdHMoaDogUmVsZWFzZUhhbHZlcyk6IGggaXMgUmVsZWFzZUhhbHZlcyAmIHsgYm9vdHN0cmFwOiBQbHVnaW47IHN5bnRoOiBQbHVnaW4gfSB7XG4gIHJldHVybiBoLnJlbGVhc2UgIT09IG51bGwgJiYgaC5ib290c3RyYXAgIT09IG51bGwgJiYgaC5zeW50aCAhPT0gbnVsbDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlbGVhc2VMaWZlY3ljbGVQcm9ibGVtcyhoOiBSZWxlYXNlSGFsdmVzKTogUmVsZWFzZUxpZmVjeWNsZVByb2JsZW1bXSB7XG4gIGlmICghcmVsZWFzZUV4aXN0cyhoKSkgcmV0dXJuIFsnbWlzc2luZyddO1xuICBjb25zdCBoYWx2ZXMgPSBbaC5ib290c3RyYXAsIGguc3ludGhdO1xuICBjb25zdCBvdXQ6IFJlbGVhc2VMaWZlY3ljbGVQcm9ibGVtW10gPSBbXTtcbiAgaWYgKGhhbHZlcy5zb21lKChwKSA9PiAhcC5pc0FjdGl2ZSkpIG91dC5wdXNoKCdpbmFjdGl2ZScpO1xuICBpZiAoaGFsdmVzLnNvbWUoaXNZYW5rZWQpKSBvdXQucHVzaCgneWFua2VkJyk7XG4gIGlmIChoYWx2ZXMuc29tZShpc0RlcHJlY2F0ZWQpKSBvdXQucHVzaCgnZGVwcmVjYXRlZCcpO1xuICByZXR1cm4gb3V0O1xufVxuXG4vKipcbiAqIFRoZSBib290c3RyYXAgaGFsZidzIHRvb2xjaGFpbiBtZXRhZGF0YSAoYHBpcGVsaW5lTWFuYWdlcmAsIGBhd3NDZGtgLCDigKYpLCBvclxuICogbnVsbCB3aGVuIGl0IGNhcnJpZXMgbm8gY29tcGxldGUsIHZhbGlkIG9uZS4gVXBsb2FkIHBlcnNpc3RzIGl0IG9uIHRoZSByb3cnc1xuICogYG1ldGFkYXRhYCBhcyBmbGF0IGB0b29sY2hhaW4uPGZpZWxkPmAga2V5cyAoYXBpLWNvcmUgYHRvb2xjaGFpbk1ldGFkYXRhYCkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBib290c3RyYXBUb29sY2hhaW5PZihyb3c6IFBsdWdpbiB8IG51bGwgfCB1bmRlZmluZWQpOiBQbHVnaW5Ub29sY2hhaW4gfCBudWxsIHtcbiAgcmV0dXJuIHJvdyA/IHRvb2xjaGFpbkZyb21NZXRhZGF0YShyb3cubWV0YWRhdGEpIDogbnVsbDtcbn1cblxuLyoqIGBQTFVHSU5fVlVMTl9NQVhfRklORElOR1NgIChkZWZhdWx0IDApOiB0aGUgZml4YWJsZS1Dcml0aWNhbCBmbG9vciBhIHJlbGVhc2UgbXVzdCBiZSB3aXRoaW4uICovXG5mdW5jdGlvbiB2dWxuRmxvb3IoKTogbnVtYmVyIHtcbiAgcmV0dXJuIGVudkludCgnUExVR0lOX1ZVTE5fTUFYX0ZJTkRJTkdTJywgMCwgeyBtaW46IDAgfSk7XG59XG5cbi8qKlxuICogVGhlIMKnOCBjYW5kaWRhdGUgZ3VhcmRzIChwYWlyLCBzY2FuLCBtZXRhZGF0YSkgYSByZWxlYXNlIGZhaWxzLCBhcyB0aGVpclxuICogZXJyb3IgY29kZXMg4oCUIGVtcHR5IHdoZW4gaXQgcGFzc2VzLiBUaGUgY2FuYXJ5IGdhdGUgYW5kIGNvbmN1cnJlbmN5IGFyZSB0aGVcbiAqIHBsYXRmb3JtLWRlZmF1bHQgc2VydmljZSdzOyBhIGNhbmFyeSBpcyBzZXJ2ZWQgb25seSB3aGlsZSB0aGlzIGlzIGVtcHR5LlxuICovXG5leHBvcnQgZnVuY3Rpb24gdG9vbGNoYWluQ2FuZGlkYXRlUHJvYmxlbXMoaDogUmVsZWFzZUhhbHZlcyk6IEVycm9yQ29kZVtdIHtcbiAgaWYgKCFyZWxlYXNlRXhpc3RzKGgpIHx8IHJlbGVhc2VMaWZlY3ljbGVQcm9ibGVtcyhoKS5sZW5ndGggPiAwKSByZXR1cm4gW0Vycm9yQ29kZS5UT09MQ0hBSU5fR1VBUkRfUEFJUl9JTkNPTVBMRVRFXTtcbiAgY29uc3Qgb3V0OiBFcnJvckNvZGVbXSA9IFtdO1xuICBjb25zdCBoYWx2ZXMgPSBbaC5ib290c3RyYXAsIGguc3ludGhdO1xuICBpZiAoaGFsdmVzLnNvbWUoKHApID0+ICFwLnNjYW5uZWRBdCkpIG91dC5wdXNoKEVycm9yQ29kZS5UT09MQ0hBSU5fR1VBUkRfVU5TQ0FOTkVEKTtcbiAgZWxzZSBpZiAoaGFsdmVzLnNvbWUoKHApID0+IChwLnZ1bG5Dcml0aWNhbEZpeGFibGUgPz8gMCkgPiB2dWxuRmxvb3IoKSkpIG91dC5wdXNoKEVycm9yQ29kZS5UT09MQ0hBSU5fR1VBUkRfVlVMTl9GTE9PUik7XG4gIGlmICghYm9vdHN0cmFwVG9vbGNoYWluT2YoaC5ib290c3RyYXApKSBvdXQucHVzaChFcnJvckNvZGUuVE9PTENIQUlOX0dVQVJEX01FVEFEQVRBKTtcbiAgcmV0dXJuIG91dDtcbn1cblxuLyoqIFdhcm5pbmdzIGZvciBhIHJlbGVhc2UgdGhhdCBFWElTVFMgYnV0IGlzIG5vIGxvbmdlciAob3IgbmV2ZXIgd2FzKSBlbGlnaWJsZS4gKi9cbmZ1bmN0aW9uIHN0YW5kaW5nV2FybmluZ3MoaDogUmVsZWFzZUhhbHZlcyAmIHsgYm9vdHN0cmFwOiBQbHVnaW47IHN5bnRoOiBQbHVnaW4gfSwgcHJvbW90ZWQ6IGJvb2xlYW4sIHZpYTogVG9vbGNoYWluUmVzb2x2ZWRWaWEpOiBNYW5hZ2VkVG9vbGNoYWluV2FybmluZ1tdIHtcbiAgY29uc3QgcmVmID0gYFRvb2xjaGFpbiByZWxlYXNlICR7aC5yZWxlYXNlVmVyc2lvbn1gO1xuICBjb25zdCBvdXQ6IE1hbmFnZWRUb29sY2hhaW5XYXJuaW5nW10gPSBbXTtcbiAgY29uc3QgeWFua2VkID0gW2guYm9vdHN0cmFwLCBoLnN5bnRoXS5maW5kKGlzWWFua2VkKTtcbiAgaWYgKHlhbmtlZCkge1xuICAgIG91dC5wdXNoKHtcbiAgICAgIGNvZGU6ICdUT09MQ0hBSU5fUkVMRUFTRV9ZQU5LRUQnLFxuICAgICAgc2V2ZXJpdHk6ICd3YXJuaW5nJyxcbiAgICAgIG1lc3NhZ2U6IGAke3JlZn0gaXMgeWFua2VkJHt5YW5rZWQueWFua1JlYXNvbiA/IGA6ICR7eWFua2VkLnlhbmtSZWFzb259YCA6ICcnfS4gSXQgcmVzb2x2ZXMgb25seSBiZWNhdXNlIGl0IGlzIHNlbGVjdGVkIGV4YWN0bHk7IG1vdmUgdG8gYSBzdXBwb3J0ZWQgcmVsZWFzZS5gLFxuICAgIH0pO1xuICB9XG4gIGNvbnN0IGRlcHJlY2F0ZWQgPSBbaC5ib290c3RyYXAsIGguc3ludGhdLmZpbmQoaXNEZXByZWNhdGVkKTtcbiAgaWYgKGRlcHJlY2F0ZWQpIHtcbiAgICBvdXQucHVzaCh7XG4gICAgICBjb2RlOiAnVE9PTENIQUlOX1JFTEVBU0VfREVQUkVDQVRFRCcsXG4gICAgICBzZXZlcml0eTogJ3dhcm5pbmcnLFxuICAgICAgbWVzc2FnZTogYCR7cmVmfSBpcyBkZXByZWNhdGVkJHtkZXByZWNhdGVkLmRlcHJlY2F0aW9uTWVzc2FnZSA/IGA6ICR7ZGVwcmVjYXRlZC5kZXByZWNhdGlvbk1lc3NhZ2V9YCA6ICcnfS5gLFxuICAgIH0pO1xuICB9XG4gIGlmIChbaC5ib290c3RyYXAsIGguc3ludGhdLnNvbWUoKHApID0+ICFwLmlzQWN0aXZlKSkge1xuICAgIG91dC5wdXNoKHsgY29kZTogJ1RPT0xDSEFJTl9SRUxFQVNFX0lOQUNUSVZFJywgc2V2ZXJpdHk6ICd3YXJuaW5nJywgbWVzc2FnZTogYCR7cmVmfSBpcyBpbmFjdGl2ZTsgbW92ZSB0byBhIHN1cHBvcnRlZCByZWxlYXNlLmAgfSk7XG4gIH1cbiAgaWYgKCFwcm9tb3RlZCAmJiAodmlhID09PSAncGluJyB8fCB2aWEgPT09ICdvcmctZGVmYXVsdCcpKSB7XG4gICAgb3V0LnB1c2goe1xuICAgICAgY29kZTogJ1RPT0xDSEFJTl9SRUxFQVNFX05PVF9QUk9NT1RFRCcsXG4gICAgICBzZXZlcml0eTogJ3dhcm5pbmcnLFxuICAgICAgbWVzc2FnZTogYCR7cmVmfSB3YXMgbmV2ZXIgdGhlIHBsYXRmb3JtIGRlZmF1bHQgYW5kIGlzIG5vdCBpbiBhIGNhbmFyeSBmb3IgeW91ciBvcmdhbml6YXRpb247IGl0IHJlc29sdmVzIG9ubHkgYmVjYXVzZSBpdCBpcyBzZWxlY3RlZCBleGFjdGx5LmAsXG4gICAgfSk7XG4gIH1cbiAgcmV0dXJuIG91dDtcbn1cblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIFJlc29sdXRpb25cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbmZ1bmN0aW9uIHBhaXJPZihoOiBSZWxlYXNlSGFsdmVzLCB2aWE6IFRvb2xjaGFpblJlc29sdmVkVmlhKTogeyBib290c3RyYXA6IFBsdWdpbjsgc3ludGg6IFBsdWdpbiB9IHtcbiAgaWYgKCFyZWxlYXNlRXhpc3RzKGgpKSB7XG4gICAgLy8gQSBkZWZhdWx0IChwbGF0Zm9ybSBvciBvcmcpIHdob3NlIGhhbHZlcyBhcmUgZ29uZSBpcyBhIGJyb2tlbiBpbnZhcmlhbnRcbiAgICAvLyAoaW4tdXNlIHByb3RlY3Rpb24gY291bnRzIGRlZmF1bHRzKTogcmVmdXNlZCwgbmV2ZXIgc2VydmVkLlxuICAgIHRocm93IG5ldyBNYW5hZ2VkVG9vbGNoYWluRXJyb3IoRXJyb3JDb2RlLlRPT0xDSEFJTl9QQUlSX01JU01BVENILCBgVG9vbGNoYWluIHJlbGVhc2UgJHtoLnJlbGVhc2VWZXJzaW9ufSAoJHt2aWF9KSBpcyBpbmNvbXBsZXRlOyBpdCBpcyBuZXZlciBzZXJ2ZWQuYCwge1xuICAgICAgcmVsZWFzZVZlcnNpb246IGgucmVsZWFzZVZlcnNpb24sXG4gICAgICBtaXNzaW5nOiBbLi4uKGguYm9vdHN0cmFwID8gW10gOiBbQk9PVFNUUkFQXSksIC4uLihoLnN5bnRoID8gW10gOiBbU1lOVEhdKSwgLi4uKGgucmVsZWFzZSA/IFtdIDogWyd0b29sY2hhaW5fcmVsZWFzZSddKV0sXG4gICAgfSk7XG4gIH1cbiAgaWYgKGguYm9vdHN0cmFwLnZlcnNpb24gIT09IGgucmVsZWFzZVZlcnNpb24gfHwgaC5zeW50aC52ZXJzaW9uICE9PSBoLnJlbGVhc2VWZXJzaW9uKSB7XG4gICAgdGhyb3cgbmV3IE1hbmFnZWRUb29sY2hhaW5FcnJvcihFcnJvckNvZGUuVE9PTENIQUlOX1BBSVJfTUlTTUFUQ0gsIGBUb29sY2hhaW4gaGFsdmVzIGRpc2FncmVlICgke0JPT1RTVFJBUH1AJHtoLmJvb3RzdHJhcC52ZXJzaW9ufSwgJHtTWU5USH1AJHtoLnN5bnRoLnZlcnNpb259KTsgbmV2ZXIgc2VydmVkLmAsIHtcbiAgICAgIHJlbGVhc2VWZXJzaW9uOiBoLnJlbGVhc2VWZXJzaW9uLFxuICAgIH0pO1xuICB9XG4gIHJldHVybiB7IGJvb3RzdHJhcDogaC5ib290c3RyYXAsIHN5bnRoOiBoLnN5bnRoIH07XG59XG5cbi8qKiBUaGUgcmVzb2x1dGlvbiBpbnNpZGUgb25lIGVsZXZhdGVkIHJlYWQsIG92ZXIgYSBrbm93biBjaGFpbi4gKi9cbmFzeW5jIGZ1bmN0aW9uIHJlc29sdmVPbkNoYWluKGRiOiBUb29sY2hhaW5EYiwgY2hhaW46IHJlYWRvbmx5IHN0cmluZ1tdLCByZWxlYXNlUGluPzogc3RyaW5nKTogUHJvbWlzZTxNYW5hZ2VkVG9vbGNoYWluUmVzb2x1dGlvbj4ge1xuICBjb25zdCBjYW5hcnkgPSBhd2FpdCBuZWFyZXN0T25DaGFpbihkYiwgc2NoZW1hLnRvb2xjaGFpblJvbGxvdXQsIGNoYWluKTtcbiAgY29uc3QgYW5zd2VyID0gYXN5bmMgKGg6IFJlbGVhc2VIYWx2ZXMsIHZpYTogVG9vbGNoYWluUmVzb2x2ZWRWaWEpOiBQcm9taXNlPE1hbmFnZWRUb29sY2hhaW5SZXNvbHV0aW9uPiA9PiB7XG4gICAgY29uc3QgcGFpciA9IHBhaXJPZihoLCB2aWEpO1xuICAgIGNvbnN0IHByb21vdGVkID0gdmlhID09PSAncGluJyB8fCB2aWEgPT09ICdvcmctZGVmYXVsdCdcbiAgICAgID8gKGF3YWl0IHdhc1BsYXRmb3JtRGVmYXVsdChkYiwgaC5yZWxlYXNlVmVyc2lvbikpIHx8IGNhbmFyeT8ucmVsZWFzZVZlcnNpb24gPT09IGgucmVsZWFzZVZlcnNpb25cbiAgICAgIDogdHJ1ZTtcbiAgICByZXR1cm4geyByZWxlYXNlVmVyc2lvbjogaC5yZWxlYXNlVmVyc2lvbiwgcmVzb2x2ZWRWaWE6IHZpYSwgLi4ucGFpciwgd2FybmluZ3M6IHN0YW5kaW5nV2FybmluZ3MoeyAuLi5oLCAuLi5wYWlyIH0sIHByb21vdGVkLCB2aWEpIH07XG4gIH07XG5cbiAgaWYgKHJlbGVhc2VQaW4gIT09IHVuZGVmaW5lZCkge1xuICAgIGlmICghaXNUb29sY2hhaW5SZWxlYXNlVmVyc2lvbihyZWxlYXNlUGluKSkge1xuICAgICAgdGhyb3cgbmV3IE1hbmFnZWRUb29sY2hhaW5FcnJvcihFcnJvckNvZGUuVkFMSURBVElPTl9FUlJPUiwgJ3JlbGVhc2VQaW4gbXVzdCBiZSBhIHJlbGVhc2UgdmVyc2lvbiAoTUFKT1IuTUlOT1IuUEFUQ0gsIGUuZy4gMS40LjIpLicsIHsgcmVsZWFzZVBpbiB9KTtcbiAgICB9XG4gICAgY29uc3QgaCA9IGF3YWl0IGxvYWRSZWxlYXNlSGFsdmVzKGRiLCByZWxlYXNlUGluKTtcbiAgICBpZiAoIXJlbGVhc2VFeGlzdHMoaCkpIHtcbiAgICAgIHRocm93IG5ldyBNYW5hZ2VkVG9vbGNoYWluRXJyb3IoRXJyb3JDb2RlLk5PVF9GT1VORCwgYFRvb2xjaGFpbiByZWxlYXNlICR7cmVsZWFzZVBpbn0gZG9lcyBub3QgZXhpc3QgKG9yIHdhcyBkZWxldGVkKS4gUGluIGFuIGVsaWdpYmxlIHJlbGVhc2UsIG9yIHJlbW92ZSB0b29sY2hhaW4ucmVsZWFzZSB0byBmb2xsb3cgeW91ciBvcmdhbml6YXRpb24ncyBkZWZhdWx0LmAsIHtcbiAgICAgICAgcmVhc29uOiAndG9vbGNoYWluX3JlbGVhc2Vfbm90X2ZvdW5kJywgcmVsZWFzZVZlcnNpb246IHJlbGVhc2VQaW4sXG4gICAgICB9KTtcbiAgICB9XG4gICAgcmV0dXJuIGFuc3dlcihoLCAncGluJyk7XG4gIH1cblxuICBjb25zdCBvcmdEZWZhdWx0ID0gYXdhaXQgbmVhcmVzdE9uQ2hhaW4oZGIsIHNjaGVtYS5vcmdUb29sY2hhaW5EZWZhdWx0LCBjaGFpbik7XG4gIGlmIChvcmdEZWZhdWx0KSByZXR1cm4gYW5zd2VyKGF3YWl0IGxvYWRSZWxlYXNlSGFsdmVzKGRiLCBvcmdEZWZhdWx0LnJlbGVhc2VWZXJzaW9uKSwgJ29yZy1kZWZhdWx0Jyk7XG5cbiAgaWYgKGNhbmFyeSkge1xuICAgIGNvbnN0IGggPSBhd2FpdCBsb2FkUmVsZWFzZUhhbHZlcyhkYiwgY2FuYXJ5LnJlbGVhc2VWZXJzaW9uKTtcbiAgICBjb25zdCBwcm9ibGVtcyA9IHRvb2xjaGFpbkNhbmRpZGF0ZVByb2JsZW1zKGgpO1xuICAgIGlmIChwcm9ibGVtcy5sZW5ndGggPT09IDApIHJldHVybiBhbnN3ZXIoaCwgJ2NhbmFyeScpO1xuICAgIC8vIE1lbWJlcnMgZmFsbCB0aHJvdWdoIHRvIHRoZSBwbGF0Zm9ybSBkZWZhdWx0LiBMb2dnZWQsIG5ldmVyIHJldHVybmVkOlxuICAgIC8vIHRoZSBhbnN3ZXIgbXVzdCBub3QgcmV2ZWFsIGNhbmFyeSBtZW1iZXJzaGlwLlxuICAgIGxvZ2dlci53YXJuKCdDYW5hcnkgdG9vbGNoYWluIHJlbGVhc2UgZmFpbHMgaXRzIGd1YXJkczsgc2VydmluZyB0aGUgcGxhdGZvcm0gZGVmYXVsdCcsIHsgcmVsZWFzZVZlcnNpb246IGNhbmFyeS5yZWxlYXNlVmVyc2lvbiwgcHJvYmxlbXMgfSk7XG4gIH1cblxuICBjb25zdCBwbGF0Zm9ybSA9IGF3YWl0IGN1cnJlbnRQbGF0Zm9ybURlZmF1bHQoZGIpO1xuICBpZiAoIXBsYXRmb3JtKSB7XG4gICAgdGhyb3cgbmV3IE1hbmFnZWRUb29sY2hhaW5FcnJvcihFcnJvckNvZGUuVE9PTENIQUlOX05PX0RFRkFVTFQsICdObyBwbGF0Zm9ybSBkZWZhdWx0IHRvb2xjaGFpbiByZWxlYXNlIGlzIHNldC4gQW4gb3BlcmF0b3IgbXVzdCBzZXQgb25lIChpbml0LXBsYXRmb3JtIGRvZXMgdGhpcyBvbiBhIGZyZXNoIGluc3RhbGwpLicpO1xuICB9XG4gIHJldHVybiBhbnN3ZXIoYXdhaXQgbG9hZFJlbGVhc2VIYWx2ZXMoZGIsIHBsYXRmb3JtKSwgJ2RlZmF1bHQnKTtcbn1cblxuLyoqIHtAbGluayByZXNvbHZlTWFuYWdlZFRvb2xjaGFpbn0gd2l0aCBpbmplY3RlZCByZWFkcyBhbmQgaGllcmFyY2h5ICh0ZXN0cykuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVzb2x2ZU1hbmFnZWRUb29sY2hhaW5XaXRoKFxuICBkZXBzOiBNYW5hZ2VkVG9vbGNoYWluRGVwcyxcbiAgY2FsbGVyOiBNYW5hZ2VkVG9vbGNoYWluQ2FsbGVyLFxuICBvcHRzOiB7IHJlbGVhc2VQaW4/OiBzdHJpbmcgfSA9IHt9LFxuKTogUHJvbWlzZTxNYW5hZ2VkVG9vbGNoYWluUmVzb2x1dGlvbj4ge1xuICBjb25zdCBzZWxmID0gY2FsbGVyLm9yZ0lkLnRvTG93ZXJDYXNlKCk7XG4gIC8vIFdhbGsgdGhlIGhpZXJhcmNoeSBvbmx5IHdoZW4gc29tZSBvcmcgaGFzIGEgc2V0dGluZyAoYW5kIG91dHNpZGUgdGhlIHRyYW5zYWN0aW9uKS5cbiAgY29uc3Qgd2FsayA9IGF3YWl0IGRlcHMucmVhZCgoZGIpID0+IGFueU9yZ1NldHRpbmdzKGRiKSk7XG4gIGNvbnN0IGNoYWluID0gd2FsayA/IGF3YWl0IHRvb2xjaGFpbk9yZ0NoYWluKHNlbGYsIGRlcHMuZ2V0UGFyZW50KSA6IFtzZWxmXTtcbiAgcmV0dXJuIGRlcHMucmVhZCgoZGIpID0+IHJlc29sdmVPbkNoYWluKGRiLCBjaGFpbiwgb3B0cy5yZWxlYXNlUGluKSk7XG59XG5cbi8qKlxuICogUmVzb2x2ZSB0aGUgbWFuYWdlZCB0b29sY2hhaW4gcmVsZWFzZSBmb3IgYGNhbGxlcmAgKHNlZSB0aGUgbW9kdWxlIGRvYykuXG4gKiBUaHJvd3Mge0BsaW5rIE1hbmFnZWRUb29sY2hhaW5FcnJvcn06IFRPT0xDSEFJTl9OT19ERUZBVUxUICg0MDksIG5vIHBsYXRmb3JtXG4gKiBkZWZhdWx0KSwgTk9UX0ZPVU5EICg0MDQsIGEgbWlzc2luZyAvIGRlbGV0ZWQgcGluKSwgVE9PTENIQUlOX1BBSVJfTUlTTUFUQ0hcbiAqICg1MDApLCBWQUxJREFUSU9OX0VSUk9SICg0MDAsIGEgbWFsZm9ybWVkIHBpbikuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlTWFuYWdlZFRvb2xjaGFpbihjYWxsZXI6IE1hbmFnZWRUb29sY2hhaW5DYWxsZXIsIG9wdHM6IHsgcmVsZWFzZVBpbj86IHN0cmluZyB9ID0ge30pOiBQcm9taXNlPE1hbmFnZWRUb29sY2hhaW5SZXNvbHV0aW9uPiB7XG4gIHJldHVybiByZXNvbHZlTWFuYWdlZFRvb2xjaGFpbldpdGgoZGVmYXVsdERlcHMsIGNhbGxlciwgb3B0cyk7XG59XG5cbi8qKiB7QGxpbmsgaXNFbGlnaWJsZVJlbGVhc2V9IHdpdGggaW5qZWN0ZWQgcmVhZHMgYW5kIGhpZXJhcmNoeSAodGVzdHMpLiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGlzRWxpZ2libGVSZWxlYXNlV2l0aChkZXBzOiBNYW5hZ2VkVG9vbGNoYWluRGVwcywgb3JnSWQ6IHN0cmluZywgcmVsZWFzZVZlcnNpb246IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICBpZiAoIWlzVG9vbGNoYWluUmVsZWFzZVZlcnNpb24ocmVsZWFzZVZlcnNpb24pKSByZXR1cm4gZmFsc2U7XG4gIGNvbnN0IHNlbGYgPSBvcmdJZC50b0xvd2VyQ2FzZSgpO1xuICBjb25zdCBoYWx2ZXMgPSBhd2FpdCBkZXBzLnJlYWQoKGRiKSA9PiBsb2FkUmVsZWFzZUhhbHZlcyhkYiwgcmVsZWFzZVZlcnNpb24pKTtcbiAgaWYgKHJlbGVhc2VMaWZlY3ljbGVQcm9ibGVtcyhoYWx2ZXMpLmxlbmd0aCA+IDApIHJldHVybiBmYWxzZTtcbiAgaWYgKGF3YWl0IGRlcHMucmVhZCgoZGIpID0+IHdhc1BsYXRmb3JtRGVmYXVsdChkYiwgcmVsZWFzZVZlcnNpb24pKSkgcmV0dXJuIHRydWU7XG4gIGNvbnN0IHdhbGsgPSBhd2FpdCBkZXBzLnJlYWQoKGRiKSA9PiBhbnlPcmdTZXR0aW5ncyhkYikpO1xuICBpZiAoIXdhbGspIHJldHVybiBmYWxzZTtcbiAgY29uc3QgY2hhaW4gPSBhd2FpdCB0b29sY2hhaW5PcmdDaGFpbihzZWxmLCBkZXBzLmdldFBhcmVudCk7XG4gIGNvbnN0IGNhbmFyeSA9IGF3YWl0IGRlcHMucmVhZCgoZGIpID0+IG5lYXJlc3RPbkNoYWluKGRiLCBzY2hlbWEudG9vbGNoYWluUm9sbG91dCwgY2hhaW4pKTtcbiAgcmV0dXJuIGNhbmFyeT8ucmVsZWFzZVZlcnNpb24gPT09IHJlbGVhc2VWZXJzaW9uO1xufVxuXG4vKipcbiAqIEQxNTogd2hldGhlciBgb3JnSWRgIG1heSBTRVQgYHJlbGVhc2VWZXJzaW9uYCBhcyBhIHBpcGVsaW5lIHBpbiBvciBpdHMgb3JnXG4gKiBkZWZhdWx0IOKAlCBib3RoIGhhbHZlcyBsaXZlIChhY3RpdmUsIHVueWFua2VkLCBub3QgZGVwcmVjYXRlZCkgQU5EIGVpdGhlciBpdFxuICogaGFzIGJlZW4gdGhlIHBsYXRmb3JtIGRlZmF1bHQgb3IgaXQgaXMgdGhlIGNhbGxlcidzIGNhbmFyeSAobmVhcmVzdFxuICogbWVtYmVyc2hpcCBvbiBpdHMgY2hhaW4pLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNFbGlnaWJsZVJlbGVhc2Uob3JnSWQ6IHN0cmluZywgcmVsZWFzZVZlcnNpb246IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICByZXR1cm4gaXNFbGlnaWJsZVJlbGVhc2VXaXRoKGRlZmF1bHREZXBzLCBvcmdJZCwgcmVsZWFzZVZlcnNpb24pO1xufVxuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gVGhlIG9yZydzIG93biBwaWN0dXJlOiB0aGUgb3JnLWRlZmF1bHQgcGFuZWwgYW5kIHRoZSBlbGlnaWJsZS1yZWxlYXNlIGxpc3Rcbi8vIChkb2NzL3BsYW5zL2Jvb3RzdHJhcC1pbWFnZS12ZXJzaW9uaW5nLm1kIMKnNSwgUGhhc2UgNCwgRDE1KVxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuLyoqXG4gKiBXaGF0IHRoZSBvcmctZGVmYXVsdCBwYW5lbCBzaG93cyBhIGNhbGxlciBhYm91dCBJVFMgT1dOIG9yZzogbmV2ZXIgYW5vdGhlclxuICogb3JnJ3MgY2hvaWNlLCBhbmQgb2YgdGhlIGFuY2VzdG9ycyBvbmx5IHdoaWNoIG9uZSdzIGRlZmF1bHQgYXBwbGllcy5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBPcmdUb29sY2hhaW5PdmVydmlldyB7XG4gIC8qKiBUaGUgY2FsbGVyJ3MgY2hhaW4sIG93biBvcmcgZmlyc3QgKGxvd2VyY2FzZWQpLiAqL1xuICBjaGFpbjogc3RyaW5nW107XG4gIC8qKiBXaGF0IHRoZSBvcmcncyBVTlBJTk5FRCBwaXBlbGluZXMgcmVzb2x2ZSB0byBub3cuICovXG4gIGVmZmVjdGl2ZTogeyByZWxlYXNlVmVyc2lvbjogc3RyaW5nOyByZXNvbHZlZFZpYTogVG9vbGNoYWluUmVzb2x2ZWRWaWE7IHdhcm5pbmdzOiBNYW5hZ2VkVG9vbGNoYWluV2FybmluZ1tdIH07XG4gIC8qKiBUaGUgY2FsbGVyIG9yZydzIG93biBgb3JnX3Rvb2xjaGFpbl9kZWZhdWx0YCByb3csIGlmIGl0IHNldCBvbmUuICovXG4gIG93bkRlZmF1bHQ6IE9yZ1Rvb2xjaGFpbkRlZmF1bHQgfCBudWxsO1xuICAvKiogVGhlIGFuY2VzdG9yIHdob3NlIG9yZyBkZWZhdWx0IGFwcGxpZXMsIHdoZW4gdGhlIG9yZyBzZXQgbm9uZSBvZiBpdHMgb3duLiAqL1xuICBpbmhlcml0ZWRGcm9tOiB7IG9yZ0lkOiBzdHJpbmc7IHJlbGVhc2VWZXJzaW9uOiBzdHJpbmcgfSB8IG51bGw7XG4gIC8qKiBUaGUgY2FsbGVyJ3MgY2FuYXJ5IHJlbGVhc2UgKGl0cyBORUFSRVNUIG1lbWJlcnNoaXAgb24gdGhlIGNoYWluKSwgb3IgbnVsbC4gKi9cbiAgY2FuYXJ5UmVsZWFzZTogc3RyaW5nIHwgbnVsbDtcbiAgcGxhdGZvcm1EZWZhdWx0OiBzdHJpbmcgfCBudWxsO1xufVxuXG4vKioge0BsaW5rIHJlYWRPcmdUb29sY2hhaW5PdmVydmlld30gd2l0aCBpbmplY3RlZCByZWFkcyBhbmQgaGllcmFyY2h5ICh0ZXN0cykuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVhZE9yZ1Rvb2xjaGFpbk92ZXJ2aWV3V2l0aChkZXBzOiBNYW5hZ2VkVG9vbGNoYWluRGVwcywgb3JnSWQ6IHN0cmluZyk6IFByb21pc2U8T3JnVG9vbGNoYWluT3ZlcnZpZXc+IHtcbiAgY29uc3Qgc2VsZiA9IG9yZ0lkLnRvTG93ZXJDYXNlKCk7XG4gIGNvbnN0IHdhbGsgPSBhd2FpdCBkZXBzLnJlYWQoKGRiKSA9PiBhbnlPcmdTZXR0aW5ncyhkYikpO1xuICBjb25zdCBjaGFpbiA9IHdhbGsgPyBhd2FpdCB0b29sY2hhaW5PcmdDaGFpbihzZWxmLCBkZXBzLmdldFBhcmVudCkgOiBbc2VsZl07XG4gIHJldHVybiBkZXBzLnJlYWQoYXN5bmMgKGRiKSA9PiB7XG4gICAgY29uc3Qgcm93cyA9IGF3YWl0IGRiLnNlbGVjdCgpLmZyb20oc2NoZW1hLm9yZ1Rvb2xjaGFpbkRlZmF1bHQpXG4gICAgICAud2hlcmUoaW5BcnJheShzcWw8c3RyaW5nPmBsb3dlcigke3NjaGVtYS5vcmdUb29sY2hhaW5EZWZhdWx0Lm9yZ0lkfSlgLCBjaGFpbikpIGFzIE9yZ1Rvb2xjaGFpbkRlZmF1bHRbXTtcbiAgICBjb25zdCBkZXB0aE9mID0gKHI6IE9yZ1Rvb2xjaGFpbkRlZmF1bHQpID0+IGNoYWluLmluZGV4T2Yoci5vcmdJZC50b0xvd2VyQ2FzZSgpKTtcbiAgICBjb25zdCBvd25EZWZhdWx0ID0gcm93cy5maW5kKChyKSA9PiBkZXB0aE9mKHIpID09PSAwKSA/PyBudWxsO1xuICAgIGNvbnN0IG5lYXJlc3QgPSByb3dzLmZpbHRlcigocikgPT4gZGVwdGhPZihyKSA+PSAwKS5zb3J0KChhLCBiKSA9PiBkZXB0aE9mKGEpIC0gZGVwdGhPZihiKSlbMF0gPz8gbnVsbDtcbiAgICBjb25zdCBbY2FuYXJ5LCBwbGF0Zm9ybURlZmF1bHQsIHJlc29sdXRpb25dID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgbmVhcmVzdE9uQ2hhaW4oZGIsIHNjaGVtYS50b29sY2hhaW5Sb2xsb3V0LCBjaGFpbiksXG4gICAgICBjdXJyZW50UGxhdGZvcm1EZWZhdWx0KGRiKSxcbiAgICAgIHJlc29sdmVPbkNoYWluKGRiLCBjaGFpbiksXG4gICAgXSk7XG4gICAgcmV0dXJuIHtcbiAgICAgIGNoYWluLFxuICAgICAgZWZmZWN0aXZlOiB7IHJlbGVhc2VWZXJzaW9uOiByZXNvbHV0aW9uLnJlbGVhc2VWZXJzaW9uLCByZXNvbHZlZFZpYTogcmVzb2x1dGlvbi5yZXNvbHZlZFZpYSwgd2FybmluZ3M6IHJlc29sdXRpb24ud2FybmluZ3MgfSxcbiAgICAgIG93bkRlZmF1bHQsXG4gICAgICBpbmhlcml0ZWRGcm9tOiAhb3duRGVmYXVsdCAmJiBuZWFyZXN0ID8geyBvcmdJZDogbmVhcmVzdC5vcmdJZCwgcmVsZWFzZVZlcnNpb246IG5lYXJlc3QucmVsZWFzZVZlcnNpb24gfSA6IG51bGwsXG4gICAgICBjYW5hcnlSZWxlYXNlOiBjYW5hcnk/LnJlbGVhc2VWZXJzaW9uID8/IG51bGwsXG4gICAgICBwbGF0Zm9ybURlZmF1bHQsXG4gICAgfTtcbiAgfSk7XG59XG5cbi8qKlxuICogVGhlIGNhbGxlciBvcmcncyB0b29sY2hhaW4gb3ZlcnZpZXcgKGVsZXZhdGVkIHJlYWRzLCB0aGUgc2FtZSBjaGFpbiB3YWxrIGFuZFxuICogcHJlY2VkZW5jZSBhcyB7QGxpbmsgcmVzb2x2ZU1hbmFnZWRUb29sY2hhaW59KS4gVGhyb3dzIHdoYXQgdGhlIHJlc29sdmVyXG4gKiB0aHJvd3Mg4oCUIFRPT0xDSEFJTl9OT19ERUZBVUxUICg0MDkpIHdoZW4gbm90aGluZyByZXNvbHZlcyBhdCBhbGwuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWFkT3JnVG9vbGNoYWluT3ZlcnZpZXcob3JnSWQ6IHN0cmluZyk6IFByb21pc2U8T3JnVG9vbGNoYWluT3ZlcnZpZXc+IHtcbiAgcmV0dXJuIHJlYWRPcmdUb29sY2hhaW5PdmVydmlld1dpdGgoZGVmYXVsdERlcHMsIG9yZ0lkKTtcbn1cblxuLyoqIE9uZSByZWxlYXNlIHRoZSBjYWxsZXIgbWF5IHBpbiBvciBzZXQgKEQxNSksIHdpdGggd2hhdCB0aGUgc2VsZWN0b3JzIHNob3cuICovXG5leHBvcnQgaW50ZXJmYWNlIEVsaWdpYmxlVG9vbGNoYWluUmVsZWFzZSB7XG4gIHJlbGVhc2VWZXJzaW9uOiBzdHJpbmc7XG4gIHJlbGVhc2U6IFRvb2xjaGFpblJlbGVhc2U7XG4gIGJvb3RzdHJhcDogUGx1Z2luO1xuICBzeW50aDogUGx1Z2luO1xuICAvKiogVEhFIHBsYXRmb3JtIGRlZmF1bHQgbm93LiAqL1xuICBpc1BsYXRmb3JtRGVmYXVsdDogYm9vbGVhbjtcbiAgLyoqIFRoZSBjYWxsZXIncyBjYW5hcnkgcmVsZWFzZSAobmVhcmVzdCBtZW1iZXJzaGlwKS4gKi9cbiAgaXNDYW5hcnk6IGJvb2xlYW47XG59XG5cbi8qKiB7QGxpbmsgbGlzdEVsaWdpYmxlUmVsZWFzZXN9IHdpdGggaW5qZWN0ZWQgcmVhZHMgYW5kIGhpZXJhcmNoeSAodGVzdHMpLiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGxpc3RFbGlnaWJsZVJlbGVhc2VzV2l0aChkZXBzOiBNYW5hZ2VkVG9vbGNoYWluRGVwcywgb3JnSWQ6IHN0cmluZyk6IFByb21pc2U8eyBwbGF0Zm9ybURlZmF1bHQ6IHN0cmluZyB8IG51bGw7IHJlbGVhc2VzOiBFbGlnaWJsZVRvb2xjaGFpblJlbGVhc2VbXSB9PiB7XG4gIGNvbnN0IHNlbGYgPSBvcmdJZC50b0xvd2VyQ2FzZSgpO1xuICBjb25zdCB3YWxrID0gYXdhaXQgZGVwcy5yZWFkKChkYikgPT4gYW55T3JnU2V0dGluZ3MoZGIpKTtcbiAgY29uc3QgY2hhaW4gPSB3YWxrID8gYXdhaXQgdG9vbGNoYWluT3JnQ2hhaW4oc2VsZiwgZGVwcy5nZXRQYXJlbnQpIDogW3NlbGZdO1xuICByZXR1cm4gZGVwcy5yZWFkKGFzeW5jIChkYikgPT4ge1xuICAgIGNvbnN0IFtyZWxlYXNlcywgcm93cywgaGlzdG9yeSwgcGxhdGZvcm1EZWZhdWx0LCBjYW5hcnldID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgZGIuc2VsZWN0KCkuZnJvbShzY2hlbWEudG9vbGNoYWluUmVsZWFzZSkgYXMgUHJvbWlzZTxUb29sY2hhaW5SZWxlYXNlW10+LFxuICAgICAgZGIuc2VsZWN0KCkuZnJvbShzY2hlbWEucGx1Z2luKS53aGVyZShhbmQoXG4gICAgICAgIGVxKHNjaGVtYS5wbHVnaW4ub3JnSWQsIFNZU1RFTV9PUkdfSUQpLFxuICAgICAgICBpbkFycmF5KHNjaGVtYS5wbHVnaW4ubmFtZSwgWy4uLk1BTkFHRURfVE9PTENIQUlOX1BMVUdJTlNdKSxcbiAgICAgICAgaXNOdWxsKHNjaGVtYS5wbHVnaW4uZGVsZXRlZEF0KSxcbiAgICAgICkpIGFzIFByb21pc2U8UGx1Z2luW10+LFxuICAgICAgZGIuc2VsZWN0KHsgcmVsZWFzZVZlcnNpb246IHNjaGVtYS50b29sY2hhaW5EZWZhdWx0SGlzdG9yeS5yZWxlYXNlVmVyc2lvbiB9KS5mcm9tKHNjaGVtYS50b29sY2hhaW5EZWZhdWx0SGlzdG9yeSkgYXMgUHJvbWlzZTxBcnJheTx7IHJlbGVhc2VWZXJzaW9uOiBzdHJpbmcgfT4+LFxuICAgICAgY3VycmVudFBsYXRmb3JtRGVmYXVsdChkYiksXG4gICAgICBuZWFyZXN0T25DaGFpbihkYiwgc2NoZW1hLnRvb2xjaGFpblJvbGxvdXQsIGNoYWluKSxcbiAgICBdKTtcbiAgICBjb25zdCBwcm9tb3RlZCA9IG5ldyBTZXQoaGlzdG9yeS5tYXAoKGgpID0+IGgucmVsZWFzZVZlcnNpb24pKTtcbiAgICBpZiAocGxhdGZvcm1EZWZhdWx0KSBwcm9tb3RlZC5hZGQocGxhdGZvcm1EZWZhdWx0KTtcbiAgICBjb25zdCBvdXQ6IEVsaWdpYmxlVG9vbGNoYWluUmVsZWFzZVtdID0gW107XG4gICAgZm9yIChjb25zdCByZWxlYXNlIG9mIHJlbGVhc2VzKSB7XG4gICAgICBjb25zdCB2ID0gcmVsZWFzZS5yZWxlYXNlVmVyc2lvbjtcbiAgICAgIGNvbnN0IGhhbHZlczogUmVsZWFzZUhhbHZlcyA9IHtcbiAgICAgICAgcmVsZWFzZVZlcnNpb246IHYsXG4gICAgICAgIHJlbGVhc2UsXG4gICAgICAgIGJvb3RzdHJhcDogcm93cy5maW5kKChwKSA9PiBwLm5hbWUgPT09IEJPT1RTVFJBUCAmJiBwLnZlcnNpb24gPT09IHYpID8/IG51bGwsXG4gICAgICAgIHN5bnRoOiByb3dzLmZpbmQoKHApID0+IHAubmFtZSA9PT0gU1lOVEggJiYgcC52ZXJzaW9uID09PSB2KSA/PyBudWxsLFxuICAgICAgfTtcbiAgICAgIGlmICghcmVsZWFzZUV4aXN0cyhoYWx2ZXMpIHx8IHJlbGVhc2VMaWZlY3ljbGVQcm9ibGVtcyhoYWx2ZXMpLmxlbmd0aCA+IDApIGNvbnRpbnVlO1xuICAgICAgY29uc3QgaXNDYW5hcnkgPSBjYW5hcnk/LnJlbGVhc2VWZXJzaW9uID09PSB2O1xuICAgICAgaWYgKCFwcm9tb3RlZC5oYXModikgJiYgIWlzQ2FuYXJ5KSBjb250aW51ZTtcbiAgICAgIG91dC5wdXNoKHsgcmVsZWFzZVZlcnNpb246IHYsIHJlbGVhc2UsIGJvb3RzdHJhcDogaGFsdmVzLmJvb3RzdHJhcCwgc3ludGg6IGhhbHZlcy5zeW50aCwgaXNQbGF0Zm9ybURlZmF1bHQ6IHBsYXRmb3JtRGVmYXVsdCA9PT0gdiwgaXNDYW5hcnkgfSk7XG4gICAgfVxuICAgIG91dC5zb3J0KChhLCBiKSA9PiBjb21wYXJlU2VtdmVyKGIucmVsZWFzZVZlcnNpb24sIGEucmVsZWFzZVZlcnNpb24pKTtcbiAgICByZXR1cm4geyBwbGF0Zm9ybURlZmF1bHQsIHJlbGVhc2VzOiBvdXQgfTtcbiAgfSk7XG59XG5cbi8qKlxuICogRXZlcnkgcmVsZWFzZSBgb3JnSWRgIG1heSBTRVQgYXMgYSBwaXBlbGluZSBwaW4gb3IgaXRzIG9yZyBkZWZhdWx0IChEMTUsIHRoZVxuICogc2FtZSBydWxlIGFzIHtAbGluayBpc0VsaWdpYmxlUmVsZWFzZX0pLCBuZXdlc3QgZmlyc3QuIE5ldmVyIGFub3RoZXIgb3JnJ3NcbiAqIGRhdGE6IGEgY2FuYXJ5IGFwcGVhcnMgb25seSB3aGVuIGl0IGlzIHRoZSBjYWxsZXIncyBvd24gKG5lYXJlc3QpIG1lbWJlcnNoaXAuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBsaXN0RWxpZ2libGVSZWxlYXNlcyhvcmdJZDogc3RyaW5nKTogUHJvbWlzZTx7IHBsYXRmb3JtRGVmYXVsdDogc3RyaW5nIHwgbnVsbDsgcmVsZWFzZXM6IEVsaWdpYmxlVG9vbGNoYWluUmVsZWFzZVtdIH0+IHtcbiAgcmV0dXJuIGxpc3RFbGlnaWJsZVJlbGVhc2VzV2l0aChkZWZhdWx0RGVwcywgb3JnSWQpO1xufVxuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gQ2FsbGVyIGhlbHBlcnNcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbi8qKlxuICogRWFjaCByZXNvbHZlciByZWZ1c2FsIGNvZGUncyBzdGVwLXJlc29sdXRpb24gcmVmdXNhbCAoYW55dGhpbmcgZWxzZSBpc1xuICogYHRvb2xjaGFpbl91bnJlc29sdmVkYCkuIGBkZXRhaWxzYCByaWRlcyBhbG9uZyBleGNlcHQgZm9yIE5PX0RFRkFVTFQsIHdoaWNoXG4gKiBjYXJyaWVzIG5vbmUgd29ydGggc2hvd2luZy5cbiAqL1xuY29uc3QgUkVGVVNBTF9CWV9DT0RFOiBQYXJ0aWFsPFJlY29yZDxFcnJvckNvZGUsIHsgY29kZTogUmVzb2x1dGlvblJlZnVzYWxbJ2NvZGUnXTsgcmVhc29uOiBzdHJpbmc7IGRldGFpbHM6IGJvb2xlYW4gfT4+ID0ge1xuICBbRXJyb3JDb2RlLk5PVF9GT1VORF06IHsgY29kZTogJ05PVF9GT1VORCcsIHJlYXNvbjogJ3Rvb2xjaGFpbl9yZWxlYXNlX25vdF9mb3VuZCcsIGRldGFpbHM6IHRydWUgfSxcbiAgW0Vycm9yQ29kZS5WQUxJREFUSU9OX0VSUk9SXTogeyBjb2RlOiAnTk9UX0ZPVU5EJywgcmVhc29uOiAndG9vbGNoYWluX3JlbGVhc2VfaW52YWxpZCcsIGRldGFpbHM6IHRydWUgfSxcbiAgW0Vycm9yQ29kZS5UT09MQ0hBSU5fTk9fREVGQVVMVF06IHsgY29kZTogJ1BMVUdJTl9VTkFWQUlMQUJMRScsIHJlYXNvbjogJ3Rvb2xjaGFpbl9ub19kZWZhdWx0JywgZGV0YWlsczogZmFsc2UgfSxcbn07XG5jb25zdCBVTlJFU09MVkVEX1JFRlVTQUwgPSB7IGNvZGU6ICdQTFVHSU5fVU5BVkFJTEFCTEUnLCByZWFzb246ICd0b29sY2hhaW5fdW5yZXNvbHZlZCcsIGRldGFpbHM6IHRydWUgfSBhcyBjb25zdDtcblxuLyoqIFRoZSByZXNvbHZlcidzIGVycm9yIGFzIHRoZSByZWZ1c2FsIHNoYXBlIHN0ZXAgcmVzb2x1dGlvbiByZXBvcnRzIChjb250cmFjdCBjaGVjaywgZGVjbGFyZWQgc2lkZSwgZmFjdHMpLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1hbmFnZWRUb29sY2hhaW5SZWZ1c2FsKGVycjogTWFuYWdlZFRvb2xjaGFpbkVycm9yKTogUmVzb2x1dGlvblJlZnVzYWwge1xuICBjb25zdCByID0gUkVGVVNBTF9CWV9DT0RFW2Vyci5jb2RlIGFzIEVycm9yQ29kZV0gPz8gVU5SRVNPTFZFRF9SRUZVU0FMO1xuICByZXR1cm4geyBjb2RlOiByLmNvZGUsIHJlYXNvbjogci5yZWFzb24sIG1lc3NhZ2U6IGVyci5tZXNzYWdlLCAuLi4oci5kZXRhaWxzICYmIGVyci5kZXRhaWxzID8geyBkZXRhaWxzOiBlcnIuZGV0YWlscyB9IDoge30pIH07XG59XG5cbi8qKlxuICogUmVzb2x2ZSBPTkUgbWFuYWdlZCBoYWxmIGZvciBhIHN0ZXA6IHRoZSBwbHVnaW4gcm93IHBsdXMgdGhlIHJlc29sdXRpb24sIG9yXG4gKiB0aGUgcmVmdXNhbC4gQW55IG5vbi1yZXNvbHZlciBlcnJvciAoYSBkYXRhYmFzZSBvciBoaWVyYXJjaHkgZmFpbHVyZSlcbiAqIHByb3BhZ2F0ZXMuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZXNvbHZlTWFuYWdlZFRvb2xjaGFpbkhhbGYoXG4gIGNhbGxlcjogTWFuYWdlZFRvb2xjaGFpbkNhbGxlcixcbiAgbmFtZTogTWFuYWdlZFRvb2xjaGFpblBsdWdpbixcbiAgb3B0czogeyByZWxlYXNlUGluPzogc3RyaW5nIH0gPSB7fSxcbik6IFByb21pc2U8eyBwbHVnaW46IFBsdWdpbjsgcmVzb2x1dGlvbjogTWFuYWdlZFRvb2xjaGFpblJlc29sdXRpb24gfSB8IHsgcmVmdXNhbDogUmVzb2x1dGlvblJlZnVzYWw7IGVycm9yOiBNYW5hZ2VkVG9vbGNoYWluRXJyb3IgfT4ge1xuICB0cnkge1xuICAgIGNvbnN0IHJlc29sdXRpb24gPSBhd2FpdCByZXNvbHZlTWFuYWdlZFRvb2xjaGFpbihjYWxsZXIsIG9wdHMpO1xuICAgIHJldHVybiB7IHBsdWdpbjogbmFtZSA9PT0gQk9PVFNUUkFQID8gcmVzb2x1dGlvbi5ib290c3RyYXAgOiByZXNvbHV0aW9uLnN5bnRoLCByZXNvbHV0aW9uIH07XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGlmIChlcnIgaW5zdGFuY2VvZiBNYW5hZ2VkVG9vbGNoYWluRXJyb3IpIHJldHVybiB7IHJlZnVzYWw6IG1hbmFnZWRUb29sY2hhaW5SZWZ1c2FsKGVyciksIGVycm9yOiBlcnIgfTtcbiAgICB0aHJvdyBlcnI7XG4gIH1cbn1cbiJdfQ==
|
|
@@ -26,22 +26,11 @@
|
|
|
26
26
|
* name (typo tolerance), ranked by `ts_rank` + name similarity, blended with the
|
|
27
27
|
* Bayesian rating and install count when present. Paused listings are hidden.
|
|
28
28
|
*/
|
|
29
|
-
import {
|
|
29
|
+
import type { PublisherTier } from '@pipeline-builder/api-core';
|
|
30
30
|
import type { HealthBreakdown } from '../database/drizzle-schema.js';
|
|
31
|
-
/**
|
|
32
|
-
* DERIVED from api-core's canonical `PUBLISHER_TIERS`, not restated.
|
|
33
|
-
*
|
|
34
|
-
* This was a hand-written copy of the same four values, and the copy is what
|
|
35
|
-
* the public route's zod enum validated — while the view types in the same
|
|
36
|
-
* package already used `PublisherTier`. A fifth tier would have been stored and
|
|
37
|
-
* displayed and then silently unfilterable, because the filter would still only
|
|
38
|
-
* accept the four this list remembered.
|
|
39
|
-
*/
|
|
40
|
-
export type DirectoryTrustTier = PublisherTier;
|
|
41
31
|
export type DirectoryIconKind = 'vendor' | 'uploaded' | 'monogram' | 'category';
|
|
42
32
|
export type DirectorySort = 'relevance' | 'rating' | 'installs' | 'updated' | 'name' | 'health';
|
|
43
33
|
export declare const DIRECTORY_SORTS: readonly DirectorySort[];
|
|
44
|
-
export declare const DIRECTORY_TIERS: readonly DirectoryTrustTier[];
|
|
45
34
|
/** Minimum `word_similarity(query, name)` for a fuzzy name match (typo tolerance). */
|
|
46
35
|
export declare const FUZZY_NAME_THRESHOLD = 0.3;
|
|
47
36
|
/** Max query length accepted (longer is truncated, never an error). */
|
|
@@ -51,7 +40,7 @@ export declare const DIRECTORY_MAX_LIMIT = 60;
|
|
|
51
40
|
export interface DirectorySearchParams {
|
|
52
41
|
q?: string;
|
|
53
42
|
category?: string;
|
|
54
|
-
tier?:
|
|
43
|
+
tier?: PublisherTier;
|
|
55
44
|
license?: string;
|
|
56
45
|
computeType?: string;
|
|
57
46
|
needsSecrets?: boolean;
|
|
@@ -64,7 +53,7 @@ export interface DirectoryListingCard {
|
|
|
64
53
|
publisher: {
|
|
65
54
|
handle: string;
|
|
66
55
|
displayName: string;
|
|
67
|
-
tier:
|
|
56
|
+
tier: PublisherTier;
|
|
68
57
|
};
|
|
69
58
|
name: string;
|
|
70
59
|
summary: string;
|
|
@@ -248,7 +237,7 @@ export interface PublicListingRow {
|
|
|
248
237
|
id: string;
|
|
249
238
|
publisher_handle: string;
|
|
250
239
|
publisher_display_name: string;
|
|
251
|
-
publisher_tier:
|
|
240
|
+
publisher_tier: PublisherTier;
|
|
252
241
|
name: string;
|
|
253
242
|
category: string;
|
|
254
243
|
summary: string | null;
|