@weasel-js/labkit 1.3.0-pre.0 → 1.3.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 (110) hide show
  1. package/dist/_dts/{index-DgcNdEdh.d.ts → types-BttTIent.d.ts} +2 -2
  2. package/dist/_dts/{types-AHlQxBNN.d.ts → types-DCGEcMO_.d.ts} +1 -1
  3. package/dist/canvas/index.d.ts +2 -2
  4. package/dist/canvas/index.js +3 -2
  5. package/dist/chrome/index.d.ts +3 -3
  6. package/dist/chrome/index.js +6 -5
  7. package/dist/chunk-3XXPU73K.js +138 -0
  8. package/dist/chunk-3XXPU73K.js.map +1 -0
  9. package/dist/{chunk-PO6L3NSH.js → chunk-6X5RBC6G.js} +17 -17
  10. package/dist/chunk-6X5RBC6G.js.map +1 -0
  11. package/dist/{chunk-NS54R52R.js → chunk-BDJXIBRZ.js} +5 -17
  12. package/dist/chunk-BDJXIBRZ.js.map +1 -0
  13. package/dist/{chunk-V7PRSIRQ.js → chunk-BMW4TDP5.js} +4 -4
  14. package/dist/chunk-BMW4TDP5.js.map +1 -0
  15. package/dist/{chunk-O7NVSCLN.js → chunk-JDROYQM3.js} +8 -8
  16. package/dist/chunk-JDROYQM3.js.map +1 -0
  17. package/dist/{chunk-HFDVGF4X.js → chunk-LGKRIUSW.js} +3 -3
  18. package/dist/{chunk-HFDVGF4X.js.map → chunk-LGKRIUSW.js.map} +1 -1
  19. package/dist/{chunk-Z6HJ5FEM.js → chunk-QCICIHEO.js} +19 -7
  20. package/dist/{chunk-Z6HJ5FEM.js.map → chunk-QCICIHEO.js.map} +1 -1
  21. package/dist/{chunk-RVNN4CHQ.js → chunk-QRYPXSGP.js} +5 -5
  22. package/dist/{chunk-RVNN4CHQ.js.map → chunk-QRYPXSGP.js.map} +1 -1
  23. package/dist/chunk-RGT4EJIB.js +6961 -0
  24. package/dist/chunk-RGT4EJIB.js.map +1 -0
  25. package/dist/chunk-SBXNQW4G.js +3 -0
  26. package/dist/chunk-SBXNQW4G.js.map +1 -0
  27. package/dist/chunk-T66HU3HX.js +17 -0
  28. package/dist/chunk-T66HU3HX.js.map +1 -0
  29. package/dist/chunk-WTI26YTM.js +266 -0
  30. package/dist/chunk-WTI26YTM.js.map +1 -0
  31. package/dist/controls/index.d.ts +2 -2
  32. package/dist/controls/index.js +3 -3
  33. package/dist/dragdrop/index.d.ts +44 -3
  34. package/dist/dragdrop/index.js +3 -1
  35. package/dist/index.d.ts +571 -541
  36. package/dist/index.js +69 -541
  37. package/dist/index.js.map +1 -1
  38. package/dist/layers/index.d.ts +3 -3
  39. package/dist/layers/index.js +4 -2
  40. package/dist/passthrough/weasel-canvas.js +1 -1
  41. package/dist/passthrough/weasel-ui.d.ts +15 -2
  42. package/dist/passthrough/weasel-ui.js +3 -2
  43. package/dist/primitives/index.js +5 -4
  44. package/dist/styles.css +1 -703
  45. package/dist/surface/index.js +2 -2
  46. package/dist/ui/layers/index.d.ts +8 -2
  47. package/dist/ui/layers/index.js +2 -4
  48. package/dist/undo/index.d.ts +2 -2
  49. package/package.json +5 -5
  50. package/src/config/builder.test.ts +7 -1
  51. package/src/config/builder.ts +1 -5
  52. package/src/config/resolve.test.ts +1 -2
  53. package/src/controls/ControlPanel.stories.tsx +41 -2
  54. package/src/controls/ControlPanel.test.tsx +31 -9
  55. package/src/controls/ControlPanel.tsx +56 -22
  56. package/src/dragdrop/index.ts +11 -0
  57. package/src/index.ts +49 -2
  58. package/src/lab/index.ts +1 -1
  59. package/src/layers/AGENTS.md +1 -1
  60. package/src/layers/LayerList.tsx +1 -1
  61. package/src/passthrough/weasel-ui.ts +22 -17
  62. package/src/styles.less +0 -4
  63. package/src/theme/Interstellar.stories.tsx +1 -1
  64. package/src/trial/Trial.config.test.tsx +3 -8
  65. package/src/ui/layers/index.ts +5 -1
  66. package/dist/chunk-NS54R52R.js.map +0 -1
  67. package/dist/chunk-O2BULFHX.js +0 -152
  68. package/dist/chunk-O2BULFHX.js.map +0 -1
  69. package/dist/chunk-O7NVSCLN.js.map +0 -1
  70. package/dist/chunk-PO6L3NSH.js.map +0 -1
  71. package/dist/chunk-PQJ5B2U2.js +0 -27
  72. package/dist/chunk-PQJ5B2U2.js.map +0 -1
  73. package/dist/chunk-TLGRYALP.js +0 -6151
  74. package/dist/chunk-TLGRYALP.js.map +0 -1
  75. package/dist/chunk-V7PRSIRQ.js.map +0 -1
  76. package/dist/chunk-ZZAYVX4X.js +0 -505
  77. package/dist/chunk-ZZAYVX4X.js.map +0 -1
  78. package/src/primitives/DragHandleGlyph.tsx +0 -29
  79. package/src/ui/format.test.ts +0 -33
  80. package/src/ui/format.ts +0 -30
  81. package/src/ui/layers/LayerStack.less +0 -143
  82. package/src/ui/layers/LayerStack.stories.tsx +0 -45
  83. package/src/ui/layers/LayerStack.test.tsx +0 -170
  84. package/src/ui/layers/LayerStack.tsx +0 -208
  85. package/src/ui/properties/CheckboxRow.stories.tsx +0 -27
  86. package/src/ui/properties/ColorRow.stories.tsx +0 -106
  87. package/src/ui/properties/CurveField.less +0 -48
  88. package/src/ui/properties/CurveField.stories.tsx +0 -20
  89. package/src/ui/properties/CurveField.test.tsx +0 -127
  90. package/src/ui/properties/CurveField.tsx +0 -184
  91. package/src/ui/properties/EffectCard.tsx +0 -324
  92. package/src/ui/properties/Gallery.stories.tsx +0 -178
  93. package/src/ui/properties/NumberRow.stories.tsx +0 -65
  94. package/src/ui/properties/PropertyGroup.less +0 -50
  95. package/src/ui/properties/PropertyGroup.stories.tsx +0 -34
  96. package/src/ui/properties/PropertyGroup.test.tsx +0 -33
  97. package/src/ui/properties/PropertyGroup.tsx +0 -45
  98. package/src/ui/properties/PropertyList.stories.tsx +0 -83
  99. package/src/ui/properties/PropertyPanel.less +0 -606
  100. package/src/ui/properties/PropertyPanel.stories.tsx +0 -190
  101. package/src/ui/properties/PropertyPanel.test.tsx +0 -193
  102. package/src/ui/properties/PropertyPanel.tsx +0 -469
  103. package/src/ui/properties/PropertyRow.stories.tsx +0 -53
  104. package/src/ui/properties/SelectRow.stories.tsx +0 -58
  105. package/src/ui/properties/SliderRow.stories.tsx +0 -74
  106. package/src/ui/properties/SpeechBalloonPanels.stories.tsx +0 -398
  107. package/src/ui/properties/TextRow.stories.tsx +0 -62
  108. package/src/ui/properties/ToggleRow.stories.tsx +0 -57
  109. package/src/ui/properties/index.ts +0 -39
  110. package/src/ui/properties/storyLayouts.tsx +0 -36
@@ -1,106 +0,0 @@
1
- import type { Meta, StoryObj } from '@storybook/react-vite';
2
- import { useState } from 'react';
3
- import { ColorRow, PropertyList } from './PropertyPanel';
4
-
5
- const meta: Meta<typeof ColorRow> = {
6
- title: 'labkit/UI/Properties/Rows/ColorRow',
7
- component: ColorRow,
8
- };
9
- export default meta;
10
- type Story = StoryObj<typeof ColorRow>;
11
-
12
- function One({ initial, label }: { initial: string; label: string }) {
13
- const [value, setValue] = useState(initial);
14
- return (
15
- <div style={{ width: 280 }}>
16
- <ColorRow label={label} value={value} onChange={setValue} />
17
- </div>
18
- );
19
- }
20
-
21
- export const Single: Story = {
22
- render: () => <One initial="#b08adb" label="Fill" />,
23
- };
24
-
25
- function Pair() {
26
- const [fill, setFill] = useState('#b08adb');
27
- const [stroke, setStroke] = useState('#1a1428');
28
- return (
29
- <div style={{ width: 320 }}>
30
- <PropertyList>
31
- <ColorRow label="Fill" value={fill} onChange={setFill} />
32
- <ColorRow label="Stroke" value={stroke} onChange={setStroke} />
33
- </PropertyList>
34
- </div>
35
- );
36
- }
37
-
38
- export const PairInList: Story = {
39
- render: () => <Pair />,
40
- };
41
-
42
- function OneWithAlpha({
43
- initial,
44
- initialAlpha,
45
- label,
46
- alphaDisabled,
47
- }: {
48
- initial: string;
49
- initialAlpha: number;
50
- label: string;
51
- alphaDisabled?: boolean;
52
- }) {
53
- const [value, setValue] = useState(initial);
54
- const [alpha, setAlpha] = useState(initialAlpha);
55
- return (
56
- <div style={{ width: 280 }}>
57
- <ColorRow
58
- label={label}
59
- value={value}
60
- onChange={setValue}
61
- alpha={alpha}
62
- onAlphaChange={setAlpha}
63
- alphaDisabled={alphaDisabled}
64
- />
65
- </div>
66
- );
67
- }
68
-
69
- export const WithAlpha: Story = {
70
- render: () => <OneWithAlpha initial="#7ec8e3" initialAlpha={0.65} label="Fill" />,
71
- };
72
-
73
- export const AlphaDisabled: Story = {
74
- render: () => <OneWithAlpha initial="#7ec8e3" initialAlpha={1} label="Fill" alphaDisabled />,
75
- };
76
-
77
- function AlphaPair() {
78
- const [fill, setFill] = useState('#b08adb');
79
- const [fillA, setFillA] = useState(0.8);
80
- const [stroke, setStroke] = useState('#1a1428');
81
- const [strokeA, setStrokeA] = useState(0.4);
82
- return (
83
- <div style={{ width: 320 }}>
84
- <PropertyList>
85
- <ColorRow
86
- label="Fill"
87
- value={fill}
88
- onChange={setFill}
89
- alpha={fillA}
90
- onAlphaChange={setFillA}
91
- />
92
- <ColorRow
93
- label="Stroke"
94
- value={stroke}
95
- onChange={setStroke}
96
- alpha={strokeA}
97
- onAlphaChange={setStrokeA}
98
- />
99
- </PropertyList>
100
- </div>
101
- );
102
- }
103
-
104
- export const AlphaPairInList: Story = {
105
- render: () => <AlphaPair />,
106
- };
@@ -1,48 +0,0 @@
1
- .lk-curve-field {
2
- display: grid;
3
- gap: 6px;
4
- grid-column: 1 / -1;
5
- }
6
-
7
- .lk-curve-field__plot {
8
- position: relative;
9
- width: 100%;
10
- }
11
-
12
- .lk-curve-field__marks {
13
- position: absolute;
14
- inset: 0;
15
- pointer-events: none;
16
- }
17
-
18
- .lk-curve-field__readouts {
19
- display: flex;
20
- justify-content: space-between;
21
- font-variant-numeric: tabular-nums;
22
- font-size: var(--wzl-font-size);
23
- color: var(--wzl-fg-subtle);
24
- }
25
-
26
- .lk-curve-field__readout {
27
- font-style: normal;
28
- }
29
-
30
- .lk-curve-field__actions {
31
- display: flex;
32
- gap: 6px;
33
- justify-self: start;
34
- }
35
-
36
- .lk-curve-field__action {
37
- background: transparent;
38
- border: 1px solid var(--wzl-border);
39
- border-radius: var(--wzl-radius-sm);
40
- color: var(--wzl-fg);
41
- padding: 4px 10px;
42
- font-size: var(--wzl-font-size-sm);
43
- cursor: pointer;
44
- }
45
-
46
- .lk-curve-field__action:hover {
47
- background: var(--wzl-surface-raised);
48
- }
@@ -1,20 +0,0 @@
1
- import type { Meta, StoryObj } from '@storybook/react-vite';
2
- import { useState } from 'react';
3
- import { CurveField } from './CurveField';
4
-
5
- const meta: Meta<typeof CurveField> = {
6
- title: 'labkit/UI/Properties/CurveField',
7
- component: CurveField,
8
- };
9
- export default meta;
10
-
11
- export const DomeContour: StoryObj<typeof CurveField> = {
12
- render: () => {
13
- const [v, setV] = useState<number[]>([0, -1, 0.5, 0.5, 1, 0.7]);
14
- return (
15
- <div style={{ width: 280 }}>
16
- <CurveField values={v} min={-1} max={1} step={0.02} width={280} onChange={setV} />
17
- </div>
18
- );
19
- },
20
- };
@@ -1,127 +0,0 @@
1
- import { render, screen } from '@testing-library/react';
2
- import { assert, describe, expect, it, vi } from 'vitest';
3
-
4
- // CurveEditor uses weasel's own bundled React and fails in jsdom.
5
- // Mock it out — these tests only assert on readouts and the flip button.
6
- vi.mock('../../passthrough/weasel-ui', async (importOriginal) => {
7
- const real = await importOriginal<typeof import('../../passthrough/weasel-ui')>();
8
- return { ...real, CurveEditor: () => null };
9
- });
10
-
11
- import { CurveField } from './CurveField';
12
-
13
- describe('CurveField', () => {
14
- it('flip button mirrors x → 1-x and resorts', () => {
15
- const onChange = vi.fn();
16
- render(
17
- <CurveField
18
- values={[0, -1, 0.3, 0.4, 1, 0.7]}
19
- min={-1}
20
- max={1}
21
- step={0.02}
22
- width={200}
23
- height={110}
24
- onChange={onChange}
25
- />,
26
- );
27
- screen.getByRole('button', { name: /flip horizontally/i }).click();
28
- expect(onChange).toHaveBeenCalledTimes(1);
29
- // After flip: (0,-1) → (1,-1), (0.3,0.4) → (0.7,0.4), (1,0.7) → (0,0.7).
30
- // Sort by x ascending: (0,0.7), (0.7,0.4), (1,-1).
31
- expect(onChange.mock.calls[0][0]).toEqual([0, 0.7, 0.7, 0.4, 1, -1]);
32
- });
33
-
34
- it('flip vertically mirrors y through (min+max)/2 and keeps x order', () => {
35
- const onChange = vi.fn();
36
- render(
37
- <CurveField
38
- values={[0, -1, 0.3, 0.4, 1, 0.7]}
39
- min={-1}
40
- max={1}
41
- step={0.02}
42
- width={200}
43
- height={110}
44
- onChange={onChange}
45
- />,
46
- );
47
- screen.getByRole('button', { name: /flip vertically/i }).click();
48
- expect(onChange).toHaveBeenCalledTimes(1);
49
- // (min+max)/2 = 0. -1 → 1, 0.4 → -0.4, 0.7 → -0.7. x order preserved.
50
- expect(onChange.mock.calls[0][0]).toEqual([0, 1, 0.3, -0.4, 1, -0.7]);
51
- });
52
-
53
- it('flip vertically with [0,1] range mirrors through 0.5', () => {
54
- const onChange = vi.fn();
55
- render(
56
- <CurveField
57
- values={[0, 0, 0.5, 0.25, 1, 1]}
58
- min={0}
59
- max={1}
60
- step={0.01}
61
- width={200}
62
- height={110}
63
- onChange={onChange}
64
- />,
65
- );
66
- screen.getByRole('button', { name: /flip vertically/i }).click();
67
- expect(onChange.mock.calls[0][0]).toEqual([0, 1, 0.5, 0.75, 1, 0]);
68
- });
69
-
70
- it('renders a band mark as a positioned overlay rect', () => {
71
- const { container } = render(
72
- <CurveField
73
- values={[0, 0, 1, 1]}
74
- min={0}
75
- max={1}
76
- step={0.01}
77
- width={200}
78
- height={110}
79
- marks={[{ kind: 'band', x: [0.2, 0.4], color: '#ffcc00' }]}
80
- onChange={() => {}}
81
- />,
82
- );
83
- const overlay = container.querySelector('.lk-curve-field__marks');
84
- assert(overlay);
85
- const rect = overlay.querySelector('rect');
86
- assert(rect);
87
- // x = 0.2 * 200 = 40; width = (0.4 - 0.2) * 200 = 40.
88
- expect(rect.getAttribute('x')).toBe('40');
89
- expect(rect.getAttribute('width')).toBe('40');
90
- expect(rect.getAttribute('fill')).toBe('#ffcc00');
91
- });
92
-
93
- it('renders a line mark as a positioned line', () => {
94
- const { container } = render(
95
- <CurveField
96
- values={[0, 0, 1, 1]}
97
- min={0}
98
- max={1}
99
- step={0.01}
100
- width={200}
101
- height={110}
102
- marks={[{ kind: 'line', x: 0.7, color: '#ffcc00' }]}
103
- onChange={() => {}}
104
- />,
105
- );
106
- const line = container.querySelector('.lk-curve-field__marks line');
107
- assert(line);
108
- expect(line.getAttribute('x1')).toBe('140');
109
- expect(line.getAttribute('x2')).toBe('140');
110
- expect(line.getAttribute('stroke')).toBe('#ffcc00');
111
- });
112
-
113
- it('omits the marks overlay when marks is undefined', () => {
114
- const { container } = render(
115
- <CurveField
116
- values={[0, 0, 1, 1]}
117
- min={0}
118
- max={1}
119
- step={0.01}
120
- width={200}
121
- height={110}
122
- onChange={() => {}}
123
- />,
124
- );
125
- expect(container.querySelector('.lk-curve-field__marks')).toBeNull();
126
- });
127
- });
@@ -1,184 +0,0 @@
1
- import { useCallback, useMemo } from 'react';
2
- import { type ControlPoint, CurveEditor, dlog } from '../../passthrough/weasel-ui';
3
-
4
- /** An annotation drawn over a curve plot: a shaded band across a range of x,
5
- * or a vertical line at one x. */
6
- export type CurveMark =
7
- | { kind: 'band'; x: [number, number]; color?: string }
8
- | { kind: 'line'; x: number; color?: string };
9
-
10
- /** Props for `<CurveField>`. */
11
- export interface CurveFieldProps {
12
- /** Flat [x0, y0, x1, y1, …] — matches how curve-as-array configs
13
- * serialize in JSON snapshots. */
14
- values: number[];
15
- min: number;
16
- max: number;
17
- step: number;
18
- /** Plot width in CSS px. Caller sizes (typically uses a ResizeObserver). */
19
- width: number;
20
- /** Plot height in CSS px. Default 110. */
21
- height?: number;
22
- /** Flat default curve. When provided, a Reset button restores it. */
23
- defaults?: readonly number[];
24
- onChange: (next: number[]) => void;
25
- /** Optional vertical marks overlaid on the plot (e.g. landmarks). */
26
- marks?: readonly CurveMark[];
27
- }
28
-
29
- /**
30
- * A function-domain (y = f(x), x ∈ [0,1]) curve editor with per-stop
31
- * numeric readouts and flip buttons. Wraps weasel-ui's
32
- * `CurveEditor`; consumers wanting the raw editor (2D paths,
33
- * custom anchors) should import it from `@weasel-js/labkit/weasel-ui`.
34
- */
35
- export function CurveField({
36
- values,
37
- min,
38
- max,
39
- step,
40
- width,
41
- height = 110,
42
- defaults,
43
- onChange,
44
- marks,
45
- }: CurveFieldProps) {
46
- const points: ControlPoint[] = useMemo(() => {
47
- const out: ControlPoint[] = [];
48
- for (let i = 0; i + 1 < values.length; i += 2) out.push({ x: values[i], y: values[i + 1] });
49
- return out;
50
- }, [values]);
51
-
52
- const handleChange = useCallback(
53
- (next: ControlPoint[]) => {
54
- const flat: number[] = new Array(next.length * 2);
55
- for (let i = 0; i < next.length; i++) {
56
- const ySnap = Math.round(next[i].y / step) * step;
57
- const y = Math.max(min, Math.min(max, ySnap));
58
- flat[i * 2] = next[i].x;
59
- flat[i * 2 + 1] = y;
60
- }
61
- dlog('curve-field', 'handleChange', {
62
- nLen: next.length,
63
- flatLen: flat.length,
64
- sample: flat.slice(0, 4),
65
- });
66
- onChange(flat);
67
- },
68
- [onChange, min, max, step],
69
- );
70
-
71
- const handleFlip = useCallback(() => {
72
- const flipped: Array<{ x: number; y: number }> = [];
73
- for (let i = 0; i + 1 < values.length; i += 2) {
74
- flipped.push({ x: 1 - values[i], y: values[i + 1] });
75
- }
76
- flipped.sort((a, b) => a.x - b.x);
77
- const out: number[] = [];
78
- for (const p of flipped) out.push(p.x, p.y);
79
- onChange(out);
80
- }, [values, onChange]);
81
-
82
- const handleFlipVertical = useCallback(() => {
83
- const mid = (min + max) / 2;
84
- const flipped: number[] = new Array(values.length);
85
- for (let i = 0; i + 1 < values.length; i += 2) {
86
- flipped[i] = values[i];
87
- flipped[i + 1] = 2 * mid - values[i + 1];
88
- }
89
- onChange(flipped);
90
- }, [values, min, max, onChange]);
91
-
92
- return (
93
- <div className="lk-curve-field">
94
- <div className="lk-curve-field__plot">
95
- <CurveEditor
96
- value={points}
97
- onInput={handleChange}
98
- domain="1d"
99
- constrain="function"
100
- xRange={[0, 1]}
101
- yRange={[min, max]}
102
- width={width}
103
- height={height}
104
- endpoints="pinned-x"
105
- addPointMode="click-curve"
106
- minPoints={2}
107
- grid={{}}
108
- history={false}
109
- />
110
- {marks && marks.length > 0 && (
111
- <svg
112
- className="lk-curve-field__marks"
113
- width={width}
114
- height={height}
115
- viewBox={`0 0 ${width} ${height}`}
116
- aria-hidden="true"
117
- >
118
- {marks.map((m) => {
119
- const color = m.color ?? '#ffcc00';
120
- if (m.kind === 'band') {
121
- const x0 = Math.max(0, Math.min(1, m.x[0])) * width;
122
- const x1 = Math.max(0, Math.min(1, m.x[1])) * width;
123
- const left = Math.min(x0, x1);
124
- const w = Math.abs(x1 - x0);
125
- return (
126
- <g key={`band-${m.x[0]}-${m.x[1]}-${color}`}>
127
- <rect x={left} y={0} width={w} height={height} fill={color} fillOpacity={0.4} />
128
- <line
129
- x1={left}
130
- y1={0}
131
- x2={left}
132
- y2={height}
133
- stroke={color}
134
- strokeOpacity={0.85}
135
- strokeWidth={1}
136
- />
137
- <line
138
- x1={left + w}
139
- y1={0}
140
- x2={left + w}
141
- y2={height}
142
- stroke={color}
143
- strokeOpacity={0.85}
144
- strokeWidth={1}
145
- />
146
- </g>
147
- );
148
- }
149
- const x = Math.max(0, Math.min(1, m.x)) * width;
150
- return (
151
- <line
152
- key={`mark-${m.x}-${color}`}
153
- x1={x}
154
- y1={0}
155
- x2={x}
156
- y2={height}
157
- stroke={color}
158
- strokeWidth={1}
159
- />
160
- );
161
- })}
162
- </svg>
163
- )}
164
- </div>
165
- <div className="lk-curve-field__actions">
166
- <button type="button" className="lk-curve-field__action" onClick={handleFlip}>
167
- Flip horizontally
168
- </button>
169
- <button type="button" className="lk-curve-field__action" onClick={handleFlipVertical}>
170
- Flip vertically
171
- </button>
172
- {defaults && (
173
- <button
174
- type="button"
175
- className="lk-curve-field__action"
176
- onClick={() => onChange([...defaults])}
177
- >
178
- Reset
179
- </button>
180
- )}
181
- </div>
182
- </div>
183
- );
184
- }