@promptctl/rich-js 0.27.0 → 0.29.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.
Files changed (185) hide show
  1. package/README.md +7 -6
  2. package/THIRD-PARTY-NOTICES +42 -0
  3. package/dist/core/animation.d.ts +65 -46
  4. package/dist/core/animation.js +91 -67
  5. package/dist/core/ansi.d.ts +19 -12
  6. package/dist/core/ansi.js +114 -36
  7. package/dist/core/bidi-data.d.ts +14 -0
  8. package/dist/core/bidi-data.js +385 -0
  9. package/dist/core/bidi.d.ts +89 -0
  10. package/dist/core/bidi.js +615 -0
  11. package/dist/core/box.d.ts +9 -1
  12. package/dist/core/box.js +11 -0
  13. package/dist/core/cell-widths.d.ts +3 -2
  14. package/dist/core/cell-widths.js +93 -93
  15. package/dist/core/cells.d.ts +20 -0
  16. package/dist/core/cells.js +94 -6
  17. package/dist/core/clock.d.ts +1 -1
  18. package/dist/core/color.d.ts +56 -57
  19. package/dist/core/color.js +79 -81
  20. package/dist/core/console.d.ts +24 -7
  21. package/dist/core/console.js +27 -8
  22. package/dist/core/control-codes.d.ts +61 -0
  23. package/dist/core/control-codes.js +157 -0
  24. package/dist/core/easing.d.ts +40 -40
  25. package/dist/core/easing.js +40 -40
  26. package/dist/core/env.d.ts +6 -0
  27. package/dist/core/env.js +9 -1
  28. package/dist/core/export-html.js +5 -4
  29. package/dist/core/export-lines.d.ts +13 -11
  30. package/dist/core/export-lines.js +19 -15
  31. package/dist/core/export-svg.d.ts +3 -3
  32. package/dist/core/export-svg.js +10 -9
  33. package/dist/core/json.js +9 -2
  34. package/dist/core/markup.js +5 -4
  35. package/dist/core/memo.d.ts +1 -1
  36. package/dist/core/memo.js +1 -1
  37. package/dist/core/oklch.d.ts +14 -14
  38. package/dist/core/oklch.js +10 -10
  39. package/dist/core/orient.d.ts +68 -0
  40. package/dist/core/orient.js +224 -0
  41. package/dist/core/osc8.d.ts +12 -5
  42. package/dist/core/osc8.js +14 -7
  43. package/dist/core/paint.d.ts +9 -9
  44. package/dist/core/paint.js +3 -3
  45. package/dist/core/pretty.d.ts +1 -1
  46. package/dist/core/pretty.js +23 -19
  47. package/dist/core/protocol.d.ts +47 -26
  48. package/dist/core/protocol.js +31 -23
  49. package/dist/core/render.d.ts +19 -14
  50. package/dist/core/render.js +30 -17
  51. package/dist/core/seal.d.ts +26 -0
  52. package/dist/core/seal.js +75 -0
  53. package/dist/core/segment.d.ts +12 -4
  54. package/dist/core/segment.js +16 -6
  55. package/dist/core/strip.d.ts +83 -83
  56. package/dist/core/strip.js +70 -70
  57. package/dist/core/style.d.ts +46 -18
  58. package/dist/core/style.js +92 -56
  59. package/dist/core/text-order.d.ts +51 -0
  60. package/dist/core/text-order.js +50 -0
  61. package/dist/core/text.d.ts +12 -2
  62. package/dist/core/text.js +136 -90
  63. package/dist/core/timeline.d.ts +5 -5
  64. package/dist/core/timeline.js +11 -11
  65. package/dist/core/tween.d.ts +6 -6
  66. package/dist/core/tween.js +10 -10
  67. package/dist/core/view.d.ts +5 -5
  68. package/dist/core/view.js +15 -14
  69. package/dist/core/wrap.d.ts +24 -6
  70. package/dist/core/wrap.js +82 -16
  71. package/dist/host/app.d.ts +50 -9
  72. package/dist/host/app.js +120 -15
  73. package/dist/host/host-environment.d.ts +2 -2
  74. package/dist/host/host-environment.js +2 -2
  75. package/dist/host/index.d.ts +3 -2
  76. package/dist/host/index.js +1 -0
  77. package/dist/host/input.d.ts +42 -9
  78. package/dist/host/input.js +91 -7
  79. package/dist/host/terminal-colors.d.ts +18 -0
  80. package/dist/host/terminal-colors.js +46 -0
  81. package/dist/host/terminal-host.d.ts +4 -3
  82. package/dist/host/terminal-host.js +1 -1
  83. package/dist/index.d.ts +17 -16
  84. package/dist/index.js +11 -11
  85. package/dist/node/prompt.d.ts +1 -1
  86. package/dist/node/prompt.js +1 -1
  87. package/dist/node/terminal-host.d.ts +1 -1
  88. package/dist/node/traceback.js +2 -2
  89. package/dist/renderables/change.d.ts +1 -3
  90. package/dist/renderables/change.js +6 -8
  91. package/dist/renderables/effect.d.ts +88 -87
  92. package/dist/renderables/effect.js +124 -114
  93. package/dist/renderables/effects.d.ts +105 -76
  94. package/dist/renderables/effects.js +309 -176
  95. package/dist/renderables/embed.d.ts +1 -1
  96. package/dist/renderables/embed.js +2 -2
  97. package/dist/renderables/flexStrip.d.ts +7 -7
  98. package/dist/renderables/flexStrip.js +15 -15
  99. package/dist/renderables/frames.d.ts +7 -16
  100. package/dist/renderables/frames.js +12 -27
  101. package/dist/renderables/glyph-effect.d.ts +22 -23
  102. package/dist/renderables/glyph-effect.js +43 -41
  103. package/dist/renderables/glyph-effects.d.ts +33 -14
  104. package/dist/renderables/glyph-effects.js +90 -22
  105. package/dist/renderables/html-entities.d.ts +1 -1
  106. package/dist/renderables/html-entities.js +1 -1
  107. package/dist/renderables/lifecycle.d.ts +8 -10
  108. package/dist/renderables/lifecycle.js +17 -18
  109. package/dist/renderables/live.d.ts +2 -2
  110. package/dist/renderables/live.js +7 -7
  111. package/dist/renderables/markdown-parse.js +3 -3
  112. package/dist/renderables/markdown.js +4 -2
  113. package/dist/renderables/panel.js +7 -5
  114. package/dist/renderables/progress.d.ts +1 -1
  115. package/dist/renderables/progress.js +1 -1
  116. package/dist/renderables/progressBar.d.ts +3 -3
  117. package/dist/renderables/progressBar.js +21 -18
  118. package/dist/renderables/prompt.d.ts +1 -1
  119. package/dist/renderables/scroll.d.ts +1 -1
  120. package/dist/renderables/scroll.js +3 -3
  121. package/dist/renderables/spinner.d.ts +4 -4
  122. package/dist/renderables/spinner.js +10 -10
  123. package/dist/renderables/syntax.d.ts +2 -2
  124. package/dist/renderables/syntax.js +9 -4
  125. package/dist/renderables/table.js +5 -4
  126. package/dist/renderables/traceback.d.ts +1 -1
  127. package/dist/renderables/traceback.js +1 -1
  128. package/dist/renderables/tree.js +3 -3
  129. package/dist/template-bindings/animation-funcs.d.ts +60 -29
  130. package/dist/template-bindings/animation-funcs.js +126 -43
  131. package/dist/template-bindings/color-funcs.d.ts +14 -14
  132. package/dist/template-bindings/color-funcs.js +25 -25
  133. package/dist/template-bindings/index.d.ts +16 -14
  134. package/dist/template-bindings/index.js +17 -14
  135. package/dist/template-bindings/palette-funcs.d.ts +2 -2
  136. package/dist/template-bindings/palette-funcs.js +4 -4
  137. package/dist/template-bindings/style-funcs.d.ts +5 -5
  138. package/dist/template-bindings/style-funcs.js +16 -16
  139. package/dist/themes/{transpose.d.ts → adjust.d.ts} +23 -23
  140. package/dist/themes/{transpose.js → adjust.js} +28 -28
  141. package/dist/themes/buildPalette.d.ts +6 -5
  142. package/dist/themes/buildPalette.js +22 -22
  143. package/dist/themes/colorMath.d.ts +16 -16
  144. package/dist/themes/colorMath.js +32 -32
  145. package/dist/themes/data/ansi-tables.d.ts +2 -2
  146. package/dist/themes/data/ansi-tables.js +2 -2
  147. package/dist/themes/data/index.js +1 -4
  148. package/dist/themes/data/textual-ansi.js +0 -143
  149. package/dist/themes/data/types.d.ts +4 -4
  150. package/dist/themes/data/types.js +2 -2
  151. package/dist/themes/palette.d.ts +12 -12
  152. package/dist/themes/palette.js +16 -16
  153. package/dist/themes/ramp.d.ts +17 -17
  154. package/dist/themes/ramp.js +12 -12
  155. package/dist/themes/registry.d.ts +6 -8
  156. package/dist/themes/registry.js +6 -8
  157. package/dist/themes/terminalThemes.d.ts +4 -11
  158. package/dist/themes/terminalThemes.js +31 -47
  159. package/dist/widgets/button.d.ts +3 -3
  160. package/dist/widgets/button.js +8 -8
  161. package/dist/widgets/checkbox.d.ts +2 -2
  162. package/dist/widgets/checkbox.js +4 -4
  163. package/dist/widgets/dropdown.d.ts +3 -3
  164. package/dist/widgets/dropdown.js +7 -5
  165. package/dist/widgets/event-router.d.ts +6 -6
  166. package/dist/widgets/event-router.js +2 -2
  167. package/dist/widgets/focus-manager.d.ts +3 -3
  168. package/dist/widgets/focus-manager.js +3 -3
  169. package/dist/widgets/index.d.ts +2 -2
  170. package/dist/widgets/index.js +1 -1
  171. package/dist/widgets/ink.d.ts +3 -3
  172. package/dist/widgets/ink.js +4 -4
  173. package/dist/widgets/slider.d.ts +2 -2
  174. package/dist/widgets/static-item.d.ts +2 -2
  175. package/dist/widgets/text-input.d.ts +2 -2
  176. package/dist/widgets/text-input.js +5 -5
  177. package/dist/widgets/themed-widget.js +4 -4
  178. package/dist/widgets/toggle.d.ts +4 -4
  179. package/dist/widgets/toggle.js +6 -6
  180. package/dist/widgets/types.d.ts +6 -6
  181. package/dist/widgets/types.js +2 -2
  182. package/dist/widgets/widget-app.d.ts +10 -10
  183. package/dist/widgets/widget-app.js +8 -8
  184. package/dist/widgets/widget-base.d.ts +2 -2
  185. package/package.json +5 -4
@@ -1,13 +1,15 @@
1
1
  /**
2
2
  * Terminal color representation, parsing, downgrading, and ANSI code generation.
3
3
  */
4
+ import { isDumbTerminal } from "./env.js";
4
5
  import { Memo, WeakMemo } from "./memo.js";
5
6
  import { pattern } from "./pattern.js";
7
+ import { detectTextOrder } from "./text-order.js";
6
8
  // --- ColorRgba ---
7
9
  function hex2(byte) {
8
10
  return byte.toString(16).padStart(2, "0");
9
11
  }
10
- // [LAW:one-source-of-truth] The one statement of a colour byte's range: the
12
+ // [LAW:one-source-of-truth] The one statement of a color byte's range: the
11
13
  // constructor asserts it and the string parser reports it, from this predicate.
12
14
  function isByte(v) {
13
15
  return Number.isInteger(v) && v >= 0 && v <= 255;
@@ -73,12 +75,12 @@ export class ColorRgba {
73
75
  }
74
76
  }
75
77
  /**
76
- * The surface a terminal draws a translucent colour over. A terminal cannot
78
+ * The surface a terminal draws a translucent color over. A terminal cannot
77
79
  * know what lies under its cells, so the SGR writer (`Style.toSgrCodes`), the
78
80
  * exports that picture its output (`resolveLook`), the strip's seam test and
79
81
  * the contrast choosers (`themes/colorMath`) all composite over this one
80
- * colour. [LAW:one-source-of-truth] One constant, so
81
- * the colour text is chosen against is the colour the writer draws.
82
+ * color. [LAW:one-source-of-truth] One constant, so
83
+ * the color text is chosen against is the color the writer draws.
82
84
  */
83
85
  export const SURFACE_BLACK = new ColorRgba(0, 0, 0);
84
86
  /**
@@ -115,7 +117,7 @@ function luminanceRatio(la, lb) {
115
117
  // --- ColorTable ---
116
118
  // [LAW:one-source-of-truth] The one distance every table scan ranks by, so
117
119
  // `matchWhere`'s "nearest by the distance `match` uses" cannot drift, and
118
- // `Effected` weighs a written colour against `ColorSpec.matchOn` by it too.
120
+ // `Effected` weighs a written color against `ColorSpec.matchOn` by it too.
119
121
  export function rgbDistance(a, b) {
120
122
  const dr = a.red - b.red;
121
123
  const dg = a.green - b.green;
@@ -125,7 +127,7 @@ export function rgbDistance(a, b) {
125
127
  /**
126
128
  * An indexed palette: entry `i` of `colors` is terminal index `firstIndex + i`.
127
129
  * `firstIndex` lets a table hold only the part of a palette a downgrade may
128
- * choose (the 256-colour cube and grey ramp start at 16) while every index it
130
+ * choose (the 256-color cube and grey ramp start at 16) while every index it
129
131
  * reports is the terminal's own.
130
132
  */
131
133
  export class ColorTable {
@@ -133,7 +135,7 @@ export class ColorTable {
133
135
  /** Each entry's relative luminance. */
134
136
  luminances;
135
137
  firstIndex;
136
- // Keyed by colours a host computes without end (ramp stops, mixes), so bounded.
138
+ // Keyed by colors a host computes without end (ramp stops, mixes), so bounded.
137
139
  matchMemo = new Memo();
138
140
  readableMemo = new Memo();
139
141
  constructor(colors, firstIndex = 0) {
@@ -207,7 +209,7 @@ export class ColorTable {
207
209
  }
208
210
  /**
209
211
  * The nearest entry to `value` (the distance `match` uses) among those
210
- * `accept` takes, given each entry's colour and terminal index; `undefined`
212
+ * `accept` takes, given each entry's color and terminal index; `undefined`
211
213
  * when it takes none. Entries are offered nearest-first (ties to the lower
212
214
  * index) and the first taken wins, so an expensive predicate runs only as
213
215
  * far out as the answer. Uncached: the predicate is the caller's, and a
@@ -230,7 +232,7 @@ export var ColorDepth;
230
232
  ColorDepth[ColorDepth["WINDOWS"] = 4] = "WINDOWS";
231
233
  })(ColorDepth || (ColorDepth = {}));
232
234
  /**
233
- * How many colours a depth can name, as a rank. WINDOWS is a sixteen-colour
235
+ * How many colors a depth can name, as a rank. WINDOWS is a sixteen-color
234
236
  * depth whose enum value sits above TRUECOLOR, so the enum's order is not this.
235
237
  * STANDARD and WINDOWS share a rank: the same sixteen slots, drawn by
236
238
  * different terminals, so each converts to the other by keeping the slot.
@@ -248,7 +250,7 @@ function fidelity(depth) {
248
250
  return 3;
249
251
  }
250
252
  }
251
- // The depths a colour system is named for. Its keys and "auto" are the whole
253
+ // The depths a color system is named for. Its keys and "auto" are the whole
252
254
  // vocabulary: `ColorSystemName` is derived from them, so the type and the
253
255
  // table cannot disagree. [LAW:one-source-of-truth]
254
256
  const COLOR_SYSTEM_DEPTHS = {
@@ -257,11 +259,11 @@ const COLOR_SYSTEM_DEPTHS = {
257
259
  ansi: ColorDepth.STANDARD,
258
260
  none: null,
259
261
  };
260
- // [LAW:one-source-of-truth] What the environment says about colour, by the
262
+ // [LAW:one-source-of-truth] What the environment says about color, by the
261
263
  // value it says it with: FORCE_COLOR values (the chalk/supports-color
262
- // convention), TERM_PROGRAM identifiers, and exact TERM names whose colour
264
+ // convention), TERM_PROGRAM identifiers, and exact TERM names whose color
263
265
  // capability is known. A different vocabulary from `ColorSystemName`, so a
264
- // different table: `FORCE_COLOR=none` is not a request for no colour. A `Map`,
266
+ // different table: `FORCE_COLOR=none` is not a request for no color. A `Map`,
265
267
  // so a value naming an `Object.prototype` member is unknown, not a function.
266
268
  // `null` means "no color".
267
269
  const ENV_DEPTHS = new Map([
@@ -297,7 +299,7 @@ const ENV_DEPTHS = new Map([
297
299
  * in the env values, not in which checks execute.
298
300
  */
299
301
  export function detectColorSystem(options = {}) {
300
- // NO_COLOR and FORCE_COLOR are preferences about colour, not facts about the
302
+ // NO_COLOR and FORCE_COLOR are preferences about color, not facts about the
301
303
  // terminal, so they sit outside the probe. NO_COLOR (any non-empty value)
302
304
  // beats FORCE_COLOR; FORCE_COLOR beats TTY/TERM detection.
303
305
  const noColor = envOf(options)["NO_COLOR"];
@@ -317,23 +319,15 @@ function forcedColorSystem(env) {
317
319
  function envOf(options) {
318
320
  return options.env ?? (typeof process !== "undefined" ? process.env : {});
319
321
  }
320
- /**
321
- * A terminal that says it cannot be drawn on: `TERM` is `dumb` or `unknown`,
322
- * as Emacs' shell mode sets it. It takes no colour and nothing that moves the
323
- * cursor.
324
- */
325
- export function isDumbTerminal(env) {
326
- const term = env["TERM"];
327
- return term === "dumb" || term === "unknown";
322
+ function isTTYOf(options) {
323
+ return options.isTTY ?? (typeof process !== "undefined" ? (process.stdout?.isTTY ?? false) : false);
328
324
  }
329
325
  // What the destination can draw, preferences aside: TTY presence,
330
326
  // TERM=dumb/unknown, COLORTERM, known terminal names, TERM patterns. `null`
331
327
  // here means the destination takes no escapes at all.
332
328
  function terminalColorSystem(options) {
333
329
  const env = envOf(options);
334
- const isTTY = options.isTTY ??
335
- (typeof process !== "undefined" ? (process.stdout?.isTTY ?? false) : false);
336
- if (!isTTY)
330
+ if (!isTTYOf(options))
337
331
  return null;
338
332
  if (isDumbTerminal(env))
339
333
  return null;
@@ -365,22 +359,25 @@ function terminalColorSystem(options) {
365
359
  return ColorDepth.STANDARD;
366
360
  }
367
361
  /**
368
- * Resolve a colour spec into a `Destination`.
362
+ * Resolve a color spec into an `OutputTarget`.
369
363
  *
370
364
  * [LAW:single-enforcer] The one place a spec becomes both facts. A hyperlink is
371
- * not a colour: an explicit depth — `"none"` and `null` included — states a
372
- * colour choice and keeps links, and under `"auto"` links follow what the
365
+ * not a color: an explicit depth — `"none"` and `null` included — states a
366
+ * color choice and keeps links, and under `"auto"` links follow what the
373
367
  * terminal can take (no TTY, TERM=dumb: none) while NO_COLOR and FORCE_COLOR=0,
374
- * colour preferences, leave them alone. A FORCE_COLOR that forces colour on
368
+ * color preferences, leave them alone. A FORCE_COLOR that forces color on
375
369
  * declares the destination takes escapes, so it keeps links on a pipe too.
376
370
  */
377
- export function resolveDestination(spec, options = {}) {
371
+ export function resolveOutputTarget(spec, options = {}) {
378
372
  const reducedMotion = options.reducedMotion ?? false;
373
+ // Ahead of both arms: a color spec says nothing about order.
374
+ const textOrder = options.textOrder ?? detectTextOrder(envOf(options), isTTYOf(options));
379
375
  if (spec !== "auto") {
380
376
  return {
381
377
  colorSystem: typeof spec === "string" ? resolveColorSystem(spec) : spec,
382
378
  hyperlinks: true,
383
379
  reducedMotion,
380
+ textOrder,
384
381
  };
385
382
  }
386
383
  return {
@@ -388,10 +385,11 @@ export function resolveDestination(spec, options = {}) {
388
385
  hyperlinks: (forcedColorSystem(envOf(options)) ?? null) !== null ||
389
386
  terminalColorSystem(options) !== null,
390
387
  reducedMotion,
388
+ textOrder,
391
389
  };
392
390
  }
393
391
  /**
394
- * Resolve a colour system name into a `ColorDepth` (or `null` for no color).
392
+ * Resolve a color system name into a `ColorDepth` (or `null` for no color).
395
393
  *
396
394
  * `"auto"` triggers env-based detection; every other name is a fixed depth.
397
395
  * A name outside the vocabulary — reachable only from untyped JavaScript —
@@ -431,12 +429,12 @@ export class ColorSpec {
431
429
  return this.type === ColorDepth.DEFAULT;
432
430
  }
433
431
  /**
434
- * The colour every terminal draws this spec as, where that is fixed — before
432
+ * The color every terminal draws this spec as, where that is fixed — before
435
433
  * any alpha is flattened, so a translucent value is drawn composited over
436
434
  * its ground (`flattenAlpha`) and should be measured that way: a
437
- * truecolor value, or a 256-colour cube or grey-ramp entry (xterm fixes
435
+ * truecolor value, or a 256-color cube or grey-ramp entry (xterm fixes
438
436
  * indices 16–255, and `fromAnsi` types only those as EIGHT_BIT). ANSI 0–15,
439
- * the default colour and a blend reaching either are the terminal theme's
437
+ * the default color and a blend reaching either are the terminal theme's
440
438
  * own, so they have none.
441
439
  */
442
440
  get fixedValue() {
@@ -555,20 +553,20 @@ export class ColorSpec {
555
553
  return ColorSpec.fromRgba(new ColorRgba(r, g, b));
556
554
  }
557
555
  /**
558
- * The colour `t` of the way from `from` to `to`: what `blend(from,to,t)`
559
- * parses to. Two fixed colours mix to a fixed colour. A mix reaching a
560
- * theme's own colour stays a mix until it is drawn, so whatever theme draws
556
+ * The color `t` of the way from `from` to `to`: what `blend(from,to,t)`
557
+ * parses to. Two fixed colors mix to a fixed color. A mix reaching a
558
+ * theme's own color stays a mix until it is drawn, so whatever theme draws
561
559
  * an end draws the mix from it: exported under a theme whose `blue` is
562
560
  * #61afef, a mix with `blue` starts from #61afef. A terminal is told its RGB
563
561
  * under the standard table, the only one a render has.
564
562
  *
565
- * Each end is one opaque colour: `default` is no colour to mix, and a
563
+ * Each end is one opaque color: `default` is no color to mix, and a
566
564
  * translucent end has no one shade until it is laid on a ground.
567
565
  */
568
566
  static blend(from, to, t) {
569
567
  for (const end of [from, to]) {
570
568
  if (end.isDefault)
571
- throw new ColorParseError(`A blend cannot mix "default", which is no colour`);
569
+ throw new ColorParseError(`A blend cannot mix "default", which is no color`);
572
570
  if (end.value !== undefined && end.value.alpha < 1) {
573
571
  throw new ColorParseError(`A blend's ends are opaque; "${end.name}" is translucent`);
574
572
  }
@@ -591,21 +589,21 @@ export class ColorSpec {
591
589
  }
592
590
  /**
593
591
  * The spec that draws `value` nearest to it at `depth` on a terminal known
594
- * to show `theme`, as the colour of the glyph (`foreground`) or of the
592
+ * to show `theme`, as the color of the glyph (`foreground`) or of the
595
593
  * ground. Where `downgrade` knows no terminal, and so rounds only against
596
- * colours every terminal fixes (or, at sixteen colours, the stock
597
- * sixteen), this rounds against every colour the depth can write whose
598
- * look `theme` fixes: the default colour, the theme's sixteen, and at 256
599
- * colours the cube and grey ramp too. A colour read off any of those and
600
- * moved a little is drawn as the colour it came from — or, where the theme
601
- * gives two slots one colour, as the lower slot, which looks the same.
594
+ * colors every terminal fixes (or, at sixteen colors, the stock
595
+ * sixteen), this rounds against every color the depth can write whose
596
+ * look `theme` fixes: the default color, the theme's sixteen, and at 256
597
+ * colors the cube and grey ramp too. A color read off any of those and
598
+ * moved a little is drawn as the color it came from — or, where the theme
599
+ * gives two slots one color, as the lower slot, which looks the same.
602
600
  *
603
- * `value` is opaque: a translucent colour has no one look until it is laid
601
+ * `value` is opaque: a translucent color has no one look until it is laid
604
602
  * on a ground (`flattenAlpha`).
605
603
  */
606
604
  static matchOn(value, depth, theme, foreground) {
607
605
  if (value.alpha < 1)
608
- throw new RangeError(`matchOn rounds an opaque colour; got alpha ${value.alpha}`);
606
+ throw new RangeError(`matchOn rounds an opaque color; got alpha ${value.alpha}`);
609
607
  if (depth === ColorDepth.TRUECOLOR)
610
608
  return ColorSpec.fromRgba(value);
611
609
  if (depth === ColorDepth.DEFAULT)
@@ -623,23 +621,23 @@ export class ColorSpec {
623
621
  return candidates.reduce((best, next) => (rgbDistance(next[1], value) < rgbDistance(best[1], value) ? next : best))[0];
624
622
  }
625
623
  /**
626
- * Every colour `depth` writes by index, each with the colour a terminal
624
+ * Every color `depth` writes by index, each with the color a terminal
627
625
  * known to show `theme` draws it in, lowest index first: the theme's
628
- * sixteen, and at 256 colours the cube and grey ramp after them. Each is
629
- * drawn alike as glyph and as ground, which the default colour is not, so
630
- * it is not among them. Truecolor writes a colour itself and the default
631
- * depth only the default, so neither writes any by index. The colours
626
+ * sixteen, and at 256 colors the cube and grey ramp after them. Each is
627
+ * drawn alike as glyph and as ground, which the default color is not, so
628
+ * it is not among them. Truecolor writes a color itself and the default
629
+ * depth only the default, so neither writes any by index. The colors
632
630
  * `matchOn` rounds to, but for the default, read off the same two tables.
633
631
  */
634
632
  static indexed(depth, theme) {
635
633
  return indexedMemo.get(theme, () => new Memo()).get(`${depth}`, () => listIndexed(depth, theme));
636
634
  }
637
635
  /**
638
- * The spec a slot is written in once its colour moves from `was`, what its
636
+ * The spec a slot is written in once its color moves from `was`, what its
639
637
  * written spec draws on `theme`, to the opaque `now`: `matchOn`'s — or
640
638
  * none, where the written spec is as near `now` as that match. A move the
641
- * depth cannot show is no move, so below truecolor a colour moved a little
642
- * off any colour the depth can write — a theme slot, the default colour,
639
+ * depth cannot show is no move, so below truecolor a color moved a little
640
+ * off any color the depth can write — a theme slot, the default color,
643
641
  * the cube — keeps the spec it was written in.
644
642
  */
645
643
  static matchMove(was, now, depth, theme, foreground) {
@@ -655,7 +653,7 @@ export class ColorSpec {
655
653
  }
656
654
  // --- private ---
657
655
  performDowngrade(targetSystem) {
658
- // The colour as the terminal this depth assumes draws it: a blend's named
656
+ // The color as the terminal this depth assumes draws it: a blend's named
659
657
  // ends are the Windows console's own at WINDOWS.
660
658
  const triplet = this.getTruecolor(resolveTerminal(undefined, targetSystem));
661
659
  switch (targetSystem) {
@@ -664,7 +662,7 @@ export class ColorSpec {
664
662
  case ColorDepth.STANDARD:
665
663
  case ColorDepth.WINDOWS: {
666
664
  // An ANSI slot is already one of the sixteen either depth writes; only
667
- // a fixed colour is matched against the depth's table, as Rich does.
665
+ // a fixed color is matched against the depth's table, as Rich does.
668
666
  const index = this.number !== undefined && this.number < 16 ? this.number : downgradeTable(targetSystem).match(triplet);
669
667
  return new ColorSpec(`color(${index})`, targetSystem, index);
670
668
  }
@@ -675,7 +673,7 @@ export class ColorSpec {
675
673
  }
676
674
  }
677
675
  }
678
- /** The cube or grey-ramp entry nearest `value`, and its colour. */
676
+ /** The cube or grey-ramp entry nearest `value`, and its color. */
679
677
  function cubeCandidate(value) {
680
678
  const index = EIGHT_BIT_DOWNGRADE_TABLE.match(value);
681
679
  return [ColorSpec.fromAnsi(index), EIGHT_BIT_DOWNGRADE_TABLE.get(index)];
@@ -701,7 +699,7 @@ function mix(from, to, t, theme) {
701
699
  return blendRgb(from.getTruecolor(theme), to.getTruecolor(theme), t);
702
700
  }
703
701
  // How a blend spells an end: by what it draws as, so every spelling of one
704
- // colour ("blue", "color(4)", an EIGHT_BIT 4) gives the blend one name.
702
+ // color ("blue", "color(4)", an EIGHT_BIT 4) gives the blend one name.
705
703
  function blendTerm(end) {
706
704
  return end.fixedValue?.hex ?? (end.number !== undefined ? `color(${end.number})` : end.name);
707
705
  }
@@ -804,8 +802,8 @@ function parseByte(key, digits, field) {
804
802
  return n;
805
803
  }
806
804
  // --- Utility functions ---
807
- // [LAW:single-enforcer] The hex colour grammar, checked here and nowhere else:
808
- // every string spelling a colour in hex — a ColorSpec, a theme's data, a colour
805
+ // [LAW:single-enforcer] The hex color grammar, checked here and nowhere else:
806
+ // every string spelling a color in hex — a ColorSpec, a theme's data, a color
809
807
  // reference, a template argument — becomes one through the three parsers below,
810
808
  // and each is this check at the lengths it admits. Each digit pair is a byte, so
811
809
  // the grammar holding is what keeps `ColorRgba`'s channels in range.
@@ -816,12 +814,12 @@ const HEX_GRAMMARS = { 6: "RRGGBB", 8: "RRGGBBAA" };
816
814
  function hexColor(input, lead, digits, lengths) {
817
815
  if (!lengths.includes(digits.length) || !HEX_DIGITS_RE.test(digits)) {
818
816
  const expected = lengths.map((n) => lead + HEX_GRAMMARS[n]).join(" or ");
819
- throw new ColorParseError(`Invalid hex colour ${JSON.stringify(input)} (expected ${expected})`);
817
+ throw new ColorParseError(`Invalid hex color ${JSON.stringify(input)} (expected ${expected})`);
820
818
  }
821
819
  const byte = (at) => parseInt(digits.slice(at, at + 2), 16);
822
820
  return new ColorRgba(byte(0), byte(2), byte(4), digits.length === 8 ? byte(6) / 255 : 1);
823
821
  }
824
- /** Six hex digits, no `#`, as an opaque colour. @throws {ColorParseError} on anything else. */
822
+ /** Six hex digits, no `#`, as an opaque color. @throws {ColorParseError} on anything else. */
825
823
  export function parseRgbHex(hex) {
826
824
  return hexColor(hex, "", hex, [6]);
827
825
  }
@@ -841,7 +839,7 @@ export function blendRgb(color1, color2, crossFade = 0.5) {
841
839
  }
842
840
  // --- TerminalTheme ---
843
841
  /**
844
- * What a terminal draws with: the part of a `TerminalTheme` a colour resolves
842
+ * What a terminal draws with: the part of a `TerminalTheme` a color resolves
845
843
  * against.
846
844
  */
847
845
  export class TerminalColors {
@@ -855,17 +853,17 @@ export class TerminalColors {
855
853
  // [LAW:parse-dont-validate] Every reader indexes `ansiColors` 0–15 as the
856
854
  // terminal's sixteen, so a theme is the proof it holds exactly those.
857
855
  if (ansiColors.firstIndex !== 0 || ansiColors.size !== 16) {
858
- throw new RangeError(`a TerminalTheme's ansiColors are the sixteen ANSI colours, indices 0–15; got ${ansiColors.size} from index ${ansiColors.firstIndex}`);
856
+ throw new RangeError(`a TerminalTheme's ansiColors are the sixteen ANSI colors, indices 0–15; got ${ansiColors.size} from index ${ansiColors.firstIndex}`);
859
857
  }
860
858
  }
861
859
  }
862
860
  /**
863
- * A terminal theme — surface/foreground baseline, the sixteen ANSI colours,
861
+ * A terminal theme — surface/foreground baseline, the sixteen ANSI colors,
864
862
  * and a semantic palette.
865
863
  *
866
- * **`ansiColors` is the theme's own sixteen colours**, the shades a terminal
864
+ * **`ansiColors` is the theme's own sixteen colors**, the shades a terminal
867
865
  * showing this theme draws `red`, `blue` and the rest in. `ColorSpec.parse("red")`
868
- * is ANSI colour 1 under every theme; which red that is, is the theme's to say,
866
+ * is ANSI color 1 under every theme; which red that is, is the theme's to say,
869
867
  * as it is in Rich, where each `TerminalTheme` carries its own table.
870
868
  */
871
869
  export class TerminalTheme extends TerminalColors {
@@ -916,8 +914,8 @@ function build256Table() {
916
914
  }
917
915
  /**
918
916
  * The Windows console's own sixteen (its default Campbell scheme), in ANSI
919
- * index order: a WINDOWS colour is written as the same `30+n`/`90+n` SGR a
920
- * STANDARD one is, so slot `n` here is the colour the console draws for it.
917
+ * index order: a WINDOWS color is written as the same `30+n`/`90+n` SGR a
918
+ * STANDARD one is, so slot `n` here is the color the console draws for it.
921
919
  */
922
920
  function buildWindowsTable() {
923
921
  return [
@@ -942,8 +940,8 @@ function buildWindowsTable() {
942
940
  export const STANDARD_TABLE = new ColorTable(buildStandard16());
943
941
  export const EIGHT_BIT_TABLE = new ColorTable(build256Table());
944
942
  /**
945
- * What a downgrade to 256 colours may choose: the cube and the grey ramp,
946
- * indices 16–255. Indices 0–15 are the terminal's own ANSI colours, which
943
+ * What a downgrade to 256 colors may choose: the cube and the grey ramp,
944
+ * indices 16–255. Indices 0–15 are the terminal's own ANSI colors, which
947
945
  * every theme redefines, so their RGB is unknown and a match against them is
948
946
  * a guess; Python Rich never picks them either.
949
947
  */
@@ -952,18 +950,18 @@ export const WINDOWS_TABLE = new ColorTable(buildWindowsTable());
952
950
  // --- Internal fallback terminals ---
953
951
  //
954
952
  // [LAW:one-way-deps] Preset themes (DEFAULT_TERMINAL_THEME, MONOKAI, NORD, ...)
955
- // live in `src/themes/terminalThemes.ts` because they need `buildPalette` from
956
- // `themes/`. Keeping them out of `core/color.ts` makes the dependency strictly
953
+ // live in `src/themes/terminalThemes.ts` because they hold the registry's
954
+ // palettes. Keeping them out of `core/color.ts` makes the dependency strictly
957
955
  // `themes/* -> core/color`, with no runtime back-edge.
958
956
  //
959
957
  // `getTruecolor()` retains a fallback for callers that omit `theme`: the
960
- // terminal a colour's depth assumes, its own sixteen and no palette, which the
958
+ // terminal a color's depth assumes, its own sixteen and no palette, which the
961
959
  // lookups it serves never read.
962
960
  const INTERNAL_DEFAULT_TERMINAL = new TerminalColors(new ColorRgba(0, 0, 0), new ColorRgba(255, 255, 255), STANDARD_TABLE);
963
- /** The Windows console in its default Campbell scheme: a WINDOWS colour's terminal. */
961
+ /** The Windows console in its default Campbell scheme: a WINDOWS color's terminal. */
964
962
  const WINDOWS_CONSOLE_TERMINAL = new TerminalColors(WINDOWS_TABLE.get(0), WINDOWS_TABLE.get(7), WINDOWS_TABLE);
965
963
  /**
966
- * The terminal a colour at `depth` is drawn by: `theme`, or when a caller names
964
+ * The terminal a color at `depth` is drawn by: `theme`, or when a caller names
967
965
  * none, the one the depth assumes — the Windows console at WINDOWS, the VGA
968
966
  * sixteen otherwise — for `ColorSpec.getTruecolor` and the contrast measurement
969
967
  * that reads it. (Widgets fall back to `DEFAULT_TERMINAL_THEME`, which carries a
@@ -973,9 +971,9 @@ export function resolveTerminal(theme, depth) {
973
971
  return theme ?? (depth === ColorDepth.WINDOWS ? WINDOWS_CONSOLE_TERMINAL : INTERNAL_DEFAULT_TERMINAL);
974
972
  }
975
973
  /**
976
- * The table a downgrade to `depth` rounds a fixed colour against.
977
- * [LAW:one-source-of-truth] `ColorSpec.downgrade` picks the index a colour is
978
- * written as from it, and colorMath hands back its entries as colours the
974
+ * The table a downgrade to `depth` rounds a fixed color against.
975
+ * [LAW:one-source-of-truth] `ColorSpec.downgrade` picks the index a color is
976
+ * written as from it, and colorMath hands back its entries as colors the
979
977
  * writer rounds to those same indices.
980
978
  */
981
979
  export function downgradeTable(depth) {
@@ -3,9 +3,10 @@
3
3
  */
4
4
  import { Style, Theme } from "./style.js";
5
5
  import { ColorDepth } from "./color.js";
6
- import type { ColorSystemName, Destination } from "./color.js";
6
+ import type { TextOrder } from "./text-order.js";
7
+ import type { ColorSystemName, OutputTarget } from "./color.js";
7
8
  import type { Env } from "./env.js";
8
- import type { TerminalTheme } from "./color.js";
9
+ import type { TerminalColors, TerminalTheme } from "./color.js";
9
10
  import { type JSONOptions } from "./json.js";
10
11
  import type { Highlighter } from "./highlighter.js";
11
12
  import { type RuleOptions } from "../renderables/rule.js";
@@ -44,7 +45,7 @@ export interface ConsoleOptions {
44
45
  * Color encoding. Accepts a `ColorSystemName` (`"auto"`, `"truecolor"`,
45
46
  * `"256"`, `"ansi"`, `"none"`), a `ColorDepth` enum value (use this for
46
47
  * `WINDOWS`, which has no name), or `null` for no color. Default `"auto"`.
47
- * Colour only: an explicit depth, `null` included, keeps hyperlinks.
48
+ * Color only: an explicit depth, `null` included, keeps hyperlinks.
48
49
  */
49
50
  colorSystem?: ColorSystemName | ColorDepth | null;
50
51
  /**
@@ -53,6 +54,8 @@ export interface ConsoleOptions {
53
54
  * TERM=dumb: false). `false` with `colorSystem: null` writes plain text.
54
55
  */
55
56
  hyperlinks?: boolean;
57
+ /** What the output's destination does with direction. Default: what `detectTextOrder` finds. */
58
+ textOrder?: TextOrder;
56
59
  /**
57
60
  * The terminal can draw only ASCII: boxes, rules, tree guides and widget
58
61
  * marks draw with ASCII characters instead of line-drawing glyphs. A
@@ -69,6 +72,12 @@ export interface ConsoleOptions {
69
72
  * it in; nothing here reads the environment for it. Default false.
70
73
  */
71
74
  reducedMotion?: boolean;
75
+ /**
76
+ * The terminal this console draws on (`RenderOptions.terminal`), which
77
+ * every effect it draws resolves its colors on. Default: the one the
78
+ * color depth assumes.
79
+ */
80
+ terminal?: TerminalColors;
72
81
  /**
73
82
  * Static width (cells). Ignored when `getSize` is provided. Falls back to
74
83
  * the `COLUMNS` env var / the bound stream's `columns` / 80.
@@ -104,7 +113,7 @@ export interface ConsoleOptions {
104
113
  stderr?: boolean;
105
114
  file?: ConsoleSink;
106
115
  /**
107
- * Host facilities to consult for colour detection, size detection, and the
116
+ * Host facilities to consult for color detection, size detection, and the
108
117
  * default output sink. Defaults to the ambient `process`, or — where there
109
118
  * is no `process` — an empty environment with no streams. Pass this to drive
110
119
  * a `Console` deterministically, or to run one against a simulated terminal.
@@ -149,6 +158,7 @@ export declare class Console {
149
158
  private readonly _lastLogTime;
150
159
  private readonly _style;
151
160
  private readonly _isTerminal;
161
+ private readonly _attended;
152
162
  private readonly _interactive;
153
163
  private readonly _file;
154
164
  private readonly _stream;
@@ -156,6 +166,7 @@ export declare class Console {
156
166
  private readonly _markup;
157
167
  private readonly _highlight;
158
168
  private readonly _theme;
169
+ private readonly _terminal;
159
170
  private readonly _onStyleError;
160
171
  private readonly _asciiOnly;
161
172
  private readonly _highlighter;
@@ -174,12 +185,12 @@ export declare class Console {
174
185
  get isInteractive(): boolean;
175
186
  get colorSystem(): ColorDepth | null;
176
187
  /**
177
- * Where this console writes: the colour depth it draws at, whether it
188
+ * Where this console writes: the color depth it draws at, whether it
178
189
  * emits OSC 8 hyperlinks, and whether its reader asked for reduced motion,
179
190
  * overrides applied — the value its output is
180
191
  * encoded for, for anything that encodes on its behalf (`Live`).
181
192
  */
182
- get destination(): Destination;
193
+ get destination(): OutputTarget;
183
194
  get file(): ConsoleSink;
184
195
  get theme(): Theme;
185
196
  get options(): RenderOptions & {
@@ -188,10 +199,16 @@ export declare class Console {
188
199
  print(...args: unknown[]): void;
189
200
  private _draw;
190
201
  log(...args: unknown[]): void;
202
+ /**
203
+ * Sounds the terminal's bell, Rich's `Console.bell`, for whoever is at it: a
204
+ * pipe, a dumb terminal and a capture get nothing. It goes straight to the sink
205
+ * because a bell moves no cursor, and a live region would repaint its frame.
206
+ */
207
+ bell(): void;
191
208
  rule(title?: string, options?: RuleOptions): void;
192
209
  printJson(json: string | object, options?: JSONOptions): void;
193
210
  /**
194
- * Hold `region` under everything this console writes until the returned
211
+ * Keep `region` under everything this console writes until the returned
195
212
  * call lets it go. One region at a time: a second would be erased and
196
213
  * painted over by the first, so claiming one while another is held throws.
197
214
  */
@@ -3,7 +3,8 @@
3
3
  */
4
4
  import { Segment } from "./segment.js";
5
5
  import { NULL_STYLE, DEFAULT_THEME } from "./style.js";
6
- import { isDumbTerminal, resolveDestination } from "./color.js";
6
+ import { resolveOutputTarget } from "./color.js";
7
+ import { isDumbTerminal } from "./env.js";
7
8
  import { encodeHtml } from "./export-html.js";
8
9
  import { encodeSvg } from "./export-svg.js";
9
10
  import { RichText } from "./text.js";
@@ -17,6 +18,7 @@ import { ReprHighlighter, NullHighlighter } from "./highlighter.js";
17
18
  // rather than being restated here; see `rule()`.
18
19
  import { Rule } from "../renderables/rule.js";
19
20
  import { segmentsToString, shownOn } from "./render.js";
21
+ import { sealed } from "./seal.js";
20
22
  import { placeBlock } from "./place.js";
21
23
  import { activePass, isRenderable, measure, render } from "./protocol.js";
22
24
  import { ListState, State, refuseRenderWrite } from "./state.js";
@@ -93,7 +95,7 @@ function ambientEnvironment() {
93
95
  // bytes go — is a question about *that* stream. Selecting it once, here, is
94
96
  // what makes the three answers agree. When each site re-selected for itself,
95
97
  // one of them (size) silently didn't, and a `Console({ stderr: true })` keyed
96
- // its colour to stderr and its width to stdout.
98
+ // its color to stderr and its width to stdout.
97
99
  function boundStream(environment, useStderr) {
98
100
  return useStderr ? environment.stderr : environment.stdout;
99
101
  }
@@ -181,6 +183,7 @@ export class Console {
181
183
  _lastLogTime = new State(null);
182
184
  _style;
183
185
  _isTerminal;
186
+ _attended;
184
187
  _interactive;
185
188
  _file;
186
189
  // [LAW:one-source-of-truth] The resolved output stream, not the `stderr`
@@ -191,6 +194,7 @@ export class Console {
191
194
  _markup;
192
195
  _highlight;
193
196
  _theme;
197
+ _terminal;
194
198
  _onStyleError;
195
199
  _asciiOnly;
196
200
  _highlighter;
@@ -211,7 +215,7 @@ export class Console {
211
215
  // [LAW:dataflow-not-control-flow] `isTTY` and `env` are forwarded
212
216
  // unconditionally, so detection stays inside the console's injected
213
217
  // environment rather than the ambient process's.
214
- const resolved = resolveDestination(options?.colorSystem === undefined ? "auto" : options.colorSystem, { isTTY: this._isTerminal, env: environment.env, reducedMotion: options?.reducedMotion });
218
+ const resolved = resolveOutputTarget(options?.colorSystem === undefined ? "auto" : options.colorSystem, { isTTY: this._isTerminal, env: environment.env, reducedMotion: options?.reducedMotion, ...(options?.textOrder === undefined ? {} : { textOrder: options.textOrder }) });
215
219
  // [LAW:single-enforcer] The console's one override, an explicit
216
220
  // `hyperlinks`, is applied here and nowhere else; every write encodes for
217
221
  // this value whole. [LAW:one-source-of-truth] The reader's motion
@@ -223,9 +227,12 @@ export class Console {
223
227
  // [LAW:no-ambient-temporal-coupling] The theme is assigned before the
224
228
  // style, because the console's own style may be one of the theme's names.
225
229
  this._theme = options?.theme ?? DEFAULT_THEME;
230
+ this._terminal = options?.terminal;
226
231
  this._style = this._theme.resolve(options?.style ?? NULL_STYLE);
227
- // Rich's rule: a terminal is interactive unless it is a dumb one.
228
- this._interactive = options?.forceInteractive ?? (this._isTerminal && !isDumbTerminal(environment.env));
232
+ // Rich's rule: a terminal is interactive unless it is a dumb one. Forcing that
233
+ // is animation policy, and says nothing of who is at the terminal.
234
+ this._attended = this._isTerminal && !isDumbTerminal(environment.env);
235
+ this._interactive = options?.forceInteractive ?? this._attended;
229
236
  this._file = options?.file;
230
237
  this._record = options?.record ?? false;
231
238
  this._markup = options?.markup !== false;
@@ -254,7 +261,7 @@ export class Console {
254
261
  return this._destination.colorSystem;
255
262
  }
256
263
  /**
257
- * Where this console writes: the colour depth it draws at, whether it
264
+ * Where this console writes: the color depth it draws at, whether it
258
265
  * emits OSC 8 hyperlinks, and whether its reader asked for reduced motion,
259
266
  * overrides applied — the value its output is
260
267
  * encoded for, for anything that encodes on its behalf (`Live`).
@@ -290,6 +297,8 @@ export class Console {
290
297
  theme: this._theme,
291
298
  onStyleError: this._onStyleError,
292
299
  colorSystem: this._destination.colorSystem,
300
+ textOrder: this._destination.textOrder,
301
+ terminal: this._terminal,
293
302
  markup: this._markup,
294
303
  highlight: this._highlight,
295
304
  highlighter: this._highlighter,
@@ -495,6 +504,16 @@ export class Console {
495
504
  // stamp, so the next row's must show.
496
505
  this._lastLogTime.set(stamped);
497
506
  }
507
+ /**
508
+ * Sounds the terminal's bell, Rich's `Console.bell`, for whoever is at it: a
509
+ * pipe, a dumb terminal and a capture get nothing. It goes straight to the sink
510
+ * because a bell moves no cursor, and a live region would repaint its frame.
511
+ */
512
+ bell() {
513
+ refuseRenderWrite(this._madeIn);
514
+ if (this._attended && this._capture.get() === null)
515
+ this.file.write("\x07");
516
+ }
498
517
  // [LAW:one-source-of-truth] `RuleOptions` is `Rule`'s, not a restatement of
499
518
  // it. `console.ts` used to declare its own copy and field-by-field forward
500
519
  // into this constructor, which made a second map of one shape — identical
@@ -515,7 +534,7 @@ export class Console {
515
534
  }
516
535
  // --- Live region ---
517
536
  /**
518
- * Hold `region` under everything this console writes until the returned
537
+ * Keep `region` under everything this console writes until the returned
519
538
  * call lets it go. One region at a time: a second would be erased and
520
539
  * painted over by the first, so claiming one while another is held throws.
521
540
  */
@@ -547,7 +566,7 @@ export class Console {
547
566
  }
548
567
  // --- Export (when record:true) ---
549
568
  exportText({ clear = true } = {}) {
550
- const text = this._recorded.get().map((s) => s.text).join("");
569
+ const text = [...sealed(this._recorded.get(), "plain")].map((s) => s.text).join("");
551
570
  if (clear)
552
571
  this._recorded.set([]);
553
572
  return text;