semantifold 0.7.0 → 0.9.0

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.
@@ -0,0 +1,1643 @@
1
+ // @ts-check
2
+ import { createHash, randomUUID } from "node:crypto";
3
+ import { constants } from "node:fs";
4
+ import { lstat, mkdir, open, readFile, readdir, realpath, rename, rm } from "node:fs/promises";
5
+ import path from "node:path";
6
+ import { findPortableArtifactPathConflict, isSafeArtifactPath } from "./artifact-path.js";
7
+ import { createGeneratedArtifactSet } from "./artifacts.js";
8
+ import { finalizeByteMapping } from "./binary-mapping.js";
9
+ import { SemantifoldDiagnostic } from "./diagnostic.js";
10
+ import { finalizeMapping, toSourceMapV3 } from "./mapping.js";
11
+ const activePointerName = "active-generation.json";
12
+ const generationsName = "generations";
13
+ const journalName = ".semantifold-publication-journal";
14
+ const identityPattern = /^[a-z][a-z0-9-]*$/u;
15
+ const generationPattern = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u;
16
+ const buildRolePattern = /^[a-z][a-z0-9-]*$/u;
17
+ const mediaTypePattern = /^[A-Za-z0-9!#$&^_.+-]+\/[A-Za-z0-9!#$&^_.+-]+(?:;[\u0020-\u007e]+)?$/u;
18
+ const targetRoles = new Set(["application", "binary", "text"]);
19
+ const publicationBoundaries = new Set([
20
+ "after-stage",
21
+ "before-pointer-replace",
22
+ "after-pointer-replace",
23
+ "before-cleanup",
24
+ "before-journal-remove"
25
+ ]);
26
+ /** @type {WeakMap<GeneratedArtifactPublisher, {boundary: string, error: Error}>} */
27
+ const injectedPublicationFailures = new WeakMap();
28
+ /** @type {WeakMap<GeneratedArtifactPublisher, (operation: string) => void>} */
29
+ const publicationFilesystemObservers = new WeakMap();
30
+ /**
31
+ * Installs one internal, one-shot deterministic failure used by real-filesystem interruption specs.
32
+ * This helper is intentionally not part of the package root API.
33
+ * @param {GeneratedArtifactPublisher} publisher - Publisher instance.
34
+ * @param {"after-stage" | "before-pointer-replace" | "after-pointer-replace" | "before-cleanup" | "before-journal-remove"} boundary - Exact lifecycle boundary.
35
+ * @param {Error} error - Injected failure.
36
+ * @returns {void}
37
+ */
38
+ export function injectPublicationFailure(publisher, boundary, error) {
39
+ if (!(publisher instanceof GeneratedArtifactPublisher) || !publicationBoundaries.has(boundary) || !(error instanceof Error)) {
40
+ throw new TypeError("Invalid publication failure injection.");
41
+ }
42
+ injectedPublicationFailures.set(publisher, { boundary, error });
43
+ }
44
+ /**
45
+ * Installs an internal deterministic filesystem-operation observer for durability specs.
46
+ * This helper is intentionally not part of the package root API.
47
+ * @param {GeneratedArtifactPublisher} publisher - Publisher instance.
48
+ * @param {(operation: string) => void} observer - Synchronous operation observer.
49
+ * @returns {void}
50
+ */
51
+ export function observePublicationFilesystem(publisher, observer) {
52
+ if (!(publisher instanceof GeneratedArtifactPublisher) || typeof observer != "function") {
53
+ throw new TypeError("Invalid publication filesystem observer.");
54
+ }
55
+ publicationFilesystemObservers.set(publisher, observer);
56
+ }
57
+ /**
58
+ * Owns transactional publication in one dedicated directory beneath a canonical project root.
59
+ */
60
+ export class GeneratedArtifactPublisher {
61
+ /** @type {string} */
62
+ #projectId;
63
+ /** @type {string} */
64
+ #projectRoot;
65
+ /** @type {string} */
66
+ #publicationRoot;
67
+ /** @type {readonly string[]} */
68
+ #sourceRoots;
69
+ /** @type {Promise<void>} */
70
+ #publicationTail = Promise.resolve();
71
+ /**
72
+ * Creates a project-scoped publisher without touching the filesystem.
73
+ * @param {object} options - Publisher identity and owned paths.
74
+ * @param {string} options.projectId - Stable lowercase project identity.
75
+ * @param {string} options.projectRoot - Canonical absolute project root.
76
+ * @param {string} options.publicationRoot - Canonical absolute publisher-owned directory beneath the project root.
77
+ * @param {readonly string[]} options.sourceRoots - Canonical absolute project source roots kept disjoint from publication.
78
+ */
79
+ constructor(options) {
80
+ if (!isPlainObject(options)) {
81
+ publicationFailure("INVALID_PUBLICATION_REQUEST", "publication", "Publisher options must be a plain object.");
82
+ }
83
+ const { projectId, projectRoot, publicationRoot, sourceRoots } = options;
84
+ if (!identityPattern.test(projectId ?? "")) {
85
+ publicationFailure("INVALID_PUBLICATION_REQUEST", "publication", "Project identity must be a stable lowercase ID.");
86
+ }
87
+ if (!isCanonicalAbsolutePath(projectRoot) || !isCanonicalAbsolutePath(publicationRoot) ||
88
+ !isStrictPathDescendant(projectRoot, publicationRoot)) {
89
+ publicationFailure("INVALID_PUBLICATION_ROOT", projectId, "Project and publication roots must be canonical absolute paths with publication strictly beneath the project root.");
90
+ }
91
+ if (!isDenseArray(sourceRoots) || sourceRoots.length == 0) {
92
+ publicationFailure("INVALID_PUBLICATION_ROOT", projectId, "Source roots must be a non-empty array of canonical absolute paths.");
93
+ }
94
+ /** @type {string[]} */
95
+ const validatedSourceRoots = [];
96
+ for (let index = 0; index < sourceRoots.length; index += 1) {
97
+ const sourceRoot = sourceRoots[index];
98
+ if (!isCanonicalAbsolutePath(sourceRoot)) {
99
+ publicationFailure("INVALID_PUBLICATION_ROOT", projectId, "Source roots must be a non-empty array of canonical absolute paths.");
100
+ }
101
+ if (!isPathWithin(projectRoot, sourceRoot)) {
102
+ publicationFailure("INVALID_PUBLICATION_ROOT", projectId, "Source roots must remain within the canonical project root.");
103
+ }
104
+ if (pathsOverlap(publicationRoot, sourceRoot)) {
105
+ publicationFailure("PUBLICATION_SOURCE_OVERLAP", projectId, "Publication root and source roots must be disjoint.");
106
+ }
107
+ validatedSourceRoots.push(sourceRoot);
108
+ }
109
+ this.#projectId = projectId;
110
+ this.#projectRoot = projectRoot;
111
+ this.#publicationRoot = publicationRoot;
112
+ this.#sourceRoots = Object.freeze(validatedSourceRoots);
113
+ }
114
+ /**
115
+ * Stages, validates, and publishes one complete immutable project generation.
116
+ * Calls on one publisher instance are serialized in invocation order.
117
+ * @param {import("./semantic/types.js").PublicationRequest} request - Complete publication request.
118
+ * @returns {Promise<import("./semantic/types.js").PublishedGeneration>} Committed immutable snapshot.
119
+ */
120
+ publish(request) {
121
+ /** @type {(value: import("./semantic/types.js").PublishedGeneration) => void} */
122
+ let resolveResult;
123
+ /** @type {(reason?: unknown) => void} */
124
+ let rejectResult;
125
+ const result = new Promise((resolve, reject) => {
126
+ resolveResult = resolve;
127
+ rejectResult = reject;
128
+ });
129
+ const operation = this.#publicationTail.then(async () => {
130
+ try {
131
+ resolveResult(await this.#publish(request));
132
+ }
133
+ catch (error) {
134
+ rejectResult(error);
135
+ }
136
+ });
137
+ this.#publicationTail = operation.catch(() => { });
138
+ return result;
139
+ }
140
+ /**
141
+ * Resolves the active pointer exactly once and verifies the referenced immutable generation.
142
+ * @returns {Promise<import("./semantic/types.js").PublishedGeneration>} Verified pointer-once snapshot.
143
+ */
144
+ async resolveActive() {
145
+ await this.#prepareRoot();
146
+ const pointerPath = path.join(this.#publicationRoot, activePointerName);
147
+ const pointer = await readActivePointer(pointerPath, this.#projectId, false);
148
+ if (!pointer)
149
+ publicationFailure("ACTIVE_GENERATION_MISSING", this.#projectId, "No active generation has been published.");
150
+ const generation = await verifyPublishedGeneration(this.#publicationRoot, this.#projectId, pointer, false);
151
+ const cleanupPending = await hasCommittedCleanupJournal(this.#publicationRoot, this.#projectId, pointer.generationId);
152
+ return publishedGeneration(this.#publicationRoot, generation.manifest, cleanupPending);
153
+ }
154
+ /**
155
+ * Performs one serialized publication.
156
+ * @param {import("./semantic/types.js").PublicationRequest} request - Complete request.
157
+ * @returns {Promise<import("./semantic/types.js").PublishedGeneration>} Publication result.
158
+ */
159
+ async #publish(request) {
160
+ const validated = validatePublicationRequest(request, this.#projectId);
161
+ await this.#prepareRoot();
162
+ await reconcilePublication(this.#publicationRoot, this.#projectId, this);
163
+ await verifyAtomicReplacement(this.#publicationRoot, this.#projectId);
164
+ await validateExistingPointer(this.#publicationRoot, this.#projectId);
165
+ const generationPath = path.join(this.#publicationRoot, generationsName, validated.generationId);
166
+ const manifestPath = path.join(generationPath, "manifest.json");
167
+ const tempPointerName = `.active-generation.${validated.generationId}.tmp`;
168
+ const tempPointerPath = path.join(this.#publicationRoot, tempPointerName);
169
+ const journalPath = path.join(this.#publicationRoot, journalName, `${validated.generationId}.json`);
170
+ let committed = false;
171
+ let journalCreated = false;
172
+ let generationCreated = false;
173
+ let tempPointerCreated = false;
174
+ let failureCode = "PUBLICATION_STAGE_WRITE_FAILED";
175
+ try {
176
+ await assertAbsent(generationPath, "PUBLICATION_UNOWNED_CONFLICT", this.#projectId, "Generation identity is already owned or ambiguous.");
177
+ await assertAbsent(tempPointerPath, "PUBLICATION_UNOWNED_CONFLICT", this.#projectId, "Temporary active pointer path is already owned or ambiguous.");
178
+ await assertAbsent(journalPath, "PUBLICATION_UNOWNED_CONFLICT", this.#projectId, "Publication journal identity is already owned or ambiguous.");
179
+ const journal = {
180
+ generationId: validated.generationId,
181
+ projectId: this.#projectId,
182
+ schema: "SemantifoldPublicationJournal",
183
+ tempPointer: tempPointerName,
184
+ version: 1
185
+ };
186
+ await writeSyncedFile(journalPath, serializeJson(journal), "wx");
187
+ journalCreated = true;
188
+ await syncDirectory(path.dirname(journalPath));
189
+ await mkdir(generationPath, { mode: 0o700 });
190
+ generationCreated = true;
191
+ await syncDirectory(path.dirname(generationPath));
192
+ /** @type {import("./semantic/types.js").GenerationTargetManifest[]} */
193
+ const targetManifests = [];
194
+ for (const target of validated.targets) {
195
+ targetManifests.push(await stageTarget(generationPath, target, this.#projectId));
196
+ }
197
+ reachPublicationBoundary(this, "after-stage");
198
+ const manifestCandidate = /** @type {import("./semantic/types.js").GenerationManifest} */ ({
199
+ generationId: validated.generationId,
200
+ projectId: this.#projectId,
201
+ schema: /** @type {const} */ ("SemantifoldGenerationManifest"),
202
+ targets: targetManifests,
203
+ version: /** @type {const} */ (1)
204
+ });
205
+ const manifestBytes = serializeJson(manifestCandidate);
206
+ const manifest = validateGenerationManifest(JSON.parse(manifestBytes.toString("utf8")), this.#projectId, validated.generationId);
207
+ await writeSyncedFile(manifestPath, manifestBytes, "wx");
208
+ await syncTreeDirectories(generationPath);
209
+ await verifyManifestFiles(generationPath, manifest, this.#projectId);
210
+ failureCode = "PUBLICATION_POINTER_FAILED";
211
+ const pointer = {
212
+ generationId: validated.generationId,
213
+ manifestHash: sha256(manifestBytes),
214
+ projectId: this.#projectId,
215
+ schema: "SemantifoldActiveGeneration",
216
+ version: 1
217
+ };
218
+ await writeSyncedFile(tempPointerPath, serializeJson(pointer), "wx", () => {
219
+ tempPointerCreated = true;
220
+ });
221
+ reachPublicationBoundary(this, "before-pointer-replace");
222
+ await rename(tempPointerPath, path.join(this.#publicationRoot, activePointerName));
223
+ tempPointerCreated = false;
224
+ committed = true;
225
+ reachPublicationBoundary(this, "after-pointer-replace");
226
+ await syncDirectory(this.#publicationRoot);
227
+ let cleanupPending = false;
228
+ try {
229
+ reachPublicationBoundary(this, "before-cleanup");
230
+ await removeJournalOwnedState({
231
+ journalPath,
232
+ projectId: this.#projectId,
233
+ publicationRoot: this.#publicationRoot,
234
+ publisher: this
235
+ });
236
+ }
237
+ catch (_error) {
238
+ cleanupPending = true;
239
+ }
240
+ return publishedGeneration(this.#publicationRoot, deepFreeze(manifest), cleanupPending);
241
+ }
242
+ catch (error) {
243
+ if (!committed) {
244
+ try {
245
+ await removeJournalOwnedState({
246
+ ...(generationCreated ? { candidatePath: generationPath } : {}),
247
+ ...(journalCreated ? { journalPath } : {}),
248
+ projectId: this.#projectId,
249
+ publicationRoot: this.#publicationRoot,
250
+ publisher: this,
251
+ ...(tempPointerCreated ? { temporaryPointerPath: tempPointerPath } : {})
252
+ });
253
+ }
254
+ catch (cleanupError) {
255
+ if (cleanupError instanceof SemantifoldDiagnostic)
256
+ throw cleanupError;
257
+ publicationFailure("PUBLICATION_RECOVERY_FAILED", this.#projectId, "Failed publication left state that requires recovery.", cleanupError);
258
+ }
259
+ }
260
+ if (error instanceof SemantifoldDiagnostic)
261
+ throw error;
262
+ publicationFailure(failureCode, this.#projectId, committed
263
+ ? "Active generation changed, but durable pointer publication did not complete."
264
+ : "Candidate generation could not be staged.", error);
265
+ }
266
+ }
267
+ /**
268
+ * Creates and validates owned root directories and source-root separation.
269
+ * @returns {Promise<void>} Completion.
270
+ */
271
+ async #prepareRoot() {
272
+ await ensureDirectoryWithoutSymlinks(this.#projectRoot, false, this.#projectId);
273
+ await ensureDirectoryWithoutSymlinks(this.#publicationRoot, true, this.#projectId);
274
+ let exactProject;
275
+ let exactPublication;
276
+ try {
277
+ exactProject = await realpath(this.#projectRoot);
278
+ exactPublication = await realpath(this.#publicationRoot);
279
+ }
280
+ catch (error) {
281
+ publicationFailure("INVALID_PUBLICATION_ROOT", this.#projectId, "Publication root could not be resolved safely.", error);
282
+ }
283
+ if (!isStrictPathDescendant(exactProject, exactPublication)) {
284
+ publicationFailure("INVALID_PUBLICATION_ROOT", this.#projectId, "Publication root must resolve strictly beneath the project root.");
285
+ }
286
+ for (const sourceRoot of this.#sourceRoots) {
287
+ await ensureDirectoryWithoutSymlinks(sourceRoot, false, this.#projectId);
288
+ let exactSource;
289
+ try {
290
+ exactSource = await realpath(sourceRoot);
291
+ }
292
+ catch (error) {
293
+ publicationFailure("INVALID_PUBLICATION_ROOT", this.#projectId, "Source root could not be resolved safely.", error);
294
+ }
295
+ if (!isPathWithin(exactProject, exactSource)) {
296
+ publicationFailure("INVALID_PUBLICATION_ROOT", this.#projectId, "Source roots must resolve within the project root.");
297
+ }
298
+ if (pathsOverlap(exactPublication, exactSource)) {
299
+ publicationFailure("PUBLICATION_SOURCE_OVERLAP", this.#projectId, "Publication root and source roots resolve to overlapping paths.");
300
+ }
301
+ }
302
+ await ensureOwnedDirectory(path.join(this.#publicationRoot, generationsName), this.#projectId);
303
+ await ensureOwnedDirectory(path.join(this.#publicationRoot, journalName), this.#projectId);
304
+ }
305
+ }
306
+ /**
307
+ * Throws and consumes a configured internal failure at an exact lifecycle boundary.
308
+ * @param {GeneratedArtifactPublisher} publisher - Active publisher.
309
+ * @param {string} boundary - Reached boundary.
310
+ * @returns {void}
311
+ */
312
+ function reachPublicationBoundary(publisher, boundary) {
313
+ const injection = injectedPublicationFailures.get(publisher);
314
+ if (injection?.boundary == boundary) {
315
+ injectedPublicationFailures.delete(publisher);
316
+ throw injection.error;
317
+ }
318
+ }
319
+ /**
320
+ * Reports one completed filesystem operation to the internal deterministic seam.
321
+ * @param {GeneratedArtifactPublisher} publisher - Active publisher.
322
+ * @param {string} operation - Completed operation.
323
+ * @returns {void}
324
+ */
325
+ function observePublicationFilesystemOperation(publisher, operation) {
326
+ publicationFilesystemObservers.get(publisher)?.(operation);
327
+ }
328
+ /**
329
+ * Reconciles only candidates and temporary pointers whose ownership is proven by a strict journal.
330
+ * The active pointer remains the sole commit authority.
331
+ * @param {string} publicationRoot - Publication root.
332
+ * @param {string} projectId - Project identity.
333
+ * @param {GeneratedArtifactPublisher} publisher - Active publisher.
334
+ * @returns {Promise<void>} Completion.
335
+ */
336
+ async function reconcilePublication(publicationRoot, projectId, publisher) {
337
+ const journals = await readPublicationJournals(publicationRoot, projectId);
338
+ if (journals.length == 0)
339
+ return;
340
+ const pointer = await readActivePointer(path.join(publicationRoot, activePointerName), projectId, true);
341
+ if (pointer)
342
+ await verifyPublishedGeneration(publicationRoot, projectId, pointer, true);
343
+ for (const { journal, journalPath } of journals) {
344
+ const candidatePath = ownedPath(path.join(publicationRoot, generationsName), journal.generationId, projectId);
345
+ const temporaryPointerPath = path.join(publicationRoot, journal.tempPointer);
346
+ const committed = pointer?.generationId == journal.generationId;
347
+ if (!committed) {
348
+ const candidateStatus = await optionalStatus(candidatePath, projectId, "candidate generation");
349
+ if (candidateStatus) {
350
+ if (!candidateStatus.isDirectory() || candidateStatus.isSymbolicLink()) {
351
+ publicationFailure("PUBLICATION_RECOVERY_FAILED", projectId, "Journal-owned candidate is not a real directory.");
352
+ }
353
+ }
354
+ }
355
+ const temporaryStatus = await optionalStatus(temporaryPointerPath, projectId, "temporary pointer");
356
+ if (temporaryStatus) {
357
+ if (!temporaryStatus.isFile() || temporaryStatus.isSymbolicLink()) {
358
+ publicationFailure("PUBLICATION_RECOVERY_FAILED", projectId, "Journal-owned temporary pointer is not a regular file.");
359
+ }
360
+ }
361
+ await removeJournalOwnedState({
362
+ ...(!committed ? { candidatePath } : {}),
363
+ journalPath,
364
+ projectId,
365
+ publicationRoot,
366
+ publisher,
367
+ temporaryPointerPath
368
+ });
369
+ }
370
+ }
371
+ /**
372
+ * Reads and validates every recovery journal without changing publication state.
373
+ * @param {string} publicationRoot - Publication root.
374
+ * @param {string} projectId - Project identity.
375
+ * @returns {Promise<readonly {journal: PublicationJournal, journalPath: string}[]>} Ordered journals.
376
+ */
377
+ async function readPublicationJournals(publicationRoot, projectId) {
378
+ const journalDirectory = path.join(publicationRoot, journalName);
379
+ let entries;
380
+ try {
381
+ entries = await readdir(journalDirectory);
382
+ }
383
+ catch (error) {
384
+ publicationFailure("PUBLICATION_RECOVERY_FAILED", projectId, "Publication journal directory could not be inspected.", error);
385
+ }
386
+ entries.sort(compareStrings);
387
+ /** @type {{journal: PublicationJournal, journalPath: string}[]} */
388
+ const journals = [];
389
+ for (const entry of entries) {
390
+ if (!entry.endsWith(".json") || !generationPattern.test(entry.slice(0, -5))) {
391
+ publicationFailure("PUBLICATION_RECOVERY_FAILED", projectId, "Publication journal contains an unrecognized entry.");
392
+ }
393
+ const journalPath = path.join(journalDirectory, entry);
394
+ let journal;
395
+ try {
396
+ const status = await lstat(journalPath);
397
+ if (!status.isFile() || status.isSymbolicLink()) {
398
+ publicationFailure("PUBLICATION_RECOVERY_FAILED", projectId, "Publication journal entry must be a regular file.");
399
+ }
400
+ journal = JSON.parse(await readFile(journalPath, "utf8"));
401
+ }
402
+ catch (error) {
403
+ if (error instanceof SemantifoldDiagnostic)
404
+ throw error;
405
+ publicationFailure("PUBLICATION_RECOVERY_FAILED", projectId, "Publication journal entry is not valid JSON.", error);
406
+ }
407
+ if (!isPublicationJournal(journal) || journal.projectId != projectId || `${journal.generationId}.json` != entry) {
408
+ publicationFailure("PUBLICATION_RECOVERY_FAILED", projectId, "Publication journal entry does not match the versioned project contract.");
409
+ }
410
+ journals.push({ journal, journalPath });
411
+ }
412
+ return Object.freeze(journals);
413
+ }
414
+ /**
415
+ * Reports committed cleanup state while failing closed on every journal entry.
416
+ * @param {string} publicationRoot - Publication root.
417
+ * @param {string} projectId - Project identity.
418
+ * @param {string} generationId - Pointer-selected generation identity.
419
+ * @returns {Promise<boolean>} Whether committed cleanup remains.
420
+ */
421
+ async function hasCommittedCleanupJournal(publicationRoot, projectId, generationId) {
422
+ const journals = await readPublicationJournals(publicationRoot, projectId);
423
+ return journals.some(({ journal }) => journal.generationId == generationId);
424
+ }
425
+ /**
426
+ * Removes proven journal-owned state and durably synchronizes each parent before discarding its ownership proof.
427
+ * @param {object} options - Exact cleanup state.
428
+ * @param {string} [options.candidatePath] - Proven candidate generation path.
429
+ * @param {string} [options.temporaryPointerPath] - Proven temporary pointer path.
430
+ * @param {string} [options.journalPath] - Ownership journal path.
431
+ * @param {string} options.projectId - Project identity.
432
+ * @param {string} options.publicationRoot - Publication root.
433
+ * @param {GeneratedArtifactPublisher} options.publisher - Active publisher.
434
+ * @returns {Promise<void>} Completion.
435
+ */
436
+ async function removeJournalOwnedState({ candidatePath, journalPath, projectId, publicationRoot, publisher, temporaryPointerPath }) {
437
+ try {
438
+ if (candidatePath) {
439
+ await rm(candidatePath, { force: true, recursive: true });
440
+ observePublicationFilesystemOperation(publisher, "remove-candidate");
441
+ await syncDirectory(path.join(publicationRoot, generationsName));
442
+ observePublicationFilesystemOperation(publisher, "sync-candidate-parent");
443
+ }
444
+ if (temporaryPointerPath) {
445
+ await rm(temporaryPointerPath, { force: true });
446
+ observePublicationFilesystemOperation(publisher, "remove-temporary-pointer");
447
+ await syncDirectory(publicationRoot);
448
+ observePublicationFilesystemOperation(publisher, "sync-temporary-pointer-parent");
449
+ }
450
+ if (journalPath) {
451
+ reachPublicationBoundary(publisher, "before-journal-remove");
452
+ await rm(journalPath);
453
+ observePublicationFilesystemOperation(publisher, "remove-journal");
454
+ await syncDirectory(path.dirname(journalPath));
455
+ observePublicationFilesystemOperation(publisher, "sync-journal-parent");
456
+ }
457
+ }
458
+ catch (error) {
459
+ if (error instanceof SemantifoldDiagnostic)
460
+ throw error;
461
+ publicationFailure("PUBLICATION_RECOVERY_FAILED", projectId, "Journal-owned publication state could not be durably reconciled.", error);
462
+ }
463
+ }
464
+ /**
465
+ * Reads optional metadata without following symbolic links.
466
+ * @param {string} filename - Exact owned path.
467
+ * @param {string} projectId - Project identity.
468
+ * @param {string} subject - Stable subject description.
469
+ * @returns {Promise<import("node:fs").Stats | null>} Status or absence.
470
+ */
471
+ async function optionalStatus(filename, projectId, subject) {
472
+ try {
473
+ return await lstat(filename);
474
+ }
475
+ catch (error) {
476
+ if (isErrorCode(error, "ENOENT"))
477
+ return null;
478
+ publicationFailure("PUBLICATION_RECOVERY_FAILED", projectId, `Journal-owned ${subject} could not be inspected.`, error);
479
+ }
480
+ }
481
+ /**
482
+ * Validates and snapshots one publication request before staging.
483
+ * @param {unknown} request - Request candidate.
484
+ * @param {string} projectId - Project diagnostic identity.
485
+ * @returns {{generationId: string, targets: readonly ValidatedPublicationTarget[]}} Validated request.
486
+ */
487
+ function validatePublicationRequest(request, projectId) {
488
+ if (!isPlainObject(request)) {
489
+ publicationFailure("INVALID_PUBLICATION_REQUEST", projectId, "Publication requires a unique generation ID and a non-empty ordered target array.");
490
+ }
491
+ const generationId = request.generationId;
492
+ const requestedTargets = request.targets;
493
+ if (typeof generationId != "string" || !generationPattern.test(generationId) ||
494
+ !isDenseArray(requestedTargets) || requestedTargets.length == 0) {
495
+ publicationFailure("INVALID_PUBLICATION_REQUEST", projectId, "Publication requires a unique generation ID and a non-empty ordered target array.");
496
+ }
497
+ /** @type {ValidatedPublicationTarget[]} */
498
+ const targets = [];
499
+ const targetIds = new Set();
500
+ /** @type {string[]} */
501
+ const projections = [];
502
+ /** @type {string[]} */
503
+ const completeArtifactPaths = [];
504
+ for (let index = 0; index < requestedTargets.length; index += 1) {
505
+ const target = requestedTargets[index];
506
+ if (!isPlainObject(target)) {
507
+ publicationFailure("INVALID_PUBLICATION_REQUEST", projectId, `Target ${index} requires a stable lowercase identity.`);
508
+ }
509
+ const targetId = target.id;
510
+ const role = target.role;
511
+ const sourceProjection = target.sourceProjection;
512
+ const buildProjection = target.buildProjection;
513
+ const artifactSetCandidate = target.artifactSet;
514
+ const validatorsCandidate = target.validators;
515
+ if (typeof targetId != "string" || !identityPattern.test(targetId)) {
516
+ publicationFailure("INVALID_PUBLICATION_REQUEST", projectId, `Target ${index} requires a stable lowercase identity.`);
517
+ }
518
+ if (typeof role != "string" || !targetRoles.has(role)) {
519
+ publicationFailure("INVALID_PUBLICATION_REQUEST", projectId, `Target '${targetId}' requires an explicit language-neutral role.`);
520
+ }
521
+ if (targetIds.has(targetId)) {
522
+ publicationFailure("PUBLICATION_PATH_COLLISION", projectId, `Duplicate target identity '${targetId}'.`);
523
+ }
524
+ targetIds.add(targetId);
525
+ if (!isSafeArtifactPath(sourceProjection) || !isSafeArtifactPath(buildProjection)) {
526
+ publicationFailure("INVALID_PUBLICATION_PROJECTION", projectId, `Target '${targetId}' requires canonical relative source and build projections.`);
527
+ }
528
+ projections.push(sourceProjection, buildProjection);
529
+ let artifactSet;
530
+ try {
531
+ artifactSet = createGeneratedArtifactSet(artifactSetCandidate);
532
+ }
533
+ catch (error) {
534
+ publicationFailure("INVALID_PUBLICATION_REQUEST", projectId, `Target '${targetId}' does not contain a valid generated artifact set.`, error);
535
+ }
536
+ const validators = validatorsCandidate === undefined ? [] : validatorsCandidate;
537
+ if (!isDenseArray(validators)) {
538
+ publicationFailure("INVALID_PUBLICATION_REQUEST", projectId, `Target '${targetId}' validators must be a dense function array.`);
539
+ }
540
+ /** @type {import("./semantic/types.js").PublicationValidator[]} */
541
+ const validatedValidators = [];
542
+ for (let validatorIndex = 0; validatorIndex < validators.length; validatorIndex += 1) {
543
+ const validator = validators[validatorIndex];
544
+ if (typeof validator != "function") {
545
+ publicationFailure("INVALID_PUBLICATION_REQUEST", projectId, `Target '${targetId}' validators must be a dense function array.`);
546
+ }
547
+ validatedValidators.push(/** @type {import("./semantic/types.js").PublicationValidator} */ (validator));
548
+ }
549
+ const artifactConflict = findPortableArtifactPathConflict(artifactSet.artifacts.map(({ path: artifactPath }) => artifactPath));
550
+ if (artifactConflict) {
551
+ publicationFailure("PUBLICATION_PATH_COLLISION", projectId, `Target '${targetId}' artifact paths have a portable ${artifactConflict.kind} conflict.`);
552
+ }
553
+ for (const artifact of artifactSet.artifacts) {
554
+ completeArtifactPaths.push(`${sourceProjection}/${artifact.path}`);
555
+ }
556
+ targets.push(Object.freeze({
557
+ artifactSet,
558
+ buildProjection,
559
+ id: targetId,
560
+ role: /** @type {import("./semantic/types.js").PublicationTargetRole} */ (role),
561
+ sourceProjection,
562
+ validators: Object.freeze(validatedValidators)
563
+ }));
564
+ }
565
+ const projectionConflict = findPortableArtifactPathConflict(projections);
566
+ if (projectionConflict) {
567
+ publicationFailure("PUBLICATION_PROJECTION_OVERLAP", projectId, "Target source/build projections must be distinct and non-nested under portable comparison.");
568
+ }
569
+ if (findPortableArtifactPathConflict([...projections, "manifest.json"])) {
570
+ publicationFailure("INVALID_PUBLICATION_PROJECTION", projectId, "Target source/build projections must not overlap the generation manifest path.");
571
+ }
572
+ const artifactConflict = findPortableArtifactPathConflict(completeArtifactPaths);
573
+ if (artifactConflict) {
574
+ publicationFailure("PUBLICATION_PATH_COLLISION", projectId, "Projected artifact paths collide under portable comparison.");
575
+ }
576
+ return { generationId, targets: Object.freeze(targets) };
577
+ }
578
+ /**
579
+ * Stages one validated target and invokes its ordered validators.
580
+ * @param {string} generationPath - Candidate generation path.
581
+ * @param {ValidatedPublicationTarget} target - Validated target.
582
+ * @param {string} projectId - Project diagnostic identity.
583
+ * @returns {Promise<import("./semantic/types.js").GenerationTargetManifest>} Target manifest.
584
+ */
585
+ async function stageTarget(generationPath, target, projectId) {
586
+ const sourcePath = ownedPath(generationPath, target.sourceProjection, projectId);
587
+ const buildPath = ownedPath(generationPath, target.buildProjection, projectId);
588
+ await mkdir(sourcePath, { mode: 0o700, recursive: true });
589
+ await mkdir(buildPath, { mode: 0o700, recursive: true });
590
+ /** @type {import("./semantic/types.js").GenerationArtifactManifest[]} */
591
+ const artifacts = [];
592
+ for (const artifact of target.artifactSet.artifacts) {
593
+ const filename = ownedPath(sourcePath, artifact.path, projectId);
594
+ const bytes = artifact.contentKind == "text"
595
+ ? Buffer.from(/** @type {string} */ (artifact.content), "utf8")
596
+ : Buffer.from(/** @type {Uint8Array} */ (artifact.content));
597
+ await mkdir(path.dirname(filename), { mode: 0o700, recursive: true });
598
+ try {
599
+ await writeSyncedFile(filename, bytes, "wx");
600
+ }
601
+ catch (error) {
602
+ if (error instanceof SemantifoldDiagnostic)
603
+ throw error;
604
+ publicationFailure("PUBLICATION_STAGE_WRITE_FAILED", projectId, `Generated artifact '${artifact.path}' could not be staged.`, error);
605
+ }
606
+ artifacts.push(Object.freeze({
607
+ byteLength: bytes.byteLength,
608
+ contentKind: artifact.contentKind,
609
+ hash: Object.freeze({ algorithm: /** @type {const} */ ("sha256"), value: sha256(bytes) }),
610
+ mediaType: artifact.mediaType,
611
+ path: artifact.path,
612
+ provenance: artifact.provenance,
613
+ role: artifact.role
614
+ }));
615
+ }
616
+ /** @type {import("./semantic/types.js").PublicationBuildArtifactInput[]} */
617
+ const buildDescriptors = [];
618
+ const context = Object.freeze({ buildPath, sourcePath, targetId: target.id });
619
+ for (let index = 0; index < target.validators.length; index += 1) {
620
+ let produced;
621
+ try {
622
+ produced = await target.validators[index](context);
623
+ }
624
+ catch (error) {
625
+ publicationFailure("PUBLICATION_VALIDATION_FAILED", projectId, `Validator ${index} failed for target '${target.id}'.`, error);
626
+ }
627
+ if (produced === undefined)
628
+ continue;
629
+ if (!isDenseArray(produced)) {
630
+ publicationFailure("PUBLICATION_VALIDATION_FAILED", projectId, `Validator ${index} returned invalid build-artifact metadata for target '${target.id}'.`);
631
+ }
632
+ for (const descriptor of produced) {
633
+ buildDescriptors.push(validateBuildArtifactDescriptor(descriptor, target.id, projectId));
634
+ }
635
+ }
636
+ const descriptorConflict = findPortableArtifactPathConflict(buildDescriptors.map(({ path: artifactPath }) => artifactPath));
637
+ if (descriptorConflict) {
638
+ publicationFailure("PUBLICATION_PATH_COLLISION", projectId, `Target '${target.id}' build artifacts have a portable ${descriptorConflict.kind} conflict.`);
639
+ }
640
+ const stagedBuildFiles = await listRegularFiles(buildPath, projectId);
641
+ const declared = new Set(buildDescriptors.map(({ path: artifactPath }) => artifactPath));
642
+ if (stagedBuildFiles.length != declared.size || stagedBuildFiles.some(filename => !declared.has(filename))) {
643
+ publicationFailure("PUBLICATION_VALIDATION_FAILED", projectId, `Target '${target.id}' validators must declare every staged build artifact exactly once.`);
644
+ }
645
+ /** @type {import("./semantic/types.js").GenerationBuildArtifactManifest[]} */
646
+ const finalizedBuildArtifacts = [];
647
+ for (const descriptor of buildDescriptors) {
648
+ const bytes = await readAndSyncRegularFile(ownedPath(buildPath, descriptor.path, projectId), projectId, "PUBLICATION_STAGE_HASH_MISMATCH", `Build artifact '${descriptor.path}' is not a stable regular file.`);
649
+ finalizedBuildArtifacts.push(Object.freeze({
650
+ byteLength: bytes.byteLength,
651
+ hash: Object.freeze({ algorithm: /** @type {const} */ ("sha256"), value: sha256(bytes) }),
652
+ mediaType: descriptor.mediaType,
653
+ path: descriptor.path,
654
+ role: descriptor.role
655
+ }));
656
+ }
657
+ return Object.freeze({
658
+ artifacts: Object.freeze(artifacts),
659
+ buildArtifacts: Object.freeze(finalizedBuildArtifacts),
660
+ id: target.id,
661
+ ...(target.artifactSet.metadata === undefined ? {} : { metadata: target.artifactSet.metadata }),
662
+ projections: Object.freeze({ build: target.buildProjection, source: target.sourceProjection }),
663
+ role: target.role,
664
+ target: target.artifactSet.target
665
+ });
666
+ }
667
+ /**
668
+ * Validates validator/compiler output metadata.
669
+ * @param {unknown} descriptor - Metadata candidate.
670
+ * @param {string} targetId - Target identity.
671
+ * @param {string} projectId - Project diagnostic identity.
672
+ * @returns {import("./semantic/types.js").PublicationBuildArtifactInput} Validated metadata.
673
+ */
674
+ function validateBuildArtifactDescriptor(descriptor, targetId, projectId) {
675
+ if (!isPlainObject(descriptor) || !hasExactKeys(descriptor, ["mediaType", "path", "role"])) {
676
+ publicationFailure("PUBLICATION_VALIDATION_FAILED", projectId, `Target '${targetId}' validator returned invalid build-artifact metadata.`);
677
+ }
678
+ const descriptorPath = descriptor.path;
679
+ const mediaType = descriptor.mediaType;
680
+ const role = descriptor.role;
681
+ if (!isSafeArtifactPath(descriptorPath) || typeof mediaType != "string" ||
682
+ !mediaTypePattern.test(mediaType) || /[\r\n]/u.test(mediaType) ||
683
+ typeof role != "string" || !buildRolePattern.test(role)) {
684
+ publicationFailure("PUBLICATION_VALIDATION_FAILED", projectId, `Target '${targetId}' validator returned invalid build-artifact metadata.`);
685
+ }
686
+ return Object.freeze({ mediaType, path: descriptorPath, role });
687
+ }
688
+ /**
689
+ * Verifies every manifest reference and staged byte before pointer reachability.
690
+ * @param {string} generationPath - Candidate generation path.
691
+ * @param {import("./semantic/types.js").GenerationManifest} manifest - Candidate manifest.
692
+ * @param {string} projectId - Project diagnostic identity.
693
+ * @returns {Promise<void>} Completion.
694
+ */
695
+ async function verifyManifestFiles(generationPath, manifest, projectId) {
696
+ for (const target of manifest.targets) {
697
+ const sourcePath = ownedPath(generationPath, target.projections.source, projectId);
698
+ const buildPath = ownedPath(generationPath, target.projections.build, projectId);
699
+ const sourceFiles = await listRegularFiles(sourcePath, projectId);
700
+ if (sourceFiles.length != target.artifacts.length ||
701
+ sourceFiles.some(filename => !target.artifacts.some(artifact => artifact.path == filename))) {
702
+ publicationFailure("PUBLICATION_STAGE_HASH_MISMATCH", projectId, `Target '${target.id}' generated-source files do not match its manifest.`);
703
+ }
704
+ for (const artifact of target.artifacts) {
705
+ await verifyManifestFile(sourcePath, artifact, projectId);
706
+ }
707
+ const buildFiles = await listRegularFiles(buildPath, projectId);
708
+ if (buildFiles.length != target.buildArtifacts.length ||
709
+ buildFiles.some(filename => !target.buildArtifacts.some(artifact => artifact.path == filename))) {
710
+ publicationFailure("PUBLICATION_STAGE_HASH_MISMATCH", projectId, `Target '${target.id}' build files do not match its manifest.`);
711
+ }
712
+ for (const artifact of target.buildArtifacts) {
713
+ await verifyManifestFile(buildPath, artifact, projectId);
714
+ }
715
+ try {
716
+ const artifacts = [];
717
+ for (const artifact of target.artifacts) {
718
+ const bytes = await readAndSyncRegularFile(ownedPath(sourcePath, artifact.path, projectId), projectId, "PUBLICATION_STAGE_HASH_MISMATCH", `Manifest artifact '${artifact.path}' is not a stable regular file.`);
719
+ let content;
720
+ if (artifact.contentKind == "text") {
721
+ try {
722
+ content = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
723
+ }
724
+ catch (error) {
725
+ publicationFailure("MALFORMED_GENERATION_MANIFEST", projectId, `Text artifact '${artifact.path}' is not valid UTF-8.`, error);
726
+ }
727
+ }
728
+ else
729
+ content = new Uint8Array(bytes);
730
+ artifacts.push({
731
+ content,
732
+ contentKind: artifact.contentKind,
733
+ mediaType: artifact.mediaType,
734
+ ownership: /** @type {const} */ ("generated"),
735
+ path: artifact.path,
736
+ provenance: rehydrateProvenance(artifact.provenance, projectId),
737
+ role: artifact.role
738
+ });
739
+ }
740
+ createGeneratedArtifactSet({
741
+ artifacts,
742
+ ...(target.metadata === undefined ? {} : { metadata: target.metadata }),
743
+ target: target.target
744
+ });
745
+ }
746
+ catch (error) {
747
+ if (error instanceof SemantifoldDiagnostic && error.code == "MALFORMED_GENERATION_MANIFEST")
748
+ throw error;
749
+ publicationFailure("MALFORMED_GENERATION_MANIFEST", projectId, `Target '${target.id}' artifact provenance does not match its staged bytes.`, error);
750
+ }
751
+ }
752
+ await verifyGenerationInventory(generationPath, manifest, projectId);
753
+ }
754
+ /**
755
+ * Restores JSON-omitted optional mapping fields and verifies persisted mapping projections.
756
+ * @param {import("./semantic/types.js").ArtifactProvenance} provenance - Persisted provenance.
757
+ * @param {string} projectId - Project identity.
758
+ * @returns {import("./semantic/types.js").ArtifactProvenance} Canonical provenance.
759
+ */
760
+ function rehydrateProvenance(provenance, projectId) {
761
+ if (provenance.kind == "text") {
762
+ const mapping = finalizeMapping(provenance.mapping);
763
+ const sourceMap = toSourceMapV3(mapping);
764
+ const jsonSourceMap = JSON.parse(JSON.stringify(sourceMap));
765
+ if (!sameJsonValue(jsonSourceMap, provenance.sourceMap)) {
766
+ publicationFailure("MALFORMED_GENERATION_MANIFEST", projectId, "Persisted Source Map projection contradicts its rich mapping.");
767
+ }
768
+ return Object.freeze({
769
+ kind: /** @type {const} */ ("text"),
770
+ mapping,
771
+ sourceMap,
772
+ ...(provenance.sourceMapFilename === undefined ? {} : { sourceMapFilename: provenance.sourceMapFilename })
773
+ });
774
+ }
775
+ if (provenance.kind == "bytes") {
776
+ return Object.freeze({ kind: /** @type {const} */ ("bytes"), mapping: finalizeByteMapping(provenance.mapping) });
777
+ }
778
+ return provenance;
779
+ }
780
+ /**
781
+ * Verifies one referenced file.
782
+ * @param {string} projectionPath - Owning projection path.
783
+ * @param {{byteLength: number, hash: import("./semantic/types.js").GenerationContentHash, path: string}} artifact - Manifest record.
784
+ * @param {string} projectId - Project diagnostic identity.
785
+ * @returns {Promise<Buffer>} Exact verified bytes.
786
+ */
787
+ async function verifyManifestFile(projectionPath, artifact, projectId) {
788
+ const bytes = await readAndSyncRegularFile(ownedPath(projectionPath, artifact.path, projectId), projectId, "PUBLICATION_STAGE_HASH_MISMATCH", `Manifest artifact '${artifact.path}' is not a stable regular file.`);
789
+ if (bytes.byteLength != artifact.byteLength || sha256(bytes) != artifact.hash.value) {
790
+ publicationFailure("PUBLICATION_STAGE_HASH_MISMATCH", projectId, `Manifest artifact '${artifact.path}' bytes do not match its recorded hash.`);
791
+ }
792
+ return bytes;
793
+ }
794
+ /**
795
+ * Validates an existing active pointer before a new candidate is staged.
796
+ * @param {string} publicationRoot - Publication root.
797
+ * @param {string} projectId - Project identity.
798
+ * @returns {Promise<void>} Completion.
799
+ */
800
+ async function validateExistingPointer(publicationRoot, projectId) {
801
+ const pointerPath = path.join(publicationRoot, activePointerName);
802
+ const pointer = await readActivePointer(pointerPath, projectId, true);
803
+ if (pointer)
804
+ await verifyPublishedGeneration(publicationRoot, projectId, pointer, false);
805
+ }
806
+ /**
807
+ * Reads and strictly validates one active pointer.
808
+ * @param {string} pointerPath - Pointer filename.
809
+ * @param {string} projectId - Expected project identity.
810
+ * @param {boolean} optional - Whether absence is allowed.
811
+ * @returns {Promise<ActivePointer | null>} Pointer or absent value.
812
+ */
813
+ async function readActivePointer(pointerPath, projectId, optional) {
814
+ let pointerBytes;
815
+ try {
816
+ const status = await lstat(pointerPath);
817
+ if (!status.isFile() || status.isSymbolicLink()) {
818
+ publicationFailure("MALFORMED_ACTIVE_GENERATION", projectId, "Active-generation pointer must be a regular file.");
819
+ }
820
+ pointerBytes = await readFile(pointerPath);
821
+ }
822
+ catch (error) {
823
+ if (optional && isErrorCode(error, "ENOENT"))
824
+ return null;
825
+ if (error instanceof SemantifoldDiagnostic)
826
+ throw error;
827
+ publicationFailure(optional ? "MALFORMED_ACTIVE_GENERATION" : "ACTIVE_GENERATION_MISSING", projectId, optional ? "Active-generation pointer could not be read." : "No active generation has been published.", error);
828
+ }
829
+ let value;
830
+ try {
831
+ value = JSON.parse(pointerBytes.toString("utf8"));
832
+ }
833
+ catch (error) {
834
+ publicationFailure("MALFORMED_ACTIVE_GENERATION", projectId, "Active-generation pointer is not valid JSON.", error);
835
+ }
836
+ if (!isActivePointer(value) || value.projectId != projectId) {
837
+ publicationFailure("MALFORMED_ACTIVE_GENERATION", projectId, "Active-generation pointer does not match the versioned project contract.");
838
+ }
839
+ return value;
840
+ }
841
+ /**
842
+ * Verifies a pointer-selected generation without consulting the pointer again.
843
+ * @param {string} publicationRoot - Publication root.
844
+ * @param {string} projectId - Project identity.
845
+ * @param {ActivePointer} pointer - Pointer snapshot.
846
+ * @param {boolean} cleanupPending - Recovery state.
847
+ * @returns {Promise<import("./semantic/types.js").PublishedGeneration>} Verified generation.
848
+ */
849
+ async function verifyPublishedGeneration(publicationRoot, projectId, pointer, cleanupPending) {
850
+ const generationPath = ownedPath(path.join(publicationRoot, generationsName), pointer.generationId, projectId);
851
+ const manifestPath = path.join(generationPath, "manifest.json");
852
+ let manifestBytes;
853
+ try {
854
+ manifestBytes = await readAndSyncRegularFile(manifestPath, projectId, "MALFORMED_GENERATION_MANIFEST", "Generation manifest must be a regular file.");
855
+ }
856
+ catch (error) {
857
+ if (error instanceof SemantifoldDiagnostic)
858
+ throw error;
859
+ publicationFailure("MALFORMED_GENERATION_MANIFEST", projectId, "Generation manifest could not be read.", error);
860
+ }
861
+ if (sha256(manifestBytes) != pointer.manifestHash) {
862
+ publicationFailure("MALFORMED_GENERATION_MANIFEST", projectId, "Generation manifest hash does not match the active pointer.");
863
+ }
864
+ let value;
865
+ try {
866
+ value = JSON.parse(manifestBytes.toString("utf8"));
867
+ }
868
+ catch (error) {
869
+ publicationFailure("MALFORMED_GENERATION_MANIFEST", projectId, "Generation manifest is not valid JSON.", error);
870
+ }
871
+ const manifest = validateGenerationManifest(value, projectId, pointer.generationId);
872
+ await verifyManifestFiles(generationPath, manifest, projectId);
873
+ return publishedGeneration(publicationRoot, manifest, cleanupPending);
874
+ }
875
+ /**
876
+ * Strictly validates a persisted generation manifest.
877
+ * @param {unknown} value - Parsed manifest value.
878
+ * @param {string} projectId - Expected project identity.
879
+ * @param {string} generationId - Expected generation identity.
880
+ * @returns {import("./semantic/types.js").GenerationManifest} Frozen manifest.
881
+ */
882
+ function validateGenerationManifest(value, projectId, generationId) {
883
+ if (!isPlainObject(value) || !hasExactKeys(value, ["generationId", "projectId", "schema", "targets", "version"]) ||
884
+ value.schema != "SemantifoldGenerationManifest" || value.version != 1 || value.projectId != projectId ||
885
+ value.generationId != generationId || !isDenseArray(value.targets) || value.targets.length == 0) {
886
+ publicationFailure("MALFORMED_GENERATION_MANIFEST", projectId, "Generation manifest does not match the versioned project contract.");
887
+ }
888
+ /** @type {import("./semantic/types.js").GenerationTargetManifest[]} */
889
+ const targets = [];
890
+ /** @type {string[]} */
891
+ const projections = [];
892
+ const ids = new Set();
893
+ for (const target of value.targets) {
894
+ const targetKeys = target && typeof target == "object" && "metadata" in target
895
+ ? ["artifacts", "buildArtifacts", "id", "metadata", "projections", "role", "target"]
896
+ : ["artifacts", "buildArtifacts", "id", "projections", "role", "target"];
897
+ if (!isPlainObject(target) || !hasExactKeys(target, targetKeys) ||
898
+ !identityPattern.test(typeof target.id == "string" ? target.id : "") || ids.has(target.id) ||
899
+ typeof target.role != "string" || !targetRoles.has(target.role) ||
900
+ typeof target.target != "string" || !identityPattern.test(target.target) ||
901
+ !isPlainObject(target.projections) || !hasExactKeys(target.projections, ["build", "source"]) ||
902
+ !isSafeArtifactPath(target.projections.source) || !isSafeArtifactPath(target.projections.build) ||
903
+ !isDenseArray(target.artifacts) || target.artifacts.length == 0 || !isDenseArray(target.buildArtifacts)) {
904
+ publicationFailure("MALFORMED_GENERATION_MANIFEST", projectId, "Generation manifest contains an invalid target record.");
905
+ }
906
+ const targetId = /** @type {string} */ (target.id);
907
+ ids.add(targetId);
908
+ projections.push(target.projections.source, target.projections.build);
909
+ const artifacts = target.artifacts.map(artifact => validatePersistedArtifact(artifact, true, projectId));
910
+ const buildArtifacts = target.buildArtifacts.map(artifact => validatePersistedArtifact(artifact, false, projectId));
911
+ if (findPortableArtifactPathConflict(artifacts.map(({ path: artifactPath }) => artifactPath)) ||
912
+ findPortableArtifactPathConflict(buildArtifacts.map(({ path: artifactPath }) => artifactPath))) {
913
+ publicationFailure("MALFORMED_GENERATION_MANIFEST", projectId, "Generation manifest contains colliding artifact paths.");
914
+ }
915
+ targets.push(Object.freeze({
916
+ artifacts: Object.freeze(/** @type {import("./semantic/types.js").GenerationArtifactManifest[]} */ (artifacts)),
917
+ buildArtifacts: Object.freeze(/** @type {import("./semantic/types.js").GenerationBuildArtifactManifest[]} */ (buildArtifacts)),
918
+ id: targetId,
919
+ ...(target.metadata === undefined ? {} : { metadata: deepFreeze(/** @type {Record<string, unknown>} */ (target.metadata)) }),
920
+ projections: Object.freeze({ build: target.projections.build, source: target.projections.source }),
921
+ role: /** @type {import("./semantic/types.js").PublicationTargetRole} */ (target.role),
922
+ target: target.target
923
+ }));
924
+ }
925
+ if (findPortableArtifactPathConflict(projections) ||
926
+ findPortableArtifactPathConflict([...projections, "manifest.json"])) {
927
+ publicationFailure("MALFORMED_GENERATION_MANIFEST", projectId, "Generation manifest contains overlapping projections.");
928
+ }
929
+ return Object.freeze({
930
+ generationId,
931
+ projectId,
932
+ schema: /** @type {const} */ ("SemantifoldGenerationManifest"),
933
+ targets: Object.freeze(targets),
934
+ version: /** @type {const} */ (1)
935
+ });
936
+ }
937
+ /**
938
+ * Validates one persisted artifact record.
939
+ * @param {unknown} value - Record candidate.
940
+ * @param {boolean} generated - Whether this is a generated-source artifact.
941
+ * @param {string} projectId - Project identity.
942
+ * @returns {import("./semantic/types.js").GenerationArtifactManifest | import("./semantic/types.js").GenerationBuildArtifactManifest} Frozen record.
943
+ */
944
+ function validatePersistedArtifact(value, generated, projectId) {
945
+ const keys = generated
946
+ ? ["byteLength", "contentKind", "hash", "mediaType", "path", "provenance", "role"]
947
+ : ["byteLength", "hash", "mediaType", "path", "role"];
948
+ if (!isPlainObject(value) || !hasExactKeys(value, keys) || !isSafeArtifactPath(value.path) ||
949
+ typeof value.byteLength != "number" || !Number.isSafeInteger(value.byteLength) || value.byteLength < 0 || typeof value.mediaType != "string" ||
950
+ !mediaTypePattern.test(value.mediaType) || typeof value.role != "string" ||
951
+ !(generated ? ["entry", "source", "manifest", "support", "mapping", "resource", "loader"].includes(value.role) :
952
+ buildRolePattern.test(value.role)) ||
953
+ (generated && value.contentKind != "text" && value.contentKind != "binary") ||
954
+ (generated && !isPlainObject(value.provenance)) ||
955
+ !isPlainObject(value.hash) || !hasExactKeys(value.hash, ["algorithm", "value"]) || value.hash.algorithm != "sha256" ||
956
+ typeof value.hash.value != "string" || !/^[a-f0-9]{64}$/u.test(value.hash.value)) {
957
+ publicationFailure("MALFORMED_GENERATION_MANIFEST", projectId, "Generation manifest contains an invalid artifact record.");
958
+ }
959
+ return Object.freeze(/** @type {import("./semantic/types.js").GenerationArtifactManifest | import("./semantic/types.js").GenerationBuildArtifactManifest} */ ({
960
+ byteLength: value.byteLength,
961
+ ...(generated ? { contentKind: value.contentKind } : {}),
962
+ hash: Object.freeze({ algorithm: /** @type {const} */ ("sha256"), value: value.hash.value }),
963
+ mediaType: value.mediaType,
964
+ path: value.path,
965
+ ...(generated ? { provenance: deepFreeze(/** @type {import("./semantic/types.js").ArtifactProvenance} */ (value.provenance)) } : {}),
966
+ role: value.role
967
+ }));
968
+ }
969
+ /**
970
+ * Constructs a frozen resolved-generation result.
971
+ * @param {string} publicationRoot - Publication root.
972
+ * @param {import("./semantic/types.js").GenerationManifest} manifest - Verified manifest.
973
+ * @param {boolean} cleanupPending - Whether cleanup remains.
974
+ * @returns {import("./semantic/types.js").PublishedGeneration} Frozen result.
975
+ */
976
+ function publishedGeneration(publicationRoot, manifest, cleanupPending) {
977
+ const generationPath = path.join(publicationRoot, generationsName, manifest.generationId);
978
+ const targets = manifest.targets.map(target => Object.freeze({
979
+ buildPath: path.join(generationPath, target.projections.build),
980
+ id: target.id,
981
+ role: target.role,
982
+ sourcePath: path.join(generationPath, target.projections.source)
983
+ }));
984
+ return Object.freeze({
985
+ cleanupPending,
986
+ generationId: manifest.generationId,
987
+ generationPath,
988
+ manifest,
989
+ manifestPath: path.join(generationPath, "manifest.json"),
990
+ targets: Object.freeze(targets)
991
+ });
992
+ }
993
+ /**
994
+ * Probes the exact same-directory regular-file replacement primitive used by the active pointer.
995
+ * @param {string} publicationRoot - Publication root.
996
+ * @param {string} projectId - Project identity.
997
+ * @returns {Promise<void>} Completion.
998
+ */
999
+ async function verifyAtomicReplacement(publicationRoot, projectId) {
1000
+ const identity = randomUUID();
1001
+ const source = path.join(publicationRoot, `.semantifold-atomic-${identity}.source`);
1002
+ const destination = path.join(publicationRoot, `.semantifold-atomic-${identity}.destination`);
1003
+ const expected = Buffer.from("candidate\n");
1004
+ let sourceCreated = false;
1005
+ let destinationCreated = false;
1006
+ try {
1007
+ await writeSyncedFile(source, Buffer.from("candidate\n"), "wx");
1008
+ sourceCreated = true;
1009
+ await writeSyncedFile(destination, Buffer.from("previous\n"), "wx");
1010
+ destinationCreated = true;
1011
+ await rename(source, destination);
1012
+ sourceCreated = false;
1013
+ await syncDirectory(publicationRoot);
1014
+ const destinationStatus = await lstat(destination);
1015
+ const replaced = await readFile(destination);
1016
+ if (!destinationStatus.isFile() || destinationStatus.isSymbolicLink() || !replaced.equals(expected)) {
1017
+ publicationFailure("PUBLICATION_ATOMIC_REPLACE_UNSUPPORTED", projectId, "Filesystem did not provide same-directory regular-file replacement.");
1018
+ }
1019
+ try {
1020
+ await lstat(source);
1021
+ publicationFailure("PUBLICATION_ATOMIC_REPLACE_UNSUPPORTED", projectId, "Filesystem did not remove the replaced temporary name atomically.");
1022
+ }
1023
+ catch (error) {
1024
+ if (!isErrorCode(error, "ENOENT"))
1025
+ throw error;
1026
+ }
1027
+ }
1028
+ catch (error) {
1029
+ if (error instanceof SemantifoldDiagnostic)
1030
+ throw error;
1031
+ publicationFailure("PUBLICATION_ATOMIC_REPLACE_UNSUPPORTED", projectId, "Filesystem did not provide same-directory regular-file replacement.", error);
1032
+ }
1033
+ finally {
1034
+ await Promise.allSettled([
1035
+ ...(sourceCreated ? [rm(source, { force: true })] : []),
1036
+ ...(destinationCreated ? [rm(destination, { force: true })] : [])
1037
+ ]);
1038
+ }
1039
+ }
1040
+ /**
1041
+ * Writes and synchronizes one newly owned file.
1042
+ * @param {string} filename - Exact filename.
1043
+ * @param {Uint8Array} bytes - Exact bytes.
1044
+ * @param {"wx"} flag - Exclusive creation mode.
1045
+ * @param {() => void} [onCreated] - Called immediately after exclusive creation succeeds.
1046
+ * @returns {Promise<void>} Completion.
1047
+ */
1048
+ async function writeSyncedFile(filename, bytes, flag, onCreated) {
1049
+ const handle = await open(filename, flag, 0o600);
1050
+ onCreated?.();
1051
+ /** @type {unknown} */
1052
+ let failure;
1053
+ try {
1054
+ await handle.writeFile(bytes);
1055
+ await handle.sync();
1056
+ }
1057
+ catch (error) {
1058
+ failure = error;
1059
+ }
1060
+ finally {
1061
+ try {
1062
+ await handle.close();
1063
+ }
1064
+ catch (error) {
1065
+ if (failure === undefined)
1066
+ failure = error;
1067
+ }
1068
+ }
1069
+ if (failure !== undefined) {
1070
+ await rm(filename, { force: true }).catch(() => { });
1071
+ throw failure;
1072
+ }
1073
+ }
1074
+ /**
1075
+ * Reads and synchronizes one regular non-symlink file.
1076
+ * @param {string} filename - Exact filename.
1077
+ * @param {string} projectId - Project identity.
1078
+ * @param {string} code - Failure code.
1079
+ * @param {string} message - Stable failure detail.
1080
+ * @returns {Promise<Buffer>} Exact bytes.
1081
+ */
1082
+ async function readAndSyncRegularFile(filename, projectId, code, message) {
1083
+ try {
1084
+ const status = await lstat(filename);
1085
+ if (!status.isFile() || status.isSymbolicLink())
1086
+ publicationFailure(code, projectId, message);
1087
+ assertRegularFileImmutability(status, new Set(), projectId);
1088
+ const handle = await open(filename, constants.O_RDONLY);
1089
+ try {
1090
+ const bytes = await handle.readFile();
1091
+ await handle.sync();
1092
+ return bytes;
1093
+ }
1094
+ finally {
1095
+ await handle.close();
1096
+ }
1097
+ }
1098
+ catch (error) {
1099
+ if (error instanceof SemantifoldDiagnostic)
1100
+ throw error;
1101
+ publicationFailure(code, projectId, message, error);
1102
+ }
1103
+ }
1104
+ /**
1105
+ * Lists every regular file beneath one projection and rejects symlinks or special nodes.
1106
+ * @param {string} directory - Projection root.
1107
+ * @param {string} projectId - Project identity.
1108
+ * @returns {Promise<string[]>} Sorted relative POSIX paths.
1109
+ */
1110
+ async function listRegularFiles(directory, projectId) {
1111
+ /** @type {string[]} */
1112
+ const files = [];
1113
+ const identities = new Set();
1114
+ try {
1115
+ await visit(directory, "");
1116
+ }
1117
+ catch (error) {
1118
+ if (error instanceof SemantifoldDiagnostic)
1119
+ throw error;
1120
+ publicationFailure("PUBLICATION_GENERATION_VERIFICATION_FAILED", projectId, "Immutable generation filesystem inventory could not be verified.", error);
1121
+ }
1122
+ return files.sort(compareStrings);
1123
+ /**
1124
+ * Visits one owned directory.
1125
+ * @param {string} current - Exact directory.
1126
+ * @param {string} relative - Projection-relative path.
1127
+ * @returns {Promise<void>} Completion.
1128
+ */
1129
+ async function visit(current, relative) {
1130
+ await assertRealInventoryDirectory(current, projectId);
1131
+ const entries = await readdir(current);
1132
+ entries.sort(compareStrings);
1133
+ for (const entry of entries) {
1134
+ const childRelative = relative.length == 0 ? entry : `${relative}/${entry}`;
1135
+ if (!isSafeArtifactPath(childRelative)) {
1136
+ publicationFailure("INVALID_PUBLICATION_PROJECTION", projectId, "Validator output contains a non-canonical relative path.");
1137
+ }
1138
+ const child = path.join(current, entry);
1139
+ const status = await lstat(child);
1140
+ if (status.isSymbolicLink()) {
1141
+ publicationFailure("PUBLICATION_SYMLINK_TRAVERSAL", projectId, "Candidate generation contains a symbolic link.");
1142
+ }
1143
+ if (status.isDirectory())
1144
+ await visit(child, childRelative);
1145
+ else if (status.isFile()) {
1146
+ assertRegularFileImmutability(status, identities, projectId);
1147
+ files.push(childRelative);
1148
+ }
1149
+ else
1150
+ publicationFailure("PUBLICATION_GENERATION_INVENTORY_MISMATCH", projectId, "Immutable generation contains an undeclared filesystem entry.");
1151
+ }
1152
+ }
1153
+ }
1154
+ /**
1155
+ * Verifies that the manifest describes every directory and regular file in the immutable generation.
1156
+ * @param {string} generationPath - Exact generation root.
1157
+ * @param {import("./semantic/types.js").GenerationManifest} manifest - Verified manifest.
1158
+ * @param {string} projectId - Project identity.
1159
+ * @returns {Promise<void>} Completion.
1160
+ */
1161
+ async function verifyGenerationInventory(generationPath, manifest, projectId) {
1162
+ const expectedFiles = new Set(["manifest.json"]);
1163
+ const expectedDirectories = new Set();
1164
+ for (const target of manifest.targets) {
1165
+ addExpectedDirectory(target.projections.source);
1166
+ addExpectedDirectory(target.projections.build);
1167
+ for (const artifact of target.artifacts) {
1168
+ addExpectedFile(`${target.projections.source}/${artifact.path}`);
1169
+ }
1170
+ for (const artifact of target.buildArtifacts) {
1171
+ addExpectedFile(`${target.projections.build}/${artifact.path}`);
1172
+ }
1173
+ }
1174
+ /** @type {Set<string>} */
1175
+ const observedFiles = new Set();
1176
+ /** @type {Set<string>} */
1177
+ const observedDirectories = new Set();
1178
+ const identities = new Set();
1179
+ try {
1180
+ await visit(generationPath, "");
1181
+ }
1182
+ catch (error) {
1183
+ if (error instanceof SemantifoldDiagnostic)
1184
+ throw error;
1185
+ publicationFailure("PUBLICATION_GENERATION_VERIFICATION_FAILED", projectId, "Immutable generation filesystem inventory could not be verified.", error);
1186
+ }
1187
+ if (!sameStringSet(expectedFiles, observedFiles) || !sameStringSet(expectedDirectories, observedDirectories)) {
1188
+ publicationFailure("PUBLICATION_GENERATION_INVENTORY_MISMATCH", projectId, "Immutable generation contains an undeclared filesystem entry.");
1189
+ }
1190
+ /**
1191
+ * Adds one expected directory and each generation-relative parent.
1192
+ * @param {string} relative - POSIX-style generation-relative directory.
1193
+ * @returns {void}
1194
+ */
1195
+ function addExpectedDirectory(relative) {
1196
+ const parts = relative.split("/");
1197
+ for (let index = 1; index <= parts.length; index += 1) {
1198
+ expectedDirectories.add(parts.slice(0, index).join("/"));
1199
+ }
1200
+ }
1201
+ /**
1202
+ * Adds one expected regular file and its parent directories.
1203
+ * @param {string} relative - POSIX-style generation-relative filename.
1204
+ * @returns {void}
1205
+ */
1206
+ function addExpectedFile(relative) {
1207
+ expectedFiles.add(relative);
1208
+ const separator = relative.lastIndexOf("/");
1209
+ if (separator >= 0)
1210
+ addExpectedDirectory(relative.slice(0, separator));
1211
+ }
1212
+ /**
1213
+ * Visits every entry in one generation directory without following links.
1214
+ * @param {string} current - Exact directory.
1215
+ * @param {string} relative - Generation-relative directory.
1216
+ * @returns {Promise<void>} Completion.
1217
+ */
1218
+ async function visit(current, relative) {
1219
+ await assertRealInventoryDirectory(current, projectId);
1220
+ const entries = await readdir(current);
1221
+ entries.sort(compareStrings);
1222
+ for (const entry of entries) {
1223
+ const childRelative = relative.length == 0 ? entry : `${relative}/${entry}`;
1224
+ if (!isSafeArtifactPath(childRelative)) {
1225
+ publicationFailure("PUBLICATION_GENERATION_INVENTORY_MISMATCH", projectId, "Immutable generation contains an undeclared filesystem entry.");
1226
+ }
1227
+ const child = path.join(current, entry);
1228
+ const status = await lstat(child);
1229
+ if (status.isSymbolicLink()) {
1230
+ publicationFailure("PUBLICATION_SYMLINK_TRAVERSAL", projectId, "Candidate generation contains a symbolic link.");
1231
+ }
1232
+ if (status.isDirectory()) {
1233
+ observedDirectories.add(childRelative);
1234
+ await visit(child, childRelative);
1235
+ }
1236
+ else if (status.isFile()) {
1237
+ assertRegularFileImmutability(status, identities, projectId);
1238
+ observedFiles.add(childRelative);
1239
+ }
1240
+ else {
1241
+ publicationFailure("PUBLICATION_GENERATION_INVENTORY_MISMATCH", projectId, "Immutable generation contains an undeclared filesystem entry.");
1242
+ }
1243
+ }
1244
+ }
1245
+ }
1246
+ /**
1247
+ * Verifies one inventory traversal root without following symbolic links.
1248
+ * @param {string} directory - Exact directory about to be read.
1249
+ * @param {string} projectId - Project identity.
1250
+ * @returns {Promise<void>} Completion.
1251
+ */
1252
+ async function assertRealInventoryDirectory(directory, projectId) {
1253
+ const status = await lstat(directory);
1254
+ if (status.isSymbolicLink()) {
1255
+ publicationFailure("PUBLICATION_SYMLINK_TRAVERSAL", projectId, "Candidate generation contains a symbolic link.");
1256
+ }
1257
+ if (!status.isDirectory()) {
1258
+ publicationFailure("PUBLICATION_GENERATION_INVENTORY_MISMATCH", projectId, "Immutable generation contains an undeclared filesystem entry.");
1259
+ }
1260
+ }
1261
+ /**
1262
+ * Rejects external hard links and duplicate stable file identities.
1263
+ * @param {import("node:fs").Stats} status - Regular-file status.
1264
+ * @param {Set<string>} identities - Previously observed device/inode identities.
1265
+ * @param {string} projectId - Project identity.
1266
+ * @returns {void}
1267
+ */
1268
+ function assertRegularFileImmutability(status, identities, projectId) {
1269
+ if (status.nlink > 1) {
1270
+ publicationFailure("PUBLICATION_HARD_LINK", projectId, "Immutable generation files must not have external hard links.");
1271
+ }
1272
+ const identity = stableFileIdentity(status);
1273
+ if (identity !== null) {
1274
+ if (identities.has(identity)) {
1275
+ publicationFailure("PUBLICATION_HARD_LINK", projectId, "Immutable generation files must have unique filesystem identities.");
1276
+ }
1277
+ identities.add(identity);
1278
+ }
1279
+ }
1280
+ /**
1281
+ * Returns a stable device/inode identity only where the host reports one.
1282
+ * @param {import("node:fs").Stats} status - File status.
1283
+ * @returns {string | null} Identity or unavailable.
1284
+ */
1285
+ function stableFileIdentity(status) {
1286
+ if ((typeof status.dev != "number" && typeof status.dev != "bigint") ||
1287
+ (typeof status.ino != "number" && typeof status.ino != "bigint") || status.ino == 0)
1288
+ return null;
1289
+ return `${String(status.dev)}:${String(status.ino)}`;
1290
+ }
1291
+ /**
1292
+ * Compares two string sets exactly.
1293
+ * @param {Set<string>} left - First set.
1294
+ * @param {Set<string>} right - Second set.
1295
+ * @returns {boolean} Equality.
1296
+ */
1297
+ function sameStringSet(left, right) {
1298
+ return left.size == right.size && [...left].every(value => right.has(value));
1299
+ }
1300
+ /**
1301
+ * Synchronizes every directory in a staged tree from leaves to root.
1302
+ * @param {string} root - Tree root.
1303
+ * @returns {Promise<void>} Completion.
1304
+ */
1305
+ async function syncTreeDirectories(root) {
1306
+ const entries = await readdir(root, { withFileTypes: true });
1307
+ for (const entry of entries) {
1308
+ if (entry.isDirectory() && !entry.isSymbolicLink())
1309
+ await syncTreeDirectories(path.join(root, entry.name));
1310
+ }
1311
+ await syncDirectory(root);
1312
+ }
1313
+ /**
1314
+ * Synchronizes one directory entry set.
1315
+ * @param {string} directory - Directory path.
1316
+ * @returns {Promise<void>} Completion.
1317
+ */
1318
+ async function syncDirectory(directory) {
1319
+ const handle = await open(directory, constants.O_RDONLY);
1320
+ try {
1321
+ await handle.sync();
1322
+ }
1323
+ finally {
1324
+ await handle.close();
1325
+ }
1326
+ }
1327
+ /**
1328
+ * Ensures every existing path component is a real directory and optionally creates missing components.
1329
+ * @param {string} directory - Canonical absolute directory.
1330
+ * @param {boolean} create - Whether missing components may be created.
1331
+ * @param {string} projectId - Project identity.
1332
+ * @returns {Promise<void>} Completion.
1333
+ */
1334
+ async function ensureDirectoryWithoutSymlinks(directory, create, projectId) {
1335
+ const parsed = path.parse(directory);
1336
+ const relative = directory.slice(parsed.root.length);
1337
+ const parts = relative.split(path.sep).filter(Boolean);
1338
+ let current = parsed.root;
1339
+ for (const part of parts) {
1340
+ current = path.join(current, part);
1341
+ try {
1342
+ const status = await lstat(current);
1343
+ if (status.isSymbolicLink()) {
1344
+ publicationFailure("PUBLICATION_SYMLINK_TRAVERSAL", projectId, "Owned path traversal encountered a symbolic link.");
1345
+ }
1346
+ if (!status.isDirectory()) {
1347
+ publicationFailure("INVALID_PUBLICATION_ROOT", projectId, "Owned root path contains a non-directory component.");
1348
+ }
1349
+ }
1350
+ catch (error) {
1351
+ if (!isErrorCode(error, "ENOENT")) {
1352
+ if (error instanceof SemantifoldDiagnostic)
1353
+ throw error;
1354
+ publicationFailure("INVALID_PUBLICATION_ROOT", projectId, "Owned root path could not be validated.", error);
1355
+ }
1356
+ if (!create) {
1357
+ publicationFailure("INVALID_PUBLICATION_ROOT", projectId, "Source root must exist as a real directory.", error);
1358
+ }
1359
+ try {
1360
+ await mkdir(current, { mode: 0o700 });
1361
+ }
1362
+ catch (mkdirError) {
1363
+ publicationFailure("INVALID_PUBLICATION_ROOT", projectId, "Publication root could not be created safely.", mkdirError);
1364
+ }
1365
+ }
1366
+ }
1367
+ }
1368
+ /**
1369
+ * Ensures one reserved publisher directory is neither a symlink nor an unowned file.
1370
+ * @param {string} directory - Reserved directory.
1371
+ * @param {string} projectId - Project identity.
1372
+ * @returns {Promise<void>} Completion.
1373
+ */
1374
+ async function ensureOwnedDirectory(directory, projectId) {
1375
+ try {
1376
+ await mkdir(directory, { mode: 0o700 });
1377
+ }
1378
+ catch (error) {
1379
+ if (!isErrorCode(error, "EEXIST")) {
1380
+ publicationFailure("PUBLICATION_STAGE_WRITE_FAILED", projectId, "Publisher-owned directory could not be created.", error);
1381
+ }
1382
+ }
1383
+ let status;
1384
+ try {
1385
+ status = await lstat(directory);
1386
+ }
1387
+ catch (error) {
1388
+ publicationFailure("PUBLICATION_STAGE_WRITE_FAILED", projectId, "Reserved publisher path could not be inspected.", error);
1389
+ }
1390
+ if (!status.isDirectory() || status.isSymbolicLink()) {
1391
+ publicationFailure(status.isSymbolicLink() ? "PUBLICATION_SYMLINK_TRAVERSAL" : "PUBLICATION_UNOWNED_CONFLICT", projectId, "Reserved publisher path is not an owned real directory.");
1392
+ }
1393
+ }
1394
+ /**
1395
+ * Ensures an owned path has no pre-existing entry.
1396
+ * @param {string} filename - Exact path.
1397
+ * @param {string} code - Diagnostic code.
1398
+ * @param {string} projectId - Project identity.
1399
+ * @param {string} message - Stable failure detail.
1400
+ * @returns {Promise<void>} Completion.
1401
+ */
1402
+ async function assertAbsent(filename, code, projectId, message) {
1403
+ try {
1404
+ await lstat(filename);
1405
+ publicationFailure(code, projectId, message);
1406
+ }
1407
+ catch (error) {
1408
+ if (isErrorCode(error, "ENOENT"))
1409
+ return;
1410
+ if (error instanceof SemantifoldDiagnostic)
1411
+ throw error;
1412
+ publicationFailure(code, projectId, message, error);
1413
+ }
1414
+ }
1415
+ /**
1416
+ * Resolves a validated relative path under an owned root and rejects escape.
1417
+ * @param {string} root - Owned root.
1418
+ * @param {string} relative - Validated relative POSIX path.
1419
+ * @param {string} projectId - Project identity.
1420
+ * @returns {string} Exact owned path.
1421
+ */
1422
+ function ownedPath(root, relative, projectId) {
1423
+ const resolved = path.resolve(root, ...relative.split("/"));
1424
+ const child = path.relative(root, resolved);
1425
+ if (child.length == 0 || child == ".." || child.startsWith(`..${path.sep}`) || path.isAbsolute(child)) {
1426
+ publicationFailure("PUBLICATION_PATH_ESCAPE", projectId, "Resolved publication path escaped its owned root.");
1427
+ }
1428
+ return resolved;
1429
+ }
1430
+ /**
1431
+ * Checks a canonical non-root absolute path without filesystem access.
1432
+ * @param {unknown} value - Path candidate.
1433
+ * @returns {value is string} Whether the path is canonical.
1434
+ */
1435
+ function isCanonicalAbsolutePath(value) {
1436
+ return isCanonicalAbsolutePathForPath(value, path);
1437
+ }
1438
+ /**
1439
+ * Checks one absolute path using the supplied host path semantics.
1440
+ * This helper is intentionally not part of the package root API.
1441
+ * @param {unknown} value - Path candidate.
1442
+ * @param {typeof path.posix | typeof path.win32} hostPath - Host-native path implementation.
1443
+ * @returns {value is string} Whether the path is canonical for that host.
1444
+ */
1445
+ export function isCanonicalAbsolutePathForPath(value, hostPath) {
1446
+ const separatorAlias = hostPath.sep == "/" ? "\\" : "/";
1447
+ return typeof value == "string" && value.length > 0 && !value.includes("\0") && !value.includes(separatorAlias) &&
1448
+ hostPath.isAbsolute(value) && value != hostPath.parse(value).root && hostPath.normalize(value) == value &&
1449
+ hostPath.resolve(value) == value;
1450
+ }
1451
+ /**
1452
+ * Checks conservative portable overlap between absolute paths.
1453
+ * @param {string} left - First path.
1454
+ * @param {string} right - Second path.
1455
+ * @returns {boolean} Whether either contains the other.
1456
+ */
1457
+ function pathsOverlap(left, right) {
1458
+ const leftKey = left.toLowerCase();
1459
+ const rightKey = right.toLowerCase();
1460
+ return leftKey == rightKey || leftKey.startsWith(`${rightKey}${path.sep}`) || rightKey.startsWith(`${leftKey}${path.sep}`);
1461
+ }
1462
+ /**
1463
+ * Checks whether a path is equal to or nested beneath one canonical root.
1464
+ * @param {string} root - Canonical root.
1465
+ * @param {string} candidate - Canonical candidate.
1466
+ * @returns {boolean} Whether the candidate is within the root.
1467
+ */
1468
+ function isPathWithin(root, candidate) {
1469
+ const relative = path.relative(root, candidate);
1470
+ return relative.length == 0 || (relative != ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative));
1471
+ }
1472
+ /**
1473
+ * Checks whether a path is strictly nested beneath one canonical root.
1474
+ * @param {string} root - Canonical root.
1475
+ * @param {string} candidate - Canonical candidate.
1476
+ * @returns {boolean} Whether the candidate is a strict descendant.
1477
+ */
1478
+ function isStrictPathDescendant(root, candidate) {
1479
+ return isPathWithin(root, candidate) && path.relative(root, candidate).length > 0;
1480
+ }
1481
+ /**
1482
+ * Serializes stable generated JSON with one trailing LF.
1483
+ * @param {unknown} value - JSON value.
1484
+ * @returns {Buffer} UTF-8 bytes.
1485
+ */
1486
+ function serializeJson(value) {
1487
+ return Buffer.from(`${JSON.stringify(value, null, 2)}\n`, "utf8");
1488
+ }
1489
+ /**
1490
+ * Hashes exact bytes with SHA-256.
1491
+ * @param {Uint8Array} bytes - Exact bytes.
1492
+ * @returns {string} Lowercase hexadecimal hash.
1493
+ */
1494
+ function sha256(bytes) {
1495
+ return createHash("sha256").update(bytes).digest("hex");
1496
+ }
1497
+ /**
1498
+ * Deeply freezes a parsed JSON value.
1499
+ * @template T
1500
+ * @param {T} value - JSON value.
1501
+ * @returns {T} Frozen value.
1502
+ */
1503
+ function deepFreeze(value) {
1504
+ if (typeof value == "object" && value != null) {
1505
+ for (const child of Object.values(value))
1506
+ deepFreeze(child);
1507
+ Object.freeze(value);
1508
+ }
1509
+ return value;
1510
+ }
1511
+ /**
1512
+ * Compares detached JSON values without depending on object-key order.
1513
+ * @param {unknown} left - First JSON value.
1514
+ * @param {unknown} right - Second JSON value.
1515
+ * @returns {boolean} Whether the values are structurally equal.
1516
+ */
1517
+ function sameJsonValue(left, right) {
1518
+ if (left === right)
1519
+ return true;
1520
+ if (Array.isArray(left) || Array.isArray(right)) {
1521
+ return Array.isArray(left) && Array.isArray(right) && left.length == right.length &&
1522
+ left.every((entry, index) => sameJsonValue(entry, right[index]));
1523
+ }
1524
+ if (!isPlainObject(left) || !isPlainObject(right))
1525
+ return false;
1526
+ const leftKeys = Object.keys(left);
1527
+ const rightKeys = Object.keys(right);
1528
+ return leftKeys.length == rightKeys.length &&
1529
+ leftKeys.every(key => Object.hasOwn(right, key) && sameJsonValue(left[key], right[key]));
1530
+ }
1531
+ /**
1532
+ * Checks an active-pointer value.
1533
+ * @param {unknown} value - Parsed value.
1534
+ * @returns {value is ActivePointer} Whether the value is strict and versioned.
1535
+ */
1536
+ function isActivePointer(value) {
1537
+ return isPlainObject(value) && hasExactKeys(value, ["generationId", "manifestHash", "projectId", "schema", "version"]) &&
1538
+ value.schema == "SemantifoldActiveGeneration" && value.version == 1 &&
1539
+ typeof value.projectId == "string" && identityPattern.test(value.projectId) &&
1540
+ typeof value.generationId == "string" && generationPattern.test(value.generationId) &&
1541
+ typeof value.manifestHash == "string" && /^[a-f0-9]{64}$/u.test(value.manifestHash);
1542
+ }
1543
+ /**
1544
+ * Checks a recovery-journal value.
1545
+ * @param {unknown} value - Parsed value.
1546
+ * @returns {value is PublicationJournal} Whether the value is strict and versioned.
1547
+ */
1548
+ function isPublicationJournal(value) {
1549
+ return isPlainObject(value) && hasExactKeys(value, ["generationId", "projectId", "schema", "tempPointer", "version"]) &&
1550
+ value.schema == "SemantifoldPublicationJournal" && value.version == 1 &&
1551
+ typeof value.projectId == "string" && identityPattern.test(value.projectId) &&
1552
+ typeof value.generationId == "string" && generationPattern.test(value.generationId) &&
1553
+ value.tempPointer == `.active-generation.${value.generationId}.tmp`;
1554
+ }
1555
+ /**
1556
+ * Checks an ordinary object with exactly the expected enumerable string keys.
1557
+ * @param {Record<string, unknown>} value - Object candidate.
1558
+ * @param {readonly string[]} keys - Sorted expected keys.
1559
+ * @returns {boolean} Whether keys match exactly.
1560
+ */
1561
+ function hasExactKeys(value, keys) {
1562
+ const actual = Object.keys(value).sort(compareStrings);
1563
+ return actual.length == keys.length && actual.every((key, index) => key == keys[index]);
1564
+ }
1565
+ /**
1566
+ * Checks for an ordinary string-keyed object.
1567
+ * @param {unknown} value - Candidate value.
1568
+ * @returns {value is Record<string, unknown>} Whether the value is plain.
1569
+ */
1570
+ function isPlainObject(value) {
1571
+ return typeof value == "object" && value != null && !Array.isArray(value) && Object.getPrototypeOf(value) == Object.prototype;
1572
+ }
1573
+ /**
1574
+ * Checks for a dense ordinary array.
1575
+ * @param {unknown} value - Candidate value.
1576
+ * @returns {value is unknown[]} Whether the value is dense.
1577
+ */
1578
+ function isDenseArray(value) {
1579
+ if (!Array.isArray(value))
1580
+ return false;
1581
+ const indexedKeys = Object.keys(value).filter(key => /^(?:0|[1-9][0-9]*)$/u.test(key));
1582
+ return indexedKeys.length == value.length;
1583
+ }
1584
+ /**
1585
+ * Compares strings by Unicode code unit.
1586
+ * @param {string} left - First string.
1587
+ * @param {string} right - Second string.
1588
+ * @returns {number} Ordering.
1589
+ */
1590
+ function compareStrings(left, right) {
1591
+ return left < right ? -1 : left > right ? 1 : 0;
1592
+ }
1593
+ /**
1594
+ * Checks a narrowed filesystem error code.
1595
+ * @param {unknown} error - Opaque error.
1596
+ * @param {string} code - Expected code.
1597
+ * @returns {boolean} Whether the code matches.
1598
+ */
1599
+ function isErrorCode(error, code) {
1600
+ return error instanceof Error && "code" in error && error.code == code;
1601
+ }
1602
+ /**
1603
+ * Throws one stable publication diagnostic without embedding host paths or raw filesystem messages.
1604
+ * @param {string} code - Stable diagnostic code.
1605
+ * @param {string} projectId - Project identity.
1606
+ * @param {string} message - Stable detail.
1607
+ * @param {unknown} [error] - Preserved cause.
1608
+ * @returns {never} Always throws.
1609
+ */
1610
+ function publicationFailure(code, projectId, message, error) {
1611
+ throw new SemantifoldDiagnostic({
1612
+ cause: error instanceof Error ? error : undefined,
1613
+ code,
1614
+ language: projectId,
1615
+ message
1616
+ });
1617
+ }
1618
+ /**
1619
+ * @typedef ValidatedPublicationTarget
1620
+ * @property {string} id - Target identity.
1621
+ * @property {import("./semantic/types.js").GeneratedArtifactSet} artifactSet - Detached artifact set.
1622
+ * @property {string} sourceProjection - Source projection.
1623
+ * @property {string} buildProjection - Build projection.
1624
+ * @property {import("./semantic/types.js").PublicationTargetRole} role - Language-neutral target role.
1625
+ * @property {readonly import("./semantic/types.js").PublicationValidator[]} validators - Ordered validators.
1626
+ */
1627
+ /**
1628
+ * @typedef ActivePointer
1629
+ * @property {"SemantifoldActiveGeneration"} schema - Schema discriminator.
1630
+ * @property {1} version - Schema version.
1631
+ * @property {string} projectId - Project identity.
1632
+ * @property {string} generationId - Generation identity.
1633
+ * @property {string} manifestHash - SHA-256 generation-manifest hash.
1634
+ */
1635
+ /**
1636
+ * @typedef PublicationJournal
1637
+ * @property {"SemantifoldPublicationJournal"} schema - Schema discriminator.
1638
+ * @property {1} version - Schema version.
1639
+ * @property {string} projectId - Project identity.
1640
+ * @property {string} generationId - Candidate generation identity.
1641
+ * @property {string} tempPointer - Owned sibling temporary-pointer filename.
1642
+ */
1643
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljYXRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcHVibGljYXRpb24uanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWTtBQUVaLE9BQU8sRUFBQyxVQUFVLEVBQUUsVUFBVSxFQUFDLE1BQU0sYUFBYSxDQUFBO0FBQ2xELE9BQU8sRUFBQyxTQUFTLEVBQUMsTUFBTSxTQUFTLENBQUE7QUFDakMsT0FBTyxFQUFDLEtBQUssRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxFQUFFLEVBQUMsTUFBTSxrQkFBa0IsQ0FBQTtBQUM1RixPQUFPLElBQUksTUFBTSxXQUFXLENBQUE7QUFDNUIsT0FBTyxFQUFDLGdDQUFnQyxFQUFFLGtCQUFrQixFQUFDLE1BQU0sb0JBQW9CLENBQUE7QUFDdkYsT0FBTyxFQUFDLDBCQUEwQixFQUFDLE1BQU0sZ0JBQWdCLENBQUE7QUFDekQsT0FBTyxFQUFDLG1CQUFtQixFQUFDLE1BQU0scUJBQXFCLENBQUE7QUFDdkQsT0FBTyxFQUFDLHFCQUFxQixFQUFDLE1BQU0saUJBQWlCLENBQUE7QUFDckQsT0FBTyxFQUFDLGVBQWUsRUFBRSxhQUFhLEVBQUMsTUFBTSxjQUFjLENBQUE7QUFFM0QsTUFBTSxpQkFBaUIsR0FBRyx3QkFBd0IsQ0FBQTtBQUNsRCxNQUFNLGVBQWUsR0FBRyxhQUFhLENBQUE7QUFDckMsTUFBTSxXQUFXLEdBQUcsa0NBQWtDLENBQUE7QUFDdEQsTUFBTSxlQUFlLEdBQUcsb0JBQW9CLENBQUE7QUFDNUMsTUFBTSxpQkFBaUIsR0FBRyxxQ0FBcUMsQ0FBQTtBQUMvRCxNQUFNLGdCQUFnQixHQUFHLG9CQUFvQixDQUFBO0FBQzdDLE1BQU0sZ0JBQWdCLEdBQUcsdUVBQXVFLENBQUE7QUFDaEcsTUFBTSxXQUFXLEdBQUcsSUFBSSxHQUFHLENBQUMsQ0FBQyxhQUFhLEVBQUUsUUFBUSxFQUFF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QztBQUVEOzs7OztHQUtHO0FBQ0gsU0FBUyxjQUFjLENBQUMsSUFBSSxFQUFFLEtBQUs7SUFDakMsT0FBTyxJQUFJLEdBQUcsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUE7QUFDakQsQ0FBQztBQUVEOzs7OztHQUtHO0FBQ0gsU0FBUyxXQUFXLENBQUMsS0FBSyxFQUFFLElBQUk7SUFDOUIsT0FBTyxLQUFLLFlBQVksS0FBSyxJQUFJLE1BQU0sSUFBSSxLQUFLLElBQUksS0FBSyxDQUFDLElBQUksSUFBSSxJQUFJLENBQUE7QUFDeEUsQ0FBQztBQUVEOzs7Ozs7O0dBT0c7QUFDSCxTQUFTLGtCQUFrQixDQUFDLElBQUksRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLEtBQUs7SUFDekQsTUFBTSxJQUFJLHFCQUFxQixDQUFDO1FBQzlCLEtBQUssRUFBRSxLQUFLLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLFNBQVM7UUFDakQsSUFBSTtRQUNKLFFBQVEsRUFBRSxTQUFTO1FBQ25CLE9BQU87S0FDUixDQUFDLENBQUE7QUFDSixDQUFDO0FBRUQ7Ozs7Ozs7O0dBUUc7QUFFSDs7Ozs7OztHQU9HO0FBRUg7Ozs7Ozs7R0FPRyIsInNvdXJjZXNDb250ZW50IjpbIi8vIEB0cy1jaGVja1xuXG5pbXBvcnQge2NyZWF0ZUhhc2gsIHJhbmRvbVVVSUR9IGZyb20gXCJub2RlOmNyeXB0b1wiXG5pbXBvcnQge2NvbnN0YW50c30gZnJvbSBcIm5vZGU6ZnNcIlxuaW1wb3J0IHtsc3RhdCwgbWtkaXIsIG9wZW4sIHJlYWRGaWxlLCByZWFkZGlyLCByZWFscGF0aCwgcmVuYW1lLCBybX0gZnJvbSBcIm5vZGU6ZnMvcHJvbWlzZXNcIlxuaW1wb3J0IHBhdGggZnJvbSBcIm5vZGU6cGF0aFwiXG5pbXBvcnQge2ZpbmRQb3J0YWJsZUFydGlmYWN0UGF0aENvbmZsaWN0LCBpc1NhZmVBcnRpZmFjdFBhdGh9IGZyb20gXCIuL2FydGlmYWN0LXBhdGguanNcIlxuaW1wb3J0IHtjcmVhdGVHZW5lcmF0ZWRBcnRpZmFjdFNldH0gZnJvbSBcIi4vYXJ0aWZhY3RzLmpzXCJcbmltcG9ydCB7ZmluYWxpemVCeXRlTWFwcGluZ30gZnJvbSBcIi4vYmluYXJ5LW1hcHBpbmcuanNcIlxuaW1wb3J0IHtTZW1hbnRpZm9sZERpYWdub3N0aWN9IGZyb20gXCIuL2RpYWdub3N0aWMuanNcIlxuaW1wb3J0IHtmaW5hbGl6ZU1hcHBpbmcsIHRvU291cmNlTWFwVjN9IGZyb20gXCIuL21hcHBpbmcuanNcIlxuXG5jb25zdCBhY3RpdmVQb2ludGVyTmFtZSA9IFwiYWN0aXZlLWdlbmVyYXRpb24uanNvblwiXG5jb25zdCBnZW5lcmF0aW9uc05hbWUgPSBcImdlbmVyYXRpb25zXCJcbmNvbnN0IGpvdXJuYWxOYW1lID0gXCIuc2VtYW50aWZvbGQtcHVibGljYXRpb24tam91cm5hbFwiXG5jb25zdCBpZGVudGl0eVBhdHRlcm4gPSAvXlthLXpdW2EtejAtOS1dKiQvdVxuY29uc3QgZ2VuZXJhdGlvblBhdHRlcm4gPSAvXltBLVphLXowLTldW0EtWmEtejAtOS5fLV17MCwxMjd9JC91XG5jb25zdCBidWlsZFJvbGVQYXR0ZXJuID0gL15bYS16XVthLXowLTktXSokL3VcbmNvbnN0IG1lZGlhVHlwZVBhdHRlcm4gPSAvXltBLVphLXowLTkhIyQmXl8uKy1dK1xcL1tBLVphLXowLTkhIyQmXl8uKy1dKyg/OjtbXFx1MDAyMC1cXHUwMDdlXSspPyQvdVxuY29uc3QgdGFyZ2V0Um9sZXMgPSBuZXcgU2V0KFtcImFwcGxpY2F0aW9uXCIsIFwiYmluYXJ5XCIsIFwidGV4dFwiXSlcbmNvbnN0IHB1YmxpY2F0aW9uQm91bmRhcmllcyA9IG5ldyBTZXQoW1xuICBcImFmdGVyLXN0YWdlXCIsXG4gIFwiYmVmb3JlLXBvaW50ZXItcmVwbGFjZVwiLFxuICBcImFmdGVyLXBvaW50ZXItcmVwbGFjZVwiLFxuICBcImJlZm9yZS1jbGVhbnVwXCIsXG4gIFwiYmVmb3JlLWpvdXJuYWwtcmVtb3ZlXCJcbl0pXG4vKiogQHR5cGUge1dlYWtNYXA8R2VuZXJhdGVkQXJ0aWZhY3RQdWJsaXNoZXIsIHtib3VuZGFyeTogc3RyaW5nLCBlcnJvcjogRXJyb3J9Pn0gKi9cbmNvbnN0IGluamVjdGVkUHVibGljYXRpb25GYWlsdXJlcyA9IG5ldyBXZWFrTWFwKClcbi8qKiBAdHlwZSB7V2Vha01hcDxHZW5lcmF0ZWRBcnRpZmFjdFB1Ymxpc2hlciwgKG9wZXJhdGlvbjogc3RyaW5nKSA9PiB2b2lkPn0gKi9cbmNvbnN0IHB1YmxpY2F0aW9uRmlsZXN5c3RlbU9ic2VydmVycyA9IG5ldyBXZWFrTWFwKClcblxuLyoqXG4gKiBJbnN0YWxscyBvbmUgaW50ZXJuYWwsIG9uZS1zaG90IGRldGVybWluaXN0aWMgZmFpbHVyZSB1c2VkIGJ5IHJlYWwtZmlsZXN5c3RlbSBpbnRlcnJ1cHRpb24gc3BlY3MuXG4gKiBUaGlzIGhlbHBlciBpcyBpbnRlbnRpb25hbGx5IG5vdCBwYXJ0IG9mIHRoZSBwYWNrYWdlIHJvb3QgQVBJLlxuICogQHBhcmFtIHtHZW5lcmF0ZWRBcnRpZmFjdFB1Ymxpc2hlcn0gcHVibGlzaGVyIC0gUHVibGlzaGVyIGluc3RhbmNlLlxuICogQHBhcmFtIHtcImFmdGVyLXN0YWdlXCIgfCBcImJlZm9yZS1wb2ludGVyLXJlcGxhY2VcIiB8IFwiYWZ0ZXItcG9pbnRlci1yZXBsYWNlXCIgfCBcImJlZm9yZS1jbGVhbnVwXCIgfCBcImJlZm9yZS1qb3VybmFsLXJlbW92ZVwifSBib3VuZGFyeSAtIEV4YWN0IGxpZmVjeWNsZSBib3VuZGFyeS5cbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gSW5qZWN0ZWQgZmFpbHVyZS5cbiAqIEByZXR1cm5zIHt2b2lkfVxuICovXG5leHBvcnQgZnVuY3Rpb24gaW5qZWN0UHVibGljYXRpb25GYWlsdXJlKHB1Ymxpc2hlciwgYm91bmRhcnksIGVycm9yKSB7XG4gIGlmICghKHB1Ymxpc2hlciBpbnN0YW5jZW9mIEdlbmVyYXRlZEFydGlmYWN0UHVibGlzaGVyKSB8fCAhcHVibGljYXRpb25Cb3VuZGFyaWVzLmhhcyhib3VuZGFyeSkgfHwgIShlcnJvciBpbnN0YW5jZW9mIEVycm9yKSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJJbnZhbGlkIHB1YmxpY2F0aW9uIGZhaWx1cmUgaW5qZWN0aW9uLlwiKVxuICB9XG4gIGluamVjdGVkUHVibGljYXRpb25GYWlsdXJlcy5zZXQocHVibGlzaGVyLCB7Ym91bmRhcnksIGVycm9yfSlcbn1cblxuLyoqXG4gKiBJbnN0YWxscyBhbiBpbnRlcm5hbCBkZXRlcm1pbmlzdGljIGZpbGVzeXN0ZW0tb3BlcmF0aW9uIG9ic2VydmVyIGZvciBkdXJhYmlsaXR5IHNwZWNzLlxuICogVGhpcyBoZWxwZXIgaXMgaW50ZW50aW9uYWxseSBub3QgcGFydCBvZiB0aGUgcGFja2FnZSByb290IEFQSS5cbiAqIEBwYXJhbSB7R2VuZXJhdGVkQXJ0aWZhY3RQdWJsaXNoZXJ9IHB1Ymxpc2hlciAtIFB1Ymxpc2hlciBpbnN0YW5jZS5cbiAqIEBwYXJhbSB7KG9wZXJhdGlvbjogc3RyaW5nKSA9PiB2b2lkfSBvYnNlcnZlciAtIFN5bmNocm9ub3VzIG9wZXJhdGlvbiBvYnNlcnZlci5cbiAqIEByZXR1cm5zIHt2b2lkfVxuICovXG5leHBvcnQgZnVuY3Rpb24gb2JzZXJ2ZVB1YmxpY2F0aW9uRmlsZXN5c3RlbShwdWJsaXNoZXIsIG9ic2VydmVyKSB7XG4gIGlmICghKHB1Ymxpc2hlciBpbnN0YW5jZW9mIEdlbmVyYXRlZEFydGlmYWN0UHVibGlzaGVyKSB8fCB0eXBlb2Ygb2JzZXJ2ZXIgIT0gXCJmdW5jdGlvblwiKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIkludmFsaWQgcHVibGljYXRpb24gZmlsZXN5c3RlbSBvYnNlcnZlci5cIilcbiAgfVxuICBwdWJsaWNhdGlvbkZpbGVzeXN0ZW1PYnNlcnZlcnMuc2V0KHB1Ymxpc2hlciwgb2JzZXJ2ZXIpXG59XG5cbi8qKlxuICogT3ducyB0cmFuc2FjdGlvbmFsIHB1YmxpY2F0aW9uIGluIG9uZSBkZWRpY2F0ZWQgZGlyZWN0b3J5IGJlbmVhdGggYSBjYW5vbmljYWwgcHJvamVjdCByb290LlxuICovXG5leHBvcnQgY2xhc3MgR2VuZXJhdGVkQXJ0aWZhY3RQdWJsaXNoZXIge1xuICAvKiogQHR5cGUge3N0cmluZ30gKi9cbiAgI3Byb2plY3RJZFxuICAvKiogQHR5cGUge3N0cmluZ30gKi9cbiAgI3Byb2plY3RSb290XG4gIC8qKiBAdHlwZSB7c3RyaW5nfSAqL1xuICAjcHVibGljYXRpb25Sb290XG4gIC8qKiBAdHlwZSB7cmVhZG9ubHkgc3RyaW5nW119ICovXG4gICNzb3VyY2VSb290c1xuICAvKiogQHR5cGUge1Byb21pc2U8dm9pZD59ICovXG4gICNwdWJsaWNhdGlvblRhaWwgPSBQcm9taXNlLnJlc29sdmUoKVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgcHJvamVjdC1zY29wZWQgcHVibGlzaGVyIHdpdGhvdXQgdG91Y2hpbmcgdGhlIGZpbGVzeXN0ZW0uXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIC0gUHVibGlzaGVyIGlkZW50aXR5IGFuZCBvd25lZCBwYXRocy5cbiAgICogQHBhcmFtIHtzdHJpbmd9IG9wdGlvbnMucHJvamVjdElkIC0gU3RhYmxlIGxvd2VyY2FzZSBwcm9qZWN0IGlkZW50aXR5LlxuICAgKiBAcGFyYW0ge3N0cmluZ30gb3B0aW9ucy5wcm9qZWN0Um9vdCAtIENhbm9uaWNhbCBhYnNvbHV0ZSBwcm9qZWN0IHJvb3QuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBvcHRpb25zLnB1YmxpY2F0aW9uUm9vdCAtIENhbm9uaWNhbCBhYnNvbHV0ZSBwdWJsaXNoZXItb3duZWQgZGlyZWN0b3J5IGJlbmVhdGggdGhlIHByb2plY3Qgcm9vdC5cbiAgICogQHBhcmFtIHtyZWFkb25seSBzdHJpbmdbXX0gb3B0aW9ucy5zb3VyY2VSb290cyAtIENhbm9uaWNhbCBhYnNvbHV0ZSBwcm9qZWN0IHNvdXJjZSByb290cyBrZXB0IGRpc2pvaW50IGZyb20gcHVibGljYXRpb24uXG4gICAqL1xuICBjb25zdHJ1Y3RvcihvcHRpb25zKSB7XG4gICAgaWYgKCFpc1BsYWluT2JqZWN0KG9wdGlvbnMpKSB7XG4gICAgICBwdWJsaWNhdGlvbkZhaWx1cmUoXCJJTlZBTElEX1BVQkxJQ0FUSU9OX1JFUVVFU1RcIiwgXCJwdWJsaWNhdGlvblwiLCBcIlB1Ymxpc2hlciBvcHRpb25zIG11c3QgYmUgYSBwbGFpbiBvYmplY3QuXCIpXG4gICAgfVxuICAgIGNvbnN0IHtwcm9qZWN0SWQsIHByb2plY3RSb290LCBwdWJsaWNhdGlvblJvb3QsIHNvdXJjZVJvb3RzfSA9IG9wdGlvbnNcblxuICAgIGlmICghaWRlbnRpdHlQYXR0ZXJuLnRlc3QocHJvamVjdElkID8/IFwiXCIpKSB7XG4gICAgICBwdWJsaWNhdGlvbkZhaWx1cmUoXCJJTlZBTElEX1BVQkxJQ0FUSU9OX1JFUVVFU1RcIiwgXCJwdWJsaWNhdGlvblwiLCBcIlByb2plY3QgaWRlbnRpdHkgbXVzdCBiZSBhIHN0YWJsZSBsb3dlcmNhc2UgSUQuXCIpXG4gICAgfVxuICAgIGlmICghaXNDYW5vbmljYWxBYnNvbHV0ZVBhdGgocHJvamVjdFJvb3QpIHx8ICFpc0Nhbm9uaWNhbEFic29sdXRlUGF0aChwdWJsaWNhdGlvblJvb3QpIHx8XG4gICAgICAhaXNTdHJpY3RQYXRoRGVzY2VuZGFudChwcm9qZWN0Um9vdCwgcHVibGljYXRpb25Sb290KSkge1xuICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiSU5WQUxJRF9QVUJMSUNBVElPTl9ST09UXCIsIHByb2plY3RJZCxcbiAgICAgICAgXCJQcm9qZWN0IGFuZCBwdWJsaWNhdGlvbiByb290cyBtdXN0IGJlIGNhbm9uaWNhbCBhYnNvbHV0ZSBwYXRocyB3aXRoIHB1YmxpY2F0aW9uIHN0cmljdGx5IGJlbmVhdGggdGhlIHByb2plY3Qgcm9vdC5cIilcbiAgICB9XG4gICAgaWYgKCFpc0RlbnNlQXJyYXkoc291cmNlUm9vdHMpIHx8IHNvdXJjZVJvb3RzLmxlbmd0aCA9PSAwKSB7XG4gICAgICBwdWJsaWNhdGlvbkZhaWx1cmUoXCJJTlZBTElEX1BVQkxJQ0FUSU9OX1JPT1RcIiwgcHJvamVjdElkLCBcIlNvdXJjZSByb290cyBtdXN0IGJlIGEgbm9uLWVtcHR5IGFycmF5IG9mIGNhbm9uaWNhbCBhYnNvbHV0ZSBwYXRocy5cIilcbiAgICB9XG4gICAgLyoqIEB0eXBlIHtzdHJpbmdbXX0gKi9cbiAgICBjb25zdCB2YWxpZGF0ZWRTb3VyY2VSb290cyA9IFtdXG5cbiAgICBmb3IgKGxldCBpbmRleCA9IDA7IGluZGV4IDwgc291cmNlUm9vdHMubGVuZ3RoOyBpbmRleCArPSAxKSB7XG4gICAgICBjb25zdCBzb3VyY2VSb290ID0gc291cmNlUm9vdHNbaW5kZXhdXG5cbiAgICAgIGlmICghaXNDYW5vbmljYWxBYnNvbHV0ZVBhdGgoc291cmNlUm9vdCkpIHtcbiAgICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiSU5WQUxJRF9QVUJMSUNBVElPTl9ST09UXCIsIHByb2plY3RJZCxcbiAgICAgICAgICBcIlNvdXJjZSByb290cyBtdXN0IGJlIGEgbm9uLWVtcHR5IGFycmF5IG9mIGNhbm9uaWNhbCBhYnNvbHV0ZSBwYXRocy5cIilcbiAgICAgIH1cbiAgICAgIGlmICghaXNQYXRoV2l0aGluKHByb2plY3RSb290LCBzb3VyY2VSb290KSkge1xuICAgICAgICBwdWJsaWNhdGlvbkZhaWx1cmUoXCJJTlZBTElEX1BVQkxJQ0FUSU9OX1JPT1RcIiwgcHJvamVjdElkLFxuICAgICAgICAgIFwiU291cmNlIHJvb3RzIG11c3QgcmVtYWluIHdpdGhpbiB0aGUgY2Fub25pY2FsIHByb2plY3Qgcm9vdC5cIilcbiAgICAgIH1cbiAgICAgIGlmIChwYXRoc092ZXJsYXAocHVibGljYXRpb25Sb290LCBzb3VyY2VSb290KSkge1xuICAgICAgICBwdWJsaWNhdGlvbkZhaWx1cmUoXCJQVUJMSUNBVElPTl9TT1VSQ0VfT1ZFUkxBUFwiLCBwcm9qZWN0SWQsXG4gICAgICAgICAgXCJQdWJsaWNhdGlvbiByb290IGFuZCBzb3VyY2Ugcm9vdHMgbXVzdCBiZSBkaXNqb2ludC5cIilcbiAgICAgIH1cbiAgICAgIHZhbGlkYXRlZFNvdXJjZVJvb3RzLnB1c2goc291cmNlUm9vdClcbiAgICB9XG5cbiAgICB0aGlzLiNwcm9qZWN0SWQgPSBwcm9qZWN0SWRcbiAgICB0aGlzLiNwcm9qZWN0Um9vdCA9IHByb2plY3RSb290XG4gICAgdGhpcy4jcHVibGljYXRpb25Sb290ID0gcHVibGljYXRpb25Sb290XG4gICAgdGhpcy4jc291cmNlUm9vdHMgPSBPYmplY3QuZnJlZXplKHZhbGlkYXRlZFNvdXJjZVJvb3RzKVxuICB9XG5cbiAgLyoqXG4gICAqIFN0YWdlcywgdmFsaWRhdGVzLCBhbmQgcHVibGlzaGVzIG9uZSBjb21wbGV0ZSBpbW11dGFibGUgcHJvamVjdCBnZW5lcmF0aW9uLlxuICAgKiBDYWxscyBvbiBvbmUgcHVibGlzaGVyIGluc3RhbmNlIGFyZSBzZXJpYWxpemVkIGluIGludm9jYXRpb24gb3JkZXIuXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5QdWJsaWNhdGlvblJlcXVlc3R9IHJlcXVlc3QgLSBDb21wbGV0ZSBwdWJsaWNhdGlvbiByZXF1ZXN0LlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxpbXBvcnQoXCIuL3NlbWFudGljL3R5cGVzLmpzXCIpLlB1Ymxpc2hlZEdlbmVyYXRpb24+fSBDb21taXR0ZWQgaW1tdXRhYmxlIHNuYXBzaG90LlxuICAgKi9cbiAgcHVibGlzaChyZXF1ZXN0KSB7XG4gICAgLyoqIEB0eXBlIHsodmFsdWU6IGltcG9ydChcIi4vc2VtYW50aWMvdHlwZXMuanNcIikuUHVibGlzaGVkR2VuZXJhdGlvbikgPT4gdm9pZH0gKi9cbiAgICBsZXQgcmVzb2x2ZVJlc3VsdFxuICAgIC8qKiBAdHlwZSB7KHJlYXNvbj86IHVua25vd24pID0+IHZvaWR9ICovXG4gICAgbGV0IHJlamVjdFJlc3VsdFxuICAgIGNvbnN0IHJlc3VsdCA9IG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIHJlc29sdmVSZXN1bHQgPSByZXNvbHZlXG4gICAgICByZWplY3RSZXN1bHQgPSByZWplY3RcbiAgICB9KVxuICAgIGNvbnN0IG9wZXJhdGlvbiA9IHRoaXMuI3B1YmxpY2F0aW9uVGFpbC50aGVuKGFzeW5jICgpID0+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHJlc29sdmVSZXN1bHQoYXdhaXQgdGhpcy4jcHVibGlzaChyZXF1ZXN0KSlcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIHJlamVjdFJlc3VsdChlcnJvcilcbiAgICAgIH1cbiAgICB9KVxuXG4gICAgdGhpcy4jcHVibGljYXRpb25UYWlsID0gb3BlcmF0aW9uLmNhdGNoKCgpID0+IHt9KVxuXG4gICAgcmV0dXJuIHJlc3VsdFxuICB9XG5cbiAgLyoqXG4gICAqIFJlc29sdmVzIHRoZSBhY3RpdmUgcG9pbnRlciBleGFjdGx5IG9uY2UgYW5kIHZlcmlmaWVzIHRoZSByZWZlcmVuY2VkIGltbXV0YWJsZSBnZW5lcmF0aW9uLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxpbXBvcnQoXCIuL3NlbWFudGljL3R5cGVzLmpzXCIpLlB1Ymxpc2hlZEdlbmVyYXRpb24+fSBWZXJpZmllZCBwb2ludGVyLW9uY2Ugc25hcHNob3QuXG4gICAqL1xuICBhc3luYyByZXNvbHZlQWN0aXZlKCkge1xuICAgIGF3YWl0IHRoaXMuI3ByZXBhcmVSb290KClcbiAgICBjb25zdCBwb2ludGVyUGF0aCA9IHBhdGguam9pbih0aGlzLiNwdWJsaWNhdGlvblJvb3QsIGFjdGl2ZVBvaW50ZXJOYW1lKVxuICAgIGNvbnN0IHBvaW50ZXIgPSBhd2FpdCByZWFkQWN0aXZlUG9pbnRlcihwb2ludGVyUGF0aCwgdGhpcy4jcHJvamVjdElkLCBmYWxzZSlcblxuICAgIGlmICghcG9pbnRlcikgcHVibGljYXRpb25GYWlsdXJlKFwiQUNUSVZFX0dFTkVSQVRJT05fTUlTU0lOR1wiLCB0aGlzLiNwcm9qZWN0SWQsIFwiTm8gYWN0aXZlIGdlbmVyYXRpb24gaGFzIGJlZW4gcHVibGlzaGVkLlwiKVxuICAgIGNvbnN0IGdlbmVyYXRpb24gPSBhd2FpdCB2ZXJpZnlQdWJsaXNoZWRHZW5lcmF0aW9uKHRoaXMuI3B1YmxpY2F0aW9uUm9vdCwgdGhpcy4jcHJvamVjdElkLCBwb2ludGVyLCBmYWxzZSlcbiAgICBjb25zdCBjbGVhbnVwUGVuZGluZyA9IGF3YWl0IGhhc0NvbW1pdHRlZENsZWFudXBKb3VybmFsKHRoaXMuI3B1YmxpY2F0aW9uUm9vdCwgdGhpcy4jcHJvamVjdElkLCBwb2ludGVyLmdlbmVyYXRpb25JZClcblxuICAgIHJldHVybiBwdWJsaXNoZWRHZW5lcmF0aW9uKHRoaXMuI3B1YmxpY2F0aW9uUm9vdCwgZ2VuZXJhdGlvbi5tYW5pZmVzdCwgY2xlYW51cFBlbmRpbmcpXG4gIH1cblxuICAvKipcbiAgICogUGVyZm9ybXMgb25lIHNlcmlhbGl6ZWQgcHVibGljYXRpb24uXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5QdWJsaWNhdGlvblJlcXVlc3R9IHJlcXVlc3QgLSBDb21wbGV0ZSByZXF1ZXN0LlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxpbXBvcnQoXCIuL3NlbWFudGljL3R5cGVzLmpzXCIpLlB1Ymxpc2hlZEdlbmVyYXRpb24+fSBQdWJsaWNhdGlvbiByZXN1bHQuXG4gICAqL1xuICBhc3luYyAjcHVibGlzaChyZXF1ZXN0KSB7XG4gICAgY29uc3QgdmFsaWRhdGVkID0gdmFsaWRhdGVQdWJsaWNhdGlvblJlcXVlc3QocmVxdWVzdCwgdGhpcy4jcHJvamVjdElkKVxuXG4gICAgYXdhaXQgdGhpcy4jcHJlcGFyZVJvb3QoKVxuICAgIGF3YWl0IHJlY29uY2lsZVB1YmxpY2F0aW9uKHRoaXMuI3B1YmxpY2F0aW9uUm9vdCwgdGhpcy4jcHJvamVjdElkLCB0aGlzKVxuICAgIGF3YWl0IHZlcmlmeUF0b21pY1JlcGxhY2VtZW50KHRoaXMuI3B1YmxpY2F0aW9uUm9vdCwgdGhpcy4jcHJvamVjdElkKVxuICAgIGF3YWl0IHZhbGlkYXRlRXhpc3RpbmdQb2ludGVyKHRoaXMuI3B1YmxpY2F0aW9uUm9vdCwgdGhpcy4jcHJvamVjdElkKVxuXG4gICAgY29uc3QgZ2VuZXJhdGlvblBhdGggPSBwYXRoLmpvaW4odGhpcy4jcHVibGljYXRpb25Sb290LCBnZW5lcmF0aW9uc05hbWUsIHZhbGlkYXRlZC5nZW5lcmF0aW9uSWQpXG4gICAgY29uc3QgbWFuaWZlc3RQYXRoID0gcGF0aC5qb2luKGdlbmVyYXRpb25QYXRoLCBcIm1hbmlmZXN0Lmpzb25cIilcbiAgICBjb25zdCB0ZW1wUG9pbnRlck5hbWUgPSBgLmFjdGl2ZS1nZW5lcmF0aW9uLiR7dmFsaWRhdGVkLmdlbmVyYXRpb25JZH0udG1wYFxuICAgIGNvbnN0IHRlbXBQb2ludGVyUGF0aCA9IHBhdGguam9pbih0aGlzLiNwdWJsaWNhdGlvblJvb3QsIHRlbXBQb2ludGVyTmFtZSlcbiAgICBjb25zdCBqb3VybmFsUGF0aCA9IHBhdGguam9pbih0aGlzLiNwdWJsaWNhdGlvblJvb3QsIGpvdXJuYWxOYW1lLCBgJHt2YWxpZGF0ZWQuZ2VuZXJhdGlvbklkfS5qc29uYClcbiAgICBsZXQgY29tbWl0dGVkID0gZmFsc2VcbiAgICBsZXQgam91cm5hbENyZWF0ZWQgPSBmYWxzZVxuICAgIGxldCBnZW5lcmF0aW9uQ3JlYXRlZCA9IGZhbHNlXG4gICAgbGV0IHRlbXBQb2ludGVyQ3JlYXRlZCA9IGZhbHNlXG4gICAgbGV0IGZhaWx1cmVDb2RlID0gXCJQVUJMSUNBVElPTl9TVEFHRV9XUklURV9GQUlMRURcIlxuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGFzc2VydEFic2VudChnZW5lcmF0aW9uUGF0aCwgXCJQVUJMSUNBVElPTl9VTk9XTkVEX0NPTkZMSUNUXCIsIHRoaXMuI3Byb2plY3RJZCxcbiAgICAgICAgXCJHZW5lcmF0aW9uIGlkZW50aXR5IGlzIGFscmVhZHkgb3duZWQgb3IgYW1iaWd1b3VzLlwiKVxuICAgICAgYXdhaXQgYXNzZXJ0QWJzZW50KHRlbXBQb2ludGVyUGF0aCwgXCJQVUJMSUNBVElPTl9VTk9XTkVEX0NPTkZMSUNUXCIsIHRoaXMuI3Byb2plY3RJZCxcbiAgICAgICAgXCJUZW1wb3JhcnkgYWN0aXZlIHBvaW50ZXIgcGF0aCBpcyBhbHJlYWR5IG93bmVkIG9yIGFtYmlndW91cy5cIilcbiAgICAgIGF3YWl0IGFzc2VydEFic2VudChqb3VybmFsUGF0aCwgXCJQVUJMSUNBVElPTl9VTk9XTkVEX0NPTkZMSUNUXCIsIHRoaXMuI3Byb2plY3RJZCxcbiAgICAgICAgXCJQdWJsaWNhdGlvbiBqb3VybmFsIGlkZW50aXR5IGlzIGFscmVhZHkgb3duZWQgb3IgYW1iaWd1b3VzLlwiKVxuICAgICAgY29uc3Qgam91cm5hbCA9IHtcbiAgICAgICAgZ2VuZXJhdGlvbklkOiB2YWxpZGF0ZWQuZ2VuZXJhdGlvbklkLFxuICAgICAgICBwcm9qZWN0SWQ6IHRoaXMuI3Byb2plY3RJZCxcbiAgICAgICAgc2NoZW1hOiBcIlNlbWFudGlmb2xkUHVibGljYXRpb25Kb3VybmFsXCIsXG4gICAgICAgIHRlbXBQb2ludGVyOiB0ZW1wUG9pbnRlck5hbWUsXG4gICAgICAgIHZlcnNpb246IDFcbiAgICAgIH1cblxuICAgICAgYXdhaXQgd3JpdGVTeW5jZWRGaWxlKGpvdXJuYWxQYXRoLCBzZXJpYWxpemVKc29uKGpvdXJuYWwpLCBcInd4XCIpXG4gICAgICBqb3VybmFsQ3JlYXRlZCA9IHRydWVcbiAgICAgIGF3YWl0IHN5bmNEaXJlY3RvcnkocGF0aC5kaXJuYW1lKGpvdXJuYWxQYXRoKSlcbiAgICAgIGF3YWl0IG1rZGlyKGdlbmVyYXRpb25QYXRoLCB7bW9kZTogMG83MDB9KVxuICAgICAgZ2VuZXJhdGlvbkNyZWF0ZWQgPSB0cnVlXG4gICAgICBhd2FpdCBzeW5jRGlyZWN0b3J5KHBhdGguZGlybmFtZShnZW5lcmF0aW9uUGF0aCkpXG5cbiAgICAgIC8qKiBAdHlwZSB7aW1wb3J0KFwiLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5HZW5lcmF0aW9uVGFyZ2V0TWFuaWZlc3RbXX0gKi9cbiAgICAgIGNvbnN0IHRhcmdldE1hbmlmZXN0cyA9IFtdXG5cbiAgICAgIGZvciAoY29uc3QgdGFyZ2V0IG9mIHZhbGlkYXRlZC50YXJnZXRzKSB7XG4gICAgICAgIHRhcmdldE1hbmlmZXN0cy5wdXNoKGF3YWl0IHN0YWdlVGFyZ2V0KGdlbmVyYXRpb25QYXRoLCB0YXJnZXQsIHRoaXMuI3Byb2plY3RJZCkpXG4gICAgICB9XG4gICAgICByZWFjaFB1YmxpY2F0aW9uQm91bmRhcnkodGhpcywgXCJhZnRlci1zdGFnZVwiKVxuICAgICAgY29uc3QgbWFuaWZlc3RDYW5kaWRhdGUgPSAvKiogQHR5cGUge2ltcG9ydChcIi4vc2VtYW50aWMvdHlwZXMuanNcIikuR2VuZXJhdGlvbk1hbmlmZXN0fSAqLyAoe1xuICAgICAgICBnZW5lcmF0aW9uSWQ6IHZhbGlkYXRlZC5nZW5lcmF0aW9uSWQsXG4gICAgICAgIHByb2plY3RJZDogdGhpcy4jcHJvamVjdElkLFxuICAgICAgICBzY2hlbWE6IC8qKiBAdHlwZSB7Y29uc3R9ICovIChcIlNlbWFudGlmb2xkR2VuZXJhdGlvbk1hbmlmZXN0XCIpLFxuICAgICAgICB0YXJnZXRzOiB0YXJnZXRNYW5pZmVzdHMsXG4gICAgICAgIHZlcnNpb246IC8qKiBAdHlwZSB7Y29uc3R9ICovICgxKVxuICAgICAgfSlcbiAgICAgIGNvbnN0IG1hbmlmZXN0Qnl0ZXMgPSBzZXJpYWxpemVKc29uKG1hbmlmZXN0Q2FuZGlkYXRlKVxuICAgICAgY29uc3QgbWFuaWZlc3QgPSB2YWxpZGF0ZUdlbmVyYXRpb25NYW5pZmVzdChKU09OLnBhcnNlKG1hbmlmZXN0Qnl0ZXMudG9TdHJpbmcoXCJ1dGY4XCIpKSwgdGhpcy4jcHJvamVjdElkLFxuICAgICAgICB2YWxpZGF0ZWQuZ2VuZXJhdGlvbklkKVxuXG4gICAgICBhd2FpdCB3cml0ZVN5bmNlZEZpbGUobWFuaWZlc3RQYXRoLCBtYW5pZmVzdEJ5dGVzLCBcInd4XCIpXG4gICAgICBhd2FpdCBzeW5jVHJlZURpcmVjdG9yaWVzKGdlbmVyYXRpb25QYXRoKVxuICAgICAgYXdhaXQgdmVyaWZ5TWFuaWZlc3RGaWxlcyhnZW5lcmF0aW9uUGF0aCwgbWFuaWZlc3QsIHRoaXMuI3Byb2plY3RJZClcbiAgICAgIGZhaWx1cmVDb2RlID0gXCJQVUJMSUNBVElPTl9QT0lOVEVSX0ZBSUxFRFwiXG5cbiAgICAgIGNvbnN0IHBvaW50ZXIgPSB7XG4gICAgICAgIGdlbmVyYXRpb25JZDogdmFsaWRhdGVkLmdlbmVyYXRpb25JZCxcbiAgICAgICAgbWFuaWZlc3RIYXNoOiBzaGEyNTYobWFuaWZlc3RCeXRlcyksXG4gICAgICAgIHByb2plY3RJZDogdGhpcy4jcHJvamVjdElkLFxuICAgICAgICBzY2hlbWE6IFwiU2VtYW50aWZvbGRBY3RpdmVHZW5lcmF0aW9uXCIsXG4gICAgICAgIHZlcnNpb246IDFcbiAgICAgIH1cblxuICAgICAgYXdhaXQgd3JpdGVTeW5jZWRGaWxlKHRlbXBQb2ludGVyUGF0aCwgc2VyaWFsaXplSnNvbihwb2ludGVyKSwgXCJ3eFwiLCAoKSA9PiB7XG4gICAgICAgIHRlbXBQb2ludGVyQ3JlYXRlZCA9IHRydWVcbiAgICAgIH0pXG4gICAgICByZWFjaFB1YmxpY2F0aW9uQm91bmRhcnkodGhpcywgXCJiZWZvcmUtcG9pbnRlci1yZXBsYWNlXCIpXG4gICAgICBhd2FpdCByZW5hbWUodGVtcFBvaW50ZXJQYXRoLCBwYXRoLmpvaW4odGhpcy4jcHVibGljYXRpb25Sb290LCBhY3RpdmVQb2ludGVyTmFtZSkpXG4gICAgICB0ZW1wUG9pbnRlckNyZWF0ZWQgPSBmYWxzZVxuICAgICAgY29tbWl0dGVkID0gdHJ1ZVxuICAgICAgcmVhY2hQdWJsaWNhdGlvbkJvdW5kYXJ5KHRoaXMsIFwiYWZ0ZXItcG9pbnRlci1yZXBsYWNlXCIpXG4gICAgICBhd2FpdCBzeW5jRGlyZWN0b3J5KHRoaXMuI3B1YmxpY2F0aW9uUm9vdClcblxuICAgICAgbGV0IGNsZWFudXBQZW5kaW5nID0gZmFsc2VcblxuICAgICAgdHJ5IHtcbiAgICAgICAgcmVhY2hQdWJsaWNhdGlvbkJvdW5kYXJ5KHRoaXMsIFwiYmVmb3JlLWNsZWFudXBcIilcbiAgICAgICAgYXdhaXQgcmVtb3ZlSm91cm5hbE93bmVkU3RhdGUoe1xuICAgICAgICAgIGpvdXJuYWxQYXRoLFxuICAgICAgICAgIHByb2plY3RJZDogdGhpcy4jcHJvamVjdElkLFxuICAgICAgICAgIHB1YmxpY2F0aW9uUm9vdDogdGhpcy4jcHVibGljYXRpb25Sb290LFxuICAgICAgICAgIHB1Ymxpc2hlcjogdGhpc1xuICAgICAgICB9KVxuICAgICAgfSBjYXRjaCAoX2Vycm9yKSB7XG4gICAgICAgIGNsZWFudXBQZW5kaW5nID0gdHJ1ZVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gcHVibGlzaGVkR2VuZXJhdGlvbih0aGlzLiNwdWJsaWNhdGlvblJvb3QsIGRlZXBGcmVlemUobWFuaWZlc3QpLCBjbGVhbnVwUGVuZGluZylcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgaWYgKCFjb21taXR0ZWQpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBhd2FpdCByZW1vdmVKb3VybmFsT3duZWRTdGF0ZSh7XG4gICAgICAgICAgICAuLi4oZ2VuZXJhdGlvbkNyZWF0ZWQgPyB7Y2FuZGlkYXRlUGF0aDogZ2VuZXJhdGlvblBhdGh9IDoge30pLFxuICAgICAgICAgICAgLi4uKGpvdXJuYWxDcmVhdGVkID8ge2pvdXJuYWxQYXRofSA6IHt9KSxcbiAgICAgICAgICAgIHByb2plY3RJZDogdGhpcy4jcHJvamVjdElkLFxuICAgICAgICAgICAgcHVibGljYXRpb25Sb290OiB0aGlzLiNwdWJsaWNhdGlvblJvb3QsXG4gICAgICAgICAgICBwdWJsaXNoZXI6IHRoaXMsXG4gICAgICAgICAgICAuLi4odGVtcFBvaW50ZXJDcmVhdGVkID8ge3RlbXBvcmFyeVBvaW50ZXJQYXRoOiB0ZW1wUG9pbnRlclBhdGh9IDoge30pXG4gICAgICAgICAgfSlcbiAgICAgICAgfSBjYXRjaCAoY2xlYW51cEVycm9yKSB7XG4gICAgICAgICAgaWYgKGNsZWFudXBFcnJvciBpbnN0YW5jZW9mIFNlbWFudGlmb2xkRGlhZ25vc3RpYykgdGhyb3cgY2xlYW51cEVycm9yXG4gICAgICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiUFVCTElDQVRJT05fUkVDT1ZFUllfRkFJTEVEXCIsIHRoaXMuI3Byb2plY3RJZCxcbiAgICAgICAgICAgIFwiRmFpbGVkIHB1YmxpY2F0aW9uIGxlZnQgc3RhdGUgdGhhdCByZXF1aXJlcyByZWNvdmVyeS5cIiwgY2xlYW51cEVycm9yKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBTZW1hbnRpZm9sZERpYWdub3N0aWMpIHRocm93IGVycm9yXG5cbiAgICAgIHB1YmxpY2F0aW9uRmFpbHVyZShmYWlsdXJlQ29kZSwgdGhpcy4jcHJvamVjdElkLFxuICAgICAgICBjb21taXR0ZWRcbiAgICAgICAgICA/IFwiQWN0aXZlIGdlbmVyYXRpb24gY2hhbmdlZCwgYnV0IGR1cmFibGUgcG9pbnRlciBwdWJsaWNhdGlvbiBkaWQgbm90IGNvbXBsZXRlLlwiXG4gICAgICAgICAgOiBcIkNhbmRpZGF0ZSBnZW5lcmF0aW9uIGNvdWxkIG5vdCBiZSBzdGFnZWQuXCIsIGVycm9yKVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGFuZCB2YWxpZGF0ZXMgb3duZWQgcm9vdCBkaXJlY3RvcmllcyBhbmQgc291cmNlLXJvb3Qgc2VwYXJhdGlvbi5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IENvbXBsZXRpb24uXG4gICAqL1xuICBhc3luYyAjcHJlcGFyZVJvb3QoKSB7XG4gICAgYXdhaXQgZW5zdXJlRGlyZWN0b3J5V2l0aG91dFN5bWxpbmtzKHRoaXMuI3Byb2plY3RSb290LCBmYWxzZSwgdGhpcy4jcHJvamVjdElkKVxuICAgIGF3YWl0IGVuc3VyZURpcmVjdG9yeVdpdGhvdXRTeW1saW5rcyh0aGlzLiNwdWJsaWNhdGlvblJvb3QsIHRydWUsIHRoaXMuI3Byb2plY3RJZClcbiAgICBsZXQgZXhhY3RQcm9qZWN0XG4gICAgbGV0IGV4YWN0UHVibGljYXRpb25cblxuICAgIHRyeSB7XG4gICAgICBleGFjdFByb2plY3QgPSBhd2FpdCByZWFscGF0aCh0aGlzLiNwcm9qZWN0Um9vdClcbiAgICAgIGV4YWN0UHVibGljYXRpb24gPSBhd2FpdCByZWFscGF0aCh0aGlzLiNwdWJsaWNhdGlvblJvb3QpXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHB1YmxpY2F0aW9uRmFpbHVyZShcIklOVkFMSURfUFVCTElDQVRJT05fUk9PVFwiLCB0aGlzLiNwcm9qZWN0SWQsXG4gICAgICAgIFwiUHVibGljYXRpb24gcm9vdCBjb3VsZCBub3QgYmUgcmVzb2x2ZWQgc2FmZWx5LlwiLCBlcnJvcilcbiAgICB9XG4gICAgaWYgKCFpc1N0cmljdFBhdGhEZXNjZW5kYW50KGV4YWN0UHJvamVjdCwgZXhhY3RQdWJsaWNhdGlvbikpIHtcbiAgICAgIHB1YmxpY2F0aW9uRmFpbHVyZShcIklOVkFMSURfUFVCTElDQVRJT05fUk9PVFwiLCB0aGlzLiNwcm9qZWN0SWQsXG4gICAgICAgIFwiUHVibGljYXRpb24gcm9vdCBtdXN0IHJlc29sdmUgc3RyaWN0bHkgYmVuZWF0aCB0aGUgcHJvamVjdCByb290LlwiKVxuICAgIH1cbiAgICBmb3IgKGNvbnN0IHNvdXJjZVJvb3Qgb2YgdGhpcy4jc291cmNlUm9vdHMpIHtcbiAgICAgIGF3YWl0IGVuc3VyZURpcmVjdG9yeVdpdGhvdXRTeW1saW5rcyhzb3VyY2VSb290LCBmYWxzZSwgdGhpcy4jcHJvamVjdElkKVxuICAgICAgbGV0IGV4YWN0U291cmNlXG5cbiAgICAgIHRyeSB7XG4gICAgICAgIGV4YWN0U291cmNlID0gYXdhaXQgcmVhbHBhdGgoc291cmNlUm9vdClcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIHB1YmxpY2F0aW9uRmFpbHVyZShcIklOVkFMSURfUFVCTElDQVRJT05fUk9PVFwiLCB0aGlzLiNwcm9qZWN0SWQsXG4gICAgICAgICAgXCJTb3VyY2Ugcm9vdCBjb3VsZCBub3QgYmUgcmVzb2x2ZWQgc2FmZWx5LlwiLCBlcnJvcilcbiAgICAgIH1cblxuICAgICAgaWYgKCFpc1BhdGhXaXRoaW4oZXhhY3RQcm9qZWN0LCBleGFjdFNvdXJjZSkpIHtcbiAgICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiSU5WQUxJRF9QVUJMSUNBVElPTl9ST09UXCIsIHRoaXMuI3Byb2plY3RJZCxcbiAgICAgICAgICBcIlNvdXJjZSByb290cyBtdXN0IHJlc29sdmUgd2l0aGluIHRoZSBwcm9qZWN0IHJvb3QuXCIpXG4gICAgICB9XG4gICAgICBpZiAocGF0aHNPdmVybGFwKGV4YWN0UHVibGljYXRpb24sIGV4YWN0U291cmNlKSkge1xuICAgICAgICBwdWJsaWNhdGlvbkZhaWx1cmUoXCJQVUJMSUNBVElPTl9TT1VSQ0VfT1ZFUkxBUFwiLCB0aGlzLiNwcm9qZWN0SWQsXG4gICAgICAgICAgXCJQdWJsaWNhdGlvbiByb290IGFuZCBzb3VyY2Ugcm9vdHMgcmVzb2x2ZSB0byBvdmVybGFwcGluZyBwYXRocy5cIilcbiAgICAgIH1cbiAgICB9XG4gICAgYXdhaXQgZW5zdXJlT3duZWREaXJlY3RvcnkocGF0aC5qb2luKHRoaXMuI3B1YmxpY2F0aW9uUm9vdCwgZ2VuZXJhdGlvbnNOYW1lKSwgdGhpcy4jcHJvamVjdElkKVxuICAgIGF3YWl0IGVuc3VyZU93bmVkRGlyZWN0b3J5KHBhdGguam9pbih0aGlzLiNwdWJsaWNhdGlvblJvb3QsIGpvdXJuYWxOYW1lKSwgdGhpcy4jcHJvamVjdElkKVxuICB9XG59XG5cbi8qKlxuICogVGhyb3dzIGFuZCBjb25zdW1lcyBhIGNvbmZpZ3VyZWQgaW50ZXJuYWwgZmFpbHVyZSBhdCBhbiBleGFjdCBsaWZlY3ljbGUgYm91bmRhcnkuXG4gKiBAcGFyYW0ge0dlbmVyYXRlZEFydGlmYWN0UHVibGlzaGVyfSBwdWJsaXNoZXIgLSBBY3RpdmUgcHVibGlzaGVyLlxuICogQHBhcmFtIHtzdHJpbmd9IGJvdW5kYXJ5IC0gUmVhY2hlZCBib3VuZGFyeS5cbiAqIEByZXR1cm5zIHt2b2lkfVxuICovXG5mdW5jdGlvbiByZWFjaFB1YmxpY2F0aW9uQm91bmRhcnkocHVibGlzaGVyLCBib3VuZGFyeSkge1xuICBjb25zdCBpbmplY3Rpb24gPSBpbmplY3RlZFB1YmxpY2F0aW9uRmFpbHVyZXMuZ2V0KHB1Ymxpc2hlcilcblxuICBpZiAoaW5qZWN0aW9uPy5ib3VuZGFyeSA9PSBib3VuZGFyeSkge1xuICAgIGluamVjdGVkUHVibGljYXRpb25GYWlsdXJlcy5kZWxldGUocHVibGlzaGVyKVxuICAgIHRocm93IGluamVjdGlvbi5lcnJvclxuICB9XG59XG5cbi8qKlxuICogUmVwb3J0cyBvbmUgY29tcGxldGVkIGZpbGVzeXN0ZW0gb3BlcmF0aW9uIHRvIHRoZSBpbnRlcm5hbCBkZXRlcm1pbmlzdGljIHNlYW0uXG4gKiBAcGFyYW0ge0dlbmVyYXRlZEFydGlmYWN0UHVibGlzaGVyfSBwdWJsaXNoZXIgLSBBY3RpdmUgcHVibGlzaGVyLlxuICogQHBhcmFtIHtzdHJpbmd9IG9wZXJhdGlvbiAtIENvbXBsZXRlZCBvcGVyYXRpb24uXG4gKiBAcmV0dXJucyB7dm9pZH1cbiAqL1xuZnVuY3Rpb24gb2JzZXJ2ZVB1YmxpY2F0aW9uRmlsZXN5c3RlbU9wZXJhdGlvbihwdWJsaXNoZXIsIG9wZXJhdGlvbikge1xuICBwdWJsaWNhdGlvbkZpbGVzeXN0ZW1PYnNlcnZlcnMuZ2V0KHB1Ymxpc2hlcik/LihvcGVyYXRpb24pXG59XG5cbi8qKlxuICogUmVjb25jaWxlcyBvbmx5IGNhbmRpZGF0ZXMgYW5kIHRlbXBvcmFyeSBwb2ludGVycyB3aG9zZSBvd25lcnNoaXAgaXMgcHJvdmVuIGJ5IGEgc3RyaWN0IGpvdXJuYWwuXG4gKiBUaGUgYWN0aXZlIHBvaW50ZXIgcmVtYWlucyB0aGUgc29sZSBjb21taXQgYXV0aG9yaXR5LlxuICogQHBhcmFtIHtzdHJpbmd9IHB1YmxpY2F0aW9uUm9vdCAtIFB1YmxpY2F0aW9uIHJvb3QuXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvamVjdElkIC0gUHJvamVjdCBpZGVudGl0eS5cbiAqIEBwYXJhbSB7R2VuZXJhdGVkQXJ0aWZhY3RQdWJsaXNoZXJ9IHB1Ymxpc2hlciAtIEFjdGl2ZSBwdWJsaXNoZXIuXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQ29tcGxldGlvbi5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gcmVjb25jaWxlUHVibGljYXRpb24ocHVibGljYXRpb25Sb290LCBwcm9qZWN0SWQsIHB1Ymxpc2hlcikge1xuICBjb25zdCBqb3VybmFscyA9IGF3YWl0IHJlYWRQdWJsaWNhdGlvbkpvdXJuYWxzKHB1YmxpY2F0aW9uUm9vdCwgcHJvamVjdElkKVxuXG4gIGlmIChqb3VybmFscy5sZW5ndGggPT0gMCkgcmV0dXJuXG4gIGNvbnN0IHBvaW50ZXIgPSBhd2FpdCByZWFkQWN0aXZlUG9pbnRlcihwYXRoLmpvaW4ocHVibGljYXRpb25Sb290LCBhY3RpdmVQb2ludGVyTmFtZSksIHByb2plY3RJZCwgdHJ1ZSlcblxuICBpZiAocG9pbnRlcikgYXdhaXQgdmVyaWZ5UHVibGlzaGVkR2VuZXJhdGlvbihwdWJsaWNhdGlvblJvb3QsIHByb2plY3RJZCwgcG9pbnRlciwgdHJ1ZSlcbiAgZm9yIChjb25zdCB7am91cm5hbCwgam91cm5hbFBhdGh9IG9mIGpvdXJuYWxzKSB7XG4gICAgY29uc3QgY2FuZGlkYXRlUGF0aCA9IG93bmVkUGF0aChwYXRoLmpvaW4ocHVibGljYXRpb25Sb290LCBnZW5lcmF0aW9uc05hbWUpLCBqb3VybmFsLmdlbmVyYXRpb25JZCwgcHJvamVjdElkKVxuICAgIGNvbnN0IHRlbXBvcmFyeVBvaW50ZXJQYXRoID0gcGF0aC5qb2luKHB1YmxpY2F0aW9uUm9vdCwgam91cm5hbC50ZW1wUG9pbnRlcilcbiAgICBjb25zdCBjb21taXR0ZWQgPSBwb2ludGVyPy5nZW5lcmF0aW9uSWQgPT0gam91cm5hbC5nZW5lcmF0aW9uSWRcblxuICAgIGlmICghY29tbWl0dGVkKSB7XG4gICAgICBjb25zdCBjYW5kaWRhdGVTdGF0dXMgPSBhd2FpdCBvcHRpb25hbFN0YXR1cyhjYW5kaWRhdGVQYXRoLCBwcm9qZWN0SWQsIFwiY2FuZGlkYXRlIGdlbmVyYXRpb25cIilcblxuICAgICAgaWYgKGNhbmRpZGF0ZVN0YXR1cykge1xuICAgICAgICBpZiAoIWNhbmRpZGF0ZVN0YXR1cy5pc0RpcmVjdG9yeSgpIHx8IGNhbmRpZGF0ZVN0YXR1cy5pc1N5bWJvbGljTGluaygpKSB7XG4gICAgICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiUFVCTElDQVRJT05fUkVDT1ZFUllfRkFJTEVEXCIsIHByb2plY3RJZCxcbiAgICAgICAgICAgIFwiSm91cm5hbC1vd25lZCBjYW5kaWRhdGUgaXMgbm90IGEgcmVhbCBkaXJlY3RvcnkuXCIpXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgY29uc3QgdGVtcG9yYXJ5U3RhdHVzID0gYXdhaXQgb3B0aW9uYWxTdGF0dXModGVtcG9yYXJ5UG9pbnRlclBhdGgsIHByb2plY3RJZCwgXCJ0ZW1wb3JhcnkgcG9pbnRlclwiKVxuXG4gICAgaWYgKHRlbXBvcmFyeVN0YXR1cykge1xuICAgICAgaWYgKCF0ZW1wb3JhcnlTdGF0dXMuaXNGaWxlKCkgfHwgdGVtcG9yYXJ5U3RhdHVzLmlzU3ltYm9saWNMaW5rKCkpIHtcbiAgICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiUFVCTElDQVRJT05fUkVDT1ZFUllfRkFJTEVEXCIsIHByb2plY3RJZCxcbiAgICAgICAgICBcIkpvdXJuYWwtb3duZWQgdGVtcG9yYXJ5IHBvaW50ZXIgaXMgbm90IGEgcmVndWxhciBmaWxlLlwiKVxuICAgICAgfVxuICAgIH1cbiAgICBhd2FpdCByZW1vdmVKb3VybmFsT3duZWRTdGF0ZSh7XG4gICAgICAuLi4oIWNvbW1pdHRlZCA/IHtjYW5kaWRhdGVQYXRofSA6IHt9KSxcbiAgICAgIGpvdXJuYWxQYXRoLFxuICAgICAgcHJvamVjdElkLFxuICAgICAgcHVibGljYXRpb25Sb290LFxuICAgICAgcHVibGlzaGVyLFxuICAgICAgdGVtcG9yYXJ5UG9pbnRlclBhdGhcbiAgICB9KVxuICB9XG59XG5cbi8qKlxuICogUmVhZHMgYW5kIHZhbGlkYXRlcyBldmVyeSByZWNvdmVyeSBqb3VybmFsIHdpdGhvdXQgY2hhbmdpbmcgcHVibGljYXRpb24gc3RhdGUuXG4gKiBAcGFyYW0ge3N0cmluZ30gcHVibGljYXRpb25Sb290IC0gUHVibGljYXRpb24gcm9vdC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBwcm9qZWN0SWQgLSBQcm9qZWN0IGlkZW50aXR5LlxuICogQHJldHVybnMge1Byb21pc2U8cmVhZG9ubHkge2pvdXJuYWw6IFB1YmxpY2F0aW9uSm91cm5hbCwgam91cm5hbFBhdGg6IHN0cmluZ31bXT59IE9yZGVyZWQgam91cm5hbHMuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHJlYWRQdWJsaWNhdGlvbkpvdXJuYWxzKHB1YmxpY2F0aW9uUm9vdCwgcHJvamVjdElkKSB7XG4gIGNvbnN0IGpvdXJuYWxEaXJlY3RvcnkgPSBwYXRoLmpvaW4ocHVibGljYXRpb25Sb290LCBqb3VybmFsTmFtZSlcbiAgbGV0IGVudHJpZXNcblxuICB0cnkge1xuICAgIGVudHJpZXMgPSBhd2FpdCByZWFkZGlyKGpvdXJuYWxEaXJlY3RvcnkpXG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgcHVibGljYXRpb25GYWlsdXJlKFwiUFVCTElDQVRJT05fUkVDT1ZFUllfRkFJTEVEXCIsIHByb2plY3RJZCxcbiAgICAgIFwiUHVibGljYXRpb24gam91cm5hbCBkaXJlY3RvcnkgY291bGQgbm90IGJlIGluc3BlY3RlZC5cIiwgZXJyb3IpXG4gIH1cbiAgZW50cmllcy5zb3J0KGNvbXBhcmVTdHJpbmdzKVxuICAvKiogQHR5cGUge3tqb3VybmFsOiBQdWJsaWNhdGlvbkpvdXJuYWwsIGpvdXJuYWxQYXRoOiBzdHJpbmd9W119ICovXG4gIGNvbnN0IGpvdXJuYWxzID0gW11cblxuICBmb3IgKGNvbnN0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICBpZiAoIWVudHJ5LmVuZHNXaXRoKFwiLmpzb25cIikgfHwgIWdlbmVyYXRpb25QYXR0ZXJuLnRlc3QoZW50cnkuc2xpY2UoMCwgLTUpKSkge1xuICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiUFVCTElDQVRJT05fUkVDT1ZFUllfRkFJTEVEXCIsIHByb2plY3RJZCxcbiAgICAgICAgXCJQdWJsaWNhdGlvbiBqb3VybmFsIGNvbnRhaW5zIGFuIHVucmVjb2duaXplZCBlbnRyeS5cIilcbiAgICB9XG4gICAgY29uc3Qgam91cm5hbFBhdGggPSBwYXRoLmpvaW4oam91cm5hbERpcmVjdG9yeSwgZW50cnkpXG4gICAgbGV0IGpvdXJuYWxcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCBzdGF0dXMgPSBhd2FpdCBsc3RhdChqb3VybmFsUGF0aClcblxuICAgICAgaWYgKCFzdGF0dXMuaXNGaWxlKCkgfHwgc3RhdHVzLmlzU3ltYm9saWNMaW5rKCkpIHtcbiAgICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiUFVCTElDQVRJT05fUkVDT1ZFUllfRkFJTEVEXCIsIHByb2plY3RJZCxcbiAgICAgICAgICBcIlB1YmxpY2F0aW9uIGpvdXJuYWwgZW50cnkgbXVzdCBiZSBhIHJlZ3VsYXIgZmlsZS5cIilcbiAgICAgIH1cbiAgICAgIGpvdXJuYWwgPSBKU09OLnBhcnNlKGF3YWl0IHJlYWRGaWxlKGpvdXJuYWxQYXRoLCBcInV0ZjhcIikpXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIFNlbWFudGlmb2xkRGlhZ25vc3RpYykgdGhyb3cgZXJyb3JcbiAgICAgIHB1YmxpY2F0aW9uRmFpbHVyZShcIlBVQkxJQ0FUSU9OX1JFQ09WRVJZX0ZBSUxFRFwiLCBwcm9qZWN0SWQsXG4gICAgICAgIFwiUHVibGljYXRpb24gam91cm5hbCBlbnRyeSBpcyBub3QgdmFsaWQgSlNPTi5cIiwgZXJyb3IpXG4gICAgfVxuICAgIGlmICghaXNQdWJsaWNhdGlvbkpvdXJuYWwoam91cm5hbCkgfHwgam91cm5hbC5wcm9qZWN0SWQgIT0gcHJvamVjdElkIHx8IGAke2pvdXJuYWwuZ2VuZXJhdGlvbklkfS5qc29uYCAhPSBlbnRyeSkge1xuICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiUFVCTElDQVRJT05fUkVDT1ZFUllfRkFJTEVEXCIsIHByb2plY3RJZCxcbiAgICAgICAgXCJQdWJsaWNhdGlvbiBqb3VybmFsIGVudHJ5IGRvZXMgbm90IG1hdGNoIHRoZSB2ZXJzaW9uZWQgcHJvamVjdCBjb250cmFjdC5cIilcbiAgICB9XG4gICAgam91cm5hbHMucHVzaCh7am91cm5hbCwgam91cm5hbFBhdGh9KVxuICB9XG5cbiAgcmV0dXJuIE9iamVjdC5mcmVlemUoam91cm5hbHMpXG59XG5cbi8qKlxuICogUmVwb3J0cyBjb21taXR0ZWQgY2xlYW51cCBzdGF0ZSB3aGlsZSBmYWlsaW5nIGNsb3NlZCBvbiBldmVyeSBqb3VybmFsIGVudHJ5LlxuICogQHBhcmFtIHtzdHJpbmd9IHB1YmxpY2F0aW9uUm9vdCAtIFB1YmxpY2F0aW9uIHJvb3QuXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvamVjdElkIC0gUHJvamVjdCBpZGVudGl0eS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBnZW5lcmF0aW9uSWQgLSBQb2ludGVyLXNlbGVjdGVkIGdlbmVyYXRpb24gaWRlbnRpdHkuXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gV2hldGhlciBjb21taXR0ZWQgY2xlYW51cCByZW1haW5zLlxuICovXG5hc3luYyBmdW5jdGlvbiBoYXNDb21taXR0ZWRDbGVhbnVwSm91cm5hbChwdWJsaWNhdGlvblJvb3QsIHByb2plY3RJZCwgZ2VuZXJhdGlvbklkKSB7XG4gIGNvbnN0IGpvdXJuYWxzID0gYXdhaXQgcmVhZFB1YmxpY2F0aW9uSm91cm5hbHMocHVibGljYXRpb25Sb290LCBwcm9qZWN0SWQpXG5cbiAgcmV0dXJuIGpvdXJuYWxzLnNvbWUoKHtqb3VybmFsfSkgPT4gam91cm5hbC5nZW5lcmF0aW9uSWQgPT0gZ2VuZXJhdGlvbklkKVxufVxuXG4vKipcbiAqIFJlbW92ZXMgcHJvdmVuIGpvdXJuYWwtb3duZWQgc3RhdGUgYW5kIGR1cmFibHkgc3luY2hyb25pemVzIGVhY2ggcGFyZW50IGJlZm9yZSBkaXNjYXJkaW5nIGl0cyBvd25lcnNoaXAgcHJvb2YuXG4gKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAtIEV4YWN0IGNsZWFudXAgc3RhdGUuXG4gKiBAcGFyYW0ge3N0cmluZ30gW29wdGlvbnMuY2FuZGlkYXRlUGF0aF0gLSBQcm92ZW4gY2FuZGlkYXRlIGdlbmVyYXRpb24gcGF0aC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBbb3B0aW9ucy50ZW1wb3JhcnlQb2ludGVyUGF0aF0gLSBQcm92ZW4gdGVtcG9yYXJ5IHBvaW50ZXIgcGF0aC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBbb3B0aW9ucy5qb3VybmFsUGF0aF0gLSBPd25lcnNoaXAgam91cm5hbCBwYXRoLlxuICogQHBhcmFtIHtzdHJpbmd9IG9wdGlvbnMucHJvamVjdElkIC0gUHJvamVjdCBpZGVudGl0eS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBvcHRpb25zLnB1YmxpY2F0aW9uUm9vdCAtIFB1YmxpY2F0aW9uIHJvb3QuXG4gKiBAcGFyYW0ge0dlbmVyYXRlZEFydGlmYWN0UHVibGlzaGVyfSBvcHRpb25zLnB1Ymxpc2hlciAtIEFjdGl2ZSBwdWJsaXNoZXIuXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQ29tcGxldGlvbi5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gcmVtb3ZlSm91cm5hbE93bmVkU3RhdGUoe2NhbmRpZGF0ZVBhdGgsIGpvdXJuYWxQYXRoLCBwcm9qZWN0SWQsIHB1YmxpY2F0aW9uUm9vdCwgcHVibGlzaGVyLCB0ZW1wb3JhcnlQb2ludGVyUGF0aH0pIHtcbiAgdHJ5IHtcbiAgICBpZiAoY2FuZGlkYXRlUGF0aCkge1xuICAgICAgYXdhaXQgcm0oY2FuZGlkYXRlUGF0aCwge2ZvcmNlOiB0cnVlLCByZWN1cnNpdmU6IHRydWV9KVxuICAgICAgb2JzZXJ2ZVB1YmxpY2F0aW9uRmlsZXN5c3RlbU9wZXJhdGlvbihwdWJsaXNoZXIsIFwicmVtb3ZlLWNhbmRpZGF0ZVwiKVxuICAgICAgYXdhaXQgc3luY0RpcmVjdG9yeShwYXRoLmpvaW4ocHVibGljYXRpb25Sb290LCBnZW5lcmF0aW9uc05hbWUpKVxuICAgICAgb2JzZXJ2ZVB1YmxpY2F0aW9uRmlsZXN5c3RlbU9wZXJhdGlvbihwdWJsaXNoZXIsIFwic3luYy1jYW5kaWRhdGUtcGFyZW50XCIpXG4gICAgfVxuICAgIGlmICh0ZW1wb3JhcnlQb2ludGVyUGF0aCkge1xuICAgICAgYXdhaXQgcm0odGVtcG9yYXJ5UG9pbnRlclBhdGgsIHtmb3JjZTogdHJ1ZX0pXG4gICAgICBvYnNlcnZlUHVibGljYXRpb25GaWxlc3lzdGVtT3BlcmF0aW9uKHB1Ymxpc2hlciwgXCJyZW1vdmUtdGVtcG9yYXJ5LXBvaW50ZXJcIilcbiAgICAgIGF3YWl0IHN5bmNEaXJlY3RvcnkocHVibGljYXRpb25Sb290KVxuICAgICAgb2JzZXJ2ZVB1YmxpY2F0aW9uRmlsZXN5c3RlbU9wZXJhdGlvbihwdWJsaXNoZXIsIFwic3luYy10ZW1wb3JhcnktcG9pbnRlci1wYXJlbnRcIilcbiAgICB9XG4gICAgaWYgKGpvdXJuYWxQYXRoKSB7XG4gICAgICByZWFjaFB1YmxpY2F0aW9uQm91bmRhcnkocHVibGlzaGVyLCBcImJlZm9yZS1qb3VybmFsLXJlbW92ZVwiKVxuICAgICAgYXdhaXQgcm0oam91cm5hbFBhdGgpXG4gICAgICBvYnNlcnZlUHVibGljYXRpb25GaWxlc3lzdGVtT3BlcmF0aW9uKHB1Ymxpc2hlciwgXCJyZW1vdmUtam91cm5hbFwiKVxuICAgICAgYXdhaXQgc3luY0RpcmVjdG9yeShwYXRoLmRpcm5hbWUoam91cm5hbFBhdGgpKVxuICAgICAgb2JzZXJ2ZVB1YmxpY2F0aW9uRmlsZXN5c3RlbU9wZXJhdGlvbihwdWJsaXNoZXIsIFwic3luYy1qb3VybmFsLXBhcmVudFwiKVxuICAgIH1cbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBTZW1hbnRpZm9sZERpYWdub3N0aWMpIHRocm93IGVycm9yXG4gICAgcHVibGljYXRpb25GYWlsdXJlKFwiUFVCTElDQVRJT05fUkVDT1ZFUllfRkFJTEVEXCIsIHByb2plY3RJZCxcbiAgICAgIFwiSm91cm5hbC1vd25lZCBwdWJsaWNhdGlvbiBzdGF0ZSBjb3VsZCBub3QgYmUgZHVyYWJseSByZWNvbmNpbGVkLlwiLCBlcnJvcilcbiAgfVxufVxuXG4vKipcbiAqIFJlYWRzIG9wdGlvbmFsIG1ldGFkYXRhIHdpdGhvdXQgZm9sbG93aW5nIHN5bWJvbGljIGxpbmtzLlxuICogQHBhcmFtIHtzdHJpbmd9IGZpbGVuYW1lIC0gRXhhY3Qgb3duZWQgcGF0aC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBwcm9qZWN0SWQgLSBQcm9qZWN0IGlkZW50aXR5LlxuICogQHBhcmFtIHtzdHJpbmd9IHN1YmplY3QgLSBTdGFibGUgc3ViamVjdCBkZXNjcmlwdGlvbi5cbiAqIEByZXR1cm5zIHtQcm9taXNlPGltcG9ydChcIm5vZGU6ZnNcIikuU3RhdHMgfCBudWxsPn0gU3RhdHVzIG9yIGFic2VuY2UuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIG9wdGlvbmFsU3RhdHVzKGZpbGVuYW1lLCBwcm9qZWN0SWQsIHN1YmplY3QpIHtcbiAgdHJ5IHtcbiAgICByZXR1cm4gYXdhaXQgbHN0YXQoZmlsZW5hbWUpXG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgaWYgKGlzRXJyb3JDb2RlKGVycm9yLCBcIkVOT0VOVFwiKSkgcmV0dXJuIG51bGxcbiAgICBwdWJsaWNhdGlvbkZhaWx1cmUoXCJQVUJMSUNBVElPTl9SRUNPVkVSWV9GQUlMRURcIiwgcHJvamVjdElkLFxuICAgICAgYEpvdXJuYWwtb3duZWQgJHtzdWJqZWN0fSBjb3VsZCBub3QgYmUgaW5zcGVjdGVkLmAsIGVycm9yKVxuICB9XG59XG5cbi8qKlxuICogVmFsaWRhdGVzIGFuZCBzbmFwc2hvdHMgb25lIHB1YmxpY2F0aW9uIHJlcXVlc3QgYmVmb3JlIHN0YWdpbmcuXG4gKiBAcGFyYW0ge3Vua25vd259IHJlcXVlc3QgLSBSZXF1ZXN0IGNhbmRpZGF0ZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBwcm9qZWN0SWQgLSBQcm9qZWN0IGRpYWdub3N0aWMgaWRlbnRpdHkuXG4gKiBAcmV0dXJucyB7e2dlbmVyYXRpb25JZDogc3RyaW5nLCB0YXJnZXRzOiByZWFkb25seSBWYWxpZGF0ZWRQdWJsaWNhdGlvblRhcmdldFtdfX0gVmFsaWRhdGVkIHJlcXVlc3QuXG4gKi9cbmZ1bmN0aW9uIHZhbGlkYXRlUHVibGljYXRpb25SZXF1ZXN0KHJlcXVlc3QsIHByb2plY3RJZCkge1xuICBpZiAoIWlzUGxhaW5PYmplY3QocmVxdWVzdCkpIHtcbiAgICBwdWJsaWNhdGlvbkZhaWx1cmUoXCJJTlZBTElEX1BVQkxJQ0FUSU9OX1JFUVVFU1RcIiwgcHJvamVjdElkLFxuICAgICAgXCJQdWJsaWNhdGlvbiByZXF1aXJlcyBhIHVuaXF1ZSBnZW5lcmF0aW9uIElEIGFuZCBhIG5vbi1lbXB0eSBvcmRlcmVkIHRhcmdldCBhcnJheS5cIilcbiAgfVxuICBjb25zdCBnZW5lcmF0aW9uSWQgPSByZXF1ZXN0LmdlbmVyYXRpb25JZFxuICBjb25zdCByZXF1ZXN0ZWRUYXJnZXRzID0gcmVxdWVzdC50YXJnZXRzXG5cbiAgaWYgKHR5cGVvZiBnZW5lcmF0aW9uSWQgIT0gXCJzdHJpbmdcIiB8fCAhZ2VuZXJhdGlvblBhdHRlcm4udGVzdChnZW5lcmF0aW9uSWQpIHx8XG4gICAgIWlzRGVuc2VBcnJheShyZXF1ZXN0ZWRUYXJnZXRzKSB8fCByZXF1ZXN0ZWRUYXJnZXRzLmxlbmd0aCA9PSAwKSB7XG4gICAgcHVibGljYXRpb25GYWlsdXJlKFwiSU5WQUxJRF9QVUJMSUNBVElPTl9SRVFVRVNUXCIsIHByb2plY3RJZCxcbiAgICAgIFwiUHVibGljYXRpb24gcmVxdWlyZXMgYSB1bmlxdWUgZ2VuZXJhdGlvbiBJRCBhbmQgYSBub24tZW1wdHkgb3JkZXJlZCB0YXJnZXQgYXJyYXkuXCIpXG4gIH1cbiAgLyoqIEB0eXBlIHtWYWxpZGF0ZWRQdWJsaWNhdGlvblRhcmdldFtdfSAqL1xuICBjb25zdCB0YXJnZXRzID0gW11cbiAgY29uc3QgdGFyZ2V0SWRzID0gbmV3IFNldCgpXG4gIC8qKiBAdHlwZSB7c3RyaW5nW119ICovXG4gIGNvbnN0IHByb2plY3Rpb25zID0gW11cbiAgLyoqIEB0eXBlIHtzdHJpbmdbXX0gKi9cbiAgY29uc3QgY29tcGxldGVBcnRpZmFjdFBhdGhzID0gW11cblxuICBmb3IgKGxldCBpbmRleCA9IDA7IGluZGV4IDwgcmVxdWVzdGVkVGFyZ2V0cy5sZW5ndGg7IGluZGV4ICs9IDEpIHtcbiAgICBjb25zdCB0YXJnZXQgPSByZXF1ZXN0ZWRUYXJnZXRzW2luZGV4XVxuXG4gICAgaWYgKCFpc1BsYWluT2JqZWN0KHRhcmdldCkpIHtcbiAgICAgIHB1YmxpY2F0aW9uRmFpbHVyZShcIklOVkFMSURfUFVCTElDQVRJT05fUkVRVUVTVFwiLCBwcm9qZWN0SWQsXG4gICAgICAgIGBUYXJnZXQgJHtpbmRleH0gcmVxdWlyZXMgYSBzdGFibGUgbG93ZXJjYXNlIGlkZW50aXR5LmApXG4gICAgfVxuICAgIGNvbnN0IHRhcmdldElkID0gdGFyZ2V0LmlkXG4gICAgY29uc3Qgcm9sZSA9IHRhcmdldC5yb2xlXG4gICAgY29uc3Qgc291cmNlUHJvamVjdGlvbiA9IHRhcmdldC5zb3VyY2VQcm9qZWN0aW9uXG4gICAgY29uc3QgYnVpbGRQcm9qZWN0aW9uID0gdGFyZ2V0LmJ1aWxkUHJvamVjdGlvblxuICAgIGNvbnN0IGFydGlmYWN0U2V0Q2FuZGlkYXRlID0gdGFyZ2V0LmFydGlmYWN0U2V0XG4gICAgY29uc3QgdmFsaWRhdG9yc0NhbmRpZGF0ZSA9IHRhcmdldC52YWxpZGF0b3JzXG5cbiAgICBpZiAodHlwZW9mIHRhcmdldElkICE9IFwic3RyaW5nXCIgfHwgIWlkZW50aXR5UGF0dGVybi50ZXN0KHRhcmdldElkKSkge1xuICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiSU5WQUxJRF9QVUJMSUNBVElPTl9SRVFVRVNUXCIsIHByb2plY3RJZCxcbiAgICAgICAgYFRhcmdldCAke2luZGV4fSByZXF1aXJlcyBhIHN0YWJsZSBsb3dlcmNhc2UgaWRlbnRpdHkuYClcbiAgICB9XG4gICAgaWYgKHR5cGVvZiByb2xlICE9IFwic3RyaW5nXCIgfHwgIXRhcmdldFJvbGVzLmhhcyhyb2xlKSkge1xuICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiSU5WQUxJRF9QVUJMSUNBVElPTl9SRVFVRVNUXCIsIHByb2plY3RJZCxcbiAgICAgICAgYFRhcmdldCAnJHt0YXJnZXRJZH0nIHJlcXVpcmVzIGFuIGV4cGxpY2l0IGxhbmd1YWdlLW5ldXRyYWwgcm9sZS5gKVxuICAgIH1cblxuICAgIGlmICh0YXJnZXRJZHMuaGFzKHRhcmdldElkKSkge1xuICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiUFVCTElDQVRJT05fUEFUSF9DT0xMSVNJT05cIiwgcHJvamVjdElkLCBgRHVwbGljYXRlIHRhcmdldCBpZGVudGl0eSAnJHt0YXJnZXRJZH0nLmApXG4gICAgfVxuICAgIHRhcmdldElkcy5hZGQodGFyZ2V0SWQpXG4gICAgaWYgKCFpc1NhZmVBcnRpZmFjdFBhdGgoc291cmNlUHJvamVjdGlvbikgfHwgIWlzU2FmZUFydGlmYWN0UGF0aChidWlsZFByb2plY3Rpb24pKSB7XG4gICAgICBwdWJsaWNhdGlvbkZhaWx1cmUoXCJJTlZBTElEX1BVQkxJQ0FUSU9OX1BST0pFQ1RJT05cIiwgcHJvamVjdElkLFxuICAgICAgICBgVGFyZ2V0ICcke3RhcmdldElkfScgcmVxdWlyZXMgY2Fub25pY2FsIHJlbGF0aXZlIHNvdXJjZSBhbmQgYnVpbGQgcHJvamVjdGlvbnMuYClcbiAgICB9XG4gICAgcHJvamVjdGlvbnMucHVzaChzb3VyY2VQcm9qZWN0aW9uLCBidWlsZFByb2plY3Rpb24pXG4gICAgbGV0IGFydGlmYWN0U2V0XG5cbiAgICB0cnkge1xuICAgICAgYXJ0aWZhY3RTZXQgPSBjcmVhdGVHZW5lcmF0ZWRBcnRpZmFjdFNldChhcnRpZmFjdFNldENhbmRpZGF0ZSlcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiSU5WQUxJRF9QVUJMSUNBVElPTl9SRVFVRVNUXCIsIHByb2plY3RJZCxcbiAgICAgICAgYFRhcmdldCAnJHt0YXJnZXRJZH0nIGRvZXMgbm90IGNvbnRhaW4gYSB2YWxpZCBnZW5lcmF0ZWQgYXJ0aWZhY3Qgc2V0LmAsIGVycm9yKVxuICAgIH1cbiAgICBjb25zdCB2YWxpZGF0b3JzID0gdmFsaWRhdG9yc0NhbmRpZGF0ZSA9PT0gdW5kZWZpbmVkID8gW10gOiB2YWxpZGF0b3JzQ2FuZGlkYXRlXG5cbiAgICBpZiAoIWlzRGVuc2VBcnJheSh2YWxpZGF0b3JzKSkge1xuICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiSU5WQUxJRF9QVUJMSUNBVElPTl9SRVFVRVNUXCIsIHByb2plY3RJZCxcbiAgICAgICAgYFRhcmdldCAnJHt0YXJnZXRJZH0nIHZhbGlkYXRvcnMgbXVzdCBiZSBhIGRlbnNlIGZ1bmN0aW9uIGFycmF5LmApXG4gICAgfVxuICAgIC8qKiBAdHlwZSB7aW1wb3J0KFwiLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5QdWJsaWNhdGlvblZhbGlkYXRvcltdfSAqL1xuICAgIGNvbnN0IHZhbGlkYXRlZFZhbGlkYXRvcnMgPSBbXVxuXG4gICAgZm9yIChsZXQgdmFsaWRhdG9ySW5kZXggPSAwOyB2YWxpZGF0b3JJbmRleCA8IHZhbGlkYXRvcnMubGVuZ3RoOyB2YWxpZGF0b3JJbmRleCArPSAxKSB7XG4gICAgICBjb25zdCB2YWxpZGF0b3IgPSB2YWxpZGF0b3JzW3ZhbGlkYXRvckluZGV4XVxuXG4gICAgICBpZiAodHlwZW9mIHZhbGlkYXRvciAhPSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiSU5WQUxJRF9QVUJMSUNBVElPTl9SRVFVRVNUXCIsIHByb2plY3RJZCxcbiAgICAgICAgICBgVGFyZ2V0ICcke3RhcmdldElkfScgdmFsaWRhdG9ycyBtdXN0IGJlIGEgZGVuc2UgZnVuY3Rpb24gYXJyYXkuYClcbiAgICAgIH1cbiAgICAgIHZhbGlkYXRlZFZhbGlkYXRvcnMucHVzaCgvKiogQHR5cGUge2ltcG9ydChcIi4vc2VtYW50aWMvdHlwZXMuanNcIikuUHVibGljYXRpb25WYWxpZGF0b3J9ICovICh2YWxpZGF0b3IpKVxuICAgIH1cbiAgICBjb25zdCBhcnRpZmFjdENvbmZsaWN0ID0gZmluZFBvcnRhYmxlQXJ0aWZhY3RQYXRoQ29uZmxpY3QoYXJ0aWZhY3RTZXQuYXJ0aWZhY3RzLm1hcCgoe3BhdGg6IGFydGlmYWN0UGF0aH0pID0+IGFydGlmYWN0UGF0aCkpXG5cbiAgICBpZiAoYXJ0aWZhY3RDb25mbGljdCkge1xuICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiUFVCTElDQVRJT05fUEFUSF9DT0xMSVNJT05cIiwgcHJvamVjdElkLFxuICAgICAgICBgVGFyZ2V0ICcke3RhcmdldElkfScgYXJ0aWZhY3QgcGF0aHMgaGF2ZSBhIHBvcnRhYmxlICR7YXJ0aWZhY3RDb25mbGljdC5raW5kfSBjb25mbGljdC5gKVxuICAgIH1cbiAgICBmb3IgKGNvbnN0IGFydGlmYWN0IG9mIGFydGlmYWN0U2V0LmFydGlmYWN0cykge1xuICAgICAgY29tcGxldGVBcnRpZmFjdFBhdGhzLnB1c2goYCR7c291cmNlUHJvamVjdGlvbn0vJHthcnRpZmFjdC5wYXRofWApXG4gICAgfVxuICAgIHRhcmdldHMucHVzaChPYmplY3QuZnJlZXplKHtcbiAgICAgIGFydGlmYWN0U2V0LFxuICAgICAgYnVpbGRQcm9qZWN0aW9uLFxuICAgICAgaWQ6IHRhcmdldElkLFxuICAgICAgcm9sZTogLyoqIEB0eXBlIHtpbXBvcnQoXCIuL3NlbWFudGljL3R5cGVzLmpzXCIpLlB1YmxpY2F0aW9uVGFyZ2V0Um9sZX0gKi8gKHJvbGUpLFxuICAgICAgc291cmNlUHJvamVjdGlvbixcbiAgICAgIHZhbGlkYXRvcnM6IE9iamVjdC5mcmVlemUodmFsaWRhdGVkVmFsaWRhdG9ycylcbiAgICB9KSlcbiAgfVxuICBjb25zdCBwcm9qZWN0aW9uQ29uZmxpY3QgPSBmaW5kUG9ydGFibGVBcnRpZmFjdFBhdGhDb25mbGljdChwcm9qZWN0aW9ucylcblxuICBpZiAocHJvamVjdGlvbkNvbmZsaWN0KSB7XG4gICAgcHVibGljYXRpb25GYWlsdXJlKFwiUFVCTElDQVRJT05fUFJPSkVDVElPTl9PVkVSTEFQXCIsIHByb2plY3RJZCxcbiAgICAgIFwiVGFyZ2V0IHNvdXJjZS9idWlsZCBwcm9qZWN0aW9ucyBtdXN0IGJlIGRpc3RpbmN0IGFuZCBub24tbmVzdGVkIHVuZGVyIHBvcnRhYmxlIGNvbXBhcmlzb24uXCIpXG4gIH1cbiAgaWYgKGZpbmRQb3J0YWJsZUFydGlmYWN0UGF0aENvbmZsaWN0KFsuLi5wcm9qZWN0aW9ucywgXCJtYW5pZmVzdC5qc29uXCJdKSkge1xuICAgIHB1YmxpY2F0aW9uRmFpbHVyZShcIklOVkFMSURfUFVCTElDQVRJT05fUFJPSkVDVElPTlwiLCBwcm9qZWN0SWQsXG4gICAgICBcIlRhcmdldCBzb3VyY2UvYnVpbGQgcHJvamVjdGlvbnMgbXVzdCBub3Qgb3ZlcmxhcCB0aGUgZ2VuZXJhdGlvbiBtYW5pZmVzdCBwYXRoLlwiKVxuICB9XG4gIGNvbnN0IGFydGlmYWN0Q29uZmxpY3QgPSBmaW5kUG9ydGFibGVBcnRpZmFjdFBhdGhDb25mbGljdChjb21wbGV0ZUFydGlmYWN0UGF0aHMpXG5cbiAgaWYgKGFydGlmYWN0Q29uZmxpY3QpIHtcbiAgICBwdWJsaWNhdGlvbkZhaWx1cmUoXCJQVUJMSUNBVElPTl9QQVRIX0NPTExJU0lPTlwiLCBwcm9qZWN0SWQsXG4gICAgICBcIlByb2plY3RlZCBhcnRpZmFjdCBwYXRocyBjb2xsaWRlIHVuZGVyIHBvcnRhYmxlIGNvbXBhcmlzb24uXCIpXG4gIH1cblxuICByZXR1cm4ge2dlbmVyYXRpb25JZCwgdGFyZ2V0czogT2JqZWN0LmZyZWV6ZSh0YXJnZXRzKX1cbn1cblxuLyoqXG4gKiBTdGFnZXMgb25lIHZhbGlkYXRlZCB0YXJnZXQgYW5kIGludm9rZXMgaXRzIG9yZGVyZWQgdmFsaWRhdG9ycy5cbiAqIEBwYXJhbSB7c3RyaW5nfSBnZW5lcmF0aW9uUGF0aCAtIENhbmRpZGF0ZSBnZW5lcmF0aW9uIHBhdGguXG4gKiBAcGFyYW0ge1ZhbGlkYXRlZFB1YmxpY2F0aW9uVGFyZ2V0fSB0YXJnZXQgLSBWYWxpZGF0ZWQgdGFyZ2V0LlxuICogQHBhcmFtIHtzdHJpbmd9IHByb2plY3RJZCAtIFByb2plY3QgZGlhZ25vc3RpYyBpZGVudGl0eS5cbiAqIEByZXR1cm5zIHtQcm9taXNlPGltcG9ydChcIi4vc2VtYW50aWMvdHlwZXMuanNcIikuR2VuZXJhdGlvblRhcmdldE1hbmlmZXN0Pn0gVGFyZ2V0IG1hbmlmZXN0LlxuICovXG5hc3luYyBmdW5jdGlvbiBzdGFnZVRhcmdldChnZW5lcmF0aW9uUGF0aCwgdGFyZ2V0LCBwcm9qZWN0SWQpIHtcbiAgY29uc3Qgc291cmNlUGF0aCA9IG93bmVkUGF0aChnZW5lcmF0aW9uUGF0aCwgdGFyZ2V0LnNvdXJjZVByb2plY3Rpb24sIHByb2plY3RJZClcbiAgY29uc3QgYnVpbGRQYXRoID0gb3duZWRQYXRoKGdlbmVyYXRpb25QYXRoLCB0YXJnZXQuYnVpbGRQcm9qZWN0aW9uLCBwcm9qZWN0SWQpXG5cbiAgYXdhaXQgbWtkaXIoc291cmNlUGF0aCwge21vZGU6IDBvNzAwLCByZWN1cnNpdmU6IHRydWV9KVxuICBhd2FpdCBta2RpcihidWlsZFBhdGgsIHttb2RlOiAwbzcwMCwgcmVjdXJzaXZlOiB0cnVlfSlcbiAgLyoqIEB0eXBlIHtpbXBvcnQoXCIuL3NlbWFudGljL3R5cGVzLmpzXCIpLkdlbmVyYXRpb25BcnRpZmFjdE1hbmlmZXN0W119ICovXG4gIGNvbnN0IGFydGlmYWN0cyA9IFtdXG5cbiAgZm9yIChjb25zdCBhcnRpZmFjdCBvZiB0YXJnZXQuYXJ0aWZhY3RTZXQuYXJ0aWZhY3RzKSB7XG4gICAgY29uc3QgZmlsZW5hbWUgPSBvd25lZFBhdGgoc291cmNlUGF0aCwgYXJ0aWZhY3QucGF0aCwgcHJvamVjdElkKVxuICAgIGNvbnN0IGJ5dGVzID0gYXJ0aWZhY3QuY29udGVudEtpbmQgPT0gXCJ0ZXh0XCJcbiAgICAgID8gQnVmZmVyLmZyb20oLyoqIEB0eXBlIHtzdHJpbmd9ICovIChhcnRpZmFjdC5jb250ZW50KSwgXCJ1dGY4XCIpXG4gICAgICA6IEJ1ZmZlci5mcm9tKC8qKiBAdHlwZSB7VWludDhBcnJheX0gKi8gKGFydGlmYWN0LmNvbnRlbnQpKVxuXG4gICAgYXdhaXQgbWtkaXIocGF0aC5kaXJuYW1lKGZpbGVuYW1lKSwge21vZGU6IDBvNzAwLCByZWN1cnNpdmU6IHRydWV9KVxuICAgIHRyeSB7XG4gICAgICBhd2FpdCB3cml0ZVN5bmNlZEZpbGUoZmlsZW5hbWUsIGJ5dGVzLCBcInd4XCIpXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIFNlbWFudGlmb2xkRGlhZ25vc3RpYykgdGhyb3cgZXJyb3JcbiAgICAgIHB1YmxpY2F0aW9uRmFpbHVyZShcIlBVQkxJQ0FUSU9OX1NUQUdFX1dSSVRFX0ZBSUxFRFwiLCBwcm9qZWN0SWQsXG4gICAgICAgIGBHZW5lcmF0ZWQgYXJ0aWZhY3QgJyR7YXJ0aWZhY3QucGF0aH0nIGNvdWxkIG5vdCBiZSBzdGFnZWQuYCwgZXJyb3IpXG4gICAgfVxuICAgIGFydGlmYWN0cy5wdXNoKE9iamVjdC5mcmVlemUoe1xuICAgICAgYnl0ZUxlbmd0aDogYnl0ZXMuYnl0ZUxlbmd0aCxcbiAgICAgIGNvbnRlbnRLaW5kOiBhcnRpZmFjdC5jb250ZW50S2luZCxcbiAgICAgIGhhc2g6IE9iamVjdC5mcmVlemUoe2FsZ29yaXRobTogLyoqIEB0eXBlIHtjb25zdH0gKi8gKFwic2hhMjU2XCIpLCB2YWx1ZTogc2hhMjU2KGJ5dGVzKX0pLFxuICAgICAgbWVkaWFUeXBlOiBhcnRpZmFjdC5tZWRpYVR5cGUsXG4gICAgICBwYXRoOiBhcnRpZmFjdC5wYXRoLFxuICAgICAgcHJvdmVuYW5jZTogYXJ0aWZhY3QucHJvdmVuYW5jZSxcbiAgICAgIHJvbGU6IGFydGlmYWN0LnJvbGVcbiAgICB9KSlcbiAgfVxuXG4gIC8qKiBAdHlwZSB7aW1wb3J0KFwiLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5QdWJsaWNhdGlvbkJ1aWxkQXJ0aWZhY3RJbnB1dFtdfSAqL1xuICBjb25zdCBidWlsZERlc2NyaXB0b3JzID0gW11cbiAgY29uc3QgY29udGV4dCA9IE9iamVjdC5mcmVlemUoe2J1aWxkUGF0aCwgc291cmNlUGF0aCwgdGFyZ2V0SWQ6IHRhcmdldC5pZH0pXG5cbiAgZm9yIChsZXQgaW5kZXggPSAwOyBpbmRleCA8IHRhcmdldC52YWxpZGF0b3JzLmxlbmd0aDsgaW5kZXggKz0gMSkge1xuICAgIGxldCBwcm9kdWNlZFxuXG4gICAgdHJ5IHtcbiAgICAgIHByb2R1Y2VkID0gYXdhaXQgdGFyZ2V0LnZhbGlkYXRvcnNbaW5kZXhdKGNvbnRleHQpXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHB1YmxpY2F0aW9uRmFpbHVyZShcIlBVQkxJQ0FUSU9OX1ZBTElEQVRJT05fRkFJTEVEXCIsIHByb2plY3RJZCxcbiAgICAgICAgYFZhbGlkYXRvciAke2luZGV4fSBmYWlsZWQgZm9yIHRhcmdldCAnJHt0YXJnZXQuaWR9Jy5gLCBlcnJvcilcbiAgICB9XG4gICAgaWYgKHByb2R1Y2VkID09PSB1bmRlZmluZWQpIGNvbnRpbnVlXG4gICAgaWYgKCFpc0RlbnNlQXJyYXkocHJvZHVjZWQpKSB7XG4gICAgICBwdWJsaWNhdGlvbkZhaWx1cmUoXCJQVUJMSUNBVElPTl9WQUxJREFUSU9OX0ZBSUxFRFwiLCBwcm9qZWN0SWQsXG4gICAgICAgIGBWYWxpZGF0b3IgJHtpbmRleH0gcmV0dXJuZWQgaW52YWxpZCBidWlsZC1hcnRpZmFjdCBtZXRhZGF0YSBmb3IgdGFyZ2V0ICcke3RhcmdldC5pZH0nLmApXG4gICAgfVxuICAgIGZvciAoY29uc3QgZGVzY3JpcHRvciBvZiBwcm9kdWNlZCkge1xuICAgICAgYnVpbGREZXNjcmlwdG9ycy5wdXNoKHZhbGlkYXRlQnVpbGRBcnRpZmFjdERlc2NyaXB0b3IoZGVzY3JpcHRvciwgdGFyZ2V0LmlkLCBwcm9qZWN0SWQpKVxuICAgIH1cbiAgfVxuXG4gIGNvbnN0IGRlc2NyaXB0b3JDb25mbGljdCA9IGZpbmRQb3J0YWJsZUFydGlmYWN0UGF0aENvbmZsaWN0KGJ1aWxkRGVzY3JpcHRvcnMubWFwKCh7cGF0aDogYXJ0aWZhY3RQYXRofSkgPT4gYXJ0aWZhY3RQYXRoKSlcblxuICBpZiAoZGVzY3JpcHRvckNvbmZsaWN0KSB7XG4gICAgcHVibGljYXRpb25GYWlsdXJlKFwiUFVCTElDQVRJT05fUEFUSF9DT0xMSVNJT05cIiwgcHJvamVjdElkLFxuICAgICAgYFRhcmdldCAnJHt0YXJnZXQuaWR9JyBidWlsZCBhcnRpZmFjdHMgaGF2ZSBhIHBvcnRhYmxlICR7ZGVzY3JpcHRvckNvbmZsaWN0LmtpbmR9IGNvbmZsaWN0LmApXG4gIH1cbiAgY29uc3Qgc3RhZ2VkQnVpbGRGaWxlcyA9IGF3YWl0IGxpc3RSZWd1bGFyRmlsZXMoYnVpbGRQYXRoLCBwcm9qZWN0SWQpXG4gIGNvbnN0IGRlY2xhcmVkID0gbmV3IFNldChidWlsZERlc2NyaXB0b3JzLm1hcCgoe3BhdGg6IGFydGlmYWN0UGF0aH0pID0+IGFydGlmYWN0UGF0aCkpXG5cbiAgaWYgKHN0YWdlZEJ1aWxkRmlsZXMubGVuZ3RoICE9IGRlY2xhcmVkLnNpemUgfHwgc3RhZ2VkQnVpbGRGaWxlcy5zb21lKGZpbGVuYW1lID0+ICFkZWNsYXJlZC5oYXMoZmlsZW5hbWUpKSkge1xuICAgIHB1YmxpY2F0aW9uRmFpbHVyZShcIlBVQkxJQ0FUSU9OX1ZBTElEQVRJT05fRkFJTEVEXCIsIHByb2plY3RJZCxcbiAgICAgIGBUYXJnZXQgJyR7dGFyZ2V0LmlkfScgdmFsaWRhdG9ycyBtdXN0IGRlY2xhcmUgZXZlcnkgc3RhZ2VkIGJ1aWxkIGFydGlmYWN0IGV4YWN0bHkgb25jZS5gKVxuICB9XG4gIC8qKiBAdHlwZSB7aW1wb3J0KFwiLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5HZW5lcmF0aW9uQnVpbGRBcnRpZmFjdE1hbmlmZXN0W119ICovXG4gIGNvbnN0IGZpbmFsaXplZEJ1aWxkQXJ0aWZhY3RzID0gW11cblxuICBmb3IgKGNvbnN0IGRlc2NyaXB0b3Igb2YgYnVpbGREZXNjcmlwdG9ycykge1xuICAgIGNvbnN0IGJ5dGVzID0gYXdhaXQgcmVhZEFuZFN5bmNSZWd1bGFyRmlsZShvd25lZFBhdGgoYnVpbGRQYXRoLCBkZXNjcmlwdG9yLnBhdGgsIHByb2plY3RJZCksIHByb2plY3RJZCxcbiAgICAgIFwiUFVCTElDQVRJT05fU1RBR0VfSEFTSF9NSVNNQVRDSFwiLCBgQnVpbGQgYXJ0aWZhY3QgJyR7ZGVzY3JpcHRvci5wYXRofScgaXMgbm90IGEgc3RhYmxlIHJlZ3VsYXIgZmlsZS5gKVxuXG4gICAgZmluYWxpemVkQnVpbGRBcnRpZmFjdHMucHVzaChPYmplY3QuZnJlZXplKHtcbiAgICAgIGJ5dGVMZW5ndGg6IGJ5dGVzLmJ5dGVMZW5ndGgsXG4gICAgICBoYXNoOiBPYmplY3QuZnJlZXplKHthbGdvcml0aG06IC8qKiBAdHlwZSB7Y29uc3R9ICovIChcInNoYTI1NlwiKSwgdmFsdWU6IHNoYTI1NihieXRlcyl9KSxcbiAgICAgIG1lZGlhVHlwZTogZGVzY3JpcHRvci5tZWRpYVR5cGUsXG4gICAgICBwYXRoOiBkZXNjcmlwdG9yLnBhdGgsXG4gICAgICByb2xlOiBkZXNjcmlwdG9yLnJvbGVcbiAgICB9KSlcbiAgfVxuXG4gIHJldHVybiBPYmplY3QuZnJlZXplKHtcbiAgICBhcnRpZmFjdHM6IE9iamVjdC5mcmVlemUoYXJ0aWZhY3RzKSxcbiAgICBidWlsZEFydGlmYWN0czogT2JqZWN0LmZyZWV6ZShmaW5hbGl6ZWRCdWlsZEFydGlmYWN0cyksXG4gICAgaWQ6IHRhcmdldC5pZCxcbiAgICAuLi4odGFyZ2V0LmFydGlmYWN0U2V0Lm1ldGFkYXRhID09PSB1bmRlZmluZWQgPyB7fSA6IHttZXRhZGF0YTogdGFyZ2V0LmFydGlmYWN0U2V0Lm1ldGFkYXRhfSksXG4gICAgcHJvamVjdGlvbnM6IE9iamVjdC5mcmVlemUoe2J1aWxkOiB0YXJnZXQuYnVpbGRQcm9qZWN0aW9uLCBzb3VyY2U6IHRhcmdldC5zb3VyY2VQcm9qZWN0aW9ufSksXG4gICAgcm9sZTogdGFyZ2V0LnJvbGUsXG4gICAgdGFyZ2V0OiB0YXJnZXQuYXJ0aWZhY3RTZXQudGFyZ2V0XG4gIH0pXG59XG5cbi8qKlxuICogVmFsaWRhdGVzIHZhbGlkYXRvci9jb21waWxlciBvdXRwdXQgbWV0YWRhdGEuXG4gKiBAcGFyYW0ge3Vua25vd259IGRlc2NyaXB0b3IgLSBNZXRhZGF0YSBjYW5kaWRhdGUuXG4gKiBAcGFyYW0ge3N0cmluZ30gdGFyZ2V0SWQgLSBUYXJnZXQgaWRlbnRpdHkuXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvamVjdElkIC0gUHJvamVjdCBkaWFnbm9zdGljIGlkZW50aXR5LlxuICogQHJldHVybnMge2ltcG9ydChcIi4vc2VtYW50aWMvdHlwZXMuanNcIikuUHVibGljYXRpb25CdWlsZEFydGlmYWN0SW5wdXR9IFZhbGlkYXRlZCBtZXRhZGF0YS5cbiAqL1xuZnVuY3Rpb24gdmFsaWRhdGVCdWlsZEFydGlmYWN0RGVzY3JpcHRvcihkZXNjcmlwdG9yLCB0YXJnZXRJZCwgcHJvamVjdElkKSB7XG4gIGlmICghaXNQbGFpbk9iamVjdChkZXNjcmlwdG9yKSB8fCAhaGFzRXhhY3RLZXlzKGRlc2NyaXB0b3IsIFtcIm1lZGlhVHlwZVwiLCBcInBhdGhcIiwgXCJyb2xlXCJdKSkge1xuICAgIHB1YmxpY2F0aW9uRmFpbHVyZShcIlBVQkxJQ0FUSU9OX1ZBTElEQVRJT05fRkFJTEVEXCIsIHByb2plY3RJZCxcbiAgICAgIGBUYXJnZXQgJyR7dGFyZ2V0SWR9JyB2YWxpZGF0b3IgcmV0dXJuZWQgaW52YWxpZCBidWlsZC1hcnRpZmFjdCBtZXRhZGF0YS5gKVxuICB9XG4gIGNvbnN0IGRlc2NyaXB0b3JQYXRoID0gZGVzY3JpcHRvci5wYXRoXG4gIGNvbnN0IG1lZGlhVHlwZSA9IGRlc2NyaXB0b3IubWVkaWFUeXBlXG4gIGNvbnN0IHJvbGUgPSBkZXNjcmlwdG9yLnJvbGVcblxuICBpZiAoIWlzU2FmZUFydGlmYWN0UGF0aChkZXNjcmlwdG9yUGF0aCkgfHwgdHlwZW9mIG1lZGlhVHlwZSAhPSBcInN0cmluZ1wiIHx8XG4gICAgIW1lZGlhVHlwZVBhdHRlcm4udGVzdChtZWRpYVR5cGUpIHx8IC9bXFxyXFxuXS91LnRlc3QobWVkaWFUeXBlKSB8fFxuICAgIHR5cGVvZiByb2xlICE9IFwic3RyaW5nXCIgfHwgIWJ1aWxkUm9sZVBhdHRlcm4udGVzdChyb2xlKSkge1xuICAgIHB1YmxpY2F0aW9uRmFpbHVyZShcIlBVQkxJQ0FUSU9OX1ZBTElEQVRJT05fRkFJTEVEXCIsIHByb2plY3RJZCxcbiAgICAgIGBUYXJnZXQgJyR7dGFyZ2V0SWR9JyB2YWxpZGF0b3IgcmV0dXJuZWQgaW52YWxpZCBidWlsZC1hcnRpZmFjdCBtZXRhZGF0YS5gKVxuICB9XG5cbiAgcmV0dXJuIE9iamVjdC5mcmVlemUoe21lZGlhVHlwZSwgcGF0aDogZGVzY3JpcHRvclBhdGgsIHJvbGV9KVxufVxuXG4vKipcbiAqIFZlcmlmaWVzIGV2ZXJ5IG1hbmlmZXN0IHJlZmVyZW5jZSBhbmQgc3RhZ2VkIGJ5dGUgYmVmb3JlIHBvaW50ZXIgcmVhY2hhYmlsaXR5LlxuICogQHBhcmFtIHtzdHJpbmd9IGdlbmVyYXRpb25QYXRoIC0gQ2FuZGlkYXRlIGdlbmVyYXRpb24gcGF0aC5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5HZW5lcmF0aW9uTWFuaWZlc3R9IG1hbmlmZXN0IC0gQ2FuZGlkYXRlIG1hbmlmZXN0LlxuICogQHBhcmFtIHtzdHJpbmd9IHByb2plY3RJZCAtIFByb2plY3QgZGlhZ25vc3RpYyBpZGVudGl0eS5cbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBDb21wbGV0aW9uLlxuICovXG5hc3luYyBmdW5jdGlvbiB2ZXJpZnlNYW5pZmVzdEZpbGVzKGdlbmVyYXRpb25QYXRoLCBtYW5pZmVzdCwgcHJvamVjdElkKSB7XG4gIGZvciAoY29uc3QgdGFyZ2V0IG9mIG1hbmlmZXN0LnRhcmdldHMpIHtcbiAgICBjb25zdCBzb3VyY2VQYXRoID0gb3duZWRQYXRoKGdlbmVyYXRpb25QYXRoLCB0YXJnZXQucHJvamVjdGlvbnMuc291cmNlLCBwcm9qZWN0SWQpXG4gICAgY29uc3QgYnVpbGRQYXRoID0gb3duZWRQYXRoKGdlbmVyYXRpb25QYXRoLCB0YXJnZXQucHJvamVjdGlvbnMuYnVpbGQsIHByb2plY3RJZClcbiAgICBjb25zdCBzb3VyY2VGaWxlcyA9IGF3YWl0IGxpc3RSZWd1bGFyRmlsZXMoc291cmNlUGF0aCwgcHJvamVjdElkKVxuXG4gICAgaWYgKHNvdXJjZUZpbGVzLmxlbmd0aCAhPSB0YXJnZXQuYXJ0aWZhY3RzLmxlbmd0aCB8fFxuICAgICAgc291cmNlRmlsZXMuc29tZShmaWxlbmFtZSA9PiAhdGFyZ2V0LmFydGlmYWN0cy5zb21lKGFydGlmYWN0ID0+IGFydGlmYWN0LnBhdGggPT0gZmlsZW5hbWUpKSkge1xuICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiUFVCTElDQVRJT05fU1RBR0VfSEFTSF9NSVNNQVRDSFwiLCBwcm9qZWN0SWQsXG4gICAgICAgIGBUYXJnZXQgJyR7dGFyZ2V0LmlkfScgZ2VuZXJhdGVkLXNvdXJjZSBmaWxlcyBkbyBub3QgbWF0Y2ggaXRzIG1hbmlmZXN0LmApXG4gICAgfVxuICAgIGZvciAoY29uc3QgYXJ0aWZhY3Qgb2YgdGFyZ2V0LmFydGlmYWN0cykge1xuICAgICAgYXdhaXQgdmVyaWZ5TWFuaWZlc3RGaWxlKHNvdXJjZVBhdGgsIGFydGlmYWN0LCBwcm9qZWN0SWQpXG4gICAgfVxuICAgIGNvbnN0IGJ1aWxkRmlsZXMgPSBhd2FpdCBsaXN0UmVndWxhckZpbGVzKGJ1aWxkUGF0aCwgcHJvamVjdElkKVxuXG4gICAgaWYgKGJ1aWxkRmlsZXMubGVuZ3RoICE9IHRhcmdldC5idWlsZEFydGlmYWN0cy5sZW5ndGggfHxcbiAgICAgIGJ1aWxkRmlsZXMuc29tZShmaWxlbmFtZSA9PiAhdGFyZ2V0LmJ1aWxkQXJ0aWZhY3RzLnNvbWUoYXJ0aWZhY3QgPT4gYXJ0aWZhY3QucGF0aCA9PSBmaWxlbmFtZSkpKSB7XG4gICAgICBwdWJsaWNhdGlvbkZhaWx1cmUoXCJQVUJMSUNBVElPTl9TVEFHRV9IQVNIX01JU01BVENIXCIsIHByb2plY3RJZCxcbiAgICAgICAgYFRhcmdldCAnJHt0YXJnZXQuaWR9JyBidWlsZCBmaWxlcyBkbyBub3QgbWF0Y2ggaXRzIG1hbmlmZXN0LmApXG4gICAgfVxuICAgIGZvciAoY29uc3QgYXJ0aWZhY3Qgb2YgdGFyZ2V0LmJ1aWxkQXJ0aWZhY3RzKSB7XG4gICAgICBhd2FpdCB2ZXJpZnlNYW5pZmVzdEZpbGUoYnVpbGRQYXRoLCBhcnRpZmFjdCwgcHJvamVjdElkKVxuICAgIH1cbiAgICB0cnkge1xuICAgICAgY29uc3QgYXJ0aWZhY3RzID0gW11cblxuICAgICAgZm9yIChjb25zdCBhcnRpZmFjdCBvZiB0YXJnZXQuYXJ0aWZhY3RzKSB7XG4gICAgICAgIGNvbnN0IGJ5dGVzID0gYXdhaXQgcmVhZEFuZFN5bmNSZWd1bGFyRmlsZShvd25lZFBhdGgoc291cmNlUGF0aCwgYXJ0aWZhY3QucGF0aCwgcHJvamVjdElkKSwgcHJvamVjdElkLFxuICAgICAgICAgIFwiUFVCTElDQVRJT05fU1RBR0VfSEFTSF9NSVNNQVRDSFwiLCBgTWFuaWZlc3QgYXJ0aWZhY3QgJyR7YXJ0aWZhY3QucGF0aH0nIGlzIG5vdCBhIHN0YWJsZSByZWd1bGFyIGZpbGUuYClcbiAgICAgICAgbGV0IGNvbnRlbnRcblxuICAgICAgICBpZiAoYXJ0aWZhY3QuY29udGVudEtpbmQgPT0gXCJ0ZXh0XCIpIHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgY29udGVudCA9IG5ldyBUZXh0RGVjb2RlcihcInV0Zi04XCIsIHtmYXRhbDogdHJ1ZX0pLmRlY29kZShieXRlcylcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiTUFMRk9STUVEX0dFTkVSQVRJT05fTUFOSUZFU1RcIiwgcHJvamVjdElkLFxuICAgICAgICAgICAgICBgVGV4dCBhcnRpZmFjdCAnJHthcnRpZmFjdC5wYXRofScgaXMgbm90IHZhbGlkIFVURi04LmAsIGVycm9yKVxuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGNvbnRlbnQgPSBuZXcgVWludDhBcnJheShieXRlcylcbiAgICAgICAgYXJ0aWZhY3RzLnB1c2goe1xuICAgICAgICAgIGNvbnRlbnQsXG4gICAgICAgICAgY29udGVudEtpbmQ6IGFydGlmYWN0LmNvbnRlbnRLaW5kLFxuICAgICAgICAgIG1lZGlhVHlwZTogYXJ0aWZhY3QubWVkaWFUeXBlLFxuICAgICAgICAgIG93bmVyc2hpcDogLyoqIEB0eXBlIHtjb25zdH0gKi8gKFwiZ2VuZXJhdGVkXCIpLFxuICAgICAgICAgIHBhdGg6IGFydGlmYWN0LnBhdGgsXG4gICAgICAgICAgcHJvdmVuYW5jZTogcmVoeWRyYXRlUHJvdmVuYW5jZShhcnRpZmFjdC5wcm92ZW5hbmNlLCBwcm9qZWN0SWQpLFxuICAgICAgICAgIHJvbGU6IGFydGlmYWN0LnJvbGVcbiAgICAgICAgfSlcbiAgICAgIH1cbiAgICAgIGNyZWF0ZUdlbmVyYXRlZEFydGlmYWN0U2V0KHtcbiAgICAgICAgYXJ0aWZhY3RzLFxuICAgICAgICAuLi4odGFyZ2V0Lm1ldGFkYXRhID09PSB1bmRlZmluZWQgPyB7fSA6IHttZXRhZGF0YTogdGFyZ2V0Lm1ldGFkYXRhfSksXG4gICAgICAgIHRhcmdldDogdGFyZ2V0LnRhcmdldFxuICAgICAgfSlcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgU2VtYW50aWZvbGREaWFnbm9zdGljICYmIGVycm9yLmNvZGUgPT0gXCJNQUxGT1JNRURfR0VORVJBVElPTl9NQU5JRkVTVFwiKSB0aHJvdyBlcnJvclxuICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiTUFMRk9STUVEX0dFTkVSQVRJT05fTUFOSUZFU1RcIiwgcHJvamVjdElkLFxuICAgICAgICBgVGFyZ2V0ICcke3RhcmdldC5pZH0nIGFydGlmYWN0IHByb3ZlbmFuY2UgZG9lcyBub3QgbWF0Y2ggaXRzIHN0YWdlZCBieXRlcy5gLCBlcnJvcilcbiAgICB9XG4gIH1cbiAgYXdhaXQgdmVyaWZ5R2VuZXJhdGlvbkludmVudG9yeShnZW5lcmF0aW9uUGF0aCwgbWFuaWZlc3QsIHByb2plY3RJZClcbn1cblxuLyoqXG4gKiBSZXN0b3JlcyBKU09OLW9taXR0ZWQgb3B0aW9uYWwgbWFwcGluZyBmaWVsZHMgYW5kIHZlcmlmaWVzIHBlcnNpc3RlZCBtYXBwaW5nIHByb2plY3Rpb25zLlxuICogQHBhcmFtIHtpbXBvcnQoXCIuL3NlbWFudGljL3R5cGVzLmpzXCIpLkFydGlmYWN0UHJvdmVuYW5jZX0gcHJvdmVuYW5jZSAtIFBlcnNpc3RlZCBwcm92ZW5hbmNlLlxuICogQHBhcmFtIHtzdHJpbmd9IHByb2plY3RJZCAtIFByb2plY3QgaWRlbnRpdHkuXG4gKiBAcmV0dXJucyB7aW1wb3J0KFwiLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5BcnRpZmFjdFByb3ZlbmFuY2V9IENhbm9uaWNhbCBwcm92ZW5hbmNlLlxuICovXG5mdW5jdGlvbiByZWh5ZHJhdGVQcm92ZW5hbmNlKHByb3ZlbmFuY2UsIHByb2plY3RJZCkge1xuICBpZiAocHJvdmVuYW5jZS5raW5kID09IFwidGV4dFwiKSB7XG4gICAgY29uc3QgbWFwcGluZyA9IGZpbmFsaXplTWFwcGluZyhwcm92ZW5hbmNlLm1hcHBpbmcpXG4gICAgY29uc3Qgc291cmNlTWFwID0gdG9Tb3VyY2VNYXBWMyhtYXBwaW5nKVxuICAgIGNvbnN0IGpzb25Tb3VyY2VNYXAgPSBKU09OLnBhcnNlKEpTT04uc3RyaW5naWZ5KHNvdXJjZU1hcCkpXG5cbiAgICBpZiAoIXNhbWVKc29uVmFsdWUoanNvblNvdXJjZU1hcCwgcHJvdmVuYW5jZS5zb3VyY2VNYXApKSB7XG4gICAgICBwdWJsaWNhdGlvbkZhaWx1cmUoXCJNQUxGT1JNRURfR0VORVJBVElPTl9NQU5JRkVTVFwiLCBwcm9qZWN0SWQsXG4gICAgICAgIFwiUGVyc2lzdGVkIFNvdXJjZSBNYXAgcHJvamVjdGlvbiBjb250cmFkaWN0cyBpdHMgcmljaCBtYXBwaW5nLlwiKVxuICAgIH1cblxuICAgIHJldHVybiBPYmplY3QuZnJlZXplKHtcbiAgICAgIGtpbmQ6IC8qKiBAdHlwZSB7Y29uc3R9ICovIChcInRleHRcIiksXG4gICAgICBtYXBwaW5nLFxuICAgICAgc291cmNlTWFwLFxuICAgICAgLi4uKHByb3ZlbmFuY2Uuc291cmNlTWFwRmlsZW5hbWUgPT09IHVuZGVmaW5lZCA/IHt9IDoge3NvdXJjZU1hcEZpbGVuYW1lOiBwcm92ZW5hbmNlLnNvdXJjZU1hcEZpbGVuYW1lfSlcbiAgICB9KVxuICB9XG4gIGlmIChwcm92ZW5hbmNlLmtpbmQgPT0gXCJieXRlc1wiKSB7XG4gICAgcmV0dXJuIE9iamVjdC5mcmVlemUoe2tpbmQ6IC8qKiBAdHlwZSB7Y29uc3R9ICovIChcImJ5dGVzXCIpLCBtYXBwaW5nOiBmaW5hbGl6ZUJ5dGVNYXBwaW5nKHByb3ZlbmFuY2UubWFwcGluZyl9KVxuICB9XG5cbiAgcmV0dXJuIHByb3ZlbmFuY2Vcbn1cblxuLyoqXG4gKiBWZXJpZmllcyBvbmUgcmVmZXJlbmNlZCBmaWxlLlxuICogQHBhcmFtIHtzdHJpbmd9IHByb2plY3Rpb25QYXRoIC0gT3duaW5nIHByb2plY3Rpb24gcGF0aC5cbiAqIEBwYXJhbSB7e2J5dGVMZW5ndGg6IG51bWJlciwgaGFzaDogaW1wb3J0KFwiLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5HZW5lcmF0aW9uQ29udGVudEhhc2gsIHBhdGg6IHN0cmluZ319IGFydGlmYWN0IC0gTWFuaWZlc3QgcmVjb3JkLlxuICogQHBhcmFtIHtzdHJpbmd9IHByb2plY3RJZCAtIFByb2plY3QgZGlhZ25vc3RpYyBpZGVudGl0eS5cbiAqIEByZXR1cm5zIHtQcm9taXNlPEJ1ZmZlcj59IEV4YWN0IHZlcmlmaWVkIGJ5dGVzLlxuICovXG5hc3luYyBmdW5jdGlvbiB2ZXJpZnlNYW5pZmVzdEZpbGUocHJvamVjdGlvblBhdGgsIGFydGlmYWN0LCBwcm9qZWN0SWQpIHtcbiAgY29uc3QgYnl0ZXMgPSBhd2FpdCByZWFkQW5kU3luY1JlZ3VsYXJGaWxlKG93bmVkUGF0aChwcm9qZWN0aW9uUGF0aCwgYXJ0aWZhY3QucGF0aCwgcHJvamVjdElkKSwgcHJvamVjdElkLFxuICAgIFwiUFVCTElDQVRJT05fU1RBR0VfSEFTSF9NSVNNQVRDSFwiLCBgTWFuaWZlc3QgYXJ0aWZhY3QgJyR7YXJ0aWZhY3QucGF0aH0nIGlzIG5vdCBhIHN0YWJsZSByZWd1bGFyIGZpbGUuYClcblxuICBpZiAoYnl0ZXMuYnl0ZUxlbmd0aCAhPSBhcnRpZmFjdC5ieXRlTGVuZ3RoIHx8IHNoYTI1NihieXRlcykgIT0gYXJ0aWZhY3QuaGFzaC52YWx1ZSkge1xuICAgIHB1YmxpY2F0aW9uRmFpbHVyZShcIlBVQkxJQ0FUSU9OX1NUQUdFX0hBU0hfTUlTTUFUQ0hcIiwgcHJvamVjdElkLFxuICAgICAgYE1hbmlmZXN0IGFydGlmYWN0ICcke2FydGlmYWN0LnBhdGh9JyBieXRlcyBkbyBub3QgbWF0Y2ggaXRzIHJlY29yZGVkIGhhc2guYClcbiAgfVxuXG4gIHJldHVybiBieXRlc1xufVxuXG4vKipcbiAqIFZhbGlkYXRlcyBhbiBleGlzdGluZyBhY3RpdmUgcG9pbnRlciBiZWZvcmUgYSBuZXcgY2FuZGlkYXRlIGlzIHN0YWdlZC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBwdWJsaWNhdGlvblJvb3QgLSBQdWJsaWNhdGlvbiByb290LlxuICogQHBhcmFtIHtzdHJpbmd9IHByb2plY3RJZCAtIFByb2plY3QgaWRlbnRpdHkuXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQ29tcGxldGlvbi5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gdmFsaWRhdGVFeGlzdGluZ1BvaW50ZXIocHVibGljYXRpb25Sb290LCBwcm9qZWN0SWQpIHtcbiAgY29uc3QgcG9pbnRlclBhdGggPSBwYXRoLmpvaW4ocHVibGljYXRpb25Sb290LCBhY3RpdmVQb2ludGVyTmFtZSlcbiAgY29uc3QgcG9pbnRlciA9IGF3YWl0IHJlYWRBY3RpdmVQb2ludGVyKHBvaW50ZXJQYXRoLCBwcm9qZWN0SWQsIHRydWUpXG5cbiAgaWYgKHBvaW50ZXIpIGF3YWl0IHZlcmlmeVB1Ymxpc2hlZEdlbmVyYXRpb24ocHVibGljYXRpb25Sb290LCBwcm9qZWN0SWQsIHBvaW50ZXIsIGZhbHNlKVxufVxuXG4vKipcbiAqIFJlYWRzIGFuZCBzdHJpY3RseSB2YWxpZGF0ZXMgb25lIGFjdGl2ZSBwb2ludGVyLlxuICogQHBhcmFtIHtzdHJpbmd9IHBvaW50ZXJQYXRoIC0gUG9pbnRlciBmaWxlbmFtZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBwcm9qZWN0SWQgLSBFeHBlY3RlZCBwcm9qZWN0IGlkZW50aXR5LlxuICogQHBhcmFtIHtib29sZWFufSBvcHRpb25hbCAtIFdoZXRoZXIgYWJzZW5jZSBpcyBhbGxvd2VkLlxuICogQHJldHVybnMge1Byb21pc2U8QWN0aXZlUG9pbnRlciB8IG51bGw+fSBQb2ludGVyIG9yIGFic2VudCB2YWx1ZS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gcmVhZEFjdGl2ZVBvaW50ZXIocG9pbnRlclBhdGgsIHByb2plY3RJZCwgb3B0aW9uYWwpIHtcbiAgbGV0IHBvaW50ZXJCeXRlc1xuXG4gIHRyeSB7XG4gICAgY29uc3Qgc3RhdHVzID0gYXdhaXQgbHN0YXQocG9pbnRlclBhdGgpXG5cbiAgICBpZiAoIXN0YXR1cy5pc0ZpbGUoKSB8fCBzdGF0dXMuaXNTeW1ib2xpY0xpbmsoKSkge1xuICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiTUFMRk9STUVEX0FDVElWRV9HRU5FUkFUSU9OXCIsIHByb2plY3RJZCxcbiAgICAgICAgXCJBY3RpdmUtZ2VuZXJhdGlvbiBwb2ludGVyIG11c3QgYmUgYSByZWd1bGFyIGZpbGUuXCIpXG4gICAgfVxuICAgIHBvaW50ZXJCeXRlcyA9IGF3YWl0IHJlYWRGaWxlKHBvaW50ZXJQYXRoKVxuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGlmIChvcHRpb25hbCAmJiBpc0Vycm9yQ29kZShlcnJvciwgXCJFTk9FTlRcIikpIHJldHVybiBudWxsXG4gICAgaWYgKGVycm9yIGluc3RhbmNlb2YgU2VtYW50aWZvbGREaWFnbm9zdGljKSB0aHJvdyBlcnJvclxuICAgIHB1YmxpY2F0aW9uRmFpbHVyZShvcHRpb25hbCA/IFwiTUFMRk9STUVEX0FDVElWRV9HRU5FUkFUSU9OXCIgOiBcIkFDVElWRV9HRU5FUkFUSU9OX01JU1NJTkdcIiwgcHJvamVjdElkLFxuICAgICAgb3B0aW9uYWwgPyBcIkFjdGl2ZS1nZW5lcmF0aW9uIHBvaW50ZXIgY291bGQgbm90IGJlIHJlYWQuXCIgOiBcIk5vIGFjdGl2ZSBnZW5lcmF0aW9uIGhhcyBiZWVuIHB1Ymxpc2hlZC5cIiwgZXJyb3IpXG4gIH1cbiAgbGV0IHZhbHVlXG5cbiAgdHJ5IHtcbiAgICB2YWx1ZSA9IEpTT04ucGFyc2UocG9pbnRlckJ5dGVzLnRvU3RyaW5nKFwidXRmOFwiKSlcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBwdWJsaWNhdGlvbkZhaWx1cmUoXCJNQUxGT1JNRURfQUNUSVZFX0dFTkVSQVRJT05cIiwgcHJvamVjdElkLFxuICAgICAgXCJBY3RpdmUtZ2VuZXJhdGlvbiBwb2ludGVyIGlzIG5vdCB2YWxpZCBKU09OLlwiLCBlcnJvcilcbiAgfVxuICBpZiAoIWlzQWN0aXZlUG9pbnRlcih2YWx1ZSkgfHwgdmFsdWUucHJvamVjdElkICE9IHByb2plY3RJZCkge1xuICAgIHB1YmxpY2F0aW9uRmFpbHVyZShcIk1BTEZPUk1FRF9BQ1RJVkVfR0VORVJBVElPTlwiLCBwcm9qZWN0SWQsXG4gICAgICBcIkFjdGl2ZS1nZW5lcmF0aW9uIHBvaW50ZXIgZG9lcyBub3QgbWF0Y2ggdGhlIHZlcnNpb25lZCBwcm9qZWN0IGNvbnRyYWN0LlwiKVxuICB9XG5cbiAgcmV0dXJuIHZhbHVlXG59XG5cbi8qKlxuICogVmVyaWZpZXMgYSBwb2ludGVyLXNlbGVjdGVkIGdlbmVyYXRpb24gd2l0aG91dCBjb25zdWx0aW5nIHRoZSBwb2ludGVyIGFnYWluLlxuICogQHBhcmFtIHtzdHJpbmd9IHB1YmxpY2F0aW9uUm9vdCAtIFB1YmxpY2F0aW9uIHJvb3QuXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvamVjdElkIC0gUHJvamVjdCBpZGVudGl0eS5cbiAqIEBwYXJhbSB7QWN0aXZlUG9pbnRlcn0gcG9pbnRlciAtIFBvaW50ZXIgc25hcHNob3QuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGNsZWFudXBQZW5kaW5nIC0gUmVjb3Zlcnkgc3RhdGUuXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxpbXBvcnQoXCIuL3NlbWFudGljL3R5cGVzLmpzXCIpLlB1Ymxpc2hlZEdlbmVyYXRpb24+fSBWZXJpZmllZCBnZW5lcmF0aW9uLlxuICovXG5hc3luYyBmdW5jdGlvbiB2ZXJpZnlQdWJsaXNoZWRHZW5lcmF0aW9uKHB1YmxpY2F0aW9uUm9vdCwgcHJvamVjdElkLCBwb2ludGVyLCBjbGVhbnVwUGVuZGluZykge1xuICBjb25zdCBnZW5lcmF0aW9uUGF0aCA9IG93bmVkUGF0aChwYXRoLmpvaW4ocHVibGljYXRpb25Sb290LCBnZW5lcmF0aW9uc05hbWUpLCBwb2ludGVyLmdlbmVyYXRpb25JZCwgcHJvamVjdElkKVxuICBjb25zdCBtYW5pZmVzdFBhdGggPSBwYXRoLmpvaW4oZ2VuZXJhdGlvblBhdGgsIFwibWFuaWZlc3QuanNvblwiKVxuICBsZXQgbWFuaWZlc3RCeXRlc1xuXG4gIHRyeSB7XG4gICAgbWFuaWZlc3RCeXRlcyA9IGF3YWl0IHJlYWRBbmRTeW5jUmVndWxhckZpbGUobWFuaWZlc3RQYXRoLCBwcm9qZWN0SWQsIFwiTUFMRk9STUVEX0dFTkVSQVRJT05fTUFOSUZFU1RcIixcbiAgICAgIFwiR2VuZXJhdGlvbiBtYW5pZmVzdCBtdXN0IGJlIGEgcmVndWxhciBmaWxlLlwiKVxuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIFNlbWFudGlmb2xkRGlhZ25vc3RpYykgdGhyb3cgZXJyb3JcbiAgICBwdWJsaWNhdGlvbkZhaWx1cmUoXCJNQUxGT1JNRURfR0VORVJBVElPTl9NQU5JRkVTVFwiLCBwcm9qZWN0SWQsXG4gICAgICBcIkdlbmVyYXRpb24gbWFuaWZlc3QgY291bGQgbm90IGJlIHJlYWQuXCIsIGVycm9yKVxuICB9XG4gIGlmIChzaGEyNTYobWFuaWZlc3RCeXRlcykgIT0gcG9pbnRlci5tYW5pZmVzdEhhc2gpIHtcbiAgICBwdWJsaWNhdGlvbkZhaWx1cmUoXCJNQUxGT1JNRURfR0VORVJBVElPTl9NQU5JRkVTVFwiLCBwcm9qZWN0SWQsXG4gICAgICBcIkdlbmVyYXRpb24gbWFuaWZlc3QgaGFzaCBkb2VzIG5vdCBtYXRjaCB0aGUgYWN0aXZlIHBvaW50ZXIuXCIpXG4gIH1cbiAgbGV0IHZhbHVlXG5cbiAgdHJ5IHtcbiAgICB2YWx1ZSA9IEpTT04ucGFyc2UobWFuaWZlc3RCeXRlcy50b1N0cmluZyhcInV0ZjhcIikpXG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgcHVibGljYXRpb25GYWlsdXJlKFwiTUFMRk9STUVEX0dFTkVSQVRJT05fTUFOSUZFU1RcIiwgcHJvamVjdElkLFxuICAgICAgXCJHZW5lcmF0aW9uIG1hbmlmZXN0IGlzIG5vdCB2YWxpZCBKU09OLlwiLCBlcnJvcilcbiAgfVxuICBjb25zdCBtYW5pZmVzdCA9IHZhbGlkYXRlR2VuZXJhdGlvbk1hbmlmZXN0KHZhbHVlLCBwcm9qZWN0SWQsIHBvaW50ZXIuZ2VuZXJhdGlvbklkKVxuXG4gIGF3YWl0IHZlcmlmeU1hbmlmZXN0RmlsZXMoZ2VuZXJhdGlvblBhdGgsIG1hbmlmZXN0LCBwcm9qZWN0SWQpXG5cbiAgcmV0dXJuIHB1Ymxpc2hlZEdlbmVyYXRpb24ocHVibGljYXRpb25Sb290LCBtYW5pZmVzdCwgY2xlYW51cFBlbmRpbmcpXG59XG5cbi8qKlxuICogU3RyaWN0bHkgdmFsaWRhdGVzIGEgcGVyc2lzdGVkIGdlbmVyYXRpb24gbWFuaWZlc3QuXG4gKiBAcGFyYW0ge3Vua25vd259IHZhbHVlIC0gUGFyc2VkIG1hbmlmZXN0IHZhbHVlLlxuICogQHBhcmFtIHtzdHJpbmd9IHByb2plY3RJZCAtIEV4cGVjdGVkIHByb2plY3QgaWRlbnRpdHkuXG4gKiBAcGFyYW0ge3N0cmluZ30gZ2VuZXJhdGlvbklkIC0gRXhwZWN0ZWQgZ2VuZXJhdGlvbiBpZGVudGl0eS5cbiAqIEByZXR1cm5zIHtpbXBvcnQoXCIuL3NlbWFudGljL3R5cGVzLmpzXCIpLkdlbmVyYXRpb25NYW5pZmVzdH0gRnJvemVuIG1hbmlmZXN0LlxuICovXG5mdW5jdGlvbiB2YWxpZGF0ZUdlbmVyYXRpb25NYW5pZmVzdCh2YWx1ZSwgcHJvamVjdElkLCBnZW5lcmF0aW9uSWQpIHtcbiAgaWYgKCFpc1BsYWluT2JqZWN0KHZhbHVlKSB8fCAhaGFzRXhhY3RLZXlzKHZhbHVlLCBbXCJnZW5lcmF0aW9uSWRcIiwgXCJwcm9qZWN0SWRcIiwgXCJzY2hlbWFcIiwgXCJ0YXJnZXRzXCIsIFwidmVyc2lvblwiXSkgfHxcbiAgICB2YWx1ZS5zY2hlbWEgIT0gXCJTZW1hbnRpZm9sZEdlbmVyYXRpb25NYW5pZmVzdFwiIHx8IHZhbHVlLnZlcnNpb24gIT0gMSB8fCB2YWx1ZS5wcm9qZWN0SWQgIT0gcHJvamVjdElkIHx8XG4gICAgdmFsdWUuZ2VuZXJhdGlvbklkICE9IGdlbmVyYXRpb25JZCB8fCAhaXNEZW5zZUFycmF5KHZhbHVlLnRhcmdldHMpIHx8IHZhbHVlLnRhcmdldHMubGVuZ3RoID09IDApIHtcbiAgICBwdWJsaWNhdGlvbkZhaWx1cmUoXCJNQUxGT1JNRURfR0VORVJBVElPTl9NQU5JRkVTVFwiLCBwcm9qZWN0SWQsXG4gICAgICBcIkdlbmVyYXRpb24gbWFuaWZlc3QgZG9lcyBub3QgbWF0Y2ggdGhlIHZlcnNpb25lZCBwcm9qZWN0IGNvbnRyYWN0LlwiKVxuICB9XG4gIC8qKiBAdHlwZSB7aW1wb3J0KFwiLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5HZW5lcmF0aW9uVGFyZ2V0TWFuaWZlc3RbXX0gKi9cbiAgY29uc3QgdGFyZ2V0cyA9IFtdXG4gIC8qKiBAdHlwZSB7c3RyaW5nW119ICovXG4gIGNvbnN0IHByb2plY3Rpb25zID0gW11cbiAgY29uc3QgaWRzID0gbmV3IFNldCgpXG5cbiAgZm9yIChjb25zdCB0YXJnZXQgb2YgdmFsdWUudGFyZ2V0cykge1xuICAgIGNvbnN0IHRhcmdldEtleXMgPSB0YXJnZXQgJiYgdHlwZW9mIHRhcmdldCA9PSBcIm9iamVjdFwiICYmIFwibWV0YWRhdGFcIiBpbiB0YXJnZXRcbiAgICAgID8gW1wiYXJ0aWZhY3RzXCIsIFwiYnVpbGRBcnRpZmFjdHNcIiwgXCJpZFwiLCBcIm1ldGFkYXRhXCIsIFwicHJvamVjdGlvbnNcIiwgXCJyb2xlXCIsIFwidGFyZ2V0XCJdXG4gICAgICA6IFtcImFydGlmYWN0c1wiLCBcImJ1aWxkQXJ0aWZhY3RzXCIsIFwiaWRcIiwgXCJwcm9qZWN0aW9uc1wiLCBcInJvbGVcIiwgXCJ0YXJnZXRcIl1cblxuICAgIGlmICghaXNQbGFpbk9iamVjdCh0YXJnZXQpIHx8ICFoYXNFeGFjdEtleXModGFyZ2V0LCB0YXJnZXRLZXlzKSB8fFxuICAgICAgIWlkZW50aXR5UGF0dGVybi50ZXN0KHR5cGVvZiB0YXJnZXQuaWQgPT0gXCJzdHJpbmdcIiA/IHRhcmdldC5pZCA6IFwiXCIpIHx8IGlkcy5oYXModGFyZ2V0LmlkKSB8fFxuICAgICAgdHlwZW9mIHRhcmdldC5yb2xlICE9IFwic3RyaW5nXCIgfHwgIXRhcmdldFJvbGVzLmhhcyh0YXJnZXQucm9sZSkgfHxcbiAgICAgIHR5cGVvZiB0YXJnZXQudGFyZ2V0ICE9IFwic3RyaW5nXCIgfHwgIWlkZW50aXR5UGF0dGVybi50ZXN0KHRhcmdldC50YXJnZXQpIHx8XG4gICAgICAhaXNQbGFpbk9iamVjdCh0YXJnZXQucHJvamVjdGlvbnMpIHx8ICFoYXNFeGFjdEtleXModGFyZ2V0LnByb2plY3Rpb25zLCBbXCJidWlsZFwiLCBcInNvdXJjZVwiXSkgfHxcbiAgICAgICFpc1NhZmVBcnRpZmFjdFBhdGgodGFyZ2V0LnByb2plY3Rpb25zLnNvdXJjZSkgfHwgIWlzU2FmZUFydGlmYWN0UGF0aCh0YXJnZXQucHJvamVjdGlvbnMuYnVpbGQpIHx8XG4gICAgICAhaXNEZW5zZUFycmF5KHRhcmdldC5hcnRpZmFjdHMpIHx8IHRhcmdldC5hcnRpZmFjdHMubGVuZ3RoID09IDAgfHwgIWlzRGVuc2VBcnJheSh0YXJnZXQuYnVpbGRBcnRpZmFjdHMpKSB7XG4gICAgICBwdWJsaWNhdGlvbkZhaWx1cmUoXCJNQUxGT1JNRURfR0VORVJBVElPTl9NQU5JRkVTVFwiLCBwcm9qZWN0SWQsXG4gICAgICAgIFwiR2VuZXJhdGlvbiBtYW5pZmVzdCBjb250YWlucyBhbiBpbnZhbGlkIHRhcmdldCByZWNvcmQuXCIpXG4gICAgfVxuICAgIGNvbnN0IHRhcmdldElkID0gLyoqIEB0eXBlIHtzdHJpbmd9ICovICh0YXJnZXQuaWQpXG5cbiAgICBpZHMuYWRkKHRhcmdldElkKVxuICAgIHByb2plY3Rpb25zLnB1c2godGFyZ2V0LnByb2plY3Rpb25zLnNvdXJjZSwgdGFyZ2V0LnByb2plY3Rpb25zLmJ1aWxkKVxuICAgIGNvbnN0IGFydGlmYWN0cyA9IHRhcmdldC5hcnRpZmFjdHMubWFwKGFydGlmYWN0ID0+IHZhbGlkYXRlUGVyc2lzdGVkQXJ0aWZhY3QoYXJ0aWZhY3QsIHRydWUsIHByb2plY3RJZCkpXG4gICAgY29uc3QgYnVpbGRBcnRpZmFjdHMgPSB0YXJnZXQuYnVpbGRBcnRpZmFjdHMubWFwKGFydGlmYWN0ID0+IHZhbGlkYXRlUGVyc2lzdGVkQXJ0aWZhY3QoYXJ0aWZhY3QsIGZhbHNlLCBwcm9qZWN0SWQpKVxuXG4gICAgaWYgKGZpbmRQb3J0YWJsZUFydGlmYWN0UGF0aENvbmZsaWN0KGFydGlmYWN0cy5tYXAoKHtwYXRoOiBhcnRpZmFjdFBhdGh9KSA9PiBhcnRpZmFjdFBhdGgpKSB8fFxuICAgICAgZmluZFBvcnRhYmxlQXJ0aWZhY3RQYXRoQ29uZmxpY3QoYnVpbGRBcnRpZmFjdHMubWFwKCh7cGF0aDogYXJ0aWZhY3RQYXRofSkgPT4gYXJ0aWZhY3RQYXRoKSkpIHtcbiAgICAgIHB1YmxpY2F0aW9uRmFpbHVyZShcIk1BTEZPUk1FRF9HRU5FUkFUSU9OX01BTklGRVNUXCIsIHByb2plY3RJZCxcbiAgICAgICAgXCJHZW5lcmF0aW9uIG1hbmlmZXN0IGNvbnRhaW5zIGNvbGxpZGluZyBhcnRpZmFjdCBwYXRocy5cIilcbiAgICB9XG4gICAgdGFyZ2V0cy5wdXNoKE9iamVjdC5mcmVlemUoe1xuICAgICAgYXJ0aWZhY3RzOiBPYmplY3QuZnJlZXplKC8qKiBAdHlwZSB7aW1wb3J0KFwiLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5HZW5lcmF0aW9uQXJ0aWZhY3RNYW5pZmVzdFtdfSAqLyAoYXJ0aWZhY3RzKSksXG4gICAgICBidWlsZEFydGlmYWN0czogT2JqZWN0LmZyZWV6ZSgvKiogQHR5cGUge2ltcG9ydChcIi4vc2VtYW50aWMvdHlwZXMuanNcIikuR2VuZXJhdGlvbkJ1aWxkQXJ0aWZhY3RNYW5pZmVzdFtdfSAqLyAoYnVpbGRBcnRpZmFjdHMpKSxcbiAgICAgIGlkOiB0YXJnZXRJZCxcbiAgICAgIC4uLih0YXJnZXQubWV0YWRhdGEgPT09IHVuZGVmaW5lZCA/IHt9IDoge21ldGFkYXRhOiBkZWVwRnJlZXplKC8qKiBAdHlwZSB7UmVjb3JkPHN0cmluZywgdW5rbm93bj59ICovICh0YXJnZXQubWV0YWRhdGEpKX0pLFxuICAgICAgcHJvamVjdGlvbnM6IE9iamVjdC5mcmVlemUoe2J1aWxkOiB0YXJnZXQucHJvamVjdGlvbnMuYnVpbGQsIHNvdXJjZTogdGFyZ2V0LnByb2plY3Rpb25zLnNvdXJjZX0pLFxuICAgICAgcm9sZTogLyoqIEB0eXBlIHtpbXBvcnQoXCIuL3NlbWFudGljL3R5cGVzLmpzXCIpLlB1YmxpY2F0aW9uVGFyZ2V0Um9sZX0gKi8gKHRhcmdldC5yb2xlKSxcbiAgICAgIHRhcmdldDogdGFyZ2V0LnRhcmdldFxuICAgIH0pKVxuICB9XG4gIGlmIChmaW5kUG9ydGFibGVBcnRpZmFjdFBhdGhDb25mbGljdChwcm9qZWN0aW9ucykgfHxcbiAgICBmaW5kUG9ydGFibGVBcnRpZmFjdFBhdGhDb25mbGljdChbLi4ucHJvamVjdGlvbnMsIFwibWFuaWZlc3QuanNvblwiXSkpIHtcbiAgICBwdWJsaWNhdGlvbkZhaWx1cmUoXCJNQUxGT1JNRURfR0VORVJBVElPTl9NQU5JRkVTVFwiLCBwcm9qZWN0SWQsXG4gICAgICBcIkdlbmVyYXRpb24gbWFuaWZlc3QgY29udGFpbnMgb3ZlcmxhcHBpbmcgcHJvamVjdGlvbnMuXCIpXG4gIH1cblxuICByZXR1cm4gT2JqZWN0LmZyZWV6ZSh7XG4gICAgZ2VuZXJhdGlvbklkLFxuICAgIHByb2plY3RJZCxcbiAgICBzY2hlbWE6IC8qKiBAdHlwZSB7Y29uc3R9ICovIChcIlNlbWFudGlmb2xkR2VuZXJhdGlvbk1hbmlmZXN0XCIpLFxuICAgIHRhcmdldHM6IE9iamVjdC5mcmVlemUodGFyZ2V0cyksXG4gICAgdmVyc2lvbjogLyoqIEB0eXBlIHtjb25zdH0gKi8gKDEpXG4gIH0pXG59XG5cbi8qKlxuICogVmFsaWRhdGVzIG9uZSBwZXJzaXN0ZWQgYXJ0aWZhY3QgcmVjb3JkLlxuICogQHBhcmFtIHt1bmtub3dufSB2YWx1ZSAtIFJlY29yZCBjYW5kaWRhdGUuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGdlbmVyYXRlZCAtIFdoZXRoZXIgdGhpcyBpcyBhIGdlbmVyYXRlZC1zb3VyY2UgYXJ0aWZhY3QuXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvamVjdElkIC0gUHJvamVjdCBpZGVudGl0eS5cbiAqIEByZXR1cm5zIHtpbXBvcnQoXCIuL3NlbWFudGljL3R5cGVzLmpzXCIpLkdlbmVyYXRpb25BcnRpZmFjdE1hbmlmZXN0IHwgaW1wb3J0KFwiLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5HZW5lcmF0aW9uQnVpbGRBcnRpZmFjdE1hbmlmZXN0fSBGcm96ZW4gcmVjb3JkLlxuICovXG5mdW5jdGlvbiB2YWxpZGF0ZVBlcnNpc3RlZEFydGlmYWN0KHZhbHVlLCBnZW5lcmF0ZWQsIHByb2plY3RJZCkge1xuICBjb25zdCBrZXlzID0gZ2VuZXJhdGVkXG4gICAgPyBbXCJieXRlTGVuZ3RoXCIsIFwiY29udGVudEtpbmRcIiwgXCJoYXNoXCIsIFwibWVkaWFUeXBlXCIsIFwicGF0aFwiLCBcInByb3ZlbmFuY2VcIiwgXCJyb2xlXCJdXG4gICAgOiBbXCJieXRlTGVuZ3RoXCIsIFwiaGFzaFwiLCBcIm1lZGlhVHlwZVwiLCBcInBhdGhcIiwgXCJyb2xlXCJdXG5cbiAgaWYgKCFpc1BsYWluT2JqZWN0KHZhbHVlKSB8fCAhaGFzRXhhY3RLZXlzKHZhbHVlLCBrZXlzKSB8fCAhaXNTYWZlQXJ0aWZhY3RQYXRoKHZhbHVlLnBhdGgpIHx8XG4gICAgdHlwZW9mIHZhbHVlLmJ5dGVMZW5ndGggIT0gXCJudW1iZXJcIiB8fCAhTnVtYmVyLmlzU2FmZUludGVnZXIodmFsdWUuYnl0ZUxlbmd0aCkgfHwgdmFsdWUuYnl0ZUxlbmd0aCA8IDAgfHwgdHlwZW9mIHZhbHVlLm1lZGlhVHlwZSAhPSBcInN0cmluZ1wiIHx8XG4gICAgIW1lZGlhVHlwZVBhdHRlcm4udGVzdCh2YWx1ZS5tZWRpYVR5cGUpIHx8IHR5cGVvZiB2YWx1ZS5yb2xlICE9IFwic3RyaW5nXCIgfHxcbiAgICAhKGdlbmVyYXRlZCA/IFtcImVudHJ5XCIsIFwic291cmNlXCIsIFwibWFuaWZlc3RcIiwgXCJzdXBwb3J0XCIsIFwibWFwcGluZ1wiLCBcInJlc291cmNlXCIsIFwibG9hZGVyXCJdLmluY2x1ZGVzKHZhbHVlLnJvbGUpIDpcbiAgICAgIGJ1aWxkUm9sZVBhdHRlcm4udGVzdCh2YWx1ZS5yb2xlKSkgfHxcbiAgICAoZ2VuZXJhdGVkICYmIHZhbHVlLmNvbnRlbnRLaW5kICE9IFwidGV4dFwiICYmIHZhbHVlLmNvbnRlbnRLaW5kICE9IFwiYmluYXJ5XCIpIHx8XG4gICAgKGdlbmVyYXRlZCAmJiAhaXNQbGFpbk9iamVjdCh2YWx1ZS5wcm92ZW5hbmNlKSkgfHxcbiAgICAhaXNQbGFpbk9iamVjdCh2YWx1ZS5oYXNoKSB8fCAhaGFzRXhhY3RLZXlzKHZhbHVlLmhhc2gsIFtcImFsZ29yaXRobVwiLCBcInZhbHVlXCJdKSB8fCB2YWx1ZS5oYXNoLmFsZ29yaXRobSAhPSBcInNoYTI1NlwiIHx8XG4gICAgdHlwZW9mIHZhbHVlLmhhc2gudmFsdWUgIT0gXCJzdHJpbmdcIiB8fCAhL15bYS1mMC05XXs2NH0kL3UudGVzdCh2YWx1ZS5oYXNoLnZhbHVlKSkge1xuICAgIHB1YmxpY2F0aW9uRmFpbHVyZShcIk1BTEZPUk1FRF9HRU5FUkFUSU9OX01BTklGRVNUXCIsIHByb2plY3RJZCxcbiAgICAgIFwiR2VuZXJhdGlvbiBtYW5pZmVzdCBjb250YWlucyBhbiBpbnZhbGlkIGFydGlmYWN0IHJlY29yZC5cIilcbiAgfVxuXG4gIHJldHVybiBPYmplY3QuZnJlZXplKC8qKiBAdHlwZSB7aW1wb3J0KFwiLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5HZW5lcmF0aW9uQXJ0aWZhY3RNYW5pZmVzdCB8IGltcG9ydChcIi4vc2VtYW50aWMvdHlwZXMuanNcIikuR2VuZXJhdGlvbkJ1aWxkQXJ0aWZhY3RNYW5pZmVzdH0gKi8gKHtcbiAgICBieXRlTGVuZ3RoOiB2YWx1ZS5ieXRlTGVuZ3RoLFxuICAgIC4uLihnZW5lcmF0ZWQgPyB7Y29udGVudEtpbmQ6IHZhbHVlLmNvbnRlbnRLaW5kfSA6IHt9KSxcbiAgICBoYXNoOiBPYmplY3QuZnJlZXplKHthbGdvcml0aG06IC8qKiBAdHlwZSB7Y29uc3R9ICovIChcInNoYTI1NlwiKSwgdmFsdWU6IHZhbHVlLmhhc2gudmFsdWV9KSxcbiAgICBtZWRpYVR5cGU6IHZhbHVlLm1lZGlhVHlwZSxcbiAgICBwYXRoOiB2YWx1ZS5wYXRoLFxuICAgIC4uLihnZW5lcmF0ZWQgPyB7cHJvdmVuYW5jZTogZGVlcEZyZWV6ZSgvKiogQHR5cGUge2ltcG9ydChcIi4vc2VtYW50aWMvdHlwZXMuanNcIikuQXJ0aWZhY3RQcm92ZW5hbmNlfSAqLyAodmFsdWUucHJvdmVuYW5jZSkpfSA6IHt9KSxcbiAgICByb2xlOiB2YWx1ZS5yb2xlXG4gIH0pKVxufVxuXG4vKipcbiAqIENvbnN0cnVjdHMgYSBmcm96ZW4gcmVzb2x2ZWQtZ2VuZXJhdGlvbiByZXN1bHQuXG4gKiBAcGFyYW0ge3N0cmluZ30gcHVibGljYXRpb25Sb290IC0gUHVibGljYXRpb24gcm9vdC5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5HZW5lcmF0aW9uTWFuaWZlc3R9IG1hbmlmZXN0IC0gVmVyaWZpZWQgbWFuaWZlc3QuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGNsZWFudXBQZW5kaW5nIC0gV2hldGhlciBjbGVhbnVwIHJlbWFpbnMuXG4gKiBAcmV0dXJucyB7aW1wb3J0KFwiLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5QdWJsaXNoZWRHZW5lcmF0aW9ufSBGcm96ZW4gcmVzdWx0LlxuICovXG5mdW5jdGlvbiBwdWJsaXNoZWRHZW5lcmF0aW9uKHB1YmxpY2F0aW9uUm9vdCwgbWFuaWZlc3QsIGNsZWFudXBQZW5kaW5nKSB7XG4gIGNvbnN0IGdlbmVyYXRpb25QYXRoID0gcGF0aC5qb2luKHB1YmxpY2F0aW9uUm9vdCwgZ2VuZXJhdGlvbnNOYW1lLCBtYW5pZmVzdC5nZW5lcmF0aW9uSWQpXG4gIGNvbnN0IHRhcmdldHMgPSBtYW5pZmVzdC50YXJnZXRzLm1hcCh0YXJnZXQgPT4gT2JqZWN0LmZyZWV6ZSh7XG4gICAgYnVpbGRQYXRoOiBwYXRoLmpvaW4oZ2VuZXJhdGlvblBhdGgsIHRhcmdldC5wcm9qZWN0aW9ucy5idWlsZCksXG4gICAgaWQ6IHRhcmdldC5pZCxcbiAgICByb2xlOiB0YXJnZXQucm9sZSxcbiAgICBzb3VyY2VQYXRoOiBwYXRoLmpvaW4oZ2VuZXJhdGlvblBhdGgsIHRhcmdldC5wcm9qZWN0aW9ucy5zb3VyY2UpXG4gIH0pKVxuXG4gIHJldHVybiBPYmplY3QuZnJlZXplKHtcbiAgICBjbGVhbnVwUGVuZGluZyxcbiAgICBnZW5lcmF0aW9uSWQ6IG1hbmlmZXN0LmdlbmVyYXRpb25JZCxcbiAgICBnZW5lcmF0aW9uUGF0aCxcbiAgICBtYW5pZmVzdCxcbiAgICBtYW5pZmVzdFBhdGg6IHBhdGguam9pbihnZW5lcmF0aW9uUGF0aCwgXCJtYW5pZmVzdC5qc29uXCIpLFxuICAgIHRhcmdldHM6IE9iamVjdC5mcmVlemUodGFyZ2V0cylcbiAgfSlcbn1cblxuLyoqXG4gKiBQcm9iZXMgdGhlIGV4YWN0IHNhbWUtZGlyZWN0b3J5IHJlZ3VsYXItZmlsZSByZXBsYWNlbWVudCBwcmltaXRpdmUgdXNlZCBieSB0aGUgYWN0aXZlIHBvaW50ZXIuXG4gKiBAcGFyYW0ge3N0cmluZ30gcHVibGljYXRpb25Sb290IC0gUHVibGljYXRpb24gcm9vdC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBwcm9qZWN0SWQgLSBQcm9qZWN0IGlkZW50aXR5LlxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IENvbXBsZXRpb24uXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHZlcmlmeUF0b21pY1JlcGxhY2VtZW50KHB1YmxpY2F0aW9uUm9vdCwgcHJvamVjdElkKSB7XG4gIGNvbnN0IGlkZW50aXR5ID0gcmFuZG9tVVVJRCgpXG4gIGNvbnN0IHNvdXJjZSA9IHBhdGguam9pbihwdWJsaWNhdGlvblJvb3QsIGAuc2VtYW50aWZvbGQtYXRvbWljLSR7aWRlbnRpdHl9LnNvdXJjZWApXG4gIGNvbnN0IGRlc3RpbmF0aW9uID0gcGF0aC5qb2luKHB1YmxpY2F0aW9uUm9vdCwgYC5zZW1hbnRpZm9sZC1hdG9taWMtJHtpZGVudGl0eX0uZGVzdGluYXRpb25gKVxuICBjb25zdCBleHBlY3RlZCA9IEJ1ZmZlci5mcm9tKFwiY2FuZGlkYXRlXFxuXCIpXG4gIGxldCBzb3VyY2VDcmVhdGVkID0gZmFsc2VcbiAgbGV0IGRlc3RpbmF0aW9uQ3JlYXRlZCA9IGZhbHNlXG5cbiAgdHJ5IHtcbiAgICBhd2FpdCB3cml0ZVN5bmNlZEZpbGUoc291cmNlLCBCdWZmZXIuZnJvbShcImNhbmRpZGF0ZVxcblwiKSwgXCJ3eFwiKVxuICAgIHNvdXJjZUNyZWF0ZWQgPSB0cnVlXG4gICAgYXdhaXQgd3JpdGVTeW5jZWRGaWxlKGRlc3RpbmF0aW9uLCBCdWZmZXIuZnJvbShcInByZXZpb3VzXFxuXCIpLCBcInd4XCIpXG4gICAgZGVzdGluYXRpb25DcmVhdGVkID0gdHJ1ZVxuICAgIGF3YWl0IHJlbmFtZShzb3VyY2UsIGRlc3RpbmF0aW9uKVxuICAgIHNvdXJjZUNyZWF0ZWQgPSBmYWxzZVxuICAgIGF3YWl0IHN5bmNEaXJlY3RvcnkocHVibGljYXRpb25Sb290KVxuICAgIGNvbnN0IGRlc3RpbmF0aW9uU3RhdHVzID0gYXdhaXQgbHN0YXQoZGVzdGluYXRpb24pXG4gICAgY29uc3QgcmVwbGFjZWQgPSBhd2FpdCByZWFkRmlsZShkZXN0aW5hdGlvbilcblxuICAgIGlmICghZGVzdGluYXRpb25TdGF0dXMuaXNGaWxlKCkgfHwgZGVzdGluYXRpb25TdGF0dXMuaXNTeW1ib2xpY0xpbmsoKSB8fCAhcmVwbGFjZWQuZXF1YWxzKGV4cGVjdGVkKSkge1xuICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiUFVCTElDQVRJT05fQVRPTUlDX1JFUExBQ0VfVU5TVVBQT1JURURcIiwgcHJvamVjdElkLFxuICAgICAgICBcIkZpbGVzeXN0ZW0gZGlkIG5vdCBwcm92aWRlIHNhbWUtZGlyZWN0b3J5IHJlZ3VsYXItZmlsZSByZXBsYWNlbWVudC5cIilcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGxzdGF0KHNvdXJjZSlcbiAgICAgIHB1YmxpY2F0aW9uRmFpbHVyZShcIlBVQkxJQ0FUSU9OX0FUT01JQ19SRVBMQUNFX1VOU1VQUE9SVEVEXCIsIHByb2plY3RJZCxcbiAgICAgICAgXCJGaWxlc3lzdGVtIGRpZCBub3QgcmVtb3ZlIHRoZSByZXBsYWNlZCB0ZW1wb3JhcnkgbmFtZSBhdG9taWNhbGx5LlwiKVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBpZiAoIWlzRXJyb3JDb2RlKGVycm9yLCBcIkVOT0VOVFwiKSkgdGhyb3cgZXJyb3JcbiAgICB9XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgaWYgKGVycm9yIGluc3RhbmNlb2YgU2VtYW50aWZvbGREaWFnbm9zdGljKSB0aHJvdyBlcnJvclxuICAgIHB1YmxpY2F0aW9uRmFpbHVyZShcIlBVQkxJQ0FUSU9OX0FUT01JQ19SRVBMQUNFX1VOU1VQUE9SVEVEXCIsIHByb2plY3RJZCxcbiAgICAgIFwiRmlsZXN5c3RlbSBkaWQgbm90IHByb3ZpZGUgc2FtZS1kaXJlY3RvcnkgcmVndWxhci1maWxlIHJlcGxhY2VtZW50LlwiLCBlcnJvcilcbiAgfSBmaW5hbGx5IHtcbiAgICBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoW1xuICAgICAgLi4uKHNvdXJjZUNyZWF0ZWQgPyBbcm0oc291cmNlLCB7Zm9yY2U6IHRydWV9KV0gOiBbXSksXG4gICAgICAuLi4oZGVzdGluYXRpb25DcmVhdGVkID8gW3JtKGRlc3RpbmF0aW9uLCB7Zm9yY2U6IHRydWV9KV0gOiBbXSlcbiAgICBdKVxuICB9XG59XG5cbi8qKlxuICogV3JpdGVzIGFuZCBzeW5jaHJvbml6ZXMgb25lIG5ld2x5IG93bmVkIGZpbGUuXG4gKiBAcGFyYW0ge3N0cmluZ30gZmlsZW5hbWUgLSBFeGFjdCBmaWxlbmFtZS5cbiAqIEBwYXJhbSB7VWludDhBcnJheX0gYnl0ZXMgLSBFeGFjdCBieXRlcy5cbiAqIEBwYXJhbSB7XCJ3eFwifSBmbGFnIC0gRXhjbHVzaXZlIGNyZWF0aW9uIG1vZGUuXG4gKiBAcGFyYW0geygpID0+IHZvaWR9IFtvbkNyZWF0ZWRdIC0gQ2FsbGVkIGltbWVkaWF0ZWx5IGFmdGVyIGV4Y2x1c2l2ZSBjcmVhdGlvbiBzdWNjZWVkcy5cbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBDb21wbGV0aW9uLlxuICovXG5hc3luYyBmdW5jdGlvbiB3cml0ZVN5bmNlZEZpbGUoZmlsZW5hbWUsIGJ5dGVzLCBmbGFnLCBvbkNyZWF0ZWQpIHtcbiAgY29uc3QgaGFuZGxlID0gYXdhaXQgb3BlbihmaWxlbmFtZSwgZmxhZywgMG82MDApXG5cbiAgb25DcmVhdGVkPy4oKVxuICAvKiogQHR5cGUge3Vua25vd259ICovXG4gIGxldCBmYWlsdXJlXG5cbiAgdHJ5IHtcbiAgICBhd2FpdCBoYW5kbGUud3JpdGVGaWxlKGJ5dGVzKVxuICAgIGF3YWl0IGhhbmRsZS5zeW5jKClcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBmYWlsdXJlID0gZXJyb3JcbiAgfSBmaW5hbGx5IHtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgaGFuZGxlLmNsb3NlKClcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgaWYgKGZhaWx1cmUgPT09IHVuZGVmaW5lZCkgZmFpbHVyZSA9IGVycm9yXG4gICAgfVxuICB9XG4gIGlmIChmYWlsdXJlICE9PSB1bmRlZmluZWQpIHtcbiAgICBhd2FpdCBybShmaWxlbmFtZSwge2ZvcmNlOiB0cnVlfSkuY2F0Y2goKCkgPT4ge30pXG4gICAgdGhyb3cgZmFpbHVyZVxuICB9XG59XG5cbi8qKlxuICogUmVhZHMgYW5kIHN5bmNocm9uaXplcyBvbmUgcmVndWxhciBub24tc3ltbGluayBmaWxlLlxuICogQHBhcmFtIHtzdHJpbmd9IGZpbGVuYW1lIC0gRXhhY3QgZmlsZW5hbWUuXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvamVjdElkIC0gUHJvamVjdCBpZGVudGl0eS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBjb2RlIC0gRmFpbHVyZSBjb2RlLlxuICogQHBhcmFtIHtzdHJpbmd9IG1lc3NhZ2UgLSBTdGFibGUgZmFpbHVyZSBkZXRhaWwuXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxCdWZmZXI+fSBFeGFjdCBieXRlcy5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gcmVhZEFuZFN5bmNSZWd1bGFyRmlsZShmaWxlbmFtZSwgcHJvamVjdElkLCBjb2RlLCBtZXNzYWdlKSB7XG4gIHRyeSB7XG4gICAgY29uc3Qgc3RhdHVzID0gYXdhaXQgbHN0YXQoZmlsZW5hbWUpXG5cbiAgICBpZiAoIXN0YXR1cy5pc0ZpbGUoKSB8fCBzdGF0dXMuaXNTeW1ib2xpY0xpbmsoKSkgcHVibGljYXRpb25GYWlsdXJlKGNvZGUsIHByb2plY3RJZCwgbWVzc2FnZSlcbiAgICBhc3NlcnRSZWd1bGFyRmlsZUltbXV0YWJpbGl0eShzdGF0dXMsIG5ldyBTZXQoKSwgcHJvamVjdElkKVxuICAgIGNvbnN0IGhhbmRsZSA9IGF3YWl0IG9wZW4oZmlsZW5hbWUsIGNvbnN0YW50cy5PX1JET05MWSlcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCBieXRlcyA9IGF3YWl0IGhhbmRsZS5yZWFkRmlsZSgpXG5cbiAgICAgIGF3YWl0IGhhbmRsZS5zeW5jKClcblxuICAgICAgcmV0dXJuIGJ5dGVzXG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIGF3YWl0IGhhbmRsZS5jbG9zZSgpXG4gICAgfVxuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIFNlbWFudGlmb2xkRGlhZ25vc3RpYykgdGhyb3cgZXJyb3JcbiAgICBwdWJsaWNhdGlvbkZhaWx1cmUoY29kZSwgcHJvamVjdElkLCBtZXNzYWdlLCBlcnJvcilcbiAgfVxufVxuXG4vKipcbiAqIExpc3RzIGV2ZXJ5IHJlZ3VsYXIgZmlsZSBiZW5lYXRoIG9uZSBwcm9qZWN0aW9uIGFuZCByZWplY3RzIHN5bWxpbmtzIG9yIHNwZWNpYWwgbm9kZXMuXG4gKiBAcGFyYW0ge3N0cmluZ30gZGlyZWN0b3J5IC0gUHJvamVjdGlvbiByb290LlxuICogQHBhcmFtIHtzdHJpbmd9IHByb2plY3RJZCAtIFByb2plY3QgaWRlbnRpdHkuXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmdbXT59IFNvcnRlZCByZWxhdGl2ZSBQT1NJWCBwYXRocy5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gbGlzdFJlZ3VsYXJGaWxlcyhkaXJlY3RvcnksIHByb2plY3RJZCkge1xuICAvKiogQHR5cGUge3N0cmluZ1tdfSAqL1xuICBjb25zdCBmaWxlcyA9IFtdXG4gIGNvbnN0IGlkZW50aXRpZXMgPSBuZXcgU2V0KClcblxuICB0cnkge1xuICAgIGF3YWl0IHZpc2l0KGRpcmVjdG9yeSwgXCJcIilcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBTZW1hbnRpZm9sZERpYWdub3N0aWMpIHRocm93IGVycm9yXG4gICAgcHVibGljYXRpb25GYWlsdXJlKFwiUFVCTElDQVRJT05fR0VORVJBVElPTl9WRVJJRklDQVRJT05fRkFJTEVEXCIsIHByb2plY3RJZCxcbiAgICAgIFwiSW1tdXRhYmxlIGdlbmVyYXRpb24gZmlsZXN5c3RlbSBpbnZlbnRvcnkgY291bGQgbm90IGJlIHZlcmlmaWVkLlwiLCBlcnJvcilcbiAgfVxuXG4gIHJldHVybiBmaWxlcy5zb3J0KGNvbXBhcmVTdHJpbmdzKVxuXG4gIC8qKlxuICAgKiBWaXNpdHMgb25lIG93bmVkIGRpcmVjdG9yeS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGN1cnJlbnQgLSBFeGFjdCBkaXJlY3RvcnkuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSByZWxhdGl2ZSAtIFByb2plY3Rpb24tcmVsYXRpdmUgcGF0aC5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IENvbXBsZXRpb24uXG4gICAqL1xuICBhc3luYyBmdW5jdGlvbiB2aXNpdChjdXJyZW50LCByZWxhdGl2ZSkge1xuICAgIGF3YWl0IGFzc2VydFJlYWxJbnZlbnRvcnlEaXJlY3RvcnkoY3VycmVudCwgcHJvamVjdElkKVxuICAgIGNvbnN0IGVudHJpZXMgPSBhd2FpdCByZWFkZGlyKGN1cnJlbnQpXG5cbiAgICBlbnRyaWVzLnNvcnQoY29tcGFyZVN0cmluZ3MpXG4gICAgZm9yIChjb25zdCBlbnRyeSBvZiBlbnRyaWVzKSB7XG4gICAgICBjb25zdCBjaGlsZFJlbGF0aXZlID0gcmVsYXRpdmUubGVuZ3RoID09IDAgPyBlbnRyeSA6IGAke3JlbGF0aXZlfS8ke2VudHJ5fWBcblxuICAgICAgaWYgKCFpc1NhZmVBcnRpZmFjdFBhdGgoY2hpbGRSZWxhdGl2ZSkpIHtcbiAgICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiSU5WQUxJRF9QVUJMSUNBVElPTl9QUk9KRUNUSU9OXCIsIHByb2plY3RJZCxcbiAgICAgICAgICBcIlZhbGlkYXRvciBvdXRwdXQgY29udGFpbnMgYSBub24tY2Fub25pY2FsIHJlbGF0aXZlIHBhdGguXCIpXG4gICAgICB9XG4gICAgICBjb25zdCBjaGlsZCA9IHBhdGguam9pbihjdXJyZW50LCBlbnRyeSlcbiAgICAgIGNvbnN0IHN0YXR1cyA9IGF3YWl0IGxzdGF0KGNoaWxkKVxuXG4gICAgICBpZiAoc3RhdHVzLmlzU3ltYm9saWNMaW5rKCkpIHtcbiAgICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiUFVCTElDQVRJT05fU1lNTElOS19UUkFWRVJTQUxcIiwgcHJvamVjdElkLFxuICAgICAgICAgIFwiQ2FuZGlkYXRlIGdlbmVyYXRpb24gY29udGFpbnMgYSBzeW1ib2xpYyBsaW5rLlwiKVxuICAgICAgfVxuICAgICAgaWYgKHN0YXR1cy5pc0RpcmVjdG9yeSgpKSBhd2FpdCB2aXNpdChjaGlsZCwgY2hpbGRSZWxhdGl2ZSlcbiAgICAgIGVsc2UgaWYgKHN0YXR1cy5pc0ZpbGUoKSkge1xuICAgICAgICBhc3NlcnRSZWd1bGFyRmlsZUltbXV0YWJpbGl0eShzdGF0dXMsIGlkZW50aXRpZXMsIHByb2plY3RJZClcbiAgICAgICAgZmlsZXMucHVzaChjaGlsZFJlbGF0aXZlKVxuICAgICAgfSBlbHNlIHB1YmxpY2F0aW9uRmFpbHVyZShcIlBVQkxJQ0FUSU9OX0dFTkVSQVRJT05fSU5WRU5UT1JZX01JU01BVENIXCIsIHByb2plY3RJZCxcbiAgICAgICAgXCJJbW11dGFibGUgZ2VuZXJhdGlvbiBjb250YWlucyBhbiB1bmRlY2xhcmVkIGZpbGVzeXN0ZW0gZW50cnkuXCIpXG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogVmVyaWZpZXMgdGhhdCB0aGUgbWFuaWZlc3QgZGVzY3JpYmVzIGV2ZXJ5IGRpcmVjdG9yeSBhbmQgcmVndWxhciBmaWxlIGluIHRoZSBpbW11dGFibGUgZ2VuZXJhdGlvbi5cbiAqIEBwYXJhbSB7c3RyaW5nfSBnZW5lcmF0aW9uUGF0aCAtIEV4YWN0IGdlbmVyYXRpb24gcm9vdC5cbiAqIEBwYXJhbSB7aW1wb3J0KFwiLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5HZW5lcmF0aW9uTWFuaWZlc3R9IG1hbmlmZXN0IC0gVmVyaWZpZWQgbWFuaWZlc3QuXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvamVjdElkIC0gUHJvamVjdCBpZGVudGl0eS5cbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBDb21wbGV0aW9uLlxuICovXG5hc3luYyBmdW5jdGlvbiB2ZXJpZnlHZW5lcmF0aW9uSW52ZW50b3J5KGdlbmVyYXRpb25QYXRoLCBtYW5pZmVzdCwgcHJvamVjdElkKSB7XG4gIGNvbnN0IGV4cGVjdGVkRmlsZXMgPSBuZXcgU2V0KFtcIm1hbmlmZXN0Lmpzb25cIl0pXG4gIGNvbnN0IGV4cGVjdGVkRGlyZWN0b3JpZXMgPSBuZXcgU2V0KClcblxuICBmb3IgKGNvbnN0IHRhcmdldCBvZiBtYW5pZmVzdC50YXJnZXRzKSB7XG4gICAgYWRkRXhwZWN0ZWREaXJlY3RvcnkodGFyZ2V0LnByb2plY3Rpb25zLnNvdXJjZSlcbiAgICBhZGRFeHBlY3RlZERpcmVjdG9yeSh0YXJnZXQucHJvamVjdGlvbnMuYnVpbGQpXG4gICAgZm9yIChjb25zdCBhcnRpZmFjdCBvZiB0YXJnZXQuYXJ0aWZhY3RzKSB7XG4gICAgICBhZGRFeHBlY3RlZEZpbGUoYCR7dGFyZ2V0LnByb2plY3Rpb25zLnNvdXJjZX0vJHthcnRpZmFjdC5wYXRofWApXG4gICAgfVxuICAgIGZvciAoY29uc3QgYXJ0aWZhY3Qgb2YgdGFyZ2V0LmJ1aWxkQXJ0aWZhY3RzKSB7XG4gICAgICBhZGRFeHBlY3RlZEZpbGUoYCR7dGFyZ2V0LnByb2plY3Rpb25zLmJ1aWxkfS8ke2FydGlmYWN0LnBhdGh9YClcbiAgICB9XG4gIH1cbiAgLyoqIEB0eXBlIHtTZXQ8c3RyaW5nPn0gKi9cbiAgY29uc3Qgb2JzZXJ2ZWRGaWxlcyA9IG5ldyBTZXQoKVxuICAvKiogQHR5cGUge1NldDxzdHJpbmc+fSAqL1xuICBjb25zdCBvYnNlcnZlZERpcmVjdG9yaWVzID0gbmV3IFNldCgpXG4gIGNvbnN0IGlkZW50aXRpZXMgPSBuZXcgU2V0KClcblxuICB0cnkge1xuICAgIGF3YWl0IHZpc2l0KGdlbmVyYXRpb25QYXRoLCBcIlwiKVxuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIFNlbWFudGlmb2xkRGlhZ25vc3RpYykgdGhyb3cgZXJyb3JcbiAgICBwdWJsaWNhdGlvbkZhaWx1cmUoXCJQVUJMSUNBVElPTl9HRU5FUkFUSU9OX1ZFUklGSUNBVElPTl9GQUlMRURcIiwgcHJvamVjdElkLFxuICAgICAgXCJJbW11dGFibGUgZ2VuZXJhdGlvbiBmaWxlc3lzdGVtIGludmVudG9yeSBjb3VsZCBub3QgYmUgdmVyaWZpZWQuXCIsIGVycm9yKVxuICB9XG4gIGlmICghc2FtZVN0cmluZ1NldChleHBlY3RlZEZpbGVzLCBvYnNlcnZlZEZpbGVzKSB8fCAhc2FtZVN0cmluZ1NldChleHBlY3RlZERpcmVjdG9yaWVzLCBvYnNlcnZlZERpcmVjdG9yaWVzKSkge1xuICAgIHB1YmxpY2F0aW9uRmFpbHVyZShcIlBVQkxJQ0FUSU9OX0dFTkVSQVRJT05fSU5WRU5UT1JZX01JU01BVENIXCIsIHByb2plY3RJZCxcbiAgICAgIFwiSW1tdXRhYmxlIGdlbmVyYXRpb24gY29udGFpbnMgYW4gdW5kZWNsYXJlZCBmaWxlc3lzdGVtIGVudHJ5LlwiKVxuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgb25lIGV4cGVjdGVkIGRpcmVjdG9yeSBhbmQgZWFjaCBnZW5lcmF0aW9uLXJlbGF0aXZlIHBhcmVudC5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHJlbGF0aXZlIC0gUE9TSVgtc3R5bGUgZ2VuZXJhdGlvbi1yZWxhdGl2ZSBkaXJlY3RvcnkuXG4gICAqIEByZXR1cm5zIHt2b2lkfVxuICAgKi9cbiAgZnVuY3Rpb24gYWRkRXhwZWN0ZWREaXJlY3RvcnkocmVsYXRpdmUpIHtcbiAgICBjb25zdCBwYXJ0cyA9IHJlbGF0aXZlLnNwbGl0KFwiL1wiKVxuXG4gICAgZm9yIChsZXQgaW5kZXggPSAxOyBpbmRleCA8PSBwYXJ0cy5sZW5ndGg7IGluZGV4ICs9IDEpIHtcbiAgICAgIGV4cGVjdGVkRGlyZWN0b3JpZXMuYWRkKHBhcnRzLnNsaWNlKDAsIGluZGV4KS5qb2luKFwiL1wiKSlcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBvbmUgZXhwZWN0ZWQgcmVndWxhciBmaWxlIGFuZCBpdHMgcGFyZW50IGRpcmVjdG9yaWVzLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gcmVsYXRpdmUgLSBQT1NJWC1zdHlsZSBnZW5lcmF0aW9uLXJlbGF0aXZlIGZpbGVuYW1lLlxuICAgKiBAcmV0dXJucyB7dm9pZH1cbiAgICovXG4gIGZ1bmN0aW9uIGFkZEV4cGVjdGVkRmlsZShyZWxhdGl2ZSkge1xuICAgIGV4cGVjdGVkRmlsZXMuYWRkKHJlbGF0aXZlKVxuICAgIGNvbnN0IHNlcGFyYXRvciA9IHJlbGF0aXZlLmxhc3RJbmRleE9mKFwiL1wiKVxuXG4gICAgaWYgKHNlcGFyYXRvciA+PSAwKSBhZGRFeHBlY3RlZERpcmVjdG9yeShyZWxhdGl2ZS5zbGljZSgwLCBzZXBhcmF0b3IpKVxuICB9XG5cbiAgLyoqXG4gICAqIFZpc2l0cyBldmVyeSBlbnRyeSBpbiBvbmUgZ2VuZXJhdGlvbiBkaXJlY3Rvcnkgd2l0aG91dCBmb2xsb3dpbmcgbGlua3MuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjdXJyZW50IC0gRXhhY3QgZGlyZWN0b3J5LlxuICAgKiBAcGFyYW0ge3N0cmluZ30gcmVsYXRpdmUgLSBHZW5lcmF0aW9uLXJlbGF0aXZlIGRpcmVjdG9yeS5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IENvbXBsZXRpb24uXG4gICAqL1xuICBhc3luYyBmdW5jdGlvbiB2aXNpdChjdXJyZW50LCByZWxhdGl2ZSkge1xuICAgIGF3YWl0IGFzc2VydFJlYWxJbnZlbnRvcnlEaXJlY3RvcnkoY3VycmVudCwgcHJvamVjdElkKVxuICAgIGNvbnN0IGVudHJpZXMgPSBhd2FpdCByZWFkZGlyKGN1cnJlbnQpXG5cbiAgICBlbnRyaWVzLnNvcnQoY29tcGFyZVN0cmluZ3MpXG4gICAgZm9yIChjb25zdCBlbnRyeSBvZiBlbnRyaWVzKSB7XG4gICAgICBjb25zdCBjaGlsZFJlbGF0aXZlID0gcmVsYXRpdmUubGVuZ3RoID09IDAgPyBlbnRyeSA6IGAke3JlbGF0aXZlfS8ke2VudHJ5fWBcblxuICAgICAgaWYgKCFpc1NhZmVBcnRpZmFjdFBhdGgoY2hpbGRSZWxhdGl2ZSkpIHtcbiAgICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiUFVCTElDQVRJT05fR0VORVJBVElPTl9JTlZFTlRPUllfTUlTTUFUQ0hcIiwgcHJvamVjdElkLFxuICAgICAgICAgIFwiSW1tdXRhYmxlIGdlbmVyYXRpb24gY29udGFpbnMgYW4gdW5kZWNsYXJlZCBmaWxlc3lzdGVtIGVudHJ5LlwiKVxuICAgICAgfVxuICAgICAgY29uc3QgY2hpbGQgPSBwYXRoLmpvaW4oY3VycmVudCwgZW50cnkpXG4gICAgICBjb25zdCBzdGF0dXMgPSBhd2FpdCBsc3RhdChjaGlsZClcblxuICAgICAgaWYgKHN0YXR1cy5pc1N5bWJvbGljTGluaygpKSB7XG4gICAgICAgIHB1YmxpY2F0aW9uRmFpbHVyZShcIlBVQkxJQ0FUSU9OX1NZTUxJTktfVFJBVkVSU0FMXCIsIHByb2plY3RJZCxcbiAgICAgICAgICBcIkNhbmRpZGF0ZSBnZW5lcmF0aW9uIGNvbnRhaW5zIGEgc3ltYm9saWMgbGluay5cIilcbiAgICAgIH1cbiAgICAgIGlmIChzdGF0dXMuaXNEaXJlY3RvcnkoKSkge1xuICAgICAgICBvYnNlcnZlZERpcmVjdG9yaWVzLmFkZChjaGlsZFJlbGF0aXZlKVxuICAgICAgICBhd2FpdCB2aXNpdChjaGlsZCwgY2hpbGRSZWxhdGl2ZSlcbiAgICAgIH0gZWxzZSBpZiAoc3RhdHVzLmlzRmlsZSgpKSB7XG4gICAgICAgIGFzc2VydFJlZ3VsYXJGaWxlSW1tdXRhYmlsaXR5KHN0YXR1cywgaWRlbnRpdGllcywgcHJvamVjdElkKVxuICAgICAgICBvYnNlcnZlZEZpbGVzLmFkZChjaGlsZFJlbGF0aXZlKVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiUFVCTElDQVRJT05fR0VORVJBVElPTl9JTlZFTlRPUllfTUlTTUFUQ0hcIiwgcHJvamVjdElkLFxuICAgICAgICAgIFwiSW1tdXRhYmxlIGdlbmVyYXRpb24gY29udGFpbnMgYW4gdW5kZWNsYXJlZCBmaWxlc3lzdGVtIGVudHJ5LlwiKVxuICAgICAgfVxuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIFZlcmlmaWVzIG9uZSBpbnZlbnRvcnkgdHJhdmVyc2FsIHJvb3Qgd2l0aG91dCBmb2xsb3dpbmcgc3ltYm9saWMgbGlua3MuXG4gKiBAcGFyYW0ge3N0cmluZ30gZGlyZWN0b3J5IC0gRXhhY3QgZGlyZWN0b3J5IGFib3V0IHRvIGJlIHJlYWQuXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvamVjdElkIC0gUHJvamVjdCBpZGVudGl0eS5cbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBDb21wbGV0aW9uLlxuICovXG5hc3luYyBmdW5jdGlvbiBhc3NlcnRSZWFsSW52ZW50b3J5RGlyZWN0b3J5KGRpcmVjdG9yeSwgcHJvamVjdElkKSB7XG4gIGNvbnN0IHN0YXR1cyA9IGF3YWl0IGxzdGF0KGRpcmVjdG9yeSlcblxuICBpZiAoc3RhdHVzLmlzU3ltYm9saWNMaW5rKCkpIHtcbiAgICBwdWJsaWNhdGlvbkZhaWx1cmUoXCJQVUJMSUNBVElPTl9TWU1MSU5LX1RSQVZFUlNBTFwiLCBwcm9qZWN0SWQsXG4gICAgICBcIkNhbmRpZGF0ZSBnZW5lcmF0aW9uIGNvbnRhaW5zIGEgc3ltYm9saWMgbGluay5cIilcbiAgfVxuICBpZiAoIXN0YXR1cy5pc0RpcmVjdG9yeSgpKSB7XG4gICAgcHVibGljYXRpb25GYWlsdXJlKFwiUFVCTElDQVRJT05fR0VORVJBVElPTl9JTlZFTlRPUllfTUlTTUFUQ0hcIiwgcHJvamVjdElkLFxuICAgICAgXCJJbW11dGFibGUgZ2VuZXJhdGlvbiBjb250YWlucyBhbiB1bmRlY2xhcmVkIGZpbGVzeXN0ZW0gZW50cnkuXCIpXG4gIH1cbn1cblxuLyoqXG4gKiBSZWplY3RzIGV4dGVybmFsIGhhcmQgbGlua3MgYW5kIGR1cGxpY2F0ZSBzdGFibGUgZmlsZSBpZGVudGl0aWVzLlxuICogQHBhcmFtIHtpbXBvcnQoXCJub2RlOmZzXCIpLlN0YXRzfSBzdGF0dXMgLSBSZWd1bGFyLWZpbGUgc3RhdHVzLlxuICogQHBhcmFtIHtTZXQ8c3RyaW5nPn0gaWRlbnRpdGllcyAtIFByZXZpb3VzbHkgb2JzZXJ2ZWQgZGV2aWNlL2lub2RlIGlkZW50aXRpZXMuXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvamVjdElkIC0gUHJvamVjdCBpZGVudGl0eS5cbiAqIEByZXR1cm5zIHt2b2lkfVxuICovXG5mdW5jdGlvbiBhc3NlcnRSZWd1bGFyRmlsZUltbXV0YWJpbGl0eShzdGF0dXMsIGlkZW50aXRpZXMsIHByb2plY3RJZCkge1xuICBpZiAoc3RhdHVzLm5saW5rID4gMSkge1xuICAgIHB1YmxpY2F0aW9uRmFpbHVyZShcIlBVQkxJQ0FUSU9OX0hBUkRfTElOS1wiLCBwcm9qZWN0SWQsXG4gICAgICBcIkltbXV0YWJsZSBnZW5lcmF0aW9uIGZpbGVzIG11c3Qgbm90IGhhdmUgZXh0ZXJuYWwgaGFyZCBsaW5rcy5cIilcbiAgfVxuICBjb25zdCBpZGVudGl0eSA9IHN0YWJsZUZpbGVJZGVudGl0eShzdGF0dXMpXG5cbiAgaWYgKGlkZW50aXR5ICE9PSBudWxsKSB7XG4gICAgaWYgKGlkZW50aXRpZXMuaGFzKGlkZW50aXR5KSkge1xuICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiUFVCTElDQVRJT05fSEFSRF9MSU5LXCIsIHByb2plY3RJZCxcbiAgICAgICAgXCJJbW11dGFibGUgZ2VuZXJhdGlvbiBmaWxlcyBtdXN0IGhhdmUgdW5pcXVlIGZpbGVzeXN0ZW0gaWRlbnRpdGllcy5cIilcbiAgICB9XG4gICAgaWRlbnRpdGllcy5hZGQoaWRlbnRpdHkpXG4gIH1cbn1cblxuLyoqXG4gKiBSZXR1cm5zIGEgc3RhYmxlIGRldmljZS9pbm9kZSBpZGVudGl0eSBvbmx5IHdoZXJlIHRoZSBob3N0IHJlcG9ydHMgb25lLlxuICogQHBhcmFtIHtpbXBvcnQoXCJub2RlOmZzXCIpLlN0YXRzfSBzdGF0dXMgLSBGaWxlIHN0YXR1cy5cbiAqIEByZXR1cm5zIHtzdHJpbmcgfCBudWxsfSBJZGVudGl0eSBvciB1bmF2YWlsYWJsZS5cbiAqL1xuZnVuY3Rpb24gc3RhYmxlRmlsZUlkZW50aXR5KHN0YXR1cykge1xuICBpZiAoKHR5cGVvZiBzdGF0dXMuZGV2ICE9IFwibnVtYmVyXCIgJiYgdHlwZW9mIHN0YXR1cy5kZXYgIT0gXCJiaWdpbnRcIikgfHxcbiAgICAodHlwZW9mIHN0YXR1cy5pbm8gIT0gXCJudW1iZXJcIiAmJiB0eXBlb2Ygc3RhdHVzLmlubyAhPSBcImJpZ2ludFwiKSB8fCBzdGF0dXMuaW5vID09IDApIHJldHVybiBudWxsXG5cbiAgcmV0dXJuIGAke1N0cmluZyhzdGF0dXMuZGV2KX06JHtTdHJpbmcoc3RhdHVzLmlubyl9YFxufVxuXG4vKipcbiAqIENvbXBhcmVzIHR3byBzdHJpbmcgc2V0cyBleGFjdGx5LlxuICogQHBhcmFtIHtTZXQ8c3RyaW5nPn0gbGVmdCAtIEZpcnN0IHNldC5cbiAqIEBwYXJhbSB7U2V0PHN0cmluZz59IHJpZ2h0IC0gU2Vjb25kIHNldC5cbiAqIEByZXR1cm5zIHtib29sZWFufSBFcXVhbGl0eS5cbiAqL1xuZnVuY3Rpb24gc2FtZVN0cmluZ1NldChsZWZ0LCByaWdodCkge1xuICByZXR1cm4gbGVmdC5zaXplID09IHJpZ2h0LnNpemUgJiYgWy4uLmxlZnRdLmV2ZXJ5KHZhbHVlID0+IHJpZ2h0Lmhhcyh2YWx1ZSkpXG59XG5cbi8qKlxuICogU3luY2hyb25pemVzIGV2ZXJ5IGRpcmVjdG9yeSBpbiBhIHN0YWdlZCB0cmVlIGZyb20gbGVhdmVzIHRvIHJvb3QuXG4gKiBAcGFyYW0ge3N0cmluZ30gcm9vdCAtIFRyZWUgcm9vdC5cbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBDb21wbGV0aW9uLlxuICovXG5hc3luYyBmdW5jdGlvbiBzeW5jVHJlZURpcmVjdG9yaWVzKHJvb3QpIHtcbiAgY29uc3QgZW50cmllcyA9IGF3YWl0IHJlYWRkaXIocm9vdCwge3dpdGhGaWxlVHlwZXM6IHRydWV9KVxuXG4gIGZvciAoY29uc3QgZW50cnkgb2YgZW50cmllcykge1xuICAgIGlmIChlbnRyeS5pc0RpcmVjdG9yeSgpICYmICFlbnRyeS5pc1N5bWJvbGljTGluaygpKSBhd2FpdCBzeW5jVHJlZURpcmVjdG9yaWVzKHBhdGguam9pbihyb290LCBlbnRyeS5uYW1lKSlcbiAgfVxuICBhd2FpdCBzeW5jRGlyZWN0b3J5KHJvb3QpXG59XG5cbi8qKlxuICogU3luY2hyb25pemVzIG9uZSBkaXJlY3RvcnkgZW50cnkgc2V0LlxuICogQHBhcmFtIHtzdHJpbmd9IGRpcmVjdG9yeSAtIERpcmVjdG9yeSBwYXRoLlxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IENvbXBsZXRpb24uXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHN5bmNEaXJlY3RvcnkoZGlyZWN0b3J5KSB7XG4gIGNvbnN0IGhhbmRsZSA9IGF3YWl0IG9wZW4oZGlyZWN0b3J5LCBjb25zdGFudHMuT19SRE9OTFkpXG5cbiAgdHJ5IHtcbiAgICBhd2FpdCBoYW5kbGUuc3luYygpXG4gIH0gZmluYWxseSB7XG4gICAgYXdhaXQgaGFuZGxlLmNsb3NlKClcbiAgfVxufVxuXG4vKipcbiAqIEVuc3VyZXMgZXZlcnkgZXhpc3RpbmcgcGF0aCBjb21wb25lbnQgaXMgYSByZWFsIGRpcmVjdG9yeSBhbmQgb3B0aW9uYWxseSBjcmVhdGVzIG1pc3NpbmcgY29tcG9uZW50cy5cbiAqIEBwYXJhbSB7c3RyaW5nfSBkaXJlY3RvcnkgLSBDYW5vbmljYWwgYWJzb2x1dGUgZGlyZWN0b3J5LlxuICogQHBhcmFtIHtib29sZWFufSBjcmVhdGUgLSBXaGV0aGVyIG1pc3NpbmcgY29tcG9uZW50cyBtYXkgYmUgY3JlYXRlZC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBwcm9qZWN0SWQgLSBQcm9qZWN0IGlkZW50aXR5LlxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IENvbXBsZXRpb24uXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGVuc3VyZURpcmVjdG9yeVdpdGhvdXRTeW1saW5rcyhkaXJlY3RvcnksIGNyZWF0ZSwgcHJvamVjdElkKSB7XG4gIGNvbnN0IHBhcnNlZCA9IHBhdGgucGFyc2UoZGlyZWN0b3J5KVxuICBjb25zdCByZWxhdGl2ZSA9IGRpcmVjdG9yeS5zbGljZShwYXJzZWQucm9vdC5sZW5ndGgpXG4gIGNvbnN0IHBhcnRzID0gcmVsYXRpdmUuc3BsaXQocGF0aC5zZXApLmZpbHRlcihCb29sZWFuKVxuICBsZXQgY3VycmVudCA9IHBhcnNlZC5yb290XG5cbiAgZm9yIChjb25zdCBwYXJ0IG9mIHBhcnRzKSB7XG4gICAgY3VycmVudCA9IHBhdGguam9pbihjdXJyZW50LCBwYXJ0KVxuICAgIHRyeSB7XG4gICAgICBjb25zdCBzdGF0dXMgPSBhd2FpdCBsc3RhdChjdXJyZW50KVxuXG4gICAgICBpZiAoc3RhdHVzLmlzU3ltYm9saWNMaW5rKCkpIHtcbiAgICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiUFVCTElDQVRJT05fU1lNTElOS19UUkFWRVJTQUxcIiwgcHJvamVjdElkLFxuICAgICAgICAgIFwiT3duZWQgcGF0aCB0cmF2ZXJzYWwgZW5jb3VudGVyZWQgYSBzeW1ib2xpYyBsaW5rLlwiKVxuICAgICAgfVxuICAgICAgaWYgKCFzdGF0dXMuaXNEaXJlY3RvcnkoKSkge1xuICAgICAgICBwdWJsaWNhdGlvbkZhaWx1cmUoXCJJTlZBTElEX1BVQkxJQ0FUSU9OX1JPT1RcIiwgcHJvamVjdElkLFxuICAgICAgICAgIFwiT3duZWQgcm9vdCBwYXRoIGNvbnRhaW5zIGEgbm9uLWRpcmVjdG9yeSBjb21wb25lbnQuXCIpXG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGlmICghaXNFcnJvckNvZGUoZXJyb3IsIFwiRU5PRU5UXCIpKSB7XG4gICAgICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIFNlbWFudGlmb2xkRGlhZ25vc3RpYykgdGhyb3cgZXJyb3JcbiAgICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiSU5WQUxJRF9QVUJMSUNBVElPTl9ST09UXCIsIHByb2plY3RJZCxcbiAgICAgICAgICBcIk93bmVkIHJvb3QgcGF0aCBjb3VsZCBub3QgYmUgdmFsaWRhdGVkLlwiLCBlcnJvcilcbiAgICAgIH1cbiAgICAgIGlmICghY3JlYXRlKSB7XG4gICAgICAgIHB1YmxpY2F0aW9uRmFpbHVyZShcIklOVkFMSURfUFVCTElDQVRJT05fUk9PVFwiLCBwcm9qZWN0SWQsXG4gICAgICAgICAgXCJTb3VyY2Ugcm9vdCBtdXN0IGV4aXN0IGFzIGEgcmVhbCBkaXJlY3RvcnkuXCIsIGVycm9yKVxuICAgICAgfVxuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgbWtkaXIoY3VycmVudCwge21vZGU6IDBvNzAwfSlcbiAgICAgIH0gY2F0Y2ggKG1rZGlyRXJyb3IpIHtcbiAgICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiSU5WQUxJRF9QVUJMSUNBVElPTl9ST09UXCIsIHByb2plY3RJZCxcbiAgICAgICAgICBcIlB1YmxpY2F0aW9uIHJvb3QgY291bGQgbm90IGJlIGNyZWF0ZWQgc2FmZWx5LlwiLCBta2RpckVycm9yKVxuICAgICAgfVxuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIEVuc3VyZXMgb25lIHJlc2VydmVkIHB1Ymxpc2hlciBkaXJlY3RvcnkgaXMgbmVpdGhlciBhIHN5bWxpbmsgbm9yIGFuIHVub3duZWQgZmlsZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBkaXJlY3RvcnkgLSBSZXNlcnZlZCBkaXJlY3RvcnkuXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvamVjdElkIC0gUHJvamVjdCBpZGVudGl0eS5cbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBDb21wbGV0aW9uLlxuICovXG5hc3luYyBmdW5jdGlvbiBlbnN1cmVPd25lZERpcmVjdG9yeShkaXJlY3RvcnksIHByb2plY3RJZCkge1xuICB0cnkge1xuICAgIGF3YWl0IG1rZGlyKGRpcmVjdG9yeSwge21vZGU6IDBvNzAwfSlcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBpZiAoIWlzRXJyb3JDb2RlKGVycm9yLCBcIkVFWElTVFwiKSkge1xuICAgICAgcHVibGljYXRpb25GYWlsdXJlKFwiUFVCTElDQVRJT05fU1RBR0VfV1JJVEVfRkFJTEVEXCIsIHByb2plY3RJZCxcbiAgICAgICAgXCJQdWJsaXNoZXItb3duZWQgZGlyZWN0b3J5IGNvdWxkIG5vdCBiZSBjcmVhdGVkLlwiLCBlcnJvcilcbiAgICB9XG4gIH1cbiAgbGV0IHN0YXR1c1xuXG4gIHRyeSB7XG4gICAgc3RhdHVzID0gYXdhaXQgbHN0YXQoZGlyZWN0b3J5KVxuICB9IGNhdGNoIChlcnJvcikge1xuICAgIHB1YmxpY2F0aW9uRmFpbHVyZShcIlBVQkxJQ0FUSU9OX1NUQUdFX1dSSVRFX0ZBSUxFRFwiLCBwcm9qZWN0SWQsXG4gICAgICBcIlJlc2VydmVkIHB1Ymxpc2hlciBwYXRoIGNvdWxkIG5vdCBiZSBpbnNwZWN0ZWQuXCIsIGVycm9yKVxuICB9XG5cbiAgaWYgKCFzdGF0dXMuaXNEaXJlY3RvcnkoKSB8fCBzdGF0dXMuaXNTeW1ib2xpY0xpbmsoKSkge1xuICAgIHB1YmxpY2F0aW9uRmFpbHVyZShzdGF0dXMuaXNTeW1ib2xpY0xpbmsoKSA/IFwiUFVCTElDQVRJT05fU1lNTElOS19UUkFWRVJTQUxcIiA6IFwiUFVCTElDQVRJT05fVU5PV05FRF9DT05GTElDVFwiLFxuICAgICAgcHJvamVjdElkLCBcIlJlc2VydmVkIHB1Ymxpc2hlciBwYXRoIGlzIG5vdCBhbiBvd25lZCByZWFsIGRpcmVjdG9yeS5cIilcbiAgfVxufVxuXG4vKipcbiAqIEVuc3VyZXMgYW4gb3duZWQgcGF0aCBoYXMgbm8gcHJlLWV4aXN0aW5nIGVudHJ5LlxuICogQHBhcmFtIHtzdHJpbmd9IGZpbGVuYW1lIC0gRXhhY3QgcGF0aC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBjb2RlIC0gRGlhZ25vc3RpYyBjb2RlLlxuICogQHBhcmFtIHtzdHJpbmd9IHByb2plY3RJZCAtIFByb2plY3QgaWRlbnRpdHkuXG4gKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZSAtIFN0YWJsZSBmYWlsdXJlIGRldGFpbC5cbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBDb21wbGV0aW9uLlxuICovXG5hc3luYyBmdW5jdGlvbiBhc3NlcnRBYnNlbnQoZmlsZW5hbWUsIGNvZGUsIHByb2plY3RJZCwgbWVzc2FnZSkge1xuICB0cnkge1xuICAgIGF3YWl0IGxzdGF0KGZpbGVuYW1lKVxuICAgIHB1YmxpY2F0aW9uRmFpbHVyZShjb2RlLCBwcm9qZWN0SWQsIG1lc3NhZ2UpXG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgaWYgKGlzRXJyb3JDb2RlKGVycm9yLCBcIkVOT0VOVFwiKSkgcmV0dXJuXG4gICAgaWYgKGVycm9yIGluc3RhbmNlb2YgU2VtYW50aWZvbGREaWFnbm9zdGljKSB0aHJvdyBlcnJvclxuICAgIHB1YmxpY2F0aW9uRmFpbHVyZShjb2RlLCBwcm9qZWN0SWQsIG1lc3NhZ2UsIGVycm9yKVxuICB9XG59XG5cbi8qKlxuICogUmVzb2x2ZXMgYSB2YWxpZGF0ZWQgcmVsYXRpdmUgcGF0aCB1bmRlciBhbiBvd25lZCByb290IGFuZCByZWplY3RzIGVzY2FwZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSByb290IC0gT3duZWQgcm9vdC5cbiAqIEBwYXJhbSB7c3RyaW5nfSByZWxhdGl2ZSAtIFZhbGlkYXRlZCByZWxhdGl2ZSBQT1NJWCBwYXRoLlxuICogQHBhcmFtIHtzdHJpbmd9IHByb2plY3RJZCAtIFByb2plY3QgaWRlbnRpdHkuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBFeGFjdCBvd25lZCBwYXRoLlxuICovXG5mdW5jdGlvbiBvd25lZFBhdGgocm9vdCwgcmVsYXRpdmUsIHByb2plY3RJZCkge1xuICBjb25zdCByZXNvbHZlZCA9IHBhdGgucmVzb2x2ZShyb290LCAuLi5yZWxhdGl2ZS5zcGxpdChcIi9cIikpXG4gIGNvbnN0IGNoaWxkID0gcGF0aC5yZWxhdGl2ZShyb290LCByZXNvbHZlZClcblxuICBpZiAoY2hpbGQubGVuZ3RoID09IDAgfHwgY2hpbGQgPT0gXCIuLlwiIHx8IGNoaWxkLnN0YXJ0c1dpdGgoYC4uJHtwYXRoLnNlcH1gKSB8fCBwYXRoLmlzQWJzb2x1dGUoY2hpbGQpKSB7XG4gICAgcHVibGljYXRpb25GYWlsdXJlKFwiUFVCTElDQVRJT05fUEFUSF9FU0NBUEVcIiwgcHJvamVjdElkLFxuICAgICAgXCJSZXNvbHZlZCBwdWJsaWNhdGlvbiBwYXRoIGVzY2FwZWQgaXRzIG93bmVkIHJvb3QuXCIpXG4gIH1cblxuICByZXR1cm4gcmVzb2x2ZWRcbn1cblxuLyoqXG4gKiBDaGVja3MgYSBjYW5vbmljYWwgbm9uLXJvb3QgYWJzb2x1dGUgcGF0aCB3aXRob3V0IGZpbGVzeXN0ZW0gYWNjZXNzLlxuICogQHBhcmFtIHt1bmtub3dufSB2YWx1ZSAtIFBhdGggY2FuZGlkYXRlLlxuICogQHJldHVybnMge3ZhbHVlIGlzIHN0cmluZ30gV2hldGhlciB0aGUgcGF0aCBpcyBjYW5vbmljYWwuXG4gKi9cbmZ1bmN0aW9uIGlzQ2Fub25pY2FsQWJzb2x1dGVQYXRoKHZhbHVlKSB7XG4gIHJldHVybiBpc0Nhbm9uaWNhbEFic29sdXRlUGF0aEZvclBhdGgodmFsdWUsIHBhdGgpXG59XG5cbi8qKlxuICogQ2hlY2tzIG9uZSBhYnNvbHV0ZSBwYXRoIHVzaW5nIHRoZSBzdXBwbGllZCBob3N0IHBhdGggc2VtYW50aWNzLlxuICogVGhpcyBoZWxwZXIgaXMgaW50ZW50aW9uYWxseSBub3QgcGFydCBvZiB0aGUgcGFja2FnZSByb290IEFQSS5cbiAqIEBwYXJhbSB7dW5rbm93bn0gdmFsdWUgLSBQYXRoIGNhbmRpZGF0ZS5cbiAqIEBwYXJhbSB7dHlwZW9mIHBhdGgucG9zaXggfCB0eXBlb2YgcGF0aC53aW4zMn0gaG9zdFBhdGggLSBIb3N0LW5hdGl2ZSBwYXRoIGltcGxlbWVudGF0aW9uLlxuICogQHJldHVybnMge3ZhbHVlIGlzIHN0cmluZ30gV2hldGhlciB0aGUgcGF0aCBpcyBjYW5vbmljYWwgZm9yIHRoYXQgaG9zdC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzQ2Fub25pY2FsQWJzb2x1dGVQYXRoRm9yUGF0aCh2YWx1ZSwgaG9zdFBhdGgpIHtcbiAgY29uc3Qgc2VwYXJhdG9yQWxpYXMgPSBob3N0UGF0aC5zZXAgPT0gXCIvXCIgPyBcIlxcXFxcIiA6IFwiL1wiXG5cbiAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PSBcInN0cmluZ1wiICYmIHZhbHVlLmxlbmd0aCA+IDAgJiYgIXZhbHVlLmluY2x1ZGVzKFwiXFwwXCIpICYmICF2YWx1ZS5pbmNsdWRlcyhzZXBhcmF0b3JBbGlhcykgJiZcbiAgICBob3N0UGF0aC5pc0Fic29sdXRlKHZhbHVlKSAmJiB2YWx1ZSAhPSBob3N0UGF0aC5wYXJzZSh2YWx1ZSkucm9vdCAmJiBob3N0UGF0aC5ub3JtYWxpemUodmFsdWUpID09IHZhbHVlICYmXG4gICAgaG9zdFBhdGgucmVzb2x2ZSh2YWx1ZSkgPT0gdmFsdWVcbn1cblxuLyoqXG4gKiBDaGVja3MgY29uc2VydmF0aXZlIHBvcnRhYmxlIG92ZXJsYXAgYmV0d2VlbiBhYnNvbHV0ZSBwYXRocy5cbiAqIEBwYXJhbSB7c3RyaW5nfSBsZWZ0IC0gRmlyc3QgcGF0aC5cbiAqIEBwYXJhbSB7c3RyaW5nfSByaWdodCAtIFNlY29uZCBwYXRoLlxuICogQHJldHVybnMge2Jvb2xlYW59IFdoZXRoZXIgZWl0aGVyIGNvbnRhaW5zIHRoZSBvdGhlci5cbiAqL1xuZnVuY3Rpb24gcGF0aHNPdmVybGFwKGxlZnQsIHJpZ2h0KSB7XG4gIGNvbnN0IGxlZnRLZXkgPSBsZWZ0LnRvTG93ZXJDYXNlKClcbiAgY29uc3QgcmlnaHRLZXkgPSByaWdodC50b0xvd2VyQ2FzZSgpXG5cbiAgcmV0dXJuIGxlZnRLZXkgPT0gcmlnaHRLZXkgfHwgbGVmdEtleS5zdGFydHNXaXRoKGAke3JpZ2h0S2V5fSR7cGF0aC5zZXB9YCkgfHwgcmlnaHRLZXkuc3RhcnRzV2l0aChgJHtsZWZ0S2V5fSR7cGF0aC5zZXB9YClcbn1cblxuLyoqXG4gKiBDaGVja3Mgd2hldGhlciBhIHBhdGggaXMgZXF1YWwgdG8gb3IgbmVzdGVkIGJlbmVhdGggb25lIGNhbm9uaWNhbCByb290LlxuICogQHBhcmFtIHtzdHJpbmd9IHJvb3QgLSBDYW5vbmljYWwgcm9vdC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBjYW5kaWRhdGUgLSBDYW5vbmljYWwgY2FuZGlkYXRlLlxuICogQHJldHVybnMge2Jvb2xlYW59IFdoZXRoZXIgdGhlIGNhbmRpZGF0ZSBpcyB3aXRoaW4gdGhlIHJvb3QuXG4gKi9cbmZ1bmN0aW9uIGlzUGF0aFdpdGhpbihyb290LCBjYW5kaWRhdGUpIHtcbiAgY29uc3QgcmVsYXRpdmUgPSBwYXRoLnJlbGF0aXZlKHJvb3QsIGNhbmRpZGF0ZSlcblxuICByZXR1cm4gcmVsYXRpdmUubGVuZ3RoID09IDAgfHwgKHJlbGF0aXZlICE9IFwiLi5cIiAmJiAhcmVsYXRpdmUuc3RhcnRzV2l0aChgLi4ke3BhdGguc2VwfWApICYmICFwYXRoLmlzQWJzb2x1dGUocmVsYXRpdmUpKVxufVxuXG4vKipcbiAqIENoZWNrcyB3aGV0aGVyIGEgcGF0aCBpcyBzdHJpY3RseSBuZXN0ZWQgYmVuZWF0aCBvbmUgY2Fub25pY2FsIHJvb3QuXG4gKiBAcGFyYW0ge3N0cmluZ30gcm9vdCAtIENhbm9uaWNhbCByb290LlxuICogQHBhcmFtIHtzdHJpbmd9IGNhbmRpZGF0ZSAtIENhbm9uaWNhbCBjYW5kaWRhdGUuXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gV2hldGhlciB0aGUgY2FuZGlkYXRlIGlzIGEgc3RyaWN0IGRlc2NlbmRhbnQuXG4gKi9cbmZ1bmN0aW9uIGlzU3RyaWN0UGF0aERlc2NlbmRhbnQocm9vdCwgY2FuZGlkYXRlKSB7XG4gIHJldHVybiBpc1BhdGhXaXRoaW4ocm9vdCwgY2FuZGlkYXRlKSAmJiBwYXRoLnJlbGF0aXZlKHJvb3QsIGNhbmRpZGF0ZSkubGVuZ3RoID4gMFxufVxuXG4vKipcbiAqIFNlcmlhbGl6ZXMgc3RhYmxlIGdlbmVyYXRlZCBKU09OIHdpdGggb25lIHRyYWlsaW5nIExGLlxuICogQHBhcmFtIHt1bmtub3dufSB2YWx1ZSAtIEpTT04gdmFsdWUuXG4gKiBAcmV0dXJucyB7QnVmZmVyfSBVVEYtOCBieXRlcy5cbiAqL1xuZnVuY3Rpb24gc2VyaWFsaXplSnNvbih2YWx1ZSkge1xuICByZXR1cm4gQnVmZmVyLmZyb20oYCR7SlNPTi5zdHJpbmdpZnkodmFsdWUsIG51bGwsIDIpfVxcbmAsIFwidXRmOFwiKVxufVxuXG4vKipcbiAqIEhhc2hlcyBleGFjdCBieXRlcyB3aXRoIFNIQS0yNTYuXG4gKiBAcGFyYW0ge1VpbnQ4QXJyYXl9IGJ5dGVzIC0gRXhhY3QgYnl0ZXMuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBMb3dlcmNhc2UgaGV4YWRlY2ltYWwgaGFzaC5cbiAqL1xuZnVuY3Rpb24gc2hhMjU2KGJ5dGVzKSB7XG4gIHJldHVybiBjcmVhdGVIYXNoKFwic2hhMjU2XCIpLnVwZGF0ZShieXRlcykuZGlnZXN0KFwiaGV4XCIpXG59XG5cbi8qKlxuICogRGVlcGx5IGZyZWV6ZXMgYSBwYXJzZWQgSlNPTiB2YWx1ZS5cbiAqIEB0ZW1wbGF0ZSBUXG4gKiBAcGFyYW0ge1R9IHZhbHVlIC0gSlNPTiB2YWx1ZS5cbiAqIEByZXR1cm5zIHtUfSBGcm96ZW4gdmFsdWUuXG4gKi9cbmZ1bmN0aW9uIGRlZXBGcmVlemUodmFsdWUpIHtcbiAgaWYgKHR5cGVvZiB2YWx1ZSA9PSBcIm9iamVjdFwiICYmIHZhbHVlICE9IG51bGwpIHtcbiAgICBmb3IgKGNvbnN0IGNoaWxkIG9mIE9iamVjdC52YWx1ZXModmFsdWUpKSBkZWVwRnJlZXplKGNoaWxkKVxuICAgIE9iamVjdC5mcmVlemUodmFsdWUpXG4gIH1cblxuICByZXR1cm4gdmFsdWVcbn1cblxuLyoqXG4gKiBDb21wYXJlcyBkZXRhY2hlZCBKU09OIHZhbHVlcyB3aXRob3V0IGRlcGVuZGluZyBvbiBvYmplY3Qta2V5IG9yZGVyLlxuICogQHBhcmFtIHt1bmtub3dufSBsZWZ0IC0gRmlyc3QgSlNPTiB2YWx1ZS5cbiAqIEBwYXJhbSB7dW5rbm93bn0gcmlnaHQgLSBTZWNvbmQgSlNPTiB2YWx1ZS5cbiAqIEByZXR1cm5zIHtib29sZWFufSBXaGV0aGVyIHRoZSB2YWx1ZXMgYXJlIHN0cnVjdHVyYWxseSBlcXVhbC5cbiAqL1xuZnVuY3Rpb24gc2FtZUpzb25WYWx1ZShsZWZ0LCByaWdodCkge1xuICBpZiAobGVmdCA9PT0gcmlnaHQpIHJldHVybiB0cnVlXG4gIGlmIChBcnJheS5pc0FycmF5KGxlZnQpIHx8IEFycmF5LmlzQXJyYXkocmlnaHQpKSB7XG4gICAgcmV0dXJuIEFycmF5LmlzQXJyYXkobGVmdCkgJiYgQXJyYXkuaXNBcnJheShyaWdodCkgJiYgbGVmdC5sZW5ndGggPT0gcmlnaHQubGVuZ3RoICYmXG4gICAgICBsZWZ0LmV2ZXJ5KChlbnRyeSwgaW5kZXgpID0+IHNhbWVKc29uVmFsdWUoZW50cnksIHJpZ2h0W2luZGV4XSkpXG4gIH1cbiAgaWYgKCFpc1BsYWluT2JqZWN0KGxlZnQpIHx8ICFpc1BsYWluT2JqZWN0KHJpZ2h0KSkgcmV0dXJuIGZhbHNlXG4gIGNvbnN0IGxlZnRLZXlzID0gT2JqZWN0LmtleXMobGVmdClcbiAgY29uc3QgcmlnaHRLZXlzID0gT2JqZWN0LmtleXMocmlnaHQpXG5cbiAgcmV0dXJuIGxlZnRLZXlzLmxlbmd0aCA9PSByaWdodEtleXMubGVuZ3RoICYmXG4gICAgbGVmdEtleXMuZXZlcnkoa2V5ID0+IE9iamVjdC5oYXNPd24ocmlnaHQsIGtleSkgJiYgc2FtZUpzb25WYWx1ZShsZWZ0W2tleV0sIHJpZ2h0W2tleV0pKVxufVxuXG4vKipcbiAqIENoZWNrcyBhbiBhY3RpdmUtcG9pbnRlciB2YWx1ZS5cbiAqIEBwYXJhbSB7dW5rbm93bn0gdmFsdWUgLSBQYXJzZWQgdmFsdWUuXG4gKiBAcmV0dXJucyB7dmFsdWUgaXMgQWN0aXZlUG9pbnRlcn0gV2hldGhlciB0aGUgdmFsdWUgaXMgc3RyaWN0IGFuZCB2ZXJzaW9uZWQuXG4gKi9cbmZ1bmN0aW9uIGlzQWN0aXZlUG9pbnRlcih2YWx1ZSkge1xuICByZXR1cm4gaXNQbGFpbk9iamVjdCh2YWx1ZSkgJiYgaGFzRXhhY3RLZXlzKHZhbHVlLCBbXCJnZW5lcmF0aW9uSWRcIiwgXCJtYW5pZmVzdEhhc2hcIiwgXCJwcm9qZWN0SWRcIiwgXCJzY2hlbWFcIiwgXCJ2ZXJzaW9uXCJdKSAmJlxuICAgIHZhbHVlLnNjaGVtYSA9PSBcIlNlbWFudGlmb2xkQWN0aXZlR2VuZXJhdGlvblwiICYmIHZhbHVlLnZlcnNpb24gPT0gMSAmJlxuICAgIHR5cGVvZiB2YWx1ZS5wcm9qZWN0SWQgPT0gXCJzdHJpbmdcIiAmJiBpZGVudGl0eVBhdHRlcm4udGVzdCh2YWx1ZS5wcm9qZWN0SWQpICYmXG4gICAgdHlwZW9mIHZhbHVlLmdlbmVyYXRpb25JZCA9PSBcInN0cmluZ1wiICYmIGdlbmVyYXRpb25QYXR0ZXJuLnRlc3QodmFsdWUuZ2VuZXJhdGlvbklkKSAmJlxuICAgIHR5cGVvZiB2YWx1ZS5tYW5pZmVzdEhhc2ggPT0gXCJzdHJpbmdcIiAmJiAvXlthLWYwLTldezY0fSQvdS50ZXN0KHZhbHVlLm1hbmlmZXN0SGFzaClcbn1cblxuLyoqXG4gKiBDaGVja3MgYSByZWNvdmVyeS1qb3VybmFsIHZhbHVlLlxuICogQHBhcmFtIHt1bmtub3dufSB2YWx1ZSAtIFBhcnNlZCB2YWx1ZS5cbiAqIEByZXR1cm5zIHt2YWx1ZSBpcyBQdWJsaWNhdGlvbkpvdXJuYWx9IFdoZXRoZXIgdGhlIHZhbHVlIGlzIHN0cmljdCBhbmQgdmVyc2lvbmVkLlxuICovXG5mdW5jdGlvbiBpc1B1YmxpY2F0aW9uSm91cm5hbCh2YWx1ZSkge1xuICByZXR1cm4gaXNQbGFpbk9iamVjdCh2YWx1ZSkgJiYgaGFzRXhhY3RLZXlzKHZhbHVlLCBbXCJnZW5lcmF0aW9uSWRcIiwgXCJwcm9qZWN0SWRcIiwgXCJzY2hlbWFcIiwgXCJ0ZW1wUG9pbnRlclwiLCBcInZlcnNpb25cIl0pICYmXG4gICAgdmFsdWUuc2NoZW1hID09IFwiU2VtYW50aWZvbGRQdWJsaWNhdGlvbkpvdXJuYWxcIiAmJiB2YWx1ZS52ZXJzaW9uID09IDEgJiZcbiAgICB0eXBlb2YgdmFsdWUucHJvamVjdElkID09IFwic3RyaW5nXCIgJiYgaWRlbnRpdHlQYXR0ZXJuLnRlc3QodmFsdWUucHJvamVjdElkKSAmJlxuICAgIHR5cGVvZiB2YWx1ZS5nZW5lcmF0aW9uSWQgPT0gXCJzdHJpbmdcIiAmJiBnZW5lcmF0aW9uUGF0dGVybi50ZXN0KHZhbHVlLmdlbmVyYXRpb25JZCkgJiZcbiAgICB2YWx1ZS50ZW1wUG9pbnRlciA9PSBgLmFjdGl2ZS1nZW5lcmF0aW9uLiR7dmFsdWUuZ2VuZXJhdGlvbklkfS50bXBgXG59XG5cbi8qKlxuICogQ2hlY2tzIGFuIG9yZGluYXJ5IG9iamVjdCB3aXRoIGV4YWN0bHkgdGhlIGV4cGVjdGVkIGVudW1lcmFibGUgc3RyaW5nIGtleXMuXG4gKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsIHVua25vd24+fSB2YWx1ZSAtIE9iamVjdCBjYW5kaWRhdGUuXG4gKiBAcGFyYW0ge3JlYWRvbmx5IHN0cmluZ1tdfSBrZXlzIC0gU29ydGVkIGV4cGVjdGVkIGtleXMuXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gV2hldGhlciBrZXlzIG1hdGNoIGV4YWN0bHkuXG4gKi9cbmZ1bmN0aW9uIGhhc0V4YWN0S2V5cyh2YWx1ZSwga2V5cykge1xuICBjb25zdCBhY3R1YWwgPSBPYmplY3Qua2V5cyh2YWx1ZSkuc29ydChjb21wYXJlU3RyaW5ncylcblxuICByZXR1cm4gYWN0dWFsLmxlbmd0aCA9PSBrZXlzLmxlbmd0aCAmJiBhY3R1YWwuZXZlcnkoKGtleSwgaW5kZXgpID0+IGtleSA9PSBrZXlzW2luZGV4XSlcbn1cblxuLyoqXG4gKiBDaGVja3MgZm9yIGFuIG9yZGluYXJ5IHN0cmluZy1rZXllZCBvYmplY3QuXG4gKiBAcGFyYW0ge3Vua25vd259IHZhbHVlIC0gQ2FuZGlkYXRlIHZhbHVlLlxuICogQHJldHVybnMge3ZhbHVlIGlzIFJlY29yZDxzdHJpbmcsIHVua25vd24+fSBXaGV0aGVyIHRoZSB2YWx1ZSBpcyBwbGFpbi5cbiAqL1xuZnVuY3Rpb24gaXNQbGFpbk9iamVjdCh2YWx1ZSkge1xuICByZXR1cm4gdHlwZW9mIHZhbHVlID09IFwib2JqZWN0XCIgJiYgdmFsdWUgIT0gbnVsbCAmJiAhQXJyYXkuaXNBcnJheSh2YWx1ZSkgJiYgT2JqZWN0LmdldFByb3RvdHlwZU9mKHZhbHVlKSA9PSBPYmplY3QucHJvdG90eXBlXG59XG5cbi8qKlxuICogQ2hlY2tzIGZvciBhIGRlbnNlIG9yZGluYXJ5IGFycmF5LlxuICogQHBhcmFtIHt1bmtub3dufSB2YWx1ZSAtIENhbmRpZGF0ZSB2YWx1ZS5cbiAqIEByZXR1cm5zIHt2YWx1ZSBpcyB1bmtub3duW119IFdoZXRoZXIgdGhlIHZhbHVlIGlzIGRlbnNlLlxuICovXG5mdW5jdGlvbiBpc0RlbnNlQXJyYXkodmFsdWUpIHtcbiAgaWYgKCFBcnJheS5pc0FycmF5KHZhbHVlKSkgcmV0dXJuIGZhbHNlXG4gIGNvbnN0IGluZGV4ZWRLZXlzID0gT2JqZWN0LmtleXModmFsdWUpLmZpbHRlcihrZXkgPT4gL14oPzowfFsxLTldWzAtOV0qKSQvdS50ZXN0KGtleSkpXG5cbiAgcmV0dXJuIGluZGV4ZWRLZXlzLmxlbmd0aCA9PSB2YWx1ZS5sZW5ndGhcbn1cblxuLyoqXG4gKiBDb21wYXJlcyBzdHJpbmdzIGJ5IFVuaWNvZGUgY29kZSB1bml0LlxuICogQHBhcmFtIHtzdHJpbmd9IGxlZnQgLSBGaXJzdCBzdHJpbmcuXG4gKiBAcGFyYW0ge3N0cmluZ30gcmlnaHQgLSBTZWNvbmQgc3RyaW5nLlxuICogQHJldHVybnMge251bWJlcn0gT3JkZXJpbmcuXG4gKi9cbmZ1bmN0aW9uIGNvbXBhcmVTdHJpbmdzKGxlZnQsIHJpZ2h0KSB7XG4gIHJldHVybiBsZWZ0IDwgcmlnaHQgPyAtMSA6IGxlZnQgPiByaWdodCA/IDEgOiAwXG59XG5cbi8qKlxuICogQ2hlY2tzIGEgbmFycm93ZWQgZmlsZXN5c3RlbSBlcnJvciBjb2RlLlxuICogQHBhcmFtIHt1bmtub3dufSBlcnJvciAtIE9wYXF1ZSBlcnJvci5cbiAqIEBwYXJhbSB7c3RyaW5nfSBjb2RlIC0gRXhwZWN0ZWQgY29kZS5cbiAqIEByZXR1cm5zIHtib29sZWFufSBXaGV0aGVyIHRoZSBjb2RlIG1hdGNoZXMuXG4gKi9cbmZ1bmN0aW9uIGlzRXJyb3JDb2RlKGVycm9yLCBjb2RlKSB7XG4gIHJldHVybiBlcnJvciBpbnN0YW5jZW9mIEVycm9yICYmIFwiY29kZVwiIGluIGVycm9yICYmIGVycm9yLmNvZGUgPT0gY29kZVxufVxuXG4vKipcbiAqIFRocm93cyBvbmUgc3RhYmxlIHB1YmxpY2F0aW9uIGRpYWdub3N0aWMgd2l0aG91dCBlbWJlZGRpbmcgaG9zdCBwYXRocyBvciByYXcgZmlsZXN5c3RlbSBtZXNzYWdlcy5cbiAqIEBwYXJhbSB7c3RyaW5nfSBjb2RlIC0gU3RhYmxlIGRpYWdub3N0aWMgY29kZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBwcm9qZWN0SWQgLSBQcm9qZWN0IGlkZW50aXR5LlxuICogQHBhcmFtIHtzdHJpbmd9IG1lc3NhZ2UgLSBTdGFibGUgZGV0YWlsLlxuICogQHBhcmFtIHt1bmtub3dufSBbZXJyb3JdIC0gUHJlc2VydmVkIGNhdXNlLlxuICogQHJldHVybnMge25ldmVyfSBBbHdheXMgdGhyb3dzLlxuICovXG5mdW5jdGlvbiBwdWJsaWNhdGlvbkZhaWx1cmUoY29kZSwgcHJvamVjdElkLCBtZXNzYWdlLCBlcnJvcikge1xuICB0aHJvdyBuZXcgU2VtYW50aWZvbGREaWFnbm9zdGljKHtcbiAgICBjYXVzZTogZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yIDogdW5kZWZpbmVkLFxuICAgIGNvZGUsXG4gICAgbGFuZ3VhZ2U6IHByb2plY3RJZCxcbiAgICBtZXNzYWdlXG4gIH0pXG59XG5cbi8qKlxuICogQHR5cGVkZWYgVmFsaWRhdGVkUHVibGljYXRpb25UYXJnZXRcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBpZCAtIFRhcmdldCBpZGVudGl0eS5cbiAqIEBwcm9wZXJ0eSB7aW1wb3J0KFwiLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5HZW5lcmF0ZWRBcnRpZmFjdFNldH0gYXJ0aWZhY3RTZXQgLSBEZXRhY2hlZCBhcnRpZmFjdCBzZXQuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gc291cmNlUHJvamVjdGlvbiAtIFNvdXJjZSBwcm9qZWN0aW9uLlxuICogQHByb3BlcnR5IHtzdHJpbmd9IGJ1aWxkUHJvamVjdGlvbiAtIEJ1aWxkIHByb2plY3Rpb24uXG4gKiBAcHJvcGVydHkge2ltcG9ydChcIi4vc2VtYW50aWMvdHlwZXMuanNcIikuUHVibGljYXRpb25UYXJnZXRSb2xlfSByb2xlIC0gTGFuZ3VhZ2UtbmV1dHJhbCB0YXJnZXQgcm9sZS5cbiAqIEBwcm9wZXJ0eSB7cmVhZG9ubHkgaW1wb3J0KFwiLi9zZW1hbnRpYy90eXBlcy5qc1wiKS5QdWJsaWNhdGlvblZhbGlkYXRvcltdfSB2YWxpZGF0b3JzIC0gT3JkZXJlZCB2YWxpZGF0b3JzLlxuICovXG5cbi8qKlxuICogQHR5cGVkZWYgQWN0aXZlUG9pbnRlclxuICogQHByb3BlcnR5IHtcIlNlbWFudGlmb2xkQWN0aXZlR2VuZXJhdGlvblwifSBzY2hlbWEgLSBTY2hlbWEgZGlzY3JpbWluYXRvci5cbiAqIEBwcm9wZXJ0eSB7MX0gdmVyc2lvbiAtIFNjaGVtYSB2ZXJzaW9uLlxuICogQHByb3BlcnR5IHtzdHJpbmd9IHByb2plY3RJZCAtIFByb2plY3QgaWRlbnRpdHkuXG4gKiBAcHJvcGVydHkge3N0cmluZ30gZ2VuZXJhdGlvbklkIC0gR2VuZXJhdGlvbiBpZGVudGl0eS5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBtYW5pZmVzdEhhc2ggLSBTSEEtMjU2IGdlbmVyYXRpb24tbWFuaWZlc3QgaGFzaC5cbiAqL1xuXG4vKipcbiAqIEB0eXBlZGVmIFB1YmxpY2F0aW9uSm91cm5hbFxuICogQHByb3BlcnR5IHtcIlNlbWFudGlmb2xkUHVibGljYXRpb25Kb3VybmFsXCJ9IHNjaGVtYSAtIFNjaGVtYSBkaXNjcmltaW5hdG9yLlxuICogQHByb3BlcnR5IHsxfSB2ZXJzaW9uIC0gU2NoZW1hIHZlcnNpb24uXG4gKiBAcHJvcGVydHkge3N0cmluZ30gcHJvamVjdElkIC0gUHJvamVjdCBpZGVudGl0eS5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBnZW5lcmF0aW9uSWQgLSBDYW5kaWRhdGUgZ2VuZXJhdGlvbiBpZGVudGl0eS5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSB0ZW1wUG9pbnRlciAtIE93bmVkIHNpYmxpbmcgdGVtcG9yYXJ5LXBvaW50ZXIgZmlsZW5hbWUuXG4gKi9cbiJdfQ==