@openuji/render-respec 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,19 @@
1
+ import type { LintResult } from '@openuji/speculator-lint';
2
+ export interface DiagnosticsByFile {
3
+ [file: string]: Array<{
4
+ code: string;
5
+ severity: 'error' | 'warning' | 'info';
6
+ message: string;
7
+ line?: number;
8
+ column?: number;
9
+ }>;
10
+ }
11
+ /**
12
+ * Group diagnostics by file
13
+ */
14
+ export declare function groupDiagnosticsByFile(lintResult: LintResult): DiagnosticsByFile;
15
+ /**
16
+ * Render diagnostics as HTML
17
+ */
18
+ export declare function renderDiagnosticsHtml(lintResult: LintResult): string;
19
+ //# sourceMappingURL=diagnostics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../../src/render/diagnostics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAE3D,MAAM,WAAW,iBAAiB;IAC9B,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;QACvC,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC,CAAC;CACN;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,UAAU,GAAG,iBAAiB,CAkBhF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CA2CpE"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Group diagnostics by file
3
+ */
4
+ export function groupDiagnosticsByFile(lintResult) {
5
+ const grouped = {};
6
+ for (const diagnostic of lintResult.diagnostics) {
7
+ const file = diagnostic.file || 'unknown';
8
+ if (!grouped[file]) {
9
+ grouped[file] = [];
10
+ }
11
+ grouped[file].push({
12
+ code: diagnostic.code,
13
+ severity: diagnostic.severity,
14
+ message: diagnostic.message,
15
+ line: diagnostic.sourcePos?.line,
16
+ column: diagnostic.sourcePos?.column,
17
+ });
18
+ }
19
+ return grouped;
20
+ }
21
+ /**
22
+ * Render diagnostics as HTML
23
+ */
24
+ export function renderDiagnosticsHtml(lintResult) {
25
+ const grouped = groupDiagnosticsByFile(lintResult);
26
+ const files = Object.keys(grouped);
27
+ if (files.length === 0) {
28
+ return '<div class="diagnostics-panel"><p>✅ No issues found</p></div>';
29
+ }
30
+ const sections = files.map(file => {
31
+ const diagnostics = grouped[file];
32
+ const items = diagnostics.map(d => {
33
+ const severityClass = `diagnostic-${d.severity}`;
34
+ const location = d.line ? ` (line ${d.line}${d.column ? `:${d.column}` : ''})` : '';
35
+ return `
36
+ <li class="${severityClass}">
37
+ <strong>${d.code}</strong>: ${d.message}${location}
38
+ </li>
39
+ `;
40
+ }).join('');
41
+ return `
42
+ <div class="diagnostic-file">
43
+ <h4>${file}</h4>
44
+ <ul class="diagnostic-list">
45
+ ${items}
46
+ </ul>
47
+ </div>
48
+ `;
49
+ }).join('');
50
+ const errorCount = lintResult.diagnostics.filter(d => d.severity === 'error').length;
51
+ const warningCount = lintResult.diagnostics.filter(d => d.severity === 'warning').length;
52
+ return `
53
+ <div class="diagnostics-panel">
54
+ <h3>📋 Diagnostics</h3>
55
+ <p class="diagnostic-summary">
56
+ ${errorCount} error${errorCount !== 1 ? 's' : ''},
57
+ ${warningCount} warning${warningCount !== 1 ? 's' : ''}
58
+ </p>
59
+ ${sections}
60
+ </div>
61
+ `;
62
+ }
63
+ //# sourceMappingURL=diagnostics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../../src/render/diagnostics.ts"],"names":[],"mappings":"AAYA;;GAEG;AACH,MAAM,UAAU,sBAAsB,CAAC,UAAsB;IACzD,MAAM,OAAO,GAAsB,EAAE,CAAC;IAEtC,KAAK,MAAM,UAAU,IAAI,UAAU,CAAC,WAAW,EAAE,CAAC;QAC9C,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,IAAI,SAAS,CAAC;QAC1C,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACjB,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;YACf,IAAI,EAAE,UAAU,CAAC,IAAI;YACrB,QAAQ,EAAE,UAAU,CAAC,QAAQ;YAC7B,OAAO,EAAE,UAAU,CAAC,OAAO;YAC3B,IAAI,EAAE,UAAU,CAAC,SAAS,EAAE,IAAI;YAChC,MAAM,EAAE,UAAU,CAAC,SAAS,EAAE,MAAM;SACvC,CAAC,CAAC;IACP,CAAC;IAED,OAAO,OAAO,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,UAAsB;IACxD,MAAM,OAAO,GAAG,sBAAsB,CAAC,UAAU,CAAC,CAAC;IACnD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAEnC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,+DAA+D,CAAC;IAC3E,CAAC;IAED,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;QAC9B,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;YAC9B,MAAM,aAAa,GAAG,cAAc,CAAC,CAAC,QAAQ,EAAE,CAAC;YACjD,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACpF,OAAO;6BACU,aAAa;8BACZ,CAAC,CAAC,IAAI,cAAc,CAAC,CAAC,OAAO,GAAG,QAAQ;;aAEzD,CAAC;QACN,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAEZ,OAAO;;sBAEO,IAAI;;sBAEJ,KAAK;;;SAGlB,CAAC;IACN,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEZ,MAAM,UAAU,GAAG,UAAU,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,MAAM,CAAC;IACrF,MAAM,YAAY,GAAG,UAAU,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC;IAEzF,OAAO;;;;kBAIO,UAAU,SAAS,UAAU,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;kBAC9C,YAAY,WAAW,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;;cAExD,QAAQ;;KAEjB,CAAC;AACN,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { Workspace } from '@openuji/speculator';
2
+ import type { LintResult } from '@openuji/speculator-lint';
3
+ import type { ReSpecConfig } from '../model.js';
4
+ /**
5
+ * Generate complete ReSpec HTML document
6
+ */
7
+ export declare function generateHTML(workspace: Workspace, config: ReSpecConfig, lintResult: LintResult): Promise<string>;
8
+ //# sourceMappingURL=html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/render/html.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAY,MAAM,qBAAqB,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAOhD;;GAEG;AACH,wBAAsB,YAAY,CAC9B,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,YAAY,EACpB,UAAU,EAAE,UAAU,GACvB,OAAO,CAAC,MAAM,CAAC,CA6DjB"}
@@ -0,0 +1,174 @@
1
+ import nunjucks from 'nunjucks';
2
+ import { dirname, join } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import { generateToc, renderTocHtml } from './toc.js';
5
+ import { renderDiagnosticsHtml } from './diagnostics.js';
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = dirname(__filename);
8
+ /**
9
+ * Generate complete ReSpec HTML document
10
+ */
11
+ export async function generateHTML(workspace, config, lintResult) {
12
+ // Get the entry document (first document in workspace)
13
+ const document = workspace.documents[0];
14
+ if (!document) {
15
+ throw new Error('No document found in workspace');
16
+ }
17
+ // Generate TOC
18
+ const tocEntries = generateToc(document, config.maxTocLevel);
19
+ const tocHtml = renderTocHtml(tocEntries);
20
+ // Render main content from AST
21
+ const contentHtml = renderDocumentContent(document);
22
+ // Render diagnostics
23
+ const diagnosticsHtml = renderDiagnosticsHtml(lintResult);
24
+ // Prepare template data
25
+ const templateData = {
26
+ // Document metadata
27
+ title: document.metadata?.title || 'Specification',
28
+ subtitle: config.subtitle,
29
+ // Status and dates
30
+ specStatus: config.specStatus,
31
+ publishDate: config.publishDate || new Date().toISOString().split('T')[0],
32
+ previousPublishDate: config.previousPublishDate,
33
+ // People
34
+ editors: config.editors || [],
35
+ authors: config.authors || [],
36
+ // Organization
37
+ group: config.group,
38
+ wg: config.wg,
39
+ wgURI: config.wgURI,
40
+ // Content
41
+ abstract: extractAbstract(document),
42
+ toc: tocHtml,
43
+ content: contentHtml,
44
+ diagnostics: diagnosticsHtml,
45
+ // GitHub
46
+ github: config.github,
47
+ // Copyright
48
+ copyrightStart: config.copyrightStart || new Date().getFullYear().toString(),
49
+ // Logos
50
+ logos: config.logos || [],
51
+ };
52
+ // Configure Nunjucks
53
+ const templatesDir = join(__dirname, '..', 'templates');
54
+ nunjucks.configure(templatesDir, { autoescape: false });
55
+ // Render template
56
+ const html = nunjucks.render('respec.html', templateData);
57
+ return html;
58
+ }
59
+ /**
60
+ * Extract abstract section from document
61
+ */
62
+ function extractAbstract(document) {
63
+ if (!document.children)
64
+ return 'No abstract provided.';
65
+ for (const child of document.children) {
66
+ if (child.type === 'section') {
67
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
68
+ const section = child;
69
+ if (section.id === 'abstract' || section.data?.respecClass === 'abstract') {
70
+ return renderNode(section);
71
+ }
72
+ }
73
+ }
74
+ return 'No abstract provided.';
75
+ }
76
+ /**
77
+ * Render document content as HTML
78
+ */
79
+ function renderDocumentContent(document) {
80
+ if (!document.children)
81
+ return '';
82
+ return document.children
83
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
84
+ .filter((child) => child.id !== 'abstract') // Skip abstract, it's rendered separately
85
+ .map(child => renderNode(child))
86
+ .join('\n');
87
+ }
88
+ /**
89
+ * Recursively render an AST node to HTML
90
+ */
91
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
92
+ function renderNode(node) {
93
+ if (!node || typeof node !== 'object')
94
+ return '';
95
+ switch (node.type) {
96
+ case 'section':
97
+ return renderSection(node);
98
+ case 'paragraph':
99
+ return renderParagraph(node);
100
+ case 'heading':
101
+ return renderHeading(node);
102
+ case 'text':
103
+ return escapeHtml(node.value || '');
104
+ case 'definition':
105
+ return renderDefinition(node);
106
+ case 'reference':
107
+ return renderReference(node);
108
+ case 'code':
109
+ return `<code>${escapeHtml(node.value || '')}</code>`;
110
+ case 'emphasis':
111
+ return `<em>${renderChildren(node)}</em>`;
112
+ case 'strong':
113
+ return `<strong>${renderChildren(node)}</strong>`;
114
+ case 'link':
115
+ return `<a href="${escapeHtml(node.href || '#')}">${renderChildren(node)}</a>`;
116
+ case 'list':
117
+ return renderList(node);
118
+ case 'listItem':
119
+ return `<li>${renderChildren(node)}</li>`;
120
+ default:
121
+ return renderChildren(node);
122
+ }
123
+ }
124
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
125
+ function renderSection(node) {
126
+ const id = node.id ? ` id="${escapeHtml(node.id)}"` : '';
127
+ const className = node.data?.respecClass ? ` class="${escapeHtml(node.data.respecClass)}"` : '';
128
+ const title = node.title ? `<h${node.level || 2}>${escapeHtml(node.title)}</h${node.level || 2}>` : '';
129
+ const content = renderChildren(node);
130
+ return `<section${id}${className}>\n${title}\n${content}\n</section>`;
131
+ }
132
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
133
+ function renderParagraph(node) {
134
+ return `<p>${renderChildren(node)}</p>`;
135
+ }
136
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
137
+ function renderHeading(node) {
138
+ const level = node.level || 2;
139
+ return `<h${level}>${renderChildren(node)}</h${level}>`;
140
+ }
141
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
142
+ function renderDefinition(node) {
143
+ const term = node.term || renderChildren(node);
144
+ const id = node.id ? ` id="${escapeHtml(node.id)}"` : '';
145
+ return `<dfn${id}>${escapeHtml(term)}</dfn>`;
146
+ }
147
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
148
+ function renderReference(node) {
149
+ const targetTerm = node.targetTerm || renderChildren(node);
150
+ const href = node.resolved?.id ? `#${escapeHtml(node.resolved.id)}` : '#';
151
+ return `<a href="${href}" class="internalDFN">${escapeHtml(targetTerm)}</a>`;
152
+ }
153
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
154
+ function renderList(node) {
155
+ const tag = node.ordered ? 'ol' : 'ul';
156
+ const content = renderChildren(node);
157
+ return `<${tag}>${content}</${tag}>`;
158
+ }
159
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
160
+ function renderChildren(node) {
161
+ if (!node.children || !Array.isArray(node.children))
162
+ return '';
163
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
164
+ return node.children.map((child) => renderNode(child)).join('');
165
+ }
166
+ function escapeHtml(text) {
167
+ return text
168
+ .replace(/&/g, '&amp;')
169
+ .replace(/</g, '&lt;')
170
+ .replace(/>/g, '&gt;')
171
+ .replace(/"/g, '&quot;')
172
+ .replace(/'/g, '&#039;');
173
+ }
174
+ //# sourceMappingURL=html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/render/html.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { Document } from '@openuji/speculator';
2
+ export interface TocEntry {
3
+ id: string;
4
+ title: string;
5
+ level: number;
6
+ children: TocEntry[];
7
+ }
8
+ /**
9
+ * Generate Table of Contents from document sections
10
+ */
11
+ export declare function generateToc(document: Document, maxLevel?: number): TocEntry[];
12
+ /**
13
+ * Render TOC as HTML
14
+ */
15
+ export declare function renderTocHtml(entries: TocEntry[], level?: number): string;
16
+ //# sourceMappingURL=toc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toc.d.ts","sourceRoot":"","sources":["../../src/render/toc.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,MAAM,WAAW,QAAQ;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,QAAQ,EAAE,CAAC;CACxB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,GAAE,MAAU,GAAG,QAAQ,EAAE,CAyChF;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,KAAK,GAAE,MAAU,GAAG,MAAM,CAgB5E"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Generate Table of Contents from document sections
3
+ */
4
+ export function generateToc(document, maxLevel = 3) {
5
+ const toc = [];
6
+ const stack = [];
7
+ // Walk through document children (sections)
8
+ if (document.children) {
9
+ for (const child of document.children) {
10
+ if (child.type === 'section') {
11
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
+ const section = child;
13
+ const level = section.level || 1;
14
+ // Only include up to maxLevel
15
+ if (level > maxLevel)
16
+ continue;
17
+ const entry = {
18
+ id: section.id || `section-${toc.length}`,
19
+ title: section.title || 'Untitled Section',
20
+ level,
21
+ children: [],
22
+ };
23
+ // Determine where to place this entry
24
+ while (stack.length > 0 && stack[stack.length - 1].level >= level) {
25
+ stack.pop();
26
+ }
27
+ if (stack.length === 0) {
28
+ // Top-level entry
29
+ toc.push(entry);
30
+ }
31
+ else {
32
+ // Nested entry
33
+ stack[stack.length - 1].entry.children.push(entry);
34
+ }
35
+ stack.push({ entry, level });
36
+ }
37
+ }
38
+ }
39
+ return toc;
40
+ }
41
+ /**
42
+ * Render TOC as HTML
43
+ */
44
+ export function renderTocHtml(entries, level = 1) {
45
+ if (entries.length === 0)
46
+ return '';
47
+ const items = entries.map(entry => {
48
+ const children = renderTocHtml(entry.children, level + 1);
49
+ return `
50
+ <li class="tocline">
51
+ <a href="#${entry.id}" class="tocxref">
52
+ <span class="secno"></span> ${entry.title}
53
+ </a>
54
+ ${children ? `<ol class="toc">${children}</ol>` : ''}
55
+ </li>
56
+ `;
57
+ }).join('');
58
+ return items;
59
+ }
60
+ //# sourceMappingURL=toc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toc.js","sourceRoot":"","sources":["../../src/render/toc.ts"],"names":[],"mappings":"AASA;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,QAAkB,EAAE,WAAmB,CAAC;IAChE,MAAM,GAAG,GAAe,EAAE,CAAC;IAC3B,MAAM,KAAK,GAA8C,EAAE,CAAC;IAE5D,4CAA4C;IAC5C,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;QACpB,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;YACpC,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC3B,8DAA8D;gBAC9D,MAAM,OAAO,GAAG,KAAY,CAAC;gBAC7B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC;gBAEjC,8BAA8B;gBAC9B,IAAI,KAAK,GAAG,QAAQ;oBAAE,SAAS;gBAE/B,MAAM,KAAK,GAAa;oBACpB,EAAE,EAAE,OAAO,CAAC,EAAE,IAAI,WAAW,GAAG,CAAC,MAAM,EAAE;oBACzC,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,kBAAkB;oBAC1C,KAAK;oBACL,QAAQ,EAAE,EAAE;iBACf,CAAC;gBAEF,sCAAsC;gBACtC,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,KAAK,EAAE,CAAC;oBAChE,KAAK,CAAC,GAAG,EAAE,CAAC;gBAChB,CAAC;gBAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBACrB,kBAAkB;oBAClB,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACpB,CAAC;qBAAM,CAAC;oBACJ,eAAe;oBACf,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACvD,CAAC;gBAED,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;YACjC,CAAC;QACL,CAAC;IACL,CAAC;IAED,OAAO,GAAG,CAAC;AACf,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,OAAmB,EAAE,QAAgB,CAAC;IAChE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEpC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;QAC9B,MAAM,QAAQ,GAAG,aAAa,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QAC1D,OAAO;;4BAEa,KAAK,CAAC,EAAE;kDACc,KAAK,CAAC,KAAK;;kBAE3C,QAAQ,CAAC,CAAC,CAAC,mBAAmB,QAAQ,OAAO,CAAC,CAAC,CAAC,EAAE;;SAE3D,CAAC;IACN,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEZ,OAAO,KAAK,CAAC;AACjB,CAAC"}