@citolab/pci-code-blocks 0.0.0-stage → 1.0.0-beta.1
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/LICENSE +22 -0
- package/README.md +277 -2
- package/codeBlocks.svg +11 -0
- package/dist/authoring.json +211 -0
- package/dist/index.js +1 -0
- package/dist/sbom.cdx.json +153 -0
- package/dist/tao-pci-codeBlocks_1.0.0-beta.1.zip +0 -0
- package/example.png +0 -0
- package/package.json +100 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 The National Center for University Entrance Examinations
|
|
4
|
+
Copyright (c) 2026 Stichting Cito Instituut voor Toetsontwikkeling (modifications)
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,278 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Code blocks
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> [!WARNING]
|
|
4
|
+
> **Experimental (beta).** This PCI is a new implementation of an open-source PCI (see "Source and licence"). It is
|
|
5
|
+
> offered as is, without any warranty, and has never been used in an assessment. Try it out with candidates and check
|
|
6
|
+
> its content and scoring before you use it in one.
|
|
7
|
+
|
|
8
|
+
A PCI in which the candidate **builds a program from code blocks**: they drag blocks (set a variable, read input,
|
|
9
|
+
print, if, if/else, while, repeat, for) from a palette into a program, nest them, fill in the blanks in the blocks
|
|
10
|
+
(text boxes and dropdowns), type the input and press **Run** to see what the program prints, or an error in plain
|
|
11
|
+
language with its line. The labels of the blocks are the author's pseudocode, in any language.
|
|
12
|
+
|
|
13
|
+
It is a port of the [Code Block Programming Interaction](https://github.com/rdncuee/CBP) for TAO, with one big
|
|
14
|
+
difference: the original attached JavaScript to every block and ran it; this PCI has a small block language and an
|
|
15
|
+
interpreter of its own and never runs code that an author or a candidate wrote (see below).
|
|
16
|
+
|
|
17
|
+
The default item asks for the sum 1 + 2 + … + n, with a locked `read n` line, seven blocks (two of them distractors),
|
|
18
|
+
blanks to fill in, the solution and three test cases.
|
|
19
|
+
|
|
20
|
+
<p align="center"><img src="./example.png" alt="Puzzle-piece blocks grouped by category on the left, four of them used; on a dotted canvas the program hangs from a green when Run is pressed block: read n (locked, striped), total ← 0, an orange C-shaped for i from 1 to n wrapping total ← total + i, and print total (selected, with its toolbar); the input 10 and the output 55" width="640"></p>
|
|
21
|
+
|
|
22
|
+
## What the candidate does
|
|
23
|
+
|
|
24
|
+
- **Build the program.** Drag a block from the palette into the program (above or below a line, into the empty branch
|
|
25
|
+
of a block, onto the lower half of a loop or condition to put it inside), or press it to add it below the selected
|
|
26
|
+
block. Drag a block by its handle to move it, or onto the palette to remove it. Blocks that hold blocks are C-shapes
|
|
27
|
+
that wrap their inside; an if/else has two mouths with an else bar between them. Removing a block
|
|
28
|
+
that holds blocks leaves them in its place (as in the original).
|
|
29
|
+
- **Keyboard.** Every block has a handle (a button): `↑` / `↓` move the block one line through the listing (into a
|
|
30
|
+
loop and out of it again, past other blocks), `→` puts it into the block above it, `←` takes it out of its block,
|
|
31
|
+
`Delete` removes it. The selected block also has buttons for this (move up, move down, out of the block, into the
|
|
32
|
+
block above, remove), for touch and mouse. The focus stays on the block that moved.
|
|
33
|
+
- **Fill in the blanks**: a text box (for a value, an expression or a name) or a dropdown with the author's choices.
|
|
34
|
+
- **Input and Run.** The input is a value per line (when the author allows, the candidate changes it). Run shows the
|
|
35
|
+
printed lines, or the error that stopped the program: "Error on line 3: the variable total has no value yet." The
|
|
36
|
+
line with the error is marked in the editor. A change to the program or the input clears the output.
|
|
37
|
+
- **Screen readers**: the program is a list; a handle is read as "Line 4: total ← total + i", the blanks as "Blank 1
|
|
38
|
+
on line 4", locked blocks as locked; every add, move, remove and run is announced in a live status line.
|
|
39
|
+
- **Look**: block-based programming style. Blocks are puzzle pieces with white bold text, a notch on top and a tab below,
|
|
40
|
+
so a stack looks snapped together. The program hangs from a "when Run is pressed" hat block on a dotted canvas. The
|
|
41
|
+
hat is only drawn: it is not part of the program, the `code` or the `codeblock`. If, if/else, while, repeat and for
|
|
42
|
+
are C-shapes: a top piece with an inner tab, an arm down the inside, and a closing bottom bar with its own tab (for
|
|
43
|
+
if/else also an else bar and a second mouth). The C is one continuous fill with no seams, a thin gap separates a C
|
|
44
|
+
inside a C, and an empty C shows a slot to drop a block into. In the palette the containers are small complete
|
|
45
|
+
C-shapes. Text boxes are white
|
|
46
|
+
pills, dropdowns are pills in a darker shade of the block with a ▾, and fixed parts are rounded reporter pills.
|
|
47
|
+
- **Colours**, with a legend in the palette, which groups the blocks by category. White text on each meets WCAG AA:
|
|
48
|
+
variables (`set`) raspberry `#C2335F`, 5.34:1; control (if, if/else, while, repeat, for) orange `#B25E00`,
|
|
49
|
+
4.67:1; input and output blue `#2D5FD3`, 5.69:1; the hat green `#1F7F4C`, 5.00:1. The dark shades of the dropdowns
|
|
50
|
+
are 6.9–8.1:1.
|
|
51
|
+
- **States**: the selected block has a white ring inside a dark one, drawn inside the piece, so it never covers the
|
|
52
|
+
blocks or bars around it. It is visible on every block colour and on the canvas, and the toolbar sits inside the
|
|
53
|
+
piece. The error line has a red ring. Locked blocks are striped on the whole shape (for a C
|
|
54
|
+
also the arm and the bars; the stripes only darken) and show a lock. Used blocks fade in the palette, with a "used" badge. While dragging, the block is lifted with a
|
|
55
|
+
shadow, and a piece-shaped gap shows where it will snap. Line numbers are kept, small and grey, for the error
|
|
56
|
+
messages.
|
|
57
|
+
- Large touch targets, one column in a narrow item (container queries, down to 360 px). The tilt of a dragged block
|
|
58
|
+
and the transitions are off with `prefers-reduced-motion`.
|
|
59
|
+
- Limits as in the original: at most 30 blocks in the program (`maxBlocks`), at most 5 levels of blocks inside blocks
|
|
60
|
+
(`maxDepth`), and a used block is used up unless `reuse` is on. The interpreter stops a program after 10 000 steps
|
|
61
|
+
(`maxSteps`, against loops that never end) or 500 printed lines.
|
|
62
|
+
|
|
63
|
+
## The block language
|
|
64
|
+
|
|
65
|
+
The author writes the blocks, a line per block: `kind: label`. The **kind** says what the block does, the **label** is
|
|
66
|
+
what the candidate sees, with parts in braces:
|
|
67
|
+
|
|
68
|
+
| in the label | is |
|
|
69
|
+
| ------------ | ---------------------------------------------------------- |
|
|
70
|
+
| `{}` | a text box the candidate fills in |
|
|
71
|
+
| `{a\|b\|c}` | a dropdown with these choices (at most 10) |
|
|
72
|
+
| `{total}` | fixed text: part of the code, not editable |
|
|
73
|
+
|
|
74
|
+
| kind | parts in braces, in order | example label |
|
|
75
|
+
| -------- | ------------------------------------------ | ------------------------------------- |
|
|
76
|
+
| `set` | a variable, a value | `set: {total} ← {}` |
|
|
77
|
+
| `input` | a variable: gets the next input value | `input: read {n}` |
|
|
78
|
+
| `print` | a value (or values separated by commas) | `print: print {total}` |
|
|
79
|
+
| `if` | a condition | `if: if {n} {<\|>} {0} then` |
|
|
80
|
+
| `ifelse` | a condition; after `\|` the else line | `ifelse: if {n mod 2 = 0} \| otherwise` |
|
|
81
|
+
| `while` | a condition | `while: while {total < n}` |
|
|
82
|
+
| `repeat` | a number of times | `repeat: repeat {} times` |
|
|
83
|
+
| `for` | a variable, from, to (steps of 1) | `for: for {i} from {1} to {}` |
|
|
84
|
+
|
|
85
|
+
Each part takes one pair of braces; the **last part takes the rest of the braces, with the text between them**: in
|
|
86
|
+
`set: {total} ← {total} {+|-|*} {i}` the variable is `total` and the value is `total + i` when the candidate chooses
|
|
87
|
+
`+`. Text before the first and after the last brace of a part is only label (`for`, `from`, `then`, `times`).
|
|
88
|
+
`if/else`, `if-else`, `assign`, `read`, `output` and `write` are accepted as kinds too.
|
|
89
|
+
|
|
90
|
+
**Values** are numbers (`3`, `2.5`), text in quotes (`"even"`), `true`/`false` and variables. The operators are
|
|
91
|
+
`+ - * /`, `div` or `//` (whole division), `mod` or `%` (remainder, with the sign of the divisor), `^` (power),
|
|
92
|
+
`= <> != < <= > >=` (and `≠ ≤ ≥`), `and or not`, and brackets. `+` with text joins text. Functions: `abs`, `round`,
|
|
93
|
+
`floor`, `ceil`, `sqrt`, `min`, `max`, `length` (also `len`, `lengte`, `longueur`). With `data-language="nl"` the
|
|
94
|
+
words `en of niet waar onwaar` work too, with `fr` `et ou non vrai faux`; true and false are printed in that language.
|
|
95
|
+
An input value is a number when it reads as one (`5`, `2,5`), otherwise text. A `for` from 1 to 0 does not run.
|
|
96
|
+
A condition must be true or false (`if 3` is an error, not "truthy").
|
|
97
|
+
|
|
98
|
+
A **program** (the starting program, the solution) is a block per line, indented inside a block, with the else of an
|
|
99
|
+
if/else as a line of its own at the level of its `if`:
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
* input: read {n}
|
|
103
|
+
total ← 0
|
|
104
|
+
for i from 1 to n
|
|
105
|
+
total ← total + i
|
|
106
|
+
print total
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
A line is plain code that one of the blocks matches (`total ← 0` fills the blank of `set: {total} ← {}`), or
|
|
110
|
+
`kind: label` for a block that is not in the palette (such as the locked `read {n}`). `*` in front locks a block: the
|
|
111
|
+
candidate cannot move or remove it (but fills its blanks). `#` starts a comment.
|
|
112
|
+
|
|
113
|
+
## Settings
|
|
114
|
+
|
|
115
|
+
Every setting is a `data-` attribute of the interaction, as text. `dist/authoring.json` describes them for authoring
|
|
116
|
+
systems.
|
|
117
|
+
|
|
118
|
+
| setting | attribute | default | what |
|
|
119
|
+
| ---------------------- | ------------------- | -------------- | ------------------------------------------------------------------------ |
|
|
120
|
+
| Instruction | `data-prompt` | the example's | above the blocks |
|
|
121
|
+
| Blocks ¹ | `data-blocks` | empty: the example | the palette, a block per line (above); blocks not in the solution are distractors |
|
|
122
|
+
| Starting program ¹ | `data-program` | empty | the program at the start, with locked blocks |
|
|
123
|
+
| Solution ¹ | `data-solution` | empty | the correct program: shown in solution status, and the correct response with `code` scoring |
|
|
124
|
+
| Input ¹ | `data-inputs` | empty | the input at the start, a value per line |
|
|
125
|
+
| Test cases ¹ | `data-tests` | empty | `5; 3 => 8` per line: input values `=>` the printed lines, at most 8 |
|
|
126
|
+
| Change the input | `data-edit-inputs` | `true` | the candidate can change the input |
|
|
127
|
+
| Reuse | `data-reuse` | `false` | a block can be used more than once (the original's repeat flag) |
|
|
128
|
+
| Response and scoring | `data-scoring` | `original` | `original`, `code` or `pci` (below) |
|
|
129
|
+
| Most blocks | `data-max-blocks` | `30` | 1 to 60 |
|
|
130
|
+
| Most levels | `data-max-depth` | `5` | blocks inside blocks, 1 to 10 |
|
|
131
|
+
| Most steps | `data-max-steps` | `10000` | per run |
|
|
132
|
+
| Language | `data-language` | `en` | `en`, `nl` or `fr`: the texts of the PCI, the example, and the words of the language |
|
|
133
|
+
|
|
134
|
+
¹ `"editor": "pci"`: written by the authoring mode (below), and still plain text an author can write by hand.
|
|
135
|
+
|
|
136
|
+
Without blocks the PCI shows the example in the language of the texts (with its prompt, starting program, solution,
|
|
137
|
+
input and tests where those are empty). What the PCI could not read of the settings goes to the console.
|
|
138
|
+
|
|
139
|
+
## Authoring mode
|
|
140
|
+
|
|
141
|
+
The original had a creator in TAO's item editor; this PCI has an authoring mode (`getAuthoringInstance`). An authoring
|
|
142
|
+
system that supports `pci` settings shows a button, **Make the blocks, the solution and the tests…** (in TAO above
|
|
143
|
+
the Blocks field, in TAO's own dialog), that opens it. It has four tabs and a list of checks above them:
|
|
144
|
+
|
|
145
|
+
- **Blocks**: a card per block with its kind, its label, and a row per part in braces (text box, dropdown with its
|
|
146
|
+
choices, or fixed text, named after what the part is: variable, value, condition, …), move up/down, remove, add a
|
|
147
|
+
part, and whether the candidate can add it (a block that is not in the palette is only in the starting program or
|
|
148
|
+
the solution). Each block shows whether it is *in the solution* or a *distractor*.
|
|
149
|
+
- **Solution**: the correct program, built in the candidate's own editor (drag and drop, keyboard, blanks), with the
|
|
150
|
+
output of the solution for the input at the start.
|
|
151
|
+
- **Starting program**: the same editor, with a *Locked* switch on every block, and *Start from the solution*.
|
|
152
|
+
- **Input and tests**: the input at the start and up to 8 test cases (input values → expected lines, one per line), a
|
|
153
|
+
pass/fail per test against the solution, and *Fill in the expected output from the solution*.
|
|
154
|
+
- **Checks**, live and in plain language: a kind of block without enough parts in braces, an unclosed brace, a
|
|
155
|
+
dropdown with fewer than two choices, a variable part that is not a name, more blocks or levels than `maxBlocks` /
|
|
156
|
+
`maxDepth`, empty blanks in the solution, tests the solution fails, values with `;`, no tests with
|
|
157
|
+
`data-scoring="pci"`, no solution with `data-scoring="code"`. These keep the author from finishing (`validate()`).
|
|
158
|
+
Notes that do not: no solution yet, a block the solution uses more often than the candidate can add it, a solution
|
|
159
|
+
that stops with an error for the input at the start.
|
|
160
|
+
|
|
161
|
+
The authoring mode writes the same text settings as above (`blocks`, `program`, `solution`, `inputs`, `tests`, the
|
|
162
|
+
settings with `"editor": "pci"`): plain code where reading it back gives the same block, `kind: label` lines where not.
|
|
163
|
+
Delivery, the response and the scoring do not change, and an authoring system without the authoring mode shows the
|
|
164
|
+
text. When the author changes nothing, the item keeps its own text (an item with the example stays the example). A
|
|
165
|
+
filled blank of a block that is not in the palette becomes fixed text when it is written. The texts of the authoring
|
|
166
|
+
mode follow the authoring system's language (`en`, `nl`, `fr`). The model is in `src/author.ts` (tested in node), the
|
|
167
|
+
view in `src/authoring.tsx`.
|
|
168
|
+
|
|
169
|
+
In TAO the five settings keep their fields in the properties form, but as one-line text fields (TAO's control for a
|
|
170
|
+
`pci` setting): edit multi-line text with the button.
|
|
171
|
+
|
|
172
|
+
## Response and scoring
|
|
173
|
+
|
|
174
|
+
**`data-scoring="original"`** (default): `cardinality="single" base-type="string"`, a JSON string with the keys of the
|
|
175
|
+
original, so that existing response processing and reports keep working:
|
|
176
|
+
|
|
177
|
+
```json
|
|
178
|
+
{
|
|
179
|
+
"result": ["15"],
|
|
180
|
+
"code": "read n\ntotal ← 0\nfor i from 1 to n\n total ← total + i\nprint total",
|
|
181
|
+
"codeblock": [
|
|
182
|
+
{ "id": "p1", "type": "input", "locked": true },
|
|
183
|
+
{ "id": "b1", "type": "set" },
|
|
184
|
+
{ "id": "b2", "type": "for", "nests": [[{ "id": "b3", "type": "set" }]] },
|
|
185
|
+
{ "id": "b4", "type": "print" }
|
|
186
|
+
],
|
|
187
|
+
"textbox": [{ "b1.2": "0" }, { "b2.2": "1" }, { "b2.3": "n" }],
|
|
188
|
+
"dropdown": [{ "b3.3": "+" }]
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
| key | in the original | here |
|
|
193
|
+
| ----------- | ---------------------------------------------------------- | -------------------------------------------------------------------------------------- |
|
|
194
|
+
| `result` | the printed lines of the last run (`[]` after a change) | the same; the lines printed before an error, `[]` when the program has not run since the last change |
|
|
195
|
+
| `code` | the generated JavaScript | the program as pseudocode: the labels with the blanks filled in (`___` when empty), four spaces per level |
|
|
196
|
+
| `codeblock` | the blocks: `id`, `type`, `nests` (a list per branch) | the same shape; `id` is `b1`, `b2` … in the order of `data-blocks` (`p1` … for blocks only in the starting program), `type` is `set`, `input`, `print`, `if`, `ifElse`, `while`, `repeat` or `for`, and a locked block has `"locked": true` |
|
|
197
|
+
| `textbox` | `{ id: value }` per text box, in the order of the program | the same, one per text box, with the id `block.part` (`b2.3`: the third part in braces of `b2`) |
|
|
198
|
+
| `dropdown` | `{ id: value }` per dropdown | the same |
|
|
199
|
+
|
|
200
|
+
Score it with custom response processing or by a rater (`human`).
|
|
201
|
+
|
|
202
|
+
**`data-scoring="code"`**: the `code` above as the response, for `match_correct`: the correct response is the
|
|
203
|
+
solution as code (`getCorrectResponse(properties)` gives it to an authoring system). Made for tasks where only one
|
|
204
|
+
program is right, such as putting given blocks in order (a Parsons problem).
|
|
205
|
+
|
|
206
|
+
**`data-scoring="pci"`**: the PCI runs the author's test cases on every change (not only when the candidate presses
|
|
207
|
+
Run) and reports a record, `cardinality="record"`, scored `custom`:
|
|
208
|
+
|
|
209
|
+
| field | type | what |
|
|
210
|
+
| ----------------- | --------- | ------------------------------------------------------------------------- |
|
|
211
|
+
| `score` | `integer` | the number of test cases the program passes |
|
|
212
|
+
| `maxscore` | `integer` | the number of test cases |
|
|
213
|
+
| `correct` | `integer` | 1 when it passes every test case, else 0 |
|
|
214
|
+
| `test1` … `test8` | `integer` | 1 or 0 per test case, only the tests there are |
|
|
215
|
+
| `code` | `string` | the program as pseudocode |
|
|
216
|
+
| `program` | `string` | the original's JSON (above) |
|
|
217
|
+
|
|
218
|
+
A test case passes when the program, run with its input values, prints exactly its lines (spaces around a line do not
|
|
219
|
+
count) and stops without an error.
|
|
220
|
+
|
|
221
|
+
In every mode `getResponse()` reports nothing until the candidate changed the program or the input, or ran it. A
|
|
222
|
+
response handed back (`boundTo`, or a correct response in the response declaration) can be any of the three: the
|
|
223
|
+
JSON, a record with `program`, or the code. In solution status the PCI shows the correct response of the declaration,
|
|
224
|
+
or else the author's solution, with its output for the author's input; in review and solution status it is read-only.
|
|
225
|
+
The whole state (program, input, last run) and a log of every action are saved and restored.
|
|
226
|
+
|
|
227
|
+
## Using it
|
|
228
|
+
|
|
229
|
+
```xml
|
|
230
|
+
<qti-response-declaration identifier="RESPONSE" cardinality="record"/>
|
|
231
|
+
…
|
|
232
|
+
<qti-portable-custom-interaction response-identifier="RESPONSE" module="pci" custom-interaction-type-identifier="codeBlocks"
|
|
233
|
+
data-scoring="pci" data-language="nl">
|
|
234
|
+
<qti-interaction-modules>
|
|
235
|
+
<qti-interaction-module id="pci" primary-path="../resources/pci/index"></qti-interaction-module>
|
|
236
|
+
</qti-interaction-modules>
|
|
237
|
+
<qti-interaction-markup></qti-interaction-markup>
|
|
238
|
+
</qti-portable-custom-interaction>
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
```sh
|
|
242
|
+
npm test # the interpreter, the model and the authoring model (src/interpreter.ts, blocks.ts, author.ts) in node
|
|
243
|
+
npm run test:stories # the stories' play functions, headless
|
|
244
|
+
npm run prod # dist/index.js
|
|
245
|
+
npm run package-qti3 # or package-tao
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## Source and licence
|
|
249
|
+
|
|
250
|
+
This PCI is a port of the [Code Block Programming Interaction](https://github.com/rdncuee/CBP) (`rdncuee/CBP`), a
|
|
251
|
+
TAO PCI by The National Center for University Entrance Examinations (Japan), © 2022. It is licensed under the MIT
|
|
252
|
+
licence (its `LICENSE` file and its README), and so is this PCI: see [LICENSE](LICENSE), which keeps the original's
|
|
253
|
+
copyright notice.
|
|
254
|
+
|
|
255
|
+
What changed, by Stichting Cito Instituut voor Toetsontwikkeling (2026):
|
|
256
|
+
|
|
257
|
+
- **No JavaScript per block.** In the original an author attached JavaScript to every block and the PCI ran the whole
|
|
258
|
+
program with `new Function` in a Web Worker (with a time limit). This PCI never evaluates code that an author or a
|
|
259
|
+
candidate wrote: it has a small declarative block language (set, input, print, if, if/else, while, repeat, for) and
|
|
260
|
+
an expression parser and interpreter of its own (`src/interpreter.ts`), with a step limit instead of a time limit.
|
|
261
|
+
The kinds of block follow the original's (process, print, if, if/else, while, for); set, input and repeat are new,
|
|
262
|
+
and process blocks with free code are gone.
|
|
263
|
+
- Rewritten in TypeScript with Preact and Tailwind in a shadow DOM (the original is jQuery with SortableJS and
|
|
264
|
+
js-beautify); no code or images of the original are used.
|
|
265
|
+
- The author writes the blocks as text (`kind: label` with `{}` blanks and `{a|b}` dropdowns) instead of the TAO
|
|
266
|
+
editor's `¥textField_…` and `¥selectBox_…[…]` codes; the starting program, locked blocks and the solution are text
|
|
267
|
+
too. The original's limits are kept as settings (30 blocks, 5 levels, reuse of blocks).
|
|
268
|
+
- Japanese texts became English, Dutch and French; the labels of the blocks are the author's.
|
|
269
|
+
- The original's creator (TAO authoring panels) became an authoring mode that writes the text settings: blocks, the
|
|
270
|
+
solution and the starting program in the candidate's editor, locks, input and test cases, with live checks.
|
|
271
|
+
- A puzzle-piece look in the style of block-based programming (an original design, see above) instead of the
|
|
272
|
+
original's coloured strips with icons.
|
|
273
|
+
- Keyboard and screen reader access (the original had drag and drop only), touch, plain-language errors with the line
|
|
274
|
+
instead of `alert` and `confirm` dialogs, the error line marked in the editor, and a start-over button with an inline
|
|
275
|
+
confirmation.
|
|
276
|
+
- **The response** keeps the original's JSON keys (with the mapping above); `code` is pseudocode instead of
|
|
277
|
+
JavaScript. New: the `code` response for `match_correct`, PCI scoring with the author's test cases, and the state
|
|
278
|
+
with a log of every action, saved and restored (the original restored the drawn HTML).
|
package/codeBlocks.svg
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32">
|
|
2
|
+
<rect x="3" y="4" width="20" height="6" rx="1.5" fill="#e0f2fe" stroke="#0284c7" stroke-width="1.2"/>
|
|
3
|
+
<rect x="3" y="4" width="2.5" height="6" rx="1" fill="#0284c7"/>
|
|
4
|
+
<rect x="3" y="12" width="22" height="6" rx="1.5" fill="#fef3c7" stroke="#d97706" stroke-width="1.2"/>
|
|
5
|
+
<rect x="3" y="12" width="2.5" height="6" rx="1" fill="#d97706"/>
|
|
6
|
+
<path d="M6 18v7" stroke="#d97706" stroke-width="1.6"/>
|
|
7
|
+
<rect x="9" y="20" width="17" height="5.5" rx="1.5" fill="#d1fae5" stroke="#059669" stroke-width="1.2"/>
|
|
8
|
+
<rect x="9" y="20" width="2.5" height="5.5" rx="1" fill="#059669"/>
|
|
9
|
+
<rect x="14" y="21.6" width="6" height="2.3" rx="0.6" fill="#fff" stroke="#059669" stroke-width="0.8" stroke-dasharray="1.2 0.8"/>
|
|
10
|
+
<path d="M26.5 4.5l3 2.5-3 2.5z" fill="#059669"/>
|
|
11
|
+
</svg>
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
{
|
|
2
|
+
"descriptorVersion": "1.0",
|
|
3
|
+
"typeIdentifier": "codeBlocks",
|
|
4
|
+
"version": "1.0.0-beta.1",
|
|
5
|
+
"label": "Code blocks",
|
|
6
|
+
"properties": {
|
|
7
|
+
"prompt": {
|
|
8
|
+
"editor": "textarea",
|
|
9
|
+
"default": "",
|
|
10
|
+
"label": {
|
|
11
|
+
"en": "Instruction (empty: the example's, when the blocks are empty too)",
|
|
12
|
+
"nl": "Instructie (leeg: die van het voorbeeld, als de blokken ook leeg zijn)",
|
|
13
|
+
"fr": "Consigne (vide : celle de l'exemple, si les blocs sont vides aussi)"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"blocks": {
|
|
17
|
+
"editor": "pci",
|
|
18
|
+
"default": "",
|
|
19
|
+
"label": {
|
|
20
|
+
"en": "Blocks: a line per block, kind: label with {} for a blank (empty: the example)",
|
|
21
|
+
"nl": "Blokken: een regel per blok, soort: label met {} voor een open plek (leeg: het voorbeeld)",
|
|
22
|
+
"fr": "Blocs : une ligne par bloc, type : étiquette avec {} pour un trou (vide : l'exemple)"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"program": {
|
|
26
|
+
"editor": "pci",
|
|
27
|
+
"default": "",
|
|
28
|
+
"label": {
|
|
29
|
+
"en": "Starting program: a block per line, indented inside a block; * in front locks it",
|
|
30
|
+
"nl": "Startprogramma: een blok per regel, ingesprongen in een blok; * ervoor zet het vast",
|
|
31
|
+
"fr": "Programme de départ : un bloc par ligne, en retrait dans un bloc ; * devant le fixe"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"solution": {
|
|
35
|
+
"editor": "pci",
|
|
36
|
+
"default": "",
|
|
37
|
+
"label": {
|
|
38
|
+
"en": "Solution: the correct program, written like the starting program",
|
|
39
|
+
"nl": "Oplossing: het goede programma, geschreven als het startprogramma",
|
|
40
|
+
"fr": "Solution : le bon programme, écrit comme le programme de départ"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"inputs": {
|
|
44
|
+
"editor": "pci",
|
|
45
|
+
"default": "",
|
|
46
|
+
"label": {
|
|
47
|
+
"en": "Input at the start: a value per line",
|
|
48
|
+
"nl": "Invoer bij het begin: een waarde per regel",
|
|
49
|
+
"fr": "Entrée au départ : une valeur par ligne"
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"tests": {
|
|
53
|
+
"editor": "pci",
|
|
54
|
+
"default": "",
|
|
55
|
+
"label": {
|
|
56
|
+
"en": "Test cases for PCI scoring: a line per test, input; input => output; output",
|
|
57
|
+
"nl": "Testgevallen voor scoren door de PCI: een regel per test, invoer; invoer => uitvoer; uitvoer",
|
|
58
|
+
"fr": "Cas de test pour le score par la PCI : une ligne par test, entrée ; entrée => sortie ; sortie"
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"editInputs": {
|
|
62
|
+
"editor": "boolean",
|
|
63
|
+
"default": "true",
|
|
64
|
+
"label": {
|
|
65
|
+
"en": "The candidate can change the input",
|
|
66
|
+
"nl": "De kandidaat kan de invoer veranderen",
|
|
67
|
+
"fr": "Le candidat peut changer l'entrée"
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"reuse": {
|
|
71
|
+
"editor": "boolean",
|
|
72
|
+
"default": "false",
|
|
73
|
+
"label": {
|
|
74
|
+
"en": "A block can be used more than once",
|
|
75
|
+
"nl": "Een blok kan meer dan eens gebruikt worden",
|
|
76
|
+
"fr": "Un bloc peut servir plusieurs fois"
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
"scoring": {
|
|
80
|
+
"editor": "enum",
|
|
81
|
+
"default": "original",
|
|
82
|
+
"label": {
|
|
83
|
+
"en": "Response and scoring",
|
|
84
|
+
"nl": "Antwoord en scoren",
|
|
85
|
+
"fr": "Réponse et score"
|
|
86
|
+
},
|
|
87
|
+
"options": [
|
|
88
|
+
{
|
|
89
|
+
"value": "original",
|
|
90
|
+
"label": {
|
|
91
|
+
"en": "The original's JSON (result, code, blocks, blanks): for a rater or custom response processing",
|
|
92
|
+
"nl": "De JSON van het origineel (resultaat, code, blokken, open plekken): voor een beoordelaar of eigen responsverwerking",
|
|
93
|
+
"fr": "Le JSON de l'original (résultat, code, blocs, trous) : pour un correcteur ou un traitement de réponse propre"
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"value": "code",
|
|
98
|
+
"label": {
|
|
99
|
+
"en": "The program as text: the item compares it with the correct response",
|
|
100
|
+
"nl": "Het programma als tekst: het item vergelijkt het met het goede antwoord",
|
|
101
|
+
"fr": "Le programme en texte : l'item le compare à la bonne réponse"
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"value": "pci",
|
|
106
|
+
"label": {
|
|
107
|
+
"en": "Test cases: the PCI runs the tests (record with score)",
|
|
108
|
+
"nl": "Testgevallen: de PCI voert de tests uit (record met score)",
|
|
109
|
+
"fr": "Cas de test : la PCI exécute les tests (record avec score)"
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
]
|
|
113
|
+
},
|
|
114
|
+
"maxBlocks": {
|
|
115
|
+
"editor": "integer",
|
|
116
|
+
"default": "30",
|
|
117
|
+
"min": 1,
|
|
118
|
+
"max": 60,
|
|
119
|
+
"label": {
|
|
120
|
+
"en": "Most blocks in the program",
|
|
121
|
+
"nl": "Hoogstens zoveel blokken in het programma",
|
|
122
|
+
"fr": "Nombre maximal de blocs dans le programme"
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
"maxDepth": {
|
|
126
|
+
"editor": "integer",
|
|
127
|
+
"default": "5",
|
|
128
|
+
"min": 1,
|
|
129
|
+
"max": 10,
|
|
130
|
+
"label": {
|
|
131
|
+
"en": "Most levels of blocks inside blocks",
|
|
132
|
+
"nl": "Hoogstens zoveel niveaus blokken in blokken",
|
|
133
|
+
"fr": "Nombre maximal de niveaux de blocs dans des blocs"
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
"maxSteps": {
|
|
137
|
+
"editor": "integer",
|
|
138
|
+
"default": "10000",
|
|
139
|
+
"min": 100,
|
|
140
|
+
"max": 1000000,
|
|
141
|
+
"label": {
|
|
142
|
+
"en": "Most steps of a run (against loops that never end)",
|
|
143
|
+
"nl": "Hoogstens zoveel stappen per uitvoering (tegen herhalingen die nooit stoppen)",
|
|
144
|
+
"fr": "Nombre maximal de pas d'une exécution (contre les boucles sans fin)"
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
"language": {
|
|
148
|
+
"editor": "enum",
|
|
149
|
+
"default": "en",
|
|
150
|
+
"options": [
|
|
151
|
+
{
|
|
152
|
+
"value": "en",
|
|
153
|
+
"label": {
|
|
154
|
+
"en": "English",
|
|
155
|
+
"nl": "Engels",
|
|
156
|
+
"fr": "Anglais"
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"value": "nl",
|
|
161
|
+
"label": {
|
|
162
|
+
"en": "Dutch",
|
|
163
|
+
"nl": "Nederlands",
|
|
164
|
+
"fr": "Néerlandais"
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
"value": "fr",
|
|
169
|
+
"label": {
|
|
170
|
+
"en": "French",
|
|
171
|
+
"nl": "Frans",
|
|
172
|
+
"fr": "Français"
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
],
|
|
176
|
+
"label": {
|
|
177
|
+
"en": "Language of the texts (and of and/or/not, true/false)",
|
|
178
|
+
"nl": "Taal van de teksten (en van en/of/niet, waar/onwaar)",
|
|
179
|
+
"fr": "Langue des textes (et de et/ou/non, vrai/faux)"
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
"markup": {},
|
|
184
|
+
"response": {
|
|
185
|
+
"$comment": "data-scoring=\"original\" (default): the JSON string of the original, {result, code, codeblock, textbox, dropdown}. data-scoring=\"code\": the program as pseudocode text, for MATCH_CORRECT. data-scoring=\"pci\": a record instead (score, maxscore, correct, test1…test8, code, program), CUSTOM. README",
|
|
186
|
+
"cardinality": "single",
|
|
187
|
+
"baseType": "string"
|
|
188
|
+
},
|
|
189
|
+
"scoring": [
|
|
190
|
+
"match_correct",
|
|
191
|
+
"custom",
|
|
192
|
+
"human"
|
|
193
|
+
],
|
|
194
|
+
"correctResponse": "properties",
|
|
195
|
+
"authoring": {
|
|
196
|
+
"label": {
|
|
197
|
+
"en": "Make the blocks, the solution and the tests…",
|
|
198
|
+
"nl": "Blokken, oplossing en tests maken…",
|
|
199
|
+
"fr": "Créer les blocs, la solution et les tests…"
|
|
200
|
+
},
|
|
201
|
+
"width": 1000,
|
|
202
|
+
"height": 760,
|
|
203
|
+
"properties": [
|
|
204
|
+
"blocks",
|
|
205
|
+
"program",
|
|
206
|
+
"solution",
|
|
207
|
+
"inputs",
|
|
208
|
+
"tests"
|
|
209
|
+
]
|
|
210
|
+
}
|
|
211
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("qtiCustomInteractionContext")):"function"==typeof define&&define.amd?define(["qtiCustomInteractionContext"],t):(e="undefined"!=typeof globalThis?globalThis:e||self)["@citolab/pci-code-blocks"]=t(e.ctx)}(this,function(e){"use strict";function t(e){var t=Object.create(null);return e&&Object.keys(e).forEach(function(n){if("default"!==n){var o=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,o.get?o:{enumerable:!0,get:function(){return e[n]}})}}),t.default=e,Object.freeze(t)}var n,o,r,a,i,l,s,c,d,u,p,h=t(e),m={},f=[],b=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,g=Array.isArray;function v(e,t){for(var n in t)e[n]=t[n];return e}function x(e){e&&e.parentNode&&e.parentNode.removeChild(e)}function k(e,t,n,a,i){var l={type:e,props:t,key:n,ref:a,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:null==i?++r:i,__i:-1,__u:0};return null==i&&null!=o.vnode&&o.vnode(l),l}function w(e){return e.children}function y(e,t){this.props=e,this.context=t}function _(e,t){if(null==t)return e.__?_(e.__,e.__i+1):null;for(var n;t<e.__k.length;t++)if(null!=(n=e.__k[t])&&null!=n.__e)return n.__e;return"function"==typeof e.type?_(e):null}function $(e){var t,n;if(null!=(e=e.__)&&null!=e.__c){for(e.__e=e.__c.base=null,t=0;t<e.__k.length;t++)if(null!=(n=e.__k[t])&&null!=n.__e){e.__e=e.__c.base=n.__e;break}return $(e)}}function N(e){(!e.__d&&(e.__d=!0)&&a.push(e)&&!S.__r++||i!=o.debounceRendering)&&((i=o.debounceRendering)||l)(S)}function S(){for(var e,t,n,r,i,l,c,d=1;a.length;)a.length>d&&a.sort(s),e=a.shift(),d=a.length,e.__d&&(n=void 0,r=void 0,i=(r=(t=e).__v).__e,l=[],c=[],t.__P&&((n=v({},r)).__v=r.__v+1,o.vnode&&o.vnode(n),B(t.__P,n,r,t.__n,t.__P.namespaceURI,32&r.__u?[i]:null,l,null==i?_(r):i,!!(32&r.__u),c),n.__v=r.__v,n.__.__k[n.__i]=n,z(l,n,c),r.__e=r.__=null,n.__e!=i&&$(n)));S.__r=0}function j(e,t,n,o,r,a,i,l,s,c,d){var u,p,h,b,v,x,y,$=o&&o.__k||f,N=t.length;for(s=function(e,t,n,o,r){var a,i,l,s,c,d=n.length,u=d,p=0;for(e.__k=new Array(r),a=0;a<r;a++)null!=(i=t[a])&&"boolean"!=typeof i&&"function"!=typeof i?("string"==typeof i||"number"==typeof i||"bigint"==typeof i||i.constructor==String?i=e.__k[a]=k(null,i,null,null,null):g(i)?i=e.__k[a]=k(w,{children:i},null,null,null):void 0===i.constructor&&i.__b>0?i=e.__k[a]=k(i.type,i.props,i.key,i.ref?i.ref:null,i.__v):e.__k[a]=i,s=a+p,i.__=e,i.__b=e.__b+1,l=null,-1!=(c=i.__i=E(i,n,s,u))&&(u--,(l=n[c])&&(l.__u|=2)),null==l||null==l.__v?(-1==c&&(r>d?p--:r<d&&p++),"function"!=typeof i.type&&(i.__u|=4)):c!=s&&(c==s-1?p--:c==s+1?p++:(c>s?p--:p++,i.__u|=4))):e.__k[a]=null;if(u)for(a=0;a<d;a++)null!=(l=n[a])&&!(2&l.__u)&&(l.__e==o&&(o=_(l)),R(l,l));return o}(n,t,$,s,N),u=0;u<N;u++)null!=(h=n.__k[u])&&(p=-1==h.__i?m:$[h.__i]||m,h.__i=u,x=B(e,h,p,r,a,i,l,s,c,d),b=h.__e,h.ref&&p.ref!=h.ref&&(p.ref&&A(p.ref,null,h),d.push(h.ref,h.__c||b,h)),null==v&&null!=b&&(v=b),(y=!!(4&h.__u))||p.__k===h.__k?s=O(h,s,e,y):"function"==typeof h.type&&void 0!==x?s=x:b&&(s=b.nextSibling),h.__u&=-7);return n.__e=v,s}function O(e,t,n,o){var r,a;if("function"==typeof e.type){for(r=e.__k,a=0;r&&a<r.length;a++)r[a]&&(r[a].__=e,t=O(r[a],t,n,o));return t}e.__e!=t&&(o&&(t&&e.type&&!t.parentNode&&(t=_(e)),n.insertBefore(e.__e,t||null)),t=e.__e);do{t=t&&t.nextSibling}while(null!=t&&8==t.nodeType);return t}function E(e,t,n,o){var r,a,i,l=e.key,s=e.type,c=t[n],d=null!=c&&!(2&c.__u);if(null===c&&null==l||d&&l==c.key&&s==c.type)return n;if(o>(d?1:0))for(r=n-1,a=n+1;r>=0||a<t.length;)if(null!=(c=t[i=r>=0?r--:a++])&&!(2&c.__u)&&l==c.key&&s==c.type)return i;return-1}function T(e,t,n){"-"==t[0]?e.setProperty(t,null==n?"":n):e[t]=null==n?"":"number"!=typeof n||b.test(t)?n:n+"px"}function L(e,t,n,o,r){var a,i;e:if("style"==t)if("string"==typeof n)e.style.cssText=n;else{if("string"==typeof o&&(e.style.cssText=o=""),o)for(t in o)n&&t in n||T(e.style,t,"");if(n)for(t in n)o&&n[t]==o[t]||T(e.style,t,n[t])}else if("o"==t[0]&&"n"==t[1])a=t!=(t=t.replace(c,"$1")),i=t.toLowerCase(),t=i in e||"onFocusOut"==t||"onFocusIn"==t?i.slice(2):t.slice(2),e.l||(e.l={}),e.l[t+a]=n,n?o?n.u=o.u:(n.u=d,e.addEventListener(t,a?p:u,a)):e.removeEventListener(t,a?p:u,a);else{if("http://www.w3.org/2000/svg"==r)t=t.replace(/xlink(H|:h)/,"h").replace(/sName$/,"s");else if("width"!=t&&"height"!=t&&"href"!=t&&"list"!=t&&"form"!=t&&"tabIndex"!=t&&"download"!=t&&"rowSpan"!=t&&"colSpan"!=t&&"role"!=t&&"popover"!=t&&t in e)try{e[t]=null==n?"":n;break e}catch(e){}"function"==typeof n||(null==n||!1===n&&"-"!=t[4]?e.removeAttribute(t):e.setAttribute(t,"popover"==t&&1==n?"":n))}}function M(e){return function(t){if(this.l){var n=this.l[t.type+e];if(null==t.t)t.t=d++;else if(t.t<n.u)return;return n(o.event?o.event(t):t)}}}function B(e,t,n,r,a,i,l,s,c,d){var u,p,h,m,f,b,k,_,$,N,S,O,E,T,L,M,B,z=t.type;if(void 0!==t.constructor)return null;128&n.__u&&(c=!!(32&n.__u),i=[s=t.__e=n.__e]),(u=o.__b)&&u(t);e:if("function"==typeof z)try{if(_=t.props,$="prototype"in z&&z.prototype.render,N=(u=z.contextType)&&r[u.__c],S=u?N?N.props.value:u.__:r,n.__c?k=(p=t.__c=n.__c).__=p.__E:($?t.__c=p=new z(_,S):(t.__c=p=new y(_,S),p.constructor=z,p.render=H),N&&N.sub(p),p.state||(p.state={}),p.__n=r,h=p.__d=!0,p.__h=[],p._sb=[]),$&&null==p.__s&&(p.__s=p.state),$&&null!=z.getDerivedStateFromProps&&(p.__s==p.state&&(p.__s=v({},p.__s)),v(p.__s,z.getDerivedStateFromProps(_,p.__s))),m=p.props,f=p.state,p.__v=t,h)$&&null==z.getDerivedStateFromProps&&null!=p.componentWillMount&&p.componentWillMount(),$&&null!=p.componentDidMount&&p.__h.push(p.componentDidMount);else{if($&&null==z.getDerivedStateFromProps&&_!==m&&null!=p.componentWillReceiveProps&&p.componentWillReceiveProps(_,S),t.__v==n.__v||!p.__e&&null!=p.shouldComponentUpdate&&!1===p.shouldComponentUpdate(_,p.__s,S)){for(t.__v!=n.__v&&(p.props=_,p.state=p.__s,p.__d=!1),t.__e=n.__e,t.__k=n.__k,t.__k.some(function(e){e&&(e.__=t)}),O=0;O<p._sb.length;O++)p.__h.push(p._sb[O]);p._sb=[],p.__h.length&&l.push(p);break e}null!=p.componentWillUpdate&&p.componentWillUpdate(_,p.__s,S),$&&null!=p.componentDidUpdate&&p.__h.push(function(){p.componentDidUpdate(m,f,b)})}if(p.context=S,p.props=_,p.__P=e,p.__e=!1,E=o.__r,T=0,$){for(p.state=p.__s,p.__d=!1,E&&E(t),u=p.render(p.props,p.state,p.context),L=0;L<p._sb.length;L++)p.__h.push(p._sb[L]);p._sb=[]}else do{p.__d=!1,E&&E(t),u=p.render(p.props,p.state,p.context),p.state=p.__s}while(p.__d&&++T<25);p.state=p.__s,null!=p.getChildContext&&(r=v(v({},r),p.getChildContext())),$&&!h&&null!=p.getSnapshotBeforeUpdate&&(b=p.getSnapshotBeforeUpdate(m,f)),M=u,null!=u&&u.type===w&&null==u.key&&(M=I(u.props.children)),s=j(e,g(M)?M:[M],t,n,r,a,i,l,s,c,d),p.base=t.__e,t.__u&=-161,p.__h.length&&l.push(p),k&&(p.__E=p.__=null)}catch(e){if(t.__v=null,c||null!=i)if(e.then){for(t.__u|=c?160:128;s&&8==s.nodeType&&s.nextSibling;)s=s.nextSibling;i[i.indexOf(s)]=null,t.__e=s}else{for(B=i.length;B--;)x(i[B]);C(t)}else t.__e=n.__e,t.__k=n.__k,e.then||C(t);o.__e(e,t,n)}else null==i&&t.__v==n.__v?(t.__k=n.__k,t.__e=n.__e):s=t.__e=D(n.__e,t,n,r,a,i,l,c,d);return(u=o.diffed)&&u(t),128&t.__u?void 0:s}function C(e){e&&e.__c&&(e.__c.__e=!0),e&&e.__k&&e.__k.forEach(C)}function z(e,t,n){for(var r=0;r<n.length;r++)A(n[r],n[++r],n[++r]);o.__c&&o.__c(t,e),e.some(function(t){try{e=t.__h,t.__h=[],e.some(function(e){e.call(t)})}catch(e){o.__e(e,t.__v)}})}function I(e){return"object"!=typeof e||null==e||e.__b&&e.__b>0?e:g(e)?e.map(I):v({},e)}function D(e,t,r,a,i,l,s,c,d){var u,p,h,f,b,v,k,w=r.props||m,y=t.props,$=t.type;if("svg"==$?i="http://www.w3.org/2000/svg":"math"==$?i="http://www.w3.org/1998/Math/MathML":i||(i="http://www.w3.org/1999/xhtml"),null!=l)for(u=0;u<l.length;u++)if((b=l[u])&&"setAttribute"in b==!!$&&($?b.localName==$:3==b.nodeType)){e=b,l[u]=null;break}if(null==e){if(null==$)return document.createTextNode(y);e=document.createElementNS(i,$,y.is&&y),c&&(o.__m&&o.__m(t,l),c=!1),l=null}if(null==$)w===y||c&&e.data==y||(e.data=y);else{if(l=l&&n.call(e.childNodes),!c&&null!=l)for(w={},u=0;u<e.attributes.length;u++)w[(b=e.attributes[u]).name]=b.value;for(u in w)if(b=w[u],"children"==u);else if("dangerouslySetInnerHTML"==u)h=b;else if(!(u in y)){if("value"==u&&"defaultValue"in y||"checked"==u&&"defaultChecked"in y)continue;L(e,u,null,b,i)}for(u in y)b=y[u],"children"==u?f=b:"dangerouslySetInnerHTML"==u?p=b:"value"==u?v=b:"checked"==u?k=b:c&&"function"!=typeof b||w[u]===b||L(e,u,b,w[u],i);if(p)c||h&&(p.__html==h.__html||p.__html==e.innerHTML)||(e.innerHTML=p.__html),t.__k=[];else if(h&&(e.innerHTML=""),j("template"==t.type?e.content:e,g(f)?f:[f],t,r,a,"foreignObject"==$?"http://www.w3.org/1999/xhtml":i,l,s,l?l[0]:r.__k&&_(r,0),c,d),null!=l)for(u=l.length;u--;)x(l[u]);c||(u="value","progress"==$&&null==v?e.removeAttribute("value"):null!=v&&(v!==e[u]||"progress"==$&&!v||"option"==$&&v!=w[u])&&L(e,u,v,w[u],i),u="checked",null!=k&&k!=e[u]&&L(e,u,k,w[u],i))}return e}function A(e,t,n){try{if("function"==typeof e){var r="function"==typeof e.__u;r&&e.__u(),r&&null==t||(e.__u=e(t))}else e.current=t}catch(e){o.__e(e,n)}}function R(e,t,n){var r,a;if(o.unmount&&o.unmount(e),(r=e.ref)&&(r.current&&r.current!=e.__e||A(r,null,t)),null!=(r=e.__c)){if(r.componentWillUnmount)try{r.componentWillUnmount()}catch(e){o.__e(e,t)}r.base=r.__P=null}if(r=e.__k)for(a=0;a<r.length;a++)r[a]&&R(r[a],t,n||"function"!=typeof e.type);n||x(e.__e),e.__c=e.__=e.__e=void 0}function H(e,t,n){return this.constructor(e,n)}function P(e,t,r){var a,i,l;t==document&&(t=document.documentElement),o.__&&o.__(e,t),a=!1?null:t.__k,i=[],l=[],B(t,e=t.__k=function(e,t,o){var r,a,i,l={};for(i in t)"key"==i?r=t[i]:"ref"==i?a=t[i]:l[i]=t[i];if(arguments.length>2&&(l.children=arguments.length>3?n.call(arguments,2):o),"function"==typeof e&&null!=e.defaultProps)for(i in e.defaultProps)void 0===l[i]&&(l[i]=e.defaultProps[i]);return k(e,l,r,a,null)}(w,null,[e]),a||m,m,t.namespaceURI,a?null:t.firstChild?n.call(t.childNodes):null,i,a?a.__e:t.firstChild,false,l),z(i,e,l)}n=f.slice,o={__e:function(e,t,n,o){for(var r,a,i;t=t.__;)if((r=t.__c)&&!r.__)try{if((a=r.constructor)&&null!=a.getDerivedStateFromError&&(r.setState(a.getDerivedStateFromError(e)),i=r.__d),null!=r.componentDidCatch&&(r.componentDidCatch(e,o||{}),i=r.__d),i)return r.__E=r}catch(t){e=t}throw e}},r=0,y.prototype.setState=function(e,t){var n;n=null!=this.__s&&this.__s!=this.state?this.__s:this.__s=v({},this.state),"function"==typeof e&&(e=e(v({},n),this.props)),e&&v(n,e),null!=e&&this.__v&&(t&&this._sb.push(t),N(this))},y.prototype.forceUpdate=function(e){this.__v&&(this.__e=!0,e&&this.__h.push(e),N(this))},y.prototype.render=w,a=[],l="function"==typeof Promise?Promise.prototype.then.bind(Promise.resolve()):setTimeout,s=function(e,t){return e.__v.__b-t.__v.__b},S.__r=0,c=/(PointerCapture)$|Capture$/i,d=0,u=M(!1),p=M(!0);var U,F=0;function V(e,t,n,r,a,i){t||(t={});var l,s,c=t;if("ref"in c)for(s in c={},t)"ref"==s?l=t[s]:c[s]=t[s];var d={type:e,props:c,key:n,ref:l,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:--F,__i:-1,__u:0,__source:a,__self:i};if("function"==typeof e&&(l=e.defaultProps))for(s in l)void 0===c[s]&&(c[s]=l[s]);return o.vnode&&o.vnode(d),d}null!=(U="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:void 0)&&U.__PREACT_DEVTOOLS__&&U.__PREACT_DEVTOOLS__.attachPreact("10.28.2",o,{Fragment:w,Component:y});var q={};function W(e){return e.type===w?"Fragment":"function"==typeof e.type?e.type.displayName||e.type.name:"string"==typeof e.type?e.type:"#text"}var Y=[],J=[];function K(){return Y.length>0?Y[Y.length-1]:null}var Z=!0;function X(e){return"function"==typeof e.type&&e.type!=w}function G(e){for(var t=[e],n=e;null!=n.__o;)t.push(n.__o),n=n.__o;return t.reduce(function(e,t){e+=" in "+W(t);var n=t.__source;return n?e+=" (at "+n.fileName+":"+n.lineNumber+")":Z&&console.warn("Add @babel/plugin-transform-react-jsx-source to get a more detailed component stack. Note that you should not add it to production builds of your App for bundle size reasons."),Z=!1,e+"\n"},"")}var Q="function"==typeof WeakMap;function ee(e){var t=[];return e.__k?(e.__k.forEach(function(e){e&&"function"==typeof e.type?t.push.apply(t,ee(e)):e&&"string"==typeof e.type&&t.push(e.type)}),t):t}function te(e){return e?"function"==typeof e.type?null==e.__?null!=e.__e&&null!=e.__e.parentNode?e.__e.parentNode.localName:"":te(e.__):e.type:""}var ne=y.prototype.setState;function oe(e){return"table"===e||"tfoot"===e||"tbody"===e||"thead"===e||"td"===e||"tr"===e||"th"===e}y.prototype.setState=function(e,t){return null==this.__v&&null==this.state&&console.warn('Calling "this.setState" inside the constructor of a component is a no-op and might be a bug in your application. Instead, set "this.state = {}" directly.\n\n'+G(K())),ne.call(this,e,t)};var re=/^(address|article|aside|blockquote|details|div|dl|fieldset|figcaption|figure|footer|form|h1|h2|h3|h4|h5|h6|header|hgroup|hr|main|menu|nav|ol|p|pre|search|section|table|ul)$/,ae=y.prototype.forceUpdate;function ie(e){var t=e.props,n=W(e),o="";for(var r in t)if(t.hasOwnProperty(r)&&"children"!==r){var a=t[r];"function"==typeof a&&(a="function "+(a.displayName||a.name)+"() {}"),a=Object(a)!==a||a.toString?a+"":Object.prototype.toString.call(a),o+=" "+r+"="+JSON.stringify(a)}var i=t.children;return"<"+n+o+(i&&i.length?">..</"+n+">":" />")}y.prototype.forceUpdate=function(e){return null==this.__v?console.warn('Calling "this.forceUpdate" inside the constructor of a component is a no-op and might be a bug in your application.\n\n'+G(K())):null==this.__P&&console.warn('Can\'t call "this.forceUpdate" on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.\n\n'+G(this.__v)),ae.call(this,e)},o.__m=function(e,t){var n=e.type,o=t.map(function(e){return e&&e.localName}).filter(Boolean);console.error('Expected a DOM node of type "'+n+'" but found "'+o.join(", ")+"\" as available DOM-node(s), this is caused by the SSR'd HTML containing different DOM-nodes compared to the hydrated one.\n\n"+G(e))},function(){!function(){var e=o.__b,t=o.diffed,n=o.__,r=o.vnode,a=o.__r;o.diffed=function(e){X(e)&&J.pop(),Y.pop(),t&&t(e)},o.__b=function(t){X(t)&&Y.push(t),e&&e(t)},o.__=function(e,t){J=[],n&&n(e,t)},o.vnode=function(e){e.__o=J.length>0?J[J.length-1]:null,r&&r(e)},o.__r=function(e){X(e)&&J.push(e),a&&a(e)}}();var e=!1,t=o.__b,n=o.diffed,r=o.vnode,a=o.__r,i=o.__e,l=o.__,s=o.__h,c=Q?{useEffect:new WeakMap,useLayoutEffect:new WeakMap,lazyPropTypes:new WeakMap}:null,d=[];o.__e=function(e,t,n,o){if(t&&t.__c&&"function"==typeof e.then){var r=e;e=new Error("Missing Suspense. The throwing component was: "+W(t));for(var a=t;a;a=a.__)if(a.__c&&a.__c.__c){e=r;break}if(e instanceof Error)throw e}try{(o=o||{}).componentStack=G(t),i(e,t,n,o),"function"!=typeof e.then&&setTimeout(function(){throw e})}catch(e){throw e}},o.__=function(e,t){if(!t)throw new Error("Undefined parent passed to render(), this is the second argument.\nCheck if the element is available in the DOM/has the correct id.");var n;switch(t.nodeType){case 1:case 11:case 9:n=!0;break;default:n=!1}if(!n){var o=W(e);throw new Error("Expected a valid HTML node as a second argument to render.\tReceived "+t+" instead: render(<"+o+" />, "+t+");")}l&&l(e,t)},o.__b=function(n){var o=n.type;if(e=!0,void 0===o)throw new Error("Undefined component passed to createElement()\n\nYou likely forgot to export your component or might have mixed up default and named imports"+ie(n)+"\n\n"+G(n));if(null!=o&&"object"==typeof o){if(void 0!==o.__k&&void 0!==o.__e)throw new Error("Invalid type passed to createElement(): "+o+"\n\nDid you accidentally pass a JSX literal as JSX twice?\n\n let My"+W(n)+" = "+ie(o)+";\n let vnode = <My"+W(n)+" />;\n\nThis usually happens when you export a JSX literal and not the component.\n\n"+G(n));throw new Error("Invalid type passed to createElement(): "+(Array.isArray(o)?"array":o))}if(void 0!==n.ref&&"function"!=typeof n.ref&&"object"!=typeof n.ref&&!("$$typeof"in n))throw new Error('Component\'s "ref" property should be a function, or an object created by createRef(), but got ['+typeof n.ref+"] instead\n"+ie(n)+"\n\n"+G(n));if("string"==typeof n.type)for(var r in n.props)if("o"===r[0]&&"n"===r[1]&&"function"!=typeof n.props[r]&&null!=n.props[r])throw new Error("Component's \""+r+'" property should be a function, but got ['+typeof n.props[r]+"] instead\n"+ie(n)+"\n\n"+G(n));if("function"==typeof n.type&&n.type.propTypes){if("Lazy"===n.type.displayName&&c&&!c.lazyPropTypes.has(n.type)){var a="PropTypes are not supported on lazy(). Use propTypes on the wrapped component itself. ";try{var i=n.type();c.lazyPropTypes.set(n.type,!0),console.warn(a+"Component wrapped in lazy() is "+W(i))}catch(e){console.warn(a+"We will log the wrapped component's name once it is loaded.")}}var l=n.props;n.type.__f&&delete(l=function(e,t){for(var n in t)e[n]=t[n];return e}({},l)).ref,function(e,t,n,o,r){Object.keys(e).forEach(function(n){var a;try{a=e[n](t,n,o,"prop",null,"SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED")}catch(e){a=e}a&&!(a.message in q)&&(q[a.message]=!0,console.error("Failed prop type: "+a.message+(r&&"\n"+r()||"")))})}(n.type.propTypes,l,0,W(n),function(){return G(n)})}t&&t(n)};var u,p=0;o.__r=function(t){a&&a(t),e=!0;var n=t.__c;if(n===u?p++:p=1,p>=25)throw new Error("Too many re-renders. This is limited to prevent an infinite loop which may lock up your browser. The component causing this is: "+W(t));u=n},o.__h=function(t,n,o){if(!t||!e)throw new Error("Hook can only be invoked from render methods.");s&&s(t,n,o)};var h=function(e,t){return{get:function(){var n="get"+e+t;d&&d.indexOf(n)<0&&(d.push(n),console.warn("getting vnode."+e+" is deprecated, "+t))},set:function(){var n="set"+e+t;d&&d.indexOf(n)<0&&(d.push(n),console.warn("setting vnode."+e+" is not allowed, "+t))}}},m={nodeName:h("nodeName","use vnode.type"),attributes:h("attributes","use vnode.props"),children:h("children","use vnode.props.children")},f=Object.create({},m);o.vnode=function(e){var t=e.props;if(null!==e.type&&null!=t&&("__source"in t||"__self"in t)){var n=e.props={};for(var o in t){var a=t[o];"__source"===o?e.__source=a:"__self"===o?e.__self=a:n[o]=a}}e.__proto__=f,r&&r(e)},o.diffed=function(t){var o,r=t.type,a=t.__;if(t.__k&&t.__k.forEach(function(e){if("object"==typeof e&&e&&void 0===e.type){var n=Object.keys(e).join(",");throw new Error("Objects are not valid as a child. Encountered an object with the keys {"+n+"}.\n\n"+G(t))}}),t.__c===u&&(p=0),"string"==typeof r&&(oe(r)||"p"===r||"a"===r||"button"===r)){var i=te(a);if(""!==i&&oe(r))"table"===r&&"td"!==i&&oe(i)?console.error("Improper nesting of table. Your <table> should not have a table-node parent."+ie(t)+"\n\n"+G(t)):"thead"!==r&&"tfoot"!==r&&"tbody"!==r||"table"===i?"tr"===r&&"thead"!==i&&"tfoot"!==i&&"tbody"!==i?console.error("Improper nesting of table. Your <tr> should have a <thead/tbody/tfoot> parent."+ie(t)+"\n\n"+G(t)):"td"===r&&"tr"!==i?console.error("Improper nesting of table. Your <td> should have a <tr> parent."+ie(t)+"\n\n"+G(t)):"th"===r&&"tr"!==i&&console.error("Improper nesting of table. Your <th> should have a <tr>."+ie(t)+"\n\n"+G(t)):console.error("Improper nesting of table. Your <thead/tbody/tfoot> should have a <table> parent."+ie(t)+"\n\n"+G(t));else if("p"===r){var l=ee(t).filter(function(e){return re.test(e)});l.length&&console.error("Improper nesting of paragraph. Your <p> should not have "+l.join(", ")+" as child-elements."+ie(t)+"\n\n"+G(t))}else"a"!==r&&"button"!==r||-1!==ee(t).indexOf(r)&&console.error("Improper nesting of interactive content. Your <"+r+"> should not have other "+("a"===r?"anchor":"button")+" tags as child-elements."+ie(t)+"\n\n"+G(t))}if(e=!1,n&&n(t),null!=t.__k)for(var s=[],c=0;c<t.__k.length;c++){var d=t.__k[c];if(d&&null!=d.key){var h=d.key;if(-1!==s.indexOf(h)){console.error('Following component has two or more children with the same key attribute: "'+h+'". This may cause glitches and misbehavior in rendering process. Component: \n\n'+ie(t)+"\n\n"+G(t));break}s.push(h)}}if(null!=t.__c&&null!=t.__c.__H){var m=t.__c.__H.__;if(m)for(var f=0;f<m.length;f+=1){var b=m[f];if(b.__H)for(var g=0;g<b.__H.length;g++)if((o=b.__H[g])!=o){var v=W(t);console.warn("Invalid argument passed to hook. Hooks should not be called with NaN in the dependency array. Hook index "+f+" in component "+v+" was called with NaN.")}}}}}();var le,se,ce,de,ue=0,pe=[],he=o,me=he.__b,fe=he.__r,be=he.diffed,ge=he.__c,ve=he.unmount,xe=he.__;function ke(e,t){he.__h&&he.__h(se,e,ue||t),ue=0;var n=se.__H||(se.__H={__:[],__h:[]});return e>=n.__.length&&n.__.push({}),n.__[e]}function we(e){return ue=1,function(e,t){var n=ke(le++,2);if(n.t=e,!n.__c&&(n.__=[Me(void 0,t),function(e){var t=n.__N?n.__N[0]:n.__[0],o=n.t(t,e);t!==o&&(n.__N=[o,n.__[1]],n.__c.setState({}))}],n.__c=se,!se.__f)){var o=function(e,t,o){if(!n.__c.__H)return!0;var a=n.__c.__H.__.filter(function(e){return!!e.__c});if(a.every(function(e){return!e.__N}))return!r||r.call(this,e,t,o);var i=n.__c.props!==e;return a.forEach(function(e){if(e.__N){var t=e.__[0];e.__=e.__N,e.__N=void 0,t!==e.__[0]&&(i=!0)}}),r&&r.call(this,e,t,o)||i};se.__f=!0;var r=se.shouldComponentUpdate,a=se.componentWillUpdate;se.componentWillUpdate=function(e,t,n){if(this.__e){var i=r;r=void 0,o(e,t,n),r=i}a&&a.call(this,e,t,n)},se.shouldComponentUpdate=o}return n.__N||n.__}(Me,e)}function ye(e,t){var n=ke(le++,3);!he.__s&&Le(n.__H,t)&&(n.__=e,n.u=t,se.__H.__h.push(n))}function _e(e,t){var n=ke(le++,4);!he.__s&&Le(n.__H,t)&&(n.__=e,n.u=t,se.__h.push(n))}function $e(e){return ue=5,Ne(function(){return{current:e}},[])}function Ne(e,t){var n=ke(le++,7);return Le(n.__H,t)&&(n.__=e(),n.__H=t,n.__h=e),n.__}function Se(){for(var e;e=pe.shift();)if(e.__P&&e.__H)try{e.__H.__h.forEach(Ee),e.__H.__h.forEach(Te),e.__H.__h=[]}catch(t){e.__H.__h=[],he.__e(t,e.__v)}}he.__b=function(e){se=null,me&&me(e)},he.__=function(e,t){e&&t.__k&&t.__k.__m&&(e.__m=t.__k.__m),xe&&xe(e,t)},he.__r=function(e){fe&&fe(e),le=0;var t=(se=e.__c).__H;t&&(ce===se?(t.__h=[],se.__h=[],t.__.forEach(function(e){e.__N&&(e.__=e.__N),e.u=e.__N=void 0})):(t.__h.forEach(Ee),t.__h.forEach(Te),t.__h=[],le=0)),ce=se},he.diffed=function(e){be&&be(e);var t=e.__c;t&&t.__H&&(t.__H.__h.length&&(1!==pe.push(t)&&de===he.requestAnimationFrame||((de=he.requestAnimationFrame)||Oe)(Se)),t.__H.__.forEach(function(e){e.u&&(e.__H=e.u),e.u=void 0})),ce=se=null},he.__c=function(e,t){t.some(function(e){try{e.__h.forEach(Ee),e.__h=e.__h.filter(function(e){return!e.__||Te(e)})}catch(n){t.some(function(e){e.__h&&(e.__h=[])}),t=[],he.__e(n,e.__v)}}),ge&&ge(e,t)},he.unmount=function(e){ve&&ve(e);var t,n=e.__c;n&&n.__H&&(n.__H.__.forEach(function(e){try{Ee(e)}catch(e){t=e}}),n.__H=void 0,t&&he.__e(t,n.__v))};var je="function"==typeof requestAnimationFrame;function Oe(e){var t,n=function(){clearTimeout(o),je&&cancelAnimationFrame(t),setTimeout(e)},o=setTimeout(n,35);je&&(t=requestAnimationFrame(n))}function Ee(e){var t=se,n=e.__c;"function"==typeof n&&(e.__c=void 0,n()),se=t}function Te(e){var t=se;e.__c=e.__(),se=t}function Le(e,t){return!e||e.length!==t.length||t.some(function(t,n){return t!==e[n]})}function Me(e,t){return"function"==typeof t?t(e):t}var Be=function(e,t,n,o){return new(n||(n=Promise))(function(r,a){function i(e){try{s(o.next(e))}catch(e){a(e)}}function l(e){try{s(o.throw(e))}catch(e){a(e)}}function s(e){var t;e.done?r(e.value):(t=e.value,t instanceof n?t:new n(function(e){e(t)})).then(i,l)}s((o=o.apply(e,t||[])).next())})};class Ce{constructor(e,t,n={}){if(this.initialState=e,this.options=n,this.listeners=[],this.actionListeners=[],this.actions=[],this.reducers={},this.timeout=e=>new Promise(t=>setTimeout(t,e)),this.state=(null==t?void 0:t.state)||e,null==t?void 0:t.actions){this.state=e,this.actions=[...t.actions];for(const e of this.actions)this.state=this.reduce(this.state,e)}}getState(){return this.state}getActions(){return this.actions}dispatch(e){const t=Date.now(),n=Object.assign(Object.assign({},e),{timestamp:t});this.log(n),this.state=this.reduce(this.state,n),this.notifyListeners(n)}reset(){this.state=this.initialState,this.actions=[],this.notifyStateListeners()}restoreState(e,t){this.state=e,this.actions=[...t],this.notifyStateListeners()}replay(e,t){return Be(this,void 0,void 0,function*(){var n,o;this.reset();let r=0;null!=(null==t?void 0:t.until)&&(e=e.slice(0,t.until));for(const a of e){let e=!1===(null==t?void 0:t.animate)?0:r?(null!==(n=a.timestamp)&&void 0!==n?n:r)-r:0;(null==t?void 0:t.speed)&&(e/=t.speed),yield this.timeout(e),this.log(a),this.state=this.reduce(this.state,a),this.notifyListeners(a),r=null!==(o=a.timestamp)&&void 0!==o?o:r}})}subscribe(e,t){return this.listeners.push(e),!1!==(null==t?void 0:t.immediate)&&e(this.state),()=>this.unsubscribe(e)}subscribeActions(e){return this.actionListeners.push(e),()=>this.unsubscribeActions(e)}unsubscribe(e){const t=this.listeners.indexOf(e);-1!==t&&this.listeners.splice(t,1)}unsubscribeActions(e){const t=this.actionListeners.indexOf(e);-1!==t&&this.actionListeners.splice(t,1)}unsubscribeAll(){this.listeners=[],this.actionListeners=[]}addReducer(e,t){this.reducers[e]=t}reduce(e,t){const n=this.reducers[t.type];return n?n(e,t.payload):e}log(e){this.actions.push(e);const t=this.options.maxActions;null!=t&&t>=0&&this.actions.length>t&&this.actions.splice(0,this.actions.length-t)}notifyStateListeners(){for(const e of[...this.listeners])e(this.state)}notifyListeners(e){this.notifyStateListeners();for(const t of[...this.actionListeners])t(e)}}class ze extends Error{constructor(e,t,n=0){super(e),this.code=e,this.detail=t,this.line=n}}const Ie={en:{and:["and"],or:["or"],not:["not"],true:["true"],false:["false"],mod:["mod"],div:["div"]},nl:{and:["and","en"],or:["or","of"],not:["not","niet"],true:["true","waar"],false:["false","onwaar"],mod:["mod"],div:["div"]},fr:{and:["and","et"],or:["or","ou"],not:["not","non"],true:["true","vrai"],false:["false","faux"],mod:["mod"],div:["div"]}},De={en:["true","false"],nl:["waar","onwaar"],fr:["vrai","faux"]},Ae=e=>{if("number"!=typeof e)throw new ze("arguments");return e},Re={abs:{min:1,max:1,call:([e])=>Math.abs(Ae(e))},round:{min:1,max:1,call:([e])=>Math.round(Ae(e))},floor:{min:1,max:1,call:([e])=>Math.floor(Ae(e))},ceil:{min:1,max:1,call:([e])=>Math.ceil(Ae(e))},sqrt:{min:1,max:1,call:([e])=>{if(Ae(e)<0)throw new ze("arguments");return Math.sqrt(Ae(e))}},min:{min:1,max:10,call:e=>Math.min(...e.map(Ae))},max:{min:1,max:10,call:e=>Math.max(...e.map(Ae))},length:{min:1,max:1,call:([e])=>{if("string"!=typeof e)throw new ze("arguments");return[...e].length}}},He={len:"length",lengte:"length",longueur:"length",afronden:"round",arrondi:"round",wortel:"sqrt",racine:"sqrt"};Object.keys(Re),Object.keys(He);const Pe=["**","//","==","!=","<>","<=",">=","≤","≥","≠","&&","||","+","-","−","*","×","/","÷","%","^","=","<",">","(",")",",","!"],Ue=/^[\p{L}_][\p{L}\p{N}_]*$/u,Fe=(e,t="en")=>{if(!Ue.test(e))return!1;const n=Ie[t];return![...n.and,...n.or,...n.not,...n.true,...n.false,...n.mod,...n.div].includes(e.toLowerCase())},Ve={"==":"=","<>":"!=","≠":"!=","≤":"<=","≥":">=","−":"-","×":"*","÷":"/","**":"^","&&":"and","||":"or","!":"not"},qe=(e,t="en",n=!1)=>{const o=(e=>{const t=[];let n=0;for(;n<e.length;){const o=e[n];if(/\s/.test(o)){n++;continue}const r=e.slice(n),a=/^(\d+(\.\d+)?|\.\d+)/.exec(r);if(a){t.push({t:"num",v:parseFloat(a[0]),at:a[0]}),n+=a[0].length;continue}const i={'"':'"',"'":"'","“":"”","‘":"’","„":"”","«":"»"}[o];if(i){const a=e.indexOf(i,n+1),l="“"===o||"„"===o?e.indexOf('"',n+1):-1,s=a>=0?a:l;if(s<0)throw new ze("syntax",r);t.push({t:"str",v:e.slice(n+1,s),at:e.slice(n,s+1)}),n=s+1;continue}const l=/^[\p{L}_][\p{L}\p{N}_]*/u.exec(r);if(l){t.push({t:"name",v:l[0],at:l[0]}),n+=l[0].length;continue}const s=Pe.find(e=>r.startsWith(e));if(!s)throw new ze("syntax",o);t.push({t:"op",v:s,at:s}),n+=s.length}return t})(e),r=Ie[t];let a=0;const i=()=>o[a],l=()=>{throw new ze("syntax",a<o.length?o.slice(a).map(e=>e.at).join(" "):e.trim())},s=()=>{var e;const t=i();if(!t)return null;if("op"===t.t)return null!==(e=Ve[t.v])&&void 0!==e?e:t.v;if("name"===t.t){const e=t.v.toLowerCase();for(const t of["and","or","not","mod","div"])if(r[t].includes(e))return t}return null},c=(...e)=>{const t=s();return t&&e.includes(t)?(a++,t):null},d=()=>{let e=u();for(;c("or");)e={k:"bin",op:"or",a:e,b:u()};return e},u=()=>{let e=p();for(;c("and");)e={k:"bin",op:"and",a:e,b:p()};return e},p=()=>c("not")?{k:"un",op:"not",a:p()}:h(),h=()=>{const e=m(),t=c("=","!=","<","<=",">",">=");return t?{k:"bin",op:t,a:e,b:m()}:e},m=()=>{let e=f();for(let t=c("+","-");t;t=c("+","-"))e={k:"bin",op:t,a:e,b:f()};return e},f=()=>{let e=b();for(let t=c("*","/","%","//","mod","div");t;t=c("*","/","%","//","mod","div"))e={k:"bin",op:"mod"===t?"%":"div"===t?"//":t,a:e,b:b()};return e},b=()=>c("-")?{k:"un",op:"-",a:b()}:c("+")?b():g(),g=()=>{const e=v();return c("^")?{k:"bin",op:"^",a:e,b:b()}:e},v=()=>{var e;const t=i();if(!t)return l();if("num"===t.t)return a++,{k:"lit",v:t.v};if("str"===t.t)return a++,{k:"lit",v:t.v};if("op"===t.t&&"("===t.v){a++;const e=d();return c(")")||l(),e}if("name"===t.t){const n=t.v.toLowerCase();if(r.true.includes(n))return a++,{k:"lit",v:!0};if(r.false.includes(n))return a++,{k:"lit",v:!1};if(s())return l();if(a++,"op"===(null===(e=o[a])||void 0===e?void 0:e.t)&&"("===o[a].v){a++;const e=[];if(!c(")")){do{e.push(d())}while(c(","));c(")")||l()}return{k:"call",fn:t.v,args:e}}return{k:"var",name:t.v}}return l()};if(!o.length)throw new ze("syntax","");const x=[d()];if(n)for(;c(",");)x.push(d());return a<o.length&&l(),x},We=e=>"number"==typeof e,Ye=e=>isFinite(e)?parseFloat(e.toPrecision(12)):e,Je=(e,t,n="en")=>{var o;switch(e.k){case"lit":return e.v;case"var":if(!t.has(e.name))throw new ze("undefined",e.name);return t.get(e.name);case"call":{const r=null!==(o=He[e.fn.toLowerCase()])&&void 0!==o?o:e.fn.toLowerCase(),a=Re[r];if(!a)throw new ze("unknownFunction",e.fn);if(e.args.length<a.min||e.args.length>a.max)throw new ze("arguments",e.fn);const i=e.args.map(e=>Je(e,t,n));try{return Ye(a.call(i))}catch(t){if(t instanceof ze)throw new ze(t.code,e.fn);throw t}}case"un":{const o=Je(e.a,t,n);if("-"===e.op){if(!We(o))throw new ze("notNumber","-");return Ye(-o)}if("boolean"!=typeof o)throw new ze("notBoolean","not");return!o}case"bin":{if("and"===e.op||"or"===e.op){const o=Je(e.a,t,n);if("boolean"!=typeof o)throw new ze("notBoolean",e.op);if("and"===e.op?!o:o)return o;const r=Je(e.b,t,n);if("boolean"!=typeof r)throw new ze("notBoolean",e.op);return r}const o=Je(e.a,t,n),r=Je(e.b,t,n);switch(e.op){case"=":return typeof o==typeof r&&(We(o)?Ye(o)===Ye(r):o===r);case"!=":return!(typeof o==typeof r&&(We(o)?Ye(o)===Ye(r):o===r));case"<":case"<=":case">":case">=":{if(!(We(o)&&We(r)||"string"==typeof o&&"string"==typeof r))throw new ze("notComparable",e.op);const t=We(o)?Ye(o):o,n=We(r)?Ye(r):r;return"<"===e.op?t<n:"<="===e.op?t<=n:">"===e.op?t>n:t>=n}case"+":if(We(o)&&We(r))return Ye(o+r);if("string"==typeof o||"string"==typeof r)return`${Ke(o,n)}${Ke(r,n)}`;throw new ze("notNumber","+")}if(!We(o)||!We(r))throw new ze("notNumber",e.op);switch(e.op){case"-":return Ye(o-r);case"*":return Ye(o*r);case"/":if(0===r)throw new ze("divZero");return Ye(o/r);case"//":if(0===r)throw new ze("divZero");return Math.floor(Ye(o/r));case"%":if(0===r)throw new ze("divZero");return Ye((o%r+r)%r);case"^":return Ye(Math.pow(o,r))}throw new ze("syntax",e.op)}}},Ke=(e,t="en")=>{if("boolean"==typeof e)return De[t][e?0:1];if("number"==typeof e){if(!isFinite(e))return String(e);let t=String(Ye(e));return/e/i.test(t)&&Math.abs(e)<1e21&&(t=Ye(e).toFixed(12).replace(/0+$/,"").replace(/\.$/,"")),"-0"===t?"0":t}return e},Ze=e=>{const t=e.trim();return/^[-−]?(\d+([.,]\d+)?|[.,]\d+)$/.test(t)?Ye(parseFloat(t.replace("−","-").replace(",","."))):t},Xe=e=>String(null!=e?e:"").split(/\r?\n/).filter(e=>""!==e.trim()).map(Ze),Ge=(e,t,n,o=0)=>e.map(e=>{const r=t=>{try{return t()}catch(t){if(t instanceof ze)throw new ze(t.code,t.detail,e.line);throw t}},a=t=>{if(null===t||""===t.trim())throw new ze("blank",void 0,e.line);return t.trim()},i=n=>{const o=a(n);if(!Fe(o,t))throw new ze("notName",o,e.line);return o},l=e=>r(()=>qe(a(e),t)[0]),s=r=>{if(o+1>n)throw new ze("tooDeep",String(n),e.line);return Ge(r,t,n,o+1)};switch(e.kind){case"set":return{kind:"set",line:e.line,name:i(e.name),expr:l(e.expr)};case"input":return{kind:"input",line:e.line,name:i(e.name)};case"print":return{kind:"print",line:e.line,exprs:r(()=>qe(a(e.expr),t,!0))};case"if":return{kind:"if",line:e.line,cond:l(e.cond),body:s(e.body),other:e.other?s(e.other):void 0};case"while":return{kind:"while",line:e.line,cond:l(e.cond),body:s(e.body)};case"repeat":return{kind:"repeat",line:e.line,count:l(e.count),body:s(e.body)};case"for":return{kind:"for",line:e.line,name:i(e.name),from:l(e.from),to:l(e.to),body:s(e.body)}}}),Qe=(e,t=[],n={})=>{var o,r,a,i;const l=null!==(o=n.language)&&void 0!==o?o:"en",s=null!==(r=n.maxSteps)&&void 0!==r?r:1e4,c=null!==(a=n.maxOutput)&&void 0!==a?a:500,d=[],u=new Map;let p=0,h=0;const m=e=>{if(++p>s)throw new ze("tooManySteps",String(s),e)},f=(e,t)=>{const n=Je(e,u,l);if("boolean"!=typeof n)throw new ze("notBoolean",Ke(n,l),t);return n},b=e=>{const t=Je(e,u,l);if("number"!=typeof t)throw new ze("notNumber",Ke(t,l));return t},g=e=>{for(const n of e){m(n.line);try{switch(n.kind){case"set":u.set(n.name,Je(n.expr,u,l));break;case"input":if(h>=t.length)throw new ze("noInput");u.set(n.name,t[h++]);break;case"print":if(d.length>=c)throw new ze("tooMuchOutput",String(c));d.push(n.exprs.map(e=>Ke(Je(e,u,l),l)).join(" "));break;case"if":f(n.cond,n.line)?g(n.body):n.other&&g(n.other);break;case"while":for(;f(n.cond,n.line);)g(n.body),m(n.line);break;case"repeat":{const e=b(n.count);if(!Number.isInteger(e)||e<0)throw new ze("notWhole",Ke(e,l));for(let t=0;t<e;t++)g(n.body),m(n.line);break}case"for":{const e=b(n.from),t=b(n.to);for(let o=e;o<=t;o=Ye(o+1))u.set(n.name,o),g(n.body),m(n.line);break}}}catch(e){throw e instanceof ze&&!e.line&&(e.line=n.line),e}}};try{if(!e.length)throw new ze("empty");return g(Ge(e,l,null!==(i=n.maxDepth)&&void 0!==i?i:5)),{output:d,steps:p}}catch(e){if(e instanceof ze){const t={code:e.code,line:e.line};return void 0!==e.detail&&(t.detail=e.detail),{output:d,error:t,steps:p}}return{output:d,error:{code:"syntax",line:0},steps:p}}},et=["set","input","print","if","ifelse","while","repeat","for"],tt={set:"set",assign:"set",input:"input",read:"input",print:"print",output:"print",write:"print",if:"if",ifelse:"ifelse","if-else":"ifelse","if/else":"ifelse",while:"while",repeat:"repeat",for:"for"},nt={set:["name","expr"],input:["name"],print:["expr"],if:["cond"],ifelse:["cond"],while:["cond"],repeat:["count"],for:["name","from","to"]},ot=e=>"if"===e||"ifelse"===e||"while"===e||"repeat"===e||"for"===e,rt=e=>{const t=[],n=[];let o=0,r="";for(;o<e.length;){const a=e[o];if("{"===a){const a=e.indexOf("}",o+1);if(a<0)return null;r&&t.push(r),r="";const i=e.slice(o+1,a);if(""===i.trim())n.push({type:"text"});else if(i.includes("|")){const e=i.split("|").map(e=>e.trim()).filter(e=>""!==e).slice(0,10);n.push(e.length?{type:"choice",options:e}:{type:"text"})}else n.push({type:"fixed",text:i.trim()});t.push({slot:n.length-1}),o=a+1}else r+=a,o++}return r&&t.push(r),{parts:t,slots:n}},at=/^([a-z/-]+)\s*:\s*(.*)$/i,it=(e,t)=>{const n=at.exec(e.trim()),o=n?tt[n[1].toLowerCase()]:void 0;if(!n||!o)return`no kind (set, input, print, if, ifelse, while, repeat, for) before a colon: ${e.trim()}`;let r,a=n[2];if("ifelse"===o){const e=(e=>{let t=0;for(let n=0;n<e.length;n++)if("{"===e[n])t++;else if("}"===e[n])t=Math.max(0,t-1);else if("|"===e[n]&&0===t)return n;return-1})(a);r=t,e>=0&&(r=a.slice(e+1).trim()||t,a=a.slice(0,e))}const i=rt(a.trim());return i?i.slots.length<nt[o].length?`${o} needs ${nt[o].length} part(s) in braces: ${e.trim()}`:Object.assign(Object.assign({kind:o},i),void 0!==r?{elseLabel:r}:{}):`a { without } in: ${e.trim()}`},lt=" ",st="___",ct={en:"else",nl:"anders",fr:"sinon"},dt={en:{prompt:"Make a program that reads a whole number n and prints the sum 1 + 2 + … + n. Put the blocks in order, fill in the blanks, and try your program with Run.",blocks:["set: {total} ← {}","for: for {i} from {} to {}","set: {total} ← {total} {+|-|*} {i}","print: print {total}","print: print {i}","while: while {total < n}","set: {i} ← {i} + {1}"].join("\n"),program:"* input: read {n}",solution:["read n","total ← 0","for i from 1 to n"," total ← total + i","print total"].join("\n"),inputs:"5",tests:["5 => 15","1 => 1","10 => 55"].join("\n")},nl:{prompt:"Maak een programma dat een geheel getal n leest en de som 1 + 2 + … + n toont. Zet de blokken in de goede volgorde, vul de open plekken in en probeer je programma met Uitvoeren.",blocks:["set: {totaal} ← {}","for: voor {i} van {} tot en met {}","set: {totaal} ← {totaal} {+|-|*} {i}","print: toon {totaal}","print: toon {i}","while: zolang {totaal < n}","set: {i} ← {i} + {1}"].join("\n"),program:"* input: lees {n}",solution:["lees n","totaal ← 0","voor i van 1 tot en met n"," totaal ← totaal + i","toon totaal"].join("\n"),inputs:"5",tests:["5 => 15","1 => 1","10 => 55"].join("\n")},fr:{prompt:"Écris un programme qui lit un nombre entier n et affiche la somme 1 + 2 + … + n. Mets les blocs dans l'ordre, remplis les trous et essaie ton programme avec Exécuter.",blocks:["set: {total} ← {}","for: pour {i} de {} à {}","set: {total} ← {total} {+|-|*} {i}","print: afficher {total}","print: afficher {i}","while: tant que {total < n}","set: {i} ← {i} + {1}"].join("\n"),program:"* input: lire {n}",solution:["lire n","total ← 0","pour i de 1 à n"," total ← total + i","afficher total"].join("\n"),inputs:"5",tests:["5 => 15","1 => 1","10 => 55"].join("\n")}},ut=(e,t,n)=>{var o;const r=e.slots[n];return r?"fixed"===r.type?r.text:(null!==(o=t.values[n])&&void 0!==o?o:"").trim():""},pt=(e,t)=>e.parts.map(n=>"string"==typeof n?n:ut(e,t,n.slot)||st).join("").replace(/\s+/g," ").trim(),ht=(e,t)=>{const n=[],o=(t,r)=>{var a,i,l;for(const s of t){const t=e.blocks[s.block];t&&(n.push({node:s,block:t,depth:r,isElse:!1,number:n.length+1,text:pt(t,s)}),ot(t.kind)&&o(null!==(a=s.body)&&void 0!==a?a:[],r+1),"ifelse"===t.kind&&(n.push({node:s,block:t,depth:r,isElse:!0,number:n.length+1,text:null!==(i=t.elseLabel)&&void 0!==i?i:ct[e.language]}),o(null!==(l=s.other)&&void 0!==l?l:[],r+1)))}};return o(t,0),n},mt=(e,t)=>ht(e,t).map(e=>lt.repeat(e.depth)+e.text).join("\n"),ft=(e,t)=>{const n=nt[e.kind],o=[];for(let r=0;r<n.length-1;r++)o.push(ut(e,t,r)||null);const r=n.length-1;let a="",i=!1,l=!1;for(const n of e.parts){if("string"==typeof n){l&&(a+=n);continue}if(n.slot<r)continue;l=!0;const o=ut(e,t,n.slot);if(o||(i=!0),a+=o,n.slot===e.slots.length-1)break}return o.push(i?null:a.replace(/\s+/g," ").trim()),o},bt=(e,t)=>{let n=0;const o=t=>{var r,a,i,l,s,c;const d=[];for(const u of t){const t=e.blocks[u.block];if(!t)continue;const p=++n,h=ft(t,u);switch(t.kind){case"set":d.push({kind:"set",line:p,name:h[0],expr:h[1]});break;case"input":d.push({kind:"input",line:p,name:h[0]});break;case"print":d.push({kind:"print",line:p,expr:h[0]});break;case"if":d.push({kind:"if",line:p,cond:h[0],body:o(null!==(r=u.body)&&void 0!==r?r:[])});break;case"ifelse":{const e=o(null!==(a=u.body)&&void 0!==a?a:[]);n++,d.push({kind:"if",line:p,cond:h[0],body:e,other:o(null!==(i=u.other)&&void 0!==i?i:[])});break}case"while":d.push({kind:"while",line:p,cond:h[0],body:o(null!==(l=u.body)&&void 0!==l?l:[])});break;case"repeat":d.push({kind:"repeat",line:p,count:h[0],body:o(null!==(s=u.body)&&void 0!==s?s:[])});break;case"for":d.push({kind:"for",line:p,name:h[0],from:h[1],to:h[2],body:o(null!==(c=u.body)&&void 0!==c?c:[])})}}return d};return o(t)},gt=(e,t,n)=>{const o=Qe(bt(e,t),Xe(n),{language:e.language,maxSteps:e.maxSteps,maxDepth:e.maxDepth});return o.error?{output:o.output,error:o.error}:{output:o.output}},vt=(e,t)=>{const n=(e,o,r,a)=>{for(let i=0;i<e.length;i++){const l=e[i];if(l.id===t)return{node:l,list:e,index:i,parent:o,branch:r,depth:a};const s=l.body&&n(l.body,l,"body",a+1);if(s)return s;const c=l.other&&n(l.other,l,"other",a+1);if(c)return c}return null};return n(e,null,"body",0)},xt=e=>e.reduce((e,t)=>{var n,o;return e+1+xt(null!==(n=t.body)&&void 0!==n?n:[])+xt(null!==(o=t.other)&&void 0!==o?o:[])},0),kt=e=>{var t,n;return Math.max(0,...[...null!==(t=e.body)&&void 0!==t?t:[],...null!==(n=e.other)&&void 0!==n?n:[]].map(e=>1+kt(e)))},wt=e=>{const t=new Map,n=e=>e.forEach(e=>{var o,r,a;t.set(e.block,(null!==(o=t.get(e.block))&&void 0!==o?o:0)+1),n(null!==(r=e.body)&&void 0!==r?r:[]),n(null!==(a=e.other)&&void 0!==a?a:[])});return n(e),t},yt=(e,t,n,o)=>{if(null===t)return o(e);const r=e=>e.map(e=>{var a;if(e.id===t)return Object.assign(Object.assign({},e),{[n]:o(null!==(a=e[n])&&void 0!==a?a:[])});const i=Object.assign({},e);return e.body&&(i.body=r(e.body)),e.other&&(i.other=r(e.other)),i});return r(e)},_t=(e,t,n,o)=>{var r;if(null!==o.parent){const n=vt(t,o.parent);if(!n)return!1;const a=null===(r=e.blocks[n.node.block])||void 0===r?void 0:r.kind;if(!a||!ot(a)||"other"===o.branch&&"ifelse"!==a)return!1}return((e,t)=>{var n,o;return null===t?0:(null!==(o=null===(n=vt(e,t))||void 0===n?void 0:n.depth)&&void 0!==o?o:0)+1})(t,o.parent)+kt(n)<=e.maxDepth},$t=(e,t,n)=>yt(e,t.parent,t.branch,e=>{const o=Math.max(0,Math.min(e.length,t.index));return[...e.slice(0,o),n,...e.slice(o)]}),Nt=(e,t,n=!0)=>{var o,r,a,i;const l=vt(e,t);if(!l)return e;const s=n?[...null!==(o=l.node.body)&&void 0!==o?o:[],...null!==(r=l.node.other)&&void 0!==r?r:[]]:[];return yt(e,null!==(i=null===(a=l.parent)||void 0===a?void 0:a.id)&&void 0!==i?i:null,l.branch,e=>[...e.slice(0,l.index),...s,...e.slice(l.index+1)])},St=(e,t)=>{const n={id:t,block:e.id,values:e.slots.map(()=>"")};return ot(e.kind)&&(n.body=[]),"ifelse"===e.kind&&(n.other=[]),n},jt=(e,t,n,o)=>{var r,a,i;const l=vt(t,n);if(!l||l.node.locked)return null;if(null!==o.parent&&(o.parent===n||vt([l.node],o.parent)))return null;let s=o.index;(null!==(r=o.parent)&&void 0!==r?r:null)===(null!==(i=null===(a=l.parent)||void 0===a?void 0:a.id)&&void 0!==i?i:null)&&o.branch===l.branch&&s>l.index&&s--;const c=Nt(t,n,!1),d=Object.assign(Object.assign({},o),{index:s});return _t(e,c,l.node,d)?$t(c,d,l.node):null},Ot=(e,t,n,o)=>{var r,a;const i=vt(t,n);if(!i||i.node.locked)return null;const l=Nt(t,n,!1),s={parent:null!==(a=null===(r=i.parent)||void 0===r?void 0:r.id)&&void 0!==a?a:null,branch:i.branch,index:i.index},c=((e,t,n)=>{const o=[],r=(t,a,i,l)=>{var s,c,d;for(let u=0;u<=t.length;u++){(!n||l+kt(n)<=e.maxDepth)&&o.push({parent:a,branch:i,index:u});const p=t[u];if(!p)break;const h=null===(s=e.blocks[p.block])||void 0===s?void 0:s.kind;h&&ot(h)&&r(null!==(c=p.body)&&void 0!==c?c:[],p.id,"body",l+1),"ifelse"===h&&r(null!==(d=p.other)&&void 0!==d?d:[],p.id,"other",l+1)}};return r(t,null,"body",0),o})(e,l,i.node),d=c.findIndex(e=>((e,t)=>e.parent===t.parent&&e.branch===t.branch&&e.index===t.index)(e,s)),u=c[d+o];return d<0||!u?null:$t(l,u,i.node)},Et=e=>e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),Tt=e=>e.split(/\s+/).map(Et).join("\\s*"),Lt=(e,t)=>{const n=(e=>{const t=e.parts.map(t=>{if("string"==typeof t)return Tt(t);const n=e.slots[t.slot];return"fixed"===n.type?Tt(n.text):"choice"===n.type?`(${[...n.options,st].map(Et).join("|")})`:"(.*?)"}).join("");return new RegExp(`^\\s*${t}\\s*$`,"u")})(e).exec(t.trim());if(!n)return null;const o=e.slots.map(()=>"");let r=1;return e.parts.forEach(t=>{var a;if("string"==typeof t)return;if("fixed"===e.slots[t.slot].type)return;const i=(null!==(a=n[r++])&&void 0!==a?a:"").trim();o[t.slot]=i===st?"":i}),o},Mt=(e,t)=>{var n,o;if(e.kind!==t.kind||e.slots.length!==t.slots.length||e.parts.length!==t.parts.length)return null;const r=e=>e.replace(/\s+/g," ").trim();for(let n=0;n<e.parts.length;n++){const o=e.parts[n],a=t.parts[n];if("string"==typeof o?"string"!=typeof a||r(o)!==r(a):"string"==typeof a||o.slot!==a.slot)return null}if((null!==(n=e.elseLabel)&&void 0!==n?n:"")!==(null!==(o=t.elseLabel)&&void 0!==o?o:""))return null;const a=[];for(let n=0;n<e.slots.length;n++){const o=e.slots[n],i=t.slots[n];if("fixed"===o.type){if("fixed"!==i.type||r(o.text)!==r(i.text))return null;a.push("")}else if("fixed"===i.type){if("choice"===o.type&&!o.options.includes(i.text))return null;a.push(i.text)}else if("choice"===o.type&&"choice"===i.type&&o.options.join("|")===i.options.join("|"))a.push("");else{if("text"!==o.type||"text"!==i.type)return null;a.push("")}}return a},Bt=e=>e.slots.filter(e=>"fixed"!==e.type).length,Ct=e=>e.parts.reduce((t,n)=>t+("string"==typeof n?n.trim().length:"fixed"===e.slots[n.slot].type?e.slots[n.slot].text.length:0),0),zt=(e,t)=>{const n=e.map(e=>({block:e,values:Lt(e,t)})).filter(e=>e.values).sort((e,t)=>Bt(e.block)-Bt(t.block)||Ct(t.block)-Ct(e.block)||Number(t.block.palette)-Number(e.block.palette));return n.length?{block:n[0].block,values:n[0].values}:null},It=(e,t,n,o,r,a)=>{var i,l;const s=[],c=ct[n],d=[];let u=null;const p=new Map;let h=0;for(const n of String(null!=e?e:"").split(/\r?\n/)){if(!n.trim()||n.trim().startsWith("#"))continue;const e=n.replace(/\t/g,lt).search(/\S/);if(d.length||d.push({indent:e,list:s}),u&&e>u.indent)d.push({indent:e,list:u.list});else for(;d.length>1&&e<d[d.length-1].indent;)d.pop();u=null;let m=n.trim();const f=d[d.length-1],b=f.list[f.list.length-1],g=b&&t[b.block];if("ifelse"===(null==g?void 0:g.kind)&&p.get(b)===e){const t=m.toLowerCase();if(t===(null!==(i=g.elseLabel)&&void 0!==i?i:c).toLowerCase()||"else"===t||t===c){u={list:b.other=null!==(l=b.other)&&void 0!==l?l:[],indent:e};continue}}let v=!1;m.startsWith("*")&&(v=!0,m=m.slice(1).trim());let x=null;if(at.test(m)&&tt[at.exec(m)[1].toLowerCase()]){const e=it(m,c);if("string"==typeof e){a.push(e);continue}const n=Object.values(t).map(t=>({b:t,values:Mt(t,e)})).find(e=>e.values);if(n)x=Object.assign(Object.assign({},St(n.b,r())),{values:n.values});else{const n=Object.assign(Object.assign({},e),{id:`${o}${++h}`,palette:!1});t[n.id]=n,x=St(n,r()),x.values=n.slots.map(()=>"")}}else{const e=zt(Object.values(t),m);if(!e){a.push(`no block matches: ${m}`);continue}x=Object.assign(Object.assign({},St(e.block,r())),{values:e.values})}v&&(x.locked=!0),p.set(x,e),f.list.push(x);const k=t[x.block].kind;ot(k)&&(u={list:x.body,indent:e})}return s},Dt=(e,t=[])=>{const n=[];for(const o of String(null!=e?e:"").split(/\r?\n/)){const e=o.trim();if(!e||e.startsWith("#"))continue;const r=/^(.*?)(=>|->|→)(.*)$/.exec(e);if(!r){t.push(`a test needs => between the input and the output: ${e}`);continue}const a=e=>""===e.trim()?[]:e.split(";").map(e=>e.trim());n.length<8&&n.push({inputs:a(r[1]),expected:a(r[3]),source:e})}return n},At=(e,t)=>{const n=bt(e,t),o=e.tests.map(t=>{const o=Qe(n,Xe(t.inputs.join("\n")),{language:e.language,maxSteps:e.maxSteps,maxDepth:e.maxDepth}),r=o.output.map(e=>e.trim()),a=!o.error&&r.length===t.expected.length&&r.every((e,n)=>e===t.expected[n]);return o.error?{passed:a,output:r,error:o.error}:{passed:a,output:r}}),r=o.filter(e=>e.passed).length;return{score:r,maxscore:o.length,correct:o.length>0&&r===o.length,results:o}},Rt=e=>null==e?"":String(e),Ht=(e,t)=>""===Rt(e).trim()?t:"false"!==Rt(e).trim().toLowerCase(),Pt=(e,t,n,o)=>{const r=parseInt(Rt(e),10);return isFinite(r)?Math.max(n,Math.min(o,r)):t},Ut=e=>{const t=(e=>{const t=String(null!=e?e:"").slice(0,2).toLowerCase();return"nl"===t||"fr"===t?t:"en"})(e.language),n=""===Rt(e.blocks).trim()?dt[t]:null,o=t=>""===Rt(e[t]).trim()&&n?n[t]:Rt(e[t]),r=[],a=ct[t],i={},l=[];for(const e of o("blocks").split(/\r?\n/)){if(!e.trim()||e.trim().startsWith("#"))continue;const t=it(e,a);if("string"==typeof t){r.push(t);continue}const n=`b${l.length+1}`;i[n]=Object.assign(Object.assign({},t),{id:n,palette:!0}),l.push(n)}let s=0;const c=It(o("program"),i,t,"p",()=>"n"+ ++s,r);let d=0;const u=o("solution"),p=u.trim()?It(u,i,t,"s",()=>"s"+ ++d,r):null,h=Rt(e.scoring).trim().toLowerCase();return{language:t,prompt:o("prompt"),blocks:i,palette:l,start:c,solution:p,inputs:o("inputs"),editInputs:Ht(e.editInputs,!0),reuse:Ht(e.reuse,!1),tests:Dt(o("tests"),r),scoring:"code"===h||"pci"===h?h:"original",maxBlocks:Pt(e.maxBlocks,30,1,60),maxDepth:Pt(e.maxDepth,5,1,10),maxSteps:Pt(e.maxSteps,1e4,100,1e6),problems:r}},Ft=e=>e.reduce((e,t)=>{var n,o;return Math.max(e,parseInt(t.id.slice(1),10)||0,Ft(null!==(n=t.body)&&void 0!==n?n:[]),Ft(null!==(o=t.other)&&void 0!==o?o:[]))},0),Vt=(e,t)=>{if(!Array.isArray(t))return null;const n=(e=>{const t=new Set,n=e=>e.forEach(e=>{var o,r;e.locked&&t.add(e.id),n(null!==(o=e.body)&&void 0!==o?o:[]),n(null!==(r=e.other)&&void 0!==r?r:[])});return n(e.start),t})(e),o=new Set;let r=0;const a=(t,i)=>{const l=[];for(const s of t){const t=s,c=t&&"string"==typeof t.block?e.blocks[t.block]:void 0;if(!c||r>=60)continue;r++;let d="string"==typeof t.id&&/^n\d+$/.test(t.id)&&!o.has(t.id)?t.id:"";d||(d=`n${1e3+r}`),o.add(d);const u={id:d,block:c.id,values:c.slots.map((e,n)=>{var o;return"fixed"===e.type?"":String(Array.isArray(t.values)&&null!==(o=t.values[n])&&void 0!==o?o:"").slice(0,200)})};ot(c.kind)&&(u.body=i<10?a(Array.isArray(t.body)?t.body:[],i+1):[]),"ifelse"===c.kind&&(u.other=i<10?a(Array.isArray(t.other)?t.other:[],i+1):[]),n.has(d)&&(u.locked=!0),l.push(u)}return l};return a(t,0)},qt=(e,t)=>{const n=e,o=Vt(t,null==n?void 0:n.program);if(!o)return null;const r=null==n?void 0:n.run,a=r&&Array.isArray(r.output)?Object.assign({inputs:Rt(r.inputs),output:r.output.map(Rt)},r.error&&"string"==typeof r.error.code?{error:r.error}:{}):null;return{program:o,inputs:"string"==typeof(null==n?void 0:n.inputs)?n.inputs:t.inputs,next:Math.max(Number(null==n?void 0:n.next)||0,Ft(o)+1),run:a}},Wt=e=>JSON.stringify(e,(e,t)=>"id"===e||"locked"===e?void 0:t),Yt={set:"set",input:"input",print:"print",if:"if",ifelse:"ifElse",while:"while",repeat:"repeat",for:"for"},Jt={variables:{c:"#C2335F",dark:"#97274A"},control:{c:"#B25E00",dark:"#8A4900"},io:{c:"#2D5FD3",dark:"#234AA4"},events:{c:"#1F7F4C",dark:"#18633B"}},Kt=e=>"set"===e?"variables":"input"===e||"print"===e?"io":"control",Zt=e=>({"--c":Jt[e].c,"--dark":Jt[e].dark}),Xt="inline-flex h-7 items-center rounded-full font-semibold",Gt=`${Xt} border-0 bg-white px-2.5 text-center text-[14px] text-slate-900 shadow-[inset_0_1px_2px_rgba(15,23,42,0.25)] focus:outline-3 focus:outline-offset-1 focus:outline-slate-900 disabled:text-slate-900 disabled:opacity-100`,Qt=({block:e,node:t,number:n,texts:o,disabled:r,onValue:a})=>{let i=0;return V("span",{"data-label":!0,className:"flex min-w-0 flex-wrap items-center gap-x-1.5 gap-y-1 text-[14px] leading-7 font-semibold text-white",children:e.parts.map((l,s)=>{var c;if("string"==typeof l)return l.trim()?V("span",{className:"whitespace-pre-wrap",children:l.trim()},s):null;const d=e.slots[l.slot];if(!d)return null;if("fixed"===d.type)return V("span",{className:`${Xt} bg-black/20 px-2.5`,children:d.text},s);if(i++,!t)return"choice"===d.type?V("span",{"aria-hidden":"true",className:`${Xt} w-11 justify-end border border-black/20 bg-[var(--dark)] pr-2 text-xs`,children:"▾"},s):V("span",{"aria-hidden":"true",className:`${Xt} w-9 bg-white shadow-[inset_0_1px_2px_rgba(15,23,42,0.25)]`},s);const u=null!==(c=t.values[l.slot])&&void 0!==c?c:"",p=o.blank(i,null!=n?n:0);return"choice"===d.type?V("span",{className:"relative inline-flex",children:[V("select",{className:`${Xt} cursor-pointer appearance-none border border-black/25 bg-[var(--dark)] pr-7 pl-3 text-[14px] text-white focus:outline-3 focus:outline-offset-1 focus:outline-slate-900 disabled:cursor-default disabled:opacity-100`,"aria-label":p,value:u,disabled:r,onChange:e=>null==a?void 0:a(l.slot,e.target.value),children:[V("option",{value:"",className:"bg-white text-slate-900",children:o.choose}),d.options.map(e=>V("option",{value:e,className:"bg-white text-slate-900",children:e},e))]}),V("span",{"aria-hidden":"true",className:"pointer-events-none absolute top-1/2 right-2.5 -translate-y-1/2 text-xs",children:"▾"})]},s):V("input",{type:"text",className:`${Gt} max-w-full`,"aria-label":p,value:u,disabled:r,spellcheck:!1,autocomplete:"off",autocapitalize:"off",maxLength:200,style:{width:`${Math.min(28,Math.max(3.5,u.length+2))}ch`},onInput:e=>null==a?void 0:a(l.slot,e.target.value)},s)})})},en=({block:e,texts:t})=>{const n=V(Qt,{block:e,texts:t});return"if"!==e.kind&&"ifelse"!==e.kind&&"while"!==e.kind&&"repeat"!==e.kind&&"for"!==e.kind?V("span",{className:"cb-piece inline-flex max-w-full items-center px-2.5 py-1.5",children:n}):V("span",{className:"flex max-w-full flex-col items-start","data-c-shape":!0,children:[V("span",{className:"cb-piece cb-c-top inline-flex max-w-full items-center px-2.5 py-1.5",children:n}),V("span",{"aria-hidden":"true",className:"cb-arm cb-mouth block"}),"ifelse"===e.kind&&V(w,{children:[V("span",{"aria-hidden":"true",className:"cb-piece cb-c-mid inline-flex items-center px-2.5 py-0.5 text-[13px] font-semibold",children:e.elseLabel}),V("span",{"aria-hidden":"true",className:"cb-arm cb-mouth block"})]}),V("span",{"aria-hidden":"true",className:"cb-piece cb-c-end block"})]})},tn=({d:e,className:t="size-4"})=>V("svg",{"aria-hidden":"true",viewBox:"0 0 16 16",className:t,fill:"none",stroke:"currentColor","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round",children:V("path",{d:e})}),nn="M8 13V3M3.5 7.5 8 3l4.5 4.5",on="M8 3v10M3.5 8.5 8 13l4.5-4.5",rn="M2 8h8M7 4.5 10.5 8 7 11.5M14 3v10",an="M14 8H6M9 4.5 5.5 8 9 11.5M2 3v10",ln="M4 4l8 8M12 4l-8 8",sn="M5 3.5v9l7-4.5z",cn=()=>V("svg",{"aria-hidden":"true",viewBox:"0 0 16 16",className:"size-4",fill:"currentColor",children:[4,8,12].flatMap(e=>[6,10].map(t=>V("circle",{cx:t,cy:e,r:"1.4"},`${t}${e}`)))}),dn=()=>V("svg",{"aria-hidden":"true",viewBox:"0 0 16 16",className:"size-4",fill:"currentColor",children:V("path",{d:"M4.5 7V5.5a3.5 3.5 0 0 1 7 0V7H12.5v7h-9V7zm1.6 0h3.8V5.5a1.9 1.9 0 0 0-3.8 0z"})}),un={blocks:"Blocks",hat:"when Run is pressed",categories:{variables:"Variables",control:"Control",io:"Input and output"},blocksHelp:"Drag a block into the program, or press it to add it below the selected block.",addBlock:e=>`Add block: ${e}`,used:"used",program:"Program",count:(e,t)=>`${e} of ${t} blocks`,emptyProgram:"Drag blocks here, or press a block on the left to add it.",emptyBranch:"Put a block here",keyboardHelp:"On the handle of a block: ↑ and ↓ move it, → puts it in the block above it, ← takes it out, Delete removes it.",handle:(e,t)=>`Line ${e}: ${t}`,locked:"locked",lockedLine:(e,t)=>`Line ${e}: ${t} (locked)`,moveUp:"Move up",moveDown:"Move down",indent:"Into the block above",outdent:"Out of the block",remove:"Remove",blank:(e,t)=>`Blank ${e} on line ${t}`,choose:"—",startOver:"Start over",startOverSure:"Remove your blocks and start over?",yes:"Yes, start over",no:"No",input:"Input",inputHelp:"One value per line; the program reads them in this order.",noInput:"No input.",run:"Run",output:"Output",notRun:"Press Run to see what the program prints.",nothingPrinted:"The program printed nothing.",finished:"The program has finished.",errorOn:e=>e>0?`Error on line ${e}:`:"Error:",added:(e,t)=>`Added “${e}” on line ${t}.`,moved:(e,t,n)=>`“${e}” is now on line ${t}${n?`, ${1===n?"1 level":`${n} levels`} in`:""}.`,removed:e=>`Removed “${e}”.`,cannotMove:"The block cannot go further that way.",full:e=>`The program is full: at most ${e} blocks.`,cleared:"The program is back to how it started.",ran:e=>`The program ran and printed ${1===e?"1 line":`${e} lines`}.`,ranWithError:e=>`The program stopped. ${e}`,errors:{empty:()=>"The program is empty: add blocks first.",blank:()=>"fill in every blank.",syntax:e=>e?`“${e}” cannot be read. Check the operators and brackets, and put text in quotes.`:"a blank cannot be read.",notName:e=>`“${e}” is not a name for a variable: use letters, digits and _, starting with a letter.`,undefined:e=>`the variable ${e} has no value yet.`,notNumber:()=>"this calculation needs numbers.",notBoolean:()=>"a condition must be true or false, such as x > 3.",notComparable:()=>"a number and a text cannot be compared.",divZero:()=>"division by zero.",noInput:()=>"there is no more input to read.",notWhole:e=>`the number of times must be a whole number of 0 or more${e?` (not ${e})`:""}.`,unknownFunction:e=>`there is no function ${e}.`,arguments:e=>`${null!=e?e:"the function"} cannot be used with these values.`,tooManySteps:e=>`the program took more than ${e} steps and was stopped. Does a loop never end?`,tooMuchOutput:e=>`the program printed more than ${e} lines and was stopped.`,tooDeep:e=>`blocks can be nested at most ${e} levels deep.`}},pn={en:un,nl:{blocks:"Blokken",hat:"wanneer Uitvoeren wordt ingedrukt",categories:{variables:"Variabelen",control:"Besturing",io:"Invoer en uitvoer"},blocksHelp:"Sleep een blok naar het programma, of druk erop om het onder het gekozen blok te zetten.",addBlock:e=>`Blok toevoegen: ${e}`,used:"gebruikt",program:"Programma",count:(e,t)=>`${e} van ${t} blokken`,emptyProgram:"Sleep blokken hierheen, of druk links op een blok om het toe te voegen.",emptyBranch:"Zet hier een blok",keyboardHelp:"Op de greep van een blok: ↑ en ↓ verplaatsen het, → zet het in het blok erboven, ← haalt het eruit, Delete verwijdert het.",handle:(e,t)=>`Regel ${e}: ${t}`,locked:"vast",lockedLine:(e,t)=>`Regel ${e}: ${t} (vast)`,moveUp:"Omhoog",moveDown:"Omlaag",indent:"In het blok erboven",outdent:"Uit het blok",remove:"Verwijderen",blank:(e,t)=>`Open plek ${e} op regel ${t}`,choose:"—",startOver:"Opnieuw beginnen",startOverSure:"Je blokken weghalen en opnieuw beginnen?",yes:"Ja, opnieuw beginnen",no:"Nee",input:"Invoer",inputHelp:"Eén waarde per regel; het programma leest ze in deze volgorde.",noInput:"Geen invoer.",run:"Uitvoeren",output:"Uitvoer",notRun:"Druk op Uitvoeren om te zien wat het programma toont.",nothingPrinted:"Het programma toonde niets.",finished:"Het programma is klaar.",errorOn:e=>e>0?`Fout op regel ${e}:`:"Fout:",added:(e,t)=>`“${e}” toegevoegd op regel ${t}.`,moved:(e,t,n)=>`“${e}” staat nu op regel ${t}${n?`, ${n} ${1===n?"niveau":"niveaus"} ingesprongen`:""}.`,removed:e=>`“${e}” verwijderd.`,cannotMove:"Het blok kan niet verder die kant op.",full:e=>`Het programma is vol: hoogstens ${e} blokken.`,cleared:"Het programma is weer zoals bij het begin.",ran:e=>`Het programma is uitgevoerd en toonde ${1===e?"1 regel":`${e} regels`}.`,ranWithError:e=>`Het programma stopte. ${e}`,errors:{empty:()=>"Het programma is leeg: voeg eerst blokken toe.",blank:()=>"vul alle open plekken in.",syntax:e=>e?`“${e}” is niet te lezen. Controleer de bewerkingen en haakjes, en zet tekst tussen aanhalingstekens.`:"een open plek is niet te lezen.",notName:e=>`“${e}” is geen naam voor een variabele: gebruik letters, cijfers en _, en begin met een letter.`,undefined:e=>`de variabele ${e} heeft nog geen waarde.`,notNumber:()=>"voor deze berekening zijn getallen nodig.",notBoolean:()=>"een voorwaarde moet waar of onwaar zijn, zoals x > 3.",notComparable:()=>"een getal en een tekst kun je niet vergelijken.",divZero:()=>"delen door nul.",noInput:()=>"er is geen invoer meer om te lezen.",notWhole:e=>`het aantal keer moet een geheel getal van 0 of meer zijn${e?` (niet ${e})`:""}.`,unknownFunction:e=>`er is geen functie ${e}.`,arguments:e=>`${null!=e?e:"de functie"} werkt niet met deze waarden.`,tooManySteps:e=>`het programma deed meer dan ${e} stappen en is gestopt. Houdt een herhaling nooit op?`,tooMuchOutput:e=>`het programma toonde meer dan ${e} regels en is gestopt.`,tooDeep:e=>`blokken kunnen hoogstens ${e} niveaus diep in elkaar.`}},fr:{blocks:"Blocs",hat:"quand on appuie sur Exécuter",categories:{variables:"Variables",control:"Contrôle",io:"Entrée et sortie"},blocksHelp:"Fais glisser un bloc dans le programme, ou appuie dessus pour l'ajouter sous le bloc choisi.",addBlock:e=>`Ajouter le bloc : ${e}`,used:"utilisé",program:"Programme",count:(e,t)=>`${e} blocs sur ${t}`,emptyProgram:"Fais glisser des blocs ici, ou appuie sur un bloc à gauche pour l'ajouter.",emptyBranch:"Mets un bloc ici",keyboardHelp:"Sur la poignée d'un bloc : ↑ et ↓ le déplacent, → le met dans le bloc au-dessus, ← l'en sort, Suppr le supprime.",handle:(e,t)=>`Ligne ${e} : ${t}`,locked:"fixe",lockedLine:(e,t)=>`Ligne ${e} : ${t} (fixe)`,moveUp:"Monter",moveDown:"Descendre",indent:"Dans le bloc au-dessus",outdent:"Hors du bloc",remove:"Supprimer",blank:(e,t)=>`Trou ${e} à la ligne ${t}`,choose:"—",startOver:"Recommencer",startOverSure:"Enlever tes blocs et recommencer ?",yes:"Oui, recommencer",no:"Non",input:"Entrée",inputHelp:"Une valeur par ligne ; le programme les lit dans cet ordre.",noInput:"Pas d'entrée.",run:"Exécuter",output:"Sortie",notRun:"Appuie sur Exécuter pour voir ce que le programme affiche.",nothingPrinted:"Le programme n'a rien affiché.",finished:"Le programme est terminé.",errorOn:e=>e>0?`Erreur à la ligne ${e} :`:"Erreur :",added:(e,t)=>`« ${e} » ajouté à la ligne ${t}.`,moved:(e,t,n)=>`« ${e} » est maintenant à la ligne ${t}${n?`, ${n} ${1===n?"niveau":"niveaux"} en retrait`:""}.`,removed:e=>`« ${e} » supprimé.`,cannotMove:"Le bloc ne peut pas aller plus loin dans ce sens.",full:e=>`Le programme est plein : ${e} blocs au plus.`,cleared:"Le programme est revenu à son début.",ran:e=>`Le programme s'est exécuté et a affiché ${e<=1?`${e} ligne`:`${e} lignes`}.`,ranWithError:e=>`Le programme s'est arrêté. ${e}`,errors:{empty:()=>"Le programme est vide : ajoute d'abord des blocs.",blank:()=>"remplis tous les trous.",syntax:e=>e?`« ${e} » ne peut pas être lu. Vérifie les opérateurs et les parenthèses, et mets le texte entre guillemets.`:"un trou ne peut pas être lu.",notName:e=>`« ${e} » n'est pas un nom de variable : utilise des lettres, des chiffres et _, en commençant par une lettre.`,undefined:e=>`la variable ${e} n'a pas encore de valeur.`,notNumber:()=>"ce calcul demande des nombres.",notBoolean:()=>"une condition doit être vraie ou fausse, comme x > 3.",notComparable:()=>"un nombre et un texte ne se comparent pas.",divZero:()=>"division par zéro.",noInput:()=>"il n'y a plus d'entrée à lire.",notWhole:e=>`le nombre de fois doit être un nombre entier de 0 ou plus${e?` (pas ${e})`:""}.`,unknownFunction:e=>`la fonction ${e} n'existe pas.`,arguments:e=>`${null!=e?e:"la fonction"} ne marche pas avec ces valeurs.`,tooManySteps:e=>`le programme a fait plus de ${e} pas et a été arrêté. Une boucle ne s'arrête-t-elle jamais ?`,tooMuchOutput:e=>`le programme a affiché plus de ${e} lignes et a été arrêté.`,tooDeep:e=>`les blocs s'emboîtent sur ${e} niveaux au plus.`}}},hn=e=>{var t;return null!==(t=pn[(null!=e?e:"").slice(0,2).toLowerCase()])&&void 0!==t?t:un},mn=(e,t)=>{var n;const o=(null!==(n=e.errors[t.code])&&void 0!==n?n:e.errors.syntax)(t.detail);return"empty"===t.code?o:`${e.errorOn(t.line)} ${o}`},fn={tabs:"Parts of the item",tabBlocks:"Blocks",tabSolution:"Solution",tabStart:"Starting program",tabTests:"Input and tests",blocksIntro:"The blocks the candidate can use. In a label, {} is a text box, {a|b|c} a dropdown and {total} fixed text that is part of the code.",block:e=>`Block ${e}`,kind:"Kind",kinds:{set:"Set a variable",input:"Read input",print:"Print",if:"If",ifelse:"If / else",while:"While",repeat:"Repeat",for:"For"},roles:{name:"variable",expr:"value",cond:"condition",count:"number of times",from:"from",to:"to"},label:"Label",elseLabel:"Else line",parts:"Parts in braces",part:(e,t)=>`Part ${e}${t?` (${t})`:""}`,partType:e=>`Type of part ${e}`,fixed:"Fixed text",textBox:"Text box",dropdown:"Dropdown",fixedText:e=>`Text of part ${e}`,choices:e=>`Choices of part ${e}, separated by |`,addPart:"Add a part",removePart:e=>`Remove part ${e}`,inPalette:"The candidate can add it",inSolution:"in the solution",distractor:"distractor",notInPalette:"not in the palette",moveBlockUp:e=>`Move block ${e} up`,moveBlockDown:e=>`Move block ${e} down`,removeBlock:e=>`Remove block ${e}`,newBlockKind:"Kind of the new block",addBlock:"Add block",blockAdded:e=>`Block ${e} added.`,blockRemoved:e=>`Block ${e} removed.`,blockMoved:e=>`The block is now block ${e}.`,solutionIntro:"Build the correct program from the blocks, as the candidate would. Blocks of the palette that it does not use are the distractors.",startIntro:"The blocks that are in place when the candidate starts. The candidate cannot move or remove a locked block, but fills in its blanks.",lock:e=>`Locked: ${e}`,locked:"Locked",copySolution:"Start from the solution",copied:"The starting program is now a copy of the solution.",solutionOutput:"Output of the solution with this input",noSolution:"No solution yet.",inputs:"Input at the start",inputsHelp:"A value per line. The candidate sees it (and can change it, unless that setting is off).",testsHeading:"Test cases",testsIntro:"A test gives the program input values and the lines it must print. At most 8.",test:e=>`Test ${e}`,testInputs:e=>`Input values of test ${e}, one per line`,testExpected:e=>`Expected output of test ${e}, one line per line`,addTest:"Add a test",removeTest:e=>`Remove test ${e}`,fill:"Fill in the expected output from the solution",filled:"The expected output is filled in from the solution.",passes:"passes",fails:"fails",notChecked:"no solution to check",solutionPrinted:e=>`The solution prints: ${e||"nothing"}`,checks:"Checks",errorsHeading:e=>1===e?"1 problem to fix":`${e} problems to fix`,warningsHeading:"Notes",allGood:"No problems found.",problem:{noBlocks:()=>"Add at least one block that the candidate can add.",unclosed:e=>`Block ${e.block}: a { has no }.`,parts:e=>`Block ${e.block}: this kind of block needs ${e.detail} parts in braces (${e.roles}).`,fewChoices:e=>`Block ${e.block}, part ${e.part}: a dropdown needs at least two choices.`,notName:e=>`Block ${e.block}, part ${e.part}: “${e.detail}” is not a variable name.`,tooManyStart:e=>`The starting program has more than ${e.detail} blocks, the most a program may have.`,tooManySolution:e=>`The solution has more than ${e.detail} blocks, the most a program may have.`,tooDeepStart:e=>`The starting program puts blocks more than ${e.detail} levels deep.`,tooDeepSolution:e=>`The solution puts blocks more than ${e.detail} levels deep.`,noSolution:e=>"error"===e.level?"The item compares the program with the solution: build it on the Solution tab.":"There is no solution yet (Solution tab).",solutionBlank:e=>`Line ${e.line} of the solution has an empty blank.`,notAvailable:e=>`The solution uses “${e.detail}” (block ${e.block}) more often than the candidate can add it.`,solutionError:e=>`With the input at the start the solution stops. ${e.message}`,testFails:e=>`Test ${e.test}: the solution does not print the expected output.`,noTests:()=>"Scoring with test cases needs at least one test.",semicolon:e=>`Test ${e.test}: a value cannot contain ;.`},newLabels:{set:"{x} ← {}",input:"read {x}",print:"print {}",if:"if {}",ifelse:"if {}",while:"while {}",repeat:"repeat {} times",for:"for {i} from {1} to {}"}},bn={en:fn,nl:{tabs:"Onderdelen van het item",tabBlocks:"Blokken",tabSolution:"Oplossing",tabStart:"Startprogramma",tabTests:"Invoer en tests",blocksIntro:"De blokken die de kandidaat kan gebruiken. In een label is {} een tekstvak, {a|b|c} een keuzelijst en {totaal} vaste tekst die bij de code hoort.",block:e=>`Blok ${e}`,kind:"Soort",kinds:{set:"Variabele een waarde geven",input:"Invoer lezen",print:"Tonen",if:"Als",ifelse:"Als / anders",while:"Zolang",repeat:"Herhaal",for:"Voor"},roles:{name:"variabele",expr:"waarde",cond:"voorwaarde",count:"aantal keer",from:"van",to:"tot"},label:"Label",elseLabel:"Anders-regel",parts:"Delen tussen accolades",part:(e,t)=>`Deel ${e}${t?` (${t})`:""}`,partType:e=>`Soort van deel ${e}`,fixed:"Vaste tekst",textBox:"Tekstvak",dropdown:"Keuzelijst",fixedText:e=>`Tekst van deel ${e}`,choices:e=>`Keuzes van deel ${e}, gescheiden door |`,addPart:"Deel toevoegen",removePart:e=>`Deel ${e} verwijderen`,inPalette:"De kandidaat kan het toevoegen",inSolution:"in de oplossing",distractor:"afleider",notInPalette:"niet in de blokken",moveBlockUp:e=>`Blok ${e} omhoog`,moveBlockDown:e=>`Blok ${e} omlaag`,removeBlock:e=>`Blok ${e} verwijderen`,newBlockKind:"Soort van het nieuwe blok",addBlock:"Blok toevoegen",blockAdded:e=>`Blok ${e} toegevoegd.`,blockRemoved:e=>`Blok ${e} verwijderd.`,blockMoved:e=>`Het blok is nu blok ${e}.`,solutionIntro:"Bouw het goede programma uit de blokken, zoals de kandidaat dat zou doen. Blokken die het niet gebruikt zijn de afleiders.",startIntro:"De blokken die al klaarstaan als de kandidaat begint. Een vast blok kan de kandidaat niet verplaatsen of verwijderen, wel invullen.",lock:e=>`Vast: ${e}`,locked:"Vast",copySolution:"Begin met de oplossing",copied:"Het startprogramma is nu een kopie van de oplossing.",solutionOutput:"Uitvoer van de oplossing met deze invoer",noSolution:"Nog geen oplossing.",inputs:"Invoer bij het begin",inputsHelp:"Eén waarde per regel. De kandidaat ziet die (en kan die veranderen, tenzij die instelling uit staat).",testsHeading:"Testgevallen",testsIntro:"Een test geeft het programma invoerwaarden en de regels die het moet tonen. Hoogstens 8.",test:e=>`Test ${e}`,testInputs:e=>`Invoerwaarden van test ${e}, één per regel`,testExpected:e=>`Verwachte uitvoer van test ${e}, één regel per regel`,addTest:"Test toevoegen",removeTest:e=>`Test ${e} verwijderen`,fill:"Verwachte uitvoer invullen met de oplossing",filled:"De verwachte uitvoer is ingevuld met de oplossing.",passes:"goed",fails:"fout",notChecked:"geen oplossing om te controleren",solutionPrinted:e=>`De oplossing toont: ${e||"niets"}`,checks:"Controle",errorsHeading:e=>1===e?"1 probleem op te lossen":`${e} problemen op te lossen`,warningsHeading:"Opmerkingen",allGood:"Geen problemen gevonden.",problem:{noBlocks:()=>"Voeg minstens één blok toe dat de kandidaat kan toevoegen.",unclosed:e=>`Blok ${e.block}: een { heeft geen }.`,parts:e=>`Blok ${e.block}: deze soort blok heeft ${e.detail} delen tussen accolades nodig (${e.roles}).`,fewChoices:e=>`Blok ${e.block}, deel ${e.part}: een keuzelijst heeft minstens twee keuzes nodig.`,notName:e=>`Blok ${e.block}, deel ${e.part}: “${e.detail}” is geen naam voor een variabele.`,tooManyStart:e=>`Het startprogramma heeft meer dan ${e.detail} blokken, het meeste dat een programma mag hebben.`,tooManySolution:e=>`De oplossing heeft meer dan ${e.detail} blokken, het meeste dat een programma mag hebben.`,tooDeepStart:e=>`Het startprogramma zet blokken meer dan ${e.detail} niveaus diep.`,tooDeepSolution:e=>`De oplossing zet blokken meer dan ${e.detail} niveaus diep.`,noSolution:e=>"error"===e.level?"Het item vergelijkt het programma met de oplossing: bouw die bij Oplossing.":"Er is nog geen oplossing (Oplossing).",solutionBlank:e=>`Regel ${e.line} van de oplossing heeft een lege open plek.`,notAvailable:e=>`De oplossing gebruikt “${e.detail}” (blok ${e.block}) vaker dan de kandidaat het kan toevoegen.`,solutionError:e=>`Met de invoer bij het begin stopt de oplossing. ${e.message}`,testFails:e=>`Test ${e.test}: de oplossing toont niet de verwachte uitvoer.`,noTests:()=>"Scoren met testgevallen vraagt minstens één test.",semicolon:e=>`Test ${e.test}: een waarde mag geen ; bevatten.`},newLabels:{set:"{x} ← {}",input:"lees {x}",print:"toon {}",if:"als {}",ifelse:"als {}",while:"zolang {}",repeat:"herhaal {} keer",for:"voor {i} van {1} tot en met {}"}},fr:{tabs:"Parties de l'item",tabBlocks:"Blocs",tabSolution:"Solution",tabStart:"Programme de départ",tabTests:"Entrée et tests",blocksIntro:"Les blocs que le candidat peut utiliser. Dans une étiquette, {} est une zone de texte, {a|b|c} une liste et {total} un texte fixe qui fait partie du code.",block:e=>`Bloc ${e}`,kind:"Type",kinds:{set:"Donner une valeur",input:"Lire l'entrée",print:"Afficher",if:"Si",ifelse:"Si / sinon",while:"Tant que",repeat:"Répéter",for:"Pour"},roles:{name:"variable",expr:"valeur",cond:"condition",count:"nombre de fois",from:"de",to:"à"},label:"Étiquette",elseLabel:"Ligne sinon",parts:"Parties entre accolades",part:(e,t)=>`Partie ${e}${t?` (${t})`:""}`,partType:e=>`Type de la partie ${e}`,fixed:"Texte fixe",textBox:"Zone de texte",dropdown:"Liste",fixedText:e=>`Texte de la partie ${e}`,choices:e=>`Choix de la partie ${e}, séparés par |`,addPart:"Ajouter une partie",removePart:e=>`Supprimer la partie ${e}`,inPalette:"Le candidat peut l'ajouter",inSolution:"dans la solution",distractor:"distracteur",notInPalette:"pas dans les blocs",moveBlockUp:e=>`Monter le bloc ${e}`,moveBlockDown:e=>`Descendre le bloc ${e}`,removeBlock:e=>`Supprimer le bloc ${e}`,newBlockKind:"Type du nouveau bloc",addBlock:"Ajouter le bloc",blockAdded:e=>`Bloc ${e} ajouté.`,blockRemoved:e=>`Bloc ${e} supprimé.`,blockMoved:e=>`Le bloc est maintenant le bloc ${e}.`,solutionIntro:"Construis le bon programme avec les blocs, comme le ferait le candidat. Les blocs qu'il n'utilise pas sont les distracteurs.",startIntro:"Les blocs déjà en place quand le candidat commence. Le candidat ne peut ni déplacer ni supprimer un bloc fixe, mais il remplit ses trous.",lock:e=>`Fixe : ${e}`,locked:"Fixe",copySolution:"Partir de la solution",copied:"Le programme de départ est maintenant une copie de la solution.",solutionOutput:"Sortie de la solution avec cette entrée",noSolution:"Pas encore de solution.",inputs:"Entrée au départ",inputsHelp:"Une valeur par ligne. Le candidat la voit (et peut la changer, sauf si ce réglage est désactivé).",testsHeading:"Cas de test",testsIntro:"Un test donne au programme des valeurs d'entrée et les lignes qu'il doit afficher. 8 au plus.",test:e=>`Test ${e}`,testInputs:e=>`Valeurs d'entrée du test ${e}, une par ligne`,testExpected:e=>`Sortie attendue du test ${e}, une ligne par ligne`,addTest:"Ajouter un test",removeTest:e=>`Supprimer le test ${e}`,fill:"Remplir la sortie attendue avec la solution",filled:"La sortie attendue est remplie avec la solution.",passes:"réussi",fails:"échoué",notChecked:"pas de solution pour vérifier",solutionPrinted:e=>`La solution affiche : ${e||"rien"}`,checks:"Vérification",errorsHeading:e=>1===e?"1 problème à corriger":`${e} problèmes à corriger`,warningsHeading:"Remarques",allGood:"Aucun problème trouvé.",problem:{noBlocks:()=>"Ajoute au moins un bloc que le candidat peut ajouter.",unclosed:e=>`Bloc ${e.block} : une { n'a pas de }.`,parts:e=>`Bloc ${e.block} : ce type de bloc demande ${e.detail} parties entre accolades (${e.roles}).`,fewChoices:e=>`Bloc ${e.block}, partie ${e.part} : une liste demande au moins deux choix.`,notName:e=>`Bloc ${e.block}, partie ${e.part} : « ${e.detail} » n'est pas un nom de variable.`,tooManyStart:e=>`Le programme de départ a plus de ${e.detail} blocs, le maximum pour un programme.`,tooManySolution:e=>`La solution a plus de ${e.detail} blocs, le maximum pour un programme.`,tooDeepStart:e=>`Le programme de départ emboîte des blocs sur plus de ${e.detail} niveaux.`,tooDeepSolution:e=>`La solution emboîte des blocs sur plus de ${e.detail} niveaux.`,noSolution:e=>"error"===e.level?"L'item compare le programme à la solution : construis-la dans Solution.":"Il n'y a pas encore de solution (Solution).",solutionBlank:e=>`La ligne ${e.line} de la solution a un trou vide.`,notAvailable:e=>`La solution utilise « ${e.detail} » (bloc ${e.block}) plus souvent que le candidat ne peut l'ajouter.`,solutionError:e=>`Avec l'entrée au départ, la solution s'arrête. ${e.message}`,testFails:e=>`Test ${e.test} : la solution n'affiche pas la sortie attendue.`,noTests:()=>"Le score par cas de test demande au moins un test.",semicolon:e=>`Test ${e.test} : une valeur ne peut pas contenir ;.`},newLabels:{set:"{x} ← {}",input:"lire {x}",print:"afficher {}",if:"si {}",ifelse:"si {}",while:"tant que {}",repeat:"répéter {} fois",for:"pour {i} de {1} à {}"}}},gn=e=>{var t;return null!==(t=bn[(null!=e?e:"").slice(0,2).toLowerCase()])&&void 0!==t?t:fn},vn="inline-flex min-h-9 items-center justify-center gap-1.5 rounded-lg border border-slate-300 bg-white px-3 text-sm font-medium text-slate-700 hover:bg-slate-50 focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-sky-600 disabled:cursor-not-allowed disabled:opacity-50",xn="cb-focus inline-flex size-9 shrink-0 items-center justify-center rounded-md text-white hover:bg-black/20 disabled:opacity-40",kn=(e,t)=>pt(e,null!=t?t:St(e,"x")),wn=({s:e,store:t,texts:n,readOnly:o,author:r})=>{var a,i,l;const s=function(e){const[t,n]=we(e.getState());return ye(()=>e.subscribe(n),[e]),t}(t),{program:c,run:d}=s,u=((e,t)=>{const n=[];let o=0;const r=(t,a,i,l,s)=>{t.length||null===a||n.push({type:"empty",key:`${a}:${i}:empty`,pos:{parent:a,branch:i,index:0},depth:l,arms:s}),t.forEach((t,c)=>{var d,u;const p=e.blocks[t.block];if(!p)return;const h={parent:a,branch:i,index:c};if(n.push({type:"line",key:t.id,node:t,block:p,number:++o,pos:h,depth:l,arms:s}),!ot(p.kind))return;const m=[...s,{category:Kt(p.kind),locked:!!t.locked}];r(null!==(d=t.body)&&void 0!==d?d:[],t.id,"body",l+1,m),"ifelse"===p.kind&&(n.push({type:"else",key:`${t.id}:else`,node:t,block:p,number:++o,depth:l,arms:s}),r(null!==(u=t.other)&&void 0!==u?u:[],t.id,"other",l+1,m)),n.push({type:"end",key:`${t.id}:end`,node:t,block:p,pos:h,depth:l,arms:s})})};return r(t,null,"body",0,[]),n})(e,c),p=wt(c),h=xt(c),[m,f]=we(null),[b,g]=we(""),[v,x]=we(null),[k,w]=we(!1),[y,_]=we(null),[$,N]=we(null),S=$e(null),j=$e(u);j.current=u;const O=$e(null),E=$e(!1),T=$e(null),L=m?vt(c,m):null,M=null!==(i=null===(a=null==d?void 0:d.error)||void 0===a?void 0:a.line)&&void 0!==i?i:0;_e(()=>{var e,t;if(!v)return;const n=null===(e=S.current)||void 0===e?void 0:e.getRootNode(),o=null==n?void 0:n.querySelector(`[data-handle="${v}"]`);null===(t=null!=o?o:T.current)||void 0===t||t.focus(),x(null)},[v,c]);const B=e=>g(e),C=(o,r,a=!0)=>{const i=t.getState().program;t.dispatch(o);const l=t.getState().program;if(l===i)return B("ADD"===o.type&&xt(i)>=e.maxBlocks?n.full(e.maxBlocks):n.cannotMove),!1;const s=((n,o=t.getState().program)=>ht(e,o).find(e=>e.node.id===n&&!e.isElse))(r,l);return s&&(B("ADD"===o.type?n.added(s.text,s.number):n.moved(s.text,s.number,s.depth)),f(r),a&&x(r)),!0},z=(e,n=(()=>{var e,t;return L?{parent:null!==(t=null===(e=L.parent)||void 0===e?void 0:e.id)&&void 0!==t?t:null,branch:L.branch,index:L.index+1}:{parent:null,branch:"body",index:c.length}})())=>C({type:"ADD",payload:{block:e,position:n}},`n${t.getState().next}`),I=o=>{var r,a,i,l,s;const c=ht(e,t.getState().program),d=c.findIndex(e=>e.node.id===o&&!e.isElse),u=null!==(a=null===(r=c[d])||void 0===r?void 0:r.text)&&void 0!==a?a:"";t.dispatch({type:"REMOVE",payload:{id:o}});const p=ht(e,t.getState().program).filter(e=>!e.isElse&&!e.node.locked);B(n.removed(u));const h=null!==(i=p.find(e=>e.number>=d+1))&&void 0!==i?i:p[p.length-1];f(null!==(l=null==h?void 0:h.node.id)&&void 0!==l?l:null),x(null!==(s=null==h?void 0:h.node.id)&&void 0!==s?s:"none")},D=e=>{if(null===e.parent)return 0;const t=j.current.find(t=>"line"===t.type&&t.node.id===e.parent);return t?t.depth+1:0},A=(e,t,n)=>{var o,r,a,i;const l=null===(o=S.current)||void 0===o?void 0:o.getRootNode(),s=null===(r=null==l?void 0:l.elementFromPoint)||void 0===r?void 0:r.call(l,e,t);if(!s)return null;if("id"in n&&s.closest("[data-palette]"))return{remove:!0};const d=s.closest("[data-row]");if(!d)return null;const u=d.dataset.row;if("tail"===u)return{pos:{parent:null,branch:"body",index:c.length},key:u,edge:"top",depth:0};if("head"===u)return{pos:{parent:null,branch:"body",index:0},key:u,edge:"bottom",depth:0};const p=j.current.find(e=>e.key===u);if(!p)return null;const h=d.getBoundingClientRect(),m=t<h.top+h.height/2?"top":"bottom";let f;if("empty"===p.type)f=p.pos;else if("end"===p.type){const e="ifelse"===p.block.kind?"other":"body";f="top"===m?{parent:p.node.id,branch:e,index:(null!==(a=p.node[e])&&void 0!==a?a:[]).length}:Object.assign(Object.assign({},p.pos),{index:p.pos.index+1})}else f="else"===p.type?"top"===m?{parent:p.node.id,branch:"body",index:(null!==(i=p.node.body)&&void 0!==i?i:[]).length}:{parent:p.node.id,branch:"other",index:0}:"top"===m?p.pos:ot(p.block.kind)?{parent:p.node.id,branch:"body",index:0}:Object.assign(Object.assign({},p.pos),{index:p.pos.index+1});return{pos:f,key:u,edge:"empty"===p.type?"top":m,depth:D(f)}},R=(e,t,n,r)=>{if(o||0!==e.button)return;O.current={source:t,x0:e.clientX,y0:e.clientY,active:!1,text:n,category:r};let a=null;const i=e=>{const t=O.current;t&&(!t.active&&Math.hypot(e.clientX-t.x0,e.clientY-t.y0)<6||(t.active=!0,e.preventDefault(),_({x:e.clientX,y:e.clientY,text:t.text,category:t.category}),a=A(e.clientX,e.clientY,t.source),N(a)))},l=e=>{var t;window.removeEventListener("pointermove",i),window.removeEventListener("pointerup",l),window.removeEventListener("pointercancel",l);const n=O.current;if(O.current=null,_(null),N(null),!(null==n?void 0:n.active)||"pointercancel"===e.type)return;E.current=!0,setTimeout(()=>E.current=!1,0);const o=null!==(t=A(e.clientX,e.clientY,n.source))&&void 0!==t?t:a;o&&("remove"in o?"id"in n.source&&I(n.source.id):"block"in n.source?z(n.source.block,o.pos):C({type:"MOVE",payload:{id:n.source.id,position:o.pos}},n.source.id,!1))};window.addEventListener("pointermove",i,{passive:!1}),window.addEventListener("pointerup",l),window.addEventListener("pointercancel",l)},H=y?Jt[y.category]:null,P=e=>$&&!("remove"in $)&&$.key===e&&y?V("span",{"aria-hidden":"true","data-testid":"drop-indicator",className:"cb-drop pointer-events-none absolute z-10 h-2.5 w-36 max-w-[60%] "+("top"===$.edge?"-top-1.5":"-bottom-1.5"),style:Object.assign(Object.assign({},Zt(y.category)),{left:`calc(1.75rem + ${$.depth} * var(--arm))`})}):null,U=e=>e.map((e,t)=>V("span",{"data-arm":!0,"aria-hidden":"true",className:"cb-arm "+(e.locked?"cb-locked":""),style:Zt(e.category)},t)),F=e=>V("span",{"aria-hidden":"true",className:"w-7 shrink-0 select-none pt-3 pr-1.5 text-right text-[11px] tabular-nums "+(e&&e===M?"font-bold text-red-700":"text-slate-400"),children:null!=e?e:""}),q=e=>{var a;const{node:i,block:l,number:s}=e,c=Kt(l.kind),d=m===i.id&&!o,u=s===M,p=kn(l,i),h=ot(l.kind);return V("div",{role:"listitem","data-row":e.key,"data-testid":`line-${s}`,className:"relative flex items-stretch",children:[F(s),U(e.arms),V("div",{className:"flex min-w-0 flex-1 items-start",children:V("div",{"data-piece":!0,"data-error":u||void 0,style:Zt(c),className:`cb-piece flex min-h-11 w-fit max-w-full flex-wrap items-center gap-1 py-1 pr-1.5 pl-1.5 ${h?"cb-c-top":""} ${i.locked?"cb-locked":""} ${d?"cb-selected":""} ${u?"cb-error":""}`,children:[o?V("span",{className:"w-1"}):i.locked?V("span",{className:"inline-flex size-9 shrink-0 items-center justify-center text-white",title:n.locked,children:V(dn,{})}):V("button",{type:"button","data-handle":i.id,"aria-label":n.handle(s,p),"aria-describedby":"cb-keys","aria-pressed":d,className:`${xn} cursor-grab touch-none text-white/90 active:cursor-grabbing`,onPointerDown:e=>R(e,{id:i.id},p,c),onClick:()=>!E.current&&f(d?null:i.id),onFocus:()=>f(i.id),onKeyDown:e=>((e,t)=>{const n={ArrowUp:()=>C({type:"MOVE_BY",payload:{id:t,delta:-1}},t),ArrowDown:()=>C({type:"MOVE_BY",payload:{id:t,delta:1}},t),ArrowRight:()=>C({type:"INDENT",payload:{id:t}},t),ArrowLeft:()=>C({type:"OUTDENT",payload:{id:t}},t),Delete:()=>I(t),Backspace:()=>I(t),Escape:()=>f(null)}[e.key];n&&(e.preventDefault(),n())})(e,i.id),children:V(cn,{})}),V(Qt,{block:l,node:i,number:s,texts:n,disabled:o,onValue:(e,n)=>t.dispatch({type:"SET_VALUE",payload:{id:i.id,slot:e,value:n}})}),i.locked&&V("span",{className:"sr-only",children:["(",n.locked,")"]}),null===(a=null==r?void 0:r.lineExtra)||void 0===a?void 0:a.call(r,i,s,p),d&&!i.locked&&V("span",{className:"ml-1 flex shrink-0 items-center rounded-lg bg-black/15",role:"group","aria-label":n.handle(s,p),"data-testid":"toolbar",children:[V("button",{type:"button",className:xn,"aria-label":n.moveUp,title:n.moveUp,onClick:()=>C({type:"MOVE_BY",payload:{id:i.id,delta:-1}},i.id,!1),children:V(tn,{d:nn})}),V("button",{type:"button",className:xn,"aria-label":n.moveDown,title:n.moveDown,onClick:()=>C({type:"MOVE_BY",payload:{id:i.id,delta:1}},i.id,!1),children:V(tn,{d:on})}),V("button",{type:"button",className:xn,"aria-label":n.outdent,title:n.outdent,onClick:()=>C({type:"OUTDENT",payload:{id:i.id}},i.id,!1),children:V(tn,{d:an})}),V("button",{type:"button",className:xn,"aria-label":n.indent,title:n.indent,onClick:()=>C({type:"INDENT",payload:{id:i.id}},i.id,!1),children:V(tn,{d:rn})}),V("button",{type:"button",className:xn,"aria-label":n.remove,title:n.remove,onClick:()=>I(i.id),children:V(tn,{d:ln})})]})]})}),P(e.key)]},e.key)},W=e.palette.map(t=>e.blocks[t]).filter(Boolean),Y=["variables","control","io"].map(e=>({category:e,blocks:W.filter(t=>Kt(t.kind)===e)})).filter(e=>e.blocks.length),J=h>=e.maxBlocks,K=$&&!("remove"in $)&&"tail"===$.key;return V("div",{ref:S,className:"cb-root @container flex max-w-full flex-col gap-4 font-sans text-slate-800",children:[!r&&e.prompt&&V("p",{className:"m-0 max-w-[70ch] text-[15px] leading-relaxed text-slate-700","data-testid":"prompt",children:e.prompt}),V("div",{className:"grid gap-4 "+(o?"":"@2xl:grid-cols-[minmax(13rem,17rem)_minmax(0,1fr)]"),children:[!o&&V("section",{"aria-labelledby":"cb-blocks","data-palette":!0,className:"cb-flyout flex flex-col gap-2 rounded-2xl border border-slate-200 p-3",children:[V("h3",{id:"cb-blocks",className:"m-0 text-xs font-semibold tracking-wide text-slate-600 uppercase",children:n.blocks}),V("p",{className:"m-0 text-xs text-slate-600",children:n.blocksHelp}),V("div",{className:"flex flex-col gap-3","data-testid":"palette",children:Y.map(({category:t,blocks:o})=>V("div",{role:"group","aria-labelledby":`cb-cat-${t}`,className:"flex flex-col gap-2",children:[V("h4",{id:`cb-cat-${t}`,className:"m-0 flex items-center gap-1.5 text-xs font-semibold text-slate-700",children:[V("span",{"aria-hidden":"true",className:"size-3 rounded-full",style:{backgroundColor:Jt[t].c}}),n.categories[t]]}),V("ul",{className:"m-0 flex list-none flex-col items-start gap-2.5 p-0",children:o.map(o=>{var r;const a=!e.reuse&&(null!==(r=p.get(o.id))&&void 0!==r?r:0)>0,i=kn(o);return V("li",{className:"relative flex max-w-full",children:[V("button",{type:"button",disabled:a||J,"aria-label":n.addBlock(i),"data-block":o.id,style:Zt(t),className:"cb-focus flex max-w-full cursor-grab touch-none rounded-[7px] bg-transparent p-0 pb-1 text-left disabled:cursor-not-allowed disabled:opacity-40",onPointerDown:e=>!a&&!J&&R(e,{block:o.id},i,t),onClick:()=>!E.current&&z(o.id),children:V(en,{block:o,texts:n})}),a&&V("span",{className:"pointer-events-none absolute -top-2 -right-2 z-10 rounded-full border border-slate-300 bg-white px-1.5 text-[11px] font-semibold text-slate-800",children:n.used})]},o.id)})})]},t))})]}),V("section",{"aria-labelledby":"cb-program",className:"flex min-w-0 flex-col gap-2",children:[V("div",{className:"flex flex-wrap items-baseline justify-between gap-2",children:[V("h3",{id:"cb-program",className:"m-0 text-xs font-semibold tracking-wide text-slate-600 uppercase",children:null!==(l=null==r?void 0:r.title)&&void 0!==l?l:n.program}),V("span",{className:"text-xs text-slate-600","data-testid":"count",children:n.count(h,e.maxBlocks)})]}),V("div",{ref:T,tabIndex:-1,"data-program":!0,className:"cb-canvas overflow-x-auto rounded-2xl border border-slate-200 py-3 pr-3 shadow-inner focus:outline-none",children:[V("div",{"data-row":"head","aria-hidden":"true",className:"relative flex items-stretch pb-0",children:[V("span",{className:"w-7 shrink-0"}),V("div",{className:"cb-piece cb-hat flex min-h-11 w-fit items-center gap-2 px-3 pb-1.5 text-[14px] font-semibold",style:Zt("events"),"data-testid":"hat",children:[V(tn,{d:sn,className:"size-4 fill-current"}),n.hat]}),$&&!("remove"in $)&&"head"===$.key&&P("head")]}),V("div",{role:"list","aria-labelledby":"cb-program","data-testid":"program",children:u.map(e=>"line"===e.type?q(e):"else"===e.type?(e=>V("div",{role:"listitem","data-row":e.key,"data-testid":`line-${e.number}`,className:"relative flex items-stretch",children:[F(e.number),U(e.arms),V("div",{className:"flex min-w-0 flex-1 items-start",children:V("div",{"data-piece":!0,className:"cb-piece cb-c-mid flex min-h-9 items-center py-1 pr-3 pl-[calc(var(--arm)+0.5rem)] "+(e.node.locked?"cb-locked":""),style:Zt(Kt(e.block.kind)),children:V("span",{"data-label":!0,className:"text-[14px] font-semibold text-white",children:e.block.elseLabel})})}),P(e.key)]},e.key))(e):"end"===e.type?(e=>V("div",{"data-row":e.key,"aria-hidden":"true",className:"relative flex items-stretch",children:[F(),U(e.arms),V("div",{className:"flex min-w-0 flex-1 items-start",children:V("div",{"data-end":!0,className:"cb-piece cb-c-end "+(e.node.locked?"cb-locked":""),style:Zt(Kt(e.block.kind))})}),P(e.key)]},e.key))(e):(e=>{const t=$&&!("remove"in $)&&$.key===e.key;return V("div",{"data-row":e.key,"aria-hidden":"true",className:"relative flex items-stretch",children:[F(),U(e.arms),V("div",{className:"flex min-w-0 flex-1 items-center pt-2.5 pb-1.5 pl-1",children:V("div",{className:"flex min-h-9 w-44 max-w-full items-center rounded-[7px] border-2 border-dashed px-2.5 text-xs "+(t?"border-slate-900 bg-white text-slate-900":"border-slate-300 bg-white/70 text-slate-600"),children:o?"":n.emptyBranch})})]},e.key)})(e))}),!o&&V("div",{"data-row":"tail",className:"relative ml-7 flex items-center rounded-lg text-sm "+(c.length?"min-h-10":"mt-2 min-h-20 justify-center border-2 border-dashed px-4 text-center "+(K?"border-slate-900 bg-white text-slate-900":"border-slate-300 bg-white/70 text-slate-600")),children:[!c.length&&n.emptyProgram,K&&c.length>0&&H&&V("span",{"aria-hidden":"true","data-testid":"drop-indicator",className:"cb-drop pointer-events-none absolute top-1 left-0 h-2.5 w-36",style:Zt(y.category)})]})]}),!o&&V("div",{className:"flex flex-wrap items-center justify-between gap-2",children:[V("p",{id:"cb-keys",className:"m-0 max-w-[60ch] text-xs text-slate-600",children:n.keyboardHelp}),r?null:k?V("span",{className:"flex flex-wrap items-center gap-2 text-sm",role:"group","aria-label":n.startOverSure,children:[V("span",{children:n.startOverSure}),V("button",{type:"button",className:vn,onClick:()=>{t.dispatch({type:"RESET",payload:{}}),w(!1),f(null),B(n.cleared)},children:n.yes}),V("button",{type:"button",className:vn,onClick:()=>w(!1),children:n.no})]}):V("button",{type:"button",className:vn,onClick:()=>w(!0),children:n.startOver})]})]})]}),!r&&V("div",{className:"grid gap-4 @xl:grid-cols-[minmax(10rem,16rem)_minmax(0,1fr)]",children:[V("div",{className:"flex flex-col gap-1",children:[V("label",{htmlFor:"cb-input",className:"text-xs font-semibold tracking-wide text-slate-600 uppercase",children:n.input}),V("textarea",{id:"cb-input",rows:4,"aria-describedby":"cb-input-help",value:s.inputs,readOnly:o||!e.editInputs,spellcheck:!1,placeholder:o||!e.editInputs?n.noInput:"",className:"min-h-24 resize-y rounded-xl border border-slate-300 bg-white p-2 font-mono text-sm text-slate-900 read-only:bg-slate-50 read-only:text-slate-600 focus:border-sky-500 focus:outline-2 focus:outline-sky-200",onInput:e=>t.dispatch({type:"SET_INPUTS",payload:{value:e.target.value}})}),V("p",{id:"cb-input-help",className:"m-0 text-xs text-slate-600",children:n.inputHelp})]}),V("div",{className:"flex min-w-0 flex-col gap-1",children:[V("div",{className:"flex items-center justify-between gap-2",children:[V("h3",{id:"cb-output",className:"m-0 text-xs font-semibold tracking-wide text-slate-600 uppercase",children:n.output}),!o&&V("button",{type:"button",className:"inline-flex min-h-10 items-center gap-1.5 rounded-full bg-emerald-700 px-5 text-sm font-bold text-white shadow-[inset_0_-2px_0_rgba(0,0,0,0.2)] hover:bg-emerald-800 focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-slate-900",onClick:()=>{t.dispatch({type:"RUN",payload:{}});const e=t.getState().run;e&&B(e.error?n.ranWithError(mn(n,e.error)):n.ran(e.output.length))},children:[V(tn,{d:sn,className:"size-4 fill-current"}),n.run]})]}),V("div",{role:"region","aria-labelledby":"cb-output","data-testid":"output",className:"max-h-72 min-h-24 overflow-auto rounded-2xl border border-slate-800 bg-slate-900 p-3 font-mono text-sm leading-6 text-slate-100 shadow-sm",children:[!d&&V("p",{className:"m-0 font-sans text-slate-400",children:n.notRun}),d&&d.output.map((e,t)=>V("div",{className:"whitespace-pre-wrap","data-testid":"output-line",children:e},t)),d&&!d.error&&!d.output.length&&V("p",{className:"m-0 font-sans text-slate-400",children:n.nothingPrinted}),d&&!d.error&&V("p",{className:"m-0 mt-1 font-sans text-xs text-emerald-300",children:n.finished}),(null==d?void 0:d.error)&&V("p",{className:"m-0 mt-1 font-sans text-red-300","data-testid":"error",children:["⚠ ",mn(n,d.error)]})]})]})]}),V("p",{role:"status",className:"sr-only",children:b}),y&&H&&V("div",{"aria-hidden":"true",className:"cb-piece cb-ghost pointer-events-none fixed z-50 flex items-center px-3 py-2 text-[14px] font-semibold text-white",style:Object.assign(Object.assign({},Zt(y.category)),{left:`${y.x+8}px`,top:`${y.y+8}px`}),children:y.text.split("___").join("▢")})]})};var yn='/*! tailwindcss v4.3.4 | MIT License | https://tailwindcss.com */\n@layer properties;\n@layer theme, base, components, utilities;\n@layer theme {\n :root, :host {\n --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",\n "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji",\n "Segoe UI Symbol", "Noto Color Emoji";\n --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",\n "Courier New", monospace;\n --color-red-50: oklch(97.1% 0.013 17.38);\n --color-red-100: oklch(93.6% 0.032 17.717);\n --color-red-200: oklch(88.5% 0.062 18.334);\n --color-red-300: oklch(80.8% 0.114 19.571);\n --color-red-700: oklch(50.5% 0.213 27.518);\n --color-red-800: oklch(44.4% 0.177 26.899);\n --color-amber-100: oklch(96.2% 0.059 95.617);\n --color-amber-800: oklch(47.3% 0.137 46.201);\n --color-amber-900: oklch(41.4% 0.112 45.904);\n --color-emerald-50: oklch(97.9% 0.021 166.113);\n --color-emerald-100: oklch(95% 0.052 163.051);\n --color-emerald-200: oklch(90.5% 0.093 164.15);\n --color-emerald-300: oklch(84.5% 0.143 164.978);\n --color-emerald-700: oklch(50.8% 0.118 165.612);\n --color-emerald-800: oklch(43.2% 0.095 166.913);\n --color-sky-200: oklch(90.1% 0.058 230.902);\n --color-sky-500: oklch(68.5% 0.169 237.323);\n --color-sky-600: oklch(58.8% 0.158 241.966);\n --color-slate-50: oklch(98.4% 0.003 247.858);\n --color-slate-100: oklch(96.8% 0.007 247.896);\n --color-slate-200: oklch(92.9% 0.013 255.508);\n --color-slate-300: oklch(86.9% 0.022 252.894);\n --color-slate-400: oklch(70.4% 0.04 256.788);\n --color-slate-500: oklch(55.4% 0.046 257.417);\n --color-slate-600: oklch(44.6% 0.043 257.281);\n --color-slate-700: oklch(37.2% 0.044 257.287);\n --color-slate-800: oklch(27.9% 0.041 260.031);\n --color-slate-900: oklch(20.8% 0.042 265.755);\n --color-black: #000;\n --color-white: #fff;\n --spacing: 0.25rem;\n --text-xs: 0.75rem;\n --text-xs--line-height: calc(1 / 0.75);\n --text-sm: 0.875rem;\n --text-sm--line-height: calc(1.25 / 0.875);\n --font-weight-medium: 500;\n --font-weight-semibold: 600;\n --font-weight-bold: 700;\n --tracking-wide: 0.025em;\n --leading-relaxed: 1.625;\n --radius-md: 0.375rem;\n --radius-lg: 0.5rem;\n --radius-xl: 0.75rem;\n --radius-2xl: 1rem;\n --default-font-family: var(--font-sans);\n --default-mono-font-family: var(--font-mono);\n }\n}\n@layer base {\n *, ::after, ::before, ::backdrop, ::file-selector-button {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n border: 0 solid;\n }\n html, :host {\n line-height: 1.5;\n -webkit-text-size-adjust: 100%;\n -moz-tab-size: 4;\n -o-tab-size: 4;\n tab-size: 4;\n font-family: var(--default-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");\n font-feature-settings: var(--default-font-feature-settings, normal);\n font-variation-settings: var(--default-font-variation-settings, normal);\n -webkit-tap-highlight-color: transparent;\n }\n hr {\n height: 0;\n color: inherit;\n border-top-width: 1px;\n }\n abbr:where([title]) {\n -webkit-text-decoration: underline dotted;\n text-decoration: underline dotted;\n }\n h1, h2, h3, h4, h5, h6 {\n font-size: inherit;\n font-weight: inherit;\n }\n a {\n color: inherit;\n -webkit-text-decoration: inherit;\n text-decoration: inherit;\n }\n b, strong {\n font-weight: bolder;\n }\n code, kbd, samp, pre {\n font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);\n font-feature-settings: var(--default-mono-font-feature-settings, normal);\n font-variation-settings: var(--default-mono-font-variation-settings, normal);\n font-size: 1em;\n }\n small {\n font-size: 80%;\n }\n sub, sup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n }\n sub {\n bottom: -0.25em;\n }\n sup {\n top: -0.5em;\n }\n table {\n text-indent: 0;\n border-color: inherit;\n border-collapse: collapse;\n }\n :-moz-focusring:where(:not(iframe)) {\n outline: auto;\n }\n progress {\n vertical-align: baseline;\n }\n summary {\n display: list-item;\n }\n ol, ul, menu {\n list-style: none;\n }\n img, svg, video, canvas, audio, iframe, embed, object {\n display: block;\n vertical-align: middle;\n }\n img, video {\n max-width: 100%;\n height: auto;\n }\n button, input, select, optgroup, textarea, ::file-selector-button {\n font: inherit;\n font-feature-settings: inherit;\n font-variation-settings: inherit;\n letter-spacing: inherit;\n color: inherit;\n border-radius: 0;\n background-color: transparent;\n opacity: 1;\n }\n :where(select:is([multiple], [size])) optgroup {\n font-weight: bolder;\n }\n :where(select:is([multiple], [size])) optgroup option {\n padding-inline-start: 20px;\n }\n ::file-selector-button {\n margin-inline-end: 4px;\n }\n ::-moz-placeholder {\n opacity: 1;\n }\n ::placeholder {\n opacity: 1;\n }\n @supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) {\n ::-moz-placeholder {\n color: currentcolor;\n @supports (color: color-mix(in lab, red, red)) {\n color: color-mix(in oklab, currentcolor 50%, transparent);\n }\n }\n ::placeholder {\n color: currentcolor;\n @supports (color: color-mix(in lab, red, red)) {\n color: color-mix(in oklab, currentcolor 50%, transparent);\n }\n }\n }\n textarea {\n resize: vertical;\n }\n ::-webkit-search-decoration {\n -webkit-appearance: none;\n }\n ::-webkit-date-and-time-value {\n min-height: 1lh;\n text-align: inherit;\n }\n ::-webkit-datetime-edit {\n display: inline-flex;\n }\n ::-webkit-datetime-edit-fields-wrapper {\n padding: 0;\n }\n ::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field {\n padding-block: 0;\n }\n ::-webkit-calendar-picker-indicator {\n line-height: 1;\n }\n :-moz-ui-invalid {\n box-shadow: none;\n }\n button, input:where([type="button"], [type="reset"], [type="submit"]), ::file-selector-button {\n -webkit-appearance: button;\n -moz-appearance: button;\n appearance: button;\n }\n ::-webkit-inner-spin-button, ::-webkit-outer-spin-button {\n height: auto;\n }\n [hidden]:where(:not([hidden="until-found"])) {\n display: none !important;\n }\n}\n@layer utilities {\n .\\@container {\n container-type: inline-size;\n }\n .pointer-events-none {\n pointer-events: none;\n }\n .visible {\n visibility: visible;\n }\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n border-width: 0;\n }\n .absolute {\n position: absolute;\n }\n .fixed {\n position: fixed;\n }\n .relative {\n position: relative;\n }\n .inset-y-0 {\n inset-block: 0px;\n }\n .-top-1\\.5 {\n top: calc(var(--spacing) * -1.5);\n }\n .-top-2 {\n top: calc(var(--spacing) * -2);\n }\n .top-1 {\n top: var(--spacing);\n }\n .top-1\\/2 {\n top: calc(1 / 2 * 100%);\n }\n .-right-2 {\n right: calc(var(--spacing) * -2);\n }\n .right-2\\.5 {\n right: calc(var(--spacing) * 2.5);\n }\n .-bottom-1\\.5 {\n bottom: calc(var(--spacing) * -1.5);\n }\n .left-0 {\n left: 0px;\n }\n .z-10 {\n z-index: 10;\n }\n .z-50 {\n z-index: 50;\n }\n .container {\n width: 100%;\n @media (width >= 40rem) {\n max-width: 40rem;\n }\n @media (width >= 48rem) {\n max-width: 48rem;\n }\n @media (width >= 64rem) {\n max-width: 64rem;\n }\n @media (width >= 80rem) {\n max-width: 80rem;\n }\n @media (width >= 96rem) {\n max-width: 96rem;\n }\n }\n .m-0 {\n margin: 0px;\n }\n .mt-1 {\n margin-top: var(--spacing);\n }\n .mt-2 {\n margin-top: calc(var(--spacing) * 2);\n }\n .-mb-px {\n margin-bottom: -1px;\n }\n .ml-1 {\n margin-left: var(--spacing);\n }\n .ml-7 {\n margin-left: calc(var(--spacing) * 7);\n }\n .ml-auto {\n margin-left: auto;\n }\n .block {\n display: block;\n }\n .flex {\n display: flex;\n }\n .grid {\n display: grid;\n }\n .inline {\n display: inline;\n }\n .inline-flex {\n display: inline-flex;\n }\n .size-3 {\n width: calc(var(--spacing) * 3);\n height: calc(var(--spacing) * 3);\n }\n .size-4 {\n width: calc(var(--spacing) * 4);\n height: calc(var(--spacing) * 4);\n }\n .size-9 {\n width: calc(var(--spacing) * 9);\n height: calc(var(--spacing) * 9);\n }\n .h-2\\.5 {\n height: calc(var(--spacing) * 2.5);\n }\n .h-7 {\n height: calc(var(--spacing) * 7);\n }\n .max-h-48 {\n max-height: calc(var(--spacing) * 48);\n }\n .max-h-72 {\n max-height: calc(var(--spacing) * 72);\n }\n .min-h-9 {\n min-height: calc(var(--spacing) * 9);\n }\n .min-h-10 {\n min-height: calc(var(--spacing) * 10);\n }\n .min-h-11 {\n min-height: calc(var(--spacing) * 11);\n }\n .min-h-16 {\n min-height: calc(var(--spacing) * 16);\n }\n .min-h-20 {\n min-height: calc(var(--spacing) * 20);\n }\n .min-h-24 {\n min-height: calc(var(--spacing) * 24);\n }\n .w-1 {\n width: var(--spacing);\n }\n .w-1\\.5 {\n width: calc(var(--spacing) * 1.5);\n }\n .w-7 {\n width: calc(var(--spacing) * 7);\n }\n .w-9 {\n width: calc(var(--spacing) * 9);\n }\n .w-11 {\n width: calc(var(--spacing) * 11);\n }\n .w-16 {\n width: calc(var(--spacing) * 16);\n }\n .w-32 {\n width: calc(var(--spacing) * 32);\n }\n .w-36 {\n width: calc(var(--spacing) * 36);\n }\n .w-44 {\n width: calc(var(--spacing) * 44);\n }\n .w-fit {\n width: -moz-fit-content;\n width: fit-content;\n }\n .max-w-\\[60\\%\\] {\n max-width: 60%;\n }\n .max-w-\\[60ch\\] {\n max-width: 60ch;\n }\n .max-w-\\[65ch\\] {\n max-width: 65ch;\n }\n .max-w-\\[70ch\\] {\n max-width: 70ch;\n }\n .max-w-\\[75ch\\] {\n max-width: 75ch;\n }\n .max-w-full {\n max-width: 100%;\n }\n .min-w-0 {\n min-width: 0px;\n }\n .min-w-\\[7rem\\] {\n min-width: 7rem;\n }\n .min-w-\\[8rem\\] {\n min-width: 8rem;\n }\n .min-w-\\[12rem\\] {\n min-width: 12rem;\n }\n .flex-1 {\n flex: 1;\n }\n .shrink-0 {\n flex-shrink: 0;\n }\n .-translate-y-1\\/2 {\n --tw-translate-y: calc(calc(1 / 2 * 100%) * -1);\n translate: var(--tw-translate-x) var(--tw-translate-y);\n }\n .cursor-grab {\n cursor: grab;\n }\n .cursor-pointer {\n cursor: pointer;\n }\n .touch-none {\n touch-action: none;\n }\n .resize-y {\n resize: vertical;\n }\n .list-disc {\n list-style-type: disc;\n }\n .list-none {\n list-style-type: none;\n }\n .appearance-none {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n }\n .flex-col {\n flex-direction: column;\n }\n .flex-wrap {\n flex-wrap: wrap;\n }\n .items-baseline {\n align-items: baseline;\n }\n .items-center {\n align-items: center;\n }\n .items-end {\n align-items: flex-end;\n }\n .items-start {\n align-items: flex-start;\n }\n .items-stretch {\n align-items: stretch;\n }\n .justify-between {\n justify-content: space-between;\n }\n .justify-center {\n justify-content: center;\n }\n .justify-end {\n justify-content: flex-end;\n }\n .gap-0\\.5 {\n gap: calc(var(--spacing) * 0.5);\n }\n .gap-1 {\n gap: var(--spacing);\n }\n .gap-1\\.5 {\n gap: calc(var(--spacing) * 1.5);\n }\n .gap-2 {\n gap: calc(var(--spacing) * 2);\n }\n .gap-2\\.5 {\n gap: calc(var(--spacing) * 2.5);\n }\n .gap-3 {\n gap: calc(var(--spacing) * 3);\n }\n .gap-4 {\n gap: calc(var(--spacing) * 4);\n }\n .gap-x-1\\.5 {\n -moz-column-gap: calc(var(--spacing) * 1.5);\n column-gap: calc(var(--spacing) * 1.5);\n }\n .gap-y-1 {\n row-gap: var(--spacing);\n }\n .overflow-auto {\n overflow: auto;\n }\n .overflow-hidden {\n overflow: hidden;\n }\n .overflow-x-auto {\n overflow-x: auto;\n }\n .rounded {\n border-radius: 0.25rem;\n }\n .rounded-2xl {\n border-radius: var(--radius-2xl);\n }\n .rounded-\\[7px\\] {\n border-radius: 7px;\n }\n .rounded-full {\n border-radius: calc(infinity * 1px);\n }\n .rounded-lg {\n border-radius: var(--radius-lg);\n }\n .rounded-md {\n border-radius: var(--radius-md);\n }\n .rounded-xl {\n border-radius: var(--radius-xl);\n }\n .rounded-t-lg {\n border-top-left-radius: var(--radius-lg);\n border-top-right-radius: var(--radius-lg);\n }\n .border {\n border-style: var(--tw-border-style);\n border-width: 1px;\n }\n .border-0 {\n border-style: var(--tw-border-style);\n border-width: 0px;\n }\n .border-2 {\n border-style: var(--tw-border-style);\n border-width: 2px;\n }\n .border-b {\n border-bottom-style: var(--tw-border-style);\n border-bottom-width: 1px;\n }\n .border-dashed {\n --tw-border-style: dashed;\n border-style: dashed;\n }\n .border-black\\/20 {\n border-color: color-mix(in srgb, #000 20%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n border-color: color-mix(in oklab, var(--color-black) 20%, transparent);\n }\n }\n .border-black\\/25 {\n border-color: color-mix(in srgb, #000 25%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n border-color: color-mix(in oklab, var(--color-black) 25%, transparent);\n }\n }\n .border-emerald-200 {\n border-color: var(--color-emerald-200);\n }\n .border-red-200 {\n border-color: var(--color-red-200);\n }\n .border-slate-200 {\n border-color: var(--color-slate-200);\n }\n .border-slate-300 {\n border-color: var(--color-slate-300);\n }\n .border-slate-800 {\n border-color: var(--color-slate-800);\n }\n .border-slate-900 {\n border-color: var(--color-slate-900);\n }\n .border-transparent {\n border-color: transparent;\n }\n .border-b-white {\n border-bottom-color: var(--color-white);\n }\n .bg-\\[var\\(--dark\\)\\] {\n background-color: var(--dark);\n }\n .bg-amber-100 {\n background-color: var(--color-amber-100);\n }\n .bg-black\\/15 {\n background-color: color-mix(in srgb, #000 15%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--color-black) 15%, transparent);\n }\n }\n .bg-black\\/20 {\n background-color: color-mix(in srgb, #000 20%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--color-black) 20%, transparent);\n }\n }\n .bg-emerald-50 {\n background-color: var(--color-emerald-50);\n }\n .bg-emerald-100 {\n background-color: var(--color-emerald-100);\n }\n .bg-emerald-700 {\n background-color: var(--color-emerald-700);\n }\n .bg-red-50 {\n background-color: var(--color-red-50);\n }\n .bg-red-100 {\n background-color: var(--color-red-100);\n }\n .bg-slate-200 {\n background-color: var(--color-slate-200);\n }\n .bg-slate-800 {\n background-color: var(--color-slate-800);\n }\n .bg-slate-900 {\n background-color: var(--color-slate-900);\n }\n .bg-transparent {\n background-color: transparent;\n }\n .bg-white {\n background-color: var(--color-white);\n }\n .bg-white\\/70 {\n background-color: color-mix(in srgb, #fff 70%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--color-white) 70%, transparent);\n }\n }\n .fill-current {\n fill: currentcolor;\n }\n .p-0 {\n padding: 0px;\n }\n .p-1 {\n padding: var(--spacing);\n }\n .p-2 {\n padding: calc(var(--spacing) * 2);\n }\n .p-3 {\n padding: calc(var(--spacing) * 3);\n }\n .px-1\\.5 {\n padding-inline: calc(var(--spacing) * 1.5);\n }\n .px-2 {\n padding-inline: calc(var(--spacing) * 2);\n }\n .px-2\\.5 {\n padding-inline: calc(var(--spacing) * 2.5);\n }\n .px-3 {\n padding-inline: calc(var(--spacing) * 3);\n }\n .px-4 {\n padding-inline: calc(var(--spacing) * 4);\n }\n .px-5 {\n padding-inline: calc(var(--spacing) * 5);\n }\n .py-0\\.5 {\n padding-block: calc(var(--spacing) * 0.5);\n }\n .py-1 {\n padding-block: var(--spacing);\n }\n .py-1\\.5 {\n padding-block: calc(var(--spacing) * 1.5);\n }\n .py-2 {\n padding-block: calc(var(--spacing) * 2);\n }\n .py-3 {\n padding-block: calc(var(--spacing) * 3);\n }\n .pt-1\\.5 {\n padding-top: calc(var(--spacing) * 1.5);\n }\n .pt-2 {\n padding-top: calc(var(--spacing) * 2);\n }\n .pt-2\\.5 {\n padding-top: calc(var(--spacing) * 2.5);\n }\n .pt-3 {\n padding-top: calc(var(--spacing) * 3);\n }\n .pr-1\\.5 {\n padding-right: calc(var(--spacing) * 1.5);\n }\n .pr-2 {\n padding-right: calc(var(--spacing) * 2);\n }\n .pr-3 {\n padding-right: calc(var(--spacing) * 3);\n }\n .pr-7 {\n padding-right: calc(var(--spacing) * 7);\n }\n .pb-0 {\n padding-bottom: 0px;\n }\n .pb-1 {\n padding-bottom: var(--spacing);\n }\n .pb-1\\.5 {\n padding-bottom: calc(var(--spacing) * 1.5);\n }\n .pl-1 {\n padding-left: var(--spacing);\n }\n .pl-1\\.5 {\n padding-left: calc(var(--spacing) * 1.5);\n }\n .pl-3 {\n padding-left: calc(var(--spacing) * 3);\n }\n .pl-4 {\n padding-left: calc(var(--spacing) * 4);\n }\n .pl-5 {\n padding-left: calc(var(--spacing) * 5);\n }\n .pl-\\[calc\\(var\\(--arm\\)\\+0\\.5rem\\)\\] {\n padding-left: calc(var(--arm) + 0.5rem);\n }\n .text-center {\n text-align: center;\n }\n .text-left {\n text-align: left;\n }\n .text-right {\n text-align: right;\n }\n .font-mono {\n font-family: var(--font-mono);\n }\n .font-sans {\n font-family: var(--font-sans);\n }\n .text-sm {\n font-size: var(--text-sm);\n line-height: var(--tw-leading, var(--text-sm--line-height));\n }\n .text-xs {\n font-size: var(--text-xs);\n line-height: var(--tw-leading, var(--text-xs--line-height));\n }\n .text-\\[11px\\] {\n font-size: 11px;\n }\n .text-\\[13px\\] {\n font-size: 13px;\n }\n .text-\\[14px\\] {\n font-size: 14px;\n }\n .text-\\[15px\\] {\n font-size: 15px;\n }\n .leading-6 {\n --tw-leading: calc(var(--spacing) * 6);\n line-height: calc(var(--spacing) * 6);\n }\n .leading-7 {\n --tw-leading: calc(var(--spacing) * 7);\n line-height: calc(var(--spacing) * 7);\n }\n .leading-relaxed {\n --tw-leading: var(--leading-relaxed);\n line-height: var(--leading-relaxed);\n }\n .font-bold {\n --tw-font-weight: var(--font-weight-bold);\n font-weight: var(--font-weight-bold);\n }\n .font-medium {\n --tw-font-weight: var(--font-weight-medium);\n font-weight: var(--font-weight-medium);\n }\n .font-semibold {\n --tw-font-weight: var(--font-weight-semibold);\n font-weight: var(--font-weight-semibold);\n }\n .tracking-wide {\n --tw-tracking: var(--tracking-wide);\n letter-spacing: var(--tracking-wide);\n }\n .whitespace-pre-wrap {\n white-space: pre-wrap;\n }\n .text-amber-800 {\n color: var(--color-amber-800);\n }\n .text-amber-900 {\n color: var(--color-amber-900);\n }\n .text-emerald-300 {\n color: var(--color-emerald-300);\n }\n .text-emerald-800 {\n color: var(--color-emerald-800);\n }\n .text-red-300 {\n color: var(--color-red-300);\n }\n .text-red-700 {\n color: var(--color-red-700);\n }\n .text-red-800 {\n color: var(--color-red-800);\n }\n .text-slate-100 {\n color: var(--color-slate-100);\n }\n .text-slate-400 {\n color: var(--color-slate-400);\n }\n .text-slate-500 {\n color: var(--color-slate-500);\n }\n .text-slate-600 {\n color: var(--color-slate-600);\n }\n .text-slate-700 {\n color: var(--color-slate-700);\n }\n .text-slate-800 {\n color: var(--color-slate-800);\n }\n .text-slate-900 {\n color: var(--color-slate-900);\n }\n .text-white {\n color: var(--color-white);\n }\n .text-white\\/90 {\n color: color-mix(in srgb, #fff 90%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n color: color-mix(in oklab, var(--color-white) 90%, transparent);\n }\n }\n .uppercase {\n text-transform: uppercase;\n }\n .tabular-nums {\n --tw-numeric-spacing: tabular-nums;\n font-variant-numeric: var(--tw-ordinal, ) var(--tw-slashed-zero, ) var(--tw-numeric-figure, ) var(--tw-numeric-spacing, ) var(--tw-numeric-fraction, );\n }\n .accent-sky-600 {\n accent-color: var(--color-sky-600);\n }\n .accent-slate-800 {\n accent-color: var(--color-slate-800);\n }\n .shadow {\n --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n }\n .shadow-\\[inset_0_-2px_0_rgba\\(0\\,0\\,0\\,0\\.2\\)\\] {\n --tw-shadow: inset 0 -2px 0 var(--tw-shadow-color, rgba(0,0,0,0.2));\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n }\n .shadow-\\[inset_0_1px_2px_rgba\\(15\\,23\\,42\\,0\\.25\\)\\] {\n --tw-shadow: inset 0 1px 2px var(--tw-shadow-color, rgba(15,23,42,0.25));\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n }\n .shadow-inner {\n --tw-shadow: inset 0 2px 4px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.05));\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n }\n .shadow-sm {\n --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n }\n .ring {\n --tw-ring-shadow: var(--tw-ring-inset, ) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n }\n .select-none {\n -webkit-user-select: none;\n -moz-user-select: none;\n user-select: none;\n }\n .read-only\\:bg-slate-50:-moz-read-only {\n background-color: var(--color-slate-50);\n }\n .read-only\\:bg-slate-50:read-only {\n background-color: var(--color-slate-50);\n }\n .read-only\\:text-slate-600:-moz-read-only {\n color: var(--color-slate-600);\n }\n .read-only\\:text-slate-600:read-only {\n color: var(--color-slate-600);\n }\n @media (hover: hover) {\n .hover\\:border-slate-200:hover {\n border-color: var(--color-slate-200);\n }\n .hover\\:bg-black\\/20:hover {\n background-color: color-mix(in srgb, #000 20%, transparent);\n }\n @supports (color: color-mix(in lab, red, red)) {\n .hover\\:bg-black\\/20:hover {\n background-color: color-mix(in oklab, var(--color-black) 20%, transparent);\n }\n }\n .hover\\:bg-emerald-800:hover {\n background-color: var(--color-emerald-800);\n }\n .hover\\:bg-slate-50:hover {\n background-color: var(--color-slate-50);\n }\n .hover\\:bg-white:hover {\n background-color: var(--color-white);\n }\n .hover\\:text-red-700:hover {\n color: var(--color-red-700);\n }\n .hover\\:text-slate-800:hover {\n color: var(--color-slate-800);\n }\n }\n .focus\\:border-sky-500:focus {\n border-color: var(--color-sky-500);\n }\n .focus\\:outline-2:focus {\n outline-style: var(--tw-outline-style);\n outline-width: 2px;\n }\n .focus\\:outline-3:focus {\n outline-style: var(--tw-outline-style);\n outline-width: 3px;\n }\n .focus\\:outline-offset-1:focus {\n outline-offset: 1px;\n }\n .focus\\:outline-sky-200:focus {\n outline-color: var(--color-sky-200);\n }\n .focus\\:outline-slate-900:focus {\n outline-color: var(--color-slate-900);\n }\n .focus\\:outline-none:focus {\n --tw-outline-style: none;\n outline-style: none;\n }\n .focus-visible\\:outline-2:focus-visible {\n outline-style: var(--tw-outline-style);\n outline-width: 2px;\n }\n .focus-visible\\:outline-3:focus-visible {\n outline-style: var(--tw-outline-style);\n outline-width: 3px;\n }\n .focus-visible\\:outline-offset-1:focus-visible {\n outline-offset: 1px;\n }\n .focus-visible\\:outline-offset-2:focus-visible {\n outline-offset: 2px;\n }\n .focus-visible\\:outline-sky-600:focus-visible {\n outline-color: var(--color-sky-600);\n }\n .focus-visible\\:outline-slate-900:focus-visible {\n outline-color: var(--color-slate-900);\n }\n .active\\:cursor-grabbing:active {\n cursor: grabbing;\n }\n .disabled\\:cursor-default:disabled {\n cursor: default;\n }\n .disabled\\:cursor-not-allowed:disabled {\n cursor: not-allowed;\n }\n .disabled\\:text-slate-900:disabled {\n color: var(--color-slate-900);\n }\n .disabled\\:opacity-40:disabled {\n opacity: 40%;\n }\n .disabled\\:opacity-50:disabled {\n opacity: 50%;\n }\n .disabled\\:opacity-100:disabled {\n opacity: 100%;\n }\n @container (width >= 36rem) {\n .\\@xl\\:grid-cols-\\[minmax\\(10rem\\,16rem\\)_minmax\\(0\\,1fr\\)\\] {\n grid-template-columns: minmax(10rem,16rem) minmax(0,1fr);\n }\n }\n @container (width >= 42rem) {\n .\\@2xl\\:grid-cols-\\[minmax\\(13rem\\,17rem\\)_minmax\\(0\\,1fr\\)\\] {\n grid-template-columns: minmax(13rem,17rem) minmax(0,1fr);\n }\n }\n}\n:host {\n display: block;\n}\n.cb-root {\n --arm: 1rem;\n --canvas: #ffffff;\n}\n.cb-canvas {\n --canvas: #f6f8fb;\n background-color: var(--canvas);\n background-image: radial-gradient(circle, #cfd8e3 1px, transparent 1.3px);\n background-size: 18px 18px;\n}\n.cb-flyout {\n --canvas: #eef2f7;\n background-color: var(--canvas);\n}\n.cb-piece {\n position: relative;\n color: #fff;\n border-radius: 7px;\n background-color: var(--c);\n background-image: var(--stripes, linear-gradient(transparent, transparent)), linear-gradient(to top, rgb(0 0 0 / 0.2) 2px, transparent 2px);\n background-repeat: no-repeat;\n background-size: 100% 100%, var(--edge, 100%) 100%;\n background-position: 0 0, right bottom;\n}\n.cb-piece::before {\n content: "";\n position: absolute;\n top: 0;\n left: 0.75rem;\n width: 1.25rem;\n height: 0.3rem;\n background-color: var(--canvas);\n border-radius: 0 0 0.4rem 0.4rem;\n z-index: 1;\n}\n.cb-piece::after {\n content: "";\n position: absolute;\n bottom: -0.3rem;\n left: var(--tab, 0.75rem);\n width: 1.25rem;\n height: 0.3rem;\n background-color: var(--c);\n background-image: var(--stripes, none);\n border-radius: 0 0 0.4rem 0.4rem;\n box-shadow: inset 0 -2px 0 rgb(0 0 0 / 0.2);\n z-index: 2;\n}\n.cb-hat {\n border-radius: 1.6rem 1.6rem 7px 7px / 1rem 1rem 7px 7px;\n padding-top: 0.7rem;\n}\n.cb-hat::before {\n display: none;\n}\n.cb-c-top {\n border-bottom-left-radius: 0;\n --edge: calc(100% - var(--arm));\n --tab: calc(var(--arm) + 0.75rem);\n}\n.cb-c-mid {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n min-width: calc(var(--arm) + 6rem);\n --edge: calc(100% - var(--arm));\n --tab: calc(var(--arm) + 0.75rem);\n}\n.cb-c-mid::before {\n display: none;\n}\n.cb-c-end {\n border-top-left-radius: 0;\n width: calc(var(--arm) + 6rem);\n max-width: 100%;\n min-height: 1.5rem;\n}\n.cb-c-end::before {\n display: none;\n}\n.cb-arm {\n width: var(--arm);\n flex-shrink: 0;\n margin-block: -1px;\n background-image: var(--stripes, linear-gradient(transparent, transparent)), linear-gradient(to right, var(--c) calc(100% - 3px), transparent calc(100% - 3px));\n background-size: calc(100% - 3px) 100%, 100% 100%;\n background-repeat: no-repeat;\n}\n.cb-mouth {\n margin-block: 0;\n height: 0.9rem;\n}\n.cb-locked {\n --stripes: repeating-linear-gradient(135deg, rgb(0 0 0 / 0.16) 0 6px, transparent 6px 12px);\n}\n.cb-selected {\n box-shadow: inset 0 0 0 3px #111827, inset 0 0 0 5px #fff;\n}\n.cb-error {\n box-shadow: inset 0 0 0 3px #dc2626, inset 0 0 0 5px #fff;\n}\n.cb-focus:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px #fff, 0 0 0 5px #111827;\n}\n.cb-ghost {\n box-shadow: 0 12px 24px rgb(15 23 42 / 0.35);\n transform: rotate(-2deg) scale(1.03);\n}\n.cb-drop {\n background-color: var(--c);\n opacity: 0.5;\n border-radius: 7px;\n box-shadow: 0 0 0 2px #fff, 0 0 0 4px #111827;\n}\n@media (prefers-reduced-motion: no-preference) {\n .cb-piece {\n transition: box-shadow 0.12s ease;\n }\n}\n@media (prefers-reduced-motion: reduce) {\n .cb-ghost {\n transform: none;\n }\n * {\n transition: none !important;\n animation: none !important;\n }\n}\n@property --tw-translate-x {\n syntax: "*";\n inherits: false;\n initial-value: 0;\n}\n@property --tw-translate-y {\n syntax: "*";\n inherits: false;\n initial-value: 0;\n}\n@property --tw-translate-z {\n syntax: "*";\n inherits: false;\n initial-value: 0;\n}\n@property --tw-border-style {\n syntax: "*";\n inherits: false;\n initial-value: solid;\n}\n@property --tw-leading {\n syntax: "*";\n inherits: false;\n}\n@property --tw-font-weight {\n syntax: "*";\n inherits: false;\n}\n@property --tw-tracking {\n syntax: "*";\n inherits: false;\n}\n@property --tw-ordinal {\n syntax: "*";\n inherits: false;\n}\n@property --tw-slashed-zero {\n syntax: "*";\n inherits: false;\n}\n@property --tw-numeric-figure {\n syntax: "*";\n inherits: false;\n}\n@property --tw-numeric-spacing {\n syntax: "*";\n inherits: false;\n}\n@property --tw-numeric-fraction {\n syntax: "*";\n inherits: false;\n}\n@property --tw-shadow {\n syntax: "*";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-shadow-color {\n syntax: "*";\n inherits: false;\n}\n@property --tw-shadow-alpha {\n syntax: "<percentage>";\n inherits: false;\n initial-value: 100%;\n}\n@property --tw-inset-shadow {\n syntax: "*";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-inset-shadow-color {\n syntax: "*";\n inherits: false;\n}\n@property --tw-inset-shadow-alpha {\n syntax: "<percentage>";\n inherits: false;\n initial-value: 100%;\n}\n@property --tw-ring-color {\n syntax: "*";\n inherits: false;\n}\n@property --tw-ring-shadow {\n syntax: "*";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-inset-ring-color {\n syntax: "*";\n inherits: false;\n}\n@property --tw-inset-ring-shadow {\n syntax: "*";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-ring-inset {\n syntax: "*";\n inherits: false;\n}\n@property --tw-ring-offset-width {\n syntax: "<length>";\n inherits: false;\n initial-value: 0px;\n}\n@property --tw-ring-offset-color {\n syntax: "*";\n inherits: false;\n initial-value: #fff;\n}\n@property --tw-ring-offset-shadow {\n syntax: "*";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-outline-style {\n syntax: "*";\n inherits: false;\n initial-value: solid;\n}\n@layer properties {\n @supports ((-webkit-hyphens: none) and (not (margin-trim: block))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {\n *, ::before, ::after, ::backdrop {\n --tw-translate-x: 0;\n --tw-translate-y: 0;\n --tw-translate-z: 0;\n --tw-border-style: solid;\n --tw-leading: initial;\n --tw-font-weight: initial;\n --tw-tracking: initial;\n --tw-ordinal: initial;\n --tw-slashed-zero: initial;\n --tw-numeric-figure: initial;\n --tw-numeric-spacing: initial;\n --tw-numeric-fraction: initial;\n --tw-shadow: 0 0 #0000;\n --tw-shadow-color: initial;\n --tw-shadow-alpha: 100%;\n --tw-inset-shadow: 0 0 #0000;\n --tw-inset-shadow-color: initial;\n --tw-inset-shadow-alpha: 100%;\n --tw-ring-color: initial;\n --tw-ring-shadow: 0 0 #0000;\n --tw-inset-ring-color: initial;\n --tw-inset-ring-shadow: 0 0 #0000;\n --tw-ring-inset: initial;\n --tw-ring-offset-width: 0px;\n --tw-ring-offset-color: #fff;\n --tw-ring-offset-shadow: 0 0 #0000;\n --tw-outline-style: solid;\n }\n }\n}\n@layer properties {\n :host, *, ::before, ::after, ::backdrop {\n --tw-translate-x: 0;\n --tw-translate-y: 0;\n --tw-translate-z: 0;\n --tw-border-style: solid;\n --tw-leading: initial;\n --tw-font-weight: initial;\n --tw-tracking: initial;\n --tw-ordinal: initial;\n --tw-slashed-zero: initial;\n --tw-numeric-figure: initial;\n --tw-numeric-spacing: initial;\n --tw-numeric-fraction: initial;\n --tw-shadow: 0 0 #0000;\n --tw-shadow-color: initial;\n --tw-shadow-alpha: 100%;\n --tw-inset-shadow: 0 0 #0000;\n --tw-inset-shadow-color: initial;\n --tw-inset-shadow-alpha: 100%;\n --tw-ring-color: initial;\n --tw-ring-shadow: 0 0 #0000;\n --tw-inset-ring-color: initial;\n --tw-inset-ring-shadow: 0 0 #0000;\n --tw-ring-inset: initial;\n --tw-ring-offset-width: 0px;\n --tw-ring-offset-color: #fff;\n --tw-ring-offset-shadow: 0 0 #0000;\n --tw-outline-style: solid;\n }\n}\n';const _n=(e,t,n={})=>t?Object.assign(Object.assign(Object.assign({},e),n),{program:t,run:null}):e,$n=(e,t)=>{const n=new Ce(e);return n.addReducer("ADD",(e,{block:n,position:o})=>_n(e,((e,t,n,o,r)=>{const a=e.blocks[n];if(!a||!a.palette)return null;if(xt(t)>=e.maxBlocks)return null;if(!e.reuse&&wt(t).get(n))return null;const i=St(a,r);return _t(e,t,i,o)?$t(t,o,i):null})(t(),e.program,n,o,`n${e.next}`),{next:e.next+1})),n.addReducer("MOVE",(e,{id:n,position:o})=>_n(e,jt(t(),e.program,n,o))),n.addReducer("MOVE_BY",(e,{id:n,delta:o})=>_n(e,Ot(t(),e.program,n,o))),n.addReducer("INDENT",(e,{id:n})=>_n(e,((e,t,n)=>{var o,r;const a=vt(t,n);if(!a||a.node.locked||0===a.index)return null;const i=a.list[a.index-1],l=null===(o=e.blocks[i.block])||void 0===o?void 0:o.kind;if(!l||!ot(l))return null;const s="ifelse"===l?"other":"body";return jt(e,t,n,{parent:i.id,branch:s,index:(null!==(r=i[s])&&void 0!==r?r:[]).length})})(t(),e.program,n))),n.addReducer("OUTDENT",(e,{id:n})=>_n(e,((e,t,n)=>{var o,r;const a=vt(t,n);if(!a||a.node.locked||!a.parent)return null;const i=vt(t,a.parent.id);return jt(e,t,n,{parent:null!==(r=null===(o=i.parent)||void 0===o?void 0:o.id)&&void 0!==r?r:null,branch:i.branch,index:i.index+1})})(t(),e.program,n))),n.addReducer("REMOVE",(e,{id:t})=>_n(e,Nt(e.program,t))),n.addReducer("SET_VALUE",(e,{id:t,slot:n,value:o})=>_n(e,((e,t,n,o)=>{const r=e=>e.map(e=>{if(e.id===t){const t=[...e.values];return t[n]=o,Object.assign(Object.assign({},e),{values:t})}const a=Object.assign({},e);return e.body&&(a.body=r(e.body)),e.other&&(a.other=r(e.other)),a});return r(e)})(e.program,t,n,String(o).slice(0,200)))),n.addReducer("SET_INPUTS",(e,{value:t})=>Object.assign(Object.assign({},e),{inputs:String(t).slice(0,2e3),run:null})),n.addReducer("RUN",e=>Object.assign(Object.assign({},e),{run:Object.assign({inputs:e.inputs},gt(t(),e.program,e.inputs))})),n.addReducer("RESET",()=>e),n.addReducer("RESTORE",(e,t)=>t),n},Nn=["blocks","program","solution","inputs","tests"],Sn=(e,t,n)=>e.map(e=>{const o="n"+ ++t.n;null==n||n.set(e.id,o);const r={id:o,block:e.block,values:[...e.values]};return e.body&&(r.body=Sn(e.body,t,n)),e.other&&(r.other=Sn(e.other,t,n)),r}),jn=(e,t)=>{const n=[],o=e=>e.forEach(e=>{var r,a;e.locked&&n.push(t.get(e.id)),o(null!==(r=e.body)&&void 0!==r?r:[]),o(null!==(a=e.other)&&void 0!==a?a:[])});return o(e),n},On=e=>`${e.kind}: ${e.label}${"ifelse"===e.kind&&e.elseLabel.trim()?` | ${e.elseLabel.trim()}`:""}`,En=(e,t)=>{var n;const o=it(On(e),ct[t]);if("string"!=typeof o)return Object.assign(Object.assign({},o),{id:e.key,palette:e.palette});const r=null!==(n=rt(e.label.trim()))&&void 0!==n?n:{parts:[e.label],slots:[]};return Object.assign(Object.assign(Object.assign({kind:e.kind},r),"ifelse"===e.kind?{elseLabel:e.elseLabel.trim()||ct[t]}:{}),{id:e.key,palette:e.palette})},Tn=(e,t)=>{const n={};for(const t of e.blocks)n[t.key]=En(t,e.language);const o=new Set(e.locked),r=e=>e.map(e=>Object.assign(Object.assign(Object.assign(Object.assign({},e),o.has(e.id)?{locked:!0}:{}),e.body?{body:r(e.body)}:{}),e.other?{other:r(e.other)}:{}));return Object.assign(Object.assign({},t),{language:e.language,blocks:n,palette:e.blocks.filter(e=>e.palette).map(e=>e.key),start:r(e.start),solution:e.solution.length?e.solution:null,inputs:e.inputs,tests:e.tests.map(e=>({inputs:e.inputs,expected:e.expected,source:Cn(e)}))})},Ln=(e,t)=>t.flatMap(t=>{var n,o,r,a,i;const l=e[t.block],s=[...Ln(e,null!==(n=t.body)&&void 0!==n?n:[]),...Ln(e,null!==(o=t.other)&&void 0!==o?o:[])];if(!l)return s;const c={id:t.id,block:t.block,values:l.slots.map((e,n)=>{var o;return null!==(o=t.values[n])&&void 0!==o?o:""})};return ot(l.kind)?(c.body=Ln(e,null!==(r=t.body)&&void 0!==r?r:[]),"ifelse"===l.kind?c.other=Ln(e,null!==(a=t.other)&&void 0!==a?a:[]):c.body.push(...Ln(e,null!==(i=t.other)&&void 0!==i?i:[])),[c]):[c,...s]}),Mn=(e,t,n)=>{const o=e.parts.map(n=>{var o;if("string"==typeof n)return n;const r=e.slots[n.slot],a=(null!==(o=t.values[n.slot])&&void 0!==o?o:"").trim();return"fixed"===r.type?`{${r.text}}`:a?`{${a}}`:"choice"===r.type?`{${r.options.join("|")}}`:"{}"}).join(""),r="ifelse"===e.kind&&e.elseLabel&&e.elseLabel!==ct[n]?` | ${e.elseLabel}`:"";return`${e.kind}: ${o}${r}`},Bn=(e,t,n,o)=>{const r=[],a=(e,t)=>e.length===t.length&&e.every((e,n)=>{var o;return e.trim()===(null!==(o=t[n])&&void 0!==o?o:"").trim()}),i=(t,l)=>{var s,c,d;for(const u of t){const t=e.blocks[u.block];if(!t)continue;const p=pt(t,u),h=zt(o,p);let m;h&&h.block.id===t.id&&a(h.values,u.values)?m=p:(m=Mn(t,u,e.language),o.some(e=>e.id===t.id)||o.push(t)),r.push(`${lt.repeat(l)}${n.has(u.id)?"* ":""}${m}`),ot(t.kind)&&i(null!==(s=u.body)&&void 0!==s?s:[],l+1),"ifelse"===t.kind&&(r.push(`${lt.repeat(l)}${null!==(c=t.elseLabel)&&void 0!==c?c:ct[e.language]}`),i(null!==(d=u.other)&&void 0!==d?d:[],l+1))}};return i(t,0),r.join("\n")},Cn=e=>`${e.inputs.map(e=>e.trim()).join("; ")} => ${e.expected.map(e=>e.trim()).join("; ")}`.trim(),zn=(e,t)=>{const n=Tn(e,t),o=e.blocks.filter(e=>e.palette).map(e=>n.blocks[e.key]),r=new Set(e.locked),a=Bn(n,e.start,r,o),i=Bn(n,e.solution,new Set,o);return{blocks:e.blocks.filter(e=>e.palette).map(On).join("\n"),program:a,solution:i,inputs:e.inputs,tests:e.tests.slice(0,8).map(Cn).join("\n")}},In=(e,t=0)=>e.reduce((e,n)=>{var o,r;return Math.max(e,t,In(null!==(o=n.body)&&void 0!==o?o:[],t+1),In(null!==(r=n.other)&&void 0!==r?r:[],t+1))},0),Dn=e=>[...e.matchAll(/\{([^}]*)\}/g)].map(e=>e[1]),An=(e,t)=>{const n=Tn(e,t),o=[];if(e.blocks.some(e=>e.palette)||o.push({level:"error",code:"noBlocks"}),e.blocks.forEach((t,n)=>{var r;const a=n+1;if((null!==(r=t.label.match(/\{/g))&&void 0!==r?r:[]).length!==Dn(t.label).length)return void o.push({level:"error",code:"unclosed",block:a});const i=Dn(t.label);i.length<nt[t.kind].length&&o.push({level:"error",code:"parts",block:a,detail:String(nt[t.kind].length)}),i.forEach((e,t)=>{e.includes("|")&&e.split("|").filter(e=>e.trim()).length<2&&o.push({level:"error",code:"fewChoices",block:a,part:t+1})}),nt[t.kind].forEach((t,n)=>{const r=i[n];"name"!==t||void 0===r||!r.trim()||r.includes("|")||Fe(r.trim(),e.language)||o.push({level:"error",code:"notName",block:a,part:n+1,detail:r.trim()})})}),xt(e.start)>n.maxBlocks&&o.push({level:"error",code:"tooManyStart",detail:String(n.maxBlocks)}),xt(e.solution)>n.maxBlocks&&o.push({level:"error",code:"tooManySolution",detail:String(n.maxBlocks)}),In(e.start)>n.maxDepth&&o.push({level:"error",code:"tooDeepStart",detail:String(n.maxDepth)}),In(e.solution)>n.maxDepth&&o.push({level:"error",code:"tooDeepSolution",detail:String(n.maxDepth)}),e.solution.length){const r=[];let a=0;const i=e=>e.forEach(e=>{var t,o;const l=n.blocks[e.block];l&&(r.push({node:e,number:++a}),i(null!==(t=e.body)&&void 0!==t?t:[]),"ifelse"===l.kind&&(a++,i(null!==(o=e.other)&&void 0!==o?o:[])))});i(e.solution);for(const{node:e,number:t}of r){n.blocks[e.block].slots.some((t,n)=>{var o;return"fixed"!==t.type&&!(null!==(o=e.values[n])&&void 0!==o?o:"").trim()})&&o.push({level:"error",code:"solutionBlank",line:t})}const l=wt(e.solution),s=wt(e.start);e.blocks.forEach((e,r)=>{var a,i,c;(null!==(a=l.get(e.key))&&void 0!==a?a:0)>(e.palette?t.reuse?1/0:Math.max(1,null!==(i=s.get(e.key))&&void 0!==i?i:0):null!==(c=s.get(e.key))&&void 0!==c?c:0)&&o.push({level:"warning",code:"notAvailable",block:r+1,detail:pt(n.blocks[e.key],{block:e.key,values:[]})})});const c=gt(n,e.solution,e.inputs);c.error&&!o.some(e=>"solutionBlank"===e.code)&&o.push({level:"warning",code:"solutionError",error:c.error}),e.tests.length&&At(n,e.solution).results.forEach((e,t)=>{e.passed||o.push({level:"error",code:"testFails",test:t+1})})}else o.push({level:"code"===t.scoring?"error":"warning",code:"noSolution"});return e.tests.forEach((e,t)=>{[...e.inputs,...e.expected].some(e=>e.includes(";"))&&o.push({level:"error",code:"semicolon",test:t+1})}),"pci"!==t.scoring||e.tests.length||o.push({level:"error",code:"noTests"}),o},Rn=(e,t,n,o)=>{var r;const a=n.block?null===(r=o.blocks[n.block-1])||void 0===r?void 0:r.kind:void 0,i=a?nt[a].map(t=>e.roles[t]).join(", "):"",l=n.error?mn(hn(t),n.error):void 0;return e.problem[n.code](Object.assign(Object.assign({},n),{roles:i,message:l}))},Hn="min-h-9 rounded-md border border-slate-300 bg-white px-2 text-sm text-slate-900 focus:border-sky-500 focus:outline-2 focus:outline-sky-200",Pn="inline-flex min-h-9 items-center justify-center gap-1.5 rounded-lg border border-slate-300 bg-white px-3 text-sm font-medium text-slate-700 hover:bg-slate-50 focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-sky-600 disabled:cursor-not-allowed disabled:opacity-50",Un="inline-flex size-9 shrink-0 items-center justify-center rounded-md border border-transparent text-slate-600 hover:border-slate-200 hover:bg-white focus-visible:outline-2 focus-visible:outline-sky-600 disabled:opacity-40",Fn=(e,t,n)=>{let o=-1;const r=e.replace(/\{[^}]*\}/g,e=>++o===t?null===n?"":`{${n}}`:e);return null===n?r.replace(/ {2,}/g," ").trim():r},Vn=e=>e.replace(/[{}]/g,""),qn=e=>e.reduce((e,t)=>{var n,o;return Math.max(e,parseInt(t.id.slice(1),10)||0,qn(null!==(n=t.body)&&void 0!==n?n:[]),qn(null!==(o=t.other)&&void 0!==o?o:[]))},0),Wn=(e,t)=>e.map(e=>Object.assign(Object.assign(Object.assign(Object.assign({},e),{id:"n"+ ++t.n}),e.body?{body:Wn(e.body,t)}:{}),e.other?{other:Wn(e.other,t)}:{})),Yn=({initial:e,base:t,language:n,onChange:o})=>{const r=gn(n),a=hn(n),i=gn(t.language).newLabels,[l,s]=we(e),[c,d]=we(0),[u,p]=we("set"),[h,m]=we(""),f=$e(0),b=$e(l);b.current=l;const g=e=>Object.assign(Object.assign({},Tn(e,t)),{palette:e.blocks.map(e=>e.key),reuse:!0,maxBlocks:60}),v=g(l),x=$e(v);x.current=v;const k=Ne(()=>({solution:$n({program:e.solution,inputs:"",next:qn([...e.solution,...e.start])+1,run:null},()=>x.current),start:$n({program:e.start,inputs:"",next:qn([...e.solution,...e.start])+1,run:null},()=>x.current)}),[]);ye(()=>{const e=[k.solution.subscribe(e=>s(t=>t.solution===e.program?t:Object.assign(Object.assign({},t),{solution:e.program})),{immediate:!1}),k.start.subscribe(e=>s(t=>{if(t.start===e.program)return t;const n=new Set,o=e=>e.forEach(e=>{var t,r;n.add(e.id),o(null!==(t=e.body)&&void 0!==t?t:[]),o(null!==(r=e.other)&&void 0!==r?r:[])});return o(e.program),Object.assign(Object.assign({},t),{start:e.program,locked:t.locked.filter(e=>n.has(e))})}),{immediate:!1})];return()=>e.forEach(e=>e())},[]);const w=$e(!0);_e(()=>{w.current?w.current=!1:o(l)},[l]);const y=e=>{const n=Object.assign(Object.assign({},b.current),{blocks:e}),o=Tn(n,t),r=Ln(o.blocks,k.solution.getState().program),a=Ln(o.blocks,k.start.getState().program);x.current=g(n),k.solution.dispatch({type:"RESTORE",payload:Object.assign(Object.assign({},k.solution.getState()),{program:r,run:null})}),k.start.dispatch({type:"RESTORE",payload:Object.assign(Object.assign({},k.start.getState()),{program:a,run:null})}),s(Object.assign(Object.assign({},n),{solution:r,start:a,locked:n.locked}))},_=(e,t)=>y(l.blocks.map((n,o)=>o===e?Object.assign(Object.assign({},n),t):n)),$=(e,t)=>{const n=e+t;if(n<0||n>=l.blocks.length)return;const o=[...l.blocks];[o[e],o[n]]=[o[n],o[e]],y(o),m(r.blockMoved(n+1))},N=e=>s(t=>Object.assign(Object.assign({},t),{tests:e})),S=An(l,t),j=S.filter(e=>"error"===e.level),O=S.filter(e=>"warning"===e.level),E=wt(l.solution),T=new Set((e=>{if(!e.solution.length)return[];const t=wt(e.solution);return e.blocks.filter(e=>e.palette&&!t.get(e.key)).map(e=>e.key)})(l)),L=Tn(l,t),M=l.solution.length?At(L,l.solution):null,B=l.solution.length?gt(L,l.solution,l.inputs):null,C=[r.tabBlocks,r.tabSolution,r.tabStart,r.tabTests],z=V("div",{className:"flex flex-col gap-3",children:[V("p",{className:"m-0 max-w-[75ch] text-sm text-slate-600",children:r.blocksIntro}),V("ol",{className:"m-0 flex list-none flex-col gap-2 p-0","data-testid":"author-blocks",children:l.blocks.map((e,t)=>{const n=t+1,o=Dn(e.label),i=nt[e.kind],s=v.blocks[e.key],c=e.palette?E.get(e.key)?{text:r.inSolution,cls:"bg-emerald-100 text-emerald-800"}:T.has(e.key)?{text:r.distractor,cls:"bg-amber-100 text-amber-800"}:null:{text:r.notInPalette,cls:"bg-slate-200 text-slate-700"};return V("li",{"data-testid":`block-${n}`,className:"cb-root relative overflow-hidden rounded-xl border border-slate-200 bg-white p-3 pl-4 shadow-sm",children:[V("span",{"aria-hidden":"true",className:"absolute inset-y-0 left-0 w-1.5",style:{backgroundColor:Jt[Kt(e.kind)].c}}),V("div",{role:"group","aria-labelledby":`cb-block-${e.key}`,className:"flex flex-col gap-2",children:[V("div",{className:"flex flex-wrap items-center gap-2",children:[V("span",{id:`cb-block-${e.key}`,className:"text-xs font-semibold tracking-wide text-slate-500 uppercase",children:r.block(n)}),V("span",{className:"min-w-0 max-w-full pb-1","data-testid":"preview",children:V("span",s?{className:"inline-flex max-w-full",style:Zt(Kt(e.kind)),children:V(en,{block:s,texts:a})}:{className:"font-mono text-sm",children:e.label})}),c&&V("span",{className:`rounded px-1.5 text-[11px] font-medium ${c.cls}`,"data-testid":"badge",children:c.text}),V("span",{className:"ml-auto flex gap-0.5",children:[V("button",{type:"button",className:Un,"aria-label":r.moveBlockUp(n),disabled:0===t,onClick:()=>$(t,-1),children:"↑"}),V("button",{type:"button",className:Un,"aria-label":r.moveBlockDown(n),disabled:t===l.blocks.length-1,onClick:()=>$(t,1),children:"↓"}),V("button",{type:"button",className:`${Un} hover:text-red-700`,"aria-label":r.removeBlock(n),onClick:()=>{y(l.blocks.filter((e,n)=>n!==t)),m(r.blockRemoved(n))},children:"✕"})]})]}),V("div",{className:"flex flex-wrap gap-2",children:[V("label",{className:"flex flex-col gap-1 text-xs text-slate-500",children:[r.kind,V("select",{className:Hn,value:e.kind,onChange:e=>_(t,{kind:e.target.value}),children:et.map(e=>V("option",{value:e,children:r.kinds[e]},e))})]}),V("label",{className:"flex min-w-[12rem] flex-1 flex-col gap-1 text-xs text-slate-500",children:[r.label,V("input",{type:"text",className:`${Hn} font-mono`,value:e.label,spellcheck:!1,maxLength:200,onInput:e=>_(t,{label:e.target.value})})]}),"ifelse"===e.kind&&V("label",{className:"flex w-32 flex-col gap-1 text-xs text-slate-500",children:[r.elseLabel,V("input",{type:"text",className:`${Hn} font-mono`,value:e.elseLabel,placeholder:null==s?void 0:s.elseLabel,maxLength:60,onInput:e=>_(t,{elseLabel:Vn(e.target.value).replace(/\|/g,"")})})]})]}),V("div",{className:"flex flex-col gap-1.5",role:"group","aria-label":`${r.block(n)}: ${r.parts}`,children:[o.map((n,o)=>{const a=(e=>""===e.trim()?"text":e.includes("|")?"choice":"fixed")(n),l=o<i.length-1?r.roles[i[o]]:o>=i.length-1&&i.length?r.roles[i[i.length-1]]:"";return V("div",{className:"flex flex-wrap items-center gap-2 text-sm",children:[V("span",{className:"w-36 shrink-0 text-xs text-slate-600",children:r.part(o+1,l)}),V("select",{className:Hn,"aria-label":r.partType(o+1),value:a,onChange:r=>{const l=r.target.value;_(t,{label:Fn(e.label,o,"text"===l?"":"choice"===l?"fixed"===a?`${n}|`:"|":"name"===i[o]?"x":"0")})},children:[V("option",{value:"text",children:r.textBox}),V("option",{value:"choice",children:r.dropdown}),V("option",{value:"fixed",children:r.fixed})]}),"text"!==a&&V(Jn,{inner:n,label:"choice"===a?r.choices(o+1):r.fixedText(o+1),norm:"choice"===a?e=>e.includes("|")?e:`${e}|`:e=>e.trim()?e:"?",onValue:n=>_(t,{label:Fn(e.label,o,n)})},`${e.key}-${o}-${a}`),V("button",{type:"button",className:Un,"aria-label":r.removePart(o+1),onClick:()=>_(t,{label:Fn(e.label,o,null)}),children:"✕"})]},o)}),V("div",{className:"flex flex-wrap items-center justify-between gap-2",children:[V("button",{type:"button",className:Pn,onClick:()=>_(t,{label:`${e.label.trimEnd()} {}`}),children:["+ ",r.addPart]}),V("label",{className:"flex min-h-9 items-center gap-2 text-sm text-slate-700",children:[V("input",{type:"checkbox",className:"size-4 accent-sky-600",checked:e.palette,onChange:e=>_(t,{palette:e.target.checked})}),r.inPalette]})]})]})]})]},e.key)})}),V("div",{className:"flex flex-wrap items-end gap-2",children:[V("label",{className:"flex flex-col gap-1 text-xs text-slate-500",children:[r.newBlockKind,V("select",{className:Hn,value:u,onChange:e=>p(e.target.value),children:et.map(e=>V("option",{value:e,children:r.kinds[e]},e))})]}),V("button",{type:"button",className:Pn,onClick:()=>{let e="a"+ ++f.current;for(;l.blocks.some(t=>t.key===e);)e="a"+ ++f.current;y([...l.blocks,{key:e,kind:u,label:i[u],elseLabel:"",palette:!0}]),m(r.blockAdded(l.blocks.length+1))},children:["+ ",r.addBlock]})]})]}),I=V("div",{className:"flex flex-col gap-3",children:[V("p",{className:"m-0 max-w-[75ch] text-sm text-slate-600",children:r.solutionIntro}),V(wn,{s:v,store:k.solution,texts:a,readOnly:!1,author:{title:r.tabSolution}}),V(Kn,{title:r.solutionOutput,run:B,empty:r.noSolution,t:a})]}),D=new Set(l.locked),A=V("div",{className:"flex flex-col gap-3",children:[V("div",{className:"flex flex-wrap items-start justify-between gap-2",children:[V("p",{className:"m-0 max-w-[65ch] text-sm text-slate-600",children:r.startIntro}),V("button",{type:"button",className:Pn,disabled:!l.solution.length,onClick:()=>{const e={n:k.start.getState().next},t=Wn(l.solution,e);k.start.dispatch({type:"RESTORE",payload:{program:t,inputs:"",next:e.n+1,run:null}}),s(e=>Object.assign(Object.assign({},e),{locked:[]})),m(r.copied)},children:r.copySolution})]}),V(wn,{s:v,store:k.start,texts:a,readOnly:!1,author:{title:r.tabStart,lineExtra:(e,t,n)=>V("label",{className:"ml-auto flex min-h-9 shrink-0 items-center gap-1.5 rounded-md px-2 text-xs "+(D.has(e.id)?"bg-slate-800 text-white":"text-slate-600 hover:bg-white"),children:[V("input",{type:"checkbox",className:"size-4 accent-slate-800","aria-label":r.lock(n),checked:D.has(e.id),onChange:t=>{const n=t.target.checked;s(t=>Object.assign(Object.assign({},t),{locked:n?[...t.locked,e.id]:t.locked.filter(t=>t!==e.id)}))}}),V("span",{"aria-hidden":"true",children:r.locked})]})}})]}),R=e=>e.split(/\r?\n/).map(e=>e.trim()).filter(e=>""!==e),H=V("div",{className:"flex flex-col gap-4",children:[V("div",{className:"grid gap-3 @xl:grid-cols-[minmax(10rem,16rem)_minmax(0,1fr)]",children:[V("div",{className:"flex flex-col gap-1",children:[V("label",{htmlFor:"cb-author-inputs",className:"text-xs font-semibold tracking-wide text-slate-500 uppercase",children:r.inputs}),V("textarea",{id:"cb-author-inputs",rows:3,"aria-describedby":"cb-author-inputs-help",value:l.inputs,spellcheck:!1,className:`${Hn} min-h-20 py-1.5 font-mono`,onInput:e=>s(t=>Object.assign(Object.assign({},t),{inputs:e.target.value}))}),V("p",{id:"cb-author-inputs-help",className:"m-0 text-xs text-slate-500",children:r.inputsHelp})]}),V(Kn,{title:r.solutionOutput,run:B,empty:r.noSolution,t:a})]}),V("section",{"aria-labelledby":"cb-tests",className:"flex flex-col gap-2",children:[V("div",{className:"flex flex-wrap items-center justify-between gap-2",children:[V("h3",{id:"cb-tests",className:"m-0 text-xs font-semibold tracking-wide text-slate-500 uppercase",children:r.testsHeading}),V("button",{type:"button",className:Pn,disabled:!l.solution.length||!l.tests.length,onClick:()=>{N(((e,t)=>{const n=Tn(e,t);return e.tests.map(t=>{const o=gt(n,e.solution,t.inputs.join("\n"));return o.error?t:{inputs:t.inputs,expected:o.output}})})(b.current,t)),m(r.filled)},children:r.fill})]}),V("p",{className:"m-0 text-sm text-slate-600",children:r.testsIntro}),V("ol",{className:"m-0 flex list-none flex-col gap-2 p-0",children:l.tests.map((e,t)=>{const n=null==M?void 0:M.results[t];return V("li",{"data-testid":`test-${t+1}`,className:"flex flex-wrap items-start gap-2 rounded-xl border border-slate-200 bg-white p-3",children:[V("span",{className:"w-16 shrink-0 pt-2 text-xs font-semibold text-slate-600",children:r.test(t+1)}),V("textarea",{rows:2,className:`${Hn} min-w-[8rem] flex-1 py-1.5 font-mono`,"aria-label":r.testInputs(t+1),value:e.inputs.join("\n"),spellcheck:!1,onInput:e=>N(l.tests.map((n,o)=>o===t?Object.assign(Object.assign({},n),{inputs:R(e.target.value)}):n))}),V("span",{"aria-hidden":"true",className:"pt-2 text-slate-400",children:"→"}),V("textarea",{rows:2,className:`${Hn} min-w-[8rem] flex-1 py-1.5 font-mono`,"aria-label":r.testExpected(t+1),value:e.expected.join("\n"),spellcheck:!1,onInput:e=>N(l.tests.map((n,o)=>o===t?Object.assign(Object.assign({},n),{expected:R(e.target.value)}):n))}),V("span",{className:"flex min-w-[7rem] flex-col gap-0.5 pt-1.5 text-xs","data-testid":"test-status",children:[V("span",n?{className:"w-fit rounded px-1.5 py-0.5 font-semibold "+(n.passed?"bg-emerald-100 text-emerald-800":"bg-red-100 text-red-800"),children:n.passed?`✓ ${r.passes}`:`✗ ${r.fails}`}:{className:"text-slate-500",children:r.notChecked}),n&&!n.passed&&V("span",{className:"text-slate-600",children:n.error?mn(a,n.error):r.solutionPrinted(n.output.join("; "))})]}),V("button",{type:"button",className:Un,"aria-label":r.removeTest(t+1),onClick:()=>N(l.tests.filter((e,n)=>n!==t)),children:"✕"})]},t)})}),V("div",{children:V("button",{type:"button",className:Pn,disabled:l.tests.length>=8,onClick:()=>N([...l.tests,{inputs:R(l.inputs),expected:[]}]),children:["+ ",r.addTest]})})]})]}),P=[z,I,A,H];return V("div",{className:"@container flex max-w-full flex-col gap-3 p-1 font-sans text-slate-800",children:[V("section",{"aria-labelledby":"cb-checks","data-testid":"checks",className:"rounded-xl border p-3 text-sm "+(j.length?"border-red-200 bg-red-50":"border-emerald-200 bg-emerald-50"),children:[V("h3",{id:"cb-checks",className:"m-0 text-xs font-semibold tracking-wide text-slate-600 uppercase",children:[r.checks,": ",V("span",{"aria-live":"polite",children:j.length?r.errorsHeading(j.length):r.allGood})]}),j.length>0&&V("ul",{className:"m-0 mt-1 list-disc pl-5 text-red-800","data-testid":"errors",children:j.map((e,t)=>V("li",{children:Rn(r,n,e,l)},t))}),O.length>0&&V("div",{className:"mt-1",children:[V("span",{className:"text-xs font-semibold text-amber-800",children:r.warningsHeading}),V("ul",{className:"m-0 list-disc pl-5 text-amber-900","data-testid":"warnings",children:O.map((e,t)=>V("li",{children:Rn(r,n,e,l)},t))})]})]}),V("div",{role:"tablist","aria-label":r.tabs,className:"flex flex-wrap gap-1 border-b border-slate-200",children:C.map((e,t)=>V("button",{type:"button",role:"tab",id:`cb-tab-${t}`,"aria-selected":c===t,"aria-controls":"cb-panel",tabIndex:c===t?0:-1,className:"-mb-px min-h-10 rounded-t-lg border px-3 text-sm font-medium focus-visible:outline-2 focus-visible:outline-sky-600 "+(c===t?"border-slate-200 border-b-white bg-white text-slate-900":"border-transparent text-slate-500 hover:text-slate-800"),onClick:()=>d(t),onKeyDown:e=>(e=>{const t="ArrowRight"===e.key?1:"ArrowLeft"===e.key?-1:0;if(!t)return;e.preventDefault();const n=(c+t+C.length)%C.length;d(n);const o=e.currentTarget.getRootNode();requestAnimationFrame(()=>{var e;return null===(e=o.querySelector(`#cb-tab-${n}`))||void 0===e?void 0:e.focus()})})(e),children:e},t))}),V("div",{role:"tabpanel",id:"cb-panel","aria-labelledby":`cb-tab-${c}`,children:P[c]}),V("p",{role:"status",className:"sr-only","data-testid":"author-status",children:h})]})},Jn=({inner:e,label:t,norm:n,onValue:o})=>{const[r,a]=we(e);return ye(()=>{n(r)!==e&&a(e)},[e]),V("input",{type:"text",className:`${Hn} min-w-[8rem] flex-1 font-mono`,value:r,spellcheck:!1,"aria-label":t,onInput:e=>{const t=Vn(e.target.value);a(t),o(n(t))}})},Kn=({title:e,run:t,empty:n,t:o})=>V("div",{className:"flex min-w-0 flex-col gap-1",children:[V("h4",{className:"m-0 text-xs font-semibold tracking-wide text-slate-500 uppercase",children:e}),V("div",{"data-testid":"solution-output",className:"max-h-48 min-h-16 overflow-auto rounded-lg bg-slate-900 p-3 font-mono text-sm leading-6 text-slate-100",children:[!t&&V("p",{className:"m-0 font-sans text-slate-400",children:n}),null==t?void 0:t.output.map((e,t)=>V("div",{className:"whitespace-pre-wrap",children:e},t)),(null==t?void 0:t.error)&&V("p",{className:"m-0 font-sans text-red-300",children:["⚠ ",mn(o,t.error)]})]})]}),Zn={prompt:"",blocks:"",program:"",solution:"",inputs:"",tests:"",editInputs:"true",reuse:"false",scoring:"original",maxBlocks:"30",maxDepth:"5",maxSteps:"10000",language:"en"},Xn=(e={})=>Object.keys(Zn).reduce((t,n)=>{const o=Object.keys(e).find(e=>e.toLowerCase()===n.toLowerCase());return void 0!==o&&(t[n]=e[o]),t},{}),Gn=e=>{var t,n,o,r,a,i;if(null==e)return null;if("string"==typeof e)return e;if(Array.isArray(null==e?void 0:e.record)){const o=t=>{var n,o;return null===(o=null===(n=e.record.find(e=>(null==e?void 0:e.name)===t))||void 0===n?void 0:n.base)||void 0===o?void 0:o.string};return null!==(n=null!==(t=o("program"))&&void 0!==t?t:o("code"))&&void 0!==n?n:null}if("string"==typeof(null===(o=null==e?void 0:e.base)||void 0===o?void 0:o.string))return e.base.string;if(Array.isArray(e)){const t=t=>e.find(e=>(null==e?void 0:e.fieldIdentifier)===t||(null==e?void 0:e.name)===t),n=null!==(r=t("program"))&&void 0!==r?r:t("code");if(n)return Gn(null!==(a=n.value)&&void 0!==a?a:null===(i=n.base)||void 0===i?void 0:i.string);for(const t of e){const e=Gn(t);if(e)return e}}return null},Qn=(e,t)=>{var n;const o=null===(n=Gn(e))||void 0===n?void 0:n.trim();if(!o)return null;let r=null,a=null;if(o.startsWith("{"))try{const e=JSON.parse(o);r=((e,t)=>{if(!Array.isArray(null==t?void 0:t.codeblock))return null;const n=e=>Array.isArray(e)?e.filter(e=>e&&"object"==typeof e):[],o=n(t.textbox),r=n(t.dropdown);let a=0;const i=new Map,l=e=>e.forEach(e=>{var t,n,o;e.locked&&i.set(e.block,[...null!==(t=i.get(e.block))&&void 0!==t?t:[],e.id]),l(null!==(n=e.body)&&void 0!==n?n:[]),l(null!==(o=e.other)&&void 0!==o?o:[])});l(e.start);const s=new Set,c=t=>t.flatMap(t=>{var n,l,d;const u=t&&e.blocks[t.id];if(!u)return[];const p=u.slots.map((e,t)=>{var n;if("fixed"===e.type)return"";const a="text"===e.type?o:r,i=`${u.id}.${t+1}`;return a.length&&i in a[0]?String(null!==(n=a.shift()[i])&&void 0!==n?n:""):""}),h=Array.isArray(t.nests)?t.nests:[],m=t.locked?(null!==(n=i.get(u.id))&&void 0!==n?n:[]).find(e=>!s.has(e)):void 0;return m&&s.add(m),[{id:null!=m?m:"n"+(1e3+ ++a),block:u.id,values:p,body:c(null!==(l=h[0])&&void 0!==l?l:[]),other:c(null!==(d=h[1])&&void 0!==d?d:[])}]});return Vt(e,c(t.codeblock))})(t,e),Array.isArray(null==e?void 0:e.result)&&e.result.length&&(a=e.result.map(String))}catch(e){return null}else r=((e,t)=>{const n=Object.assign({},e.blocks);let o=0;const r=It(t,n,e.language,"x",()=>"n"+ ++o,[]);return r.length?Vt(e,r):null})(t,o);return r?qt({program:r,inputs:t.inputs,run:a?{inputs:t.inputs,output:a}:null},t):null};class eo{constructor(e=!0){this.typeIdentifier="codeBlocks",this.correctState=null,this.getInstance=(e,t,n)=>new eo(!1).setup(e,t,n),this.setup=(e,t,n)=>{var o,r,a,i,l;t.properties=Object.assign(Object.assign({},Zn),Xn(t.properties)),this.config=t,this.settings=Ut(this.config.properties),this.settings.problems.length&&console.warn("codeBlocks: settings not understood",this.settings.problems);const s=null===(o=t.responseDeclaration)||void 0===o?void 0:o.correctResponse;if(this.correctState=null!==(a=Qn(null!==(r=null==s?void 0:s.value)&&void 0!==r?r:s,this.settings))&&void 0!==a?a:(e=>{if(!e.solution)return null;const t=Vt(e,e.solution),n=gt(e,t,e.inputs);return{program:t,inputs:e.inputs,next:Ft(t)+1,run:Object.assign({inputs:e.inputs},n)}})(this.settings),this.initialState=(e=>({program:e.start,inputs:e.inputs,next:Ft(e.start)+1,run:null}))(this.settings),this.store=$n(this.initialState,()=>this.settings),n)try{const e=JSON.parse(n),t=qt(null==e?void 0:e.state,this.settings);t&&this.store.restoreState(t,null!==(i=e.log)&&void 0!==i?i:[])}catch(e){}if(this.shadowdom=null!==(l=e.shadowRoot)&&void 0!==l?l:e.attachShadow({mode:"open"}),this.render(),this.config.boundTo&&Object.keys(this.config.boundTo).length>0){const e=Object.keys(this.config.boundTo)[0],t=this.config.boundTo[e];!n&&Qn(t,this.settings)&&this.setResponse(t)}return"solution"===this.config.status&&this.correctState&&this.showCorrectResponse(),this.store.subscribe(()=>{const t={interaction:this,responseIdentifier:this.config.responseIdentifier,valid:!0,value:this.getResponse()};e.dispatchEvent(new CustomEvent("qti-interaction-changed",{detail:t}))},{immediate:!1}),this.config.onready&&this.config.onready(this),this},this.showCorrectResponse=()=>{var e;if(!this.correctState)return;const t=this.correctState,n=null!==(e=t.run)&&void 0!==e?e:Object.assign({inputs:this.settings.inputs},gt(this.settings,t.program,this.settings.inputs));this.store.dispatch({type:"RESTORE",payload:Object.assign(Object.assign({},t),{run:n})})},this.render=()=>{this.settings=Ut(this.config.properties),P(null,this.shadowdom);const e=document.createElement("style");e.innerHTML=yn,this.shadowdom.appendChild(e);const t=this.config.status;P(V(wn,{s:this.settings,store:this.store,texts:hn(this.settings.language),readOnly:"review"===t||"solution"===t||"closed"===t}),this.shadowdom)},this.off=()=>{},this.on=e=>{},this.trigger=(e,t)=>{var n;const o=null!==(n=Object.keys(Zn).find(t=>t.toLowerCase()===e.toLowerCase()))&&void 0!==n?n:e;this.config.properties[o]=t,window.requestAnimationFrame(()=>this.render())},this.responseFor=e=>{const t=this.settings;if("code"===t.scoring)return{base:{string:mt(t,e.program)}};const n=JSON.stringify(((e,t)=>{const n=[],o=[],r=t=>t.flatMap(t=>{var a,i;const l=e.blocks[t.block];if(!l)return[];l.slots.forEach((e,r)=>{var a,i;"text"===e.type&&n.push({[`${l.id}.${r+1}`]:null!==(a=t.values[r])&&void 0!==a?a:""}),"choice"===e.type&&o.push({[`${l.id}.${r+1}`]:null!==(i=t.values[r])&&void 0!==i?i:""})});const s={id:l.id,type:Yt[l.kind]};return ot(l.kind)&&(s.nests=[r(null!==(a=t.body)&&void 0!==a?a:[])]),"ifelse"===l.kind&&s.nests.push(r(null!==(i=t.other)&&void 0!==i?i:[])),t.locked&&(s.locked=!0),[s]}),a=r(t.program);return{result:t.run?t.run.output:[],code:mt(e,t.program),codeblock:a,textbox:n,dropdown:o}})(t,e));if("pci"!==t.scoring)return{base:{string:n}};const o=At(t,e.program),r=[{name:"score",base:{integer:o.score}},{name:"maxscore",base:{integer:o.maxscore}},{name:"correct",base:{integer:o.correct?1:0}}];for(let e=0;e<8;e++){const t=o.results[e];t&&r.push({name:`test${e+1}`,base:{integer:t.passed?1:0}})}return r.push({name:"code",base:{string:mt(t,e.program)}}),r.push({name:"program",base:{string:n}}),{record:r}},this.getResponse=()=>{const e=this.store.getState();if(!((e,t)=>Wt(e.program)===Wt(t.program)&&e.inputs===t.inputs&&!e.run==!t.run)(e,this.initialState))return this.responseFor(e)},this.getAuthoringInstance=(e,t)=>{var n,o,r;const a=Object.assign(Object.assign({},Zn),Xn(t.properties)),i=Ut(a),l=(e=>{var t;const n=[...e.palette,...Object.keys(e.blocks).filter(t=>!e.palette.includes(t))].map(t=>{const n=e.blocks[t],o="ifelse"===n.kind&&n.elseLabel&&n.elseLabel!==ct[e.language]?n.elseLabel:"";return{key:t,kind:n.kind,label:(r=n,r.parts.map(e=>{if("string"==typeof e)return e;const t=r.slots[e.slot];return"fixed"===t.type?`{${t.text}}`:"choice"===t.type?`{${t.options.join("|")}}`:"{}"}).join("")),elseLabel:o,palette:n.palette};var r}),o={n:0},r=new Map,a=Sn(e.start,o,r);return{language:e.language,blocks:n,start:a,locked:jn(e.start,r),solution:Sn(null!==(t=e.solution)&&void 0!==t?t:[],o),inputs:e.inputs,tests:e.tests.map(e=>({inputs:[...e.inputs],expected:[...e.expected]}))}})(i);let s=l;const c=(null!==(n=t.language)&&void 0!==n?n:"en").slice(0,2),d=null!==(o=e.shadowRoot)&&void 0!==o?o:e.attachShadow({mode:"open"}),u=document.createElement("style");u.innerHTML=yn,d.appendChild(u);const p=document.createElement("div");d.appendChild(p),P(V(Yn,{initial:l,base:i,language:c,onChange:e=>{var n;s=e,null===(n=t.onchange)||void 0===n||n.call(t)}}),p);const h=JSON.stringify(zn(l,i)),m=Object.fromEntries(Nn.map(e=>{var t;return[e,String(null!==(t=a[e])&&void 0!==t?t:"")]})),f={getProperties:()=>{const e=zn(s,i);return JSON.stringify(e)===h?m:e},validate:()=>An(s,i).filter(e=>"error"===e.level).map(e=>Rn(gn(c),c,e,s)),oncompleted:()=>P(null,p)};return null===(r=t.onready)||void 0===r||r.call(t,f),f},this.getCorrectResponse=e=>{const t=Ut(Object.assign(Object.assign({},Zn),Xn(e)));if("code"===t.scoring&&t.solution)return{base:{string:mt(t,t.solution)}}},this.resetResponse=()=>{this.store.reset()},this.setResponse=e=>{const t=Qn(e,this.settings);t?this.store.dispatch({type:"RESTORE",payload:t}):console.error("couldn't restore the response",e)},this.oncompleted=()=>{this.store.unsubscribeAll()},this.getState=()=>JSON.stringify({state:this.store.getState(),log:this.store.getActions()}),this.evaluation=()=>At(this.settings,this.store.getState().program),e&&h&&h.register(this)}}return new eo});
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
{
|
|
2
|
+
"bomFormat": "CycloneDX",
|
|
3
|
+
"specVersion": "1.6",
|
|
4
|
+
"version": 1,
|
|
5
|
+
"serialNumber": "urn:uuid:79e65782-fabd-2272-60c4-5435fcbb1f5b",
|
|
6
|
+
"metadata": {
|
|
7
|
+
"tools": {
|
|
8
|
+
"components": [
|
|
9
|
+
{
|
|
10
|
+
"type": "application",
|
|
11
|
+
"name": "@citolab/tspci",
|
|
12
|
+
"version": "3.0.1"
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
"component": {
|
|
17
|
+
"type": "library",
|
|
18
|
+
"bom-ref": "pkg:npm/%40citolab/pci-code-blocks@1.0.0-beta.1",
|
|
19
|
+
"name": "@citolab/pci-code-blocks",
|
|
20
|
+
"version": "1.0.0-beta.1",
|
|
21
|
+
"description": "the candidate builds a program from code blocks (set, input, print, if, if/else, while, repeat, for), fills in the blanks and runs it; a port of the Code Block Programming Interaction (rdncuee/CBP) with a safe interpreter of its own",
|
|
22
|
+
"purl": "pkg:npm/%40citolab/pci-code-blocks@1.0.0-beta.1",
|
|
23
|
+
"supplier": {
|
|
24
|
+
"name": "Citolab",
|
|
25
|
+
"url": [
|
|
26
|
+
"https://github.com/Citolab"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"licenses": [
|
|
30
|
+
{
|
|
31
|
+
"license": {
|
|
32
|
+
"id": "MIT"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"hashes": [
|
|
37
|
+
{
|
|
38
|
+
"alg": "SHA-512",
|
|
39
|
+
"content": "a7d365b81073a9bb0c3a6d6a92297994483c3e177f6d5d48452bc2691b28e04641691fedacf061fbbea219053082c3196f9ac3f5298fab0db8a8487b4a983246"
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
"properties": [
|
|
43
|
+
{
|
|
44
|
+
"name": "tspci:typeIdentifier",
|
|
45
|
+
"value": "codeBlocks"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"name": "tspci:bundleFile",
|
|
49
|
+
"value": "index.js"
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"components": [
|
|
55
|
+
{
|
|
56
|
+
"type": "library",
|
|
57
|
+
"bom-ref": "pkg:npm/%40citolab/preact-store@3.0.1",
|
|
58
|
+
"name": "@citolab/preact-store",
|
|
59
|
+
"version": "3.0.1",
|
|
60
|
+
"description": "simple preact store",
|
|
61
|
+
"purl": "pkg:npm/%40citolab/preact-store@3.0.1",
|
|
62
|
+
"licenses": [
|
|
63
|
+
{
|
|
64
|
+
"license": {
|
|
65
|
+
"id": "MIT"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
],
|
|
69
|
+
"hashes": [
|
|
70
|
+
{
|
|
71
|
+
"alg": "SHA-512",
|
|
72
|
+
"content": "a8dc0eb0958ea026f7a6d272e4655715cdfaec03461f0503c0c24cd0ce115d4ccecbe305b9351753e1b6e9d802bed349890a1f6f75cd7e5927637134a21a9301"
|
|
73
|
+
}
|
|
74
|
+
],
|
|
75
|
+
"externalReferences": [
|
|
76
|
+
{
|
|
77
|
+
"type": "vcs",
|
|
78
|
+
"url": "git+https://github.com/Citolab/tspci.git"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"type": "distribution",
|
|
82
|
+
"url": "https://registry.npmjs.org/@citolab/preact-store/-/preact-store-3.0.1.tgz"
|
|
83
|
+
}
|
|
84
|
+
],
|
|
85
|
+
"properties": [
|
|
86
|
+
{
|
|
87
|
+
"name": "tspci:origin",
|
|
88
|
+
"value": "bundled"
|
|
89
|
+
}
|
|
90
|
+
]
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"type": "library",
|
|
94
|
+
"bom-ref": "pkg:npm/preact@10.28.2",
|
|
95
|
+
"name": "preact",
|
|
96
|
+
"version": "10.28.2",
|
|
97
|
+
"description": "Fast 3kb React-compatible Virtual DOM library.",
|
|
98
|
+
"purl": "pkg:npm/preact@10.28.2",
|
|
99
|
+
"licenses": [
|
|
100
|
+
{
|
|
101
|
+
"license": {
|
|
102
|
+
"id": "MIT"
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
],
|
|
106
|
+
"hashes": [
|
|
107
|
+
{
|
|
108
|
+
"alg": "SHA-512",
|
|
109
|
+
"content": "95bb5e6961b318776522e889d25d89ab8e789ba91ca48d733637ba77c32518016562f3f618ee226e76adecfef812c7f3e2c3d374ce94c6d4f087f777a7033d24"
|
|
110
|
+
}
|
|
111
|
+
],
|
|
112
|
+
"externalReferences": [
|
|
113
|
+
{
|
|
114
|
+
"type": "vcs",
|
|
115
|
+
"url": "https://github.com/preactjs/preact"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"type": "website",
|
|
119
|
+
"url": "https://preactjs.com"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"type": "distribution",
|
|
123
|
+
"url": "https://registry.npmjs.org/preact/-/preact-10.28.2.tgz"
|
|
124
|
+
}
|
|
125
|
+
],
|
|
126
|
+
"properties": [
|
|
127
|
+
{
|
|
128
|
+
"name": "tspci:origin",
|
|
129
|
+
"value": "bundled"
|
|
130
|
+
}
|
|
131
|
+
]
|
|
132
|
+
}
|
|
133
|
+
],
|
|
134
|
+
"dependencies": [
|
|
135
|
+
{
|
|
136
|
+
"ref": "pkg:npm/%40citolab/pci-code-blocks@1.0.0-beta.1",
|
|
137
|
+
"dependsOn": [
|
|
138
|
+
"pkg:npm/%40citolab/preact-store@3.0.1",
|
|
139
|
+
"pkg:npm/preact@10.28.2"
|
|
140
|
+
]
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"ref": "pkg:npm/%40citolab/preact-store@3.0.1",
|
|
144
|
+
"dependsOn": [
|
|
145
|
+
"pkg:npm/preact@10.28.2"
|
|
146
|
+
]
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"ref": "pkg:npm/preact@10.28.2",
|
|
150
|
+
"dependsOn": []
|
|
151
|
+
}
|
|
152
|
+
]
|
|
153
|
+
}
|
|
Binary file
|
package/example.png
ADDED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,102 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@citolab/pci-code-blocks",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.0.0-beta.1",
|
|
4
|
+
"description": "the candidate builds a program from code blocks (set, input, print, if, if/else, while, repeat, for), fills in the blanks and runs it; a port of the Code Block Programming Interaction (rdncuee/CBP) with a safe interpreter of its own",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Citolab",
|
|
7
|
+
"url": "https://github.com/Citolab"
|
|
8
|
+
},
|
|
9
|
+
"contributors": [
|
|
10
|
+
"The National Center for University Entrance Examinations (original Code Block Programming Interaction, https://github.com/rdncuee/CBP)"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"homepage": "https://github.com/Citolab/tspci-examples#readme",
|
|
14
|
+
"bugs": "https://github.com/Citolab/tspci-examples/issues",
|
|
15
|
+
"keywords": [
|
|
16
|
+
"qti",
|
|
17
|
+
"qti3",
|
|
18
|
+
"pci",
|
|
19
|
+
"portable-custom-interaction",
|
|
20
|
+
"tspci",
|
|
21
|
+
"programming",
|
|
22
|
+
"code blocks",
|
|
23
|
+
"pseudocode",
|
|
24
|
+
"computational thinking"
|
|
25
|
+
],
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
},
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/Citolab/tspci-examples.git",
|
|
32
|
+
"directory": "tspci-code-blocks"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist/index.js",
|
|
36
|
+
"dist/authoring.json",
|
|
37
|
+
"dist/sbom.cdx.json",
|
|
38
|
+
"dist/tao-pci-*.zip",
|
|
39
|
+
"codeBlocks.svg",
|
|
40
|
+
"example.png",
|
|
41
|
+
"README.md",
|
|
42
|
+
"LICENSE"
|
|
43
|
+
],
|
|
44
|
+
"source": "src/index.tsx",
|
|
45
|
+
"main": "dist/index.js",
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@citolab/preact-store": "3.0.1",
|
|
48
|
+
"@citolab/tspci": "3.0.1",
|
|
49
|
+
"@citolab/tspci-qti3": "3.0.1",
|
|
50
|
+
"@citolab/tspci-tao": "3.0.1",
|
|
51
|
+
"@tailwindcss/postcss": "^4.1.18",
|
|
52
|
+
"archiver": "7.0.1",
|
|
53
|
+
"autoprefixer": "10.4.23",
|
|
54
|
+
"preact": "10.28.2",
|
|
55
|
+
"tailwindcss": "^4.1.18"
|
|
56
|
+
},
|
|
57
|
+
"scripts": {
|
|
58
|
+
"dev": "tspci --dev",
|
|
59
|
+
"preprod": "npm test && npm run test:stories",
|
|
60
|
+
"prod": "tspci",
|
|
61
|
+
"watch": "tspci --watch",
|
|
62
|
+
"test": "node --no-warnings --test test/",
|
|
63
|
+
"package-tao": "tspci --target tao",
|
|
64
|
+
"package-qti3": "tspci --target qti3",
|
|
65
|
+
"prepack": "npm run prod && npm run package-tao",
|
|
66
|
+
"storybook": "cd .. && TSPCI_STORIES=tspci-code-blocks npx storybook dev -p 6006",
|
|
67
|
+
"test:stories": "cd .. && TSPCI_STORIES=tspci-code-blocks npx vitest run --project=storybook"
|
|
68
|
+
},
|
|
69
|
+
"config": {
|
|
70
|
+
"tspci": {
|
|
71
|
+
"typeIdentifier": "codeBlocks",
|
|
72
|
+
"label": "Code blocks",
|
|
73
|
+
"tags": [
|
|
74
|
+
"programming",
|
|
75
|
+
"code blocks",
|
|
76
|
+
"pseudocode",
|
|
77
|
+
"algorithm"
|
|
78
|
+
],
|
|
79
|
+
"scoring": [
|
|
80
|
+
"match_correct",
|
|
81
|
+
"custom",
|
|
82
|
+
"human"
|
|
83
|
+
],
|
|
84
|
+
"short": "codeBlocks",
|
|
85
|
+
"response": {
|
|
86
|
+
"$comment": "data-scoring=\"original\" (default): the JSON string of the original, {result, code, codeblock, textbox, dropdown}. data-scoring=\"code\": the program as pseudocode text, for MATCH_CORRECT. data-scoring=\"pci\": a record instead (score, maxscore, correct, test1…test8, code, program), CUSTOM. README",
|
|
87
|
+
"cardinality": "single",
|
|
88
|
+
"baseType": "string"
|
|
89
|
+
},
|
|
90
|
+
"authoring": {
|
|
91
|
+
"label": {
|
|
92
|
+
"en": "Make the blocks, the solution and the tests…",
|
|
93
|
+
"nl": "Blokken, oplossing en tests maken…",
|
|
94
|
+
"fr": "Créer les blocs, la solution et les tests…"
|
|
95
|
+
},
|
|
96
|
+
"width": 1000,
|
|
97
|
+
"height": 760
|
|
98
|
+
},
|
|
99
|
+
"correctResponse": "properties"
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|