@mariozechner/pi-tui 0.5.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,225 @@
1
+ import chalk from "chalk";
2
+ import { marked } from "marked";
3
+ export class MarkdownComponent {
4
+ text;
5
+ lines = [];
6
+ previousLines = [];
7
+ constructor(text = "") {
8
+ this.text = text;
9
+ }
10
+ setText(text) {
11
+ this.text = text;
12
+ }
13
+ render(width) {
14
+ // Parse markdown to HTML-like tokens
15
+ const tokens = marked.lexer(this.text);
16
+ // Convert tokens to styled terminal output
17
+ const renderedLines = [];
18
+ for (let i = 0; i < tokens.length; i++) {
19
+ const token = tokens[i];
20
+ const nextToken = tokens[i + 1];
21
+ const tokenLines = this.renderToken(token, width, nextToken?.type);
22
+ renderedLines.push(...tokenLines);
23
+ }
24
+ // Wrap lines to fit width
25
+ const wrappedLines = [];
26
+ for (const line of renderedLines) {
27
+ wrappedLines.push(...this.wrapLine(line, width));
28
+ }
29
+ this.previousLines = this.lines;
30
+ this.lines = wrappedLines;
31
+ // Determine if content changed
32
+ const changed = this.lines.length !== this.previousLines.length ||
33
+ this.lines.some((line, i) => line !== this.previousLines[i]);
34
+ return {
35
+ lines: this.lines,
36
+ changed,
37
+ };
38
+ }
39
+ renderToken(token, width, nextTokenType) {
40
+ const lines = [];
41
+ switch (token.type) {
42
+ case "heading": {
43
+ const headingLevel = token.depth;
44
+ const headingPrefix = "#".repeat(headingLevel) + " ";
45
+ const headingText = this.renderInlineTokens(token.tokens || []);
46
+ if (headingLevel === 1) {
47
+ lines.push(chalk.bold.underline.yellow(headingText));
48
+ }
49
+ else if (headingLevel === 2) {
50
+ lines.push(chalk.bold.yellow(headingText));
51
+ }
52
+ else {
53
+ lines.push(chalk.bold(headingPrefix + headingText));
54
+ }
55
+ lines.push(""); // Add spacing after headings
56
+ break;
57
+ }
58
+ case "paragraph": {
59
+ const paragraphText = this.renderInlineTokens(token.tokens || []);
60
+ lines.push(paragraphText);
61
+ // Don't add spacing if next token is space or list
62
+ if (nextTokenType && nextTokenType !== "list" && nextTokenType !== "space") {
63
+ lines.push("");
64
+ }
65
+ break;
66
+ }
67
+ case "code": {
68
+ lines.push(chalk.gray("```" + (token.lang || "")));
69
+ // Split code by newlines and style each line
70
+ const codeLines = token.text.split("\n");
71
+ for (const codeLine of codeLines) {
72
+ lines.push(chalk.dim(" ") + chalk.green(codeLine));
73
+ }
74
+ lines.push(chalk.gray("```"));
75
+ lines.push(""); // Add spacing after code blocks
76
+ break;
77
+ }
78
+ case "list":
79
+ for (let i = 0; i < token.items.length; i++) {
80
+ const item = token.items[i];
81
+ const bullet = token.ordered ? `${i + 1}. ` : "- ";
82
+ const itemText = this.renderInlineTokens(item.tokens || []);
83
+ // Check if the item text contains multiple lines (embedded content)
84
+ const itemLines = itemText.split("\n").filter((line) => line.trim());
85
+ if (itemLines.length > 1) {
86
+ // First line is the list item
87
+ lines.push(chalk.cyan(bullet) + itemLines[0]);
88
+ // Rest are treated as separate content
89
+ for (let j = 1; j < itemLines.length; j++) {
90
+ lines.push(""); // Add spacing
91
+ lines.push(itemLines[j]);
92
+ }
93
+ }
94
+ else {
95
+ lines.push(chalk.cyan(bullet) + itemText);
96
+ }
97
+ }
98
+ // Don't add spacing after lists if a space token follows
99
+ // (the space token will handle it)
100
+ break;
101
+ case "blockquote": {
102
+ const quoteText = this.renderInlineTokens(token.tokens || []);
103
+ const quoteLines = quoteText.split("\n");
104
+ for (const quoteLine of quoteLines) {
105
+ lines.push(chalk.gray("│ ") + chalk.italic(quoteLine));
106
+ }
107
+ lines.push(""); // Add spacing after blockquotes
108
+ break;
109
+ }
110
+ case "hr":
111
+ lines.push(chalk.gray("─".repeat(Math.min(width, 80))));
112
+ lines.push(""); // Add spacing after horizontal rules
113
+ break;
114
+ case "html":
115
+ // Skip HTML for terminal output
116
+ break;
117
+ case "space":
118
+ // Space tokens represent blank lines in markdown
119
+ lines.push("");
120
+ break;
121
+ default:
122
+ // Handle any other token types as plain text
123
+ if ("text" in token && typeof token.text === "string") {
124
+ lines.push(token.text);
125
+ }
126
+ }
127
+ return lines;
128
+ }
129
+ renderInlineTokens(tokens) {
130
+ let result = "";
131
+ for (const token of tokens) {
132
+ switch (token.type) {
133
+ case "text":
134
+ // Text tokens in list items can have nested tokens for inline formatting
135
+ if (token.tokens && token.tokens.length > 0) {
136
+ result += this.renderInlineTokens(token.tokens);
137
+ }
138
+ else {
139
+ result += token.text;
140
+ }
141
+ break;
142
+ case "strong":
143
+ result += chalk.bold(this.renderInlineTokens(token.tokens || []));
144
+ break;
145
+ case "em":
146
+ result += chalk.italic(this.renderInlineTokens(token.tokens || []));
147
+ break;
148
+ case "codespan":
149
+ result += chalk.gray("`") + chalk.cyan(token.text) + chalk.gray("`");
150
+ break;
151
+ case "link": {
152
+ const linkText = this.renderInlineTokens(token.tokens || []);
153
+ result += chalk.underline.blue(linkText) + chalk.gray(` (${token.href})`);
154
+ break;
155
+ }
156
+ case "br":
157
+ result += "\n";
158
+ break;
159
+ case "del":
160
+ result += chalk.strikethrough(this.renderInlineTokens(token.tokens || []));
161
+ break;
162
+ default:
163
+ // Handle any other inline token types as plain text
164
+ if ("text" in token && typeof token.text === "string") {
165
+ result += token.text;
166
+ }
167
+ }
168
+ }
169
+ return result;
170
+ }
171
+ wrapLine(line, width) {
172
+ // Handle ANSI escape codes properly when wrapping
173
+ const wrapped = [];
174
+ // Handle undefined or null lines
175
+ if (!line) {
176
+ return [""];
177
+ }
178
+ // If line fits within width, return as-is
179
+ const visibleLength = this.getVisibleLength(line);
180
+ if (visibleLength <= width) {
181
+ return [line];
182
+ }
183
+ // Need to wrap - this is complex with ANSI codes
184
+ // For now, use a simple approach that may break styling at wrap points
185
+ let currentLine = "";
186
+ let currentLength = 0;
187
+ let i = 0;
188
+ while (i < line.length) {
189
+ if (line[i] === "\x1b" && line[i + 1] === "[") {
190
+ // ANSI escape sequence - include it without counting length
191
+ let j = i + 2;
192
+ while (j < line.length && line[j] && !/[mGKHJ]/.test(line[j])) {
193
+ j++;
194
+ }
195
+ if (j < line.length) {
196
+ currentLine += line.substring(i, j + 1);
197
+ i = j + 1;
198
+ }
199
+ else {
200
+ break;
201
+ }
202
+ }
203
+ else {
204
+ // Regular character
205
+ if (currentLength >= width) {
206
+ wrapped.push(currentLine);
207
+ currentLine = "";
208
+ currentLength = 0;
209
+ }
210
+ currentLine += line[i];
211
+ currentLength++;
212
+ i++;
213
+ }
214
+ }
215
+ if (currentLine) {
216
+ wrapped.push(currentLine);
217
+ }
218
+ return wrapped.length > 0 ? wrapped : [""];
219
+ }
220
+ getVisibleLength(str) {
221
+ // Remove ANSI escape codes and count visible characters
222
+ return (str || "").replace(/\x1b\[[0-9;]*m/g, "").length;
223
+ }
224
+ }
225
+ //# sourceMappingURL=markdown-component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown-component.js","sourceRoot":"","sources":["../src/markdown-component.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { Component, ComponentRenderResult } from "./tui.js";
2
+ export interface SelectItem {
3
+ value: string;
4
+ label: string;
5
+ description?: string;
6
+ }
7
+ export declare class SelectList implements Component {
8
+ private items;
9
+ private filteredItems;
10
+ private selectedIndex;
11
+ private filter;
12
+ private maxVisible;
13
+ onSelect?: (item: SelectItem) => void;
14
+ onCancel?: () => void;
15
+ constructor(items: SelectItem[], maxVisible?: number);
16
+ setFilter(filter: string): void;
17
+ render(width: number): ComponentRenderResult;
18
+ handleInput(keyData: string): void;
19
+ getSelectedItem(): SelectItem | null;
20
+ }
21
+ //# sourceMappingURL=select-list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"select-list.d.ts","sourceRoot":"","sources":["../src/select-list.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAEjE,MAAM,WAAW,UAAU;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,UAAW,YAAW,SAAS;IAC3C,OAAO,CAAC,KAAK,CAAoB;IACjC,OAAO,CAAC,aAAa,CAAoB;IACzC,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,UAAU,CAAa;IAExB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;gBAEjB,KAAK,EAAE,UAAU,EAAE,EAAE,UAAU,GAAE,MAAU;IAMvD,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAO/B,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,qBAAqB;IA6F5C,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAwBlC,eAAe,IAAI,UAAU,GAAG,IAAI;CAIpC"}
@@ -0,0 +1,130 @@
1
+ import chalk from "chalk";
2
+ export class SelectList {
3
+ items = [];
4
+ filteredItems = [];
5
+ selectedIndex = 0;
6
+ filter = "";
7
+ maxVisible = 5;
8
+ onSelect;
9
+ onCancel;
10
+ constructor(items, maxVisible = 5) {
11
+ this.items = items;
12
+ this.filteredItems = items;
13
+ this.maxVisible = maxVisible;
14
+ }
15
+ setFilter(filter) {
16
+ this.filter = filter;
17
+ this.filteredItems = this.items.filter((item) => item.value.toLowerCase().startsWith(filter.toLowerCase()));
18
+ // Reset selection when filter changes
19
+ this.selectedIndex = 0;
20
+ }
21
+ render(width) {
22
+ const lines = [];
23
+ // If no items match filter, show message
24
+ if (this.filteredItems.length === 0) {
25
+ lines.push(chalk.gray(" No matching commands"));
26
+ return { lines, changed: true };
27
+ }
28
+ // Calculate visible range with scrolling
29
+ const startIndex = Math.max(0, Math.min(this.selectedIndex - Math.floor(this.maxVisible / 2), this.filteredItems.length - this.maxVisible));
30
+ const endIndex = Math.min(startIndex + this.maxVisible, this.filteredItems.length);
31
+ // Render visible items
32
+ for (let i = startIndex; i < endIndex; i++) {
33
+ const item = this.filteredItems[i];
34
+ if (!item)
35
+ continue;
36
+ const isSelected = i === this.selectedIndex;
37
+ let line = "";
38
+ if (isSelected) {
39
+ // Use arrow indicator for selection
40
+ const prefix = chalk.blue("→ ");
41
+ const displayValue = item.label || item.value;
42
+ if (item.description && width > 40) {
43
+ // Calculate how much space we have for value + description
44
+ const maxValueLength = Math.min(displayValue.length, 30);
45
+ const truncatedValue = displayValue.substring(0, maxValueLength);
46
+ const spacing = " ".repeat(Math.max(1, 32 - truncatedValue.length));
47
+ // Calculate remaining space for description
48
+ const descriptionStart = prefix.length + truncatedValue.length + spacing.length - 2; // -2 for arrow color codes
49
+ const remainingWidth = width - descriptionStart - 2; // -2 for safety
50
+ if (remainingWidth > 10) {
51
+ const truncatedDesc = item.description.substring(0, remainingWidth);
52
+ line = prefix + chalk.blue(truncatedValue) + chalk.gray(spacing + truncatedDesc);
53
+ }
54
+ else {
55
+ // Not enough space for description
56
+ const maxWidth = width - 4; // 2 for arrow + space, 2 for safety
57
+ line = prefix + chalk.blue(displayValue.substring(0, maxWidth));
58
+ }
59
+ }
60
+ else {
61
+ // No description or not enough width
62
+ const maxWidth = width - 4; // 2 for arrow + space, 2 for safety
63
+ line = prefix + chalk.blue(displayValue.substring(0, maxWidth));
64
+ }
65
+ }
66
+ else {
67
+ const displayValue = item.label || item.value;
68
+ const prefix = " ";
69
+ if (item.description && width > 40) {
70
+ // Calculate how much space we have for value + description
71
+ const maxValueLength = Math.min(displayValue.length, 30);
72
+ const truncatedValue = displayValue.substring(0, maxValueLength);
73
+ const spacing = " ".repeat(Math.max(1, 32 - truncatedValue.length));
74
+ // Calculate remaining space for description
75
+ const descriptionStart = prefix.length + truncatedValue.length + spacing.length;
76
+ const remainingWidth = width - descriptionStart - 2; // -2 for safety
77
+ if (remainingWidth > 10) {
78
+ const truncatedDesc = item.description.substring(0, remainingWidth);
79
+ line = prefix + truncatedValue + chalk.gray(spacing + truncatedDesc);
80
+ }
81
+ else {
82
+ // Not enough space for description
83
+ const maxWidth = width - prefix.length - 2;
84
+ line = prefix + displayValue.substring(0, maxWidth);
85
+ }
86
+ }
87
+ else {
88
+ // No description or not enough width
89
+ const maxWidth = width - prefix.length - 2;
90
+ line = prefix + displayValue.substring(0, maxWidth);
91
+ }
92
+ }
93
+ lines.push(line);
94
+ }
95
+ // Add scroll indicators if needed
96
+ if (startIndex > 0 || endIndex < this.filteredItems.length) {
97
+ const scrollInfo = chalk.gray(` (${this.selectedIndex + 1}/${this.filteredItems.length})`);
98
+ lines.push(scrollInfo);
99
+ }
100
+ return { lines, changed: true };
101
+ }
102
+ handleInput(keyData) {
103
+ // Up arrow
104
+ if (keyData === "\x1b[A") {
105
+ this.selectedIndex = Math.max(0, this.selectedIndex - 1);
106
+ }
107
+ // Down arrow
108
+ else if (keyData === "\x1b[B") {
109
+ this.selectedIndex = Math.min(this.filteredItems.length - 1, this.selectedIndex + 1);
110
+ }
111
+ // Enter
112
+ else if (keyData === "\r") {
113
+ const selectedItem = this.filteredItems[this.selectedIndex];
114
+ if (selectedItem && this.onSelect) {
115
+ this.onSelect(selectedItem);
116
+ }
117
+ }
118
+ // Escape
119
+ else if (keyData === "\x1b") {
120
+ if (this.onCancel) {
121
+ this.onCancel();
122
+ }
123
+ }
124
+ }
125
+ getSelectedItem() {
126
+ const item = this.filteredItems[this.selectedIndex];
127
+ return item || null;
128
+ }
129
+ }
130
+ //# sourceMappingURL=select-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"select-list.js","sourceRoot":"","sources":["../src/select-list.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { Component, ComponentRenderResult, Padding } from "./tui.js";
2
+ export declare class TextComponent implements Component {
3
+ private text;
4
+ private lastRenderedLines;
5
+ private padding;
6
+ constructor(text: string, padding?: Padding);
7
+ render(width: number): ComponentRenderResult;
8
+ setText(text: string): void;
9
+ getText(): string;
10
+ private arraysEqual;
11
+ private getVisibleLength;
12
+ }
13
+ //# sourceMappingURL=text-component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-component.d.ts","sourceRoot":"","sources":["../src/text-component.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,qBAAqB,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAE1E,qBAAa,aAAc,YAAW,SAAS;IAC9C,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,iBAAiB,CAAgB;IACzC,OAAO,CAAC,OAAO,CAAoB;gBAEvB,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO;IAU3C,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,qBAAqB;IAkE5C,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI3B,OAAO,IAAI,MAAM;IAIjB,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,gBAAgB;CAIxB"}
@@ -0,0 +1,90 @@
1
+ export class TextComponent {
2
+ text;
3
+ lastRenderedLines = [];
4
+ padding;
5
+ constructor(text, padding) {
6
+ this.text = text;
7
+ this.padding = {
8
+ top: padding?.top ?? 0,
9
+ bottom: padding?.bottom ?? 0,
10
+ left: padding?.left ?? 0,
11
+ right: padding?.right ?? 0,
12
+ };
13
+ }
14
+ render(width) {
15
+ // Calculate available width after horizontal padding
16
+ const availableWidth = Math.max(1, width - this.padding.left - this.padding.right);
17
+ const leftPadding = " ".repeat(this.padding.left);
18
+ // First split by newlines to preserve line breaks
19
+ const textLines = this.text.split("\n");
20
+ const lines = [];
21
+ // Add top padding
22
+ for (let i = 0; i < this.padding.top; i++) {
23
+ lines.push("");
24
+ }
25
+ // Process each line for word wrapping
26
+ for (const textLine of textLines) {
27
+ if (textLine.length === 0) {
28
+ // Preserve empty lines with padding
29
+ lines.push(leftPadding);
30
+ }
31
+ else {
32
+ // Word wrapping with ANSI-aware length calculation
33
+ const words = textLine.split(" ");
34
+ let currentLine = "";
35
+ let currentVisibleLength = 0;
36
+ for (const word of words) {
37
+ const wordVisibleLength = this.getVisibleLength(word);
38
+ const spaceLength = currentLine ? 1 : 0;
39
+ if (currentVisibleLength + spaceLength + wordVisibleLength <= availableWidth) {
40
+ currentLine += (currentLine ? " " : "") + word;
41
+ currentVisibleLength += spaceLength + wordVisibleLength;
42
+ }
43
+ else {
44
+ if (currentLine) {
45
+ lines.push(leftPadding + currentLine);
46
+ }
47
+ currentLine = word;
48
+ currentVisibleLength = wordVisibleLength;
49
+ }
50
+ }
51
+ if (currentLine) {
52
+ lines.push(leftPadding + currentLine);
53
+ }
54
+ }
55
+ }
56
+ // Add bottom padding
57
+ for (let i = 0; i < this.padding.bottom; i++) {
58
+ lines.push("");
59
+ }
60
+ const newLines = lines.length > 0 ? lines : [""];
61
+ // Check if content changed
62
+ const changed = !this.arraysEqual(newLines, this.lastRenderedLines);
63
+ // Always cache the current rendered lines
64
+ this.lastRenderedLines = [...newLines];
65
+ return {
66
+ lines: newLines,
67
+ changed,
68
+ };
69
+ }
70
+ setText(text) {
71
+ this.text = text;
72
+ }
73
+ getText() {
74
+ return this.text;
75
+ }
76
+ arraysEqual(a, b) {
77
+ if (a.length !== b.length)
78
+ return false;
79
+ for (let i = 0; i < a.length; i++) {
80
+ if (a[i] !== b[i])
81
+ return false;
82
+ }
83
+ return true;
84
+ }
85
+ getVisibleLength(str) {
86
+ // Remove ANSI escape codes and count visible characters
87
+ return (str || "").replace(/\x1b\[[0-9;]*m/g, "").length;
88
+ }
89
+ }
90
+ //# sourceMappingURL=text-component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-component.js","sourceRoot":"","sources":["../src/text-component.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import type { AutocompleteProvider } from "./autocomplete.js";
2
+ import type { Component, ComponentRenderResult } from "./tui.js";
3
+ export interface TextEditorConfig {
4
+ }
5
+ export declare class TextEditor implements Component {
6
+ private state;
7
+ private config;
8
+ private autocompleteProvider?;
9
+ private autocompleteList?;
10
+ private isAutocompleting;
11
+ private autocompletePrefix;
12
+ onSubmit?: (text: string) => void;
13
+ onChange?: (text: string) => void;
14
+ disableSubmit: boolean;
15
+ constructor(config?: TextEditorConfig);
16
+ configure(config: Partial<TextEditorConfig>): void;
17
+ setAutocompleteProvider(provider: AutocompleteProvider): void;
18
+ render(width: number): ComponentRenderResult;
19
+ handleInput(data: string): void;
20
+ private layoutText;
21
+ getText(): string;
22
+ setText(text: string): void;
23
+ private insertCharacter;
24
+ private handlePaste;
25
+ private addNewLine;
26
+ private handleBackspace;
27
+ private moveToLineStart;
28
+ private moveToLineEnd;
29
+ private handleForwardDelete;
30
+ private deleteCurrentLine;
31
+ private moveCursor;
32
+ private isAtStartOfMessage;
33
+ private tryTriggerAutocomplete;
34
+ private handleTabCompletion;
35
+ private handleSlashCommandCompletion;
36
+ private forceFileAutocomplete;
37
+ private cancelAutocomplete;
38
+ private updateAutocomplete;
39
+ }
40
+ //# sourceMappingURL=text-editor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-editor.d.ts","sourceRoot":"","sources":["../src/text-editor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAgC,MAAM,mBAAmB,CAAC;AAG5F,OAAO,KAAK,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAcjE,MAAM,WAAW,gBAAgB;CAEhC;AAED,qBAAa,UAAW,YAAW,SAAS;IAC3C,OAAO,CAAC,KAAK,CAIX;IAEF,OAAO,CAAC,MAAM,CAAwB;IAGtC,OAAO,CAAC,oBAAoB,CAAC,CAAuB;IACpD,OAAO,CAAC,gBAAgB,CAAC,CAAa;IACtC,OAAO,CAAC,gBAAgB,CAAkB;IAC1C,OAAO,CAAC,kBAAkB,CAAc;IAEjC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,aAAa,EAAE,OAAO,CAAS;gBAE1B,MAAM,CAAC,EAAE,gBAAgB;IAOrC,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,IAAI;IAKlD,uBAAuB,CAAC,QAAQ,EAAE,oBAAoB,GAAG,IAAI;IAI7D,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,qBAAqB;IAsE5C,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IA8M/B,OAAO,CAAC,UAAU;IAsElB,OAAO,IAAI,MAAM;IAIjB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAkB3B,OAAO,CAAC,eAAe;IAiCvB,OAAO,CAAC,WAAW;IA0EnB,OAAO,CAAC,UAAU;IAmBlB,OAAO,CAAC,eAAe;IAgCvB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,mBAAmB;IAoB3B,OAAO,CAAC,iBAAiB;IAyBzB,OAAO,CAAC,UAAU;IAqBlB,OAAO,CAAC,kBAAkB;IAS1B,OAAO,CAAC,sBAAsB;IAiD9B,OAAO,CAAC,mBAAmB;IAgB3B,OAAO,CAAC,4BAA4B;IAOpC,OAAO,CAAC,qBAAqB;IAoC7B,OAAO,CAAC,kBAAkB;IAM1B,OAAO,CAAC,kBAAkB;CAoB1B"}