@openelement/ssg 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 +21 -0
- package/package.json +30 -0
- package/src/build-postprocess.d.ts +24 -0
- package/src/build-postprocess.js +74 -0
- package/src/cem-compat.js +226 -0
- package/src/entry-generators.d.ts +3 -0
- package/src/entry-generators.js +126 -0
- package/src/entry-render-helpers.js +307 -0
- package/src/entry-render-runtime.js +94 -0
- package/src/entry-render-ssg.js +169 -0
- package/src/entry-renderer.d.ts +87 -0
- package/src/entry-renderer.js +555 -0
- package/src/external-resolver.d.ts +62 -0
- package/src/external-resolver.js +285 -0
- package/src/index.d.ts +31 -0
- package/src/index.js +28 -0
- package/src/island-manifest.d.ts +27 -0
- package/src/island-manifest.js +78 -0
- package/src/postprocess.d.ts +73 -0
- package/src/postprocess.js +376 -0
- package/src/route-scanner-fs.js +29 -0
- package/src/route-scanner.d.ts +132 -0
- package/src/route-scanner.js +497 -0
- package/src/route-type-generator.d.ts +29 -0
- package/src/route-type-generator.js +99 -0
- package/src/ssg-dynamic.js +66 -0
- package/src/ssg-helpers.d.ts +8 -0
- package/src/ssg-helpers.js +96 -0
- package/src/ssg-i18n.js +78 -0
- package/src/ssg-render.d.ts +3 -0
- package/src/ssg-render.js +162 -0
- package/src/ssg-report.js +172 -0
- package/src/ssr-polyfills.d.ts +15 -0
- package/src/ssr-polyfills.js +26 -0
|
@@ -0,0 +1,555 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @openelement/core - Entry Renderer
|
|
3
|
+
*
|
|
4
|
+
* Pure function: routes + options -> Hono entry virtual module code.
|
|
5
|
+
*
|
|
6
|
+
* openElement Architecture (v0.5.0):
|
|
7
|
+
* - API routes use Hono standard app.route() (not app.all + fetch transform)
|
|
8
|
+
* - Island upgrade is handled by the client entry (built by Vite in Phase 2).
|
|
9
|
+
* No inline script in SSG HTML; the client entry is a Vite-built module
|
|
10
|
+
* referenced via <script type="module" src="..."> and imports island modules
|
|
11
|
+
* for side-effect custom element registration.
|
|
12
|
+
* - HTML document wrapping delegates to wrapInDocument from html-escape.ts
|
|
13
|
+
* (imported at runtime - single source of truth, no duplicate HTML logic)
|
|
14
|
+
* - DSD output must remain plain HTML, without Lit SSR marker comments.
|
|
15
|
+
*
|
|
16
|
+
* H-16 KNOWN ISSUE: Circular dependency between adapter-vite <-> content
|
|
17
|
+
* adapter-vite generates code that imports @openelement/content/sitemap
|
|
18
|
+
* content package imports @openelement/adapter-vite/build-context
|
|
19
|
+
* Shared contracts now live in @openelement/core, @openelement/ssg, @openelement/router,
|
|
20
|
+
* and @openelement/signal. Generated optional package imports are still emitted explicitly
|
|
21
|
+
* so consumer import maps can be checked.
|
|
22
|
+
*
|
|
23
|
+
* Thin orchestrator: delegates code generation to focused sub-modules:
|
|
24
|
+
* - entry-render-helpers.ts — individual code fragment generators
|
|
25
|
+
* - entry-render-runtime.ts — runtime helper function code generation
|
|
26
|
+
* - entry-render-ssg.ts — SSG re-export & routeInfo/renderRoute/getStaticPaths
|
|
27
|
+
*
|
|
28
|
+
* v0.41.0-alpha.1: The intermediate EntryDescriptor data model was collapsed
|
|
29
|
+
* into this file. `generateHonoEntryCode()` builds descriptor-shaped data and
|
|
30
|
+
* passes it directly to `renderEntry()` without a separate public descriptor
|
|
31
|
+
* builder or file.
|
|
32
|
+
*/ import { fileToTagName } from './route-scanner.js';
|
|
33
|
+
import { renderActionRoute, renderApiRoute, renderDataEndpoint, renderDataRouteMap, renderImport, renderMiddleware, renderPageRoute, routeTagNameExpr } from './entry-render-helpers.js';
|
|
34
|
+
import { renderRuntimeHelpers } from './entry-render-runtime.js';
|
|
35
|
+
import { renderSsgSection } from './entry-render-ssg.js';
|
|
36
|
+
/**
|
|
37
|
+
* Render an EntryDescriptor into a complete virtual module string.
|
|
38
|
+
*
|
|
39
|
+
* Pure function - deterministic, testable, side-effect-free.
|
|
40
|
+
*/ export function renderEntry(desc) {
|
|
41
|
+
const lines = [];
|
|
42
|
+
const ssrAdmissionPlan = desc.ssrAdmissionPlan;
|
|
43
|
+
// --- Imports ---
|
|
44
|
+
for (const imp of desc.imports){
|
|
45
|
+
lines.push(renderImport(imp));
|
|
46
|
+
}
|
|
47
|
+
// --- Island lookup (build-time known list) ---
|
|
48
|
+
const islandLookup = {};
|
|
49
|
+
for (const island of desc.islands){
|
|
50
|
+
islandLookup[island.tagName] = island.modulePath;
|
|
51
|
+
}
|
|
52
|
+
const appShellImports = new Set();
|
|
53
|
+
const collectShellImport = (shell)=>{
|
|
54
|
+
if (shell) appShellImports.add(shell.importPath);
|
|
55
|
+
};
|
|
56
|
+
collectShellImport(desc.appShell.default);
|
|
57
|
+
for (const shell of Object.values(desc.appShell.layouts))collectShellImport(shell);
|
|
58
|
+
lines.push(`// Known islands (determined at build time by scanning islandsDir)`);
|
|
59
|
+
lines.push(`const __islandMap = ${JSON.stringify(islandLookup)}`);
|
|
60
|
+
lines.push('');
|
|
61
|
+
// --- Document wrapper ---
|
|
62
|
+
lines.push(`import { wrapInDocument } from '@openelement/core';`);
|
|
63
|
+
lines.push(`import { jsx } from '@openelement/core/jsx-runtime';`);
|
|
64
|
+
lines.push(`import { createLogger } from '@openelement/core/logger';`);
|
|
65
|
+
lines.push(`import { createRuntimeAdapter } from '@openelement/core/runtime';`);
|
|
66
|
+
lines.push(`import { headerNav as __headerNav, navSections as __navSections } from '@openelement/generated/nav';`);
|
|
67
|
+
lines.push(`import { getDefaultLocale as __getDefaultLocale, locales as __locales } from '@openelement/generated/i18n';`);
|
|
68
|
+
for (const importPath of appShellImports){
|
|
69
|
+
lines.push(`import '${importPath}';`);
|
|
70
|
+
}
|
|
71
|
+
lines.push(`const log = createLogger('core');`);
|
|
72
|
+
lines.push('');
|
|
73
|
+
// --- Route module imports ---
|
|
74
|
+
for (const route of [
|
|
75
|
+
...desc.apiRoutes,
|
|
76
|
+
...desc.pageRoutes
|
|
77
|
+
]){
|
|
78
|
+
lines.push(`import * as ${route.varName} from '${route.importPath}'`);
|
|
79
|
+
}
|
|
80
|
+
for (const renderer of desc.renderers){
|
|
81
|
+
lines.push(`import * as ${renderer.varName} from '${renderer.importPath}'`);
|
|
82
|
+
}
|
|
83
|
+
for (const mwScope of desc.middlewareScopes){
|
|
84
|
+
lines.push(`import * as ${mwScope.varName} from '${mwScope.importPath}'`);
|
|
85
|
+
}
|
|
86
|
+
lines.push('');
|
|
87
|
+
// --- Register page components in SSR customElements registry ---
|
|
88
|
+
{
|
|
89
|
+
lines.push('// ADR 0014: Idempotent customElements.define for SSR (dev + SSG)');
|
|
90
|
+
lines.push('// Island modules call customElements.define() as a side-effect.');
|
|
91
|
+
lines.push('// The SSR dom-shim does not make define() idempotent, so we patch it.');
|
|
92
|
+
lines.push('const _origDefine = customElements.define.bind(customElements);');
|
|
93
|
+
lines.push('customElements.define = (name, ctor, options) => {');
|
|
94
|
+
lines.push(' if (customElements.get(name)) return;');
|
|
95
|
+
lines.push(' try { _origDefine(name, ctor, options); } catch { /* already defined */ }');
|
|
96
|
+
lines.push('};');
|
|
97
|
+
lines.push('');
|
|
98
|
+
}
|
|
99
|
+
for (const route of desc.pageRoutes){
|
|
100
|
+
const tagNameExpr = routeTagNameExpr(route.varName, route.tagName);
|
|
101
|
+
lines.push(`if (!customElements.get(${tagNameExpr})) {`);
|
|
102
|
+
lines.push(` customElements.define(${tagNameExpr}, ${route.varName}.default)`);
|
|
103
|
+
lines.push(`}`);
|
|
104
|
+
}
|
|
105
|
+
lines.push('');
|
|
106
|
+
// --- Register island components in SSR customElements registry ---
|
|
107
|
+
const ssrRenderableTags = new Set(ssrAdmissionPlan.renderableTags);
|
|
108
|
+
const ssrIslands = desc.islands.filter((island)=>ssrRenderableTags.has(island.tagName));
|
|
109
|
+
for (const island of ssrIslands){
|
|
110
|
+
const varName = `__island_${island.tagName.replace(/-/g, '_')}`;
|
|
111
|
+
lines.push(`import * as ${varName} from '${island.modulePath}'`);
|
|
112
|
+
}
|
|
113
|
+
for (const island of ssrIslands){
|
|
114
|
+
const varName = `__island_${island.tagName.replace(/-/g, '_')}`;
|
|
115
|
+
const componentVar = `__island_component_${island.tagName.replace(/-/g, '_')}`;
|
|
116
|
+
lines.push(`const ${componentVar} = ${varName}?.default`);
|
|
117
|
+
lines.push(`if (${componentVar} && !customElements.get('${island.tagName}')) {`);
|
|
118
|
+
lines.push(` customElements.define('${island.tagName}', ${componentVar})`);
|
|
119
|
+
lines.push(`}`);
|
|
120
|
+
}
|
|
121
|
+
lines.push('');
|
|
122
|
+
lines.push('// v0.17.4: SSR admission plan');
|
|
123
|
+
lines.push(`(globalThis).__CLIENT_ONLY_TAGS__ = new Set(${JSON.stringify(ssrAdmissionPlan.clientOnlyTags)})`);
|
|
124
|
+
lines.push(`export const ssrAdmissionPlan = ${JSON.stringify(ssrAdmissionPlan, null, 2)};`);
|
|
125
|
+
lines.push('');
|
|
126
|
+
// --- SSG: headExtras via define injection ---
|
|
127
|
+
if (desc.isSSG && desc.document.headExtras) {
|
|
128
|
+
lines.push('// SSG: headExtras injected via Vite define (ADR 0008 Phase A)');
|
|
129
|
+
lines.push('// Replaces the old .openElement/head-extras.html runtime file read');
|
|
130
|
+
lines.push('const __headExtras = __HEAD_EXTRAS__ || "";');
|
|
131
|
+
lines.push('');
|
|
132
|
+
}
|
|
133
|
+
// --- Runtime helpers ---
|
|
134
|
+
lines.push(renderRuntimeHelpers(desc.appShell));
|
|
135
|
+
lines.push('');
|
|
136
|
+
// --- App creation + Middleware ---
|
|
137
|
+
lines.push('const app = new Hono()');
|
|
138
|
+
lines.push('');
|
|
139
|
+
for (const mw of desc.middleware){
|
|
140
|
+
renderMiddleware(lines, mw);
|
|
141
|
+
}
|
|
142
|
+
// --- Middleware scopes (v0.3.0: _middleware.ts files) ---
|
|
143
|
+
for (const mwScope of desc.middlewareScopes){
|
|
144
|
+
lines.push(`// Middleware scope: ${mwScope.scope} (${mwScope.importPath})`);
|
|
145
|
+
lines.push(`app.use('${mwScope.scope === '/' ? '' : mwScope.scope}/*', ${mwScope.varName}.default)`);
|
|
146
|
+
lines.push('');
|
|
147
|
+
}
|
|
148
|
+
// --- API routes ---
|
|
149
|
+
for (const route of desc.apiRoutes){
|
|
150
|
+
renderApiRoute(lines, route);
|
|
151
|
+
}
|
|
152
|
+
// --- Page routes ---
|
|
153
|
+
const docConfig = {
|
|
154
|
+
title: desc.document.title,
|
|
155
|
+
lang: desc.document.lang,
|
|
156
|
+
headExtras: desc.document.headExtras,
|
|
157
|
+
allowHeadExtrasScripts: desc.document.allowHeadExtrasScripts
|
|
158
|
+
};
|
|
159
|
+
for (const route of desc.pageRoutes){
|
|
160
|
+
renderPageRoute(lines, route, desc.renderers, docConfig, desc.isSSG);
|
|
161
|
+
}
|
|
162
|
+
// --- Action POST handlers ---
|
|
163
|
+
for (const route of desc.pageRoutes){
|
|
164
|
+
renderActionRoute(lines, route, desc.renderers, docConfig, desc.isSSG);
|
|
165
|
+
}
|
|
166
|
+
// --- /_data endpoint for SPA navigation ---
|
|
167
|
+
renderDataRouteMap(lines, desc.pageRoutes);
|
|
168
|
+
renderDataEndpoint(lines);
|
|
169
|
+
// --- Export ---
|
|
170
|
+
lines.push('export const openElementHandler = (request, context = {}) => {');
|
|
171
|
+
lines.push(' return app.fetch(request, context.env || {}, context.platform)');
|
|
172
|
+
lines.push('}');
|
|
173
|
+
lines.push('');
|
|
174
|
+
lines.push('export const openElementRuntimeAdapter = {');
|
|
175
|
+
lines.push(" ...createRuntimeAdapter({ name: 'openelement-hono', fetch: openElementHandler }),");
|
|
176
|
+
lines.push('}');
|
|
177
|
+
lines.push('');
|
|
178
|
+
lines.push('export default app');
|
|
179
|
+
// --- SSG section ---
|
|
180
|
+
const ssgSection = renderSsgSection(desc);
|
|
181
|
+
if (ssgSection) {
|
|
182
|
+
lines.push(ssgSection);
|
|
183
|
+
}
|
|
184
|
+
return lines.join('\n');
|
|
185
|
+
}
|
|
186
|
+
function normalizeAppShellImport(importPath) {
|
|
187
|
+
if (importPath.startsWith('./')) return `/${importPath.slice(2)}`;
|
|
188
|
+
if (importPath.startsWith('../')) return importPath;
|
|
189
|
+
return importPath;
|
|
190
|
+
}
|
|
191
|
+
function normalizeAppShell(config) {
|
|
192
|
+
if (config === false) return false;
|
|
193
|
+
if (config === undefined || config === 'default') {
|
|
194
|
+
return {
|
|
195
|
+
tagName: 'open-layout',
|
|
196
|
+
importPath: '@openelement/ui/open-layout',
|
|
197
|
+
props: {}
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
tagName: config.tagName,
|
|
202
|
+
importPath: normalizeAppShellImport(config.import),
|
|
203
|
+
props: config.props ?? {}
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
function buildAppShellPlan(options) {
|
|
207
|
+
const defaultShell = normalizeAppShell(options.layouts?.default ?? options.appShell);
|
|
208
|
+
const layouts = {};
|
|
209
|
+
for (const [name, config] of Object.entries(options.layouts ?? {})){
|
|
210
|
+
if (name === 'default' || config === undefined) continue;
|
|
211
|
+
layouts[name] = normalizeAppShell(config);
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
default: defaultShell,
|
|
215
|
+
layouts
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
export function buildEntryDescriptor(routes, options = {}) {
|
|
219
|
+
const routesDir = options.routesDir || 'app/routes';
|
|
220
|
+
const islandsDir = options.islandsDir || 'app/islands';
|
|
221
|
+
const isSSG = options.ssg === true;
|
|
222
|
+
// --- Imports ---
|
|
223
|
+
const imports = [];
|
|
224
|
+
// Always needed
|
|
225
|
+
imports.push({
|
|
226
|
+
from: 'hono',
|
|
227
|
+
names: [
|
|
228
|
+
'Hono'
|
|
229
|
+
]
|
|
230
|
+
});
|
|
231
|
+
imports.push({
|
|
232
|
+
from: '@openelement/core',
|
|
233
|
+
names: [
|
|
234
|
+
'renderDsd',
|
|
235
|
+
'renderDsdTree',
|
|
236
|
+
'escapeHtml'
|
|
237
|
+
]
|
|
238
|
+
});
|
|
239
|
+
// Conditional middleware imports
|
|
240
|
+
const mw = options.middleware;
|
|
241
|
+
if (mw?.requestId !== false) {
|
|
242
|
+
imports.push({
|
|
243
|
+
from: 'hono/request-id',
|
|
244
|
+
names: [
|
|
245
|
+
'requestId'
|
|
246
|
+
]
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
if (mw?.logger !== false) {
|
|
250
|
+
imports.push({
|
|
251
|
+
from: 'hono/logger',
|
|
252
|
+
names: [
|
|
253
|
+
'logger'
|
|
254
|
+
],
|
|
255
|
+
alias: 'honoLogger'
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
if (mw?.cors !== false) {
|
|
259
|
+
imports.push({
|
|
260
|
+
from: 'hono/cors',
|
|
261
|
+
names: [
|
|
262
|
+
'cors'
|
|
263
|
+
]
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
if (mw?.securityHeaders !== false) {
|
|
267
|
+
imports.push({
|
|
268
|
+
from: 'hono/secure-headers',
|
|
269
|
+
names: [
|
|
270
|
+
'secureHeaders'
|
|
271
|
+
]
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
// --- Middleware ---
|
|
275
|
+
const middleware = [];
|
|
276
|
+
if (mw?.requestId !== false) {
|
|
277
|
+
middleware.push({
|
|
278
|
+
kind: 'requestId',
|
|
279
|
+
comment: '1. Request ID - base for logging and error tracking'
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
if (mw?.logger !== false) {
|
|
283
|
+
middleware.push({
|
|
284
|
+
kind: 'logger',
|
|
285
|
+
comment: '2. Logger - structured request logging'
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
if (mw?.cors !== false) {
|
|
289
|
+
let corsOrigin;
|
|
290
|
+
if (mw?.corsOrigin !== undefined) {
|
|
291
|
+
if (typeof mw.corsOrigin === 'string') {
|
|
292
|
+
corsOrigin = mw.corsOrigin;
|
|
293
|
+
} else if (Array.isArray(mw.corsOrigin)) {
|
|
294
|
+
corsOrigin = mw.corsOrigin;
|
|
295
|
+
} else {
|
|
296
|
+
corsOrigin = {
|
|
297
|
+
type: 'function',
|
|
298
|
+
body: mw.corsOrigin.toString()
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
middleware.push({
|
|
303
|
+
kind: 'cors',
|
|
304
|
+
comment: '3. CORS - Web Standards (no process.env)',
|
|
305
|
+
config: {
|
|
306
|
+
corsOrigin
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
if (mw?.securityHeaders !== false) {
|
|
311
|
+
middleware.push({
|
|
312
|
+
kind: 'securityHeaders',
|
|
313
|
+
comment: '4. Security headers'
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
if (mw?.csp) {
|
|
317
|
+
middleware.push({
|
|
318
|
+
kind: 'csp',
|
|
319
|
+
comment: '5. Content Security Policy',
|
|
320
|
+
config: {
|
|
321
|
+
csp: mw.csp
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
// --- Routes ---
|
|
326
|
+
const apiRoutes = routes.filter((r)=>r.type === 'api' && !r.special).map((r)=>({
|
|
327
|
+
kind: 'api',
|
|
328
|
+
path: r.path,
|
|
329
|
+
varName: `$${r.varName}`,
|
|
330
|
+
filePath: r.filePath,
|
|
331
|
+
importPath: `/${routesDir}/${r.filePath}`
|
|
332
|
+
}));
|
|
333
|
+
const pageRoutes = routes.filter((r)=>r.type === 'page' && !r.special).map((r)=>{
|
|
334
|
+
const isDynamic = r.path.includes(':');
|
|
335
|
+
const paramNames = isDynamic ? [
|
|
336
|
+
...r.path.matchAll(/:([^/]+)/g)
|
|
337
|
+
].map((m)=>m[1]) : [];
|
|
338
|
+
return {
|
|
339
|
+
kind: 'page',
|
|
340
|
+
path: r.path,
|
|
341
|
+
varName: `$${r.varName}`,
|
|
342
|
+
filePath: r.filePath,
|
|
343
|
+
defaultTagName: fileToTagName(r.filePath),
|
|
344
|
+
tagName: r.tagName || fileToTagName(r.filePath),
|
|
345
|
+
importPath: `/${routesDir}/${r.filePath}`,
|
|
346
|
+
isDynamic,
|
|
347
|
+
paramNames
|
|
348
|
+
};
|
|
349
|
+
});
|
|
350
|
+
// --- Special files: _renderer.ts / _middleware.ts (v0.3.0) ---
|
|
351
|
+
const specialRoutes = routes.filter((r)=>r.type === 'special');
|
|
352
|
+
const renderers = specialRoutes.filter((r)=>r.special === 'renderer').map((r)=>{
|
|
353
|
+
const scope = r.path.replace(/\/?_renderer$/, '') || '/';
|
|
354
|
+
const depth = scope === '/' ? 0 : scope.split('/').filter(Boolean).length;
|
|
355
|
+
return {
|
|
356
|
+
varName: `$${r.varName}`,
|
|
357
|
+
scope,
|
|
358
|
+
importPath: `/${routesDir}/${r.filePath}`,
|
|
359
|
+
depth
|
|
360
|
+
};
|
|
361
|
+
}).sort((a, b)=>b.depth - a.depth);
|
|
362
|
+
const middlewareScopes = specialRoutes.filter((r)=>r.special === 'middleware').map((r)=>({
|
|
363
|
+
varName: `$${r.varName}`,
|
|
364
|
+
scope: r.path.replace(/\/?_middleware$/, '') || '/',
|
|
365
|
+
importPath: `/${routesDir}/${r.filePath}`
|
|
366
|
+
}));
|
|
367
|
+
// --- Islands ---
|
|
368
|
+
const islandTagNames = options.islandTagNames || [];
|
|
369
|
+
const islandFiles = options.islandFiles || [];
|
|
370
|
+
const islandMeta = options.islandMeta || {};
|
|
371
|
+
const packageManifests = options.packageManifests || [];
|
|
372
|
+
const localIslands = islandTagNames.map((tagName, i)=>({
|
|
373
|
+
tagName,
|
|
374
|
+
modulePath: islandFiles[i] ? `/${islandsDir}/${islandFiles[i]}` : `/${islandsDir}/${tagName}.ts`,
|
|
375
|
+
source: 'local',
|
|
376
|
+
ssr: islandMeta[tagName]?.hydrate === 'only' ? false : islandMeta[tagName]?.ssr,
|
|
377
|
+
dsd: islandMeta[tagName]?.hydrate === 'only' ? false : islandMeta[tagName]?.dsd,
|
|
378
|
+
hydrate: islandMeta[tagName]?.hydrate || options.upgradeStrategy || 'idle',
|
|
379
|
+
reason: islandMeta[tagName]?.reason
|
|
380
|
+
}));
|
|
381
|
+
const packageIslandDecls = packageManifests.flatMap((pkg)=>pkg.declarations.filter((d)=>d.openElement?.module).map((d)=>{
|
|
382
|
+
const modulePath = d.openElement?.module;
|
|
383
|
+
if (!modulePath) {
|
|
384
|
+
throw new Error(`Package manifest declaration "${d.tagName}" is missing openElement.module`);
|
|
385
|
+
}
|
|
386
|
+
return {
|
|
387
|
+
tagName: d.tagName,
|
|
388
|
+
modulePath,
|
|
389
|
+
isPackage: true,
|
|
390
|
+
source: 'package',
|
|
391
|
+
hydrate: d.openElement?.hydrate || options.upgradeStrategy || 'idle',
|
|
392
|
+
ssr: d.openElement?.hydrate === 'only' ? false : d.openElement?.ssr,
|
|
393
|
+
dsd: d.openElement?.hydrate === 'only' ? false : d.openElement?.dsd
|
|
394
|
+
};
|
|
395
|
+
}));
|
|
396
|
+
const islands = [
|
|
397
|
+
...localIslands,
|
|
398
|
+
...packageIslandDecls
|
|
399
|
+
];
|
|
400
|
+
const cemClassifications = options.cemClassifications || [];
|
|
401
|
+
const ssrAdmissionPlan = buildSsrAdmissionPlan(islands, cemClassifications, options.clientOnlyTags || []);
|
|
402
|
+
// --- Document ---
|
|
403
|
+
const document = {
|
|
404
|
+
lang: options.html?.lang || 'en',
|
|
405
|
+
title: options.html?.title || 'openElement',
|
|
406
|
+
headExtras: options.headExtras || '',
|
|
407
|
+
allowHeadExtrasScripts: options.allowHeadExtrasScripts || false
|
|
408
|
+
};
|
|
409
|
+
const appShell = buildAppShellPlan({
|
|
410
|
+
appShell: options.appShell,
|
|
411
|
+
layouts: options.layouts
|
|
412
|
+
});
|
|
413
|
+
// --- Debug routes (dev only) ---
|
|
414
|
+
const debugRoutes = isSSG ? undefined : routes.filter((r)=>!r.special).map((r)=>({
|
|
415
|
+
path: r.path,
|
|
416
|
+
type: r.type
|
|
417
|
+
}));
|
|
418
|
+
return {
|
|
419
|
+
isSSG,
|
|
420
|
+
imports,
|
|
421
|
+
middleware,
|
|
422
|
+
apiRoutes,
|
|
423
|
+
pageRoutes,
|
|
424
|
+
islands,
|
|
425
|
+
ssrAdmissionPlan,
|
|
426
|
+
cemClassifications,
|
|
427
|
+
clientOnlyTags: options.clientOnlyTags,
|
|
428
|
+
renderers,
|
|
429
|
+
middlewareScopes,
|
|
430
|
+
document,
|
|
431
|
+
appShell,
|
|
432
|
+
upgradeStrategy: options.upgradeStrategy || 'idle',
|
|
433
|
+
debugRoutes
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
export function buildSsrAdmissionPlan(islands, cemClassifications = [], clientOnlyTags = []) {
|
|
437
|
+
const renderableTags = [];
|
|
438
|
+
const mergedClientOnlyTags = [];
|
|
439
|
+
const rejectedTags = [];
|
|
440
|
+
const reasons = {};
|
|
441
|
+
const decisions = [];
|
|
442
|
+
const seen = new Set();
|
|
443
|
+
const admittedTags = new Set();
|
|
444
|
+
const cemMap = new Map();
|
|
445
|
+
for (const classification of cemClassifications){
|
|
446
|
+
cemMap.set(classification.tagName, classification);
|
|
447
|
+
}
|
|
448
|
+
for (const island of islands){
|
|
449
|
+
const source = island.source || (island.isPackage ? 'package' : 'local');
|
|
450
|
+
if (seen.has(island.tagName)) {
|
|
451
|
+
const reason = 'duplicate custom element tag';
|
|
452
|
+
rejectedTags.push(island.tagName);
|
|
453
|
+
reasons[island.tagName] = reason;
|
|
454
|
+
if (admittedTags.has(island.tagName)) {
|
|
455
|
+
const rIdx = renderableTags.indexOf(island.tagName);
|
|
456
|
+
if (rIdx !== -1) renderableTags.splice(rIdx, 1);
|
|
457
|
+
const cIdx = mergedClientOnlyTags.indexOf(island.tagName);
|
|
458
|
+
if (cIdx !== -1) mergedClientOnlyTags.splice(cIdx, 1);
|
|
459
|
+
admittedTags.delete(island.tagName);
|
|
460
|
+
}
|
|
461
|
+
decisions.push({
|
|
462
|
+
tagName: island.tagName,
|
|
463
|
+
modulePath: island.modulePath,
|
|
464
|
+
source,
|
|
465
|
+
renderPath: 'rejected',
|
|
466
|
+
reason
|
|
467
|
+
});
|
|
468
|
+
continue;
|
|
469
|
+
}
|
|
470
|
+
seen.add(island.tagName);
|
|
471
|
+
let renderPath;
|
|
472
|
+
let reason;
|
|
473
|
+
const cemClassification = cemMap.get(island.tagName);
|
|
474
|
+
if (cemClassification) {
|
|
475
|
+
const TIER_RENDER_PATH = {
|
|
476
|
+
'ssr-capable': 'ssr+client',
|
|
477
|
+
'client-only': 'client-only',
|
|
478
|
+
'experimental-dom': 'client-only',
|
|
479
|
+
rejected: 'rejected'
|
|
480
|
+
};
|
|
481
|
+
const knownTier = cemClassification.tier in TIER_RENDER_PATH;
|
|
482
|
+
renderPath = TIER_RENDER_PATH[cemClassification.tier] ?? 'client-only';
|
|
483
|
+
reason = knownTier ? `CEM ${cemClassification.tier}: ${cemClassification.reason}` : `Unknown CEM tier (${cemClassification.tier}) - conservative default to client-only`;
|
|
484
|
+
} else if (island.hydrate === 'only') {
|
|
485
|
+
renderPath = 'client-only';
|
|
486
|
+
reason = island.reason || 'client:only island is excluded from SSR';
|
|
487
|
+
} else if (island.ssr === false) {
|
|
488
|
+
renderPath = 'client-only';
|
|
489
|
+
reason = island.reason || 'openElement.ssr is false';
|
|
490
|
+
} else if (source === 'package') {
|
|
491
|
+
if (island.ssr === true) {
|
|
492
|
+
renderPath = 'ssr+client';
|
|
493
|
+
reason = 'package island with openElement.ssr=true';
|
|
494
|
+
} else {
|
|
495
|
+
renderPath = 'client-only';
|
|
496
|
+
reason = 'package island has no validated SSR capability (conservative default)';
|
|
497
|
+
}
|
|
498
|
+
} else {
|
|
499
|
+
renderPath = 'ssr+client';
|
|
500
|
+
reason = island.ssr === true ? 'openElement.ssr is true' : 'local island default SSR path';
|
|
501
|
+
}
|
|
502
|
+
if (renderPath === 'ssr+client') {
|
|
503
|
+
renderableTags.push(island.tagName);
|
|
504
|
+
admittedTags.add(island.tagName);
|
|
505
|
+
}
|
|
506
|
+
if (renderPath === 'client-only') {
|
|
507
|
+
mergedClientOnlyTags.push(island.tagName);
|
|
508
|
+
admittedTags.add(island.tagName);
|
|
509
|
+
}
|
|
510
|
+
if (renderPath === 'rejected') {
|
|
511
|
+
rejectedTags.push(island.tagName);
|
|
512
|
+
admittedTags.delete(island.tagName);
|
|
513
|
+
}
|
|
514
|
+
reasons[island.tagName] = reason;
|
|
515
|
+
decisions.push({
|
|
516
|
+
tagName: island.tagName,
|
|
517
|
+
modulePath: island.modulePath,
|
|
518
|
+
source,
|
|
519
|
+
renderPath,
|
|
520
|
+
reason
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
for (const tag of clientOnlyTags){
|
|
524
|
+
if (!seen.has(tag) && !admittedTags.has(tag)) {
|
|
525
|
+
mergedClientOnlyTags.push(tag);
|
|
526
|
+
admittedTags.add(tag);
|
|
527
|
+
seen.add(tag);
|
|
528
|
+
reasons[tag] = 'Registry client-only component (ADR-0035)';
|
|
529
|
+
decisions.push({
|
|
530
|
+
tagName: tag,
|
|
531
|
+
modulePath: '',
|
|
532
|
+
source: 'nested',
|
|
533
|
+
renderPath: 'client-only',
|
|
534
|
+
reason: 'Registry client-only component (ADR-0035)'
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
return {
|
|
539
|
+
renderableTags,
|
|
540
|
+
clientOnlyTags: mergedClientOnlyTags,
|
|
541
|
+
rejectedTags,
|
|
542
|
+
reasons,
|
|
543
|
+
decisions,
|
|
544
|
+
cemClassifications
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Generate the Hono entry module code from scanned routes.
|
|
549
|
+
*
|
|
550
|
+
* Internally builds a descriptor-shaped object and renders it directly.
|
|
551
|
+
*/ export function generateHonoEntryCode(routes, options = {}) {
|
|
552
|
+
const descriptor = buildEntryDescriptor(routes, options);
|
|
553
|
+
return renderEntry(descriptor);
|
|
554
|
+
}
|
|
555
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9vcGVuZWxlbWVudC9vcGVuZWxlbWVudC9wYWNrYWdlcy9zc2cvc3JjL2VudHJ5LXJlbmRlcmVyLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQG9wZW5lbGVtZW50L2NvcmUgLSBFbnRyeSBSZW5kZXJlclxuICpcbiAqIFB1cmUgZnVuY3Rpb246IHJvdXRlcyArIG9wdGlvbnMgLT4gSG9ubyBlbnRyeSB2aXJ0dWFsIG1vZHVsZSBjb2RlLlxuICpcbiAqIG9wZW5FbGVtZW50IEFyY2hpdGVjdHVyZSAodjAuNS4wKTpcbiAqIC0gQVBJIHJvdXRlcyB1c2UgSG9ubyBzdGFuZGFyZCBhcHAucm91dGUoKSAobm90IGFwcC5hbGwgKyBmZXRjaCB0cmFuc2Zvcm0pXG4gKiAtIElzbGFuZCB1cGdyYWRlIGlzIGhhbmRsZWQgYnkgdGhlIGNsaWVudCBlbnRyeSAoYnVpbHQgYnkgVml0ZSBpbiBQaGFzZSAyKS5cbiAqICAgTm8gaW5saW5lIHNjcmlwdCBpbiBTU0cgSFRNTDsgdGhlIGNsaWVudCBlbnRyeSBpcyBhIFZpdGUtYnVpbHQgbW9kdWxlXG4gKiAgIHJlZmVyZW5jZWQgdmlhIDxzY3JpcHQgdHlwZT1cIm1vZHVsZVwiIHNyYz1cIi4uLlwiPiBhbmQgaW1wb3J0cyBpc2xhbmQgbW9kdWxlc1xuICogICBmb3Igc2lkZS1lZmZlY3QgY3VzdG9tIGVsZW1lbnQgcmVnaXN0cmF0aW9uLlxuICogLSBIVE1MIGRvY3VtZW50IHdyYXBwaW5nIGRlbGVnYXRlcyB0byB3cmFwSW5Eb2N1bWVudCBmcm9tIGh0bWwtZXNjYXBlLnRzXG4gKiAgIChpbXBvcnRlZCBhdCBydW50aW1lIC0gc2luZ2xlIHNvdXJjZSBvZiB0cnV0aCwgbm8gZHVwbGljYXRlIEhUTUwgbG9naWMpXG4gKiAtIERTRCBvdXRwdXQgbXVzdCByZW1haW4gcGxhaW4gSFRNTCwgd2l0aG91dCBMaXQgU1NSIG1hcmtlciBjb21tZW50cy5cbiAqXG4gKiBILTE2IEtOT1dOIElTU1VFOiBDaXJjdWxhciBkZXBlbmRlbmN5IGJldHdlZW4gYWRhcHRlci12aXRlIDwtPiBjb250ZW50XG4gKiAgIGFkYXB0ZXItdml0ZSBnZW5lcmF0ZXMgY29kZSB0aGF0IGltcG9ydHMgQG9wZW5lbGVtZW50L2NvbnRlbnQvc2l0ZW1hcFxuICogICBjb250ZW50IHBhY2thZ2UgaW1wb3J0cyBAb3BlbmVsZW1lbnQvYWRhcHRlci12aXRlL2J1aWxkLWNvbnRleHRcbiAqIFNoYXJlZCBjb250cmFjdHMgbm93IGxpdmUgaW4gQG9wZW5lbGVtZW50L2NvcmUsIEBvcGVuZWxlbWVudC9zc2csIEBvcGVuZWxlbWVudC9yb3V0ZXIsXG4gKiBhbmQgQG9wZW5lbGVtZW50L3NpZ25hbC4gR2VuZXJhdGVkIG9wdGlvbmFsIHBhY2thZ2UgaW1wb3J0cyBhcmUgc3RpbGwgZW1pdHRlZCBleHBsaWNpdGx5XG4gKiBzbyBjb25zdW1lciBpbXBvcnQgbWFwcyBjYW4gYmUgY2hlY2tlZC5cbiAqXG4gKiBUaGluIG9yY2hlc3RyYXRvcjogZGVsZWdhdGVzIGNvZGUgZ2VuZXJhdGlvbiB0byBmb2N1c2VkIHN1Yi1tb2R1bGVzOlxuICogICAtIGVudHJ5LXJlbmRlci1oZWxwZXJzLnRzICDigJQgaW5kaXZpZHVhbCBjb2RlIGZyYWdtZW50IGdlbmVyYXRvcnNcbiAqICAgLSBlbnRyeS1yZW5kZXItcnVudGltZS50cyAg4oCUIHJ1bnRpbWUgaGVscGVyIGZ1bmN0aW9uIGNvZGUgZ2VuZXJhdGlvblxuICogICAtIGVudHJ5LXJlbmRlci1zc2cudHMgICAgICDigJQgU1NHIHJlLWV4cG9ydCAmIHJvdXRlSW5mby9yZW5kZXJSb3V0ZS9nZXRTdGF0aWNQYXRoc1xuICpcbiAqIHYwLjQxLjAtYWxwaGEuMTogVGhlIGludGVybWVkaWF0ZSBFbnRyeURlc2NyaXB0b3IgZGF0YSBtb2RlbCB3YXMgY29sbGFwc2VkXG4gKiBpbnRvIHRoaXMgZmlsZS4gYGdlbmVyYXRlSG9ub0VudHJ5Q29kZSgpYCBidWlsZHMgZGVzY3JpcHRvci1zaGFwZWQgZGF0YSBhbmRcbiAqIHBhc3NlcyBpdCBkaXJlY3RseSB0byBgcmVuZGVyRW50cnkoKWAgd2l0aG91dCBhIHNlcGFyYXRlIHB1YmxpYyBkZXNjcmlwdG9yXG4gKiBidWlsZGVyIG9yIGZpbGUuXG4gKi9cblxuaW1wb3J0IHR5cGUge1xuICBBcGlSb3V0ZURlY2wsXG4gIEFwcFNoZWxsUGxhbixcbiAgQ29yc09yaWdpbkNvbmZpZyxcbiAgRG9jdW1lbnRDb25maWcsXG4gIEVudHJ5RGVzY3JpcHRvcixcbiAgSW1wb3J0RGVjbCxcbiAgSXNsYW5kRGVjbCxcbiAgTWlkZGxld2FyZURlY2wsXG4gIFBhZ2VSb3V0ZURlY2wsXG4gIFJlbmRlcmVyRGVjbCxcbiAgUmVzb2x2ZWRBcHBTaGVsbCxcbiAgU3NyQWRtaXNzaW9uUGxhbixcbn0gZnJvbSAnQG9wZW5lbGVtZW50L3Byb3RvY29sL3NzZyc7XG5pbXBvcnQgdHlwZSB7XG4gIEFwcFNoZWxsQ29uZmlnLFxuICBDb21wYXRpYmlsaXR5Q2xhc3NpZmljYXRpb24sXG4gIEZyYW1ld29ya09wdGlvbnMsXG4gIEh5ZHJhdGlvblN0cmF0ZWd5LFxuICBSb3V0ZUVudHJ5LFxufSBmcm9tICdAb3BlbmVsZW1lbnQvcHJvdG9jb2wvZnJhbWV3b3JrJztcbmltcG9ydCB0eXBlIHsgT3BlbkVsZW1lbnRQYWNrYWdlTWFuaWZlc3QgfSBmcm9tICdAb3BlbmVsZW1lbnQvcHJvdG9jb2wvbWFuaWZlc3QnO1xuaW1wb3J0IHR5cGUgeyBTc3JBZG1pc3Npb25EZWNpc2lvbiB9IGZyb20gJ0BvcGVuZWxlbWVudC9wcm90b2NvbC9yZW5kZXInO1xuaW1wb3J0IHsgZmlsZVRvVGFnTmFtZSB9IGZyb20gJy4vcm91dGUtc2Nhbm5lci5qcyc7XG5pbXBvcnQge1xuICByZW5kZXJBY3Rpb25Sb3V0ZSxcbiAgcmVuZGVyQXBpUm91dGUsXG4gIHJlbmRlckRhdGFFbmRwb2ludCxcbiAgcmVuZGVyRGF0YVJvdXRlTWFwLFxuICByZW5kZXJJbXBvcnQsXG4gIHJlbmRlck1pZGRsZXdhcmUsXG4gIHJlbmRlclBhZ2VSb3V0ZSxcbiAgcm91dGVUYWdOYW1lRXhwcixcbn0gZnJvbSAnLi9lbnRyeS1yZW5kZXItaGVscGVycy5qcyc7XG5pbXBvcnQgeyByZW5kZXJSdW50aW1lSGVscGVycyB9IGZyb20gJy4vZW50cnktcmVuZGVyLXJ1bnRpbWUuanMnO1xuaW1wb3J0IHsgcmVuZGVyU3NnU2VjdGlvbiB9IGZyb20gJy4vZW50cnktcmVuZGVyLXNzZy5qcyc7XG5cbi8vIFJlLWV4cG9ydCB0aGUgY2Fub25pY2FsIGRlc2NyaXB0b3IgdHlwZSBmb3IgY29uc3VtZXJzIHRoYXQgbmVlZCBpdC5cbmV4cG9ydCB0eXBlIHsgRW50cnlEZXNjcmlwdG9yIH0gZnJvbSAnQG9wZW5lbGVtZW50L3Byb3RvY29sL3NzZyc7XG5cbi8qKlxuICogUmVuZGVyIGFuIEVudHJ5RGVzY3JpcHRvciBpbnRvIGEgY29tcGxldGUgdmlydHVhbCBtb2R1bGUgc3RyaW5nLlxuICpcbiAqIFB1cmUgZnVuY3Rpb24gLSBkZXRlcm1pbmlzdGljLCB0ZXN0YWJsZSwgc2lkZS1lZmZlY3QtZnJlZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlbmRlckVudHJ5KGRlc2M6IEVudHJ5RGVzY3JpcHRvcik6IHN0cmluZyB7XG4gIGNvbnN0IGxpbmVzOiBzdHJpbmdbXSA9IFtdO1xuICBjb25zdCBzc3JBZG1pc3Npb25QbGFuID0gZGVzYy5zc3JBZG1pc3Npb25QbGFuO1xuXG4gIC8vIC0tLSBJbXBvcnRzIC0tLVxuICBmb3IgKGNvbnN0IGltcCBvZiBkZXNjLmltcG9ydHMpIHtcbiAgICBsaW5lcy5wdXNoKHJlbmRlckltcG9ydChpbXApKTtcbiAgfVxuXG4gIC8vIC0tLSBJc2xhbmQgbG9va3VwIChidWlsZC10aW1lIGtub3duIGxpc3QpIC0tLVxuICBjb25zdCBpc2xhbmRMb29rdXA6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7fTtcbiAgZm9yIChjb25zdCBpc2xhbmQgb2YgZGVzYy5pc2xhbmRzKSB7XG4gICAgaXNsYW5kTG9va3VwW2lzbGFuZC50YWdOYW1lXSA9IGlzbGFuZC5tb2R1bGVQYXRoO1xuICB9XG4gIGNvbnN0IGFwcFNoZWxsSW1wb3J0cyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICBjb25zdCBjb2xsZWN0U2hlbGxJbXBvcnQgPSAoc2hlbGw6IHR5cGVvZiBkZXNjLmFwcFNoZWxsLmRlZmF1bHQpID0+IHtcbiAgICBpZiAoc2hlbGwpIGFwcFNoZWxsSW1wb3J0cy5hZGQoc2hlbGwuaW1wb3J0UGF0aCk7XG4gIH07XG4gIGNvbGxlY3RTaGVsbEltcG9ydChkZXNjLmFwcFNoZWxsLmRlZmF1bHQpO1xuICBmb3IgKGNvbnN0IHNoZWxsIG9mIE9iamVjdC52YWx1ZXMoZGVzYy5hcHBTaGVsbC5sYXlvdXRzKSkgY29sbGVjdFNoZWxsSW1wb3J0KHNoZWxsKTtcblxuICBsaW5lcy5wdXNoKFxuICAgIGAvLyBLbm93biBpc2xhbmRzIChkZXRlcm1pbmVkIGF0IGJ1aWxkIHRpbWUgYnkgc2Nhbm5pbmcgaXNsYW5kc0RpcilgLFxuICApO1xuICBsaW5lcy5wdXNoKGBjb25zdCBfX2lzbGFuZE1hcCA9ICR7SlNPTi5zdHJpbmdpZnkoaXNsYW5kTG9va3VwKX1gKTtcbiAgbGluZXMucHVzaCgnJyk7XG5cbiAgLy8gLS0tIERvY3VtZW50IHdyYXBwZXIgLS0tXG4gIGxpbmVzLnB1c2goYGltcG9ydCB7IHdyYXBJbkRvY3VtZW50IH0gZnJvbSAnQG9wZW5lbGVtZW50L2NvcmUnO2ApO1xuICBsaW5lcy5wdXNoKGBpbXBvcnQgeyBqc3ggfSBmcm9tICdAb3BlbmVsZW1lbnQvY29yZS9qc3gtcnVudGltZSc7YCk7XG4gIGxpbmVzLnB1c2goYGltcG9ydCB7IGNyZWF0ZUxvZ2dlciB9IGZyb20gJ0BvcGVuZWxlbWVudC9jb3JlL2xvZ2dlcic7YCk7XG4gIGxpbmVzLnB1c2goYGltcG9ydCB7IGNyZWF0ZVJ1bnRpbWVBZGFwdGVyIH0gZnJvbSAnQG9wZW5lbGVtZW50L2NvcmUvcnVudGltZSc7YCk7XG4gIGxpbmVzLnB1c2goXG4gICAgYGltcG9ydCB7IGhlYWRlck5hdiBhcyBfX2hlYWRlck5hdiwgbmF2U2VjdGlvbnMgYXMgX19uYXZTZWN0aW9ucyB9IGZyb20gJ0BvcGVuZWxlbWVudC9nZW5lcmF0ZWQvbmF2JztgLFxuICApO1xuICBsaW5lcy5wdXNoKFxuICAgIGBpbXBvcnQgeyBnZXREZWZhdWx0TG9jYWxlIGFzIF9fZ2V0RGVmYXVsdExvY2FsZSwgbG9jYWxlcyBhcyBfX2xvY2FsZXMgfSBmcm9tICdAb3BlbmVsZW1lbnQvZ2VuZXJhdGVkL2kxOG4nO2AsXG4gICk7XG4gIGZvciAoY29uc3QgaW1wb3J0UGF0aCBvZiBhcHBTaGVsbEltcG9ydHMpIHtcbiAgICBsaW5lcy5wdXNoKGBpbXBvcnQgJyR7aW1wb3J0UGF0aH0nO2ApO1xuICB9XG4gIGxpbmVzLnB1c2goYGNvbnN0IGxvZyA9IGNyZWF0ZUxvZ2dlcignY29yZScpO2ApO1xuICBsaW5lcy5wdXNoKCcnKTtcblxuICAvLyAtLS0gUm91dGUgbW9kdWxlIGltcG9ydHMgLS0tXG4gIGZvciAoY29uc3Qgcm91dGUgb2YgWy4uLmRlc2MuYXBpUm91dGVzLCAuLi5kZXNjLnBhZ2VSb3V0ZXNdKSB7XG4gICAgbGluZXMucHVzaChgaW1wb3J0ICogYXMgJHtyb3V0ZS52YXJOYW1lfSBmcm9tICcke3JvdXRlLmltcG9ydFBhdGh9J2ApO1xuICB9XG4gIGZvciAoY29uc3QgcmVuZGVyZXIgb2YgZGVzYy5yZW5kZXJlcnMpIHtcbiAgICBsaW5lcy5wdXNoKGBpbXBvcnQgKiBhcyAke3JlbmRlcmVyLnZhck5hbWV9IGZyb20gJyR7cmVuZGVyZXIuaW1wb3J0UGF0aH0nYCk7XG4gIH1cbiAgZm9yIChjb25zdCBtd1Njb3BlIG9mIGRlc2MubWlkZGxld2FyZVNjb3Blcykge1xuICAgIGxpbmVzLnB1c2goYGltcG9ydCAqIGFzICR7bXdTY29wZS52YXJOYW1lfSBmcm9tICcke213U2NvcGUuaW1wb3J0UGF0aH0nYCk7XG4gIH1cbiAgbGluZXMucHVzaCgnJyk7XG5cbiAgLy8gLS0tIFJlZ2lzdGVyIHBhZ2UgY29tcG9uZW50cyBpbiBTU1IgY3VzdG9tRWxlbWVudHMgcmVnaXN0cnkgLS0tXG4gIHtcbiAgICBsaW5lcy5wdXNoKCcvLyBBRFIgMDAxNDogSWRlbXBvdGVudCBjdXN0b21FbGVtZW50cy5kZWZpbmUgZm9yIFNTUiAoZGV2ICsgU1NHKScpO1xuICAgIGxpbmVzLnB1c2goXG4gICAgICAnLy8gSXNsYW5kIG1vZHVsZXMgY2FsbCBjdXN0b21FbGVtZW50cy5kZWZpbmUoKSBhcyBhIHNpZGUtZWZmZWN0LicsXG4gICAgKTtcbiAgICBsaW5lcy5wdXNoKFxuICAgICAgJy8vIFRoZSBTU1IgZG9tLXNoaW0gZG9lcyBub3QgbWFrZSBkZWZpbmUoKSBpZGVtcG90ZW50LCBzbyB3ZSBwYXRjaCBpdC4nLFxuICAgICk7XG4gICAgbGluZXMucHVzaChcbiAgICAgICdjb25zdCBfb3JpZ0RlZmluZSA9IGN1c3RvbUVsZW1lbnRzLmRlZmluZS5iaW5kKGN1c3RvbUVsZW1lbnRzKTsnLFxuICAgICk7XG4gICAgbGluZXMucHVzaCgnY3VzdG9tRWxlbWVudHMuZGVmaW5lID0gKG5hbWUsIGN0b3IsIG9wdGlvbnMpID0+IHsnKTtcbiAgICBsaW5lcy5wdXNoKCcgIGlmIChjdXN0b21FbGVtZW50cy5nZXQobmFtZSkpIHJldHVybjsnKTtcbiAgICBsaW5lcy5wdXNoKFxuICAgICAgJyAgdHJ5IHsgX29yaWdEZWZpbmUobmFtZSwgY3Rvciwgb3B0aW9ucyk7IH0gY2F0Y2ggeyAvKiBhbHJlYWR5IGRlZmluZWQgKi8gfScsXG4gICAgKTtcbiAgICBsaW5lcy5wdXNoKCd9OycpO1xuICAgIGxpbmVzLnB1c2goJycpO1xuICB9XG4gIGZvciAoY29uc3Qgcm91dGUgb2YgZGVzYy5wYWdlUm91dGVzKSB7XG4gICAgY29uc3QgdGFnTmFtZUV4cHIgPSByb3V0ZVRhZ05hbWVFeHByKHJvdXRlLnZhck5hbWUsIHJvdXRlLnRhZ05hbWUpO1xuICAgIGxpbmVzLnB1c2goXG4gICAgICBgaWYgKCFjdXN0b21FbGVtZW50cy5nZXQoJHt0YWdOYW1lRXhwcn0pKSB7YCxcbiAgICApO1xuICAgIGxpbmVzLnB1c2goXG4gICAgICBgICBjdXN0b21FbGVtZW50cy5kZWZpbmUoJHt0YWdOYW1lRXhwcn0sICR7cm91dGUudmFyTmFtZX0uZGVmYXVsdClgLFxuICAgICk7XG4gICAgbGluZXMucHVzaChgfWApO1xuICB9XG4gIGxpbmVzLnB1c2goJycpO1xuXG4gIC8vIC0tLSBSZWdpc3RlciBpc2xhbmQgY29tcG9uZW50cyBpbiBTU1IgY3VzdG9tRWxlbWVudHMgcmVnaXN0cnkgLS0tXG4gIGNvbnN0IHNzclJlbmRlcmFibGVUYWdzID0gbmV3IFNldChzc3JBZG1pc3Npb25QbGFuLnJlbmRlcmFibGVUYWdzKTtcbiAgY29uc3Qgc3NySXNsYW5kcyA9IGRlc2MuaXNsYW5kcy5maWx0ZXIoKGlzbGFuZCkgPT4gc3NyUmVuZGVyYWJsZVRhZ3MuaGFzKGlzbGFuZC50YWdOYW1lKSk7XG4gIGZvciAoY29uc3QgaXNsYW5kIG9mIHNzcklzbGFuZHMpIHtcbiAgICBjb25zdCB2YXJOYW1lID0gYF9faXNsYW5kXyR7aXNsYW5kLnRhZ05hbWUucmVwbGFjZSgvLS9nLCAnXycpfWA7XG4gICAgbGluZXMucHVzaChgaW1wb3J0ICogYXMgJHt2YXJOYW1lfSBmcm9tICcke2lzbGFuZC5tb2R1bGVQYXRofSdgKTtcbiAgfVxuICBmb3IgKGNvbnN0IGlzbGFuZCBvZiBzc3JJc2xhbmRzKSB7XG4gICAgY29uc3QgdmFyTmFtZSA9IGBfX2lzbGFuZF8ke2lzbGFuZC50YWdOYW1lLnJlcGxhY2UoLy0vZywgJ18nKX1gO1xuICAgIGNvbnN0IGNvbXBvbmVudFZhciA9IGBfX2lzbGFuZF9jb21wb25lbnRfJHtpc2xhbmQudGFnTmFtZS5yZXBsYWNlKC8tL2csICdfJyl9YDtcbiAgICBsaW5lcy5wdXNoKGBjb25zdCAke2NvbXBvbmVudFZhcn0gPSAke3Zhck5hbWV9Py5kZWZhdWx0YCk7XG4gICAgbGluZXMucHVzaChcbiAgICAgIGBpZiAoJHtjb21wb25lbnRWYXJ9ICYmICFjdXN0b21FbGVtZW50cy5nZXQoJyR7aXNsYW5kLnRhZ05hbWV9JykpIHtgLFxuICAgICk7XG4gICAgbGluZXMucHVzaChgICBjdXN0b21FbGVtZW50cy5kZWZpbmUoJyR7aXNsYW5kLnRhZ05hbWV9JywgJHtjb21wb25lbnRWYXJ9KWApO1xuICAgIGxpbmVzLnB1c2goYH1gKTtcbiAgfVxuICBsaW5lcy5wdXNoKCcnKTtcblxuICBsaW5lcy5wdXNoKCcvLyB2MC4xNy40OiBTU1IgYWRtaXNzaW9uIHBsYW4nKTtcbiAgbGluZXMucHVzaChcbiAgICBgKGdsb2JhbFRoaXMpLl9fQ0xJRU5UX09OTFlfVEFHU19fID0gbmV3IFNldCgke1xuICAgICAgSlNPTi5zdHJpbmdpZnkoc3NyQWRtaXNzaW9uUGxhbi5jbGllbnRPbmx5VGFncylcbiAgICB9KWAsXG4gICk7XG4gIGxpbmVzLnB1c2goXG4gICAgYGV4cG9ydCBjb25zdCBzc3JBZG1pc3Npb25QbGFuID0gJHtKU09OLnN0cmluZ2lmeShzc3JBZG1pc3Npb25QbGFuLCBudWxsLCAyKX07YCxcbiAgKTtcbiAgbGluZXMucHVzaCgnJyk7XG5cbiAgLy8gLS0tIFNTRzogaGVhZEV4dHJhcyB2aWEgZGVmaW5lIGluamVjdGlvbiAtLS1cbiAgaWYgKGRlc2MuaXNTU0cgJiYgZGVzYy5kb2N1bWVudC5oZWFkRXh0cmFzKSB7XG4gICAgbGluZXMucHVzaChcbiAgICAgICcvLyBTU0c6IGhlYWRFeHRyYXMgaW5qZWN0ZWQgdmlhIFZpdGUgZGVmaW5lIChBRFIgMDAwOCBQaGFzZSBBKScsXG4gICAgKTtcbiAgICBsaW5lcy5wdXNoKCcvLyBSZXBsYWNlcyB0aGUgb2xkIC5vcGVuRWxlbWVudC9oZWFkLWV4dHJhcy5odG1sIHJ1bnRpbWUgZmlsZSByZWFkJyk7XG4gICAgbGluZXMucHVzaCgnY29uc3QgX19oZWFkRXh0cmFzID0gX19IRUFEX0VYVFJBU19fIHx8IFwiXCI7Jyk7XG4gICAgbGluZXMucHVzaCgnJyk7XG4gIH1cblxuICAvLyAtLS0gUnVudGltZSBoZWxwZXJzIC0tLVxuICBsaW5lcy5wdXNoKHJlbmRlclJ1bnRpbWVIZWxwZXJzKGRlc2MuYXBwU2hlbGwpKTtcbiAgbGluZXMucHVzaCgnJyk7XG5cbiAgLy8gLS0tIEFwcCBjcmVhdGlvbiArIE1pZGRsZXdhcmUgLS0tXG4gIGxpbmVzLnB1c2goJ2NvbnN0IGFwcCA9IG5ldyBIb25vKCknKTtcbiAgbGluZXMucHVzaCgnJyk7XG5cbiAgZm9yIChjb25zdCBtdyBvZiBkZXNjLm1pZGRsZXdhcmUpIHtcbiAgICByZW5kZXJNaWRkbGV3YXJlKGxpbmVzLCBtdyk7XG4gIH1cblxuICAvLyAtLS0gTWlkZGxld2FyZSBzY29wZXMgKHYwLjMuMDogX21pZGRsZXdhcmUudHMgZmlsZXMpIC0tLVxuICBmb3IgKGNvbnN0IG13U2NvcGUgb2YgZGVzYy5taWRkbGV3YXJlU2NvcGVzKSB7XG4gICAgbGluZXMucHVzaChgLy8gTWlkZGxld2FyZSBzY29wZTogJHttd1Njb3BlLnNjb3BlfSAoJHttd1Njb3BlLmltcG9ydFBhdGh9KWApO1xuICAgIGxpbmVzLnB1c2goXG4gICAgICBgYXBwLnVzZSgnJHttd1Njb3BlLnNjb3BlID09PSAnLycgPyAnJyA6IG13U2NvcGUuc2NvcGV9LyonLCAke213U2NvcGUudmFyTmFtZX0uZGVmYXVsdClgLFxuICAgICk7XG4gICAgbGluZXMucHVzaCgnJyk7XG4gIH1cblxuICAvLyAtLS0gQVBJIHJvdXRlcyAtLS1cbiAgZm9yIChjb25zdCByb3V0ZSBvZiBkZXNjLmFwaVJvdXRlcykge1xuICAgIHJlbmRlckFwaVJvdXRlKGxpbmVzLCByb3V0ZSk7XG4gIH1cblxuICAvLyAtLS0gUGFnZSByb3V0ZXMgLS0tXG4gIGNvbnN0IGRvY0NvbmZpZyA9IHtcbiAgICB0aXRsZTogZGVzYy5kb2N1bWVudC50aXRsZSxcbiAgICBsYW5nOiBkZXNjLmRvY3VtZW50LmxhbmcsXG4gICAgaGVhZEV4dHJhczogZGVzYy5kb2N1bWVudC5oZWFkRXh0cmFzLFxuICAgIGFsbG93SGVhZEV4dHJhc1NjcmlwdHM6IGRlc2MuZG9jdW1lbnQuYWxsb3dIZWFkRXh0cmFzU2NyaXB0cyxcbiAgfTtcbiAgZm9yIChjb25zdCByb3V0ZSBvZiBkZXNjLnBhZ2VSb3V0ZXMpIHtcbiAgICByZW5kZXJQYWdlUm91dGUobGluZXMsIHJvdXRlLCBkZXNjLnJlbmRlcmVycywgZG9jQ29uZmlnLCBkZXNjLmlzU1NHKTtcbiAgfVxuXG4gIC8vIC0tLSBBY3Rpb24gUE9TVCBoYW5kbGVycyAtLS1cbiAgZm9yIChjb25zdCByb3V0ZSBvZiBkZXNjLnBhZ2VSb3V0ZXMpIHtcbiAgICByZW5kZXJBY3Rpb25Sb3V0ZShsaW5lcywgcm91dGUsIGRlc2MucmVuZGVyZXJzLCBkb2NDb25maWcsIGRlc2MuaXNTU0cpO1xuICB9XG5cbiAgLy8gLS0tIC9fZGF0YSBlbmRwb2ludCBmb3IgU1BBIG5hdmlnYXRpb24gLS0tXG4gIHJlbmRlckRhdGFSb3V0ZU1hcChsaW5lcywgZGVzYy5wYWdlUm91dGVzKTtcbiAgcmVuZGVyRGF0YUVuZHBvaW50KGxpbmVzKTtcblxuICAvLyAtLS0gRXhwb3J0IC0tLVxuICBsaW5lcy5wdXNoKCdleHBvcnQgY29uc3Qgb3BlbkVsZW1lbnRIYW5kbGVyID0gKHJlcXVlc3QsIGNvbnRleHQgPSB7fSkgPT4geycpO1xuICBsaW5lcy5wdXNoKCcgIHJldHVybiBhcHAuZmV0Y2gocmVxdWVzdCwgY29udGV4dC5lbnYgfHwge30sIGNvbnRleHQucGxhdGZvcm0pJyk7XG4gIGxpbmVzLnB1c2goJ30nKTtcbiAgbGluZXMucHVzaCgnJyk7XG4gIGxpbmVzLnB1c2goJ2V4cG9ydCBjb25zdCBvcGVuRWxlbWVudFJ1bnRpbWVBZGFwdGVyID0geycpO1xuICBsaW5lcy5wdXNoKFwiICAuLi5jcmVhdGVSdW50aW1lQWRhcHRlcih7IG5hbWU6ICdvcGVuZWxlbWVudC1ob25vJywgZmV0Y2g6IG9wZW5FbGVtZW50SGFuZGxlciB9KSxcIik7XG4gIGxpbmVzLnB1c2goJ30nKTtcbiAgbGluZXMucHVzaCgnJyk7XG4gIGxpbmVzLnB1c2goJ2V4cG9ydCBkZWZhdWx0IGFwcCcpO1xuXG4gIC8vIC0tLSBTU0cgc2VjdGlvbiAtLS1cbiAgY29uc3Qgc3NnU2VjdGlvbiA9IHJlbmRlclNzZ1NlY3Rpb24oZGVzYyk7XG4gIGlmIChzc2dTZWN0aW9uKSB7XG4gICAgbGluZXMucHVzaChzc2dTZWN0aW9uKTtcbiAgfVxuXG4gIHJldHVybiBsaW5lcy5qb2luKCdcXG4nKTtcbn1cblxuZnVuY3Rpb24gbm9ybWFsaXplQXBwU2hlbGxJbXBvcnQoaW1wb3J0UGF0aDogc3RyaW5nKTogc3RyaW5nIHtcbiAgaWYgKGltcG9ydFBhdGguc3RhcnRzV2l0aCgnLi8nKSkgcmV0dXJuIGAvJHtpbXBvcnRQYXRoLnNsaWNlKDIpfWA7XG4gIGlmIChpbXBvcnRQYXRoLnN0YXJ0c1dpdGgoJy4uLycpKSByZXR1cm4gaW1wb3J0UGF0aDtcbiAgcmV0dXJuIGltcG9ydFBhdGg7XG59XG5cbmZ1bmN0aW9uIG5vcm1hbGl6ZUFwcFNoZWxsKGNvbmZpZzogQXBwU2hlbGxDb25maWcgfCB1bmRlZmluZWQpOiBSZXNvbHZlZEFwcFNoZWxsIHtcbiAgaWYgKGNvbmZpZyA9PT0gZmFsc2UpIHJldHVybiBmYWxzZTtcbiAgaWYgKGNvbmZpZyA9PT0gdW5kZWZpbmVkIHx8IGNvbmZpZyA9PT0gJ2RlZmF1bHQnKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHRhZ05hbWU6ICdvcGVuLWxheW91dCcsXG4gICAgICBpbXBvcnRQYXRoOiAnQG9wZW5lbGVtZW50L3VpL29wZW4tbGF5b3V0JyxcbiAgICAgIHByb3BzOiB7fSxcbiAgICB9O1xuICB9XG4gIHJldHVybiB7XG4gICAgdGFnTmFtZTogY29uZmlnLnRhZ05hbWUsXG4gICAgaW1wb3J0UGF0aDogbm9ybWFsaXplQXBwU2hlbGxJbXBvcnQoY29uZmlnLmltcG9ydCksXG4gICAgcHJvcHM6IGNvbmZpZy5wcm9wcyA/PyB7fSxcbiAgfTtcbn1cblxuZnVuY3Rpb24gYnVpbGRBcHBTaGVsbFBsYW4ob3B0aW9uczoge1xuICBhcHBTaGVsbD86IEZyYW1ld29ya09wdGlvbnNbJ2FwcFNoZWxsJ107XG4gIGxheW91dHM/OiBGcmFtZXdvcmtPcHRpb25zWydsYXlvdXRzJ107XG59KTogQXBwU2hlbGxQbGFuIHtcbiAgY29uc3QgZGVmYXVsdFNoZWxsID0gbm9ybWFsaXplQXBwU2hlbGwob3B0aW9ucy5sYXlvdXRzPy5kZWZhdWx0ID8/IG9wdGlvbnMuYXBwU2hlbGwpO1xuICBjb25zdCBsYXlvdXRzOiBSZWNvcmQ8c3RyaW5nLCBSZXNvbHZlZEFwcFNoZWxsPiA9IHt9O1xuICBmb3IgKGNvbnN0IFtuYW1lLCBjb25maWddIG9mIE9iamVjdC5lbnRyaWVzKG9wdGlvbnMubGF5b3V0cyA/PyB7fSkpIHtcbiAgICBpZiAobmFtZSA9PT0gJ2RlZmF1bHQnIHx8IGNvbmZpZyA9PT0gdW5kZWZpbmVkKSBjb250aW51ZTtcbiAgICBsYXlvdXRzW25hbWVdID0gbm9ybWFsaXplQXBwU2hlbGwoY29uZmlnKTtcbiAgfVxuICByZXR1cm4geyBkZWZhdWx0OiBkZWZhdWx0U2hlbGwsIGxheW91dHMgfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGJ1aWxkRW50cnlEZXNjcmlwdG9yKFxuICByb3V0ZXM6IFJvdXRlRW50cnlbXSxcbiAgb3B0aW9uczoge1xuICAgIHJvdXRlc0Rpcj86IHN0cmluZztcbiAgICBpc2xhbmRzRGlyPzogc3RyaW5nO1xuICAgIG1pZGRsZXdhcmU/OiBGcmFtZXdvcmtPcHRpb25zWydtaWRkbGV3YXJlJ107XG4gICAgc3NnPzogYm9vbGVhbjtcbiAgICBpc2xhbmRUYWdOYW1lcz86IHN0cmluZ1tdO1xuICAgIC8qKiBSZWxhdGl2ZSBmaWxlIHBhdGhzIGZvciBsb2NhbCBpc2xhbmRzIChwcmVzZXJ2ZXMgc3ViZGlyZWN0b3J5IHN0cnVjdHVyZSkgKi9cbiAgICBpc2xhbmRGaWxlcz86IHN0cmluZ1tdO1xuICAgIC8qKiBMb2NhbCBpc2xhbmQgbWV0YWRhdGEgaW5kZXhlZCBieSB0YWcgbmFtZS4gKi9cbiAgICBpc2xhbmRNZXRhPzogUmVjb3JkPHN0cmluZywgUGFydGlhbDxJc2xhbmREZWNsPj47XG4gICAgLyoqIFBhY2thZ2UgbWFuaWZlc3RzIGRpc2NvdmVyZWQgZnJvbSBucG0vSlNSIHBhY2thZ2VzICovXG4gICAgcGFja2FnZU1hbmlmZXN0cz86IE9wZW5FbGVtZW50UGFja2FnZU1hbmlmZXN0W107XG4gICAgLyoqIENFTS1kZXJpdmVkIGNvbXBhdGliaWxpdHkgY2xhc3NpZmljYXRpb25zIChmcm9tIGNvbXBhdGliaWxpdHkgY2xhc3NpZmllcikgKi9cbiAgICBjZW1DbGFzc2lmaWNhdGlvbnM/OiBDb21wYXRpYmlsaXR5Q2xhc3NpZmljYXRpb25bXTtcbiAgICAvKiogQHNlY3VyaXR5IEluamVjdGVkIGFzIHJhdyBIVE1MIHdpdGhvdXQgc2FuaXRpemF0aW9uICovXG4gICAgaGVhZEV4dHJhcz86IHN0cmluZztcbiAgICBhbGxvd0hlYWRFeHRyYXNTY3JpcHRzPzogYm9vbGVhbjtcbiAgICBodG1sPzogeyBsYW5nPzogc3RyaW5nOyB0aXRsZT86IHN0cmluZyB9O1xuICAgIHVwZ3JhZGVTdHJhdGVneT86IEh5ZHJhdGlvblN0cmF0ZWd5O1xuICAgIC8qKiBBZGRpdGlvbmFsIGNsaWVudC1vbmx5IHRhZyBuYW1lcyBmcm9tIGV4dGVybmFsIHJlZ2lzdHJpZXMgKEFEUi0wMDM1IEExKSAqL1xuICAgIGNsaWVudE9ubHlUYWdzPzogc3RyaW5nW107XG4gICAgYXBwU2hlbGw/OiBGcmFtZXdvcmtPcHRpb25zWydhcHBTaGVsbCddO1xuICAgIGxheW91dHM/OiBGcmFtZXdvcmtPcHRpb25zWydsYXlvdXRzJ107XG4gIH0gPSB7fSxcbik6IEVudHJ5RGVzY3JpcHRvciB7XG4gIGNvbnN0IHJvdXRlc0RpciA9IG9wdGlvbnMucm91dGVzRGlyIHx8ICdhcHAvcm91dGVzJztcbiAgY29uc3QgaXNsYW5kc0RpciA9IG9wdGlvbnMuaXNsYW5kc0RpciB8fCAnYXBwL2lzbGFuZHMnO1xuICBjb25zdCBpc1NTRyA9IG9wdGlvbnMuc3NnID09PSB0cnVlO1xuXG4gIC8vIC0tLSBJbXBvcnRzIC0tLVxuICBjb25zdCBpbXBvcnRzOiBJbXBvcnREZWNsW10gPSBbXTtcblxuICAvLyBBbHdheXMgbmVlZGVkXG4gIGltcG9ydHMucHVzaCh7IGZyb206ICdob25vJywgbmFtZXM6IFsnSG9ubyddIH0pO1xuICBpbXBvcnRzLnB1c2goe1xuICAgIGZyb206ICdAb3BlbmVsZW1lbnQvY29yZScsXG4gICAgbmFtZXM6IFsncmVuZGVyRHNkJywgJ3JlbmRlckRzZFRyZWUnLCAnZXNjYXBlSHRtbCddLFxuICB9KTtcblxuICAvLyBDb25kaXRpb25hbCBtaWRkbGV3YXJlIGltcG9ydHNcbiAgY29uc3QgbXcgPSBvcHRpb25zLm1pZGRsZXdhcmU7XG4gIGlmIChtdz8ucmVxdWVzdElkICE9PSBmYWxzZSkge1xuICAgIGltcG9ydHMucHVzaCh7IGZyb206ICdob25vL3JlcXVlc3QtaWQnLCBuYW1lczogWydyZXF1ZXN0SWQnXSB9KTtcbiAgfVxuICBpZiAobXc/LmxvZ2dlciAhPT0gZmFsc2UpIHtcbiAgICBpbXBvcnRzLnB1c2goeyBmcm9tOiAnaG9uby9sb2dnZXInLCBuYW1lczogWydsb2dnZXInXSwgYWxpYXM6ICdob25vTG9nZ2VyJyB9KTtcbiAgfVxuICBpZiAobXc/LmNvcnMgIT09IGZhbHNlKSB7XG4gICAgaW1wb3J0cy5wdXNoKHsgZnJvbTogJ2hvbm8vY29ycycsIG5hbWVzOiBbJ2NvcnMnXSB9KTtcbiAgfVxuICBpZiAobXc/LnNlY3VyaXR5SGVhZGVycyAhPT0gZmFsc2UpIHtcbiAgICBpbXBvcnRzLnB1c2goeyBmcm9tOiAnaG9uby9zZWN1cmUtaGVhZGVycycsIG5hbWVzOiBbJ3NlY3VyZUhlYWRlcnMnXSB9KTtcbiAgfVxuXG4gIC8vIC0tLSBNaWRkbGV3YXJlIC0tLVxuICBjb25zdCBtaWRkbGV3YXJlOiBNaWRkbGV3YXJlRGVjbFtdID0gW107XG5cbiAgaWYgKG13Py5yZXF1ZXN0SWQgIT09IGZhbHNlKSB7XG4gICAgbWlkZGxld2FyZS5wdXNoKHtcbiAgICAgIGtpbmQ6ICdyZXF1ZXN0SWQnLFxuICAgICAgY29tbWVudDogJzEuIFJlcXVlc3QgSUQgLSBiYXNlIGZvciBsb2dnaW5nIGFuZCBlcnJvciB0cmFja2luZycsXG4gICAgfSk7XG4gIH1cbiAgaWYgKG13Py5sb2dnZXIgIT09IGZhbHNlKSB7XG4gICAgbWlkZGxld2FyZS5wdXNoKHtcbiAgICAgIGtpbmQ6ICdsb2dnZXInLFxuICAgICAgY29tbWVudDogJzIuIExvZ2dlciAtIHN0cnVjdHVyZWQgcmVxdWVzdCBsb2dnaW5nJyxcbiAgICB9KTtcbiAgfVxuICBpZiAobXc/LmNvcnMgIT09IGZhbHNlKSB7XG4gICAgbGV0IGNvcnNPcmlnaW46IENvcnNPcmlnaW5Db25maWcgfCB1bmRlZmluZWQ7XG4gICAgaWYgKG13Py5jb3JzT3JpZ2luICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGlmICh0eXBlb2YgbXcuY29yc09yaWdpbiA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgY29yc09yaWdpbiA9IG13LmNvcnNPcmlnaW47XG4gICAgICB9IGVsc2UgaWYgKEFycmF5LmlzQXJyYXkobXcuY29yc09yaWdpbikpIHtcbiAgICAgICAgY29yc09yaWdpbiA9IG13LmNvcnNPcmlnaW47XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb3JzT3JpZ2luID0geyB0eXBlOiAnZnVuY3Rpb24nLCBib2R5OiBtdy5jb3JzT3JpZ2luLnRvU3RyaW5nKCkgfTtcbiAgICAgIH1cbiAgICB9XG4gICAgbWlkZGxld2FyZS5wdXNoKHtcbiAgICAgIGtpbmQ6ICdjb3JzJyxcbiAgICAgIGNvbW1lbnQ6ICczLiBDT1JTIC0gV2ViIFN0YW5kYXJkcyAobm8gcHJvY2Vzcy5lbnYpJyxcbiAgICAgIGNvbmZpZzogeyBjb3JzT3JpZ2luIH0sXG4gICAgfSk7XG4gIH1cbiAgaWYgKG13Py5zZWN1cml0eUhlYWRlcnMgIT09IGZhbHNlKSB7XG4gICAgbWlkZGxld2FyZS5wdXNoKHtcbiAgICAgIGtpbmQ6ICdzZWN1cml0eUhlYWRlcnMnLFxuICAgICAgY29tbWVudDogJzQuIFNlY3VyaXR5IGhlYWRlcnMnLFxuICAgIH0pO1xuICB9XG4gIGlmIChtdz8uY3NwKSB7XG4gICAgbWlkZGxld2FyZS5wdXNoKHtcbiAgICAgIGtpbmQ6ICdjc3AnLFxuICAgICAgY29tbWVudDogJzUuIENvbnRlbnQgU2VjdXJpdHkgUG9saWN5JyxcbiAgICAgIGNvbmZpZzogeyBjc3A6IG13LmNzcCB9LFxuICAgIH0pO1xuICB9XG5cbiAgLy8gLS0tIFJvdXRlcyAtLS1cbiAgY29uc3QgYXBpUm91dGVzOiBBcGlSb3V0ZURlY2xbXSA9IHJvdXRlc1xuICAgIC5maWx0ZXIoKHIpID0+IHIudHlwZSA9PT0gJ2FwaScgJiYgIXIuc3BlY2lhbClcbiAgICAubWFwKChyKSA9PiAoe1xuICAgICAga2luZDogJ2FwaScgYXMgY29uc3QsXG4gICAgICBwYXRoOiByLnBhdGgsXG4gICAgICB2YXJOYW1lOiBgJCR7ci52YXJOYW1lfWAsXG4gICAgICBmaWxlUGF0aDogci5maWxlUGF0aCxcbiAgICAgIGltcG9ydFBhdGg6IGAvJHtyb3V0ZXNEaXJ9LyR7ci5maWxlUGF0aH1gLFxuICAgIH0pKTtcblxuICBjb25zdCBwYWdlUm91dGVzOiBQYWdlUm91dGVEZWNsW10gPSByb3V0ZXNcbiAgICAuZmlsdGVyKChyKSA9PiByLnR5cGUgPT09ICdwYWdlJyAmJiAhci5zcGVjaWFsKVxuICAgIC5tYXAoKHIpID0+IHtcbiAgICAgIGNvbnN0IGlzRHluYW1pYyA9IHIucGF0aC5pbmNsdWRlcygnOicpO1xuICAgICAgY29uc3QgcGFyYW1OYW1lcyA9IGlzRHluYW1pYyA/IFsuLi5yLnBhdGgubWF0Y2hBbGwoLzooW14vXSspL2cpXS5tYXAoKG0pID0+IG1bMV0pIDogW107XG4gICAgICByZXR1cm4ge1xuICAgICAgICBraW5kOiAncGFnZScgYXMgY29uc3QsXG4gICAgICAgIHBhdGg6IHIucGF0aCxcbiAgICAgICAgdmFyTmFtZTogYCQke3IudmFyTmFtZX1gLFxuICAgICAgICBmaWxlUGF0aDogci5maWxlUGF0aCxcbiAgICAgICAgZGVmYXVsdFRhZ05hbWU6IGZpbGVUb1RhZ05hbWUoci5maWxlUGF0aCksXG4gICAgICAgIHRhZ05hbWU6IHIudGFnTmFtZSB8fCBmaWxlVG9UYWdOYW1lKHIuZmlsZVBhdGgpLFxuICAgICAgICBpbXBvcnRQYXRoOiBgLyR7cm91dGVzRGlyfS8ke3IuZmlsZVBhdGh9YCxcbiAgICAgICAgaXNEeW5hbWljLFxuICAgICAgICBwYXJhbU5hbWVzLFxuICAgICAgfTtcbiAgICB9KTtcblxuICAvLyAtLS0gU3BlY2lhbCBmaWxlczogX3JlbmRlcmVyLnRzIC8gX21pZGRsZXdhcmUudHMgKHYwLjMuMCkgLS0tXG4gIGNvbnN0IHNwZWNpYWxSb3V0ZXMgPSByb3V0ZXMuZmlsdGVyKChyKSA9PiByLnR5cGUgPT09ICdzcGVjaWFsJyk7XG5cbiAgY29uc3QgcmVuZGVyZXJzOiBSZW5kZXJlckRlY2xbXSA9IHNwZWNpYWxSb3V0ZXNcbiAgICAuZmlsdGVyKChyKSA9PiByLnNwZWNpYWwgPT09ICdyZW5kZXJlcicpXG4gICAgLm1hcCgocikgPT4ge1xuICAgICAgY29uc3Qgc2NvcGUgPSByLnBhdGgucmVwbGFjZSgvXFwvP19yZW5kZXJlciQvLCAnJykgfHwgJy8nO1xuICAgICAgY29uc3QgZGVwdGggPSBzY29wZSA9PT0gJy8nID8gMCA6IHNjb3BlLnNwbGl0KCcvJykuZmlsdGVyKEJvb2xlYW4pLmxlbmd0aDtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHZhck5hbWU6IGAkJHtyLnZhck5hbWV9YCxcbiAgICAgICAgc2NvcGUsXG4gICAgICAgIGltcG9ydFBhdGg6IGAvJHtyb3V0ZXNEaXJ9LyR7ci5maWxlUGF0aH1gLFxuICAgICAgICBkZXB0aCxcbiAgICAgIH07XG4gICAgfSlcbiAgICAuc29ydCgoYSwgYikgPT4gYi5kZXB0aCAtIGEuZGVwdGgpO1xuXG4gIGNvbnN0IG1pZGRsZXdhcmVTY29wZXMgPSBzcGVjaWFsUm91dGVzXG4gICAgLmZpbHRlcigocikgPT4gci5zcGVjaWFsID09PSAnbWlkZGxld2FyZScpXG4gICAgLm1hcCgocikgPT4gKHtcbiAgICAgIHZhck5hbWU6IGAkJHtyLnZhck5hbWV9YCxcbiAgICAgIHNjb3BlOiByLnBhdGgucmVwbGFjZSgvXFwvP19taWRkbGV3YXJlJC8sICcnKSB8fCAnLycsXG4gICAgICBpbXBvcnRQYXRoOiBgLyR7cm91dGVzRGlyfS8ke3IuZmlsZVBhdGh9YCxcbiAgICB9KSk7XG5cbiAgLy8gLS0tIElzbGFuZHMgLS0tXG4gIGNvbnN0IGlzbGFuZFRhZ05hbWVzID0gb3B0aW9ucy5pc2xhbmRUYWdOYW1lcyB8fCBbXTtcbiAgY29uc3QgaXNsYW5kRmlsZXMgPSBvcHRpb25zLmlzbGFuZEZpbGVzIHx8IFtdO1xuICBjb25zdCBpc2xhbmRNZXRhID0gb3B0aW9ucy5pc2xhbmRNZXRhIHx8IHt9O1xuICBjb25zdCBwYWNrYWdlTWFuaWZlc3RzID0gb3B0aW9ucy5wYWNrYWdlTWFuaWZlc3RzIHx8IFtdO1xuXG4gIGNvbnN0IGxvY2FsSXNsYW5kczogSXNsYW5kRGVjbFtdID0gaXNsYW5kVGFnTmFtZXMubWFwKCh0YWdOYW1lLCBpKSA9PiAoe1xuICAgIHRhZ05hbWUsXG4gICAgbW9kdWxlUGF0aDogaXNsYW5kRmlsZXNbaV1cbiAgICAgID8gYC8ke2lzbGFuZHNEaXJ9LyR7aXNsYW5kRmlsZXNbaV19YFxuICAgICAgOiBgLyR7aXNsYW5kc0Rpcn0vJHt0YWdOYW1lfS50c2AsXG4gICAgc291cmNlOiAnbG9jYWwnLFxuICAgIHNzcjogaXNsYW5kTWV0YVt0YWdOYW1lXT8uaHlkcmF0ZSA9PT0gJ29ubHknID8gZmFsc2UgOiBpc2xhbmRNZXRhW3RhZ05hbWVdPy5zc3IsXG4gICAgZHNkOiBpc2xhbmRNZXRhW3RhZ05hbWVdPy5oeWRyYXRlID09PSAnb25seScgPyBmYWxzZSA6IGlzbGFuZE1ldGFbdGFnTmFtZV0/LmRzZCxcbiAgICBoeWRyYXRlOiBpc2xhbmRNZXRhW3RhZ05hbWVdPy5oeWRyYXRlIHx8IG9wdGlvbnMudXBncmFkZVN0cmF0ZWd5IHx8ICdpZGxlJyxcbiAgICByZWFzb246IGlzbGFuZE1ldGFbdGFnTmFtZV0/LnJlYXNvbixcbiAgfSkpO1xuXG4gIGNvbnN0IHBhY2thZ2VJc2xhbmREZWNsczogSXNsYW5kRGVjbFtdID0gcGFja2FnZU1hbmlmZXN0cy5mbGF0TWFwKChwa2cpID0+XG4gICAgcGtnLmRlY2xhcmF0aW9uc1xuICAgICAgLmZpbHRlcigoZCkgPT4gZC5vcGVuRWxlbWVudD8ubW9kdWxlKVxuICAgICAgLm1hcCgoZCkgPT4ge1xuICAgICAgICBjb25zdCBtb2R1bGVQYXRoID0gZC5vcGVuRWxlbWVudD8ubW9kdWxlO1xuICAgICAgICBpZiAoIW1vZHVsZVBhdGgpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICBgUGFja2FnZSBtYW5pZmVzdCBkZWNsYXJhdGlvbiBcIiR7ZC50YWdOYW1lfVwiIGlzIG1pc3Npbmcgb3BlbkVsZW1lbnQubW9kdWxlYCxcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgdGFnTmFtZTogZC50YWdOYW1lLFxuICAgICAgICAgIG1vZHVsZVBhdGgsXG4gICAgICAgICAgaXNQYWNrYWdlOiB0cnVlLFxuICAgICAgICAgIHNvdXJjZTogJ3BhY2thZ2UnLFxuICAgICAgICAgIGh5ZHJhdGU6XG4gICAgICAgICAgICAoZC5vcGVuRWxlbWVudD8uaHlkcmF0ZSB8fCBvcHRpb25zLnVwZ3JhZGVTdHJhdGVneSB8fCAnaWRsZScpIGFzIElzbGFuZERlY2xbJ2h5ZHJhdGUnXSxcbiAgICAgICAgICBzc3I6IGQub3BlbkVsZW1lbnQ/Lmh5ZHJhdGUgPT09ICdvbmx5JyA/IGZhbHNlIDogZC5vcGVuRWxlbWVudD8uc3NyLFxuICAgICAgICAgIGRzZDogZC5vcGVuRWxlbWVudD8uaHlkcmF0ZSA9PT0gJ29ubHknID8gZmFsc2UgOiBkLm9wZW5FbGVtZW50Py5kc2QsXG4gICAgICAgIH07XG4gICAgICB9KVxuICApO1xuXG4gIGNvbnN0IGlzbGFuZHM6IElzbGFuZERlY2xbXSA9IFsuLi5sb2NhbElzbGFuZHMsIC4uLnBhY2thZ2VJc2xhbmREZWNsc107XG4gIGNvbnN0IGNlbUNsYXNzaWZpY2F0aW9ucyA9IG9wdGlvbnMuY2VtQ2xhc3NpZmljYXRpb25zIHx8IFtdO1xuICBjb25zdCBzc3JBZG1pc3Npb25QbGFuID0gYnVpbGRTc3JBZG1pc3Npb25QbGFuKFxuICAgIGlzbGFuZHMsXG4gICAgY2VtQ2xhc3NpZmljYXRpb25zLFxuICAgIG9wdGlvbnMuY2xpZW50T25seVRhZ3MgfHwgW10sXG4gICk7XG5cbiAgLy8gLS0tIERvY3VtZW50IC0tLVxuICBjb25zdCBkb2N1bWVudDogRG9jdW1lbnRDb25maWcgPSB7XG4gICAgbGFuZzogb3B0aW9ucy5odG1sPy5sYW5nIHx8ICdlbicsXG4gICAgdGl0bGU6IG9wdGlvbnMuaHRtbD8udGl0bGUgfHwgJ29wZW5FbGVtZW50JyxcbiAgICBoZWFkRXh0cmFzOiBvcHRpb25zLmhlYWRFeHRyYXMgfHwgJycsXG4gICAgYWxsb3dIZWFkRXh0cmFzU2NyaXB0czogb3B0aW9ucy5hbGxvd0hlYWRFeHRyYXNTY3JpcHRzIHx8IGZhbHNlLFxuICB9O1xuICBjb25zdCBhcHBTaGVsbCA9IGJ1aWxkQXBwU2hlbGxQbGFuKHtcbiAgICBhcHBTaGVsbDogb3B0aW9ucy5hcHBTaGVsbCxcbiAgICBsYXlvdXRzOiBvcHRpb25zLmxheW91dHMsXG4gIH0pO1xuXG4gIC8vIC0tLSBEZWJ1ZyByb3V0ZXMgKGRldiBvbmx5KSAtLS1cbiAgY29uc3QgZGVidWdSb3V0ZXMgPSBpc1NTRyA/IHVuZGVmaW5lZCA6IHJvdXRlc1xuICAgIC5maWx0ZXIoKHIpID0+ICFyLnNwZWNpYWwpXG4gICAgLm1hcCgocikgPT4gKHsgcGF0aDogci5wYXRoLCB0eXBlOiByLnR5cGUgfSkpO1xuXG4gIHJldHVybiB7XG4gICAgaXNTU0csXG4gICAgaW1wb3J0cyxcbiAgICBtaWRkbGV3YXJlLFxuICAgIGFwaVJvdXRlcyxcbiAgICBwYWdlUm91dGVzLFxuICAgIGlzbGFuZHMsXG4gICAgc3NyQWRtaXNzaW9uUGxhbixcbiAgICBjZW1DbGFzc2lmaWNhdGlvbnMsXG4gICAgY2xpZW50T25seVRhZ3M6IG9wdGlvbnMuY2xpZW50T25seVRhZ3MsXG4gICAgcmVuZGVyZXJzLFxuICAgIG1pZGRsZXdhcmVTY29wZXMsXG4gICAgZG9jdW1lbnQsXG4gICAgYXBwU2hlbGwsXG4gICAgdXBncmFkZVN0cmF0ZWd5OiBvcHRpb25zLnVwZ3JhZGVTdHJhdGVneSB8fCAnaWRsZScsXG4gICAgZGVidWdSb3V0ZXMsXG4gIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBidWlsZFNzckFkbWlzc2lvblBsYW4oXG4gIGlzbGFuZHM6IElzbGFuZERlY2xbXSxcbiAgY2VtQ2xhc3NpZmljYXRpb25zOiBDb21wYXRpYmlsaXR5Q2xhc3NpZmljYXRpb25bXSA9IFtdLFxuICBjbGllbnRPbmx5VGFnczogc3RyaW5nW10gPSBbXSxcbik6IFNzckFkbWlzc2lvblBsYW4ge1xuICBjb25zdCByZW5kZXJhYmxlVGFnczogc3RyaW5nW10gPSBbXTtcbiAgY29uc3QgbWVyZ2VkQ2xpZW50T25seVRhZ3M6IHN0cmluZ1tdID0gW107XG4gIGNvbnN0IHJlamVjdGVkVGFnczogc3RyaW5nW10gPSBbXTtcbiAgY29uc3QgcmVhc29uczogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHt9O1xuICBjb25zdCBkZWNpc2lvbnM6IFNzckFkbWlzc2lvbkRlY2lzaW9uW10gPSBbXTtcbiAgY29uc3Qgc2VlbiA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICBjb25zdCBhZG1pdHRlZFRhZ3MgPSBuZXcgU2V0PHN0cmluZz4oKTtcblxuICBjb25zdCBjZW1NYXAgPSBuZXcgTWFwPHN0cmluZywgQ29tcGF0aWJpbGl0eUNsYXNzaWZpY2F0aW9uPigpO1xuICBmb3IgKGNvbnN0IGNsYXNzaWZpY2F0aW9uIG9mIGNlbUNsYXNzaWZpY2F0aW9ucykge1xuICAgIGNlbU1hcC5zZXQoY2xhc3NpZmljYXRpb24udGFnTmFtZSwgY2xhc3NpZmljYXRpb24pO1xuICB9XG5cbiAgZm9yIChjb25zdCBpc2xhbmQgb2YgaXNsYW5kcykge1xuICAgIGNvbnN0IHNvdXJjZSA9IGlzbGFuZC5zb3VyY2UgfHwgKGlzbGFuZC5pc1BhY2thZ2UgPyAncGFja2FnZScgOiAnbG9jYWwnKTtcblxuICAgIGlmIChzZWVuLmhhcyhpc2xhbmQudGFnTmFtZSkpIHtcbiAgICAgIGNvbnN0IHJlYXNvbiA9ICdkdXBsaWNhdGUgY3VzdG9tIGVsZW1lbnQgdGFnJztcbiAgICAgIHJlamVjdGVkVGFncy5wdXNoKGlzbGFuZC50YWdOYW1lKTtcbiAgICAgIHJlYXNvbnNbaXNsYW5kLnRhZ05hbWVdID0gcmVhc29uO1xuXG4gICAgICBpZiAoYWRtaXR0ZWRUYWdzLmhhcyhpc2xhbmQudGFnTmFtZSkpIHtcbiAgICAgICAgY29uc3QgcklkeCA9IHJlbmRlcmFibGVUYWdzLmluZGV4T2YoaXNsYW5kLnRhZ05hbWUpO1xuICAgICAgICBpZiAocklkeCAhPT0gLTEpIHJlbmRlcmFibGVUYWdzLnNwbGljZShySWR4LCAxKTtcbiAgICAgICAgY29uc3QgY0lkeCA9IG1lcmdlZENsaWVudE9ubHlUYWdzLmluZGV4T2YoaXNsYW5kLnRhZ05hbWUpO1xuICAgICAgICBpZiAoY0lkeCAhPT0gLTEpIG1lcmdlZENsaWVudE9ubHlUYWdzLnNwbGljZShjSWR4LCAxKTtcbiAgICAgICAgYWRtaXR0ZWRUYWdzLmRlbGV0ZShpc2xhbmQudGFnTmFtZSk7XG4gICAgICB9XG5cbiAgICAgIGRlY2lzaW9ucy5wdXNoKHtcbiAgICAgICAgdGFnTmFtZTogaXNsYW5kLnRhZ05hbWUsXG4gICAgICAgIG1vZHVsZVBhdGg6IGlzbGFuZC5tb2R1bGVQYXRoLFxuICAgICAgICBzb3VyY2UsXG4gICAgICAgIHJlbmRlclBhdGg6ICdyZWplY3RlZCcsXG4gICAgICAgIHJlYXNvbixcbiAgICAgIH0pO1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIHNlZW4uYWRkKGlzbGFuZC50YWdOYW1lKTtcblxuICAgIGxldCByZW5kZXJQYXRoOiBTc3JBZG1pc3Npb25EZWNpc2lvblsncmVuZGVyUGF0aCddO1xuICAgIGxldCByZWFzb246IHN0cmluZztcblxuICAgIGNvbnN0IGNlbUNsYXNzaWZpY2F0aW9uID0gY2VtTWFwLmdldChpc2xhbmQudGFnTmFtZSk7XG5cbiAgICBpZiAoY2VtQ2xhc3NpZmljYXRpb24pIHtcbiAgICAgIGNvbnN0IFRJRVJfUkVOREVSX1BBVEg6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgICAgICdzc3ItY2FwYWJsZSc6ICdzc3IrY2xpZW50JyxcbiAgICAgICAgJ2NsaWVudC1vbmx5JzogJ2NsaWVudC1vbmx5JyxcbiAgICAgICAgJ2V4cGVyaW1lbnRhbC1kb20nOiAnY2xpZW50LW9ubHknLFxuICAgICAgICByZWplY3RlZDogJ3JlamVjdGVkJyxcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IGtub3duVGllciA9IGNlbUNsYXNzaWZpY2F0aW9uLnRpZXIgaW4gVElFUl9SRU5ERVJfUEFUSDtcbiAgICAgIHJlbmRlclBhdGggPSAoVElFUl9SRU5ERVJfUEFUSFtjZW1DbGFzc2lmaWNhdGlvbi50aWVyXSA/PyAnY2xpZW50LW9ubHknKSBhcyB0eXBlb2YgcmVuZGVyUGF0aDtcbiAgICAgIHJlYXNvbiA9IGtub3duVGllclxuICAgICAgICA/IGBDRU0gJHtjZW1DbGFzc2lmaWNhdGlvbi50aWVyfTogJHtjZW1DbGFzc2lmaWNhdGlvbi5yZWFzb259YFxuICAgICAgICA6IGBVbmtub3duIENFTSB0aWVyICgke2NlbUNsYXNzaWZpY2F0aW9uLnRpZXJ9KSAtIGNvbnNlcnZhdGl2ZSBkZWZhdWx0IHRvIGNsaWVudC1vbmx5YDtcbiAgICB9IGVsc2UgaWYgKGlzbGFuZC5oeWRyYXRlID09PSAnb25seScpIHtcbiAgICAgIHJlbmRlclBhdGggPSAnY2xpZW50LW9ubHknO1xuICAgICAgcmVhc29uID0gaXNsYW5kLnJlYXNvbiB8fCAnY2xpZW50Om9ubHkgaXNsYW5kIGlzIGV4Y2x1ZGVkIGZyb20gU1NSJztcbiAgICB9IGVsc2UgaWYgKGlzbGFuZC5zc3IgPT09IGZhbHNlKSB7XG4gICAgICByZW5kZXJQYXRoID0gJ2NsaWVudC1vbmx5JztcbiAgICAgIHJlYXNvbiA9IGlzbGFuZC5yZWFzb24gfHwgJ29wZW5FbGVtZW50LnNzciBpcyBmYWxzZSc7XG4gICAgfSBlbHNlIGlmIChzb3VyY2UgPT09ICdwYWNrYWdlJykge1xuICAgICAgaWYgKGlzbGFuZC5zc3IgPT09IHRydWUpIHtcbiAgICAgICAgcmVuZGVyUGF0aCA9ICdzc3IrY2xpZW50JztcbiAgICAgICAgcmVhc29uID0gJ3BhY2thZ2UgaXNsYW5kIHdpdGggb3BlbkVsZW1lbnQuc3NyPXRydWUnO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmVuZGVyUGF0aCA9ICdjbGllbnQtb25seSc7XG4gICAgICAgIHJlYXNvbiA9ICdwYWNrYWdlIGlzbGFuZCBoYXMgbm8gdmFsaWRhdGVkIFNTUiBjYXBhYmlsaXR5IChjb25zZXJ2YXRpdmUgZGVmYXVsdCknO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICByZW5kZXJQYXRoID0gJ3NzcitjbGllbnQnO1xuICAgICAgcmVhc29uID0gaXNsYW5kLnNzciA9PT0gdHJ1ZSA/ICdvcGVuRWxlbWVudC5zc3IgaXMgdHJ1ZScgOiAnbG9jYWwgaXNsYW5kIGRlZmF1bHQgU1NSIHBhdGgnO1xuICAgIH1cblxuICAgIGlmIChyZW5kZXJQYXRoID09PSAnc3NyK2NsaWVudCcpIHtcbiAgICAgIHJlbmRlcmFibGVUYWdzLnB1c2goaXNsYW5kLnRhZ05hbWUpO1xuICAgICAgYWRtaXR0ZWRUYWdzLmFkZChpc2xhbmQudGFnTmFtZSk7XG4gICAgfVxuICAgIGlmIChyZW5kZXJQYXRoID09PSAnY2xpZW50LW9ubHknKSB7XG4gICAgICBtZXJnZWRDbGllbnRPbmx5VGFncy5wdXNoKGlzbGFuZC50YWdOYW1lKTtcbiAgICAgIGFkbWl0dGVkVGFncy5hZGQoaXNsYW5kLnRhZ05hbWUpO1xuICAgIH1cbiAgICBpZiAocmVuZGVyUGF0aCA9PT0gJ3JlamVjdGVkJykge1xuICAgICAgcmVqZWN0ZWRUYWdzLnB1c2goaXNsYW5kLnRhZ05hbWUpO1xuICAgICAgYWRtaXR0ZWRUYWdzLmRlbGV0ZShpc2xhbmQudGFnTmFtZSk7XG4gICAgfVxuXG4gICAgcmVhc29uc1tpc2xhbmQudGFnTmFtZV0gPSByZWFzb247XG4gICAgZGVjaXNpb25zLnB1c2goe1xuICAgICAgdGFnTmFtZTogaXNsYW5kLnRhZ05hbWUsXG4gICAgICBtb2R1bGVQYXRoOiBpc2xhbmQubW9kdWxlUGF0aCxcbiAgICAgIHNvdXJjZSxcbiAgICAgIHJlbmRlclBhdGgsXG4gICAgICByZWFzb24sXG4gICAgfSk7XG4gIH1cblxuICBmb3IgKGNvbnN0IHRhZyBvZiBjbGllbnRPbmx5VGFncykge1xuICAgIGlmICghc2Vlbi5oYXModGFnKSAmJiAhYWRtaXR0ZWRUYWdzLmhhcyh0YWcpKSB7XG4gICAgICBtZXJnZWRDbGllbnRPbmx5VGFncy5wdXNoKHRhZyk7XG4gICAgICBhZG1pdHRlZFRhZ3MuYWRkKHRhZyk7XG4gICAgICBzZWVuLmFkZCh0YWcpO1xuICAgICAgcmVhc29uc1t0YWddID0gJ1JlZ2lzdHJ5IGNsaWVudC1vbmx5IGNvbXBvbmVudCAoQURSLTAwMzUpJztcbiAgICAgIGRlY2lzaW9ucy5wdXNoKHtcbiAgICAgICAgdGFnTmFtZTogdGFnLFxuICAgICAgICBtb2R1bGVQYXRoOiAnJyxcbiAgICAgICAgc291cmNlOiAnbmVzdGVkJyxcbiAgICAgICAgcmVuZGVyUGF0aDogJ2NsaWVudC1vbmx5JyxcbiAgICAgICAgcmVhc29uOiAnUmVnaXN0cnkgY2xpZW50LW9ubHkgY29tcG9uZW50IChBRFItMDAzNSknLFxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHtcbiAgICByZW5kZXJhYmxlVGFncyxcbiAgICBjbGllbnRPbmx5VGFnczogbWVyZ2VkQ2xpZW50T25seVRhZ3MsXG4gICAgcmVqZWN0ZWRUYWdzLFxuICAgIHJlYXNvbnMsXG4gICAgZGVjaXNpb25zLFxuICAgIGNlbUNsYXNzaWZpY2F0aW9ucyxcbiAgfTtcbn1cblxuLyoqIE9wdGlvbnMgZm9yIHRoZSBIb25vIGVudHJ5IGNvZGUgZ2VuZXJhdG9yICovXG5leHBvcnQgaW50ZXJmYWNlIEhvbm9FbnRyeU9wdGlvbnMge1xuICByb3V0ZXNEaXI/OiBzdHJpbmc7XG4gIGlzbGFuZHNEaXI/OiBzdHJpbmc7XG4gIGNvbXBvbmVudHNEaXI/OiBzdHJpbmc7XG4gIG1pZGRsZXdhcmU/OiBGcmFtZXdvcmtPcHRpb25zWydtaWRkbGV3YXJlJ107XG4gIHNzZz86IGJvb2xlYW47XG4gIGlzbGFuZFRhZ05hbWVzPzogc3RyaW5nW107XG4gIC8qKiBSZWxhdGl2ZSBmaWxlIHBhdGhzIGZvciBsb2NhbCBpc2xhbmRzIChwcmVzZXJ2ZXMgc3ViZGlyZWN0b3J5IHN0cnVjdHVyZSkgKi9cbiAgaXNsYW5kRmlsZXM/OiBzdHJpbmdbXTtcbiAgaXNsYW5kTWV0YT86IFJlY29yZDxzdHJpbmcsIFBhcnRpYWw8SXNsYW5kRGVjbD4+O1xuICBwYWNrYWdlTWFuaWZlc3RzPzogT3BlbkVsZW1lbnRQYWNrYWdlTWFuaWZlc3RbXTtcbiAgLyoqIEBzZWN1cml0eSBJbmplY3RlZCBhcyByYXcgSFRNTCB3aXRob3V0IHNhbml0aXphdGlvbiAqL1xuICBoZWFkRXh0cmFzPzogc3RyaW5nO1xuICBhbGxvd0hlYWRFeHRyYXNTY3JpcHRzPzogYm9vbGVhbjtcbiAgaHRtbD86IHsgbGFuZz86IHN0cmluZzsgdGl0bGU/OiBzdHJpbmcgfTtcbiAgdXBncmFkZVN0cmF0ZWd5PzogSHlkcmF0aW9uU3RyYXRlZ3k7XG4gIC8qKiBBZGRpdGlvbmFsIGNsaWVudC1vbmx5IHRhZyBuYW1lcyBmcm9tIGV4dGVybmFsIHJlZ2lzdHJpZXMgKEFEUi0wMDM1IEExKSAqL1xuICBjbGllbnRPbmx5VGFncz86IHN0cmluZ1tdO1xuICBhcHBTaGVsbD86IEZyYW1ld29ya09wdGlvbnNbJ2FwcFNoZWxsJ107XG4gIGxheW91dHM/OiBGcmFtZXdvcmtPcHRpb25zWydsYXlvdXRzJ107XG59XG5cbi8qKlxuICogR2VuZXJhdGUgdGhlIEhvbm8gZW50cnkgbW9kdWxlIGNvZGUgZnJvbSBzY2FubmVkIHJvdXRlcy5cbiAqXG4gKiBJbnRlcm5hbGx5IGJ1aWxkcyBhIGRlc2NyaXB0b3Itc2hhcGVkIG9iamVjdCBhbmQgcmVuZGVycyBpdCBkaXJlY3RseS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdlbmVyYXRlSG9ub0VudHJ5Q29kZShcbiAgcm91dGVzOiBSb3V0ZUVudHJ5W10sXG4gIG9wdGlvbnM6IEhvbm9FbnRyeU9wdGlvbnMgPSB7fSxcbik6IHN0cmluZyB7XG4gIGNvbnN0IGRlc2NyaXB0b3IgPSBidWlsZEVudHJ5RGVzY3JpcHRvcihyb3V0ZXMsIG9wdGlvbnMpO1xuICByZXR1cm4gcmVuZGVyRW50cnkoZGVzY3JpcHRvcik7XG59XG4iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Q0ErQkMsR0F5QkQsU0FBUyxhQUFhLFFBQVEscUJBQXFCO0FBQ25ELFNBQ0UsaUJBQWlCLEVBQ2pCLGNBQWMsRUFDZCxrQkFBa0IsRUFDbEIsa0JBQWtCLEVBQ2xCLFlBQVksRUFDWixnQkFBZ0IsRUFDaEIsZUFBZSxFQUNmLGdCQUFnQixRQUNYLDRCQUE0QjtBQUNuQyxTQUFTLG9CQUFvQixRQUFRLDRCQUE0QjtBQUNqRSxTQUFTLGdCQUFnQixRQUFRLHdCQUF3QjtBQUt6RDs7OztDQUlDLEdBQ0QsT0FBTyxTQUFTLFlBQVksSUFBcUI7RUFDL0MsTUFBTSxRQUFrQixFQUFFO0VBQzFCLE1BQU0sbUJBQW1CLEtBQUssZ0JBQWdCO0VBRTlDLGtCQUFrQjtFQUNsQixLQUFLLE1BQU0sT0FBTyxLQUFLLE9BQU8sQ0FBRTtJQUM5QixN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
|