@openelement/adapter-vite 0.41.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +87 -0
- package/package.json +87 -0
- package/src/alias-utils.js +39 -0
- package/src/build-context.d.ts +111 -0
- package/src/build-context.js +184 -0
- package/src/build-manifest.d.ts +38 -0
- package/src/build-manifest.js +198 -0
- package/src/build.js +97 -0
- package/src/cli/build-client.d.ts +3 -0
- package/src/cli/build-client.js +292 -0
- package/src/cli/build-ssg.d.ts +40 -0
- package/src/cli/build-ssg.js +377 -0
- package/src/cli/build.d.ts +0 -0
- package/src/cli/build.js +27 -0
- package/src/cli/ssg-render.js +32 -0
- package/src/generated-data-resolver.d.ts +12 -0
- package/src/generated-data-resolver.js +52 -0
- package/src/head-injection.d.ts +31 -0
- package/src/head-injection.js +248 -0
- package/src/index.d.ts +58 -0
- package/src/index.js +52 -0
- package/src/island-transform.js +27 -0
- package/src/nitro-mount.d.ts +24 -0
- package/src/nitro-mount.js +27 -0
- package/src/plugin-mdx.d.ts +7 -0
- package/src/plugin-mdx.js +15 -0
- package/src/plugin.d.ts +22 -0
- package/src/plugin.js +264 -0
- package/src/ssg-package-resolver.js +256 -0
- package/src/subpath-resolver.d.ts +26 -0
- package/src/subpath-resolver.js +153 -0
- package/src/workspace-alias.js +113 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @openelement/adapter-vite - Build Manifest / Observability
|
|
3
|
+
*
|
|
4
|
+
* Scans build output directories after each phase and prints a structured
|
|
5
|
+
* summary table. This gives developers visibility into:
|
|
6
|
+
* - Per-island chunk sizes (Phase 2)
|
|
7
|
+
* - Total JS/CSS bundle budgets (Phase 3)
|
|
8
|
+
* - HTML page counts and compression potential
|
|
9
|
+
* - headExtras injection size
|
|
10
|
+
*
|
|
11
|
+
* Output format: Fixed-width table via console.info (no external dependency).
|
|
12
|
+
*
|
|
13
|
+
* Called by:
|
|
14
|
+
* - cli/build-client.ts (after Phase 2: client chunks ready)
|
|
15
|
+
* - cli/build-ssg.ts (after Phase 3: HTML + post-process complete)
|
|
16
|
+
*/ import { join, resolve } from 'node:path';
|
|
17
|
+
import { existsSync, readdirSync, statSync } from 'node:fs';
|
|
18
|
+
import { createLogger } from '@openelement/core/logger';
|
|
19
|
+
const log = createLogger('ssg');
|
|
20
|
+
/**
|
|
21
|
+
* Format bytes to human-readable string.
|
|
22
|
+
*/ function formatSize(bytes) {
|
|
23
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
24
|
+
if (bytes < 1024 * 10) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
25
|
+
if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;
|
|
26
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Recursively collect all matching files with their sizes.
|
|
30
|
+
*/ function collectFiles(dir, extension, basePath = '') {
|
|
31
|
+
const results = [];
|
|
32
|
+
if (!existsSync(dir)) return results;
|
|
33
|
+
const entries = readdirSync(dir, {
|
|
34
|
+
withFileTypes: true
|
|
35
|
+
});
|
|
36
|
+
for (const entry of entries){
|
|
37
|
+
const fullPath = join(dir, entry.name);
|
|
38
|
+
const relPath = basePath ? `${basePath}/${entry.name}` : entry.name;
|
|
39
|
+
if (entry.isDirectory()) {
|
|
40
|
+
results.push(...collectFiles(fullPath, extension, relPath));
|
|
41
|
+
} else if (entry.name.endsWith(extension)) {
|
|
42
|
+
try {
|
|
43
|
+
const stat = statSync(fullPath);
|
|
44
|
+
results.push({
|
|
45
|
+
name: entry.name,
|
|
46
|
+
path: relPath,
|
|
47
|
+
sizeBytes: stat.size,
|
|
48
|
+
sizeKB: formatSize(stat.size)
|
|
49
|
+
});
|
|
50
|
+
} catch (e) {
|
|
51
|
+
log.warn(`Cannot stat ${relPath}: ${e.message}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return results;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Scan client build output (dist/client/) for island chunks.
|
|
59
|
+
*/ export function scanClientBuild(root, outDir = 'dist') {
|
|
60
|
+
const clientDir = resolve(root, outDir, 'client');
|
|
61
|
+
const islands = [];
|
|
62
|
+
let clientEntry = null;
|
|
63
|
+
let totalJsBytes = 0;
|
|
64
|
+
// Scan islands/ subdirectory (single pass - avoid redundant directory scans)
|
|
65
|
+
const islandsDir = join(clientDir, 'islands');
|
|
66
|
+
if (existsSync(islandsDir)) {
|
|
67
|
+
const files = readdirSync(islandsDir);
|
|
68
|
+
for (const file of files){
|
|
69
|
+
if (!file.endsWith('.js')) continue;
|
|
70
|
+
const fullPath = join(islandsDir, file);
|
|
71
|
+
try {
|
|
72
|
+
const fileStat = statSync(fullPath);
|
|
73
|
+
if (file === 'client.js') {
|
|
74
|
+
// Client entry (shared island upgrade runtime)
|
|
75
|
+
clientEntry = {
|
|
76
|
+
name: 'client.js',
|
|
77
|
+
path: 'islands/client.js',
|
|
78
|
+
sizeBytes: fileStat.size,
|
|
79
|
+
sizeKB: formatSize(fileStat.size)
|
|
80
|
+
};
|
|
81
|
+
} else {
|
|
82
|
+
// Island chunk or shared chunk
|
|
83
|
+
const _isIslandChunk = /^island-(.+?)-[A-Za-z0-9]+\.js$/.test(file);
|
|
84
|
+
islands.push({
|
|
85
|
+
name: file,
|
|
86
|
+
path: `islands/${file}`,
|
|
87
|
+
sizeBytes: fileStat.size,
|
|
88
|
+
sizeKB: formatSize(fileStat.size)
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
totalJsBytes += fileStat.size;
|
|
92
|
+
} catch (e) {
|
|
93
|
+
log.warn(`Cannot stat ${file}: ${e.message}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
islands,
|
|
99
|
+
clientEntry,
|
|
100
|
+
totalJsBytes
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Scan SSG output (dist/*.html) for page information.
|
|
105
|
+
*/ export function scanSSGOutput(root, outDir = 'dist') {
|
|
106
|
+
const distDir = resolve(root, outDir);
|
|
107
|
+
return collectFiles(distDir, '.html');
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Print a formatted build manifest table to console.
|
|
111
|
+
*
|
|
112
|
+
* This is called at the end of each build phase to provide observability
|
|
113
|
+
* into what was produced and how large everything is.
|
|
114
|
+
*/ export function printBuildManifest(options) {
|
|
115
|
+
const { root, outDir = 'dist', phase, headExtras = '' } = options;
|
|
116
|
+
const timestamp = new Date().toISOString();
|
|
117
|
+
// Gather data
|
|
118
|
+
const clientData = scanClientBuild(root, outDir);
|
|
119
|
+
const htmlPages = phase === 3 ? scanSSGOutput(root, outDir) : [];
|
|
120
|
+
const headExtrasSize = new TextEncoder().encode(headExtras).length;
|
|
121
|
+
// Budget thresholds
|
|
122
|
+
const ISLAND_BUDGET_KB = 50; // Warn if single island > 50KB
|
|
123
|
+
const TOTAL_JS_BUDGET_KB = 200; // Warn if total JS > 200KB
|
|
124
|
+
const PAGE_BUDGET_KB = 200; // Advisory only: single uncompressed HTML page budget.
|
|
125
|
+
const warnings = [];
|
|
126
|
+
// Check island budgets
|
|
127
|
+
for (const island of clientData.islands){
|
|
128
|
+
if (island.sizeBytes > ISLAND_BUDGET_KB * 1024) {
|
|
129
|
+
warnings.push(`Warning: ${island.name} (${island.sizeKB}) exceeds ${ISLAND_BUDGET_KB} KB budget`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// Check total JS budget
|
|
133
|
+
if (clientData.totalJsBytes > TOTAL_JS_BUDGET_KB * 1024) {
|
|
134
|
+
warnings.push(`Warning: Total JS (${formatSize(clientData.totalJsBytes)}) exceeds ${TOTAL_JS_BUDGET_KB} KB budget`);
|
|
135
|
+
}
|
|
136
|
+
// Check page sizes
|
|
137
|
+
for (const page of htmlPages){
|
|
138
|
+
if (page.sizeBytes > PAGE_BUDGET_KB * 1024) {
|
|
139
|
+
warnings.push(`Warning: ${page.path} (${page.sizeKB}) exceeds advisory ${PAGE_BUDGET_KB} KB HTML budget - consider compression`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const manifest = {
|
|
143
|
+
phase,
|
|
144
|
+
timestamp,
|
|
145
|
+
islands: clientData.islands,
|
|
146
|
+
clientEntry: clientData.clientEntry,
|
|
147
|
+
htmlPages,
|
|
148
|
+
totalJsBytes: clientData.totalJsBytes,
|
|
149
|
+
totalHtmlBytes: htmlPages.reduce((sum, p)=>sum + p.sizeBytes, 0),
|
|
150
|
+
headExtrasSize,
|
|
151
|
+
warnings
|
|
152
|
+
};
|
|
153
|
+
// Print table using ASCII-only output so build logs remain portable.
|
|
154
|
+
console.info('');
|
|
155
|
+
console.info(`== openElement Build Manifest - Phase ${phase} @ ${timestamp.slice(11, 19)} ==`);
|
|
156
|
+
if (manifest.islands.length > 0 || manifest.clientEntry) {
|
|
157
|
+
console.info('\n Client Islands:');
|
|
158
|
+
console.info(' File Size');
|
|
159
|
+
console.info(' -------------------------- --------');
|
|
160
|
+
for (const island of manifest.islands){
|
|
161
|
+
const displayName = island.name.length > 30 ? island.name.slice(0, 27) + '...' : island.name;
|
|
162
|
+
console.info(` ${displayName.padEnd(26)} ${island.sizeKB.padEnd(8)}`);
|
|
163
|
+
}
|
|
164
|
+
if (manifest.clientEntry) {
|
|
165
|
+
console.info(` ${'client.js (entry)'.padEnd(26)} ${manifest.clientEntry.sizeKB.padEnd(8)}`);
|
|
166
|
+
}
|
|
167
|
+
console.info(' -------------------------- --------');
|
|
168
|
+
console.info(` ${'TOTAL JS'.padEnd(26)} ${formatSize(manifest.totalJsBytes).padEnd(8)}`);
|
|
169
|
+
} else {
|
|
170
|
+
console.info('\n Client Islands: none - zero client JS');
|
|
171
|
+
}
|
|
172
|
+
if (phase === 3 && manifest.htmlPages.length > 0) {
|
|
173
|
+
console.info(`\n HTML Pages (${manifest.htmlPages.length} files, ${formatSize(manifest.totalHtmlBytes)} total):`);
|
|
174
|
+
const maxShow = 15;
|
|
175
|
+
const shown = manifest.htmlPages.slice(0, maxShow);
|
|
176
|
+
for (const page of shown){
|
|
177
|
+
const displayName = page.path.length > 40 ? page.path.slice(0, 37) + '...' : page.path;
|
|
178
|
+
console.info(` - ${displayName} (${page.sizeKB})`);
|
|
179
|
+
}
|
|
180
|
+
if (manifest.htmlPages.length > maxShow) {
|
|
181
|
+
console.info(` ... +${manifest.htmlPages.length - maxShow} more pages`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (manifest.headExtrasSize > 0) {
|
|
185
|
+
console.info(`\n headExtras: ${formatSize(manifest.headExtrasSize)} (${manifest.headExtrasSize} bytes injected)`);
|
|
186
|
+
}
|
|
187
|
+
if (warnings.length > 0) {
|
|
188
|
+
console.info('\n Budget Warnings:');
|
|
189
|
+
for (const w of warnings){
|
|
190
|
+
console.info(` ${w}`);
|
|
191
|
+
}
|
|
192
|
+
} else {
|
|
193
|
+
console.info('\n All artifacts within budget limits');
|
|
194
|
+
}
|
|
195
|
+
console.info('');
|
|
196
|
+
return manifest;
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9vcGVuZWxlbWVudC9vcGVuZWxlbWVudC9wYWNrYWdlcy9hZGFwdGVyLXZpdGUvc3JjL2J1aWxkLW1hbmlmZXN0LnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQG9wZW5lbGVtZW50L2FkYXB0ZXItdml0ZSAtIEJ1aWxkIE1hbmlmZXN0IC8gT2JzZXJ2YWJpbGl0eVxuICpcbiAqIFNjYW5zIGJ1aWxkIG91dHB1dCBkaXJlY3RvcmllcyBhZnRlciBlYWNoIHBoYXNlIGFuZCBwcmludHMgYSBzdHJ1Y3R1cmVkXG4gKiBzdW1tYXJ5IHRhYmxlLiBUaGlzIGdpdmVzIGRldmVsb3BlcnMgdmlzaWJpbGl0eSBpbnRvOlxuICogICAtIFBlci1pc2xhbmQgY2h1bmsgc2l6ZXMgKFBoYXNlIDIpXG4gKiAgIC0gVG90YWwgSlMvQ1NTIGJ1bmRsZSBidWRnZXRzIChQaGFzZSAzKVxuICogICAtIEhUTUwgcGFnZSBjb3VudHMgYW5kIGNvbXByZXNzaW9uIHBvdGVudGlhbFxuICogICAtIGhlYWRFeHRyYXMgaW5qZWN0aW9uIHNpemVcbiAqXG4gKiBPdXRwdXQgZm9ybWF0OiBGaXhlZC13aWR0aCB0YWJsZSB2aWEgY29uc29sZS5pbmZvIChubyBleHRlcm5hbCBkZXBlbmRlbmN5KS5cbiAqXG4gKiBDYWxsZWQgYnk6XG4gKiAgIC0gY2xpL2J1aWxkLWNsaWVudC50cyAoYWZ0ZXIgUGhhc2UgMjogY2xpZW50IGNodW5rcyByZWFkeSlcbiAqICAgLSBjbGkvYnVpbGQtc3NnLnRzICAgIChhZnRlciBQaGFzZSAzOiBIVE1MICsgcG9zdC1wcm9jZXNzIGNvbXBsZXRlKVxuICovXG5cbmltcG9ydCB7IGpvaW4sIHJlc29sdmUgfSBmcm9tICdub2RlOnBhdGgnO1xuaW1wb3J0IHsgZXhpc3RzU3luYywgcmVhZGRpclN5bmMsIHN0YXRTeW5jIH0gZnJvbSAnbm9kZTpmcyc7XG5pbXBvcnQgeyBjcmVhdGVMb2dnZXIgfSBmcm9tICdAb3BlbmVsZW1lbnQvY29yZS9sb2dnZXInO1xuXG5jb25zdCBsb2cgPSBjcmVhdGVMb2dnZXIoJ3NzZycpO1xuXG4vKiogRmlsZSBzaXplIGluZm8gZm9yIGEgc2luZ2xlIGFydGlmYWN0ICovXG5leHBvcnQgaW50ZXJmYWNlIEFydGlmYWN0SW5mbyB7XG4gIG5hbWU6IHN0cmluZztcbiAgcGF0aDogc3RyaW5nO1xuICBzaXplQnl0ZXM6IG51bWJlcjtcbiAgc2l6ZUtCOiBzdHJpbmc7XG59XG5cbi8qKiBGdWxsIGJ1aWxkIG1hbmlmZXN0IHN1bW1hcnkgKi9cbmV4cG9ydCBpbnRlcmZhY2UgQnVpbGRNYW5pZmVzdCB7XG4gIHBoYXNlOiAxIHwgMiB8IDM7XG4gIHRpbWVzdGFtcDogc3RyaW5nO1xuICBpc2xhbmRzOiBBcnRpZmFjdEluZm9bXTtcbiAgY2xpZW50RW50cnk6IEFydGlmYWN0SW5mbyB8IG51bGw7XG4gIGh0bWxQYWdlczogQXJ0aWZhY3RJbmZvW107XG4gIHRvdGFsSnNCeXRlczogbnVtYmVyO1xuICB0b3RhbEh0bWxCeXRlczogbnVtYmVyO1xuICBoZWFkRXh0cmFzU2l6ZTogbnVtYmVyO1xuICAvKiogQnVkZ2V0IHdhcm5pbmdzIChmaWxlcyA+IHRocmVzaG9sZCkgKi9cbiAgd2FybmluZ3M6IHN0cmluZ1tdO1xufVxuXG4vKipcbiAqIEZvcm1hdCBieXRlcyB0byBodW1hbi1yZWFkYWJsZSBzdHJpbmcuXG4gKi9cbmZ1bmN0aW9uIGZvcm1hdFNpemUoYnl0ZXM6IG51bWJlcik6IHN0cmluZyB7XG4gIGlmIChieXRlcyA8IDEwMjQpIHJldHVybiBgJHtieXRlc30gQmA7XG4gIGlmIChieXRlcyA8IDEwMjQgKiAxMCkgcmV0dXJuIGAkeyhieXRlcyAvIDEwMjQpLnRvRml4ZWQoMSl9IEtCYDtcbiAgaWYgKGJ5dGVzIDwgMTAyNCAqIDEwMjQpIHJldHVybiBgJHtNYXRoLnJvdW5kKGJ5dGVzIC8gMTAyNCl9IEtCYDtcbiAgcmV0dXJuIGAkeyhieXRlcyAvICgxMDI0ICogMTAyNCkpLnRvRml4ZWQoMSl9IE1CYDtcbn1cblxuLyoqXG4gKiBSZWN1cnNpdmVseSBjb2xsZWN0IGFsbCBtYXRjaGluZyBmaWxlcyB3aXRoIHRoZWlyIHNpemVzLlxuICovXG5mdW5jdGlvbiBjb2xsZWN0RmlsZXMoXG4gIGRpcjogc3RyaW5nLFxuICBleHRlbnNpb246IHN0cmluZyxcbiAgYmFzZVBhdGggPSAnJyxcbik6IEFydGlmYWN0SW5mb1tdIHtcbiAgY29uc3QgcmVzdWx0czogQXJ0aWZhY3RJbmZvW10gPSBbXTtcbiAgaWYgKCFleGlzdHNTeW5jKGRpcikpIHJldHVybiByZXN1bHRzO1xuXG4gIGNvbnN0IGVudHJpZXMgPSByZWFkZGlyU3luYyhkaXIsIHsgd2l0aEZpbGVUeXBlczogdHJ1ZSB9KTtcbiAgZm9yIChjb25zdCBlbnRyeSBvZiBlbnRyaWVzKSB7XG4gICAgY29uc3QgZnVsbFBhdGggPSBqb2luKGRpciwgZW50cnkubmFtZSk7XG4gICAgY29uc3QgcmVsUGF0aCA9IGJhc2VQYXRoID8gYCR7YmFzZVBhdGh9LyR7ZW50cnkubmFtZX1gIDogZW50cnkubmFtZTtcbiAgICBpZiAoZW50cnkuaXNEaXJlY3RvcnkoKSkge1xuICAgICAgcmVzdWx0cy5wdXNoKC4uLmNvbGxlY3RGaWxlcyhmdWxsUGF0aCwgZXh0ZW5zaW9uLCByZWxQYXRoKSk7XG4gICAgfSBlbHNlIGlmIChlbnRyeS5uYW1lLmVuZHNXaXRoKGV4dGVuc2lvbikpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHN0YXQgPSBzdGF0U3luYyhmdWxsUGF0aCk7XG4gICAgICAgIHJlc3VsdHMucHVzaCh7XG4gICAgICAgICAgbmFtZTogZW50cnkubmFtZSxcbiAgICAgICAgICBwYXRoOiByZWxQYXRoLFxuICAgICAgICAgIHNpemVCeXRlczogc3RhdC5zaXplLFxuICAgICAgICAgIHNpemVLQjogZm9ybWF0U2l6ZShzdGF0LnNpemUpLFxuICAgICAgICB9KTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgbG9nLndhcm4oYENhbm5vdCBzdGF0ICR7cmVsUGF0aH06ICR7KGUgYXMgRXJyb3IpLm1lc3NhZ2V9YCk7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIHJldHVybiByZXN1bHRzO1xufVxuXG4vKipcbiAqIFNjYW4gY2xpZW50IGJ1aWxkIG91dHB1dCAoZGlzdC9jbGllbnQvKSBmb3IgaXNsYW5kIGNodW5rcy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNjYW5DbGllbnRCdWlsZChcbiAgcm9vdDogc3RyaW5nLFxuICBvdXREaXI6IHN0cmluZyA9ICdkaXN0Jyxcbik6IHsgaXNsYW5kczogQXJ0aWZhY3RJbmZvW107IGNsaWVudEVudHJ5OiBBcnRpZmFjdEluZm8gfCBudWxsOyB0b3RhbEpzQnl0ZXM6IG51bWJlciB9IHtcbiAgY29uc3QgY2xpZW50RGlyID0gcmVzb2x2ZShyb290LCBvdXREaXIsICdjbGllbnQnKTtcbiAgY29uc3QgaXNsYW5kczogQXJ0aWZhY3RJbmZvW10gPSBbXTtcbiAgbGV0IGNsaWVudEVudHJ5OiBBcnRpZmFjdEluZm8gfCBudWxsID0gbnVsbDtcbiAgbGV0IHRvdGFsSnNCeXRlcyA9IDA7XG5cbiAgLy8gU2NhbiBpc2xhbmRzLyBzdWJkaXJlY3RvcnkgKHNpbmdsZSBwYXNzIC0gYXZvaWQgcmVkdW5kYW50IGRpcmVjdG9yeSBzY2FucylcbiAgY29uc3QgaXNsYW5kc0RpciA9IGpvaW4oY2xpZW50RGlyLCAnaXNsYW5kcycpO1xuICBpZiAoZXhpc3RzU3luYyhpc2xhbmRzRGlyKSkge1xuICAgIGNvbnN0IGZpbGVzID0gcmVhZGRpclN5bmMoaXNsYW5kc0Rpcik7XG4gICAgZm9yIChjb25zdCBmaWxlIG9mIGZpbGVzKSB7XG4gICAgICBpZiAoIWZpbGUuZW5kc1dpdGgoJy5qcycpKSBjb250aW51ZTtcbiAgICAgIGNvbnN0IGZ1bGxQYXRoID0gam9pbihpc2xhbmRzRGlyLCBmaWxlKTtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGZpbGVTdGF0ID0gc3RhdFN5bmMoZnVsbFBhdGgpO1xuICAgICAgICBpZiAoZmlsZSA9PT0gJ2NsaWVudC5qcycpIHtcbiAgICAgICAgICAvLyBDbGllbnQgZW50cnkgKHNoYXJlZCBpc2xhbmQgdXBncmFkZSBydW50aW1lKVxuICAgICAgICAgIGNsaWVudEVudHJ5ID0ge1xuICAgICAgICAgICAgbmFtZTogJ2NsaWVudC5qcycsXG4gICAgICAgICAgICBwYXRoOiAnaXNsYW5kcy9jbGllbnQuanMnLFxuICAgICAgICAgICAgc2l6ZUJ5dGVzOiBmaWxlU3RhdC5zaXplLFxuICAgICAgICAgICAgc2l6ZUtCOiBmb3JtYXRTaXplKGZpbGVTdGF0LnNpemUpLFxuICAgICAgICAgIH07XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gSXNsYW5kIGNodW5rIG9yIHNoYXJlZCBjaHVua1xuICAgICAgICAgIGNvbnN0IF9pc0lzbGFuZENodW5rID0gL15pc2xhbmQtKC4rPyktW0EtWmEtejAtOV0rXFwuanMkLy50ZXN0KGZpbGUpO1xuICAgICAgICAgIGlzbGFuZHMucHVzaCh7XG4gICAgICAgICAgICBuYW1lOiBmaWxlLFxuICAgICAgICAgICAgcGF0aDogYGlzbGFuZHMvJHtmaWxlfWAsXG4gICAgICAgICAgICBzaXplQnl0ZXM6IGZpbGVTdGF0LnNpemUsXG4gICAgICAgICAgICBzaXplS0I6IGZvcm1hdFNpemUoZmlsZVN0YXQuc2l6ZSksXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgdG90YWxKc0J5dGVzICs9IGZpbGVTdGF0LnNpemU7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGxvZy53YXJuKGBDYW5ub3Qgc3RhdCAke2ZpbGV9OiAkeyhlIGFzIEVycm9yKS5tZXNzYWdlfWApO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB7IGlzbGFuZHMsIGNsaWVudEVudHJ5LCB0b3RhbEpzQnl0ZXMgfTtcbn1cblxuLyoqXG4gKiBTY2FuIFNTRyBvdXRwdXQgKGRpc3QvKi5odG1sKSBmb3IgcGFnZSBpbmZvcm1hdGlvbi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNjYW5TU0dPdXRwdXQoXG4gIHJvb3Q6IHN0cmluZyxcbiAgb3V0RGlyOiBzdHJpbmcgPSAnZGlzdCcsXG4pOiBBcnRpZmFjdEluZm9bXSB7XG4gIGNvbnN0IGRpc3REaXIgPSByZXNvbHZlKHJvb3QsIG91dERpcik7XG4gIHJldHVybiBjb2xsZWN0RmlsZXMoZGlzdERpciwgJy5odG1sJyk7XG59XG5cbi8qKlxuICogUHJpbnQgYSBmb3JtYXR0ZWQgYnVpbGQgbWFuaWZlc3QgdGFibGUgdG8gY29uc29sZS5cbiAqXG4gKiBUaGlzIGlzIGNhbGxlZCBhdCB0aGUgZW5kIG9mIGVhY2ggYnVpbGQgcGhhc2UgdG8gcHJvdmlkZSBvYnNlcnZhYmlsaXR5XG4gKiBpbnRvIHdoYXQgd2FzIHByb2R1Y2VkIGFuZCBob3cgbGFyZ2UgZXZlcnl0aGluZyBpcy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHByaW50QnVpbGRNYW5pZmVzdChvcHRpb25zOiB7XG4gIHJvb3Q6IHN0cmluZztcbiAgb3V0RGlyPzogc3RyaW5nO1xuICBwaGFzZTogMiB8IDM7XG4gIGhlYWRFeHRyYXM/OiBzdHJpbmc7XG59KTogQnVpbGRNYW5pZmVzdCB7XG4gIGNvbnN0IHsgcm9vdCwgb3V0RGlyID0gJ2Rpc3QnLCBwaGFzZSwgaGVhZEV4dHJhcyA9ICcnIH0gPSBvcHRpb25zO1xuICBjb25zdCB0aW1lc3RhbXAgPSBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCk7XG5cbiAgLy8gR2F0aGVyIGRhdGFcbiAgY29uc3QgY2xpZW50RGF0YSA9IHNjYW5DbGllbnRCdWlsZChyb290LCBvdXREaXIpO1xuICBjb25zdCBodG1sUGFnZXMgPSBwaGFzZSA9PT0gMyA/IHNjYW5TU0dPdXRwdXQocm9vdCwgb3V0RGlyKSA6IFtdO1xuICBjb25zdCBoZWFkRXh0cmFzU2l6ZSA9IG5ldyBUZXh0RW5jb2RlcigpLmVuY29kZShoZWFkRXh0cmFzKS5sZW5ndGg7XG5cbiAgLy8gQnVkZ2V0IHRocmVzaG9sZHNcbiAgY29uc3QgSVNMQU5EX0JVREdFVF9LQiA9IDUwOyAvLyBXYXJuIGlmIHNpbmdsZSBpc2xhbmQgPiA1MEtCXG4gIGNvbnN0IFRPVEFMX0pTX0JVREdFVF9LQiA9IDIwMDsgLy8gV2FybiBpZiB0b3RhbCBKUyA+IDIwMEtCXG4gIGNvbnN0IFBBR0VfQlVER0VUX0tCID0gMjAwOyAvLyBBZHZpc29yeSBvbmx5OiBzaW5nbGUgdW5jb21wcmVzc2VkIEhUTUwgcGFnZSBidWRnZXQuXG5cbiAgY29uc3Qgd2FybmluZ3M6IHN0cmluZ1tdID0gW107XG5cbiAgLy8gQ2hlY2sgaXNsYW5kIGJ1ZGdldHNcbiAgZm9yIChjb25zdCBpc2xhbmQgb2YgY2xpZW50RGF0YS5pc2xhbmRzKSB7XG4gICAgaWYgKGlzbGFuZC5zaXplQnl0ZXMgPiBJU0xBTkRfQlVER0VUX0tCICogMTAyNCkge1xuICAgICAgd2FybmluZ3MucHVzaChcbiAgICAgICAgYFdhcm5pbmc6ICR7aXNsYW5kLm5hbWV9ICgke2lzbGFuZC5zaXplS0J9KSBleGNlZWRzICR7SVNMQU5EX0JVREdFVF9LQn0gS0IgYnVkZ2V0YCxcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLy8gQ2hlY2sgdG90YWwgSlMgYnVkZ2V0XG4gIGlmIChjbGllbnREYXRhLnRvdGFsSnNCeXRlcyA+IFRPVEFMX0pTX0JVREdFVF9LQiAqIDEwMjQpIHtcbiAgICB3YXJuaW5ncy5wdXNoKFxuICAgICAgYFdhcm5pbmc6IFRvdGFsIEpTICgke1xuICAgICAgICBmb3JtYXRTaXplKGNsaWVudERhdGEudG90YWxKc0J5dGVzKVxuICAgICAgfSkgZXhjZWVkcyAke1RPVEFMX0pTX0JVREdFVF9LQn0gS0IgYnVkZ2V0YCxcbiAgICApO1xuICB9XG5cbiAgLy8gQ2hlY2sgcGFnZSBzaXplc1xuICBmb3IgKGNvbnN0IHBhZ2Ugb2YgaHRtbFBhZ2VzKSB7XG4gICAgaWYgKHBhZ2Uuc2l6ZUJ5dGVzID4gUEFHRV9CVURHRVRfS0IgKiAxMDI0KSB7XG4gICAgICB3YXJuaW5ncy5wdXNoKFxuICAgICAgICBgV2FybmluZzogJHtwYWdlLnBhdGh9ICgke3BhZ2Uuc2l6ZUtCfSkgZXhjZWVkcyBhZHZpc29yeSAke1BBR0VfQlVER0VUX0tCfSBLQiBIVE1MIGJ1ZGdldCAtIGNvbnNpZGVyIGNvbXByZXNzaW9uYCxcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgY29uc3QgbWFuaWZlc3Q6IEJ1aWxkTWFuaWZlc3QgPSB7XG4gICAgcGhhc2UsXG4gICAgdGltZXN0YW1wLFxuICAgIGlzbGFuZHM6IGNsaWVudERhdGEuaXNsYW5kcyxcbiAgICBjbGllbnRFbnRyeTogY2xpZW50RGF0YS5jbGllbnRFbnRyeSxcbiAgICBodG1sUGFnZXMsXG4gICAgdG90YWxKc0J5dGVzOiBjbGllbnREYXRhLnRvdGFsSnNCeXRlcyxcbiAgICB0b3RhbEh0bWxCeXRlczogaHRtbFBhZ2VzLnJlZHVjZSgoc3VtLCBwKSA9PiBzdW0gKyBwLnNpemVCeXRlcywgMCksXG4gICAgaGVhZEV4dHJhc1NpemUsXG4gICAgd2FybmluZ3MsXG4gIH07XG5cbiAgLy8gUHJpbnQgdGFibGUgdXNpbmcgQVNDSUktb25seSBvdXRwdXQgc28gYnVpbGQgbG9ncyByZW1haW4gcG9ydGFibGUuXG4gIGNvbnNvbGUuaW5mbygnJyk7XG4gIGNvbnNvbGUuaW5mbyhgPT0gb3BlbkVsZW1lbnQgQnVpbGQgTWFuaWZlc3QgLSBQaGFzZSAke3BoYXNlfSBAICR7dGltZXN0YW1wLnNsaWNlKDExLCAxOSl9ID09YCk7XG5cbiAgaWYgKG1hbmlmZXN0LmlzbGFuZHMubGVuZ3RoID4gMCB8fCBtYW5pZmVzdC5jbGllbnRFbnRyeSkge1xuICAgIGNvbnNvbGUuaW5mbygnXFxuICBDbGllbnQgSXNsYW5kczonKTtcbiAgICBjb25zb2xlLmluZm8oJyAgRmlsZSAgICAgICAgICAgICAgICAgICAgICAgICBTaXplJyk7XG4gICAgY29uc29sZS5pbmZvKCcgIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICAgLS0tLS0tLS0nKTtcblxuICAgIGZvciAoY29uc3QgaXNsYW5kIG9mIG1hbmlmZXN0LmlzbGFuZHMpIHtcbiAgICAgIGNvbnN0IGRpc3BsYXlOYW1lID0gaXNsYW5kLm5hbWUubGVuZ3RoID4gMzAgPyBpc2xhbmQubmFtZS5zbGljZSgwLCAyNykgKyAnLi4uJyA6IGlzbGFuZC5uYW1lO1xuICAgICAgY29uc29sZS5pbmZvKGAgICR7ZGlzcGxheU5hbWUucGFkRW5kKDI2KX0gICAke2lzbGFuZC5zaXplS0IucGFkRW5kKDgpfWApO1xuICAgIH1cblxuICAgIGlmIChtYW5pZmVzdC5jbGllbnRFbnRyeSkge1xuICAgICAgY29uc29sZS5pbmZvKFxuICAgICAgICBgICAkeydjbGllbnQuanMgKGVudHJ5KScucGFkRW5kKDI2KX0gICAke21hbmlmZXN0LmNsaWVudEVudHJ5LnNpemVLQi5wYWRFbmQoOCl9YCxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgY29uc29sZS5pbmZvKCcgIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICAgLS0tLS0tLS0nKTtcbiAgICBjb25zb2xlLmluZm8oYCAgJHsnVE9UQUwgSlMnLnBhZEVuZCgyNil9ICAgJHtmb3JtYXRTaXplKG1hbmlmZXN0LnRvdGFsSnNCeXRlcykucGFkRW5kKDgpfWApO1xuICB9IGVsc2Uge1xuICAgIGNvbnNvbGUuaW5mbygnXFxuICBDbGllbnQgSXNsYW5kczogbm9uZSAtIHplcm8gY2xpZW50IEpTJyk7XG4gIH1cblxuICBpZiAocGhhc2UgPT09IDMgJiYgbWFuaWZlc3QuaHRtbFBhZ2VzLmxlbmd0aCA+IDApIHtcbiAgICBjb25zb2xlLmluZm8oXG4gICAgICBgXFxuICBIVE1MIFBhZ2VzICgke21hbmlmZXN0Lmh0bWxQYWdlcy5sZW5ndGh9IGZpbGVzLCAke1xuICAgICAgICBmb3JtYXRTaXplKG1hbmlmZXN0LnRvdGFsSHRtbEJ5dGVzKVxuICAgICAgfSB0b3RhbCk6YCxcbiAgICApO1xuXG4gICAgY29uc3QgbWF4U2hvdyA9IDE1O1xuICAgIGNvbnN0IHNob3duID0gbWFuaWZlc3QuaHRtbFBhZ2VzLnNsaWNlKDAsIG1heFNob3cpO1xuICAgIGZvciAoY29uc3QgcGFnZSBvZiBzaG93bikge1xuICAgICAgY29uc3QgZGlzcGxheU5hbWUgPSBwYWdlLnBhdGgubGVuZ3RoID4gNDAgPyBwYWdlLnBhdGguc2xpY2UoMCwgMzcpICsgJy4uLicgOiBwYWdlLnBhdGg7XG4gICAgICBjb25zb2xlLmluZm8oYCAgICAtICR7ZGlzcGxheU5hbWV9ICgke3BhZ2Uuc2l6ZUtCfSlgKTtcbiAgICB9XG4gICAgaWYgKG1hbmlmZXN0Lmh0bWxQYWdlcy5sZW5ndGggPiBtYXhTaG93KSB7XG4gICAgICBjb25zb2xlLmluZm8oYCAgICAuLi4gKyR7bWFuaWZlc3QuaHRtbFBhZ2VzLmxlbmd0aCAtIG1heFNob3d9IG1vcmUgcGFnZXNgKTtcbiAgICB9XG4gIH1cblxuICBpZiAobWFuaWZlc3QuaGVhZEV4dHJhc1NpemUgPiAwKSB7XG4gICAgY29uc29sZS5pbmZvKFxuICAgICAgYFxcbiAgaGVhZEV4dHJhczogJHtcbiAgICAgICAgZm9ybWF0U2l6ZShtYW5pZmVzdC5oZWFkRXh0cmFzU2l6ZSlcbiAgICAgIH0gKCR7bWFuaWZlc3QuaGVhZEV4dHJhc1NpemV9IGJ5dGVzIGluamVjdGVkKWAsXG4gICAgKTtcbiAgfVxuXG4gIGlmICh3YXJuaW5ncy5sZW5ndGggPiAwKSB7XG4gICAgY29uc29sZS5pbmZvKCdcXG4gIEJ1ZGdldCBXYXJuaW5nczonKTtcbiAgICBmb3IgKGNvbnN0IHcgb2Ygd2FybmluZ3MpIHtcbiAgICAgIGNvbnNvbGUuaW5mbyhgICAgICAke3d9YCk7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIGNvbnNvbGUuaW5mbygnXFxuICBBbGwgYXJ0aWZhY3RzIHdpdGhpbiBidWRnZXQgbGltaXRzJyk7XG4gIH1cblxuICBjb25zb2xlLmluZm8oJycpO1xuXG4gIHJldHVybiBtYW5pZmVzdDtcbn1cbiJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7O0NBZUMsR0FFRCxTQUFTLElBQUksRUFBRSxPQUFPLFFBQVEsWUFBWTtBQUMxQyxTQUFTLFVBQVUsRUFBRSxXQUFXLEVBQUUsUUFBUSxRQUFRLFVBQVU7QUFDNUQsU0FBUyxZQUFZLFFBQVEsMkJBQTJCO0FBRXhELE1BQU0sTUFBTSxhQUFhO0FBd0J6Qjs7Q0FFQyxHQUNELFNBQVMsV0FBVyxLQUFhO0VBQy9CLElBQUksUUFBUSxNQUFNLE9BQU8sR0FBRyxNQUFNLEVBQUUsQ0FBQztFQUNyQyxJQUFJLFFBQVEsT0FBTyxJQUFJLE9BQU8sR0FBRyxDQUFDLFFBQVEsSUFBSSxFQUFFLE9BQU8sQ0FBQyxHQUFHLEdBQUcsQ0FBQztFQUMvRCxJQUFJLFFBQVEsT0FBTyxNQUFNLE9BQU8sR0FBRyxLQUFLLEtBQUssQ0FBQyxRQUFRLE1BQU0sR0FBRyxDQUFDO0VBQ2hFLE9BQU8sR0FBRyxDQUFDLFFBQVEsQ0FBQyxPQUFPLElBQUksQ0FBQyxFQUFFLE9BQU8sQ0FBQyxHQUFHLEdBQUcsQ0FBQztBQUNuRDtBQUVBOztDQUVDLEdBQ0QsU0FBUyxhQUNQLEdBQVcsRUFDWCxTQUFpQixFQUNqQixXQUFXLEVBQUU7RUFFYixNQUFNLFVBQTBCLEVBQUU7RUFDbEMsSUFBSSxDQUFDLFdBQVcsTUFBTSxPQUFPO0VBRTdCLE1BQU0sVUFBVSxZQUFZLEtBQUs7SUFBRSxlQUFlO0VBQUs7RUFDdkQsS0FBSyxNQUFNLFNBQVMsUUFBUztJQUMzQixNQUFNLFdBQVcsS0FBSyxLQUFLLE1BQU0sSUFBSTtJQUNyQyxNQUFNLFVBQVUsV0FBVyxHQUFHLFNBQVMsQ0FBQyxFQUFFLE1BQU0sSUFBSSxFQUFFLEdBQUcsTUFBTSxJQUFJO0lBQ25FLElBQUksTUFBTSxXQUFXLElBQUk7TUFDdkIsUUFBUSxJQUFJLElBQUksYUFBYSxVQUFVLFdBQVc7SUFDcEQsT0FBTyxJQUFJLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxZQUFZO01BQ3pDLElBQUk7UUFDRixNQUFNLE9BQU8sU0FBUztRQUN0QixRQUFRLElBQUksQ0FBQztVQUNYLE1BQU0sTUFBTSxJQUFJO1VBQ2hCLE1BQU07VUFDTixXQUFXLEtBQUssSUFBSTtVQUNwQixRQUFRLFdBQVcsS0FBSyxJQUFJO1FBQzlCO01BQ0YsRUFBRSxPQUFPLEdBQUc7UUFDVixJQUFJLElBQUksQ0FBQyxDQUFDLFlBQVksRUFBRSxRQUFRLEVBQUUsRUFBRSxBQUFDLEVBQVksT0FBTyxFQUFFO01BQzVEO0lBQ0Y7RUFDRjtFQUNBLE9BQU87QUFDVDtBQUVBOztDQUVDLEdBQ0QsT0FBTyxTQUFTLGdCQUNkLElBQVksRUFDWixTQUFpQixNQUFNO0VBRXZCLE1BQU0sWUFBWSxRQUFRLE1BQU0sUUFBUTtFQUN4QyxNQUFNLFVBQTBCLEVBQUU7RUFDbEMsSUFBSSxjQUFtQztFQUN2QyxJQUFJLGVBQWU7RUFFbkIsNkVBQTZFO0VBQzdFLE1BQU0sYUFBYSxLQUFLLFdBQVc7RUFDbkMsSUFBSSxXQUFXLGFBQWE7SUFDMUIsTUFBTSxRQUFRLFlBQVk7SUFDMUIsS0FBSyxNQUFNLFFBQVEsTUFBTztNQUN4QixJQUFJLENBQUMsS0FBSyxRQUFRLENBQUMsUUFBUTtNQUMzQixNQUFNLFdBQVcsS0FBSyxZQUFZO01BQ2xDLElBQUk7UUFDRixNQUFNLFdBQVcsU0FBUztRQUMxQixJQUFJLFNBQVMsYUFBYTtVQUN4QiwrQ0FBK0M7VUFDL0MsY0FBYztZQUNaLE1BQU07WUFDTixNQUFNO1lBQ04sV0FBVyxTQUFTLElBQUk7WUFDeEIsUUFBUSxXQUFXLFNBQVMsSUFBSTtVQUNsQztRQUNGLE9BQU87VUFDTCwrQkFBK0I7VUFDL0IsTUFBTSxpQkFBaUIsa0NBQWtDLElBQUksQ0FBQztVQUM5RCxRQUFRLElBQUksQ0FBQztZQUNYLE1BQU07WUFDTixNQUFNLENBQUMsUUFBUSxFQUFFLE1BQU07WUFDdkIsV0FBVyxTQUFTLElBQUk7WUFDeEIsUUFBUSxXQUFXLFNBQVMsSUFBSTtVQUNsQztRQUNGO1FBQ0EsZ0JBQWdCLFNBQVMsSUFBSTtNQUMvQixFQUFFLE9BQU8sR0FBRztRQUNWLElBQUksSUFBSSxDQUFDLENBQUMsWUFBWSxFQUFFLEtBQUssRUFBRSxFQUFFLEFBQUMsRUFBWSxPQUFPLEVBQUU7TUFDekQ7SUFDRjtFQUNGO0VBRUEsT0FBTztJQUFFO0lBQVM7SUFBYTtFQUFhO0FBQzlDO0FBRUE7O0NBRUMsR0FDRCxPQUFPLFNBQVMsY0FDZCxJQUFZLEVBQ1osU0FBaUIsTUFBTTtFQUV2QixNQUFNLFVBQVUsUUFBUSxNQUFNO0VBQzlCLE9BQU8sYUFBYSxTQUFTO0FBQy9CO0FBRUE7Ozs7O0NBS0MsR0FDRCxPQUFPLFNBQVMsbUJBQW1CLE9BS2xDO0VBQ0MsTUFBTSxFQUFFLElBQUksRUFBRSxTQUFTLE1BQU0sRUFBRSxLQUFLLEVBQUUsYUFBYSxFQUFFLEVBQUUsR0FBRztFQUMxRCxNQUFNLFlBQVksSUFBSSxPQUFPLFdBQVc7RUFFeEMsY0FBYztFQUNkLE1BQU0sYUFBYSxnQkFBZ0IsTUFBTTtFQUN6QyxNQUFNLFlBQVksVUFBVSxJQUFJLGNBQWMsTUFBTSxVQUFVLEVBQUU7RUFDaEUsTUFBTSxpQkFBaUIsSUFBSSxjQUFjLE1BQU0sQ0FBQyxZQUFZLE1BQU07RUFFbEUsb0JBQW9CO0VBQ3BCLE1BQU0sbUJBQW1CLElBQUksK0JBQStCO0VBQzVELE1BQU0scUJBQXFCLEtBQUssMkJBQTJCO0VBQzNELE1BQU0saUJBQWlCLEtBQUssdURBQXVEO0VBRW5GLE1BQU0sV0FBcUIsRUFBRTtFQUU3Qix1QkFBdUI7RUFDdkIsS0FBSyxNQUFNLFVBQVUsV0FBVyxPQUFPLENBQUU7SUFDdkMsSUFBSSxPQUFPLFNBQVMsR0FBRyxtQkFBbUIsTUFBTTtNQUM5QyxTQUFTLElBQUksQ0FDWCxDQUFDLFNBQVMsRUFBRSxPQUFPLElBQUksQ0FBQyxFQUFFLEVBQUUsT0FBTyxNQUFNLENBQUMsVUFBVSxFQUFFLGlCQUFpQixVQUFVLENBQUM7SUFFdEY7RUFDRjtFQUVBLHdCQUF3QjtFQUN4QixJQUFJLFdBQVcsWUFBWSxHQUFHLHFCQUFxQixNQUFNO0lBQ3ZELFNBQVMsSUFBSSxDQUNYLENBQUMsbUJBQW1CLEVBQ2xCLFdBQVcsV0FBVyxZQUFZLEVBQ25DLFVBQVUsRUFBRSxtQkFBbUIsVUFBVSxDQUFDO0VBRS9DO0VBRUEsbUJBQW1CO0VBQ25CLEtBQUssTUFBTSxRQUFRLFVBQVc7SUFDNUIsSUFBSSxLQUFLLFNBQVMsR0FBRyxpQkFBaUIsTUFBTTtNQUMxQyxTQUFTLElBQUksQ0FDWCxDQUFDLFNBQVMsRUFBRSxLQUFLLElBQUksQ0FBQyxFQUFFLEVBQUUsS0FBSyxNQUFNLENBQUMsbUJBQW1CLEVBQUUsZUFBZSxzQ0FBc0MsQ0FBQztJQUVySDtFQUNGO0VBRUEsTUFBTSxXQUEwQjtJQUM5QjtJQUNBO0lBQ0EsU0FBUyxXQUFXLE9BQU87SUFDM0IsYUFBYSxXQUFXLFdBQVc7SUFDbkM7SUFDQSxjQUFjLFdBQVcsWUFBWTtJQUNyQyxnQkFBZ0IsVUFBVSxNQUFNLENBQUMsQ0FBQyxLQUFLLElBQU0sTUFBTSxFQUFFLFNBQVMsRUFBRTtJQUNoRTtJQUNBO0VBQ0Y7RUFFQSxxRUFBcUU7RUFDckUsUUFBUSxJQUFJLENBQUM7RUFDYixRQUFRLElBQUksQ0FBQyxDQUFDLHNDQUFzQyxFQUFFLE1BQU0sR0FBRyxFQUFFLFVBQVUsS0FBSyxDQUFDLElBQUksSUFBSSxHQUFHLENBQUM7RUFFN0YsSUFBSSxTQUFTLE9BQU8sQ0FBQyxNQUFNLEdBQUcsS0FBSyxTQUFTLFdBQVcsRUFBRTtJQUN2RCxRQUFRLElBQUksQ0FBQztJQUNiLFFBQVEsSUFBSSxDQUFDO0lBQ2IsUUFBUSxJQUFJLENBQUM7SUFFYixLQUFLLE1BQU0sVUFBVSxTQUFTLE9BQU8sQ0FBRTtNQUNyQyxNQUFNLGNBQWMsT0FBTyxJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsTUFBTSxRQUFRLE9BQU8sSUFBSTtNQUM1RixRQUFRLElBQUksQ0FBQyxDQUFDLEVBQUUsRUFBRSxZQUFZLE1BQU0sQ0FBQyxJQUFJLEdBQUcsRUFBRSxPQUFPLE1BQU0sQ0FBQyxNQUFNLENBQUMsSUFBSTtJQUN6RTtJQUVBLElBQUksU0FBUyxXQUFXLEVBQUU7TUFDeEIsUUFBUSxJQUFJLENBQ1YsQ0FBQyxFQUFFLEVBQUUsb0JBQW9CLE1BQU0sQ0FBQyxJQUFJLEdBQUcsRUFBRSxTQUFTLFdBQVcsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUk7SUFFcEY7SUFFQSxRQUFRLElBQUksQ0FBQztJQUNiLFFBQVEsSUFBSSxDQUFDLENBQUMsRUFBRSxFQUFFLFdBQVcsTUFBTSxDQUFDLElBQUksR0FBRyxFQUFFLFdBQVcsU0FBUyxZQUFZLEVBQUUsTUFBTSxDQUFDLElBQUk7RUFDNUYsT0FBTztJQUNMLFFBQVEsSUFBSSxDQUFDO0VBQ2Y7RUFFQSxJQUFJLFVBQVUsS0FBSyxTQUFTLFNBQVMsQ0FBQyxNQUFNLEdBQUcsR0FBRztJQUNoRCxRQUFRLElBQUksQ0FDVixDQUFDLGdCQUFnQixFQUFFLFNBQVMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQ25ELFdBQVcsU0FBUyxjQUFjLEVBQ25DLFFBQVEsQ0FBQztJQUdaLE1BQU0sVUFBVTtJQUNoQixNQUFNLFFBQVEsU0FBUyxTQUFTLENBQUMsS0FBSyxDQUFDLEdBQUc7SUFDMUMsS0FBSyxNQUFNLFFBQVEsTUFBTztNQUN4QixNQUFNLGNBQWMsS0FBSyxJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssS0FBSyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsTUFBTSxRQUFRLEtBQUssSUFBSTtNQUN0RixRQUFRLElBQUksQ0FBQyxDQUFDLE1BQU0sRUFBRSxZQUFZLEVBQUUsRUFBRSxLQUFLLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDdEQ7SUFDQSxJQUFJLFNBQVMsU0FBUyxDQUFDLE1BQU0sR0FBRyxTQUFTO01BQ3ZDLFFBQVEsSUFBSSxDQUFDLENBQUMsU0FBUyxFQUFFLFNBQVMsU0FBUyxDQUFDLE1BQU0sR0FBRyxRQUFRLFdBQVcsQ0FBQztJQUMzRTtFQUNGO0VBRUEsSUFBSSxTQUFTLGNBQWMsR0FBRyxHQUFHO0lBQy9CLFFBQVEsSUFBSSxDQUNWLENBQUMsZ0JBQWdCLEVBQ2YsV0FBVyxTQUFTLGNBQWMsRUFDbkMsRUFBRSxFQUFFLFNBQVMsY0FBYyxDQUFDLGdCQUFnQixDQUFDO0VBRWxEO0VBRUEsSUFBSSxTQUFTLE1BQU0sR0FBRyxHQUFHO0lBQ3ZCLFFBQVEsSUFBSSxDQUFDO0lBQ2IsS0FBSyxNQUFNLEtBQUssU0FBVTtNQUN4QixRQUFRLElBQUksQ0FBQyxDQUFDLEtBQUssRUFBRSxHQUFHO0lBQzFCO0VBQ0YsT0FBTztJQUNMLFFBQVEsSUFBSSxDQUFDO0VBQ2Y7RUFFQSxRQUFRLElBQUksQ0FBQztFQUViLE9BQU87QUFDVCJ9
|
package/src/build.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @openelement/adapter-vite - Build plugin
|
|
3
|
+
* openElement Architecture (K·I·S·S): Knowledge · Isolated · Semantic · Static
|
|
4
|
+
* Build produces only static files (K+S), Islands are the only JS (I).
|
|
5
|
+
* API Routes (S - Serverless extension) deploy separately.
|
|
6
|
+
*
|
|
7
|
+
* ADR 0011: closeBundle writes metadata to ctx, then triggers Phase 2/3.
|
|
8
|
+
* No globalThis bridge - ctx stays in createOpenPlugin() closure scope throughout.
|
|
9
|
+
*/ import { join } from 'node:path';
|
|
10
|
+
import process from 'node:process';
|
|
11
|
+
import { createLogger } from '@openelement/core/logger';
|
|
12
|
+
import { cleanSsrArtifacts, postProcessClientIslandBuild } from '@openelement/ssg';
|
|
13
|
+
const log = createLogger('core');
|
|
14
|
+
/** Vite plugin: writes build metadata to ctx, then runs Phase 2 + Phase 3 */ export function buildPlugin(options = {}, ctx) {
|
|
15
|
+
let config;
|
|
16
|
+
return {
|
|
17
|
+
name: 'open:build',
|
|
18
|
+
configResolved (resolvedConfig) {
|
|
19
|
+
config = resolvedConfig;
|
|
20
|
+
},
|
|
21
|
+
async closeBundle () {
|
|
22
|
+
// Only run in build mode (not dev)
|
|
23
|
+
if (config.command !== 'build') return;
|
|
24
|
+
if (!ctx) {
|
|
25
|
+
log.warn('open:build skipped Phase 2/3 because no OpenElementBuildContext was provided.');
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
// Serialize SSR noExternal patterns (RegExp -> marker objects)
|
|
29
|
+
const ssrNoExternal = (options.ssr?.noExternal || config.ssr?.noExternal || []).map((item)=>{
|
|
30
|
+
if (item instanceof RegExp) {
|
|
31
|
+
return {
|
|
32
|
+
__type: 'RegExp',
|
|
33
|
+
source: item.source,
|
|
34
|
+
flags: item.flags
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return item;
|
|
38
|
+
});
|
|
39
|
+
// --- Write to OpenElementBuildContext ----------
|
|
40
|
+
ctx.populatePhase3(options, config, ssrNoExternal);
|
|
41
|
+
const totalIslands = (ctx.phase1.islandTagNames?.length || 0) + (ctx.phase1.packageIslandDecls?.length || 0);
|
|
42
|
+
log.info('Phase 1/3 complete - SSR bundle + metadata written to ctx');
|
|
43
|
+
// ADR 0023: Phase 3 (SSG) runs before Phase 2 (client bundle).
|
|
44
|
+
// SSG only needs Phase 1 - it renders HTML from the SSR bundle.
|
|
45
|
+
// Phase 2 runs last because client chunks have content hashes that
|
|
46
|
+
// don't affect HTML content, and injection is a post-processing step.
|
|
47
|
+
ctx.completePhase1();
|
|
48
|
+
await ctx.runPhase3(async ()=>{
|
|
49
|
+
const { buildSSG } = await import('./cli/build-ssg.js');
|
|
50
|
+
await buildSSG({}, ctx);
|
|
51
|
+
});
|
|
52
|
+
// Phase 2: Client island bundle (only if islands exist)
|
|
53
|
+
if (totalIslands > 0) {
|
|
54
|
+
await ctx.runPhase2(async ()=>{
|
|
55
|
+
const { buildClient } = await import('./cli/build-client.js');
|
|
56
|
+
await buildClient(ctx);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
// -- Inject client script (only runs if Phase 2 completed) --
|
|
60
|
+
// Phase 2's manifest.json tells us the client chunk URLs to inject
|
|
61
|
+
// into the already-rendered HTML pages.
|
|
62
|
+
if (ctx.isPhaseComplete(2)) {
|
|
63
|
+
try {
|
|
64
|
+
const outDir = ctx.phase3.outDir || 'dist';
|
|
65
|
+
const root = ctx.phase3.root || process.cwd();
|
|
66
|
+
const clientManifestPath = join(root, outDir, 'client', '.vite', 'manifest.json');
|
|
67
|
+
const { existsSync, readFileSync } = await import('node:fs');
|
|
68
|
+
if (existsSync(clientManifestPath)) {
|
|
69
|
+
const manifestRaw = readFileSync(clientManifestPath, 'utf-8');
|
|
70
|
+
const manifest = JSON.parse(manifestRaw);
|
|
71
|
+
for (const [src, entry] of Object.entries(manifest)){
|
|
72
|
+
if ((src.includes('open-client-entry') || src.includes('virtual:open-client')) && entry.file) {
|
|
73
|
+
const base = ctx.phase3.base || '/';
|
|
74
|
+
const scriptSrc = `${base}client/${entry.file}`;
|
|
75
|
+
await postProcessClientIslandBuild(ctx, scriptSrc);
|
|
76
|
+
log.info(`Client script injected: ${scriptSrc}`);
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
} catch (error) {
|
|
82
|
+
log.warn(`Failed to inject client script: ${error}`);
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
log.info('No Phase 2 - client script injection skipped');
|
|
86
|
+
}
|
|
87
|
+
// -- Clean Phase 1 SSR artifacts from public dist (v0.14.10) --
|
|
88
|
+
try {
|
|
89
|
+
await cleanSsrArtifacts(ctx);
|
|
90
|
+
} catch (error) {
|
|
91
|
+
log.warn(`Failed to clean SSR artifacts: ${error}`);
|
|
92
|
+
}
|
|
93
|
+
log.info('Build complete.');
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9vcGVuZWxlbWVudC9vcGVuZWxlbWVudC9wYWNrYWdlcy9hZGFwdGVyLXZpdGUvc3JjL2J1aWxkLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQG9wZW5lbGVtZW50L2FkYXB0ZXItdml0ZSAtIEJ1aWxkIHBsdWdpblxuICogb3BlbkVsZW1lbnQgQXJjaGl0ZWN0dXJlIChLwrdJwrdTwrdTKTogS25vd2xlZGdlIMK3IElzb2xhdGVkIMK3IFNlbWFudGljIMK3IFN0YXRpY1xuICogQnVpbGQgcHJvZHVjZXMgb25seSBzdGF0aWMgZmlsZXMgKEsrUyksIElzbGFuZHMgYXJlIHRoZSBvbmx5IEpTIChJKS5cbiAqIEFQSSBSb3V0ZXMgKFMgLSBTZXJ2ZXJsZXNzIGV4dGVuc2lvbikgZGVwbG95IHNlcGFyYXRlbHkuXG4gKlxuICogQURSIDAwMTE6IGNsb3NlQnVuZGxlIHdyaXRlcyBtZXRhZGF0YSB0byBjdHgsIHRoZW4gdHJpZ2dlcnMgUGhhc2UgMi8zLlxuICogTm8gZ2xvYmFsVGhpcyBicmlkZ2UgLSBjdHggc3RheXMgaW4gY3JlYXRlT3BlblBsdWdpbigpIGNsb3N1cmUgc2NvcGUgdGhyb3VnaG91dC5cbiAqL1xuXG5pbXBvcnQgdHlwZSB7IFBsdWdpbiwgUmVzb2x2ZWRDb25maWcgfSBmcm9tICd2aXRlJztcbmltcG9ydCB0eXBlIHsgRnJhbWV3b3JrT3B0aW9ucyB9IGZyb20gJ0BvcGVuZWxlbWVudC9wcm90b2NvbC9mcmFtZXdvcmsnO1xuaW1wb3J0IHR5cGUgeyBPcGVuRWxlbWVudEJ1aWxkQ29udGV4dCB9IGZyb20gJy4vYnVpbGQtY29udGV4dC5qcyc7XG5pbXBvcnQgeyBqb2luIH0gZnJvbSAnbm9kZTpwYXRoJztcbmltcG9ydCBwcm9jZXNzIGZyb20gJ25vZGU6cHJvY2Vzcyc7XG5pbXBvcnQgeyBjcmVhdGVMb2dnZXIgfSBmcm9tICdAb3BlbmVsZW1lbnQvY29yZS9sb2dnZXInO1xuaW1wb3J0IHsgY2xlYW5Tc3JBcnRpZmFjdHMsIHBvc3RQcm9jZXNzQ2xpZW50SXNsYW5kQnVpbGQgfSBmcm9tICdAb3BlbmVsZW1lbnQvc3NnJztcblxuY29uc3QgbG9nID0gY3JlYXRlTG9nZ2VyKCdjb3JlJyk7XG5cbi8qKiBWaXRlIHBsdWdpbjogd3JpdGVzIGJ1aWxkIG1ldGFkYXRhIHRvIGN0eCwgdGhlbiBydW5zIFBoYXNlIDIgKyBQaGFzZSAzICovXG5leHBvcnQgZnVuY3Rpb24gYnVpbGRQbHVnaW4oXG4gIG9wdGlvbnM6IEZyYW1ld29ya09wdGlvbnMgJiB7IGFsbG93SGVhZEV4dHJhc1NjcmlwdHM/OiBib29sZWFuIH0gPSB7fSxcbiAgY3R4PzogT3BlbkVsZW1lbnRCdWlsZENvbnRleHQsXG4pOiBQbHVnaW4ge1xuICBsZXQgY29uZmlnOiBSZXNvbHZlZENvbmZpZztcblxuICByZXR1cm4ge1xuICAgIG5hbWU6ICdvcGVuOmJ1aWxkJyxcblxuICAgIGNvbmZpZ1Jlc29sdmVkKHJlc29sdmVkQ29uZmlnKSB7XG4gICAgICBjb25maWcgPSByZXNvbHZlZENvbmZpZztcbiAgICB9LFxuXG4gICAgYXN5bmMgY2xvc2VCdW5kbGUoKSB7XG4gICAgICAvLyBPbmx5IHJ1biBpbiBidWlsZCBtb2RlIChub3QgZGV2KVxuICAgICAgaWYgKGNvbmZpZy5jb21tYW5kICE9PSAnYnVpbGQnKSByZXR1cm47XG5cbiAgICAgIGlmICghY3R4KSB7XG4gICAgICAgIGxvZy53YXJuKCdvcGVuOmJ1aWxkIHNraXBwZWQgUGhhc2UgMi8zIGJlY2F1c2Ugbm8gT3BlbkVsZW1lbnRCdWlsZENvbnRleHQgd2FzIHByb3ZpZGVkLicpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIC8vIFNlcmlhbGl6ZSBTU1Igbm9FeHRlcm5hbCBwYXR0ZXJucyAoUmVnRXhwIC0+IG1hcmtlciBvYmplY3RzKVxuICAgICAgY29uc3Qgc3NyTm9FeHRlcm5hbCA9ICgob3B0aW9ucy5zc3I/Lm5vRXh0ZXJuYWwgfHxcbiAgICAgICAgKGNvbmZpZy5zc3IgYXMgeyBub0V4dGVybmFsPzogKHN0cmluZyB8IFJlZ0V4cClbXSB9IHwgdW5kZWZpbmVkKT8ubm9FeHRlcm5hbCkgfHwgW10pXG4gICAgICAgIC5tYXAoKGl0ZW0pID0+IHtcbiAgICAgICAgICBpZiAoaXRlbSBpbnN0YW5jZW9mIFJlZ0V4cCkge1xuICAgICAgICAgICAgcmV0dXJuIHsgX190eXBlOiAnUmVnRXhwJywgc291cmNlOiBpdGVtLnNvdXJjZSwgZmxhZ3M6IGl0ZW0uZmxhZ3MgfTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIGl0ZW07XG4gICAgICAgIH0pO1xuXG4gICAgICAvLyAtLS0gV3JpdGUgdG8gT3BlbkVsZW1lbnRCdWlsZENvbnRleHQgLS0tLS0tLS0tLVxuICAgICAgY3R4LnBvcHVsYXRlUGhhc2UzKFxuICAgICAgICBvcHRpb25zLFxuICAgICAgICBjb25maWcsXG4gICAgICAgIHNzck5vRXh0ZXJuYWwgYXMgKHN0cmluZyB8IHsgX190eXBlOiAnUmVnRXhwJzsgc291cmNlOiBzdHJpbmc7IGZsYWdzOiBzdHJpbmcgfSlbXSxcbiAgICAgICk7XG5cbiAgICAgIGNvbnN0IHRvdGFsSXNsYW5kcyA9IChjdHgucGhhc2UxLmlzbGFuZFRhZ05hbWVzPy5sZW5ndGggfHwgMCkgK1xuICAgICAgICAoY3R4LnBoYXNlMS5wYWNrYWdlSXNsYW5kRGVjbHM/Lmxlbmd0aCB8fCAwKTtcblxuICAgICAgbG9nLmluZm8oJ1BoYXNlIDEvMyBjb21wbGV0ZSAtIFNTUiBidW5kbGUgKyBtZXRhZGF0YSB3cml0dGVuIHRvIGN0eCcpO1xuXG4gICAgICAvLyBBRFIgMDAyMzogUGhhc2UgMyAoU1NHKSBydW5zIGJlZm9yZSBQaGFzZSAyIChjbGllbnQgYnVuZGxlKS5cbiAgICAgIC8vIFNTRyBvbmx5IG5lZWRzIFBoYXNlIDEgLSBpdCByZW5kZXJzIEhUTUwgZnJvbSB0aGUgU1NSIGJ1bmRsZS5cbiAgICAgIC8vIFBoYXNlIDIgcnVucyBsYXN0IGJlY2F1c2UgY2xpZW50IGNodW5rcyBoYXZlIGNvbnRlbnQgaGFzaGVzIHRoYXRcbiAgICAgIC8vIGRvbid0IGFmZmVjdCBIVE1MIGNvbnRlbnQsIGFuZCBpbmplY3Rpb24gaXMgYSBwb3N0LXByb2Nlc3Npbmcgc3RlcC5cbiAgICAgIGN0eC5jb21wbGV0ZVBoYXNlMSgpO1xuXG4gICAgICBhd2FpdCBjdHgucnVuUGhhc2UzKGFzeW5jICgpID0+IHtcbiAgICAgICAgY29uc3QgeyBidWlsZFNTRyB9ID0gYXdhaXQgaW1wb3J0KCcuL2NsaS9idWlsZC1zc2cuanMnKTtcbiAgICAgICAgYXdhaXQgYnVpbGRTU0coe30sIGN0eCk7XG4gICAgICB9KTtcblxuICAgICAgLy8gUGhhc2UgMjogQ2xpZW50IGlzbGFuZCBidW5kbGUgKG9ubHkgaWYgaXNsYW5kcyBleGlzdClcbiAgICAgIGlmICh0b3RhbElzbGFuZHMgPiAwKSB7XG4gICAgICAgIGF3YWl0IGN0eC5ydW5QaGFzZTIoYXN5bmMgKCkgPT4ge1xuICAgICAgICAgIGNvbnN0IHsgYnVpbGRDbGllbnQgfSA9IGF3YWl0IGltcG9ydCgnLi9jbGkvYnVpbGQtY2xpZW50LmpzJyk7XG4gICAgICAgICAgYXdhaXQgYnVpbGRDbGllbnQoY3R4KTtcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIC8vIC0tIEluamVjdCBjbGllbnQgc2NyaXB0IChvbmx5IHJ1bnMgaWYgUGhhc2UgMiBjb21wbGV0ZWQpIC0tXG4gICAgICAvLyBQaGFzZSAyJ3MgbWFuaWZlc3QuanNvbiB0ZWxscyB1cyB0aGUgY2xpZW50IGNodW5rIFVSTHMgdG8gaW5qZWN0XG4gICAgICAvLyBpbnRvIHRoZSBhbHJlYWR5LXJlbmRlcmVkIEhUTUwgcGFnZXMuXG4gICAgICBpZiAoY3R4LmlzUGhhc2VDb21wbGV0ZSgyKSkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IG91dERpciA9IGN0eC5waGFzZTMub3V0RGlyIHx8ICdkaXN0JztcbiAgICAgICAgICBjb25zdCByb290ID0gY3R4LnBoYXNlMy5yb290IHx8IHByb2Nlc3MuY3dkKCk7XG4gICAgICAgICAgY29uc3QgY2xpZW50TWFuaWZlc3RQYXRoID0gam9pbihyb290LCBvdXREaXIsICdjbGllbnQnLCAnLnZpdGUnLCAnbWFuaWZlc3QuanNvbicpO1xuICAgICAgICAgIGNvbnN0IHsgZXhpc3RzU3luYywgcmVhZEZpbGVTeW5jIH0gPSBhd2FpdCBpbXBvcnQoJ25vZGU6ZnMnKTtcbiAgICAgICAgICBpZiAoZXhpc3RzU3luYyhjbGllbnRNYW5pZmVzdFBhdGgpKSB7XG4gICAgICAgICAgICBjb25zdCBtYW5pZmVzdFJhdyA9IHJlYWRGaWxlU3luYyhjbGllbnRNYW5pZmVzdFBhdGgsICd1dGYtOCcpO1xuICAgICAgICAgICAgY29uc3QgbWFuaWZlc3QgPSBKU09OLnBhcnNlKG1hbmlmZXN0UmF3KTtcbiAgICAgICAgICAgIGZvciAoY29uc3QgW3NyYywgZW50cnldIG9mIE9iamVjdC5lbnRyaWVzKG1hbmlmZXN0KSBhcyBbc3RyaW5nLCB7IGZpbGU/OiBzdHJpbmcgfV1bXSkge1xuICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgKHNyYy5pbmNsdWRlcygnb3Blbi1jbGllbnQtZW50cnknKSB8fCBzcmMuaW5jbHVkZXMoJ3ZpcnR1YWw6b3Blbi1jbGllbnQnKSkgJiZcbiAgICAgICAgICAgICAgICBlbnRyeS5maWxlXG4gICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGJhc2UgPSBjdHgucGhhc2UzLmJhc2UgfHwgJy8nO1xuICAgICAgICAgICAgICAgIGNvbnN0IHNjcmlwdFNyYyA9IGAke2Jhc2V9Y2xpZW50LyR7ZW50cnkuZmlsZX1gO1xuICAgICAgICAgICAgICAgIGF3YWl0IHBvc3RQcm9jZXNzQ2xpZW50SXNsYW5kQnVpbGQoY3R4LCBzY3JpcHRTcmMpO1xuICAgICAgICAgICAgICAgIGxvZy5pbmZvKGBDbGllbnQgc2NyaXB0IGluamVjdGVkOiAke3NjcmlwdFNyY31gKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBsb2cud2FybihgRmFpbGVkIHRvIGluamVjdCBjbGllbnQgc2NyaXB0OiAke2Vycm9yfWApO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBsb2cuaW5mbygnTm8gUGhhc2UgMiAtIGNsaWVudCBzY3JpcHQgaW5qZWN0aW9uIHNraXBwZWQnKTtcbiAgICAgIH1cblxuICAgICAgLy8gLS0gQ2xlYW4gUGhhc2UgMSBTU1IgYXJ0aWZhY3RzIGZyb20gcHVibGljIGRpc3QgKHYwLjE0LjEwKSAtLVxuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgY2xlYW5Tc3JBcnRpZmFjdHMoY3R4KTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGxvZy53YXJuKGBGYWlsZWQgdG8gY2xlYW4gU1NSIGFydGlmYWN0czogJHtlcnJvcn1gKTtcbiAgICAgIH1cblxuICAgICAgbG9nLmluZm8oJ0J1aWxkIGNvbXBsZXRlLicpO1xuICAgIH0sXG4gIH07XG59XG4iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7O0NBUUMsR0FLRCxTQUFTLElBQUksUUFBUSxZQUFZO0FBQ2pDLE9BQU8sYUFBYSxlQUFlO0FBQ25DLFNBQVMsWUFBWSxRQUFRLDJCQUEyQjtBQUN4RCxTQUFTLGlCQUFpQixFQUFFLDRCQUE0QixRQUFRLG1CQUFtQjtBQUVuRixNQUFNLE1BQU0sYUFBYTtBQUV6QiwyRUFBMkUsR0FDM0UsT0FBTyxTQUFTLFlBQ2QsVUFBbUUsQ0FBQyxDQUFDLEVBQ3JFLEdBQTZCO0VBRTdCLElBQUk7RUFFSixPQUFPO0lBQ0wsTUFBTTtJQUVOLGdCQUFlLGNBQWM7TUFDM0IsU0FBUztJQUNYO0lBRUEsTUFBTTtNQUNKLG1DQUFtQztNQUNuQyxJQUFJLE9BQU8sT0FBTyxLQUFLLFNBQVM7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
|