@alchemy.run/sigil 0.0.0-alpha.4 → 0.0.0-alpha.6
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/README.md +21 -9
- package/THIRD_PARTY_NOTICES.md +39 -1
- package/dist/Text-BobFKi74.d.ts +452 -0
- package/dist/ansi.d.ts +122 -131
- package/dist/ansi.js +86 -6
- package/dist/capabilities.d.ts +5 -0
- package/dist/capabilities.js +3 -0
- package/dist/cell-_ZVhbfl0.js +44 -0
- package/dist/color-CkbalRqK.js +2 -0
- package/dist/color-policy-BMzMwV7Q.d.ts +22 -0
- package/dist/color-policy-SVj1pYTA.js +560 -0
- package/dist/color-profile-DHhQHY55.js +36 -0
- package/dist/color-profile-u0Nhe9Nv.d.ts +97 -0
- package/dist/color.d.ts +21 -0
- package/dist/color.js +3 -0
- package/dist/cursor-position-D2LAkRG0.d.ts +7 -0
- package/dist/detect-Bh4yGP6w.d.ts +186 -0
- package/dist/detect-BuTXtY6e.js +373 -0
- package/dist/env-YVw64yZS.js +9 -0
- package/dist/escapes-CB_6CWOE.d.ts +72 -0
- package/dist/geometry-BxXOzJgo.d.ts +11 -0
- package/dist/index-DZ88EXJv.d.ts +21 -0
- package/dist/index.d.ts +143 -498
- package/dist/index.js +1026 -2244
- package/dist/osc-CCH7xDoS.js +71 -0
- package/dist/osc-Cn0fw77g.d.ts +23 -0
- package/dist/paint-C19minOS.d.ts +81 -0
- package/dist/query-vaIeGOkH.d.ts +152 -0
- package/dist/router.d.ts +392 -0
- package/dist/router.js +709 -0
- package/dist/sample-Cqw1bjUL.js +445 -0
- package/dist/screen-BOSLQ8fF.d.ts +49 -0
- package/dist/screen-CiPytswf.js +342 -0
- package/dist/screen.d.ts +5 -0
- package/dist/screen.js +5 -0
- package/dist/semantic-text-style-DIMzC7xt.js +91 -0
- package/dist/serialize-BTkAZgw1.js +79 -0
- package/dist/session-aZr9O8h3.js +665 -0
- package/dist/sgr-BhwaWAJB.js +246 -0
- package/dist/store-CgrG9K4y.d.ts +72 -0
- package/dist/string-width-CijQwpIk.js +69 -0
- package/dist/strip-BvU4toXG.js +6 -0
- package/dist/terminal.d.ts +118 -0
- package/dist/terminal.js +2 -0
- package/dist/tokenize-AjqbvtiT.js +1242 -0
- package/dist/tokenize-Dx1y_l5H.d.ts +57 -0
- package/dist/truncate-D31fhU6i.js +562 -0
- package/dist/use-focus-BzqAJi0n.js +1337 -0
- package/package.json +41 -9
- package/src/ansi/chalk.ts +5 -3
- package/src/ansi/escapes.ts +14 -0
- package/src/ansi/graphemes.ts +8 -0
- package/src/ansi/hyperlink.ts +44 -0
- package/src/ansi/index.ts +3 -1
- package/src/ansi/osc.ts +77 -0
- package/src/ansi/tokenize.ts +3 -4
- package/src/capabilities/color-policy.ts +34 -0
- package/src/capabilities/detect.ts +594 -0
- package/src/capabilities/index.ts +37 -0
- package/src/capabilities/query.ts +657 -0
- package/src/capabilities/store.ts +379 -0
- package/src/color/index.ts +3 -0
- package/src/color/paint.ts +169 -0
- package/src/color/palette.ts +48 -0
- package/src/color/sample.ts +323 -0
- package/src/color.ts +1 -0
- package/src/components/AnsiText.tsx +42 -0
- package/src/components/App.tsx +98 -10
- package/src/components/BackgroundContext.ts +2 -3
- package/src/components/Box.tsx +0 -8
- package/src/components/CursorContext.ts +1 -1
- package/src/components/Hyperlink.tsx +56 -0
- package/src/components/TerminalOscContext.ts +25 -0
- package/src/components/Text.tsx +22 -45
- package/src/components/Transform.tsx +1 -1
- package/src/dom.ts +11 -2
- package/src/global.d.ts +3 -0
- package/src/hooks/use-capabilities.ts +73 -0
- package/src/hooks/use-cursor.ts +2 -2
- package/src/hooks/use-terminal-osc.ts +59 -0
- package/src/index.ts +45 -1
- package/src/ink.tsx +213 -153
- package/src/{render-node-to-output.ts → paint-tree.ts} +75 -48
- package/src/reconciler.ts +24 -3
- package/src/render-background.ts +36 -15
- package/src/render-border.ts +94 -61
- package/src/render-frame.ts +83 -0
- package/src/render-to-string.ts +21 -6
- package/src/render.ts +15 -6
- package/src/router/components.tsx +343 -0
- package/src/router/context.ts +41 -0
- package/src/router/history.ts +194 -0
- package/src/router/hooks.tsx +391 -0
- package/src/router/index.ts +34 -0
- package/src/router/matcher.ts +571 -0
- package/src/screen/ansi.ts +184 -0
- package/src/screen/canvas.ts +160 -0
- package/src/screen/cell.ts +138 -0
- package/src/screen/color-profile.ts +47 -0
- package/src/screen/geometry.ts +9 -0
- package/src/screen/index.ts +6 -0
- package/src/screen/screen.ts +305 -0
- package/src/screen/serialize.ts +129 -0
- package/src/screen.ts +1 -0
- package/src/semantic-text-style.ts +118 -0
- package/src/squash-text-nodes.ts +2 -5
- package/src/structured-text.ts +325 -0
- package/src/styles.ts +19 -14
- package/src/terminal/index.ts +2 -0
- package/src/terminal/inline-presenter.ts +120 -0
- package/src/terminal/input.ts +86 -0
- package/src/terminal/render-scheduler.ts +37 -0
- package/src/terminal/screen-presenter.ts +188 -0
- package/src/terminal/session.ts +407 -0
- package/src/terminal.ts +1 -0
- package/src/testing/browser.ts +588 -0
- package/src/testing/emulators.ts +205 -0
- package/src/testing/explorer-app/index.html +12 -0
- package/src/testing/explorer-app/main.ts +381 -0
- package/src/testing/explorer-app/style.css +194 -0
- package/src/testing/explorer-app/tsconfig.json +15 -0
- package/src/testing/explorer-app/vite-env.d.ts +1 -0
- package/src/testing/index.ts +26 -0
- package/src/testing/keys.ts +56 -0
- package/src/testing/live.ts +85 -0
- package/src/testing/matchers.ts +70 -0
- package/src/testing/public.ts +94 -0
- package/src/testing/terminal.ts +349 -0
- package/src/testing/vitest.ts +157 -0
- package/src/transform-adapter.ts +14 -0
- package/src/wrap-text.ts +4 -0
- package/dist/sgr-CMfEpjSk.d.ts +0 -91
- package/dist/truncate-Cr6xVFMa.js +0 -2330
- package/src/ansi/supports-color.ts +0 -207
- package/src/colorize.ts +0 -60
- package/src/log-update.ts +0 -370
- package/src/output.ts +0 -308
- package/src/renderer.ts +0 -73
package/src/output.ts
DELETED
|
@@ -1,308 +0,0 @@
|
|
|
1
|
-
import { sliceAnsi } from "#/ansi/slice.ts";
|
|
2
|
-
import { stringWidth } from "#/ansi/string-width.ts";
|
|
3
|
-
import {
|
|
4
|
-
type StyledChar,
|
|
5
|
-
styledCharsFromTokens,
|
|
6
|
-
styledCharsToString,
|
|
7
|
-
tokenize,
|
|
8
|
-
} from "#/ansi/tokenize.ts";
|
|
9
|
-
import { type OutputTransformer } from "#/render-node-to-output.ts";
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
"Virtual" output class
|
|
13
|
-
|
|
14
|
-
Handles the positioning and saving of the output of each node in the tree. Also responsible for applying transformations to each character of the output.
|
|
15
|
-
|
|
16
|
-
Used to generate the final output of all nodes before writing it to actual output stream (e.g. stdout)
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
type Options = {
|
|
20
|
-
width: number;
|
|
21
|
-
height: number;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
type Operation = WriteOperation | ClipOperation | UnclipOperation;
|
|
25
|
-
|
|
26
|
-
type WriteOperation = {
|
|
27
|
-
type: "write";
|
|
28
|
-
x: number;
|
|
29
|
-
y: number;
|
|
30
|
-
text: string;
|
|
31
|
-
transformers: OutputTransformer[];
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
type ClipOperation = {
|
|
35
|
-
type: "clip";
|
|
36
|
-
clip: Clip;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
type Clip = {
|
|
40
|
-
x1: number | undefined;
|
|
41
|
-
x2: number | undefined;
|
|
42
|
-
y1: number | undefined;
|
|
43
|
-
y2: number | undefined;
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
type UnclipOperation = {
|
|
47
|
-
type: "unclip";
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
class OutputCaches {
|
|
51
|
-
widths = new Map<string, number>();
|
|
52
|
-
blockWidths = new Map<string, number>();
|
|
53
|
-
styledChars = new Map<string, StyledChar[]>();
|
|
54
|
-
|
|
55
|
-
getStyledChars(line: string): StyledChar[] {
|
|
56
|
-
let cached = this.styledChars.get(line);
|
|
57
|
-
if (cached === undefined) {
|
|
58
|
-
cached = styledCharsFromTokens(tokenize(line));
|
|
59
|
-
this.styledChars.set(line, cached);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return cached;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
getStringWidth(text: string): number {
|
|
66
|
-
let cached = this.widths.get(text);
|
|
67
|
-
if (cached === undefined) {
|
|
68
|
-
cached = stringWidth(text);
|
|
69
|
-
this.widths.set(text, cached);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return cached;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
getWidestLine(text: string): number {
|
|
76
|
-
let cached = this.blockWidths.get(text);
|
|
77
|
-
if (cached === undefined) {
|
|
78
|
-
let lineWidth = 0;
|
|
79
|
-
for (const line of text.split("\n")) {
|
|
80
|
-
lineWidth = Math.max(lineWidth, this.getStringWidth(line));
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
cached = lineWidth;
|
|
84
|
-
this.blockWidths.set(text, cached);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return cached;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export class Output {
|
|
92
|
-
width: number;
|
|
93
|
-
height: number;
|
|
94
|
-
|
|
95
|
-
private readonly operations: Operation[] = [];
|
|
96
|
-
private readonly caches: OutputCaches = new OutputCaches();
|
|
97
|
-
|
|
98
|
-
constructor(options: Options) {
|
|
99
|
-
const { width, height } = options;
|
|
100
|
-
|
|
101
|
-
this.width = width;
|
|
102
|
-
this.height = height;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
write(x: number, y: number, text: string, options: { transformers: OutputTransformer[] }): void {
|
|
106
|
-
const { transformers } = options;
|
|
107
|
-
|
|
108
|
-
if (!text) {
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
this.operations.push({
|
|
113
|
-
type: "write",
|
|
114
|
-
x,
|
|
115
|
-
y,
|
|
116
|
-
text,
|
|
117
|
-
transformers,
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
clip(clip: Clip) {
|
|
122
|
-
this.operations.push({
|
|
123
|
-
type: "clip",
|
|
124
|
-
clip,
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
unclip() {
|
|
129
|
-
this.operations.push({
|
|
130
|
-
type: "unclip",
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
get(): { output: string; height: number } {
|
|
135
|
-
// Initialize output array with a specific set of rows, so that margin/padding at the bottom is preserved
|
|
136
|
-
const output: StyledChar[][] = [];
|
|
137
|
-
|
|
138
|
-
for (let y = 0; y < this.height; y++) {
|
|
139
|
-
const row: StyledChar[] = [];
|
|
140
|
-
|
|
141
|
-
for (let x = 0; x < this.width; x++) {
|
|
142
|
-
row.push({
|
|
143
|
-
type: "char",
|
|
144
|
-
value: " ",
|
|
145
|
-
fullWidth: false,
|
|
146
|
-
styles: [],
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
output.push(row);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const clips: Clip[] = [];
|
|
154
|
-
|
|
155
|
-
for (const operation of this.operations) {
|
|
156
|
-
if (operation.type === "clip") {
|
|
157
|
-
clips.push(operation.clip);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (operation.type === "unclip") {
|
|
161
|
-
clips.pop();
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
if (operation.type === "write") {
|
|
165
|
-
const { text, transformers } = operation;
|
|
166
|
-
let { x, y } = operation;
|
|
167
|
-
let lines = text.split("\n");
|
|
168
|
-
|
|
169
|
-
const clip = clips.at(-1);
|
|
170
|
-
|
|
171
|
-
if (clip) {
|
|
172
|
-
const clipHorizontally = typeof clip?.x1 === "number" && typeof clip?.x2 === "number";
|
|
173
|
-
|
|
174
|
-
const clipVertically = typeof clip?.y1 === "number" && typeof clip?.y2 === "number";
|
|
175
|
-
|
|
176
|
-
// If text is positioned outside of clipping area altogether,
|
|
177
|
-
// skip to the next operation to avoid unnecessary calculations
|
|
178
|
-
if (clipHorizontally) {
|
|
179
|
-
const width = this.caches.getWidestLine(text);
|
|
180
|
-
|
|
181
|
-
if (x + width < clip.x1! || x > clip.x2!) {
|
|
182
|
-
continue;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
if (clipVertically) {
|
|
187
|
-
const height = lines.length;
|
|
188
|
-
|
|
189
|
-
if (y + height < clip.y1! || y > clip.y2!) {
|
|
190
|
-
continue;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
if (clipHorizontally) {
|
|
195
|
-
lines = lines.map((line) => {
|
|
196
|
-
const from = x < clip.x1! ? clip.x1! - x : 0;
|
|
197
|
-
const width = this.caches.getStringWidth(line);
|
|
198
|
-
const to = x + width > clip.x2! ? clip.x2! - x : width;
|
|
199
|
-
|
|
200
|
-
return sliceAnsi(line, from, to);
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
if (x < clip.x1!) {
|
|
204
|
-
x = clip.x1!;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
if (clipVertically) {
|
|
209
|
-
const from = y < clip.y1! ? clip.y1! - y : 0;
|
|
210
|
-
const height = lines.length;
|
|
211
|
-
const to = y + height > clip.y2! ? clip.y2! - y : height;
|
|
212
|
-
|
|
213
|
-
lines = lines.slice(from, to);
|
|
214
|
-
|
|
215
|
-
if (y < clip.y1!) {
|
|
216
|
-
y = clip.y1!;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
let offsetY = 0;
|
|
222
|
-
|
|
223
|
-
for (let [index, line] of lines.entries()) {
|
|
224
|
-
const currentLine = output[y + offsetY];
|
|
225
|
-
|
|
226
|
-
// Line can be missing if `text` is taller than height of pre-initialized `this.output`
|
|
227
|
-
if (!currentLine) {
|
|
228
|
-
continue;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
for (const transformer of transformers) {
|
|
232
|
-
line = transformer(line, index);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
const characters = this.caches.getStyledChars(line);
|
|
236
|
-
let offsetX = x;
|
|
237
|
-
|
|
238
|
-
// Nothing to write (e.g. line was clipped away).
|
|
239
|
-
if (characters.length === 0) {
|
|
240
|
-
offsetY++;
|
|
241
|
-
continue;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
const spaceCell: StyledChar = {
|
|
245
|
-
type: "char",
|
|
246
|
-
value: " ",
|
|
247
|
-
fullWidth: false,
|
|
248
|
-
styles: [],
|
|
249
|
-
};
|
|
250
|
-
|
|
251
|
-
// Wide characters (e.g. CJK) occupy two cells: a leading
|
|
252
|
-
// cell with the character and a trailing placeholder with
|
|
253
|
-
// value ''. When an overlapping write lands in the middle
|
|
254
|
-
// of a wide character, the boundary cells need cleanup so
|
|
255
|
-
// the terminal never renders a half-visible wide character.
|
|
256
|
-
if (
|
|
257
|
-
currentLine[offsetX]?.value === "" &&
|
|
258
|
-
offsetX > 0 &&
|
|
259
|
-
this.caches.getStringWidth(currentLine[offsetX - 1]?.value ?? "") > 1
|
|
260
|
-
) {
|
|
261
|
-
currentLine[offsetX - 1] = spaceCell;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
for (const character of characters) {
|
|
265
|
-
currentLine[offsetX] = character;
|
|
266
|
-
|
|
267
|
-
// Determine printed width using string-width to align with measurement
|
|
268
|
-
const characterWidth = Math.max(1, this.caches.getStringWidth(character.value));
|
|
269
|
-
|
|
270
|
-
// For multi-column characters, clear following cells to avoid stray spaces/artifacts
|
|
271
|
-
if (characterWidth > 1) {
|
|
272
|
-
for (let columnOffset = 1; columnOffset < characterWidth; columnOffset++) {
|
|
273
|
-
currentLine[offsetX + columnOffset] = {
|
|
274
|
-
type: "char",
|
|
275
|
-
value: "",
|
|
276
|
-
fullWidth: false,
|
|
277
|
-
styles: character.styles,
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
offsetX += characterWidth;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
if (currentLine[offsetX]?.value === "") {
|
|
286
|
-
currentLine[offsetX] = spaceCell;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
offsetY++;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
const generatedOutput = output
|
|
295
|
-
.map((line) => {
|
|
296
|
-
// See https://github.com/vadimdemedes/ink/pull/564#issuecomment-1637022742
|
|
297
|
-
const lineWithoutEmptyItems = line.filter((item) => item !== undefined);
|
|
298
|
-
|
|
299
|
-
return styledCharsToString(lineWithoutEmptyItems).trimEnd();
|
|
300
|
-
})
|
|
301
|
-
.join("\n");
|
|
302
|
-
|
|
303
|
-
return {
|
|
304
|
-
output: generatedOutput,
|
|
305
|
-
height: output.length,
|
|
306
|
-
};
|
|
307
|
-
}
|
|
308
|
-
}
|
package/src/renderer.ts
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { type DOMElement } from "#/dom.ts";
|
|
2
|
-
import { Output } from "#/output.ts";
|
|
3
|
-
import { renderNodeToOutput, renderNodeToScreenReaderOutput } from "#/render-node-to-output.ts";
|
|
4
|
-
|
|
5
|
-
type Result = {
|
|
6
|
-
output: string;
|
|
7
|
-
outputHeight: number;
|
|
8
|
-
staticOutput: string;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export const renderer = (node: DOMElement, isScreenReaderEnabled: boolean): Result => {
|
|
12
|
-
if (node.yogaNode) {
|
|
13
|
-
if (isScreenReaderEnabled) {
|
|
14
|
-
const output = renderNodeToScreenReaderOutput(node, {
|
|
15
|
-
skipStaticElements: true,
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
const outputHeight = output === "" ? 0 : output.split("\n").length;
|
|
19
|
-
|
|
20
|
-
let staticOutput = "";
|
|
21
|
-
|
|
22
|
-
if (node.staticNode) {
|
|
23
|
-
staticOutput = renderNodeToScreenReaderOutput(node.staticNode, {
|
|
24
|
-
skipStaticElements: false,
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return {
|
|
29
|
-
output,
|
|
30
|
-
outputHeight,
|
|
31
|
-
staticOutput: staticOutput ? `${staticOutput}\n` : "",
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const output = new Output({
|
|
36
|
-
width: node.yogaNode.getComputedWidth(),
|
|
37
|
-
height: node.yogaNode.getComputedHeight(),
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
renderNodeToOutput(node, output, {
|
|
41
|
-
skipStaticElements: true,
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
let staticOutput;
|
|
45
|
-
|
|
46
|
-
if (node.staticNode?.yogaNode) {
|
|
47
|
-
staticOutput = new Output({
|
|
48
|
-
width: node.staticNode.yogaNode.getComputedWidth(),
|
|
49
|
-
height: node.staticNode.yogaNode.getComputedHeight(),
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
renderNodeToOutput(node.staticNode, staticOutput, {
|
|
53
|
-
skipStaticElements: false,
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const { output: generatedOutput, height: outputHeight } = output.get();
|
|
58
|
-
|
|
59
|
-
return {
|
|
60
|
-
output: generatedOutput,
|
|
61
|
-
outputHeight,
|
|
62
|
-
// Newline at the end is needed, because static output doesn't have one, so
|
|
63
|
-
// interactive output will override last line of static output
|
|
64
|
-
staticOutput: staticOutput ? `${staticOutput.get().output}\n` : "",
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return {
|
|
69
|
-
output: "",
|
|
70
|
-
outputHeight: 0,
|
|
71
|
-
staticOutput: "",
|
|
72
|
-
};
|
|
73
|
-
};
|