diff --git a/README.md b/README.md index 96c0f87..9e86ceb 100644 --- a/README.md +++ b/README.md @@ -76,11 +76,29 @@ stemctl debug rp2350 freertos heap4 3 --device /dev/bus/usb/BBB/DDD ## Debugowanie Task 3 -Automatyczny start: `heap4_fragmented_checkpoint`. +Automatyczny start: `heap4_reset_checkpoint`. Karta prowadzi po ośmiu +powtarzalnych stanach jednego procesu: + +| Event | Symbol | Najważniejszy dowód Hazard3 | +|---|---|---| +| E01 | `heap4_reset_checkpoint` | `free=largest=4080`, 1 blok | +| E02 | `heap4_alloc_a_checkpoint` | A(24), `consumed=48`, `free=4032` | +| E03 | `heap4_alloc_b_checkpoint` | B(40), `consumed=64`, `free=3968` | +| E04 | `heap4_alloc_c_checkpoint` | C(16), `consumed=32`, `free=3936` | +| E05 | `heap4_free_a_checkpoint` | `free=3984`, 2 bloki | +| E06 | `heap4_fragmented_checkpoint` | `free=4016`, 2 bloki, `free>largest` | +| E07 | `heap4_coalesced_checkpoint` | `free=largest=4080`, 1 blok | +| E08 | `task03_debug_checkpoint` | OOM `NULL`, hook=1, asserts=0, PASS=1 | + +`BlockLink_t` ma na RV32 8 B, ale port wymaga wyrównania 16 B, dlatego +`xHeapStructSize` wynosi 16 B. To rozróżnienie tłumaczy zużycie 48/64/32 B. ```gdb p g_fragmented_stats p g_final_stats +p g_a_consumed +p g_b_consumed +p g_c_consumed p xFreeBytesRemaining p xMinimumEverFreeBytesRemaining p xStart @@ -91,6 +109,12 @@ b pvPortMalloc b vPortFree ``` +Scalanie sprawdzamy z replay E06: zatrzymujemy się przed `vPortFree(g_b)`, +ustawiamy tymczasowy breakpoint na `prvInsertBlockIntoFreeList` i krokujemy. +Upstream V11.3.0 scala najpierw poprzedni/lewy, a potem następny/prawy blok. +Pełna macierz kroków diagramów jest w +[`doc/hazard3-iteration-plan.md`](doc/hazard3-iteration-plan.md). + W UI: Termdebug po lewej; źródło i listing po prawej; bash pod Neovimem. `F5` continue, `F9` breakpoint, `F10` next, `F11` step, `Shift-F11` finish, `F8` stepi, `:StudentStack`, `:StudentMemory`, `:StudentLst`. diff --git a/doc/assets/a2-structure.png b/doc/assets/a2-structure.png index 2f802e8..a2715c6 100644 Binary files a/doc/assets/a2-structure.png and b/doc/assets/a2-structure.png differ diff --git a/doc/assets/a2-structure.puml b/doc/assets/a2-structure.puml index 262ad72..b8bcce8 100644 --- a/doc/assets/a2-structure.puml +++ b/doc/assets/a2-structure.puml @@ -8,41 +8,46 @@ skinparam defaultFontSize 10 skinparam classBorderColor #2c7794 skinparam classBackgroundColor #edf6fa skinparam ArrowColor #8095a1 -title A2 STRUCTURE — in-band metadata and address order +title A2 STRUCTURE — RV32 header, split and two-sided coalescing class "01 Block header" as HEADER { next : BlockLink_t* size : size_t + raw sizeof = 8 bytes on RV32 + aligned xHeapStructSize = 16 } class "Allocated block" as ALLOC { - 02 header + 13 byte request - aligned total = 32 bytes + 02 A: header + 24 byte request + aligned total = 48 bytes payload begins after header } class "03 Free remainder" as REM { own header - size = 224 bytes + free = 4032 bytes after A } HEADER *-- ALLOC : precedes payload -ALLOC -down-> REM : split preserves 256 +ALLOC -down-> REM : first-fit + split class "04 Address-ordered free list" as LIST { previous < inserted < current + A < B < C+tail } -class "05 Right neighbour" as RIGHT { - block + block.size == current +class "05 Previous / left neighbour" as LEFT { + previous + previous.size == inserted + merge previous first } -class "06 Left neighbour" as LEFT { - previous + previous.size == block +class "06 Next / right neighbour" as RIGHT { + merged + merged.size == current + merge next second } REM -down-> LIST : insert by address -LIST -down-> RIGHT : join first -RIGHT -down-> LEFT : then join left +LIST -down-> LEFT : heap_4 tests first +LEFT -down-> RIGHT : then tests next note right of LIST -Ordering makes both physical -neighbours locally visible. +Address order exposes both physical +neighbours without scanning the arena. end note @enduml diff --git a/doc/assets/a2-structure.svg b/doc/assets/a2-structure.svg index cc49cc7..bd54938 100644 --- a/doc/assets/a2-structure.svg +++ b/doc/assets/a2-structure.svg @@ -1,63 +1,68 @@ -A2 STRUCTURE — in-band metadata and address order01 Block headernext : BlockLink_t*size : size_tAllocated block02 header + 13 byte requestaligned total = 32 bytespayload begins after header03 Free remainderown headersize = 224 bytes04 Address-ordered free listprevious < inserted < current05 Right neighbourblock + block.size == current06 Left neighbourprevious + previous.size == blockOrdering makes both physicalneighbours locally visible.precedes payloadsplit preserves 256insert by addressjoin firstthen join left01 Block headernext : BlockLink_t*size : size_traw sizeof = 8 bytes on RV32aligned xHeapStructSize = 16Allocated block02 A: header + 24 byte requestaligned total = 48 bytespayload begins after header03 Free remainderown headerfree = 4032 bytes after A04 Address-ordered free listprevious < inserted < currentA < B < C+tail05 Previous / left neighbourprevious + previous.size == insertedmerge previous first06 Next / right neighbourmerged + merged.size == currentmerge next secondAddress order exposes both physicalneighbours without scanning the arena.precedes payloadfirst-fit + splitinsert by addressheap_4 tests firstthen tests next01 RESETinitial free = 408002 ALLOC A24 byte payloadfirst-fit + split03 ALLOC B / C40 + 16 byte payloadafter = 395204 FREE A / CB remains allocated05 E01 FRAGMENTED2 free blockscurrent > largest06 FREE Binsert by addressjoin right + left07 E02 COALESCED1 free blockfinal = initial08 OOM CHECKNULL · hook=1asserts=0 · PASS=1pvPortMallocsplit remaindervPortFreeheap statscontinuecoalesceoversized request01 E01 RESET1 block · free=4080raw header=8 · aligned=1602 E02 ALLOC A(24)consumed=48free=403203 E03 ALLOC B(40)consumed=64free=396804 E04 ALLOC C(16)consumed=32free=393605 E05 FREE A2 free blocksfree=398406 E06 FREE C2 blocks · fragmentedfree=401607 E07 FREE Bmerge left + right1 block · free=408008 E08 OOM / VERIFYNULL · hook=1asserts=0 · PASS=1pvPortMallocsplit remaindersplit remaindervPortFree(A)vPortFree(C)vPortFree(B)oversized request Free : 01 one list node -Free --> Allocated : 02 first-fit + split\ncurrent free decreases -Allocated --> Fragmented : free A and C -Fragmented : 03 two free blocks +[*] --> Free : 01 E01 one list node +Free --> Allocated : 02 E04 A+B+C allocated\ncurrent free = 3936 +Allocated --> Fragmented : E05 free A\nE06 free C +Fragmented : 03 E06 two free blocks Fragmented : sum free > largest block -Fragmented --> Coalesced : free B\naddress-order joins neighbours -Coalesced : 04 one free block -Coalesced : current free = initial free -Coalesced --> OOMChecked : request > arena -OOMChecked : NULL + hook once +Fragmented --> Coalesced : 04 E07 free B\nmerge previous, then next +Coalesced : one free block +Coalesced : current = largest = initial +Coalesced --> OOMChecked : 05 E08 request > arena +OOMChecked : NULL · hook=1 · PASS=1 OOMChecked --> [*] -state "05 minimum-ever" as MIN +state "minimum-ever" as MIN Allocated -right-> MIN : records low watermark Fragmented -right-> MIN : does not rise Coalesced -right-> MIN : history remains diff --git a/doc/assets/a6-state.svg b/doc/assets/a6-state.svg index 12a9095..8c07583 100644 --- a/doc/assets/a6-state.svg +++ b/doc/assets/a6-state.svg @@ -1,42 +1,42 @@ -A6 STATE — block state and heap statisticsFreeAllocatedFragmented03 two free blockssum free > largest blockCoalesced04 one free blockcurrent free = initial freeOOMCheckedNULL + hook once05 minimum-ever01 one list node02 first-fit + splitcurrent free decreasesfree A and Cfree Baddress-order joins neighboursrequest > arenarecords low watermarkdoes not risehistory remains01 E01 one list node02 E04 A+B+C allocatedcurrent free = 3936E05 free AE06 free C04 E07 free Bmerge previous, then next05 E08 request > arenarecords low watermarkdoes not risehistory remains ELF : compile + link ELF --> E1 : reset / load / replay diff --git a/doc/assets/a7-runtime.svg b/doc/assets/a7-runtime.svg index 62a80d5..0d55821 100644 --- a/doc/assets/a7-runtime.svg +++ b/doc/assets/a7-runtime.svg @@ -1,36 +1,36 @@ -A7 RUNTIME — one artifact, two checkpoints, one proof«source»01 task03 CA/B/C experiment«artifact»02 ELF + imageheap_4 symbols«checkpoint E01»03 fragmentedblocks=2 · aligned=1«memory»04 ucHeap[4096]headers + payload«checkpoint E02»05 coalescedfinal=initial · blocks=1OOM=1 · PASS=1compile + linkreset / load / replayinspect bytescontinue«source»01 task03 CA/B/C experiment«artifact»02 ELF + imageheap_4 symbols«checkpoint E06»03 fragmentedblocks=2 · free>largest«memory»04 ucHeap[4096]headers + payload«checkpoint E08»05 verifiedfinal=initial · blocks=1OOM=1 · PASS=1compile + linkreset / load / replayinspect bytescontinue C vPortFree(B) 1. wstaw B pomiędzy A i C według adresu; - 2. jeśli end(B) == addr(C), połącz B+C; - 3. jeśli end(A) == addr(BC), połącz A+BC; + 2. jeśli end(A) == addr(B), połącz A+B; + 3. jeśli end(AB) == addr(C), połącz AB+C; wynik: [ ABC:144 FREE ] free list: A -> END @@ -126,26 +126,32 @@ Uczeń przed odsłonięciem rysuje listę i wpisuje `2 -> 1`, `96 -> 144` oraz ```text RESET/INIT + -> heap4_reset_checkpoint # E01: 4080 B -> ALLOC A(24) + -> heap4_alloc_a_checkpoint # E02: 4032 B -> ALLOC B(40) + -> heap4_alloc_b_checkpoint # E03: 3968 B -> ALLOC C(16) + -> heap4_alloc_c_checkpoint # E04: 3936 B -> FREE A + -> heap4_free_a_checkpoint # E05: 3984 B, 2 bloki -> FREE C - -> heap4_fragmented_checkpoint # 2 free blocks + -> heap4_fragmented_checkpoint # E06: 4016 B, 2 bloki -> FREE B + -> heap4_coalesced_checkpoint # E07: 4080 B, 1 blok -> OOM request - -> task03_debug_checkpoint # 1 free block, pass=1 + -> task03_debug_checkpoint # E08: NULL, hook=1, pass=1 ``` -Uczeń zapisuje tylko relacje, ponieważ dokładne bajty zależą od ABI i -konfiguracji: +Na Hazard3 `sizeof(BlockLink_t)=8`, ale `portBYTE_ALIGNMENT=16`, dlatego +`xHeapStructSize=16`. Główny replay ma stałe, testowane wartości: -| Obserwacja | Oczekiwany związek | +| Obserwacja | Oczekiwany wynik RV32/Hazard3 | | --- | --- | -| po trzech alokacjach | `after_allocations < initial_free` | -| stan pofragmentowany | `free_blocks == 2`, `largest < total_free` | -| po `free(B)` | `final_free == initial_free`, `free_blocks == 1` | -| low-water mark | `minimum_ever <= after_allocations` i nie rośnie po free | +| E01--E04 | `4080 -> 4032 -> 3968 -> 3936`, zużycie `48/64/32` | +| E05--E06 | `3984 -> 4016`, nadal 2 bloki i `largest < total_free` | +| E07 | `final_free == initial_free == 4080`, `free_blocks == 1` | +| low-water mark | `minimum_ever == 3936` i nie rośnie po free | | OOM | wynik `NULL`, hook `1`, brak uszkodzenia listy | Minimalny dowód w GDB: @@ -153,6 +159,9 @@ Minimalny dowód w GDB: ```gdb p g_fragmented_stats p g_final_stats +p g_a_consumed +p g_b_consumed +p g_c_consumed p xFreeBytesRemaining p xMinimumEverFreeBytesRemaining p xStart @@ -160,6 +169,9 @@ p pxEnd x/96bx ucHeap ``` +Szczegółowe mapowanie wszystkich diagramów do kodu, replay i dowodów zawiera +[`hazard3-iteration-plan.md`](hazard3-iteration-plan.md). + ## Kryterium zaliczenia Uczeń zalicza lekcję, jeżeli: diff --git a/doc/generated/main.tex b/doc/generated/main.tex index 3130740..941a7bf 100644 --- a/doc/generated/main.tex +++ b/doc/generated/main.tex @@ -11,7 +11,7 @@ \usepackage{amsmath} \usepackage{amssymb} \usepackage{xcolor} -\usepackage[a4paper,left=2.15cm,right=2.15cm,top=0.5cm,bottom=0.5cm,headheight=24mm,headsep=3mm,includehead]{geometry} +\usepackage[a4paper,left=2.15cm,right=2.15cm,top=0.5cm,bottom=1cm,headheight=24mm,headsep=3mm,includehead,includefoot]{geometry} \usepackage{eso-pic} \usepackage{marginnote} \usepackage{array} @@ -42,13 +42,15 @@ \newcommand{\BuildCommit}{lokalna}% } -\newcommand{\DocumentAuthor}{M. Pabiszczak} +\newcommand{\DocumentAuthor}{Mateusz Pabiszczak} \newcommand{\DocumentYear}{2026} \newcommand{\CardSeries}{freertos-c} +\newcommand{\CardSeriesTitle}{FreeRTOS C} \newcommand{\CardNumber}{01} \newcommand{\CardCount}{15} \newcommand{\CardSlug}{heap4-mechanics} \newcommand{\CardVersion}{v00.01} +\newcommand{\CardStatus}{Gotowa} \newcommand{\DocumentUUID}{87e48095-7793-54e3-9230-4e61d31bd459} \newcommand{\EmptyCheck}{\(\square\)} @@ -92,7 +94,7 @@ \hrule height0.35pt% \nointerlineskip% \begin{tabularx}{\linewidth}{@{}p{\dimexpr0.05882353\linewidth-\arrayrulewidth\relax}|p{\dimexpr0.05042017\linewidth-\arrayrulewidth\relax}|p{\dimexpr0.14705882\linewidth-\arrayrulewidth\relax}|p{\dimexpr0.09243697\linewidth-\arrayrulewidth\relax}|p{\dimexpr0.07563025\linewidth-\arrayrulewidth\relax}|p{\dimexpr0.07563025\linewidth-\arrayrulewidth\relax}|X@{}}% - \parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.15mm}{\fontsize{2.85}{3}\selectfont\ttfamily\bfseries SUBJ.}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{4.45}{4.65}\selectfont\ttfamily\bfseries Inf.}\hspace{0.15mm}}\par} & \parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.15mm}{\fontsize{2.85}{3}\selectfont\ttfamily\bfseries PROG.}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{4.45}{4.65}\selectfont\ttfamily\bfseries —}\hspace{0.15mm}}\par} & \parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.15mm}{\fontsize{2.85}{3}\selectfont\ttfamily\bfseries CORE}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{4.45}{4.65}\selectfont\ttfamily\bfseries —}\hspace{0.15mm}}\par} & \parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.15mm}{\fontsize{2.85}{3}\selectfont\ttfamily\bfseries SCOPE}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{4.45}{4.65}\selectfont\ttfamily\bfseries —}\hspace{0.15mm}}\par} & \parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.15mm}{\fontsize{2.85}{3}\selectfont\ttfamily\bfseries LEVEL}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{4.45}{4.65}\selectfont\ttfamily\bfseries —}\hspace{0.15mm}}\par} & \parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.15mm}{\fontsize{2.85}{3}\selectfont\ttfamily\bfseries POS.}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{4.45}{4.65}\selectfont\ttfamily\bfseries —}\hspace{0.15mm}}\par} & \parbox[c][5.19414mm][c]{\linewidth}{\hbox to\linewidth{\hspace{0.35mm}{\fontsize{3.4}{3.75}\selectfont\ttfamily\bfseries GITEA UUID}\hfill{\fontsize{3.4}{3.75}\selectfont\ttfamily 87e48095-7793-54e3-9230-4e61d31bd459}\hspace{0.35mm}}\par\nointerlineskip\hbox to\linewidth{\hspace{0.35mm}{\fontsize{3.4}{3.75}\selectfont\ttfamily\bfseries CARD UUID} {\fontsize{3.4}{3.75}\selectfont\ttfamily aea09ab7-9bfd-5368-8d1b-c8724871c1a7}\hfill{\fontsize{3.4}{3.75}\selectfont\ttfamily\bfseries AUTHOR M. Pabiszczak}\hspace{0.35mm}}} \\% + \parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.15mm}{\fontsize{2.85}{3}\selectfont\ttfamily\bfseries SUBJ.}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{4.45}{4.65}\selectfont\ttfamily\bfseries Inf.}\hspace{0.15mm}}\par} & \parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.15mm}{\fontsize{2.85}{3}\selectfont\ttfamily\bfseries PROG.}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{4.45}{4.65}\selectfont\ttfamily\bfseries —}\hspace{0.15mm}}\par} & \parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.15mm}{\fontsize{2.85}{3}\selectfont\ttfamily\bfseries CORE}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{4.45}{4.65}\selectfont\ttfamily\bfseries —}\hspace{0.15mm}}\par} & \parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.15mm}{\fontsize{2.85}{3}\selectfont\ttfamily\bfseries SCOPE}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{4.45}{4.65}\selectfont\ttfamily\bfseries —}\hspace{0.15mm}}\par} & \parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.15mm}{\fontsize{2.85}{3}\selectfont\ttfamily\bfseries LEVEL}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{4.45}{4.65}\selectfont\ttfamily\bfseries —}\hspace{0.15mm}}\par} & \parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.15mm}{\fontsize{2.85}{3}\selectfont\ttfamily\bfseries POS.}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{4.45}{4.65}\selectfont\ttfamily\bfseries —}\hspace{0.15mm}}\par} & \parbox[c][5.19414mm][c]{\linewidth}{\hbox to\linewidth{\hspace{0.35mm}{\fontsize{3.4}{3.75}\selectfont\ttfamily\bfseries GITEA UUID}\hfill{\fontsize{3.4}{3.75}\selectfont\ttfamily 87e48095-7793-54e3-9230-4e61d31bd459}\hspace{0.35mm}}\par\nointerlineskip\hbox to\linewidth{\hspace{0.35mm}{\fontsize{3.4}{3.75}\selectfont\ttfamily\bfseries CARD UUID} {\fontsize{3.4}{3.75}\selectfont\ttfamily aea09ab7-9bfd-5368-8d1b-c8724871c1a7}\hfill{\fontsize{3.4}{3.75}\selectfont\ttfamily\bfseries AUTHOR Mateusz Pabiszczak}\hspace{0.35mm}}} \\% \end{tabularx}% \par\nointerlineskip% \hrule height0.35pt% @@ -119,8 +121,11 @@ \pagestyle{fancy} \fancyhf{} \fancyhead[C]{\ESCPageResourceHeader} +\fancyfoot[L]{{\fontsize{6.4}{7.0}\selectfont\ttfamily UUID \DocumentUUID}} +\fancyfoot[C]{{\fontsize{6.4}{7.0}\selectfont\ttfamily \DocumentAuthor}} +\fancyfoot[R]{{\fontsize{6.4}{7.0}\selectfont\ttfamily STRONA \thepage/\pageref{LastPage}}} \renewcommand{\headrulewidth}{0pt} -\renewcommand{\footrulewidth}{0pt} +\renewcommand{\footrulewidth}{0.35pt} \newcommand{\ESCMarginTag}[4]{% \hspace*{#1}\textcolor{#2}{#3~#4}% @@ -155,7 +160,7 @@ {\bfseries\textcolor{black!65}{TECH}\par}% \vspace{0.08em}% \hspace*{0.00em}\textcolor{red}{WE~01}\textcolor{black!48}{}\par% - \hspace*{0.28em}\textcolor{orange!85!black}{EK~LOCAL~RTOS}\textcolor{black!48}{\pdftooltip[width=\textwidth]{.01}{Uczeń odtwarza dwa checkpointy Hazard3 i odróżnia current free, largest free block oraz\textCR minimum-ever.}}\par% + \hspace*{0.28em}\textcolor{orange!85!black}{EK~LOCAL~RTOS}\textcolor{black!48}{\pdftooltip[width=\textwidth]{.01}{Uczeń odtwarza osiem checkpointów Hazard3 i odróżnia current free, largest free block oraz\textCR minimum-ever.}}\par% \hspace*{0.54em}\textcolor{blue!70!black}{KW~LOCAL~RTOS}\textcolor{black!48}{\pdftooltip[width=\textwidth]{.01}{Łączy kod, diagram i zweryfikowany dowód.}}\par% \end{minipage}% }% @@ -197,10 +202,10 @@ Uczeń przechodzi od liniowego kursora z K\&R 5.4 do wielokrotnego użycia tej s \vspace{0.35em} Dwa małe modele C przygotowują przewidywanie. Główny replay uruchamia prawdziwe FreeRTOS-Kernel V11.3.0 heap\_4 na RV32I/Hazard3 i dowodzi fragmentacji, pełnego scalenia, minimum-ever oraz kontrolowanego OOM. \vspace{0.55em} -\small\begin{tabularx}{\textwidth}{@{}>{\ttfamily\raggedright\arraybackslash}p{0.85cm}>{\ttfamily\raggedright\arraybackslash}p{1.45cm}X>{\raggedright\arraybackslash}p{2.45cm}>{\raggedright\arraybackslash}p{1.75cm}>{\ttfamily\raggedright\arraybackslash}p{1.50cm}@{}} +\small\begin{tabularx}{\textwidth}{@{}>{\ttfamily\raggedright\arraybackslash}p{1.10cm}>{\ttfamily\raggedright\arraybackslash}p{1.45cm}X>{\raggedright\arraybackslash}p{2.50cm}>{\raggedright\arraybackslash}p{1.75cm}>{\ttfamily\raggedright\arraybackslash}p{1.50cm}@{}} \textbf{Lekcja} & \textbf{Task} & \textbf{Najważniejsza idea} & \textbf{Priorytet} & \textbf{Status} & \textbf{Version} \\ \hline \hline -\multicolumn{1}{|l|}{\textbf{\texttt{FC01}}} & \multicolumn{1}{l|}{\textbf{\texttt{Task01}}} & \multicolumn{1}{l|}{\textbf{headers, address-ordered free list, first-fit, split, coalescing and heap statistics}} & \multicolumn{1}{l|}{\textbf{główny}} & \multicolumn{1}{l|}{\textbf{opracowane}} & \multicolumn{1}{l|}{\textbf{\texttt{v00.01}}} \\ \hline +\textbf{\texttt{FC01}} & \textbf{\texttt{Task01}} & \textbf{headers, address-ordered free list, first-fit, split, coalescing and heap statistics} & \textbf{główny} & \textbf{opracowane} & \textbf{\texttt{v00.01}} \\ \hline \end{tabularx} \normalsize @@ -219,6 +224,10 @@ Dwa małe modele C przygotowują przewidywanie. Główny replay uruchamia prawdz \caption{A1 CONTEXT — od żądania aplikacji do rzeczywistych bajtów ucHeap. — część 1/1 (r1 c1).} \label{fig:a1-context} \end{figure} +\Needspace{6\baselineskip} +\begin{tcolorbox}[enhanced,arc=0pt,boxrule=0.35pt,colback=blue!2,colframe=blue!45!black,boxsep=0pt,left=1.2mm,right=1.2mm,top=0.7mm,bottom=0.7mm,colbacktitle=blue!7,coltitle=black,title={\ttfamily\bfseries INTERPRETACJA}] +Aplikacja korzysta z publicznego API, heap\_4 zarządza jedną areną, a Hazard3 pokazuje jej rzeczywisty stan. +\end{tcolorbox} \ESCSectionBlockEnd \clearpage @@ -227,10 +236,14 @@ Dwa małe modele C przygotowują przewidywanie. Główny replay uruchamia prawdz \vspace{0.35em} \begin{figure}[H] \centering - \includegraphics[width=0.44697\linewidth,trim=0.000bp 0.000bp 0.000bp 0.000bp,clip]{\detokenize{../assets/a2-structure.png}} + \includegraphics[width=0.47273\linewidth,trim=0.000bp 0.000bp 0.000bp 0.000bp,clip]{\detokenize{../assets/a2-structure.png}} \caption{A2 STRUCTURE — metadane wewnątrz areny i adresowo uporządkowana lista. — część 1/1 (r1 c1).} \label{fig:a2-structure} \end{figure} +\Needspace{6\baselineskip} +\begin{tcolorbox}[enhanced,arc=0pt,boxrule=0.35pt,colback=blue!2,colframe=blue!45!black,boxsep=0pt,left=1.2mm,right=1.2mm,top=0.7mm,bottom=0.7mm,colbacktitle=blue!7,coltitle=black,title={\ttfamily\bfseries INTERPRETACJA}] +Każdy blok ma nagłówek, a tylko wolne bloki wykorzystują wskaźnik next do budowy listy uporządkowanej adresami. +\end{tcolorbox} \ESCSectionBlockEnd \clearpage @@ -240,10 +253,14 @@ Dwa małe modele C przygotowują przewidywanie. Główny replay uruchamia prawdz \vspace{0.35em} \begin{figure}[H] \centering - \includegraphics[width=0.86277\linewidth,trim=0.000bp 0.000bp 0.000bp 0.000bp,clip]{\detokenize{../assets/a5-flow.png}} + \includegraphics[width=0.86383\linewidth,trim=0.000bp 0.000bp 0.000bp 0.000bp,clip]{\detokenize{../assets/a5-flow.png}} \caption{A5 FLOW — inicjalizacja, A/B/C, fragmentacja, dwustronne scalenie i OOM. — część 1/1 (r1 c1).} \label{fig:a5-flow} \end{figure} +\Needspace{6\baselineskip} +\begin{tcolorbox}[enhanced,arc=0pt,boxrule=0.35pt,colback=blue!2,colframe=blue!45!black,boxsep=0pt,left=1.2mm,right=1.2mm,top=0.7mm,bottom=0.7mm,colbacktitle=blue!7,coltitle=black,title={\ttfamily\bfseries INTERPRETACJA}] +Jeden przebieg A/B/C przechodzi od pustej areny przez trzy przydziały i dwa wolne obszary do ponownie scalonego bloku. +\end{tcolorbox} \ESCSectionBlockEnd \end{landscape} @@ -253,10 +270,14 @@ Dwa małe modele C przygotowują przewidywanie. Główny replay uruchamia prawdz \vspace{0.35em} \begin{figure}[H] \centering - \includegraphics[width=0.52424\linewidth,trim=0.000bp 0.000bp 0.000bp 0.000bp,clip]{\detokenize{../assets/a6-state.png}} + \includegraphics[width=0.48636\linewidth,trim=0.000bp 0.000bp 0.000bp 0.000bp,clip]{\detokenize{../assets/a6-state.png}} \caption{A6 STATE — wolny, przydzielony, rozdzielony, scalony oraz minimum-ever. — część 1/1 (r1 c1).} \label{fig:a6-state} \end{figure} +\Needspace{6\baselineskip} +\begin{tcolorbox}[enhanced,arc=0pt,boxrule=0.35pt,colback=blue!2,colframe=blue!45!black,boxsep=0pt,left=1.2mm,right=1.2mm,top=0.7mm,bottom=0.7mm,colbacktitle=blue!7,coltitle=black,title={\ttfamily\bfseries INTERPRETACJA}] +Bieżąca liczba wolnych bajtów może rosnąć po free, ale minimum-ever pozostaje historycznym minimum. +\end{tcolorbox} \ESCSectionBlockEnd \clearpage @@ -270,6 +291,10 @@ Dwa małe modele C przygotowują przewidywanie. Główny replay uruchamia prawdz \caption{A7 RUNTIME — kod, ELF, checkpoint, pamięć i statystyki jednego przebiegu. — część 1/1 (r1 c1).} \label{fig:a7-runtime} \end{figure} +\Needspace{6\baselineskip} +\begin{tcolorbox}[enhanced,arc=0pt,boxrule=0.35pt,colback=blue!2,colframe=blue!45!black,boxsep=0pt,left=1.2mm,right=1.2mm,top=0.7mm,bottom=0.7mm,colbacktitle=blue!7,coltitle=black,title={\ttfamily\bfseries INTERPRETACJA}] +Ten sam artefakt łączy źródło, symbole ELF, osiem checkpointów, pamięć ucHeap i końcowe asercje. +\end{tcolorbox} \ESCSectionBlockEnd \end{landscape} @@ -281,20 +306,23 @@ Dwa małe modele C przygotowują przewidywanie. Główny replay uruchamia prawdz {\scriptsize\ttfamily aea09ab7-9bfd-5368-8d1b-c8724871c1a7}\par \begin{ESCBlockFrame}{A — przewidywanie} Przejdź przez model nagłówka, split i porządek adresowy przed uruchomieniem prawdziwego heap\_4. -\begin{ESCStepFrame}{size · Policz rozmiar bloku.} -Dodaj nagłówek do 13 bajtów i wyrównaj wynik do ośmiu. +\begin{ESCStepFrame}{size · Policz rozmiary całych bloków.} +Rozróżnij surowy BlockLink\_t (8 bajtów) od xHeapStructSize (16 bajtów), dodaj nagłówek do żądań 24, 40 i 16 bajtów, a następnie wyrównaj wynik do 16. \end{ESCStepFrame} \begin{ESCStepFrame}{list · Narysuj listę po free(A,C).} Zaznacz, dlaczego przydzielony B rozdziela dwa wolne obszary. \end{ESCStepFrame} \end{ESCBlockFrame} \begin{ESCBlockFrame}{B — replay Hazard3} -Powiąż diagram z dwoma deterministycznymi checkpointami. -\begin{ESCStepFrame}{fragmented · Sprawdź E01.} -Porównaj liczbę wolnych bloków, największy blok i bieżące wolne bajty. +Powiąż każdy stan diagramu z deterministycznym checkpointem E01--E08. +\begin{ESCStepFrame}{allocate · Sprawdź E01--E04.} +Potwierdź wartości 4080, 4032, 3968 i 3936 oraz zużycie 48/64/32 bajtów. \end{ESCStepFrame} -\begin{ESCStepFrame}{coalesced · Sprawdź E02.} -Udowodnij pełne scalenie, zachowanie minimum-ever i kontrolowany OOM. +\begin{ESCStepFrame}{release · Sprawdź E05--E07.} +Porównaj liczbę wolnych bloków i udowodnij scalenie poprzedniego, a potem następnego sąsiada. +\end{ESCStepFrame} +\begin{ESCStepFrame}{verify · Sprawdź E08.} +Udowodnij zachowanie minimum-ever, kontrolowany OOM, brak asercji i PASS=1. \end{ESCStepFrame} \end{ESCBlockFrame} \begin{ESCBlockFrame}{Ćwiczenie · Ćwiczenie — ta sama suma, inna użyteczność} @@ -302,7 +330,7 @@ Zaproponuj dwa układy wolnych bloków o tej samej sumie bajtów, ale tylko jede \par\textbf{Evidence:} Dwa diagramy listy, suma wolnych bajtów, rozmiar największego bloku i wynik pvPortMalloc. \par\textbf{Acceptance:} Uczeń nie utożsamia sumy wolnej pamięci z możliwością pojedynczego dużego przydziału. \end{ESCBlockFrame} -\tcblower\textbf{Task acceptance:} Model 13 -> 32 bajty; poprawna predykcja dwóch wolnych bloków po free(A,C) i jednego po free(B); final free = initial free; minimum-ever nie rośnie; OOM zwraca NULL; PASS=1. +\tcblower\textbf{Task acceptance:} Na RV32 BlockLink\_t ma 8 bajtów, lecz 16-bajtowe wyrównanie portu daje xHeapStructSize=16; A/B/C zużywają 48/64/32 bajty; po free(A,C) są dwa wolne bloki, po free(B) jeden; final free = initial free; minimum-ever nie rośnie; OOM zwraca NULL; PASS=1. \end{ESCTaskFrame} \begin{ESCConclusionFrame} heap\_4 odzyskuje pamięć dzięki metadanym w arenie, adresowo uporządkowanej liście i scalaniu sąsiadów. Suma wolnych bajtów nie zastępuje informacji o największym bloku, a minimum-ever jest historią, nie bieżącym stanem. diff --git a/doc/hazard3-iteration-plan.md b/doc/hazard3-iteration-plan.md new file mode 100644 index 0000000..3d237eb --- /dev/null +++ b/doc/hazard3-iteration-plan.md @@ -0,0 +1,102 @@ +# FC01 — plan iteracji diagramów w Hazard3 + +## Zasada + +Kursor porusza się po diagramie, nie po przypadkowych liniach programu. +Każda kotwica ma jeden z dwóch kontraktów: + +- `CODE` — otwiera właściwe źródło lub dowód ELF; nie uruchamia programu; +- `RUN` — odtwarza program od czystego resetu do wskazanego checkpointu, + ustawia Neovima i udostępnia zestaw wyrażeń GDB. + +Ten sam snapshot może wystąpić w kilku perspektywach. Nie powtarza to +eksperymentu: A2 pyta o strukturę, A6 o stan, a A7 o jakość dowodu. + +## A1 CONTEXT — granice odpowiedzialności + +| Step | Tryb | Otwórz | Pytanie kontrolne | +|---|---|---|---| +| 01 Application | CODE | `main()` | Czy aplikacja dotyka metadanych allocatora? | +| 02 FreeRTOS API | CODE | wywołania `pvPortMalloc`, `vPortFree`, stats | Gdzie kończy się publiczny kontrakt? | +| 03 heap_4 | CODE | upstream `heap_4.c` | Które funkcje wybierają, dzielą i scalają blok? | +| 04 ucHeap | CODE | definicja `ucHeap[4096]` | Gdzie fizycznie leżą nagłówki i payload? | +| 05 Hazard3 | CODE | test symboli ELF | Czy debugujemy dokładnie artefakt z karty? | + +A1 nie ma checkpointu: opisuje architekturę, a nie zdarzenie runtime. + +## A2 STRUCTURE — nagłówek, split i scalenie + +| Step | Tryb / replay | Obserwuj | Warunek zaliczenia | +|---|---|---|---| +| 01 Header | CODE | `BlockLink_t`, `portBYTE_ALIGNMENT` | raw header=8 B, alignment=16 B, `xHeapStructSize`=16 B | +| 02 Alignment | RUN E02 | `g_a`, `g_a_consumed` | A jest wyrównane, cały blok zużywa 48 B | +| 03 Split | RUN E02 | `g_after_a_stats` | pozostaje 1 wolny blok i 4032 B | +| 04 Address order | RUN E06 | `g_a`, `g_b`, `g_c`, stats | adresy rosną, a B rozdziela 2 wolne obszary | +| 05 Merge previous | RUN E06 + step | `pxIterator`, `pxBlockToInsert` | poprzedni/lewy blok jest testowany i scalany pierwszy | +| 06 Merge next | RUN E06 + step | powiększony blok i `pxNextFreeBlock` | następny/prawy blok jest scalany drugi | + +Dla kroków 05–06 po replay E06: + +```gdb +tbreak prvInsertBlockIntoFreeList +continue # wykonaj vPortFree(g_b) +p pxIterator +p pxBlockToInsert +next # test poprzedniego/lewego sąsiada +next # test następnego/prawego sąsiada +``` + +## A5 FLOW — pełny przebieg + +| Event | Operacja | Wartości RV32/Hazard3 | Dowód | +|---|---|---|---| +| E01 | reset/init | free=4080 | 1 blok, largest=4080 | +| E02 | alloc A(24) | consumed=48, free=4032 | A != NULL, aligned=1 | +| E03 | alloc B(40) | consumed=64, free=3968 | B != NULL, aligned=1 | +| E04 | alloc C(16) | consumed=32, free=3936 | C != NULL, aligned=1 | +| E05 | free A | free=3984 | 2 wolne bloki | +| E06 | free C | free=4016 | 2 bloki, free > largest | +| E07 | free B | free=largest=4080 | 1 wolny blok, minimum-ever=3936 | +| E08 | oversized alloc | NULL | hook=1, asserts=0, layout=1, PASS=1 | + +Każdy Enter na A5 wykonuje czysty replay do dokładnie jednego eventu. Nie +kontynuujemy stanu pozostałego po poprzednim kroku. + +## A6 STATE — znaczenie liczników + +| Step | Replay | Hipoteza | +|---|---|---| +| 01 Free | E01 | current free i largest są równe | +| 02 Allocated | E04 | przydziały zmniejszają current free do 3936 | +| 03 Fragmented | E06 | total free może być większe od largest | +| 04 Coalesced | E07 | current, largest i initial znów są równe | +| 05 Minimum-ever | E08 | minimum-ever pozostaje 3936 mimo odzyskania areny | + +## A7 RUNTIME — jakość dowodu + +| Step | Tryb / replay | Co musi znaleźć się w dowodzie | +|---|---|---| +| 01 Source | CODE | blob źródła eksperymentu | +| 02 ELF | CODE | SHA artefaktu i symbole upstream/checkpointów | +| 03 Fragmented | RUN E06 | PC, 2 bloki, free=4016, largest 1} \\ -16--27 & Task 3 RUN & dwa checkpointy prawdziwego \texttt{heap\_4.c} na Pico 2 W \\ +16--27 & Task 3 RUN & osiem checkpointów E01--E08 prawdziwego \texttt{heap\_4.c} \\ 27--30 & wyjście & odróżnić total free, largest free i minimum-ever \\ \bottomrule \end{tabularx} @@ -209,8 +209,9 @@ po: A:144 -> END blocks=1 total=144 largest=144 \end{lstlisting} Porządek po adresie sprawia, że fizycznych sąsiadów można sprawdzić podczas -jednego wstawienia. To jest mechanizm funkcji -\texttt{prvInsertBlockIntoFreeList()} z \texttt{heap\_4.c}. +jednego wstawienia. Uproszczony Task 2 scala prawą, a następnie lewą stronę. +Właściwy \texttt{prvInsertBlockIntoFreeList()} z FreeRTOS V11.3.0 wykonuje +te same dwa testy w kolejności: poprzedni/lewy, następnie kolejny/prawy blok. \section{Task 3 — jedyny centralny RUN (11 minut)} @@ -224,17 +225,21 @@ stemctl debug rp2350 freertos heap4 3 --device /dev/bus/usb/BBB/DDD \begin{lstlisting} RESET/INIT - -> ALLOC A(24) -> ALLOC B(40) -> ALLOC C(16) - -> FREE A -> FREE C - -> heap4_fragmented_checkpoint # STOP 1 - -> FREE B -> OOM request - -> task03_debug_checkpoint # STOP 2 + -> heap4_reset_checkpoint # E01: free=4080 + -> heap4_alloc_a_checkpoint # E02: free=4032, used=48 + -> heap4_alloc_b_checkpoint # E03: free=3968, used=64 + -> heap4_alloc_c_checkpoint # E04: free=3936, used=32 + -> heap4_free_a_checkpoint # E05: free=3984, blocks=2 + -> heap4_fragmented_checkpoint # E06: free=4016, blocks=2 + -> heap4_coalesced_checkpoint # E07: free=4080, blocks=1 + -> task03_debug_checkpoint # E08: OOM, hook, PASS \end{lstlisting} -\textbf{STOP 1:} zapisz liczbę bloków, sumę i largest. Przed \texttt{F5} -przewidź, co zmieni \texttt{FREE B}. - -\textbf{STOP 2:} sprawdź odzyskanie areny, minimum-ever, OOM i hook. +\textbf{E01--E04:} sprawdź, że zużycie obejmuje wyrównany nagłówek całego +bloku, a nie tylko payload. \textbf{E05--E06:} porównaj sumę wolną z largest. +Przed przejściem z E06 do E07 ustaw tymczasowy breakpoint na +\texttt{prvInsertBlockIntoFreeList()} i sprawdź oba testy sąsiedztwa. +\textbf{E07--E08:} potwierdź odzyskanie areny, minimum-ever, OOM i hook. \newpage \section{Dowód na Pico 2 W / RP2350} @@ -248,11 +253,14 @@ realną pamięć SRAM, w której obserwujemy ten sam algorytm. \begin{lstlisting} p g_fragmented_stats p g_final_stats +p g_a_consumed +p g_b_consumed +p g_c_consumed p xFreeBytesRemaining p xMinimumEverFreeBytesRemaining p xStart p pxEnd -x/96bx ucHeap +x/160bx ucHeap \end{lstlisting} \subsection*{Tabela obserwacji} @@ -263,10 +271,10 @@ Wielkość & Odczyt & Warunek \\ \midrule \texttt{initial\_free} & \blank{2.3cm} & punkt odniesienia \\ \texttt{after\_allocations} & \blank{2.3cm} & mniejsze niż initial \\ -STOP 1: free blocks & \blank{2.3cm} & równe 2 \\ -STOP 1: total / largest & \blank{2.3cm} & largest mniejsze niż total \\ -STOP 2: final free & \blank{2.3cm} & równe initial \\ -STOP 2: free blocks & \blank{2.3cm} & równe 1 \\ +E06: free blocks & \blank{2.3cm} & równe 2 \\ +E06: total / largest & \blank{2.3cm} & largest mniejsze niż total \\ +E07: final free & \blank{2.3cm} & równe initial \\ +E07: free blocks & \blank{2.3cm} & równe 1 \\ minimum-ever & \blank{2.3cm} & nie rośnie po free \\ OOM / hook / asserts / pass & \blank{2.3cm} & \texttt{1 / 1 / 0 / 1} \\ \bottomrule diff --git a/doc/pdf/mpabi-inf-freertos-c-01-heap4-mechanics-v00.01-87e48095-7793-54e3-9230-4e61d31bd459.pdf b/doc/pdf/mpabi-inf-freertos-c-01-heap4-mechanics-v00.01-87e48095-7793-54e3-9230-4e61d31bd459.pdf index 6f53776..83da598 100644 Binary files a/doc/pdf/mpabi-inf-freertos-c-01-heap4-mechanics-v00.01-87e48095-7793-54e3-9230-4e61d31bd459.pdf and b/doc/pdf/mpabi-inf-freertos-c-01-heap4-mechanics-v00.01-87e48095-7793-54e3-9230-4e61d31bd459.pdf differ diff --git a/doc/stan-prac.md b/doc/stan-prac.md index b29a965..83771cd 100644 --- a/doc/stan-prac.md +++ b/doc/stan-prac.md @@ -1,133 +1,51 @@ -# K01 `heap4` — punkt zatrzymania +# FC01 `heap_4` — stan weryfikacji -## Stan repozytorium +## Stan na 2026-07-20 -- Data: `2026-07-14`. -- Commit bazowy: `8aee0b104c4f6e6ffef119ab6f57a3e724144221`. -- Gałąź robocza: `work/list-first-rp2350-debug`. -- Zmienione źródła: brak. -- Zmieniona karta PDF: brak. -- Lokalny stan `.stem/`: wygenerowany przez testy `stemctl`, nie jest częścią karty. -- Review Claude: nieukończony; dwie sesje CLI nie zwróciły wyniku i zostały zatrzymane. +Karta ma jeden centralny eksperyment na niezmodyfikowanym +`heap_4.c` z FreeRTOS-Kernel V11.3.0. Przebieg jest podzielony na osiem +deterministycznych checkpointów E01–E08 i działa na RV32I/Hazard3. -## Potwierdzone +## Potwierdzone na Hazard3 -- [x] `make host` buduje 10/10 programów. -- [x] Wszystkie programy hostowe uruchamiają się z kodem `0`. -- [x] `make tasks RV_ENV_ROOT=...` buduje 10/10 ELF dla RV32I. -- [x] `stemctl test native-amd64 freertos heap4 10` przechodzi. -- [x] RP2350 Probe jest wykrywany bez `sudo` po wejściu do grupy `rpdebug`. -- [x] OpenOCD wykrywa `rp2350.rv0` i `rp2350.rv1`. -- [x] Oba rdzenie raportują `XLEN=32`. -- [ ] Nie wykonano testu programu K01 na RTL Hazard3. -- [ ] Nie wgrano programu K01 na fizyczny RP2350. +| Event | Stan | Dowód | +|---|---|---| +| E01 | arena po inicjalizacji | `free=largest=4080`, 1 blok | +| E02 | `alloc A(24)` | zużyto 48, zostało 4032 | +| E03 | `alloc B(40)` | zużyto 64, zostało 3968 | +| E04 | `alloc C(16)` | zużyto 32, zostało 3936 | +| E05 | `free(A)` | 3984, 2 wolne bloki | +| E06 | `free(C)` | 4016, 2 bloki, `free > largest` | +| E07 | `free(B)` | `free=largest=4080`, 1 blok | +| E08 | kontrolowany OOM | `NULL`, hook=1, asserts=0, PASS=1 | -## Wyniki bazowe — host AMD64 +Na RV32 `sizeof(BlockLink_t) == 8`, ale `portBYTE_ALIGNMENT == 16`, więc +prywatne `xHeapStructSize == 16`. To wyjaśnia zużycie 48/64/32 bajtów. -| Task | Wynik | -|---|---| -| 01 | `header=16 aligned=16 allocated=1 total=32 user=16` | -| 02 | `free=136 largest=80 count=3` | -| 03 | `offset=0 free=144 end_last=1` | -| 04 | `r1=24 r9=32 r17=40 delta=7` | -| 05 | `ok=1 allocated=120 remaining=0` | -| 06 | `allocated=48 split=128 nodes=1` | -| 07 | `order=1 count=3 total=120` | -| 08 | `count=1 size=160 merged_right=1` | -| 09 | `heap=256 adjusted=248 dynamic=1 host_trace=1` | -| 10 | `ok=1 nodes=1 free=240 min=144` | +## Diagramy i iteracja -## Braki P0 +- A1 CONTEXT: pięć kroków CODE — granice odpowiedzialności. +- A2 STRUCTURE: jeden krok CODE i pięć kroków RUN — nagłówek, split, + lista adresowa oraz scalenie lewego i prawego sąsiada. +- A5 FLOW: osiem kroków RUN mapowanych 1:1 na E01–E08. +- A6 STATE: pięć reprezentatywnych stanów E01, E04, E06, E07 i E08. +- A7 RUNTIME: tożsamość źródła/ELF, pamięć `ucHeap` i końcowy werdykt. +- A3, A4 i A8 są jawnie pominięte, ponieważ dublowałyby A2/A5. -- [ ] Dodać `stem-card.yaml`. -- [ ] Obsłużyć targety: - - [ ] `native` / `native-amd64`; - - [ ] `hazard3-baremetal` / `hazard3-sim`; - - [ ] `rp2350-rv` / fizyczny Hazard3. -- [ ] Naprawić `stemctl test hazard3-sim freertos heap4 10`. - - Stan obecny: `Legacy Hazard3 card/task is unsupported`. -- [ ] Dodać asercje wyniku. - - Stan obecny: każdy `main()` zwraca `0` niezależnie od wartości `g_*`. -- [ ] Dodać automatyczne porównanie wyników AMD64 i RV32. -- [ ] Dodać bezpieczne sprawdzanie przepełnienia rozmiaru żądania. -- [ ] Sprawdzić wyrównanie buforów używanych jako `HeapBlock`. -- [ ] Nie dereferencjonować wyniku alokacji przed sprawdzeniem `p != NULL`. +Szczegółowa kolejność komend, obserwacji i kryteriów znajduje się w +[`hazard3-iteration-plan.md`](hazard3-iteration-plan.md). -## Braki debug +## Wykonane testy -- [ ] K10: dodać jawne checkpointy: - - [ ] `INIT`; - - [ ] `ALLOC_A`; - - [ ] `ALLOC_B`; - - [ ] `FREE_A`; - - [ ] `ALLOC_C`; - - [ ] `ALLOC_REJECTED`; - - [ ] `FREE_B`; - - [ ] `FREE_C`; - - [ ] `DONE`. -- [ ] K10: zapisywać przy checkpointcie: - - [ ] numer zdarzenia; - - [ ] adres bloku; - - [ ] liczbę wolnych bloków; - - [ ] sumę wolnej pamięci; - - [ ] minimum wolnej pamięci; - - [ ] status `RUNNING/PASS/FAIL`. -- [ ] Simulator: - - [ ] breakpoint na funkcji checkpointu; - - [ ] inspekcja listy i pamięci; - - [ ] bez obiecywania watchpointów — szybki stub obsługuje obecnie breakpointy wykonania. -- [ ] RP2350: - - [ ] OpenOCD `target/rp2350-riscv.cfg`; - - [ ] breakpoint `main`; - - [ ] sprzętowy watchpoint na numerze zdarzenia/statusie; - - [ ] porównanie adresów i wyników z symulatorem; - - [ ] Termdebug i DAP na tym samym ELF. +- testy hostowe Task 1–3; +- budowa RV32I i kontrola symboli ELF; +- Hazard3 RTL: zakończenie kodem 0 po 27308 cyklach; +- osiem checkpointów obecnych w ELF; +- walidacja JSON i odwołań `code_ref`/`snapshot_ref`; +- kontrola PlantUML, SVG, HTML, TeX i siedmiostronicowego PDF; +- TypeScript/React typecheck generatora. -## Braki materiału - -- [ ] Zmniejszyć udział prozy. -- [ ] Zastąpić akapity: - - [ ] listami kontrolnymi; - - [ ] tabelami wartości; - - [ ] komendami do skopiowania; - - [ ] punktami zatrzymania GDB; - - [ ] kryteriami zaliczenia. -- [ ] Szablon każdego taska: - - [ ] `Cel` — maksymalnie 3 punkty; - - [ ] `Uruchom` — komendy; - - [ ] `Zatrzymaj` — breakpoint/watchpoint; - - [ ] `Obserwuj` — symbole i pamięć; - - [ ] `Oczekuj` — wartości host/RV32; - - [ ] `Zmień` — jeden eksperyment; - - [ ] `Zaliczenie` — mierzalna checklista. -- [ ] Przenieść pełne listingi C/ASM do dodatku. -- [ ] Pierwsze strony PDF przeznaczyć na kartę prowadzącego i przebieg lekcji. - -## Kolejność wznowienia K01 - -1. Zamknąć wymagania w bezpośrednim poprzedniku `inf/structures`. -2. Dodać testy wyniku do K01. -3. Dodać kontrakt `stem-card.yaml`. -4. Uruchomić 10/10 tasków na Hazard3 RTL. -5. Dodać checkpointy K10. -6. Zbudować K10 dla `rp2350-rv`. -7. Wgrać i debugować K10 przez JTAG. -8. Przebudować README/PDF do formatu list-first. -9. Wykonać końcowy review techniczny i dydaktyczny. - -## Bezpośredni poprzednik - -- Seria: `inf`. -- Karta: `structures`. -- Repozytorium: `lab-rv32i-c-structures`. -- Przejście wymagane przed K01: - - [ ] `struct` i `typedef`; - - [ ] struktura samoreferencyjna; - - [ ] pole `next`; - - [ ] przejście po liście; - - [ ] wstawianie elementu; - - [ ] wartownik; - - [ ] `sizeof`, padding i wyrównanie na AMD64/RV32; - - [ ] niezmienniki listy; - - [ ] obserwacja w GDB. +## Pozostaje poza zakresem tej iteracji +- próba na fizycznym RP2350/Pico 2 W; +- commit i publikacja — wymagają osobnego polecenia. diff --git a/json/card_source.json b/json/card_source.json index 9decc8c..d5e6d3d 100644 --- a/json/card_source.json +++ b/json/card_source.json @@ -17,7 +17,7 @@ "status": "Gotowa", "version": "v00.01", "uuid": "87e48095-7793-54e3-9230-4e61d31bd459", - "author": "M. Pabiszczak", + "author": "Mateusz Pabiszczak", "year": "2026" }, "generated": { @@ -39,7 +39,7 @@ { "id": "A2", "label": "STRUCTURE", - "subtitle": "headers and address order", + "subtitle": "RV32 header, split and address order", "status": "enabled", "target_label": "fig:a2-structure" }, @@ -55,7 +55,7 @@ "label": "APPLICATION", "subtitle": "experiment is already explicit", "status": "unavailable", - "reason": "The concrete A/B/C allocation experiment is completely represented by A5 and its two runtime checkpoints." + "reason": "The concrete A/B/C allocation experiment is completely represented by the eight-state replay in A5." }, { "id": "A5", @@ -87,35 +87,37 @@ } ], "debug_strategies": { - "code.model": { - "id": "code.model", + "code.boundary": { + "id": "code.boundary", "kind": "code", "action": "open", "expected_observations": [ - "requested size includes header and alignment", - "free list is ordered by block address" + "application code calls only the public FreeRTOS allocation API", + "the selected heap implementation is linked below that API" ], "assertions": [ - "payload begins after the header", - "split preserves the total arena size" + "the application never edits allocator metadata", + "Hazard3 observes the same ucHeap object named by the ELF" ], "evidence_fields": [ "code_ref", - "header bytes", - "wanted bytes", - "block address" + "public symbol", + "arena symbol", + "target profile" ], "prerequisites": [ "K&R 5.4 linear allocator complete" ], "layout": [ - "header", - "payload", - "remainder", - "address-ordered list" + "application", + "FreeRTOS API", + "heap_4", + "ucHeap", + "Hazard3" ], "commands": [ - "rg -n 'ModelBlock|align_up|insert_and_coalesce' src/tasks" + "rg -n 'pvPortMalloc|vPortFree|vPortGetHeapStats|ucHeap' src/tasks/task03_freertos_heap4.c", + "rg -n 'TASK03_KERNEL_SOURCES|HEAP4_SOURCE' Makefile" ] }, "code.heap4": { @@ -146,7 +148,45 @@ "pxEnd" ], "commands": [ - "rg -n 'BlockLink_t|prvInsertBlockIntoFreeList|pvPortMalloc|vPortFree' vendor/FreeRTOS-Kernel/portable/MemMang/heap_4.c" + "rg -n 'BlockLink_t|prvHeapInit|prvInsertBlockIntoFreeList|pvPortMalloc|vPortFree' ${FREERTOS_KERNEL_PATH:-/opt/FreeRTOS-Kernel}/portable/MemMang/heap_4.c" + ] + }, + "run.timeline": { + "id": "run.timeline", + "kind": "run", + "action": "replay", + "expected_observations": [ + "every checkpoint is reached from a clean reset with the same ELF", + "free bytes change by the aligned whole-block size, not by payload alone" + ], + "assertions": [ + "A, B and C are aligned", + "the free-byte sequence is strictly decreasing during allocation" + ], + "evidence_fields": [ + "payload pointer", + "consumed bytes", + "available bytes", + "free-list statistics" + ], + "prerequisites": [ + "clean Hazard3 RAM", + "task03 image loaded" + ], + "layout": [ + "current checkpoint", + "source call", + "heap statistics", + "ucHeap memory" + ], + "commands": [ + "print g_initial_free", + "print g_after_a_free", + "print g_after_b_free", + "print g_after_allocations", + "print g_a_consumed", + "print g_b_consumed", + "print g_c_consumed" ] }, "run.fragmented": { @@ -180,7 +220,43 @@ "commands": [ "break heap4_fragmented_checkpoint", "print g_fragmented_stats", - "x/64bx ucHeap" + "print g_fragmented_free", + "x/96bx ucHeap" + ] + }, + "run.coalescing": { + "id": "run.coalescing", + "kind": "run", + "action": "replay", + "expected_observations": [ + "the replay stops after free(C), immediately before free(B)", + "inside prvInsertBlockIntoFreeList the previous block is merged before the next block" + ], + "assertions": [ + "pxIterator < pxBlockToInsert < pxIterator->pxNextFreeBlock", + "the left adjacency test is evaluated before the right adjacency test" + ], + "evidence_fields": [ + "pxIterator", + "pxBlockToInsert", + "left end address", + "right start address" + ], + "prerequisites": [ + "task01.fragmented replay ready" + ], + "layout": [ + "application call vPortFree(g_b)", + "prvInsertBlockIntoFreeList", + "free-list links", + "ucHeap addresses" + ], + "commands": [ + "tbreak prvInsertBlockIntoFreeList", + "continue", + "print pxIterator", + "print pxBlockToInsert", + "next" ] }, "run.coalesced": { @@ -193,15 +269,14 @@ ], "assertions": [ "final free equals initial free", - "minimum-ever does not rise after free", - "oversized allocation returns NULL and calls the hook once" + "one free block is also the largest block", + "minimum-ever does not rise after free" ], "evidence_fields": [ "final free", "largest block", "minimum-ever", - "OOM hook", - "PASS" + "free blocks" ], "prerequisites": [ "fragmented checkpoint reached" @@ -213,8 +288,46 @@ "PASS" ], "commands": [ - "break task03_debug_checkpoint", + "break heap4_coalesced_checkpoint", "print g_final_stats", + "print g_final_free", + "print g_minimum_ever_free" + ] + }, + "run.verified": { + "id": "run.verified", + "kind": "run", + "action": "replay", + "expected_observations": [ + "the oversized request returns NULL", + "the malloc-failed hook runs once without corrupting the recovered arena" + ], + "assertions": [ + "g_oom_is_null equals 1", + "g_malloc_failed_hooks equals 1", + "g_assert_failures equals 0", + "g_task03_pass equals 1" + ], + "evidence_fields": [ + "OOM result", + "hook count", + "assert count", + "PASS" + ], + "prerequisites": [ + "coalesced checkpoint reproducible" + ], + "layout": [ + "final stats", + "OOM result", + "hook", + "PASS" + ], + "commands": [ + "break task03_debug_checkpoint", + "print g_too_large", + "print g_malloc_failed_hooks", + "print g_assert_failures", "print g_task03_pass" ] }, @@ -228,7 +341,8 @@ ], "assertions": [ "pvPortMalloc and vPortFree are present", - "prvInsertBlockIntoFreeList is present" + "prvInsertBlockIntoFreeList is present", + "all eight replay checkpoint symbols are present" ], "evidence_fields": [ "source blob", @@ -252,7 +366,7 @@ "template": "templates/karta-klasyczna.json", "title_block": { "category": "KARTA PRACY · INFORMATYKA", - "prepared_by": "M. Pabiszczak", + "prepared_by": "Mateusz Pabiszczak", "prepared_on": "2026-07-20T00:00:00+02:00", "title": "heap_4: From Linear Cursor to Reusable Blocks", "url": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/aea09ab7-9bfd-5368-8d1b-c8724871c1a7", @@ -328,7 +442,7 @@ "FC01.EK01": { "bloom_level": "Zastosowanie", "label": "Fragmentacja i odzyskanie areny", - "text": "Uczeń odtwarza dwa checkpointy Hazard3 i odróżnia current free, largest free block oraz minimum-ever.", + "text": "Uczeń odtwarza osiem checkpointów Hazard3 i odróżnia current free, largest free block oraz minimum-ever.", "assessment_criteria": [ "FC01.KW01" ] @@ -336,7 +450,7 @@ }, "assessment_criteria": { "FC01.KW01": { - "text": "Model 13 -> 32 bajty; poprawna predykcja dwóch wolnych bloków po free(A,C) i jednego po free(B); final free = initial free; minimum-ever nie rośnie; OOM zwraca NULL; PASS=1.", + "text": "Na RV32 BlockLink_t ma 8 bajtów, lecz 16-bajtowe wyrównanie portu daje xHeapStructSize=16; A/B/C zużywają 48/64/32 bajty; po free(A,C) są dwa wolne bloki, po free(B) jeden; final free = initial free; minimum-ever nie rośnie; OOM zwraca NULL; PASS=1.", "learning_effects": [ "FC01.EN01", "FC01.EK01" @@ -386,7 +500,7 @@ "local": "01", "kind": "EK", "tree_id": "FC01.WE01.TECH.LOCAL.RTOS.01", - "text": "Uczeń odtwarza dwa checkpointy Hazard3 i odróżnia current free, largest free block oraz minimum-ever.", + "text": "Uczeń odtwarza osiem checkpointów Hazard3 i odróżnia current free, largest free block oraz minimum-ever.", "kw": [ { "criterion_ref": "FC01.KW01", @@ -408,11 +522,11 @@ "semantics": "deterministic-replay", "artifact": { "source": "src/tasks/task03_freertos_heap4.c", - "source_git_blob": "a73eb936ad3896bc212fe7fcc1e9918e4430746e", + "source_git_blob": "14ee8fedf1eec198c6b373e2805e07825c3fd0ed", "elf": "build/task03_freertos_heap4/prog.elf", - "hazard3_elf_sha256": "6a7b20ad3447d0877e7ecff39087653e32f4931e2364bdc2ea533bf5d70f7854", + "hazard3_elf_sha256": "91af9f1169945abe4b16037ded2b8047253bf33f4ea6823f46a427ec17d3d4fa", "hazard3_image": "build/task03_freertos_heap4/prog.bin", - "hazard3_image_sha256": "c9d9b45546305671fa6172156fbfc58b90b145fe952e3b7cfe8cce0da0f5e7dd" + "hazard3_image_sha256": "0d943814bb518fefda254f1cdf3771e4104ba1ad9e5f31bb04e672b5015ce31a" }, "targets": { "hazard3-sim": { @@ -422,8 +536,151 @@ } }, "items": { - "task01.fragmented": { + "task01.reset": { "event_id": "E01", + "stop": { + "symbol": "heap4_reset_checkpoint", + "offset": 0 + }, + "verify": { + "expressions": [ + { + "expr": "g_initial_stats.xNumberOfFreeBlocks", + "equals": 1 + }, + { + "expr": "g_initial_stats.xSizeOfLargestFreeBlockInBytes == g_initial_free", + "equals": 1 + }, + { + "expr": "g_initial_free", + "equals": 4080 + } + ] + } + }, + "task01.alloc-a": { + "event_id": "E02", + "stop": { + "symbol": "heap4_alloc_a_checkpoint", + "offset": 0 + }, + "verify": { + "expressions": [ + { + "expr": "g_a != 0", + "equals": 1 + }, + { + "expr": "g_a_aligned", + "equals": 1 + }, + { + "expr": "g_a_consumed", + "equals": 48 + }, + { + "expr": "g_after_a_stats.xNumberOfFreeBlocks", + "equals": 1 + }, + { + "expr": "g_after_a_free", + "equals": 4032 + } + ] + } + }, + "task01.alloc-b": { + "event_id": "E03", + "stop": { + "symbol": "heap4_alloc_b_checkpoint", + "offset": 0 + }, + "verify": { + "expressions": [ + { + "expr": "g_b != 0", + "equals": 1 + }, + { + "expr": "g_b_aligned", + "equals": 1 + }, + { + "expr": "g_b_consumed", + "equals": 64 + }, + { + "expr": "g_after_b_free < g_after_a_free", + "equals": 1 + }, + { + "expr": "g_after_b_free", + "equals": 3968 + } + ] + } + }, + "task01.alloc-c": { + "event_id": "E04", + "stop": { + "symbol": "heap4_alloc_c_checkpoint", + "offset": 0 + }, + "verify": { + "expressions": [ + { + "expr": "g_c != 0", + "equals": 1 + }, + { + "expr": "g_c_aligned", + "equals": 1 + }, + { + "expr": "g_c_consumed", + "equals": 32 + }, + { + "expr": "g_allocations_aligned", + "equals": 1 + }, + { + "expr": "g_after_allocations", + "equals": 3936 + } + ] + } + }, + "task01.free-a": { + "event_id": "E05", + "stop": { + "symbol": "heap4_free_a_checkpoint", + "offset": 0 + }, + "verify": { + "expressions": [ + { + "expr": "g_after_free_a_stats.xNumberOfFreeBlocks", + "equals": 2 + }, + { + "expr": "g_after_free_a == g_after_allocations + g_a_consumed", + "equals": 1 + }, + { + "expr": "g_after_free_a_stats.xAvailableHeapSpaceInBytes > g_after_free_a_stats.xSizeOfLargestFreeBlockInBytes", + "equals": 1 + }, + { + "expr": "g_after_free_a", + "equals": 3984 + } + ] + } + }, + "task01.fragmented": { + "event_id": "E06", "stop": { "symbol": "heap4_fragmented_checkpoint", "offset": 0 @@ -435,20 +692,24 @@ "equals": 2 }, { - "expr": "g_initial_free > g_after_allocations", + "expr": "g_fragmented_free == g_after_free_a + g_c_consumed", "equals": 1 }, { - "expr": "g_allocations_aligned", + "expr": "g_fragmented_stats.xAvailableHeapSpaceInBytes > g_fragmented_stats.xSizeOfLargestFreeBlockInBytes", "equals": 1 + }, + { + "expr": "g_fragmented_free", + "equals": 4016 } ] } }, "task01.coalesced": { - "event_id": "E02", + "event_id": "E07", "stop": { - "symbol": "task03_debug_checkpoint", + "symbol": "heap4_coalesced_checkpoint", "offset": 0 }, "verify": { @@ -461,13 +722,48 @@ "expr": "g_final_free == g_initial_free", "equals": 1 }, + { + "expr": "g_final_stats.xSizeOfLargestFreeBlockInBytes == g_initial_free", + "equals": 1 + }, + { + "expr": "g_minimum_ever_free <= g_after_allocations", + "equals": 1 + }, + { + "expr": "g_final_free", + "equals": 4080 + } + ] + } + }, + "task01.verified": { + "event_id": "E08", + "stop": { + "symbol": "task03_debug_checkpoint", + "offset": 0 + }, + "verify": { + "expressions": [ { "expr": "g_oom_is_null", "equals": 1 }, + { + "expr": "g_malloc_failed_hooks", + "equals": 1 + }, + { + "expr": "g_assert_failures", + "equals": 0 + }, { "expr": "g_task03_pass", "equals": 1 + }, + { + "expr": "g_rv32_layout_expected", + "equals": 1 } ] } @@ -529,9 +825,9 @@ "number": 1, "label": "aplikacja żąda i zwalnia bajty", "mode": "CODE", - "strategy_ref": "code.heap4", + "strategy_ref": "code.boundary", "svg_label": "01", - "code_ref": "src/tasks/task03_freertos_heap4.c:78", + "code_ref": "src/tasks/task03_freertos_heap4.c:127", "description": "Aplikacja zna wyłącznie publiczne API i wskaźniki payloadu.", "evidence": "trzy żądania 24, 40 i 16 bajtów" }, @@ -540,9 +836,9 @@ "number": 2, "label": "FreeRTOS wystawia malloc, free i statystyki", "mode": "CODE", - "strategy_ref": "code.heap4", + "strategy_ref": "code.boundary", "svg_label": "02", - "code_ref": "src/tasks/task03_freertos_heap4.c:90", + "code_ref": "src/tasks/task03_freertos_heap4.c:127", "description": "API oddziela eksperyment od prywatnej listy bloków.", "evidence": "pvPortMalloc, vPortFree, vPortGetHeapStats" }, @@ -553,16 +849,16 @@ "mode": "CODE", "strategy_ref": "code.heap4", "svg_label": "03", - "code_ref": "src/tasks/task03_freertos_heap4.c:70", - "description": "Prywatny mechanizm wybiera, dzieli i scala wolne bloki.", - "evidence": "reset i inicjalizacja listy" + "code_ref": "UPSTREAM.md:1", + "description": "Prywatny mechanizm wybiera, dzieli i scala wolne bloki; strategia otwiera prawdziwy heap_4.c.", + "evidence": "prvHeapInit i prvInsertBlockIntoFreeList" }, { "id": "arena", "number": 4, "label": "ucHeap jest jedną ograniczoną areną", "mode": "CODE", - "strategy_ref": "code.heap4", + "strategy_ref": "code.boundary", "svg_label": "04", "code_ref": "src/tasks/task03_freertos_heap4.c:11", "description": "Metadane i payload znajdują się w tej samej statycznej tablicy.", @@ -614,8 +910,8 @@ "alignment": 1, "split": 1, "address-order": 1, - "right-join": 1, - "left-join": 1 + "left-join": 1, + "right-join": 1 } }, "interactive": { @@ -639,68 +935,78 @@ { "id": "header", "number": 1, - "label": "nagłówek przechowuje next i size", + "label": "nagłówek RV32 przechowuje next i size", "mode": "CODE", - "strategy_ref": "code.model", + "strategy_ref": "code.heap4", "svg_label": "01", - "code_ref": "src/tasks/heap4_model.h:11", - "description": "ModelBlock pokazuje minimalny kontrakt metadanych heap_4.", - "evidence": "dwa słowa metadanych" + "code_ref": "UPSTREAM.md:1", + "description": "Prawdziwy BlockLink_t zawiera wskaźnik i size_t, po 4 bajty na RV32; port wyrównuje nagłówek do 16 bajtów.", + "evidence": "sizeof(BlockLink_t)=8; portBYTE_ALIGNMENT=16; xHeapStructSize=16" }, { "id": "alignment", "number": 2, - "label": "żądanie obejmuje nagłówek i wyrównanie", - "mode": "CODE", - "strategy_ref": "code.model", + "label": "A(24) obejmuje nagłówek i wyrównanie", + "mode": "RUN", + "event_id": "E02", + "strategy_ref": "run.timeline", "svg_label": "02", - "code_ref": "src/tasks/task01_first_fit_split.c:3", - "description": "13 bajtów payloadu zajmuje 32 bajty całego bloku.", - "evidence": "header=16, wanted=32" + "code_ref": "src/tasks/task03_freertos_heap4.c:137", + "snapshot_ref": "task01.alloc-a", + "description": "Różnica licznika wolnych bajtów mierzy cały blok, nie sam payload.", + "evidence": "g_a_consumed = 48; g_a_aligned = 1" }, { "id": "split", "number": 3, "label": "split pozostawia osobny wolny blok", - "mode": "CODE", - "strategy_ref": "code.model", + "mode": "RUN", + "event_id": "E02", + "strategy_ref": "run.timeline", "svg_label": "03", - "code_ref": "src/tasks/task01_first_fit_split.c:43", - "description": "Reszta zachowuje własny nagłówek i trafia na listę wolnych.", - "evidence": "32 + 224 = 256" + "code_ref": "src/tasks/task03_freertos_heap4.c:137", + "snapshot_ref": "task01.alloc-a", + "description": "Po pierwszym first-fit pozostała część areny nadal jest jednym wolnym blokiem.", + "evidence": "free = 4032; free blocks = 1" }, { "id": "address-order", "number": 4, "label": "lista jest uporządkowana rosnącymi adresami", - "mode": "CODE", - "strategy_ref": "code.model", + "mode": "RUN", + "event_id": "E06", + "strategy_ref": "run.fragmented", "svg_label": "04", - "code_ref": "src/tasks/task02_address_order_coalesce.c:29", + "code_ref": "src/tasks/task03_freertos_heap4.c:168", + "snapshot_ref": "task01.fragmented", "description": "Pozycja w liście ujawnia bezpośredniego poprzednika i następnika.", - "evidence": "previous < block < current" - }, - { - "id": "right-join", - "number": 5, - "label": "blok scala się z prawym sąsiadem", - "mode": "CODE", - "strategy_ref": "code.model", - "svg_label": "05", - "code_ref": "src/tasks/task02_address_order_coalesce.c:40", - "description": "Koniec zwalnianego bloku równy adresowi current oznacza ciągłość.", - "evidence": "block + size == current" + "evidence": "g_a < g_b < g_c; dwa wolne obszary" }, { "id": "left-join", + "number": 5, + "label": "heap_4 scala najpierw poprzedni blok", + "mode": "RUN", + "event_id": "E06", + "strategy_ref": "run.coalescing", + "svg_label": "05", + "code_ref": "src/tasks/task03_freertos_heap4.c:173", + "snapshot_ref": "task01.fragmented", + "description": "Replay E06, tymczasowy breakpoint i step w prywatnej funkcji pokazują pierwszy test ciągłości.", + "evidence": "previous + previous.size == inserted" + }, + { + "id": "right-join", "number": 6, - "label": "wynik scala się z lewym sąsiadem", - "mode": "CODE", - "strategy_ref": "code.model", + "label": "następnie scala prawy blok", + "mode": "RUN", + "event_id": "E06", + "strategy_ref": "run.coalescing", "svg_label": "06", - "code_ref": "src/tasks/task02_address_order_coalesce.c:48", - "description": "Drugi test domyka dwustronne scalanie w jeden blok.", - "evidence": "previous + size == block" + "code_ref": "src/tasks/task03_freertos_heap4.c:173", + "snapshot_ref": "task01.fragmented", + "description": "Drugi test wykorzystuje już powiększony lewy blok i domyka scalenie areny.", + "evidence": "merged + merged.size == current" } ] } @@ -715,7 +1021,7 @@ "content_kind": "prose", "asset_page_mode": "one-per-page", "page_orientation": "landscape", - "content_tex": "Uczeń najpierw przewiduje liczbę wolnych bloków. RUN odtwarza dwa stabilne stany: po zwolnieniu A i C oraz po zwolnieniu B.", + "content_tex": "Uczeń przewiduje układ bloków, a następnie odtwarza osiem deterministycznych stanów tego samego przebiegu Hazard3.", "assets": [ { "path": "assets/a5-flow.png", @@ -735,10 +1041,10 @@ "step_tiles": { "reset": 1, "alloc-a": 1, - "alloc-bc": 1, - "free-ac": 1, + "alloc-b": 1, + "alloc-c": 1, + "free-a": 1, "fragmented": 1, - "free-b": 1, "coalesced": 1, "oom": 1 } @@ -765,93 +1071,105 @@ "id": "reset", "number": 1, "label": "reset i inicjalizacja areny", - "mode": "CODE", - "strategy_ref": "code.heap4", + "mode": "RUN", + "event_id": "E01", + "strategy_ref": "run.timeline", "svg_label": "01", - "code_ref": "src/tasks/task03_freertos_heap4.c:70", - "description": "Pierwsze małe żądanie inicjalizuje sentinele i listę.", - "evidence": "initial free = 4080" + "code_ref": "src/tasks/task03_freertos_heap4.c:127", + "snapshot_ref": "task01.reset", + "description": "Próbne żądanie inicjalizuje sentinele; po jego zwolnieniu arena ma jeden blok.", + "evidence": "free = largest = 4080; blocks = 1" }, { "id": "alloc-a", "number": 2, "label": "first-fit przydziela A", - "mode": "CODE", - "strategy_ref": "code.heap4", + "mode": "RUN", + "event_id": "E02", + "strategy_ref": "run.timeline", "svg_label": "02", - "code_ref": "src/tasks/task03_freertos_heap4.c:78", + "code_ref": "src/tasks/task03_freertos_heap4.c:137", + "snapshot_ref": "task01.alloc-a", "description": "Pierwszy wystarczający blok zostaje rozdzielony.", - "evidence": "A payload = 24" + "evidence": "A=24; consumed=48; free=4032" }, { - "id": "alloc-bc", + "id": "alloc-b", "number": 3, - "label": "kolejne split tworzą B i C", - "mode": "CODE", - "strategy_ref": "code.heap4", + "label": "kolejny split tworzy B", + "mode": "RUN", + "event_id": "E03", + "strategy_ref": "run.timeline", "svg_label": "03", - "code_ref": "src/tasks/task03_freertos_heap4.c:79", - "description": "B i C zajmują kolejne fragmenty tego samego wolnego bloku.", - "evidence": "after allocations = 3952" + "code_ref": "src/tasks/task03_freertos_heap4.c:145", + "snapshot_ref": "task01.alloc-b", + "description": "B zajmuje następny fragment tej samej reszty.", + "evidence": "B=40; consumed=64; free=3968" }, { - "id": "free-ac", + "id": "alloc-c", "number": 4, - "label": "zwolnij A i C, pozostaw B", - "mode": "CODE", - "strategy_ref": "code.heap4", + "label": "trzeci split tworzy C", + "mode": "RUN", + "event_id": "E04", + "strategy_ref": "run.timeline", "svg_label": "04", - "code_ref": "src/tasks/task03_freertos_heap4.c:88", - "description": "C scala się z prawą resztą, ale B oddziela ją od A.", - "evidence": "dwa wolne bloki" + "code_ref": "src/tasks/task03_freertos_heap4.c:153", + "snapshot_ref": "task01.alloc-c", + "description": "A, B i C są wyrównane, a za nimi pozostaje jedna wolna reszta.", + "evidence": "C=16; consumed=32; free=3936" + }, + { + "id": "free-a", + "number": 5, + "label": "zwolnij A, pozostaw B i C", + "mode": "RUN", + "event_id": "E05", + "strategy_ref": "run.timeline", + "svg_label": "05", + "code_ref": "src/tasks/task03_freertos_heap4.c:163", + "snapshot_ref": "task01.free-a", + "description": "Wolny A i końcowa reszta są rozdzielone przez B i C.", + "evidence": "blocks=2; free=3984" }, { "id": "fragmented", - "number": 5, - "label": "checkpoint fragmentacji", - "mode": "RUN", - "event_id": "E01", - "strategy_ref": "run.fragmented", - "svg_label": "05", - "code_ref": "src/tasks/task03_freertos_heap4.c:91", - "snapshot_ref": "task01.fragmented", - "description": "GDB zatrzymuje program przy dwóch wolnych blokach.", - "evidence": "xNumberOfFreeBlocks = 2" - }, - { - "id": "free-b", "number": 6, - "label": "zwolnij B między dwoma sąsiadami", - "mode": "CODE", - "strategy_ref": "code.heap4", + "label": "zwolnij C, pozostaw B", + "mode": "RUN", + "event_id": "E06", + "strategy_ref": "run.fragmented", "svg_label": "06", - "code_ref": "src/tasks/task03_freertos_heap4.c:93", - "description": "Wstawienie adresowe umożliwia dwa testy ciągłości.", - "evidence": "A + B + C + reszta są ciągłe" + "code_ref": "src/tasks/task03_freertos_heap4.c:168", + "snapshot_ref": "task01.fragmented", + "description": "C scala się z prawą resztą, ale B nadal rozdziela dwa wolne obszary.", + "evidence": "blocks=2; free=4016; free>largest" }, { "id": "coalesced", "number": 7, - "label": "arena wraca do jednego bloku", + "label": "zwolnij B i scal oba sąsiednie bloki", "mode": "RUN", - "event_id": "E02", + "event_id": "E07", "strategy_ref": "run.coalesced", "svg_label": "07", - "code_ref": "src/tasks/task03_freertos_heap4.c:96", + "code_ref": "src/tasks/task03_freertos_heap4.c:173", "snapshot_ref": "task01.coalesced", - "description": "Finalne statystyki dowodzą pełnego odzyskania areny.", - "evidence": "final free = initial free; blocks = 1" + "description": "Scalenie lewego, a potem prawego sąsiada przywraca jeden blok.", + "evidence": "free=largest=initial=4080; blocks=1" }, { "id": "oom", "number": 8, "label": "zbyt duże żądanie kończy się NULL", - "mode": "CODE", - "strategy_ref": "code.heap4", + "mode": "RUN", + "event_id": "E08", + "strategy_ref": "run.verified", "svg_label": "08", - "code_ref": "src/tasks/task03_freertos_heap4.c:98", + "code_ref": "src/tasks/task03_freertos_heap4.c:179", + "snapshot_ref": "task01.verified", "description": "Kontrolowany OOM nie narusza listy i wywołuje hook dokładnie raz.", - "evidence": "NULL, hooks=1, asserts=0" + "evidence": "NULL; hooks=1; asserts=0; PASS=1" } ] } @@ -913,33 +1231,37 @@ "id": "free", "number": 1, "label": "wolny blok należy do listy", - "mode": "CODE", - "strategy_ref": "code.heap4", + "mode": "RUN", + "event_id": "E01", + "strategy_ref": "run.timeline", "svg_label": "01", - "code_ref": "src/tasks/task03_freertos_heap4.c:70", + "code_ref": "src/tasks/task03_freertos_heap4.c:127", + "snapshot_ref": "task01.reset", "description": "Stan początkowy zawiera jeden największy wolny blok.", - "evidence": "initial free = largest free" + "evidence": "initial free = largest free = 4080" }, { "id": "allocated", "number": 2, "label": "przydzielony blok znika z listy wolnych", - "mode": "CODE", - "strategy_ref": "code.heap4", + "mode": "RUN", + "event_id": "E04", + "strategy_ref": "run.timeline", "svg_label": "02", - "code_ref": "src/tasks/task03_freertos_heap4.c:78", + "code_ref": "src/tasks/task03_freertos_heap4.c:153", + "snapshot_ref": "task01.alloc-c", "description": "Payload jest wyrównany, a bieżąca wolna pamięć maleje.", - "evidence": "all payload pointers aligned" + "evidence": "all payload pointers aligned; free=3936" }, { "id": "fragmented-state", "number": 3, "label": "dwa wolne bloki nie są jednym dużym blokiem", "mode": "RUN", - "event_id": "E01", + "event_id": "E06", "strategy_ref": "run.fragmented", "svg_label": "03", - "code_ref": "src/tasks/task03_freertos_heap4.c:90", + "code_ref": "src/tasks/task03_freertos_heap4.c:168", "snapshot_ref": "task01.fragmented", "description": "Suma wolnego miejsca nie gwarantuje jednego dużego przydziału.", "evidence": "free blocks = 2" @@ -949,10 +1271,10 @@ "number": 4, "label": "scalenie przywraca jeden największy blok", "mode": "RUN", - "event_id": "E02", + "event_id": "E07", "strategy_ref": "run.coalesced", "svg_label": "04", - "code_ref": "src/tasks/task03_freertos_heap4.c:94", + "code_ref": "src/tasks/task03_freertos_heap4.c:173", "snapshot_ref": "task01.coalesced", "description": "Current free i largest wracają do wartości początkowej.", "evidence": "free blocks = 1" @@ -961,10 +1283,12 @@ "id": "minimum-ever", "number": 5, "label": "minimum-ever zachowuje najniższy poziom", - "mode": "CODE", - "strategy_ref": "code.heap4", + "mode": "RUN", + "event_id": "E08", + "strategy_ref": "run.verified", "svg_label": "05", - "code_ref": "src/tasks/task03_freertos_heap4.c:95", + "code_ref": "src/tasks/task03_freertos_heap4.c:179", + "snapshot_ref": "task01.verified", "description": "Historyczne minimum nie zwiększa się po odzyskaniu pamięci.", "evidence": "minimum-ever <= after allocations" } @@ -1017,7 +1341,7 @@ "block": { "id": "a7", "label": "A7 RUNTIME", - "description": "Ten sam artefakt łączy źródło, symbole ELF, dwa checkpointy, pamięć ucHeap i końcowe asercje." + "description": "Ten sam artefakt łączy źródło, symbole ELF, osiem checkpointów, pamięć ucHeap i końcowe asercje." }, "phases": [ { @@ -1031,7 +1355,7 @@ "mode": "CODE", "strategy_ref": "code.identity", "svg_label": "01", - "code_ref": "src/tasks/task03_freertos_heap4.c:62", + "code_ref": "src/tasks/task03_freertos_heap4.c:127", "description": "Blob źródła jest częścią tożsamości karty.", "evidence": "source git blob" }, @@ -1051,22 +1375,24 @@ "number": 3, "label": "checkpoint pokazuje dwa wolne bloki", "mode": "RUN", - "event_id": "E01", + "event_id": "E06", "strategy_ref": "run.fragmented", "svg_label": "03", - "code_ref": "src/tasks/task03_freertos_heap4.c:91", + "code_ref": "src/tasks/task03_freertos_heap4.c:168", "snapshot_ref": "task01.fragmented", "description": "Neovim, GDB i pamięć zatrzymują się na tym samym stanie.", - "evidence": "blocks=2 and aligned=1" + "evidence": "blocks=2 and free>largest" }, { "id": "memory", "number": 4, "label": "ucHeap ujawnia nagłówki i payload", - "mode": "CODE", - "strategy_ref": "code.heap4", + "mode": "RUN", + "event_id": "E06", + "strategy_ref": "run.fragmented", "svg_label": "04", "code_ref": "src/tasks/task03_freertos_heap4.c:11", + "snapshot_ref": "task01.fragmented", "description": "Widok bajtów łączy diagram z realnym układem areny.", "evidence": "aligned arena and in-band metadata" }, @@ -1075,11 +1401,11 @@ "number": 5, "label": "checkpoint końcowy dowodzi odzyskania", "mode": "RUN", - "event_id": "E02", - "strategy_ref": "run.coalesced", + "event_id": "E08", + "strategy_ref": "run.verified", "svg_label": "05", - "code_ref": "src/tasks/task03_freertos_heap4.c:111", - "snapshot_ref": "task01.coalesced", + "code_ref": "src/tasks/task03_freertos_heap4.c:179", + "snapshot_ref": "task01.verified", "description": "Jedna ramka łączy stats, OOM, hook i PASS.", "evidence": "final=initial, blocks=1, pass=1" } @@ -1103,8 +1429,8 @@ "task01": { "title": "Predict and prove reusable heap_4 blocks", "uuid": "aea09ab7-9bfd-5368-8d1b-c8724871c1a7", - "prompt_tex": "Przewidź układ bloków po alloc A/B/C, następnie po free(A,C) i free(B). Odtwórz oba checkpointy i udowodnij, że arena została scalona bez utraty minimum-ever.", - "criterion": "Model 13 -> 32 bajty; poprawna predykcja dwóch wolnych bloków po free(A,C) i jednego po free(B); final free = initial free; minimum-ever nie rośnie; OOM zwraca NULL; PASS=1.", + "prompt_tex": "Przewidź układ bloków po alloc A/B/C, następnie po free(A), free(C) i free(B). Odtwórz checkpointy E01--E08 i udowodnij, że arena została scalona bez utraty minimum-ever.", + "criterion": "Na RV32 BlockLink_t ma 8 bajtów, lecz 16-bajtowe wyrównanie portu daje xHeapStructSize=16; A/B/C zużywają 48/64/32 bajty; po free(A,C) są dwa wolne bloki, po free(B) jeden; final free = initial free; minimum-ever nie rośnie; OOM zwraca NULL; PASS=1.", "conclusion_tex": "heap\\_4 odzyskuje pamięć dzięki metadanym w arenie, adresowo uporządkowanej liście i scalaniu sąsiadów. Suma wolnych bajtów nie zastępuje informacji o największym bloku, a minimum-ever jest historią, nie bieżącym stanem.", "flow": [ { @@ -1115,8 +1441,8 @@ "steps": [ { "id": "size", - "title": "Policz rozmiar bloku.", - "content_tex": "Dodaj nagłówek do 13 bajtów i wyrównaj wynik do ośmiu." + "title": "Policz rozmiary całych bloków.", + "content_tex": "Rozróżnij surowy BlockLink\\_t (8 bajtów) od xHeapStructSize (16 bajtów), dodaj nagłówek do żądań 24, 40 i 16 bajtów, a następnie wyrównaj wynik do 16." }, { "id": "list", @@ -1129,17 +1455,22 @@ "kind": "block", "id": "replay", "title": "B — replay Hazard3", - "content_tex": "Powiąż diagram z dwoma deterministycznymi checkpointami.", + "content_tex": "Powiąż każdy stan diagramu z deterministycznym checkpointem E01--E08.", "steps": [ { - "id": "fragmented", - "title": "Sprawdź E01.", - "content_tex": "Porównaj liczbę wolnych bloków, największy blok i bieżące wolne bajty." + "id": "allocate", + "title": "Sprawdź E01--E04.", + "content_tex": "Potwierdź wartości 4080, 4032, 3968 i 3936 oraz zużycie 48/64/32 bajtów." }, { - "id": "coalesced", - "title": "Sprawdź E02.", - "content_tex": "Udowodnij pełne scalenie, zachowanie minimum-ever i kontrolowany OOM." + "id": "release", + "title": "Sprawdź E05--E07.", + "content_tex": "Porównaj liczbę wolnych bloków i udowodnij scalenie poprzedniego, a potem następnego sąsiada." + }, + { + "id": "verify", + "title": "Sprawdź E08.", + "content_tex": "Udowodnij zachowanie minimum-ever, kontrolowany OOM, brak asercji i PASS=1." } ] }, diff --git a/json/card_spec.json b/json/card_spec.json index 74ca110..383a9dc 100644 --- a/json/card_spec.json +++ b/json/card_spec.json @@ -22,7 +22,7 @@ { "id": "A2", "label": "STRUCTURE", - "subtitle": "headers and address order", + "subtitle": "RV32 header, split and address order", "status": "enabled" }, { @@ -37,7 +37,7 @@ "label": "APPLICATION", "subtitle": "experiment is already explicit", "status": "unavailable", - "reason": "The concrete A/B/C allocation experiment is completely represented by A5 and its two runtime checkpoints." + "reason": "The concrete A/B/C allocation experiment is completely represented by the eight-state replay in A5." }, { "id": "A5", @@ -72,50 +72,40 @@ }, "strategies": [ { - "id": "code.model", + "id": "code.boundary", "kind": "code", + "expected_observations": [ + "application code calls only the public FreeRTOS allocation API", + "the selected heap implementation is linked below that API" + ], + "assertions": [ + "the application never edits allocator metadata", + "Hazard3 observes the same ucHeap object named by the ELF" + ], + "evidence_fields": [ + "code_ref", + "public symbol", + "arena symbol", + "target profile" + ], "prerequisites": [ "K&R 5.4 linear allocator complete" ], "layout": [ - "header", - "payload", - "remainder", - "address-ordered list" + "application", + "FreeRTOS API", + "heap_4", + "ucHeap", + "Hazard3" ], "commands": [ - "rg -n 'ModelBlock|align_up|insert_and_coalesce' src/tasks" - ], - "expected_observations": [ - "requested size includes header and alignment", - "free list is ordered by block address" - ], - "assertions": [ - "payload begins after the header", - "split preserves the total arena size" - ], - "evidence_fields": [ - "code_ref", - "header bytes", - "wanted bytes", - "block address" + "rg -n 'pvPortMalloc|vPortFree|vPortGetHeapStats|ucHeap' src/tasks/task03_freertos_heap4.c", + "rg -n 'TASK03_KERNEL_SOURCES|HEAP4_SOURCE' Makefile" ] }, { "id": "code.heap4", "kind": "code", - "prerequisites": [ - "FreeRTOS-Kernel V11.3.0 available" - ], - "layout": [ - "ucHeap", - "BlockLink_t", - "xStart", - "pxEnd" - ], - "commands": [ - "rg -n 'BlockLink_t|prvInsertBlockIntoFreeList|pvPortMalloc|vPortFree' vendor/FreeRTOS-Kernel/portable/MemMang/heap_4.c" - ], "expected_observations": [ "heap_4 keeps metadata inside the arena", "free blocks form one address-ordered intrusive list" @@ -129,26 +119,60 @@ "list link", "block size", "arena address" + ], + "prerequisites": [ + "FreeRTOS-Kernel V11.3.0 available" + ], + "layout": [ + "ucHeap", + "BlockLink_t", + "xStart", + "pxEnd" + ], + "commands": [ + "rg -n 'BlockLink_t|prvHeapInit|prvInsertBlockIntoFreeList|pvPortMalloc|vPortFree' ${FREERTOS_KERNEL_PATH:-/opt/FreeRTOS-Kernel}/portable/MemMang/heap_4.c" ] }, { - "id": "run.fragmented", + "id": "run.timeline", "kind": "run", + "expected_observations": [ + "every checkpoint is reached from a clean reset with the same ELF", + "free bytes change by the aligned whole-block size, not by payload alone" + ], + "assertions": [ + "A, B and C are aligned", + "the free-byte sequence is strictly decreasing during allocation" + ], + "evidence_fields": [ + "payload pointer", + "consumed bytes", + "available bytes", + "free-list statistics" + ], "prerequisites": [ "clean Hazard3 RAM", "task03 image loaded" ], "layout": [ - "source", - "free-list stats", - "ucHeap memory", - "registers" + "current checkpoint", + "source call", + "heap statistics", + "ucHeap memory" ], "commands": [ - "break heap4_fragmented_checkpoint", - "print g_fragmented_stats", - "x/64bx ucHeap" - ], + "print g_initial_free", + "print g_after_a_free", + "print g_after_b_free", + "print g_after_allocations", + "print g_a_consumed", + "print g_b_consumed", + "print g_c_consumed" + ] + }, + { + "id": "run.fragmented", + "kind": "run", "expected_observations": [ "A and C are free while B remains allocated", "the free list contains two blocks" @@ -162,11 +186,76 @@ "largest block", "free bytes", "heap bytes" + ], + "prerequisites": [ + "clean Hazard3 RAM", + "task03 image loaded" + ], + "layout": [ + "source", + "free-list stats", + "ucHeap memory", + "registers" + ], + "commands": [ + "break heap4_fragmented_checkpoint", + "print g_fragmented_stats", + "print g_fragmented_free", + "x/96bx ucHeap" + ] + }, + { + "id": "run.coalescing", + "kind": "run", + "expected_observations": [ + "the replay stops after free(C), immediately before free(B)", + "inside prvInsertBlockIntoFreeList the previous block is merged before the next block" + ], + "assertions": [ + "pxIterator < pxBlockToInsert < pxIterator->pxNextFreeBlock", + "the left adjacency test is evaluated before the right adjacency test" + ], + "evidence_fields": [ + "pxIterator", + "pxBlockToInsert", + "left end address", + "right start address" + ], + "prerequisites": [ + "task01.fragmented replay ready" + ], + "layout": [ + "application call vPortFree(g_b)", + "prvInsertBlockIntoFreeList", + "free-list links", + "ucHeap addresses" + ], + "commands": [ + "tbreak prvInsertBlockIntoFreeList", + "continue", + "print pxIterator", + "print pxBlockToInsert", + "next" ] }, { "id": "run.coalesced", "kind": "run", + "expected_observations": [ + "freeing B joins both neighbours", + "the arena returns to one reusable block" + ], + "assertions": [ + "final free equals initial free", + "one free block is also the largest block", + "minimum-ever does not rise after free" + ], + "evidence_fields": [ + "final free", + "largest block", + "minimum-ever", + "free blocks" + ], "prerequisites": [ "fragmented checkpoint reached" ], @@ -177,30 +266,66 @@ "PASS" ], "commands": [ - "break task03_debug_checkpoint", + "break heap4_coalesced_checkpoint", "print g_final_stats", - "print g_task03_pass" - ], + "print g_final_free", + "print g_minimum_ever_free" + ] + }, + { + "id": "run.verified", + "kind": "run", "expected_observations": [ - "freeing B joins both neighbours", - "the arena returns to one reusable block" + "the oversized request returns NULL", + "the malloc-failed hook runs once without corrupting the recovered arena" ], "assertions": [ - "final free equals initial free", - "minimum-ever does not rise after free", - "oversized allocation returns NULL and calls the hook once" + "g_oom_is_null equals 1", + "g_malloc_failed_hooks equals 1", + "g_assert_failures equals 0", + "g_task03_pass equals 1" ], "evidence_fields": [ - "final free", - "largest block", - "minimum-ever", - "OOM hook", + "OOM result", + "hook count", + "assert count", "PASS" + ], + "prerequisites": [ + "coalesced checkpoint reproducible" + ], + "layout": [ + "final stats", + "OOM result", + "hook", + "PASS" + ], + "commands": [ + "break task03_debug_checkpoint", + "print g_too_large", + "print g_malloc_failed_hooks", + "print g_assert_failures", + "print g_task03_pass" ] }, { "id": "code.identity", "kind": "code", + "expected_observations": [ + "upstream heap_4 symbols are linked", + "checkpoint and ucHeap symbols remain observable" + ], + "assertions": [ + "pvPortMalloc and vPortFree are present", + "prvInsertBlockIntoFreeList is present", + "all eight replay checkpoint symbols are present" + ], + "evidence_fields": [ + "source blob", + "ELF SHA256", + "image SHA256", + "symbol" + ], "prerequisites": [ "built ELF" ], @@ -211,26 +336,155 @@ ], "commands": [ "tests/check_task03_elf.sh build/task03_freertos_heap4/prog.elf" - ], - "expected_observations": [ - "upstream heap_4 symbols are linked", - "checkpoint and ucHeap symbols remain observable" - ], - "assertions": [ - "pvPortMalloc and vPortFree are present", - "prvInsertBlockIntoFreeList is present" - ], - "evidence_fields": [ - "source blob", - "ELF SHA256", - "image SHA256", - "symbol" ] } ], "checkpoints": { - "task01.fragmented": { + "task01.reset": { "event_id": "E01", + "stop": { + "symbol": "heap4_reset_checkpoint", + "offset": 0 + }, + "verify": { + "expressions": [ + { + "expr": "g_initial_stats.xNumberOfFreeBlocks", + "equals": 1 + }, + { + "expr": "g_initial_stats.xSizeOfLargestFreeBlockInBytes == g_initial_free", + "equals": 1 + }, + { + "expr": "g_initial_free", + "equals": 4080 + } + ] + } + }, + "task01.alloc-a": { + "event_id": "E02", + "stop": { + "symbol": "heap4_alloc_a_checkpoint", + "offset": 0 + }, + "verify": { + "expressions": [ + { + "expr": "g_a != 0", + "equals": 1 + }, + { + "expr": "g_a_aligned", + "equals": 1 + }, + { + "expr": "g_a_consumed", + "equals": 48 + }, + { + "expr": "g_after_a_stats.xNumberOfFreeBlocks", + "equals": 1 + }, + { + "expr": "g_after_a_free", + "equals": 4032 + } + ] + } + }, + "task01.alloc-b": { + "event_id": "E03", + "stop": { + "symbol": "heap4_alloc_b_checkpoint", + "offset": 0 + }, + "verify": { + "expressions": [ + { + "expr": "g_b != 0", + "equals": 1 + }, + { + "expr": "g_b_aligned", + "equals": 1 + }, + { + "expr": "g_b_consumed", + "equals": 64 + }, + { + "expr": "g_after_b_free < g_after_a_free", + "equals": 1 + }, + { + "expr": "g_after_b_free", + "equals": 3968 + } + ] + } + }, + "task01.alloc-c": { + "event_id": "E04", + "stop": { + "symbol": "heap4_alloc_c_checkpoint", + "offset": 0 + }, + "verify": { + "expressions": [ + { + "expr": "g_c != 0", + "equals": 1 + }, + { + "expr": "g_c_aligned", + "equals": 1 + }, + { + "expr": "g_c_consumed", + "equals": 32 + }, + { + "expr": "g_allocations_aligned", + "equals": 1 + }, + { + "expr": "g_after_allocations", + "equals": 3936 + } + ] + } + }, + "task01.free-a": { + "event_id": "E05", + "stop": { + "symbol": "heap4_free_a_checkpoint", + "offset": 0 + }, + "verify": { + "expressions": [ + { + "expr": "g_after_free_a_stats.xNumberOfFreeBlocks", + "equals": 2 + }, + { + "expr": "g_after_free_a == g_after_allocations + g_a_consumed", + "equals": 1 + }, + { + "expr": "g_after_free_a_stats.xAvailableHeapSpaceInBytes > g_after_free_a_stats.xSizeOfLargestFreeBlockInBytes", + "equals": 1 + }, + { + "expr": "g_after_free_a", + "equals": 3984 + } + ] + } + }, + "task01.fragmented": { + "event_id": "E06", "stop": { "symbol": "heap4_fragmented_checkpoint", "offset": 0 @@ -242,20 +496,24 @@ "equals": 2 }, { - "expr": "g_initial_free > g_after_allocations", + "expr": "g_fragmented_free == g_after_free_a + g_c_consumed", "equals": 1 }, { - "expr": "g_allocations_aligned", + "expr": "g_fragmented_stats.xAvailableHeapSpaceInBytes > g_fragmented_stats.xSizeOfLargestFreeBlockInBytes", "equals": 1 + }, + { + "expr": "g_fragmented_free", + "equals": 4016 } ] } }, "task01.coalesced": { - "event_id": "E02", + "event_id": "E07", "stop": { - "symbol": "task03_debug_checkpoint", + "symbol": "heap4_coalesced_checkpoint", "offset": 0 }, "verify": { @@ -268,13 +526,48 @@ "expr": "g_final_free == g_initial_free", "equals": 1 }, + { + "expr": "g_final_stats.xSizeOfLargestFreeBlockInBytes == g_initial_free", + "equals": 1 + }, + { + "expr": "g_minimum_ever_free <= g_after_allocations", + "equals": 1 + }, + { + "expr": "g_final_free", + "equals": 4080 + } + ] + } + }, + "task01.verified": { + "event_id": "E08", + "stop": { + "symbol": "task03_debug_checkpoint", + "offset": 0 + }, + "verify": { + "expressions": [ { "expr": "g_oom_is_null", "equals": 1 }, + { + "expr": "g_malloc_failed_hooks", + "equals": 1 + }, + { + "expr": "g_assert_failures", + "equals": 0 + }, { "expr": "g_task03_pass", "equals": 1 + }, + { + "expr": "g_rv32_layout_expected", + "equals": 1 } ] } @@ -306,9 +599,9 @@ "number": 1, "label": "aplikacja żąda i zwalnia bajty", "mode": "CODE", - "strategy_ref": "code.heap4", + "strategy_ref": "code.boundary", "svg_label": "01", - "code_ref": "src/tasks/task03_freertos_heap4.c:78", + "code_ref": "src/tasks/task03_freertos_heap4.c:127", "description": "Aplikacja zna wyłącznie publiczne API i wskaźniki payloadu.", "evidence": "trzy żądania 24, 40 i 16 bajtów" }, @@ -317,9 +610,9 @@ "number": 2, "label": "FreeRTOS wystawia malloc, free i statystyki", "mode": "CODE", - "strategy_ref": "code.heap4", + "strategy_ref": "code.boundary", "svg_label": "02", - "code_ref": "src/tasks/task03_freertos_heap4.c:90", + "code_ref": "src/tasks/task03_freertos_heap4.c:127", "description": "API oddziela eksperyment od prywatnej listy bloków.", "evidence": "pvPortMalloc, vPortFree, vPortGetHeapStats" }, @@ -330,16 +623,16 @@ "mode": "CODE", "strategy_ref": "code.heap4", "svg_label": "03", - "code_ref": "src/tasks/task03_freertos_heap4.c:70", - "description": "Prywatny mechanizm wybiera, dzieli i scala wolne bloki.", - "evidence": "reset i inicjalizacja listy" + "code_ref": "UPSTREAM.md:1", + "description": "Prywatny mechanizm wybiera, dzieli i scala wolne bloki; strategia otwiera prawdziwy heap_4.c.", + "evidence": "prvHeapInit i prvInsertBlockIntoFreeList" }, { "id": "arena", "number": 4, "label": "ucHeap jest jedną ograniczoną areną", "mode": "CODE", - "strategy_ref": "code.heap4", + "strategy_ref": "code.boundary", "svg_label": "04", "code_ref": "src/tasks/task03_freertos_heap4.c:11", "description": "Metadane i payload znajdują się w tej samej statycznej tablicy.", @@ -385,68 +678,78 @@ { "id": "header", "number": 1, - "label": "nagłówek przechowuje next i size", + "label": "nagłówek RV32 przechowuje next i size", "mode": "CODE", - "strategy_ref": "code.model", + "strategy_ref": "code.heap4", "svg_label": "01", - "code_ref": "src/tasks/heap4_model.h:11", - "description": "ModelBlock pokazuje minimalny kontrakt metadanych heap_4.", - "evidence": "dwa słowa metadanych" + "code_ref": "UPSTREAM.md:1", + "description": "Prawdziwy BlockLink_t zawiera wskaźnik i size_t, po 4 bajty na RV32; port wyrównuje nagłówek do 16 bajtów.", + "evidence": "sizeof(BlockLink_t)=8; portBYTE_ALIGNMENT=16; xHeapStructSize=16" }, { "id": "alignment", "number": 2, - "label": "żądanie obejmuje nagłówek i wyrównanie", - "mode": "CODE", - "strategy_ref": "code.model", + "label": "A(24) obejmuje nagłówek i wyrównanie", + "mode": "RUN", + "event_id": "E02", + "strategy_ref": "run.timeline", "svg_label": "02", - "code_ref": "src/tasks/task01_first_fit_split.c:3", - "description": "13 bajtów payloadu zajmuje 32 bajty całego bloku.", - "evidence": "header=16, wanted=32" + "code_ref": "src/tasks/task03_freertos_heap4.c:137", + "snapshot_ref": "task01.alloc-a", + "description": "Różnica licznika wolnych bajtów mierzy cały blok, nie sam payload.", + "evidence": "g_a_consumed = 48; g_a_aligned = 1" }, { "id": "split", "number": 3, "label": "split pozostawia osobny wolny blok", - "mode": "CODE", - "strategy_ref": "code.model", + "mode": "RUN", + "event_id": "E02", + "strategy_ref": "run.timeline", "svg_label": "03", - "code_ref": "src/tasks/task01_first_fit_split.c:43", - "description": "Reszta zachowuje własny nagłówek i trafia na listę wolnych.", - "evidence": "32 + 224 = 256" + "code_ref": "src/tasks/task03_freertos_heap4.c:137", + "snapshot_ref": "task01.alloc-a", + "description": "Po pierwszym first-fit pozostała część areny nadal jest jednym wolnym blokiem.", + "evidence": "free = 4032; free blocks = 1" }, { "id": "address-order", "number": 4, "label": "lista jest uporządkowana rosnącymi adresami", - "mode": "CODE", - "strategy_ref": "code.model", + "mode": "RUN", + "event_id": "E06", + "strategy_ref": "run.fragmented", "svg_label": "04", - "code_ref": "src/tasks/task02_address_order_coalesce.c:29", + "code_ref": "src/tasks/task03_freertos_heap4.c:168", + "snapshot_ref": "task01.fragmented", "description": "Pozycja w liście ujawnia bezpośredniego poprzednika i następnika.", - "evidence": "previous < block < current" - }, - { - "id": "right-join", - "number": 5, - "label": "blok scala się z prawym sąsiadem", - "mode": "CODE", - "strategy_ref": "code.model", - "svg_label": "05", - "code_ref": "src/tasks/task02_address_order_coalesce.c:40", - "description": "Koniec zwalnianego bloku równy adresowi current oznacza ciągłość.", - "evidence": "block + size == current" + "evidence": "g_a < g_b < g_c; dwa wolne obszary" }, { "id": "left-join", + "number": 5, + "label": "heap_4 scala najpierw poprzedni blok", + "mode": "RUN", + "event_id": "E06", + "strategy_ref": "run.coalescing", + "svg_label": "05", + "code_ref": "src/tasks/task03_freertos_heap4.c:173", + "snapshot_ref": "task01.fragmented", + "description": "Replay E06, tymczasowy breakpoint i step w prywatnej funkcji pokazują pierwszy test ciągłości.", + "evidence": "previous + previous.size == inserted" + }, + { + "id": "right-join", "number": 6, - "label": "wynik scala się z lewym sąsiadem", - "mode": "CODE", - "strategy_ref": "code.model", + "label": "następnie scala prawy blok", + "mode": "RUN", + "event_id": "E06", + "strategy_ref": "run.coalescing", "svg_label": "06", - "code_ref": "src/tasks/task02_address_order_coalesce.c:48", - "description": "Drugi test domyka dwustronne scalanie w jeden blok.", - "evidence": "previous + size == block" + "code_ref": "src/tasks/task03_freertos_heap4.c:173", + "snapshot_ref": "task01.fragmented", + "description": "Drugi test wykorzystuje już powiększony lewy blok i domyka scalenie areny.", + "evidence": "merged + merged.size == current" } ] } @@ -461,7 +764,7 @@ "order": 50, "orientation": "landscape", "description": "Jeden przebieg A/B/C przechodzi od pustej areny przez trzy przydziały i dwa wolne obszary do ponownie scalonego bloku.", - "content_tex": "Uczeń najpierw przewiduje liczbę wolnych bloków. RUN odtwarza dwa stabilne stany: po zwolnieniu A i C oraz po zwolnieniu B.", + "content_tex": "Uczeń przewiduje układ bloków, a następnie odtwarza osiem deterministycznych stanów tego samego przebiegu Hazard3.", "assets": [ { "stem": "a5-flow", @@ -469,7 +772,6 @@ "caption": "A5 FLOW — inicjalizacja, A/B/C, fragmentacja, dwustronne scalenie i OOM.", "label": "fig:a5-flow", "alt": "A5 · pełny przebieg heap_4", - "diagram_kind": "sequence", "phases": [ { "id": "replay", @@ -479,97 +781,110 @@ "id": "reset", "number": 1, "label": "reset i inicjalizacja areny", - "mode": "CODE", - "strategy_ref": "code.heap4", + "mode": "RUN", + "event_id": "E01", + "strategy_ref": "run.timeline", "svg_label": "01", - "code_ref": "src/tasks/task03_freertos_heap4.c:70", - "description": "Pierwsze małe żądanie inicjalizuje sentinele i listę.", - "evidence": "initial free = 4080" + "code_ref": "src/tasks/task03_freertos_heap4.c:127", + "snapshot_ref": "task01.reset", + "description": "Próbne żądanie inicjalizuje sentinele; po jego zwolnieniu arena ma jeden blok.", + "evidence": "free = largest = 4080; blocks = 1" }, { "id": "alloc-a", "number": 2, "label": "first-fit przydziela A", - "mode": "CODE", - "strategy_ref": "code.heap4", + "mode": "RUN", + "event_id": "E02", + "strategy_ref": "run.timeline", "svg_label": "02", - "code_ref": "src/tasks/task03_freertos_heap4.c:78", + "code_ref": "src/tasks/task03_freertos_heap4.c:137", + "snapshot_ref": "task01.alloc-a", "description": "Pierwszy wystarczający blok zostaje rozdzielony.", - "evidence": "A payload = 24" + "evidence": "A=24; consumed=48; free=4032" }, { - "id": "alloc-bc", + "id": "alloc-b", "number": 3, - "label": "kolejne split tworzą B i C", - "mode": "CODE", - "strategy_ref": "code.heap4", + "label": "kolejny split tworzy B", + "mode": "RUN", + "event_id": "E03", + "strategy_ref": "run.timeline", "svg_label": "03", - "code_ref": "src/tasks/task03_freertos_heap4.c:79", - "description": "B i C zajmują kolejne fragmenty tego samego wolnego bloku.", - "evidence": "after allocations = 3952" + "code_ref": "src/tasks/task03_freertos_heap4.c:145", + "snapshot_ref": "task01.alloc-b", + "description": "B zajmuje następny fragment tej samej reszty.", + "evidence": "B=40; consumed=64; free=3968" }, { - "id": "free-ac", + "id": "alloc-c", "number": 4, - "label": "zwolnij A i C, pozostaw B", - "mode": "CODE", - "strategy_ref": "code.heap4", + "label": "trzeci split tworzy C", + "mode": "RUN", + "event_id": "E04", + "strategy_ref": "run.timeline", "svg_label": "04", - "code_ref": "src/tasks/task03_freertos_heap4.c:88", - "description": "C scala się z prawą resztą, ale B oddziela ją od A.", - "evidence": "dwa wolne bloki" + "code_ref": "src/tasks/task03_freertos_heap4.c:153", + "snapshot_ref": "task01.alloc-c", + "description": "A, B i C są wyrównane, a za nimi pozostaje jedna wolna reszta.", + "evidence": "C=16; consumed=32; free=3936" + }, + { + "id": "free-a", + "number": 5, + "label": "zwolnij A, pozostaw B i C", + "mode": "RUN", + "event_id": "E05", + "strategy_ref": "run.timeline", + "svg_label": "05", + "code_ref": "src/tasks/task03_freertos_heap4.c:163", + "snapshot_ref": "task01.free-a", + "description": "Wolny A i końcowa reszta są rozdzielone przez B i C.", + "evidence": "blocks=2; free=3984" }, { "id": "fragmented", - "number": 5, - "label": "checkpoint fragmentacji", - "mode": "RUN", - "event_id": "E01", - "strategy_ref": "run.fragmented", - "svg_label": "05", - "code_ref": "src/tasks/task03_freertos_heap4.c:91", - "snapshot_ref": "task01.fragmented", - "description": "GDB zatrzymuje program przy dwóch wolnych blokach.", - "evidence": "xNumberOfFreeBlocks = 2" - }, - { - "id": "free-b", "number": 6, - "label": "zwolnij B między dwoma sąsiadami", - "mode": "CODE", - "strategy_ref": "code.heap4", + "label": "zwolnij C, pozostaw B", + "mode": "RUN", + "event_id": "E06", + "strategy_ref": "run.fragmented", "svg_label": "06", - "code_ref": "src/tasks/task03_freertos_heap4.c:93", - "description": "Wstawienie adresowe umożliwia dwa testy ciągłości.", - "evidence": "A + B + C + reszta są ciągłe" + "code_ref": "src/tasks/task03_freertos_heap4.c:168", + "snapshot_ref": "task01.fragmented", + "description": "C scala się z prawą resztą, ale B nadal rozdziela dwa wolne obszary.", + "evidence": "blocks=2; free=4016; free>largest" }, { "id": "coalesced", "number": 7, - "label": "arena wraca do jednego bloku", + "label": "zwolnij B i scal oba sąsiednie bloki", "mode": "RUN", - "event_id": "E02", + "event_id": "E07", "strategy_ref": "run.coalesced", "svg_label": "07", - "code_ref": "src/tasks/task03_freertos_heap4.c:96", + "code_ref": "src/tasks/task03_freertos_heap4.c:173", "snapshot_ref": "task01.coalesced", - "description": "Finalne statystyki dowodzą pełnego odzyskania areny.", - "evidence": "final free = initial free; blocks = 1" + "description": "Scalenie lewego, a potem prawego sąsiada przywraca jeden blok.", + "evidence": "free=largest=initial=4080; blocks=1" }, { "id": "oom", "number": 8, "label": "zbyt duże żądanie kończy się NULL", - "mode": "CODE", - "strategy_ref": "code.heap4", + "mode": "RUN", + "event_id": "E08", + "strategy_ref": "run.verified", "svg_label": "08", - "code_ref": "src/tasks/task03_freertos_heap4.c:98", + "code_ref": "src/tasks/task03_freertos_heap4.c:179", + "snapshot_ref": "task01.verified", "description": "Kontrolowany OOM nie narusza listy i wywołuje hook dokładnie raz.", - "evidence": "NULL, hooks=1, asserts=0" + "evidence": "NULL; hooks=1; asserts=0; PASS=1" } ] } - ] + ], + "diagram_kind": "sequence" } ] }, @@ -597,33 +912,37 @@ "id": "free", "number": 1, "label": "wolny blok należy do listy", - "mode": "CODE", - "strategy_ref": "code.heap4", + "mode": "RUN", + "event_id": "E01", + "strategy_ref": "run.timeline", "svg_label": "01", - "code_ref": "src/tasks/task03_freertos_heap4.c:70", + "code_ref": "src/tasks/task03_freertos_heap4.c:127", + "snapshot_ref": "task01.reset", "description": "Stan początkowy zawiera jeden największy wolny blok.", - "evidence": "initial free = largest free" + "evidence": "initial free = largest free = 4080" }, { "id": "allocated", "number": 2, "label": "przydzielony blok znika z listy wolnych", - "mode": "CODE", - "strategy_ref": "code.heap4", + "mode": "RUN", + "event_id": "E04", + "strategy_ref": "run.timeline", "svg_label": "02", - "code_ref": "src/tasks/task03_freertos_heap4.c:78", + "code_ref": "src/tasks/task03_freertos_heap4.c:153", + "snapshot_ref": "task01.alloc-c", "description": "Payload jest wyrównany, a bieżąca wolna pamięć maleje.", - "evidence": "all payload pointers aligned" + "evidence": "all payload pointers aligned; free=3936" }, { "id": "fragmented-state", "number": 3, "label": "dwa wolne bloki nie są jednym dużym blokiem", "mode": "RUN", - "event_id": "E01", + "event_id": "E06", "strategy_ref": "run.fragmented", "svg_label": "03", - "code_ref": "src/tasks/task03_freertos_heap4.c:90", + "code_ref": "src/tasks/task03_freertos_heap4.c:168", "snapshot_ref": "task01.fragmented", "description": "Suma wolnego miejsca nie gwarantuje jednego dużego przydziału.", "evidence": "free blocks = 2" @@ -633,10 +952,10 @@ "number": 4, "label": "scalenie przywraca jeden największy blok", "mode": "RUN", - "event_id": "E02", + "event_id": "E07", "strategy_ref": "run.coalesced", "svg_label": "04", - "code_ref": "src/tasks/task03_freertos_heap4.c:94", + "code_ref": "src/tasks/task03_freertos_heap4.c:173", "snapshot_ref": "task01.coalesced", "description": "Current free i largest wracają do wartości początkowej.", "evidence": "free blocks = 1" @@ -645,10 +964,12 @@ "id": "minimum-ever", "number": 5, "label": "minimum-ever zachowuje najniższy poziom", - "mode": "CODE", - "strategy_ref": "code.heap4", + "mode": "RUN", + "event_id": "E08", + "strategy_ref": "run.verified", "svg_label": "05", - "code_ref": "src/tasks/task03_freertos_heap4.c:95", + "code_ref": "src/tasks/task03_freertos_heap4.c:179", + "snapshot_ref": "task01.verified", "description": "Historyczne minimum nie zwiększa się po odzyskaniu pamięci.", "evidence": "minimum-ever <= after allocations" } @@ -664,7 +985,7 @@ "title": "Dowód w Hazard3 i ELF", "order": 70, "orientation": "landscape", - "description": "Ten sam artefakt łączy źródło, symbole ELF, dwa checkpointy, pamięć ucHeap i końcowe asercje.", + "description": "Ten sam artefakt łączy źródło, symbole ELF, osiem checkpointów, pamięć ucHeap i końcowe asercje.", "content_tex": "Snapshot jest dowodem tylko wtedy, gdy zawiera tożsamość artefaktu, pozycję programu i wartości, które rozstrzygają hipotezę.", "assets": [ { @@ -685,7 +1006,7 @@ "mode": "CODE", "strategy_ref": "code.identity", "svg_label": "01", - "code_ref": "src/tasks/task03_freertos_heap4.c:62", + "code_ref": "src/tasks/task03_freertos_heap4.c:127", "description": "Blob źródła jest częścią tożsamości karty.", "evidence": "source git blob" }, @@ -705,22 +1026,24 @@ "number": 3, "label": "checkpoint pokazuje dwa wolne bloki", "mode": "RUN", - "event_id": "E01", + "event_id": "E06", "strategy_ref": "run.fragmented", "svg_label": "03", - "code_ref": "src/tasks/task03_freertos_heap4.c:91", + "code_ref": "src/tasks/task03_freertos_heap4.c:168", "snapshot_ref": "task01.fragmented", "description": "Neovim, GDB i pamięć zatrzymują się na tym samym stanie.", - "evidence": "blocks=2 and aligned=1" + "evidence": "blocks=2 and free>largest" }, { "id": "memory", "number": 4, "label": "ucHeap ujawnia nagłówki i payload", - "mode": "CODE", - "strategy_ref": "code.heap4", + "mode": "RUN", + "event_id": "E06", + "strategy_ref": "run.fragmented", "svg_label": "04", "code_ref": "src/tasks/task03_freertos_heap4.c:11", + "snapshot_ref": "task01.fragmented", "description": "Widok bajtów łączy diagram z realnym układem areny.", "evidence": "aligned arena and in-band metadata" }, @@ -729,11 +1052,11 @@ "number": 5, "label": "checkpoint końcowy dowodzi odzyskania", "mode": "RUN", - "event_id": "E02", - "strategy_ref": "run.coalesced", + "event_id": "E08", + "strategy_ref": "run.verified", "svg_label": "05", - "code_ref": "src/tasks/task03_freertos_heap4.c:111", - "snapshot_ref": "task01.coalesced", + "code_ref": "src/tasks/task03_freertos_heap4.c:179", + "snapshot_ref": "task01.verified", "description": "Jedna ramka łączy stats, OOM, hook i PASS.", "evidence": "final=initial, blocks=1, pass=1" } @@ -748,14 +1071,14 @@ "model_label": "Model bloków heap_4", "model": "Uczeń wyjaśnia nagłówek, wyrównanie, first-fit, split, adresową listę wolnych bloków i dwustronne coalescing.", "replay_label": "Fragmentacja i odzyskanie areny", - "replay": "Uczeń odtwarza dwa checkpointy Hazard3 i odróżnia current free, largest free block oraz minimum-ever.", - "criterion": "Model 13 -> 32 bajty; poprawna predykcja dwóch wolnych bloków po free(A,C) i jednego po free(B); final free = initial free; minimum-ever nie rośnie; OOM zwraca NULL; PASS=1.", + "replay": "Uczeń odtwarza osiem checkpointów Hazard3 i odróżnia current free, largest free block oraz minimum-ever.", + "criterion": "Na RV32 BlockLink_t ma 8 bajtów, lecz 16-bajtowe wyrównanie portu daje xHeapStructSize=16; A/B/C zużywają 48/64/32 bajty; po free(A,C) są dwa wolne bloki, po free(B) jeden; final free = initial free; minimum-ever nie rośnie; OOM zwraca NULL; PASS=1.", "requirement": "Analiza i weryfikacja mechaniki dynamicznej alokacji heap_4 w FreeRTOS C na RV32I/Hazard3." }, "task": { "short_label": "mechanika heap_4", "title": "Predict and prove reusable heap_4 blocks", - "prompt_tex": "Przewidź układ bloków po alloc A/B/C, następnie po free(A,C) i free(B). Odtwórz oba checkpointy i udowodnij, że arena została scalona bez utraty minimum-ever.", + "prompt_tex": "Przewidź układ bloków po alloc A/B/C, następnie po free(A), free(C) i free(B). Odtwórz checkpointy E01--E08 i udowodnij, że arena została scalona bez utraty minimum-ever.", "conclusion_tex": "heap\\_4 odzyskuje pamięć dzięki metadanym w arenie, adresowo uporządkowanej liście i scalaniu sąsiadów. Suma wolnych bajtów nie zastępuje informacji o największym bloku, a minimum-ever jest historią, nie bieżącym stanem.", "flow": [ { @@ -766,8 +1089,8 @@ "steps": [ { "id": "size", - "title": "Policz rozmiar bloku.", - "content_tex": "Dodaj nagłówek do 13 bajtów i wyrównaj wynik do ośmiu." + "title": "Policz rozmiary całych bloków.", + "content_tex": "Rozróżnij surowy BlockLink\\_t (8 bajtów) od xHeapStructSize (16 bajtów), dodaj nagłówek do żądań 24, 40 i 16 bajtów, a następnie wyrównaj wynik do 16." }, { "id": "list", @@ -780,17 +1103,22 @@ "kind": "block", "id": "replay", "title": "B — replay Hazard3", - "content_tex": "Powiąż diagram z dwoma deterministycznymi checkpointami.", + "content_tex": "Powiąż każdy stan diagramu z deterministycznym checkpointem E01--E08.", "steps": [ { - "id": "fragmented", - "title": "Sprawdź E01.", - "content_tex": "Porównaj liczbę wolnych bloków, największy blok i bieżące wolne bajty." + "id": "allocate", + "title": "Sprawdź E01--E04.", + "content_tex": "Potwierdź wartości 4080, 4032, 3968 i 3936 oraz zużycie 48/64/32 bajtów." }, { - "id": "coalesced", - "title": "Sprawdź E02.", - "content_tex": "Udowodnij pełne scalenie, zachowanie minimum-ever i kontrolowany OOM." + "id": "release", + "title": "Sprawdź E05--E07.", + "content_tex": "Porównaj liczbę wolnych bloków i udowodnij scalenie poprzedniego, a potem następnego sąsiada." + }, + { + "id": "verify", + "title": "Sprawdź E08.", + "content_tex": "Udowodnij zachowanie minimum-ever, kontrolowany OOM, brak asercji i PASS=1." } ] }, diff --git a/src/tasks/task03_freertos_heap4.c b/src/tasks/task03_freertos_heap4.c index a73eb93..14ee8fe 100644 --- a/src/tasks/task03_freertos_heap4.c +++ b/src/tasks/task03_freertos_heap4.c @@ -10,16 +10,37 @@ uint8_t ucHeap[configTOTAL_HEAP_SIZE] __attribute__((aligned(portBYTE_ALIGNMENT))); +HeapStats_t g_initial_stats; +HeapStats_t g_after_a_stats; +HeapStats_t g_after_b_stats; +HeapStats_t g_after_allocations_stats; +HeapStats_t g_after_free_a_stats; HeapStats_t g_fragmented_stats; HeapStats_t g_final_stats; volatile size_t g_initial_free; +volatile size_t g_after_a_free; +volatile size_t g_after_b_free; volatile size_t g_after_allocations; +volatile size_t g_after_free_a; +volatile size_t g_fragmented_free; volatile size_t g_final_free; volatile size_t g_minimum_ever_free; +volatile size_t g_a_consumed; +volatile size_t g_b_consumed; +volatile size_t g_c_consumed; +void * volatile g_probe; +void * volatile g_a; +void * volatile g_b; +void * volatile g_c; +void * volatile g_too_large; +volatile int g_a_aligned; +volatile int g_b_aligned; +volatile int g_c_aligned; volatile int g_allocations_aligned; volatile int g_oom_is_null; volatile int g_malloc_failed_hooks; volatile int g_assert_failures; +volatile int g_rv32_layout_expected; volatile int g_task03_pass; void vApplicationMallocFailedHook(void) @@ -45,6 +66,41 @@ BaseType_t xTaskResumeAll(void) } #endif +__attribute__((noinline)) void heap4_reset_checkpoint(void) +{ +#if defined(__GNUC__) + __asm__ volatile("" ::: "memory"); +#endif +} + +__attribute__((noinline)) void heap4_alloc_a_checkpoint(void) +{ +#if defined(__GNUC__) + __asm__ volatile("" ::: "memory"); +#endif +} + +__attribute__((noinline)) void heap4_alloc_b_checkpoint(void) +{ +#if defined(__GNUC__) + __asm__ volatile("" ::: "memory"); +#endif +} + +__attribute__((noinline)) void heap4_alloc_c_checkpoint(void) +{ +#if defined(__GNUC__) + __asm__ volatile("" ::: "memory"); +#endif +} + +__attribute__((noinline)) void heap4_free_a_checkpoint(void) +{ +#if defined(__GNUC__) + __asm__ volatile("" ::: "memory"); +#endif +} + __attribute__((noinline)) void heap4_fragmented_checkpoint(void) { #if defined(__GNUC__) @@ -52,6 +108,13 @@ __attribute__((noinline)) void heap4_fragmented_checkpoint(void) #endif } +__attribute__((noinline)) void heap4_coalesced_checkpoint(void) +{ +#if defined(__GNUC__) + __asm__ volatile("" ::: "memory"); +#endif +} + __attribute__((noinline)) void task03_debug_checkpoint(void) { #if defined(__GNUC__) @@ -61,48 +124,88 @@ __attribute__((noinline)) void task03_debug_checkpoint(void) int main(void) { - void *probe; - void *a; - void *b; - void *c; - void *too_large; - vPortHeapResetState(); - probe = pvPortMalloc(1U); - if (probe != NULL) + g_probe = pvPortMalloc(1U); + if (g_probe != NULL) { - vPortFree(probe); + vPortFree(g_probe); } g_initial_free = xPortGetFreeHeapSize(); + vPortGetHeapStats(&g_initial_stats); + heap4_reset_checkpoint(); - a = pvPortMalloc(24U); - b = pvPortMalloc(40U); - c = pvPortMalloc(16U); + g_a = pvPortMalloc(24U); + g_after_a_free = xPortGetFreeHeapSize(); + g_a_consumed = g_initial_free - g_after_a_free; + g_a_aligned = + g_a != NULL && ((uintptr_t)g_a % portBYTE_ALIGNMENT) == 0U; + vPortGetHeapStats(&g_after_a_stats); + heap4_alloc_a_checkpoint(); + + g_b = pvPortMalloc(40U); + g_after_b_free = xPortGetFreeHeapSize(); + g_b_consumed = g_after_a_free - g_after_b_free; + g_b_aligned = + g_b != NULL && ((uintptr_t)g_b % portBYTE_ALIGNMENT) == 0U; + vPortGetHeapStats(&g_after_b_stats); + heap4_alloc_b_checkpoint(); + + g_c = pvPortMalloc(16U); g_after_allocations = xPortGetFreeHeapSize(); + g_c_consumed = g_after_b_free - g_after_allocations; + g_c_aligned = + g_c != NULL && ((uintptr_t)g_c % portBYTE_ALIGNMENT) == 0U; g_allocations_aligned = - a != NULL && b != NULL && c != NULL && - ((uintptr_t)a % portBYTE_ALIGNMENT) == 0U && - ((uintptr_t)b % portBYTE_ALIGNMENT) == 0U && - ((uintptr_t)c % portBYTE_ALIGNMENT) == 0U; + g_a_aligned && g_b_aligned && g_c_aligned; + vPortGetHeapStats(&g_after_allocations_stats); + heap4_alloc_c_checkpoint(); - vPortFree(a); - vPortFree(c); + vPortFree(g_a); + g_after_free_a = xPortGetFreeHeapSize(); + vPortGetHeapStats(&g_after_free_a_stats); + heap4_free_a_checkpoint(); + + vPortFree(g_c); + g_fragmented_free = xPortGetFreeHeapSize(); vPortGetHeapStats(&g_fragmented_stats); heap4_fragmented_checkpoint(); - vPortFree(b); + vPortFree(g_b); g_final_free = xPortGetFreeHeapSize(); g_minimum_ever_free = xPortGetMinimumEverFreeHeapSize(); vPortGetHeapStats(&g_final_stats); + heap4_coalesced_checkpoint(); - too_large = pvPortMalloc(configTOTAL_HEAP_SIZE * 2U); - g_oom_is_null = too_large == NULL; + g_too_large = pvPortMalloc(configTOTAL_HEAP_SIZE * 2U); + g_oom_is_null = g_too_large == NULL; +#if defined(__riscv) && (__riscv_xlen == 32) + g_rv32_layout_expected = + portBYTE_ALIGNMENT == 16U && + g_initial_free == 4080U && + g_after_a_free == 4032U && g_a_consumed == 48U && + g_after_b_free == 3968U && g_b_consumed == 64U && + g_after_allocations == 3936U && g_c_consumed == 32U && + g_after_free_a == 3984U && + g_fragmented_free == 4016U && + g_final_free == 4080U; +#else + g_rv32_layout_expected = 1; +#endif g_task03_pass = - probe != NULL && g_allocations_aligned && + g_probe != NULL && g_allocations_aligned && + g_rv32_layout_expected && + g_initial_stats.xNumberOfFreeBlocks == 1U && + g_after_a_free < g_initial_free && + g_after_b_free < g_after_a_free && g_initial_free > g_after_allocations && + g_after_free_a > g_after_allocations && + g_fragmented_free > g_after_free_a && g_final_free == g_initial_free && g_minimum_ever_free <= g_after_allocations && + g_after_free_a_stats.xNumberOfFreeBlocks == 2U && g_fragmented_stats.xNumberOfFreeBlocks == 2U && + g_fragmented_stats.xAvailableHeapSpaceInBytes > + g_fragmented_stats.xSizeOfLargestFreeBlockInBytes && g_final_stats.xNumberOfFreeBlocks == 1U && g_final_stats.xSizeOfLargestFreeBlockInBytes == g_initial_free && g_oom_is_null && g_malloc_failed_hooks == 1 && @@ -111,11 +214,15 @@ int main(void) task03_debug_checkpoint(); #if defined(HOST_PRINTF) - printf("initial=%zu after=%zu fragmented=%zu final=%zu min=%zu " - "aligned=%d oom=%d hooks=%d asserts=%d pass=%d\n", - g_initial_free, g_after_allocations, - g_fragmented_stats.xNumberOfFreeBlocks, g_final_free, - g_minimum_ever_free, g_allocations_aligned, g_oom_is_null, + printf("initial=%zu after_a=%zu after_b=%zu after_c=%zu " + "free_a=%zu fragmented=%zu final=%zu min=%zu " + "consumed=%zu/%zu/%zu aligned=%d oom=%d hooks=%d " + "asserts=%d pass=%d\n", + g_initial_free, g_after_a_free, g_after_b_free, + g_after_allocations, g_after_free_a, g_fragmented_free, + g_final_free, g_minimum_ever_free, + g_a_consumed, g_b_consumed, g_c_consumed, + g_allocations_aligned, g_oom_is_null, g_malloc_failed_hooks, g_assert_failures, g_task03_pass); #endif return g_task03_pass ? 0 : 1; diff --git a/tests/check_task03_elf.sh b/tests/check_task03_elf.sh index 304a752..fd4dcf2 100755 --- a/tests/check_task03_elf.sh +++ b/tests/check_task03_elf.sh @@ -8,8 +8,13 @@ objdump="${prefix}objdump" test -s "$elf" for symbol in pvPortMalloc vPortFree prvInsertBlockIntoFreeList ucHeap \ - heap4_fragmented_checkpoint task03_debug_checkpoint g_task03_pass; do + heap4_reset_checkpoint heap4_alloc_a_checkpoint \ + heap4_alloc_b_checkpoint heap4_alloc_c_checkpoint \ + heap4_free_a_checkpoint heap4_fragmented_checkpoint \ + heap4_coalesced_checkpoint task03_debug_checkpoint \ + g_initial_stats g_after_allocations_stats g_fragmented_stats \ + g_final_stats g_rv32_layout_expected g_task03_pass; do "$nm" -a "$elf" | grep -E "[[:space:]]${symbol}$" >/dev/null done "$objdump" -d "$elf" | grep -E 'addi[[:space:]]+sp,sp,-' >/dev/null -printf 'PASS Task 3 links upstream heap_4 and observable checkpoints: %s\n' "$elf" +printf 'PASS Task 3 links upstream heap_4 and eight observable checkpoints: %s\n' "$elf" diff --git a/tests/test_host.sh b/tests/test_host.sh index 322dc3b..a0a53ba 100755 --- a/tests/test_host.sh +++ b/tests/test_host.sh @@ -19,4 +19,4 @@ check_output "$root/host-build/task01_first_fit_split/prog" \ check_output "$root/host-build/task02_address_order_coalesce/prog" \ 'before_nodes=2 before_total=96 before_largest=48 after_nodes=1 after_total=144 after_largest=144 pass=1' check_output "$root/host-build/task03_freertos_heap4/prog" \ - 'initial=4080 after=3952 fragmented=2 final=4080 min=3952 aligned=1 oom=1 hooks=1 asserts=0 pass=1' + 'initial=4080 after_a=4040 after_b=3984 after_c=3952 free_a=3992 fragmented=4024 final=4080 min=3952 consumed=40/56/32 aligned=1 oom=1 hooks=1 asserts=0 pass=1' diff --git a/tools/card-action.sh b/tools/card-action.sh index 1a99120..f26f8db 100755 --- a/tools/card-action.sh +++ b/tools/card-action.sh @@ -105,6 +105,9 @@ build_native() { rv_env_root() { if [[ -n "${RV_ENV_ROOT:-}" ]]; then printf '%s\n' "$RV_ENV_ROOT" + elif [[ -f "$root/vendor/Hazard3/test/sim/common/init.S" && \ + -f "$root/vendor/lab-runtime/memops.c" ]]; then + printf '%s\n' "$root" elif [[ -d /opt/rv-env ]]; then printf '%s\n' /opt/rv-env else @@ -123,6 +126,9 @@ build_hazard3() { "FREERTOS_KERNEL_PATH=$kernel" PROFILE=observe >&2 || return elf="$build_dir/$task_stem/prog.elf" test -s "$elf" + if [[ "$task_number" -eq 3 ]]; then + "$root/tests/check_task03_elf.sh" "$elf" >&2 + fi copy_artifact "$elf" copy_artifact "${elf%.elf}.bin" copy_artifact "${elf%.elf}.lst" @@ -283,7 +289,7 @@ configure_debug_view() { export STEM_DEBUG_MEMORY_EXPR='&g_coalesce_arena' STEM_DEBUG_MEMORY_LENGTH=160 ;; 3) - export STEM_DEBUG_INITIAL_BREAK=heap4_fragmented_checkpoint + export STEM_DEBUG_INITIAL_BREAK=heap4_reset_checkpoint export STEM_DEBUG_MEMORY_EXPR='ucHeap' STEM_DEBUG_MEMORY_LENGTH=160 ;; esac diff --git a/web/app.css b/web/app.css index eac8d78..388a0ab 100644 --- a/web/app.css +++ b/web/app.css @@ -1 +1 @@ -.paper{display:flex;flex-direction:column;gap:3.3cm}.paper>.sheet,.paper>.sheet-spread>.sheet{width:210mm;height:297mm;min-height:297mm;max-height:297mm;margin:0 auto;overflow:hidden}.paper>.sheet.sheet--landscape,.paper>.sheet-spread>.sheet.sheet--landscape{width:297mm;min-width:297mm;max-width:297mm;height:210mm;min-height:210mm;max-height:210mm}.paper>.sheet>.sheet-content,.paper>.sheet-spread>.sheet>.sheet-content{height:297mm;min-height:297mm;max-height:297mm;overflow-x:hidden;overflow-y:hidden}.paper>.sheet.sheet--landscape>.sheet-content,.paper>.sheet-spread>.sheet.sheet--landscape>.sheet-content{height:210mm;min-height:210mm;max-height:210mm}.sheet-spread{display:contents}.paper.is-diagram-spread .sheet-spread{display:grid;grid-template-columns:repeat(var(--spread-columns, 1),max-content);width:max-content;max-width:none;margin:0 auto;align-items:flex-start;gap:2mm;zoom:var(--spread-fit-scale, 1)}.paper.is-diagram-spread .sheet-spread>.sheet{flex:0 0 auto}.viewer-chrome{position:sticky;top:0;z-index:80;width:100%}.viewer-action-toast{position:absolute;z-index:12;right:9px;bottom:9px;max-width:min(720px,calc(100vw - 18px));box-sizing:border-box;overflow:hidden;border:1px solid #42b8e7;border-radius:3px;background:#102c38ee;color:#dff7ff;padding:5px 9px;box-shadow:0 4px 14px #0007;text-overflow:ellipsis;white-space:nowrap;font:750 10px/1.25 ui-monospace,monospace}.viewer-chrome .topbar{position:sticky;top:0;z-index:90}.viewpoint-bar{display:grid;grid-template-columns:repeat(8,minmax(0,1fr));gap:1px;min-height:31px;border-top:1px solid #9aa8ae;border-bottom:1px solid #718087;background:#718087;box-shadow:0 2px 5px #0002}.viewpoint-bar button{position:relative;display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:5px;min-width:0;border:0;background:#f7f9fa;color:#1f3038;padding:5px 7px;text-align:left;cursor:pointer}.viewpoint-bar button:hover,.viewpoint-bar button:focus-visible{z-index:1;background:#e9f3f7;outline:2px solid #287495;outline-offset:-2px}.viewpoint-bar button[aria-current=location]{background:#dcecf3;box-shadow:inset 0 -3px #167ca4}.viewpoint-bar button>span{color:#1b6785;font:850 10px/1 ui-monospace,monospace}.viewpoint-bar button>strong{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font:750 10px/1.1 system-ui,sans-serif}.viewpoint-bar button.is-unavailable{background:#eef0f1;color:#5d686d;cursor:not-allowed}.viewpoint-bar button.is-unavailable>span{color:#68747a}.viewpoint-bar button.is-unavailable>small{border:1px solid #9da7ab;border-radius:2px;padding:1px 3px;font:750 7px/1 ui-monospace,monospace}.card-library-toggle{display:inline-flex;align-items:center;flex:none;height:28px;gap:6px;border:1px solid #6e7d84;border-radius:3px;background:#f6f8f9;color:#26373f;padding:2px 8px;font:750 11px/1 ui-monospace,monospace;cursor:pointer}.card-library-toggle:hover,.card-library-toggle:focus-visible{border-color:#1d7799;background:#edf7fa;outline:none}.card-library-toggle.is-active{border-color:#126d8f;background:#174f67;color:#fff}.card-library-toggle-icon{font:700 16px/1 system-ui,sans-serif}.card-library-toggle kbd{color:#267697;font:inherit}.card-library-toggle.is-active kbd{color:#aee9ff}:root{--side-panel-top: 36px;--side-panel-width: min(960px, calc(100vw - 28px) );--side-panel-trigger-length: 56px}.side-panel-dock{position:fixed;z-index:240;top:var(--side-panel-top);bottom:0;width:0;pointer-events:none}.side-panel-dock--left{left:0}.side-panel-dock--right{right:0}.side-panel-rail{position:fixed;z-index:243;top:calc(var(--side-panel-top) + 8px);display:flex;width:13px;flex-direction:column;gap:10px;pointer-events:auto}.side-panel-dock--left .side-panel-rail{left:0}.side-panel-dock--right .side-panel-rail{right:0}.side-panel-trigger{--side-panel-accent: #167ca4;position:relative;display:grid;width:13px;height:var(--side-panel-trigger-length);place-items:center;border:0;border-radius:0;background:transparent;padding:0;cursor:pointer}.side-panel-trigger:before{content:"";display:block;width:3px;height:calc(var(--side-panel-trigger-length) - 8px);border-radius:999px;background:var(--side-panel-accent);box-shadow:0 0 0 1px #ffffff73,0 3px 10px -5px var(--side-panel-accent);opacity:.78;transition:width .14s ease,opacity .14s ease,box-shadow .14s ease}.side-panel-trigger:hover:before,.side-panel-trigger:focus-visible:before,.side-panel-trigger.is-open:before{width:4px;opacity:1}.side-panel-trigger.is-pinned:before{width:5px;box-shadow:0 0 0 1px #ffffff9e,0 3px 12px -4px var(--side-panel-accent)}.side-panel-trigger:focus-visible{outline:2px solid var(--side-panel-accent);outline-offset:-2px}.side-panel-trigger>span{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}.side-panel{position:fixed;z-index:241;top:var(--side-panel-top);bottom:0;display:flex;width:var(--side-panel-width);max-width:calc(100vw - 20px);box-sizing:border-box;flex-direction:column;overflow:hidden;border-color:#819098;background:#f7f9fa;color:#17252c;pointer-events:none;transition:transform .18s cubic-bezier(.22,.78,.24,1);will-change:transform}.side-panel-dock--left .side-panel{left:0;border-right:1px solid #819098;box-shadow:15px 0 34px -24px #101b218c;transform:translate(calc(-100% - 14px))}.side-panel-dock--right .side-panel{right:0;border-left:1px solid #819098;box-shadow:-15px 0 34px -24px #101b218c;transform:translate(calc(100% + 14px))}.side-panel.is-open{transform:translate(0);pointer-events:auto}.side-panel:after{content:"";position:absolute;top:10px;width:4px;height:48px;border-radius:999px;background:var(--side-panel-accent);pointer-events:none}.side-panel-dock--left .side-panel:after{right:-2px}.side-panel-dock--right .side-panel:after{left:-2px}.side-panel-header{display:flex;min-height:38px;box-sizing:border-box;align-items:center;justify-content:space-between;gap:10px;border-bottom:1px solid #aebbc1;background:#e7edef;padding:4px 7px 4px 10px}.side-panel-header>div:first-child{display:flex;min-width:0;align-items:baseline;gap:7px}.side-panel-header small{color:#52666f;font:600 16px/1 ui-monospace,monospace;letter-spacing:.08em}.side-panel-header strong{overflow:hidden;color:#11191d;text-overflow:ellipsis;white-space:nowrap;font:600 16px/1.2 system-ui,sans-serif}.side-panel-actions{display:flex;flex:none;gap:4px}.side-panel-actions button{display:grid;min-width:38px;height:24px;place-items:center;border:1px solid #8b999f;border-radius:3px;background:#fff;color:#26373f;padding:0 6px;font:650 16px/1 ui-monospace,monospace;cursor:pointer}.side-panel-actions button:last-child{min-width:24px;padding:0;font-size:18px}.side-panel-actions button:hover,.side-panel-actions button:focus-visible,.side-panel-actions button.is-pinned{border-color:var(--side-panel-accent);background:#edf7fa;outline:none}.side-panel-body,.card-library-panel{display:flex;min-height:0;flex:1;flex-direction:column;overflow:hidden}.card-library-header{display:flex;align-items:flex-start;justify-content:space-between;gap:14px;padding:18px 18px 15px;border-bottom:1px solid #bdc9ce;background:#e8eef1}.card-library-header small{color:#52666f;font:600 16px/1.25 ui-monospace,monospace;letter-spacing:.09em;text-transform:uppercase}.card-library-header h2{margin:4px 0 2px;font:750 22px/1.15 system-ui,sans-serif}.card-library-header p{margin:0;color:#607078;font:500 16px/1.35 system-ui,sans-serif}.card-library-header>button{display:grid;width:34px;height:34px;place-items:center;flex:none;border:1px solid #77878e;border-radius:3px;background:#fff;color:#25353c;padding:0;font:25px/1 system-ui,sans-serif;cursor:pointer}.card-library-header>button:hover,.card-library-header>button:focus-visible{border-color:#126d8f;background:#edf7fa;outline:2px solid #85c5dc;outline-offset:1px}.card-library-tree{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:6px 0 18px;scrollbar-color:#8a9aa1 #edf1f3}.card-library-tree details{border:0}.card-library-tree summary{display:grid;grid-template-columns:14px minmax(0,1fr) auto;align-items:center;gap:6px;min-height:30px;box-sizing:border-box;padding:5px 10px 5px 4px;list-style:none;cursor:pointer;user-select:none}.card-library-tree summary::-webkit-details-marker{display:none}.card-library-tree summary:hover,.card-library-tree summary:focus-visible{background:#eaf1f4;outline:none}.card-library-branch{color:#25363d;font:16px/1 ui-monospace,monospace;transform:rotate(-90deg);transition:transform .12s ease}.card-library-tree details[open]>summary .card-library-branch{transform:rotate(0)}.card-library-tree summary strong,.card-library-tree summary small{display:block}.card-library-tree summary strong{color:#070a0b;font:550 16px/1.3 system-ui,sans-serif}.card-library-tree summary small{margin-top:2px;color:#303b40;font:500 16px/1.25 ui-monospace,monospace;letter-spacing:.04em}.card-library-tree summary output{min-width:22px;color:#26363d;padding:0 2px;text-align:center;font:550 16px/1.2 ui-monospace,monospace}.card-library-subject>summary{min-height:42px;border-bottom:1px solid #9eacb2;background:#dfe8ec;padding:7px 14px}.card-library-subject>summary:hover,.card-library-subject>summary:focus-visible{background:#d5e1e5}.card-library-subject>summary strong{color:#000;font:600 16px/1.3 system-ui,sans-serif}.card-library-subject>summary small{color:#28353a;font:500 16px/1.25 ui-monospace,monospace}.card-library-level-list{margin-left:18px;border-left:1px solid #8e9da4}.card-library-level>summary{min-height:38px;border-bottom:1px solid #cbd4d8;padding-left:8px}.card-library-level>summary strong{color:#000;font:550 16px/1.3 system-ui,sans-serif}.card-library-series-list{margin-left:18px;border-left:1px solid #a5b1b6;padding:2px 0 6px}.card-library-series>summary{min-height:34px;padding-left:8px}.card-library-series>summary strong{color:#000;font:550 16px/1.3 system-ui,sans-serif}.card-library-series>summary small{color:#26343a;font:500 16px/1.25 ui-monospace,monospace}.card-library-cards,.card-library-tasks{list-style:none;margin-top:0;margin-bottom:2px;padding:0}.card-library-cards{margin-left:18px;border-left:1px solid #bac3c7}.card-library-card-entry{margin:0}.card-library-card{display:grid;grid-template-columns:19px minmax(0,1fr) auto;align-items:start;gap:5px;min-height:38px;box-sizing:border-box;border:0;border-left:3px solid transparent;color:#000;padding:5px 8px 5px 3px;text-decoration:none}.card-library-node{color:#536168;font:16px/1.35 ui-monospace,monospace}.card-library-card-copy,.card-library-card-copy strong,.card-library-card-copy>span{display:block;min-width:0}.card-library-card-copy strong{color:#000;font:550 16px/1.3 ui-monospace,monospace}.card-library-card-copy>span{margin-top:2px;color:#0b0d0e;font:500 16px/1.35 system-ui,sans-serif;white-space:normal}.card-library-card-meta{display:flex;align-items:flex-end;flex-direction:column;gap:2px}.card-library-card-meta small{color:#26343a;font:500 16px/1.25 ui-monospace,monospace}.card-library-card.is-available{cursor:pointer}.card-library-card.is-available:hover,.card-library-card.is-available:focus-visible{background:#eaf5f8;outline:none}.card-library-card.is-current{border-left-color:#16769b;background:#dff1f7}.card-library-card.is-current:hover,.card-library-card.is-current:focus-visible{background:#cfeaf3;outline:1px solid #5ba9c4;outline-offset:-1px}.card-library-card.is-unavailable{color:#000}.card-library-card.is-unavailable .card-library-card-copy strong,.card-library-card.is-unavailable .card-library-card-meta small{color:#1d292e}.card-library-card.is-unavailable .card-library-card-copy>span{color:#0b0d0e}.card-library-tasks{margin-left:36px;border-left:1px solid #c3cacc}.card-library-tasks li>a,.card-library-tasks li>span{display:grid;grid-template-columns:19px auto minmax(0,1fr);gap:5px;align-items:start;color:#000;padding:4px 8px 5px 3px;text-decoration:none}.card-library-tasks li>a:hover,.card-library-tasks li>a:focus-visible{background:#eaf5f8;outline:none}.card-library-tasks strong{color:#000;font:550 16px/1.35 ui-monospace,monospace}.card-library-tasks li>a>span:last-child,.card-library-tasks li>span>span:last-child{color:#111;font:500 16px/1.35 system-ui,sans-serif}.card-library-footer{display:flex;align-items:center;gap:12px;flex-wrap:wrap;padding:10px 16px;border-top:1px solid #bdc9ce;background:#edf1f3;color:#5a6a72;font:500 16px/1.3 system-ui,sans-serif}.card-library-footer span{display:inline-flex;align-items:center;gap:4px}.card-library-footer i{width:7px;height:7px;border-radius:50%;background:#929da2}.card-library-footer i.is-online{background:#26815b}.card-library-footer kbd{margin-left:auto;border:1px solid #a2afb5;border-radius:2px;background:#fff;padding:2px 5px;font:600 16px/1 ui-monospace,monospace}.card-library-treegrid{min-height:0;flex:1;overflow:auto;margin:8px;border:1px solid rgb(31 35 40 / 18%);border-radius:6px;background:#fff;scrollbar-color:#93a2a8 #edf1f2;scrollbar-width:thin}.card-library-treegrid-row{display:grid;min-width:760px;min-height:38px;box-sizing:border-box;grid-template-columns:minmax(500px,1fr) 110px 120px;align-items:stretch;border-bottom:1px solid rgb(31 35 40 / 9%);color:#273941;font:500 16px/1.25 ui-monospace,monospace}.card-library-treegrid-row>[role=gridcell],.card-library-treegrid-row>[role=columnheader]{display:flex;min-width:0;align-items:center;overflow:hidden;padding:7px 9px;text-overflow:ellipsis;white-space:nowrap}.card-library-treegrid-row>[role=gridcell]+[role=gridcell],.card-library-treegrid-row>[role=columnheader]+[role=columnheader]{border-left:1px solid rgb(31 35 40 / 9%)}.card-library-treegrid-head{position:sticky;z-index:3;top:0;min-height:34px;border-bottom-color:#1f232833;background:#eef1f2;color:#3e525b;font-weight:700;letter-spacing:.045em}.card-library-treegrid-row:not(.card-library-treegrid-head):hover{background:#1f23280a}.card-library-treegrid-row.is-subject{background:#dfe8e5}.card-library-treegrid-row.is-level{background:#f5f8f8}.card-library-treegrid-row.is-series{background:#f9fbfb}.card-library-treegrid-row.is-card{min-height:42px;background:#fff}.card-library-treegrid-row.is-task{background:#fbfcfc}.card-library-treegrid-row.is-current{box-shadow:inset 3px 0 #1680a5;background:#e1f1f6}.card-library-tree-title{gap:6px;padding-left:calc(8px + (var(--card-library-depth, 0) * 21px))!important;font-family:system-ui,sans-serif}.card-library-tree-expander{display:inline-grid;width:24px;height:24px;flex:none;place-items:center;border:0;background:transparent;color:#405961;padding:0;font:18px/1 ui-monospace,monospace;cursor:pointer}.card-library-tree-expander:hover,.card-library-tree-expander:focus-visible{background:#165d6b1a;color:#165d6b;outline:1px solid rgb(22 93 107 / 28%)}.card-library-tree-expander.is-empty{cursor:default}.card-library-tree-link,.card-library-tree-label{display:flex;min-width:0;align-items:baseline;gap:7px;overflow:hidden;color:#10181c;text-decoration:none;white-space:nowrap}.card-library-tree-link:hover,.card-library-tree-link:focus-visible{color:#075d7c;outline:none;text-decoration:underline;text-underline-offset:2px}.card-library-tree-link strong,.card-library-tree-label strong{flex:none;color:inherit;font:700 16px/1.25 ui-monospace,monospace}.card-library-tree-link>span,.card-library-tree-label>span{min-width:0;overflow:hidden;color:inherit;text-overflow:ellipsis;white-space:nowrap;font:500 16px/1.25 system-ui,sans-serif}.card-library-treegrid-row.is-subject .card-library-tree-label strong,.card-library-treegrid-row.is-level .card-library-tree-label strong,.card-library-treegrid-row.is-series .card-library-tree-label strong{font-family:system-ui,sans-serif;font-weight:650}.card-library-tree-state{display:inline-flex;min-width:76px;min-height:24px;box-sizing:border-box;align-items:center;justify-content:center;border:1px solid transparent;border-radius:5px;color:#33474f;padding:2px 7px;font:650 14px/1 ui-monospace,monospace;white-space:nowrap}.card-library-tree-state[data-state=current]{border-color:#3184a0;background:#e9f5f8;color:#075d7c}.card-library-tree-state[data-state=online]{border-color:#4b9a7a;background:#edf8f2;color:#176144}.card-library-tree-state[data-state=plan]{border-color:#c59a49;background:#fff7e5;color:#775313}.card-library-treegrid-row.is-unavailable .card-library-tree-label,.card-library-treegrid-row.is-unavailable .card-library-tree-label strong{color:#10181c}.side-toc,.side-progress{min-height:0;flex:1;overflow-y:auto;background:#fff;color:#11191d}.side-toc>header,.side-progress>header{padding:16px 18px 13px;border-bottom:1px solid #bdc9ce;background:#f0f4f5}.side-toc>header small,.side-progress>header small{color:#53666f;font:750 9px/1 ui-monospace,monospace;letter-spacing:.08em}.side-toc>header h2,.side-progress>header h2{margin:4px 0 0;color:#10181c;font:750 21px/1.15 system-ui,sans-serif}.side-toc ol{margin:0;padding:7px 0 20px;list-style:none}.side-toc li{border-bottom:1px solid #e2e7e9}.side-toc a{display:grid;grid-template-columns:34px minmax(0,1fr);gap:9px;align-items:baseline;padding:10px 16px;color:#11191d;text-decoration:none}.side-toc a:hover,.side-toc a:focus-visible{background:#eaf5f8;outline:none}.side-toc a span{color:#267493;font:800 10px/1 ui-monospace,monospace}.side-toc a strong{font:650 13px/1.3 system-ui,sans-serif}.side-progress-summary{display:flex;align-items:center;justify-content:space-between;gap:16px;margin:16px;border:1px solid #b6c2c7;background:#f4f7f8;padding:14px;font:650 13px/1.3 system-ui,sans-serif}.side-progress-summary strong{color:#1d617b;font:850 20px/1 ui-monospace,monospace}.side-progress-links{display:grid;gap:8px;padding:0 16px 18px}.side-progress-links a{border:1px solid #87979e;border-radius:3px;background:#fff;color:#174f67;padding:10px 12px;text-decoration:none;font:700 12px/1.2 system-ui,sans-serif}.side-progress-links a:hover,.side-progress-links a:focus-visible{border-color:#167ca4;background:#edf7fa;outline:none}.side-progress-error{margin:0 16px 14px;border-left:3px solid #a52d2d;background:#fff1f1;color:#7d1f1f;padding:8px 10px;font:12px/1.35 system-ui,sans-serif}.classroom-panel{display:flex;min-height:0;flex:1;flex-direction:column;overflow:hidden;background:#f7f9fa;color:#11191d}.classroom-treegrid{min-height:0;flex:1;overflow:auto;margin:8px;border:1px solid rgb(31 35 40 / 18%);border-radius:6px;background:#fff;scrollbar-color:#93a2a8 #edf1f2;scrollbar-width:thin}.classroom-treegrid-row{display:grid;min-width:920px;box-sizing:border-box;grid-template-columns:minmax(410px,1fr) 100px 150px 150px 110px;align-items:center;border-bottom:1px solid rgb(31 35 40 / 8%);color:#273941;font:500 16px/1.25 ui-monospace,monospace}.classroom-treegrid-row>[role=gridcell],.classroom-treegrid-row>[role=columnheader]{min-width:0;overflow:hidden;padding:8px;text-overflow:ellipsis;white-space:nowrap}.classroom-treegrid-row>[role=gridcell]+[role=gridcell],.classroom-treegrid-row>[role=columnheader]+[role=columnheader]{border-left:1px solid rgb(31 35 40 / 8%)}.classroom-treegrid-head{position:sticky;z-index:2;top:0;border-bottom-color:#1f23282e;background:#eef1f2;color:#3e525b;font-weight:650;letter-spacing:.04em}.classroom-node-row:hover{background:#1f23280a}.classroom-node-row.is-class{background:#dfe8e5}.classroom-node-row.is-student{background:#f8faf9}.classroom-node-row.is-task{background:#edf3f5}.classroom-node-row.is-block,.classroom-node-row.is-exercises{background:#f5f7f8}.classroom-node-row.is-phase{background:#fafbfb}.classroom-node-title{display:flex;align-items:center;gap:6px;padding-left:calc(8px + (var(--classroom-depth, 0) * 20px))!important;font-family:system-ui,sans-serif}.classroom-node-title strong{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:16px;font-weight:500}.classroom-node-row.is-class .classroom-node-title strong,.classroom-node-row.is-student .classroom-node-title strong,.classroom-node-row.is-task .classroom-node-title strong{font-weight:650}.classroom-expander{display:inline-grid;width:24px;height:24px;flex:none;place-items:center;border:0;background:transparent;color:#405961;padding:0;font:18px/1 ui-monospace,monospace;cursor:pointer}.classroom-expander:hover,.classroom-expander:focus-visible{background:#165d6b1a;color:#165d6b;outline:1px solid rgb(22 93 107 / 28%)}.classroom-expander.is-empty{cursor:default}.classroom-status,.classroom-sync,.classroom-visit,.classroom-commit{display:inline-flex;min-width:92px;box-sizing:border-box;align-items:center;justify-content:center;border:1px solid;border-radius:5px;padding:4px 6px;font:550 16px/1 ui-monospace,monospace;letter-spacing:.015em}.classroom-status[data-status=online]{border-color:#6b9a87;background:#e7f4ee;color:#155e43}.classroom-status[data-status=away]{border-color:#baa06a;background:#fff5d9;color:#765510}.classroom-status[data-status=offline]{border-color:#a5afb3;background:#f0f2f3;color:#596970}.classroom-status[data-status=error]{border-color:#bd7b7b;background:#fff0f0;color:#8c2929}.classroom-sync[data-sync=follow]{border-color:#6c98aa;background:#e8f3f7;color:#155c77}.classroom-sync[data-sync=paused]{border-color:#baa06a;background:#fff6df;color:#765510}.classroom-sync[data-sync=local]{border-color:#9a86ae;background:#f4eef9;color:#65427c}.classroom-visit[data-visit=present],.classroom-commit[data-commit=committed]{border-color:#6b9a87;background:#e7f4ee;color:#155e43}.classroom-visit[data-visit=missed],.classroom-commit[data-commit=missing]{border-color:#bd7b7b;background:#fff0f0;color:#8c2929}.classroom-visit[data-visit=pending],.classroom-commit[data-commit=working]{border-color:#baa06a;background:#fff6df;color:#765510}.classroom-legend{display:flex;flex:none;flex-wrap:wrap;gap:7px 12px;border-top:1px solid #aebbc1;background:#edf1f2;padding:9px 11px;color:#485c65;font:500 16px/1.35 system-ui,sans-serif}.classroom-legend span{display:inline-flex;align-items:center;gap:4px}.classroom-legend i{width:12px;height:12px;border:1px solid #73858c;border-radius:50%;background:#aeb7bb}.classroom-legend i[data-status=online]{border-color:#3e7c63;background:#45a27b}.classroom-legend i[data-status=away]{border-color:#a0782d;background:#dcae51}.classroom-legend i[data-status=offline]{border-color:#859399;background:#b6c0c4}.classroom-legend b{color:#65427c;font:600 16px/1 ui-monospace,monospace}.viewer-chrome.is-nvim-fit{display:flex;width:100%;height:100vh;height:100dvh;max-height:100dvh;flex-direction:column;overflow:hidden;background:#11171a}.viewer-chrome.is-nvim-fit .topbar,.viewer-chrome.is-nvim-fit .viewpoint-bar,.viewer-chrome.is-nvim-fit .allocator-panel{flex:none}.viewer-chrome.is-nvim-fit .nvim-panel{display:flex;min-height:0;flex:1;flex-direction:column}.viewer-chrome.is-nvim-fit .nvim-screen-scroll{min-height:0;height:auto!important;flex:1}.viewer-chrome.is-nvim-fit .nvim-resize-handle{display:none}.viewer-chrome.is-nvim-fit .nvim-screen-stage{width:100%;height:100%;margin:0;zoom:1}.viewer-chrome.is-nvim-fit .nvim-screen-content{right:1mm;overflow:hidden;scrollbar-width:none}.viewer-chrome.is-nvim-fit .nvim-screen-grid{display:flex;width:100%;min-height:0;height:100%;align-items:center;justify-content:center}.viewer-chrome.is-nvim-fit .nvim-screen{width:auto!important;height:auto!important;max-width:100%;max-height:100%}.viewer-chrome.is-nvim-fit .nvim-screen-content::-webkit-scrollbar{display:none}.topbar-nvim-section{display:flex;align-items:center;min-width:0;gap:6px}.nvim-toolbar-boundary{flex:none;color:#6f7d83;font:700 14px/1 ui-monospace,monospace}.nvim-toolbar-context{flex:none;width:5ch;color:#263238;font:800 12px/1 ui-monospace,monospace;letter-spacing:.08em;text-align:center}.nvim-toolbar-actions{display:flex;align-items:center;gap:3px}.nvim-toolbar-button{display:inline-flex;align-items:center}.nvim-toolbar-key{flex:0 0 2ch;color:#267697;font:inherit;text-align:center}.nvim-toolbar-label{flex:0 0 5ch;max-width:5ch;overflow:hidden;text-align:left;white-space:nowrap}.topbar-nvim-meta{display:flex;align-items:baseline;min-width:0;max-width:min(44vw,720px);gap:6px}.topbar-nvim-meta strong,.topbar-nvim-meta small{overflow:auto;text-overflow:ellipsis;white-space:nowrap}.topbar-nvim-meta strong{color:#263238;font:700 12px/1.25 system-ui,sans-serif}.topbar-nvim-meta small{color:#66747a;font:500 10px/1.25 system-ui,sans-serif}.viewer-nvim-toggle{border:1px solid #68747a;border-radius:3px;background:#fff;color:#263238;padding:2px 8px;font:650 16px/1.3 system-ui,sans-serif;cursor:pointer}.viewer-nvim-toggle[aria-pressed=true]{border-color:#267697;background:#eaf6fb;color:#174d64}.allocator-panel{width:100%;box-sizing:border-box;border-top:1px solid #40515a;border-bottom:1px solid #40515a;background:#f7f9f5;color:#182127;box-shadow:0 4px 12px #0002;font:11px/1.25 system-ui,sans-serif}.allocator-panel>header{display:grid;grid-template-columns:125px minmax(260px,auto) 1fr;gap:8px;align-items:baseline;min-height:22px;padding:3px 8px;border-bottom:1px solid #b7c1c4;background:#e8eef0}.allocator-panel>header>span{color:#166987;font:800 9px/1.2 ui-monospace,monospace;letter-spacing:.06em}.allocator-panel>header>strong{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font:750 11px/1.2 ui-monospace,monospace}.allocator-panel>header>small{overflow:hidden;color:#536168;text-overflow:ellipsis;white-space:nowrap}.allocator-panel-body{display:grid;grid-template-columns:230px minmax(420px,1fr) minmax(310px,.8fr);gap:9px;align-items:stretch;padding:5px 8px 7px}.allocator-metrics{display:grid;grid-template-columns:1fr 1fr;gap:3px 8px;margin:0}.allocator-metrics>div{min-width:0;border-left:2px solid #8ea2ab;padding-left:5px}.allocator-metrics dt{color:#627077;font:750 7px/1.2 ui-monospace,monospace;letter-spacing:.05em}.allocator-metrics dd{margin:1px 0 0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font:700 10px/1.2 ui-monospace,monospace}.allocator-arena-view{min-width:0}.allocator-arena-view.is-inactive{opacity:.42}.allocator-arena-labels{display:flex;justify-content:space-between;gap:8px;margin-bottom:3px;color:#536168;font:700 8px/1.2 ui-monospace,monospace}.allocator-arena-labels strong{color:#075f80}.allocator-pinned-arena{position:relative;display:grid;grid-template-columns:repeat(var(--allocator-size),minmax(2px,1fr));height:32px;border:1px solid #28343a;background:#fff}.allocator-pinned-arena i{min-width:0;border-right:1px solid #e1e5e6;background:#fbfcfc}.allocator-pinned-arena i:nth-child(8n){border-right-color:#87969d}.allocator-pinned-arena i.is-allocated{border-right-color:#b2d8e6;background:#43a8ce}.allocator-cursor{position:absolute;z-index:2;top:-4px;bottom:-4px;width:2px;background:#d02d25;transform:translate(-1px);box-shadow:0 0 0 1px #fff9}.allocator-cursor:before{content:"allocp";position:absolute;top:1px;left:4px;color:#8d1d17;font:800 7px/1 ui-monospace,monospace}.allocator-facts{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:2px 7px;min-width:0}.allocator-facts>div{display:flex;min-width:0;justify-content:space-between;gap:5px;border-bottom:1px dotted #b4bec2}.allocator-facts span{overflow:hidden;color:#46565e;text-overflow:ellipsis;white-space:nowrap}.allocator-facts code{overflow:hidden;color:#142e39;text-overflow:ellipsis;white-space:nowrap;font:700 9px/1.3 ui-monospace,monospace}.allocator-facts p{grid-column:1 / -1;margin:0;color:#647278}.nvim-panel{width:100%;box-sizing:border-box;border-bottom:1px solid #52616a;background:var(--desk, #eee);color:#e7eef1;box-shadow:0 5px 16px #0004;font:12px/1.3 system-ui,sans-serif}.nvim-status{flex:none;border:1px solid #66757c;border-radius:999px;padding:1px 6px;color:#c9d3d8;font:750 9px/1.35 ui-monospace,monospace;letter-spacing:.04em}.nvim-status--connected,.nvim-status--ready{border-color:#31a86d;background:#173b2a;color:#8aefb7}.nvim-status--connecting,.nvim-status--replaying,.nvim-status--verifying{border-color:#c38f2a;background:#3e321b;color:#ffd47d}.nvim-status--failed,.nvim-status--offline,.nvim-status--unselected{border-color:#a34b4b;background:#3b2020;color:#faa}.nvim-control-indicator{flex:none;border:1px solid #60747e;border-radius:3px;background:#222e34;color:#b9c6cc;padding:3px 8px;font:700 10px/1.2 ui-monospace,monospace;letter-spacing:.04em;white-space:nowrap;cursor:pointer}.nvim-control-indicator.is-active{border-color:#3cb3e2;background:#17465a;color:#d9f5ff}.nvim-control-indicator.is-engaged{box-shadow:inset 0 0 0 1px #8ee4ff}.nvim-work-indicator{flex:none;border:1px solid #7a878d;border-radius:3px;background:#f4f6f7;color:#56646a;padding:3px 8px;font:700 10px/1.2 ui-monospace,monospace;letter-spacing:.03em;white-space:nowrap;cursor:pointer}.nvim-work-indicator.is-active{border-color:#cf3d31;background:#fff0ee;color:#9f241b}.nvim-work-indicator.is-engaged{box-shadow:inset 0 0 0 1px #cf3d31}.nvim-work-indicator:disabled{border-color:#a8b0b4;background:#e6e9ea;color:#7c878c;cursor:not-allowed;opacity:.8}.nvim-height-toggle{flex:none;border:1px solid #75848b;border-radius:3px;background:#f4f6f7;color:#425159;padding:3px 8px;font:700 10px/1.2 ui-monospace,monospace;letter-spacing:.03em;white-space:nowrap;cursor:pointer}.nvim-height-toggle.is-active{border-color:#267697;background:#eaf6fb;color:#174d64}.topbar-nvim-section .nvim-toolbar-button{flex:0 0 9.5ch;width:9.5ch;min-width:9.5ch;max-width:9.5ch;height:24px;box-sizing:border-box;justify-content:flex-start;gap:.55ch;padding:2px .55ch;font:750 12px/1 ui-monospace,monospace;letter-spacing:0}.nvim-shortcut-strip{flex:none;color:#536168;font:650 10px/1.2 ui-monospace,monospace;white-space:nowrap}.nvim-shortcut-strip kbd{color:#263238;font:inherit}.nvim-screen-scroll{position:relative;width:100%;box-sizing:border-box;height:var(--nvim-panel-height, 75vh);max-height:none;min-height:240px;overflow:auto;overscroll-behavior:contain;background:var(--desk, #eee);outline:none;scrollbar-color:#58666d #171d20}.nvim-screen-stage{position:relative;width:210mm;margin:0 auto;background:#fff;zoom:var(--viewer-canvas-scale)}.nvim-screen-surface{position:absolute;inset:0 4mm;box-sizing:border-box;padding:1mm;background:#fff}.nvim-screen-frame{position:relative;height:100%;box-sizing:border-box;border:1px solid #267697;background:#101315;box-shadow:0 0 0 3px #000}.nvim-screen-scroll[data-sync=on] .nvim-screen-frame{border-color:#35b9ef}.nvim-screen-scroll[data-control=true] .nvim-screen-frame{box-shadow:0 0 0 3px #cf3d31}.nvim-screen-scroll[data-control=true]{cursor:text}.nvim-screen-content{position:absolute;inset:1mm -5mm 1mm 1mm;overflow-x:hidden;overflow-y:scroll;overscroll-behavior:contain;background:transparent;scrollbar-width:thin;scrollbar-color:#829097 #fff}.nvim-screen-grid{width:calc(100% - 6mm);min-height:100%;background:#101315}.nvim-screen-content::-webkit-scrollbar{width:.8mm}.nvim-screen-content::-webkit-scrollbar-track{background:#fff}.nvim-screen-content::-webkit-scrollbar-thumb{border:.12mm solid #fff;border-radius:99px;background:#829097}.nvim-screen-content::-webkit-scrollbar-thumb:hover{background:#aeb9be}.nvim-screen{display:block;max-width:none;margin:0;outline:none;image-rendering:auto}.nvim-screen:focus{box-shadow:none}.nvim-screen-empty{position:absolute;inset:0;display:grid;place-content:center;gap:5px;padding:16px;color:#9cabb2;text-align:center}.nvim-screen-empty strong{color:#e0e8eb;font:750 11px/1.3 ui-monospace,monospace}.nvim-resize-handle{position:relative;width:100%;height:12px;border-top:1px solid #46565e;background:#182126;cursor:ns-resize;touch-action:none}.nvim-resize-handle:after{content:"";position:absolute;top:4px;left:50%;width:min(160px,22vw);height:3px;border-radius:999px;background:#6c7e87;transform:translate(-50%)}.nvim-resize-handle:hover,.nvim-resize-handle:focus-visible{background:#23323a;outline:none}.nvim-resize-handle:hover:after,.nvim-resize-handle:focus-visible:after{background:#35b9ef}.shortcut-help-backdrop{position:fixed;z-index:200;inset:0;display:grid;place-items:center;padding:20px;background:#10171dcc}.shortcut-help{width:min(680px,calc(100vw - 40px));max-height:calc(100vh - 40px);overflow:auto;border:1px solid #71818a;border-radius:6px;background:#f8fafb;color:#172127;box-shadow:0 18px 60px #0008;font:14px/1.4 system-ui,sans-serif}.shortcut-help>header{display:flex;align-items:start;justify-content:space-between;gap:16px;padding:16px 18px;border-bottom:1px solid #c8d1d5;background:#e8eef1}.shortcut-help header small{color:#52646d;font:750 10px/1.2 ui-monospace,monospace;letter-spacing:.08em}.shortcut-help h2{margin:4px 0 0;font-size:17px}.shortcut-help header button{width:32px;height:32px;border:1px solid #71818a;border-radius:3px;background:#fff;font:22px/1 system-ui,sans-serif;cursor:pointer}.shortcut-help dl{margin:0;padding:10px 18px}.shortcut-help dl>div{display:grid;grid-template-columns:minmax(180px,.8fr) 1.5fr;gap:14px;align-items:center;padding:8px 0;border-bottom:1px solid #dde3e6}.shortcut-help dt,.shortcut-help dd{margin:0}.shortcut-help kbd{display:inline-block;border:1px solid #839198;border-bottom-width:2px;border-radius:3px;background:#fff;padding:3px 7px;font:700 12px/1.2 ui-monospace,monospace}.shortcut-help>p{margin:0;padding:4px 18px 16px;color:#526068}.memory-react{border:1px solid #555;background:#fff;font:14px/1.35 system-ui,sans-serif;padding:10px;color:#1b1b1b}.memory-react>header{display:flex;align-items:center;justify-content:space-between;gap:12px;border-bottom:1px solid #bbb;padding-bottom:7px}.memory-react>header small{display:block;margin-bottom:2px;color:#555;font:700 10px/1.2 ui-monospace,monospace;letter-spacing:.08em}.memory-react h3{font-size:15px;margin:0}.memory-actions{display:flex;gap:5px;flex-wrap:wrap;justify-content:flex-end}.memory-actions button{border:1px solid #777;background:#fff;padding:4px 8px;cursor:pointer}.memory-actions button[aria-pressed=true]{background:#dff3fb;border-color:#237da1;font-weight:700}.memory-lanes{display:grid;grid-template-columns:repeat(auto-fit,minmax(125px,1fr));gap:6px;margin:8px 0}.memory-lane{min-width:0;display:flex;flex-direction:column;align-items:stretch;gap:3px;border:1px solid #999;background:#fafafa;padding:7px;text-align:left}.memory-lane.compile{background:#fff8dc}.memory-lane.bss{background:#edf7fb}.memory-lane.stack{background:#f3f8ef}.memory-lane.registers{background:#f4f4f4}.memory-lane.text{background:#f7f0fa}.memory-lane>b{font-size:11px;letter-spacing:.04em}.memory-lane button{border:1px solid transparent;background:transparent;padding:3px;text-align:left;cursor:pointer}.memory-lane button:hover,.memory-lane button.active{border-color:#238bb7;background:#fff}.memory-lane code{font-size:10px;white-space:normal}.arena-wrap{margin:12px 0 6px}.arena-label{display:flex;justify-content:space-between;margin-bottom:4px}.arena{--allocp: 0;--arena-size: 64;position:relative;display:grid;grid-template-columns:repeat(var(--arena-size),1fr);height:40px;border:1px solid #222;margin-bottom:28px}.arena i{border-right:1px solid #ddd}.arena .allocp{position:absolute;left:calc(var(--allocp) / var(--arena-size) * 100%);top:43px;transform:translate(-50%);color:#087da8;font:700 11px/1.2 ui-monospace,monospace;white-space:nowrap}.memory-stage{border-top:1px solid #ddd;padding-top:7px;margin:0}.memory-inspector{display:grid;grid-template-columns:auto 1fr;gap:2px 10px;margin-top:7px;padding:7px;border-left:3px solid #238bb7;background:#f5fbfd}.memory-inspector strong{grid-row:1/3}.memory-inspector code{font-size:11px}.memory-inspector span{font-size:12px}.asset-static-fallback{display:none}.uml-react{border:1px solid #555;background:#fff;font:13px/1.35 system-ui,sans-serif;color:#1b1b1b}.uml-react>header{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:6px 8px;border-bottom:1px solid #bbb;background:#fafafa}.uml-react>header small{display:block;color:#555;font:700 10px/1.2 ui-monospace,monospace;letter-spacing:.06em}.uml-react h3{margin:2px 0 0;font-size:15px}.uml-actions{display:flex;gap:3px;flex-wrap:wrap;justify-content:flex-end}.uml-actions button{border:1px solid #aaa;border-radius:2px;background:#fcfcfc;color:#444;padding:2px 6px;font:600 10px/1.25 ui-monospace,monospace;cursor:pointer}.uml-actions button:hover{border-color:#64879a;background:#f5fafc}.uml-actions button[data-completed=true]{border-color:#62a47f;background:#edf8f1;color:#14613a}.uml-actions button[aria-pressed=true]{border-color:#287495;background:#edf7fb;color:#174d64;box-shadow:inset 0 0 0 1px #b9dce9}.uml-canvas{display:block;overflow-x:hidden;overflow-y:visible;box-sizing:border-box;padding:8px 10px;text-align:center}.uml-svg-host{width:max-content;min-width:100%}.uml-canvas img,.uml-svg-host svg{display:block;width:auto!important;max-width:none!important;height:auto!important;max-height:none;margin-inline:auto;object-fit:contain}.uml-svg-host{cursor:pointer}.uml-svg-host.is-tiled{position:relative;width:var(--uml-tile-page-width);min-width:var(--uml-tile-page-width);height:var(--uml-tile-page-height);overflow:hidden;cursor:default}.uml-svg-host.is-tiled>svg{position:absolute;top:var(--uml-tile-top);left:var(--uml-tile-left);margin:0}.uml-static-crop{position:absolute;top:var(--uml-tile-top);left:var(--uml-tile-left);overflow:hidden}.uml-static-crop>img{display:block;max-width:none!important;max-height:none!important;margin:0!important;object-fit:fill!important;transform-origin:0 0}.uml-tile-part{display:inline-block;margin-left:.65em;color:#607985;font:650 9px/1.2 ui-monospace,monospace;letter-spacing:.03em;white-space:nowrap}.uml-phase-actions>span{display:inline-flex;align-items:center;border:1px solid #9eb2bd;border-radius:2px;background:#f1f5f7;color:#3d5967;padding:2px 6px;font:700 10px/1.25 ui-monospace,monospace}.uml-stage-region{cursor:pointer;transition:fill .14s ease,stroke .14s ease,stroke-width .14s ease}.uml-stage-region-completed.uml-stage-region-bg{fill:#e7f6ed!important;fill-opacity:1!important;stroke:#258154!important;stroke-width:3px!important}.uml-stage-region-completed.uml-stage-region-outline{stroke:#258154!important;stroke-width:3px!important}.uml-stage-region-active.uml-stage-region-bg{fill:#e7f6fc!important;fill-opacity:1!important;stroke:#187ea7!important;stroke-width:3px!important}.uml-stage-region-active.uml-stage-region-outline{stroke:#187ea7!important;stroke-width:3px!important}.uml-stage-region-active.uml-stage-region-completed.uml-stage-region-bg{fill:#e7f6ed!important}.uml-stage-region:focus{outline:none;stroke:#005f87!important;stroke-width:4px!important}.uml-inline-warning{display:block;padding-top:5px;color:#8b2d20;font-size:11px}.uml-stage{display:grid;grid-template-columns:auto 1fr;gap:3px 10px;margin:0 8px 8px;padding:8px;border-left:3px solid #315f78;background:#eef7fb}.uml-stage strong{grid-row:1/3}.uml-stage code{grid-column:2;font-size:11px}.uml-approval{display:flex;align-items:center;justify-content:space-between;gap:8px;margin:0 8px 8px;padding-top:6px;border-top:1px solid #d2d2d2;color:#555;font-size:11px}.uml-approval button{flex:0 0 auto;border:1px solid #477a5d;border-radius:2px;background:#edf8f1;color:#174e30;padding:3px 7px;font:600 10px/1.25 system-ui,sans-serif;cursor:pointer}.uml-approval button:disabled{border-color:#bbb;background:#f3f3f3;color:#888;cursor:not-allowed}.uml-react>.uml-snapshot-header{display:block;padding:5px 8px 4px}.uml-header-first-line{display:flex;align-items:center;justify-content:space-between;gap:10px}.uml-header-first-line h3{flex:1 1 auto;min-width:0;margin:0;color:#20282c;text-align:left;font-size:12px;line-height:1.25}.uml-header-first-line h3>span{color:#245f7a;font-family:ui-monospace,monospace;letter-spacing:.04em}.uml-header-description{max-width:620px;margin:2px 0 0;color:#555;text-align:left;font-size:8px}.uml-header-navigation{display:flex;flex:0 0 auto;align-items:center;justify-content:flex-end;gap:6px}.uml-page-continuation{display:inline-flex;flex:0 0 auto;align-items:center;gap:2px;min-height:22px;border:1px solid #86a5b3;border-radius:3px;background:#edf7fa;padding:1px 5px;color:#126b8c;font:850 15px/1 ui-monospace,monospace;animation:uml-continuation-pulse 1.15s ease-in-out infinite alternate}.uml-page-continuation i{display:inline-grid;min-width:14px;place-items:center;font-style:normal}@keyframes uml-continuation-pulse{0%{border-color:#9fb5be;background:#f6fafb;color:#4c7180;box-shadow:none}to{border-color:#167ca4;background:#dff2f8;color:#075c7c;box-shadow:0 0 0 2px #8dcde433}}@media(prefers-reduced-motion:reduce){.uml-page-continuation{animation:none}}.uml-phase-actions,.uml-step-actions{display:flex;align-items:center;flex-wrap:wrap;gap:3px}.uml-phase-actions{flex:0 0 auto;flex-wrap:nowrap;justify-content:flex-end;white-space:nowrap}.uml-phase-actions button,.uml-step-actions button,.uml-edit-toggle,.uml-snapshot-cursor button{border:1px solid #aaa;border-radius:2px;background:#fff;color:#444;cursor:pointer;font:600 9px/1.2 ui-monospace,monospace}.uml-edit-toggle{min-width:42px;padding:3px 7px;border:1px solid #8a9ca5;border-radius:2px;background:#f7f9fa;color:#334d59;cursor:pointer;font:750 9px/1.2 ui-monospace,monospace;letter-spacing:.04em}.uml-edit-toggle.is-active{border-color:#b56b16;background:#fff3df;color:#713c00;box-shadow:inset 0 0 0 1px #f0c78f}.uml-phase-actions button{padding:3px 7px}.uml-phase-actions button[aria-pressed=true]{border-color:#287495;background:#edf7fb;color:#174d64}.uml-step-actions{min-height:0;padding:0;border:0;background:transparent}.uml-step-actions>span{margin-right:4px;color:#555;font:700 9px/1.2 ui-monospace,monospace}.uml-step-actions button{min-width:25px;padding:2px 4px}.uml-step-actions button[data-completed=true]{border-color:#62a47f;background:#edf8f1;color:#14613a}.uml-step-actions button[aria-pressed=true]{border-color:#287495;background:#287495;color:#fff}.uml-step-actions button[data-mode=CODE]:after,.uml-step-actions button[data-mode=RUN]:after{margin-left:3px;font-size:7px;letter-spacing:.02em}.uml-step-actions button[data-mode=CODE]:after{content:"C"}.uml-step-actions button[data-mode=RUN]:after{content:"R"}.uml-snapshot-layout{background:#fff;border-bottom:1px solid #ddd}.uml-step-canvas{min-width:0}.uml-step-canvas .uml-svg-host svg{max-height:none}.uml-step-hit{cursor:pointer;fill:transparent}.uml-step-hit-active{fill:#3ea6ce!important;fill-opacity:.08!important}.uml-step-element{transition:fill .12s ease,stroke .12s ease,stroke-width .12s ease}line.uml-step-element-completed:not(.uml-step-element-active){stroke:#258154!important;stroke-width:1.8px!important}polygon.uml-step-element-completed:not(.uml-step-element-active){fill:#258154!important;stroke:#258154!important}text.uml-step-element-completed:not(.uml-step-element-active){fill:#1d7049!important}line.uml-step-element-active{stroke:#087ca8!important;stroke-width:2.6px!important}polygon.uml-step-element-active{fill:#087ca8!important;stroke:#087ca8!important}text.uml-step-element-active{fill:#075d7d!important;font-weight:700!important}.uml-step-hit:focus{outline:none;stroke:#bd554d;stroke-width:.8px;stroke-dasharray:3 3}.uml-class-svg-active>g>*:not(.uml-class-focus-region):not(.uml-class-step-hit):not(.uml-layout-hit):not(.uml-layout-resize){opacity:.62;transition:opacity .12s ease}.uml-class-svg-active .uml-step-element:not(.uml-step-element-active){opacity:.98!important}.uml-class-svg-active text.uml-step-element-tone-a:not(.uml-step-element-active){fill:#174f69!important}.uml-class-svg-active text.uml-step-element-tone-b:not(.uml-step-element-active){fill:#586581!important}.uml-class-svg-active rect.uml-step-element-tone-a:not(.uml-step-element-active){fill:#eaf5f8!important;stroke:#3f7890!important}.uml-class-svg-active rect.uml-step-element-tone-b:not(.uml-step-element-active){fill:#f2eef8!important;stroke:#7b86a1!important}.uml-class-svg-active path.uml-step-element-tone-a:not(.uml-step-element-active),.uml-class-svg-active line.uml-step-element-tone-a:not(.uml-step-element-active),.uml-class-svg-active polygon.uml-step-element-tone-a:not(.uml-step-element-active){stroke:#3f7890!important}.uml-class-svg-active path.uml-step-element-tone-b:not(.uml-step-element-active),.uml-class-svg-active line.uml-step-element-tone-b:not(.uml-step-element-active),.uml-class-svg-active polygon.uml-step-element-tone-b:not(.uml-step-element-active){stroke:#7b86a1!important}.uml-class-svg-active .uml-step-element-active{opacity:1!important}.uml-class-svg-active text.uml-step-element-active{fill:#b42318!important;font-weight:700!important}.uml-class-svg-active path.uml-step-element-active,.uml-class-svg-active line.uml-step-element-active,.uml-class-svg-active polygon.uml-step-element-active,.uml-class-svg-active rect.uml-step-element-active{stroke:#bd554d!important;stroke-width:1.35px!important}.uml-class-svg-active polygon.uml-step-element-active{fill:#bd554d!important}.uml-class-focus-region{display:none}.uml-step-canvas.is-layout-editing{position:relative;touch-action:none;background-color:#fbfcfd;background-image:linear-gradient(#7d98a20d 1px,transparent 1px),linear-gradient(90deg,#7d98a20d 1px,transparent 1px);background-size:12px 12px}.uml-layout-editing .uml-step-hit,.uml-layout-editing .uml-class-focus-region{pointer-events:none}.uml-layout-hit{fill:#4e9ec4;fill-opacity:.035;stroke:#247a9e;stroke-width:1.1px;stroke-dasharray:5 3;vector-effect:non-scaling-stroke;cursor:grab;pointer-events:all}.uml-layout-hit:hover{fill-opacity:.09;stroke-width:1.6px}.uml-layout-hit.is-selected{fill:#f7a928;fill-opacity:.08;stroke:#b66b00;stroke-width:1.8px;stroke-dasharray:none}.uml-layout-hit:active{cursor:grabbing}.uml-layout-resize{fill:#fff;stroke:#b66b00;stroke-width:1.5px;vector-effect:non-scaling-stroke;cursor:nwse-resize;pointer-events:all}.uml-layout-editor{display:grid;grid-template-columns:minmax(140px,.8fr) minmax(240px,1.8fr) minmax(260px,1.4fr);gap:7px 10px;align-items:end;padding:8px 10px 9px;border-top:2px solid #b97822;background:#f7f5f0;color:#26343a;text-align:left;font:10px/1.3 system-ui,sans-serif}.uml-layout-editor-title{grid-column:1/-1;display:flex;align-items:baseline;gap:9px}.uml-layout-editor-title strong{color:#713c00;font:800 11px/1.2 ui-monospace,monospace;text-transform:uppercase}.uml-layout-editor-title span{color:#65737a}.uml-layout-editor-title b{margin-left:auto;color:#9c2f1b;font-size:9px}.uml-layout-editor label{display:grid;gap:2px;color:#52636b;font:700 8px/1.2 ui-monospace,monospace;text-transform:uppercase}.uml-layout-editor input,.uml-layout-editor select,.uml-layout-editor textarea{box-sizing:border-box;width:100%;min-width:0;border:1px solid #9ca9ae;border-radius:2px;background:#fff;color:#172126;padding:4px 5px;font:10px/1.25 ui-monospace,monospace;text-transform:none}.uml-layout-editor textarea{resize:vertical;line-height:1.35}.uml-layout-number-grid,.uml-layout-style-grid{display:grid;gap:5px}.uml-layout-number-grid{grid-template-columns:repeat(4,minmax(48px,1fr))}.uml-layout-style-grid{grid-template-columns:repeat(5,minmax(54px,1fr))}.uml-layout-editor-text{align-self:stretch}.uml-layout-editor input[type=color]{min-height:27px;padding:2px}.uml-layout-editor-actions{grid-column:1/-1;display:flex;gap:5px}.uml-layout-editor-actions button{border:1px solid #87979f;border-radius:2px;background:#fff;color:#283940;padding:4px 8px;cursor:pointer;font:700 9px/1.2 ui-monospace,monospace}.uml-layout-editor-actions button.is-primary{border-color:#287495;background:#287495;color:#fff}.uml-layout-editor-actions button.is-danger{margin-left:auto;border-color:#a26156;color:#812b1c}.uml-layout-editor-actions button:disabled{opacity:.45;cursor:not-allowed}.uml-layout-editor output{grid-column:1/-1;min-height:1.2em;color:#52636b;font:9px/1.25 ui-monospace,monospace}@media(max-width:900px){.uml-layout-editor{grid-template-columns:1fr}.uml-layout-editor-title,.uml-layout-editor-actions,.uml-layout-editor output{grid-column:1}}@media print{.uml-edit-toggle,.uml-layout-editor,.uml-layout-hit,.uml-layout-resize{display:none!important}}.uml-snapshot-panel{display:grid;gap:8px;min-width:0;padding:8px;background:#fafafa;font-size:10px}.uml-snapshot-panel>header{display:flex;justify-content:space-between;gap:8px;align-items:center}.uml-snapshot-panel>header>div:first-child>span,.uml-snapshot-panel>header>div:first-child>strong{display:block}.uml-snapshot-panel>header>div:first-child>span{color:#5a5a5a;font:700 9px/1.2 ui-monospace,monospace}.uml-snapshot-panel>header>div:first-child>strong{font-size:12px}.uml-snapshot-panel>header>div:first-child>strong code{display:inline-block;min-width:24px;color:#075d7d}.uml-snapshot-cursor{display:flex;align-items:center;gap:4px}.uml-snapshot-cursor button{width:23px;height:23px;padding:0}.uml-snapshot-cursor button:disabled{opacity:.35;cursor:default}.uml-snapshot-cursor output{min-width:34px;text-align:center;font:700 9px/1 ui-monospace,monospace}.uml-snapshot-description{margin:0;color:#333}.uml-snapshot-panel section{min-width:0;border:1px solid #d0d0d0;background:#fff;padding:7px}.uml-snapshot-panel h4{margin:0 0 4px;color:#315f78;font:700 9px/1.2 ui-monospace,monospace;text-transform:uppercase}.uml-state-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:7px;min-width:0}.uml-snapshot-registers dl{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:3px;margin:0}.uml-snapshot-registers dl>div{display:grid;grid-template-columns:auto 1fr;gap:5px;min-width:0;padding:2px 4px;border-left:2px solid #bbb;background:#f6f6f6}.uml-snapshot-registers dl>div.primary{grid-column:1/-1;border-color:#287495;background:#edf7fb}.uml-snapshot-registers dt{color:#555;font-weight:700}.uml-snapshot-registers dd,.uml-snapshot-variables dd,.uml-snapshot-memory dd{min-width:0;margin:0;overflow-wrap:anywhere;text-align:right;font:600 9px/1.25 ui-monospace,monospace}.uml-snapshot-variables dl{display:grid;gap:3px;margin:0}.uml-snapshot-variables dl>div{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:5px;padding:3px 5px;border-left:2px solid #5f899b;background:#f5f8f9}.uml-snapshot-variables dt{font-weight:700}.uml-snapshot-variables dt small{display:block;color:#777;font:8px/1.2 ui-monospace,monospace}.uml-snapshot-variables [data-state=uninitialised],.uml-stack-lane article[data-state=uninitialised]{color:#777;background:#f5f5f5}.uml-snapshot-variables [data-state=uninitialised] dt:after,.uml-stack-lane article[data-state=uninitialised]>strong:after{content:" ?";color:#9a6a00}.uml-arena-snapshot>div{position:relative;height:10px;border:1px solid #666;background:repeating-linear-gradient(90deg,#fff 0 7px,#eee 7px 8px)}.uml-arena-snapshot>div span{display:block;height:100%;background:#b8ddeb}.uml-arena-snapshot>div i{position:absolute;top:-3px;bottom:-3px;width:2px;background:#075d7d;transform:translate(-1px)}.uml-arena-snapshot>p{display:grid;grid-template-columns:1fr auto 1fr;gap:4px;margin:3px 0;font-size:8px}.uml-arena-snapshot>p code:last-child{text-align:right}.uml-arena-bytes{display:block;margin-bottom:4px;overflow-wrap:anywhere;color:#666;font-size:8px}.uml-snapshot-memory dl{display:grid;gap:2px;margin:0}.uml-snapshot-memory dl>div{display:grid;grid-template-columns:1fr auto;gap:4px;padding-top:2px;border-top:1px solid #eee}.uml-snapshot-memory dt{font-weight:700}.uml-snapshot-memory dt small{display:block;color:#777;font:8px/1.2 ui-monospace,monospace}.uml-snapshot-stack>header{display:flex;align-items:baseline;justify-content:space-between;gap:8px}.uml-snapshot-stack>header>p{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:4px 9px;margin:0;color:#555;font-size:8px}.uml-stack-axis{display:flex;justify-content:space-between;gap:8px;margin:3px 89px 2px;color:#777;font:8px/1.2 ui-monospace,monospace}.uml-stack-lane{display:flex;align-items:stretch;min-width:0;overflow-x:auto;border:1px solid #66757c;background:#eef1f2}.uml-stack-boundary{display:grid;place-content:center;flex:0 1 82px;min-width:64px;padding:5px;background:#273941;color:#fff;text-align:center;font:700 8px/1.25 ui-monospace,monospace}.uml-stack-boundary small{color:#a9d9eb;font-size:8px;text-transform:uppercase}.uml-stack-gap{display:grid;place-content:center;flex:.7 1 70px;min-width:60px;min-height:52px;border-right:1px dashed #9da8ad;color:#78858b;text-align:center;font:8px/1.2 ui-monospace,monospace}.uml-stack-gap strong,.uml-stack-gap small{display:block}.uml-stack-gap strong{color:#52636b}.uml-stack-gap small{color:#78858b;font-size:8px}.uml-stack-lane article{display:grid;align-content:center;flex:1 1 92px;min-width:76px;padding:5px 7px;border-right:1px solid #9da8ad;background:#fff;text-align:center}.uml-stack-lane article[data-state=initialised]{border-top:3px solid #2c8060}.uml-stack-lane article[data-state=saved]{border-top:3px solid #6d7196;background:#f7f6fb}.uml-stack-lane article strong,.uml-stack-lane article code,.uml-stack-lane article small{display:block;overflow-wrap:anywhere}.uml-stack-lane article strong{font:700 9px/1.2 ui-monospace,monospace}.uml-stack-lane article code{margin:2px 0;color:#1f4555;font-size:8px}.uml-stack-lane article small{color:#777;font:8px/1.2 ui-monospace,monospace}.uml-snapshot-observation p{margin:0 0 3px}.uml-snapshot-observation small{display:block;overflow-wrap:anywhere;color:#666;font:8px/1.3 ui-monospace,monospace}.task-conclusion{margin:8px 0 0;padding:7px 9px;border:1px solid #315f78;background:#f3f9fc}.task-conclusion>strong{display:block;margin-bottom:3px;color:#315f78;font:700 10px/1.2 ui-monospace,monospace}.task-conclusion p{margin:0}.asset-source-link{display:inline-block;margin:5px 0;color:#315f78;font:600 11px/1.3 system-ui,sans-serif}.section-sheet--asset .section-heading{align-items:baseline;margin:0 0 1.5mm}.section-sheet--asset .section-heading .section-index{margin-right:4mm;color:#68757b;font-size:10px;font-weight:600}.section-sheet--asset .section-heading .section-title{color:#20282c;font:750 13px/1.2 system-ui,sans-serif}.section-sheet--asset .card-section>p{max-width:110ch;margin:0 0 2mm;color:#58656b;font:9px/1.3 system-ui,sans-serif}.section-sheet--asset .card-asset{margin-top:2mm}.lesson-progress-control{display:inline-flex;align-items:center;margin-right:7px;padding:2px 7px;border:1px solid #8c8c8c;border-radius:12px;background:#fff;cursor:pointer}.lesson-progress-control:disabled{cursor:wait;opacity:.6}.lesson-progress-control[data-status=approved]{background:#e7f6ed;border-color:#18794e}.lesson-progress-topbar{display:flex;flex:none;align-items:center;gap:5px;min-width:0;padding-left:7px;border-left:1px solid #a9b3b8;color:#33444c;font:650 10px/1.2 system-ui,sans-serif;white-space:nowrap}.lesson-progress-topbar strong{color:#52636b;font:800 9px/1 ui-monospace,monospace;letter-spacing:.05em}.lesson-progress-topbar output{min-width:3.8ch;border:1px solid #91a1a8;border-radius:999px;background:#fff;padding:2px 6px;color:#1e566e;text-align:center;font:800 9px/1 ui-monospace,monospace}.lesson-progress-topbar a{color:#245f7a;text-decoration:none}.lesson-progress-topbar a:hover,.lesson-progress-topbar a:focus-visible{text-decoration:underline}.lesson-progress-error{color:#9b1c1c;font-weight:900}.step-row{display:flex;align-items:center;margin:4px 0}.section-anchor{position:relative;top:-45px}.app-load-error{max-width:760px;margin:10vh auto;padding:24px;border:1px solid #9b1c1c;background:#fff;font-family:system-ui,sans-serif}.app-load-error pre{white-space:pre-wrap}@media(max-width:800px){.viewpoint-bar{grid-template-columns:repeat(4,minmax(0,1fr))}.viewpoint-bar button{min-height:28px}.card-library-toggle>span:last-child{display:none}.card-library-toggle{gap:4px;padding-inline:6px}.topbar-nvim-meta{display:none}.topbar-nvim-section .nvim-control-indicator{max-width:42vw;overflow:hidden;text-overflow:ellipsis}.nvim-shortcut-strip,.nvim-work-indicator{display:none}.allocator-panel>header{grid-template-columns:auto 1fr}.allocator-panel>header>small{display:none}.allocator-panel-body{grid-template-columns:1fr}.allocator-metrics,.allocator-facts{display:none}.memory-lanes{grid-template-columns:1fr 1fr}.memory-react>header,.uml-react>header{align-items:flex-start;flex-direction:column}.uml-header-first-line,.uml-header-navigation{width:100%;align-items:flex-start;flex-direction:column}.uml-header-navigation{gap:4px}.memory-actions{justify-content:flex-start}.uml-snapshot-layout{display:block}.uml-step-canvas{border:0}.uml-phase-actions{width:100%;justify-content:flex-end}.uml-state-grid{grid-template-columns:1fr}.uml-snapshot-stack>header{align-items:flex-start;flex-direction:column}.uml-snapshot-stack>header>p{justify-content:flex-start}.uml-stack-axis{margin-right:0;margin-left:0}}@media print{@page card-portrait{size:A4 portrait;margin:0}@page card-landscape{size:A4 landscape;margin:0}.sheet--portrait{page:card-portrait}.sheet--landscape{page:card-landscape}.paper{display:block;gap:0}.paper>.sheet,.paper>.sheet>.sheet-content,.paper>.sheet-spread>.sheet,.paper>.sheet-spread>.sheet>.sheet-content{height:auto;min-height:0;max-height:none;overflow:visible}.sheet-spread{display:contents!important}.viewer-chrome,.side-panel-dock,.memory-react{display:none!important}.asset-static-fallback{display:block!important;width:100%}.uml-actions,.uml-phase-actions,.uml-step-actions,.uml-snapshot-panel,.uml-stage,.uml-approval,.asset-source-link,.lesson-progress-topbar,.lesson-progress-control,.uml-page-continuation{display:none!important}} +.paper{display:flex;flex-direction:column;gap:3.3cm}.paper>.sheet,.paper>.sheet-spread>.sheet{width:210mm;height:297mm;min-height:297mm;max-height:297mm;margin:0 auto;overflow:hidden}.paper>.sheet.sheet--landscape,.paper>.sheet-spread>.sheet.sheet--landscape{width:297mm;min-width:297mm;max-width:297mm;height:210mm;min-height:210mm;max-height:210mm}.paper>.sheet>.sheet-content,.paper>.sheet-spread>.sheet>.sheet-content{box-sizing:border-box;height:297mm;min-height:297mm;max-height:297mm;overflow-x:hidden;overflow-y:hidden}.paper>.sheet.sheet--landscape>.sheet-content,.paper>.sheet-spread>.sheet.sheet--landscape>.sheet-content{height:210mm;min-height:210mm;max-height:210mm}.page-resource-footer{position:absolute;z-index:4;right:21.5mm;bottom:3mm;left:21.5mm;display:grid;grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);align-items:center;gap:8px;min-height:5mm;border-top:.35mm solid #252525;background:#fff;padding-top:1.2mm;color:#68747a;font:650 7px/1.15 ui-monospace,monospace}.page-resource-footer__uuid{overflow:hidden;color:#4d5d65;text-align:left;text-overflow:ellipsis;white-space:nowrap;font:inherit}.page-resource-footer__author{color:#4d5d65;text-align:center;white-space:nowrap}.page-resource-footer__page{color:#283940;text-align:right;white-space:nowrap}.sheet-spread{display:contents}.paper.is-diagram-spread .sheet-spread{display:grid;grid-template-columns:repeat(var(--spread-columns, 1),max-content);width:max-content;max-width:none;margin:0 auto;align-items:flex-start;gap:2mm;zoom:var(--spread-fit-scale, 1)}.paper.is-diagram-spread .sheet-spread>.sheet{flex:0 0 auto}.viewer-chrome{position:sticky;top:0;z-index:80;width:100%}.viewer-action-toast{position:absolute;z-index:12;right:9px;bottom:9px;max-width:min(720px,calc(100vw - 18px));box-sizing:border-box;overflow:hidden;border:1px solid #42b8e7;border-radius:3px;background:#102c38ee;color:#dff7ff;padding:5px 9px;box-shadow:0 4px 14px #0007;text-overflow:ellipsis;white-space:nowrap;font:750 10px/1.25 ui-monospace,monospace}.viewer-chrome .topbar{position:sticky;top:0;z-index:90}.viewpoint-bar{display:grid;grid-template-columns:repeat(8,minmax(0,1fr));gap:1px;min-height:31px;border-top:1px solid #9aa8ae;border-bottom:1px solid #718087;background:#718087;box-shadow:0 2px 5px #0002}.viewpoint-bar button{position:relative;display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:5px;min-width:0;border:0;background:#f7f9fa;color:#1f3038;padding:5px 7px;text-align:left;cursor:pointer}.viewpoint-bar button:hover,.viewpoint-bar button:focus-visible{z-index:1;background:#e9f3f7;outline:2px solid #287495;outline-offset:-2px}.viewpoint-bar button[aria-current=location]{background:#dcecf3;box-shadow:inset 0 -3px #167ca4}.viewpoint-bar button>span{color:#1b6785;font:850 10px/1 ui-monospace,monospace}.viewpoint-bar button>strong{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font:750 10px/1.1 system-ui,sans-serif}.viewpoint-bar button.is-unavailable{background:#eef0f1;color:#5d686d;cursor:not-allowed}.viewpoint-bar button.is-unavailable>span{color:#68747a}.viewpoint-bar button.is-unavailable>small{border:1px solid #9da7ab;border-radius:2px;padding:1px 3px;font:750 7px/1 ui-monospace,monospace}.card-library-toggle{display:inline-flex;align-items:center;flex:none;height:28px;gap:6px;border:1px solid #6e7d84;border-radius:3px;background:#f6f8f9;color:#26373f;padding:2px 8px;font:750 11px/1 ui-monospace,monospace;cursor:pointer}.card-library-toggle:hover,.card-library-toggle:focus-visible{border-color:#1d7799;background:#edf7fa;outline:none}.card-library-toggle.is-active{border-color:#126d8f;background:#174f67;color:#fff}.card-library-toggle-icon{font:700 16px/1 system-ui,sans-serif}.card-library-toggle kbd{color:#267697;font:inherit}.card-library-toggle.is-active kbd{color:#aee9ff}.runtime-source-selector{display:inline-flex;align-items:center;flex:none;height:28px;box-sizing:border-box;gap:5px;border:1px solid #6e7d84;border-radius:3px;background:#edf2f4;color:#44545b;padding-left:7px;font:750 9px/1 ui-monospace,monospace;letter-spacing:.05em}.runtime-source-selector select{height:26px;min-width:17ch;max-width:19ch;border:0;border-left:1px solid #a8b4b9;border-radius:0 2px 2px 0;background:#fff;color:#174f67;padding:2px 22px 2px 7px;font:800 10px/1 ui-monospace,monospace;cursor:pointer}.runtime-source-selector select:hover,.runtime-source-selector select:focus-visible{background:#edf7fa;outline:2px solid #287495;outline-offset:-2px}.runtime-source-selector option:disabled{color:#7d898e}:root{--side-panel-top: 36px;--side-panel-width: min(960px, calc(100vw - 28px) );--side-panel-trigger-length: 56px}.side-panel-dock{position:fixed;z-index:240;top:var(--side-panel-top);bottom:0;width:0;pointer-events:none}.side-panel-dock--left{left:0}.side-panel-dock--right{right:0}.side-panel-rail{position:fixed;z-index:243;top:calc(var(--side-panel-top) + 8px);display:flex;width:13px;flex-direction:column;gap:10px;pointer-events:auto}.side-panel-dock--left .side-panel-rail{left:0}.side-panel-dock--right .side-panel-rail{right:0}.side-panel-trigger{--side-panel-accent: #167ca4;position:relative;display:grid;width:13px;height:var(--side-panel-trigger-length);place-items:center;border:0;border-radius:0;background:transparent;padding:0;cursor:pointer}.side-panel-trigger:before{content:"";display:block;width:3px;height:calc(var(--side-panel-trigger-length) - 8px);border-radius:999px;background:var(--side-panel-accent);box-shadow:0 0 0 1px #ffffff73,0 3px 10px -5px var(--side-panel-accent);opacity:.78;transition:width .14s ease,opacity .14s ease,box-shadow .14s ease}.side-panel-trigger:hover:before,.side-panel-trigger:focus-visible:before,.side-panel-trigger.is-open:before{width:4px;opacity:1}.side-panel-trigger.is-pinned:before{width:5px;box-shadow:0 0 0 1px #ffffff9e,0 3px 12px -4px var(--side-panel-accent)}.side-panel-trigger:focus-visible{outline:2px solid var(--side-panel-accent);outline-offset:-2px}.side-panel-trigger>span{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}.side-panel{position:fixed;z-index:241;top:var(--side-panel-top);bottom:0;display:flex;width:var(--side-panel-width);max-width:calc(100vw - 20px);box-sizing:border-box;flex-direction:column;overflow:hidden;border-color:#819098;background:#f7f9fa;color:#17252c;pointer-events:none;transition:transform .18s cubic-bezier(.22,.78,.24,1);will-change:transform}.side-panel-dock--left .side-panel{left:0;border-right:1px solid #819098;box-shadow:15px 0 34px -24px #101b218c;transform:translate(calc(-100% - 14px))}.side-panel-dock--right .side-panel{right:0;border-left:1px solid #819098;box-shadow:-15px 0 34px -24px #101b218c;transform:translate(calc(100% + 14px))}.side-panel.is-open{transform:translate(0);pointer-events:auto}.side-panel:after{content:"";position:absolute;top:10px;width:4px;height:48px;border-radius:999px;background:var(--side-panel-accent);pointer-events:none}.side-panel-dock--left .side-panel:after{right:-2px}.side-panel-dock--right .side-panel:after{left:-2px}.side-panel-header{display:flex;min-height:38px;box-sizing:border-box;align-items:center;justify-content:space-between;gap:10px;border-bottom:1px solid #aebbc1;background:#e7edef;padding:4px 7px 4px 10px}.side-panel-header>div:first-child{display:flex;min-width:0;align-items:baseline;gap:7px}.side-panel-header small{color:#52666f;font:600 16px/1 ui-monospace,monospace;letter-spacing:.08em}.side-panel-header strong{overflow:hidden;color:#11191d;text-overflow:ellipsis;white-space:nowrap;font:600 16px/1.2 system-ui,sans-serif}.side-panel-actions{display:flex;flex:none;gap:4px}.side-panel-actions button{display:grid;min-width:38px;height:24px;place-items:center;border:1px solid #8b999f;border-radius:3px;background:#fff;color:#26373f;padding:0 6px;font:650 16px/1 ui-monospace,monospace;cursor:pointer}.side-panel-actions button:last-child{min-width:24px;padding:0;font-size:18px}.side-panel-actions button:hover,.side-panel-actions button:focus-visible,.side-panel-actions button.is-pinned{border-color:var(--side-panel-accent);background:#edf7fa;outline:none}.side-panel-body,.card-library-panel{display:flex;min-height:0;flex:1;flex-direction:column;overflow:hidden}.card-library-header{display:flex;align-items:flex-start;justify-content:space-between;gap:14px;padding:18px 18px 15px;border-bottom:1px solid #bdc9ce;background:#e8eef1}.card-library-header small{color:#52666f;font:600 16px/1.25 ui-monospace,monospace;letter-spacing:.09em;text-transform:uppercase}.card-library-header h2{margin:4px 0 2px;font:750 22px/1.15 system-ui,sans-serif}.card-library-header p{margin:0;color:#607078;font:500 16px/1.35 system-ui,sans-serif}.card-library-header>button{display:grid;width:34px;height:34px;place-items:center;flex:none;border:1px solid #77878e;border-radius:3px;background:#fff;color:#25353c;padding:0;font:25px/1 system-ui,sans-serif;cursor:pointer}.card-library-header>button:hover,.card-library-header>button:focus-visible{border-color:#126d8f;background:#edf7fa;outline:2px solid #85c5dc;outline-offset:1px}.card-library-tree{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:6px 0 18px;scrollbar-color:#8a9aa1 #edf1f3}.card-library-tree details{border:0}.card-library-tree summary{display:grid;grid-template-columns:14px minmax(0,1fr) auto;align-items:center;gap:6px;min-height:30px;box-sizing:border-box;padding:5px 10px 5px 4px;list-style:none;cursor:pointer;user-select:none}.card-library-tree summary::-webkit-details-marker{display:none}.card-library-tree summary:hover,.card-library-tree summary:focus-visible{background:#eaf1f4;outline:none}.card-library-branch{color:#25363d;font:16px/1 ui-monospace,monospace;transform:rotate(-90deg);transition:transform .12s ease}.card-library-tree details[open]>summary .card-library-branch{transform:rotate(0)}.card-library-tree summary strong,.card-library-tree summary small{display:block}.card-library-tree summary strong{color:#070a0b;font:550 16px/1.3 system-ui,sans-serif}.card-library-tree summary small{margin-top:2px;color:#303b40;font:500 16px/1.25 ui-monospace,monospace;letter-spacing:.04em}.card-library-tree summary output{min-width:22px;color:#26363d;padding:0 2px;text-align:center;font:550 16px/1.2 ui-monospace,monospace}.card-library-subject>summary{min-height:42px;border-bottom:1px solid #9eacb2;background:#dfe8ec;padding:7px 14px}.card-library-subject>summary:hover,.card-library-subject>summary:focus-visible{background:#d5e1e5}.card-library-subject>summary strong{color:#000;font:600 16px/1.3 system-ui,sans-serif}.card-library-subject>summary small{color:#28353a;font:500 16px/1.25 ui-monospace,monospace}.card-library-level-list{margin-left:18px;border-left:1px solid #8e9da4}.card-library-level>summary{min-height:38px;border-bottom:1px solid #cbd4d8;padding-left:8px}.card-library-level>summary strong{color:#000;font:550 16px/1.3 system-ui,sans-serif}.card-library-series-list{margin-left:18px;border-left:1px solid #a5b1b6;padding:2px 0 6px}.card-library-series>summary{min-height:34px;padding-left:8px}.card-library-series>summary strong{color:#000;font:550 16px/1.3 system-ui,sans-serif}.card-library-series>summary small{color:#26343a;font:500 16px/1.25 ui-monospace,monospace}.card-library-cards,.card-library-tasks{list-style:none;margin-top:0;margin-bottom:2px;padding:0}.card-library-cards{margin-left:18px;border-left:1px solid #bac3c7}.card-library-card-entry{margin:0}.card-library-card{display:grid;grid-template-columns:19px minmax(0,1fr) auto;align-items:start;gap:5px;min-height:38px;box-sizing:border-box;border:0;border-left:3px solid transparent;color:#000;padding:5px 8px 5px 3px;text-decoration:none}.card-library-node{color:#536168;font:16px/1.35 ui-monospace,monospace}.card-library-card-copy,.card-library-card-copy strong,.card-library-card-copy>span{display:block;min-width:0}.card-library-card-copy strong{color:#000;font:550 16px/1.3 ui-monospace,monospace}.card-library-card-copy>span{margin-top:2px;color:#0b0d0e;font:500 16px/1.35 system-ui,sans-serif;white-space:normal}.card-library-card-meta{display:flex;align-items:flex-end;flex-direction:column;gap:2px}.card-library-card-meta small{color:#26343a;font:500 16px/1.25 ui-monospace,monospace}.card-library-card.is-available{cursor:pointer}.card-library-card.is-available:hover,.card-library-card.is-available:focus-visible{background:#eaf5f8;outline:none}.card-library-card.is-current{border-left-color:#16769b;background:#dff1f7}.card-library-card.is-current:hover,.card-library-card.is-current:focus-visible{background:#cfeaf3;outline:1px solid #5ba9c4;outline-offset:-1px}.card-library-card.is-unavailable{color:#000}.card-library-card.is-unavailable .card-library-card-copy strong,.card-library-card.is-unavailable .card-library-card-meta small{color:#1d292e}.card-library-card.is-unavailable .card-library-card-copy>span{color:#0b0d0e}.card-library-tasks{margin-left:36px;border-left:1px solid #c3cacc}.card-library-tasks li>a,.card-library-tasks li>span{display:grid;grid-template-columns:19px auto minmax(0,1fr);gap:5px;align-items:start;color:#000;padding:4px 8px 5px 3px;text-decoration:none}.card-library-tasks li>a:hover,.card-library-tasks li>a:focus-visible{background:#eaf5f8;outline:none}.card-library-tasks strong{color:#000;font:550 16px/1.35 ui-monospace,monospace}.card-library-tasks li>a>span:last-child,.card-library-tasks li>span>span:last-child{color:#111;font:500 16px/1.35 system-ui,sans-serif}.card-library-footer{display:flex;align-items:center;gap:12px;flex-wrap:wrap;padding:10px 16px;border-top:1px solid #bdc9ce;background:#edf1f3;color:#5a6a72;font:500 16px/1.3 system-ui,sans-serif}.card-library-footer span{display:inline-flex;align-items:center;gap:4px}.card-library-footer i{width:7px;height:7px;border-radius:50%;background:#929da2}.card-library-footer i.is-online{background:#26815b}.card-library-footer kbd{margin-left:auto;border:1px solid #a2afb5;border-radius:2px;background:#fff;padding:2px 5px;font:600 16px/1 ui-monospace,monospace}.card-library-treegrid{min-height:0;flex:1;overflow:auto;margin:8px;border:1px solid rgb(31 35 40 / 18%);border-radius:6px;background:#fff;scrollbar-color:#93a2a8 #edf1f2;scrollbar-width:thin}.card-library-treegrid-row{display:grid;min-width:760px;min-height:38px;box-sizing:border-box;grid-template-columns:minmax(500px,1fr) 110px 120px;align-items:stretch;border-bottom:1px solid rgb(31 35 40 / 9%);color:#273941;font:500 16px/1.25 ui-monospace,monospace}.card-library-treegrid-row>[role=gridcell],.card-library-treegrid-row>[role=columnheader]{display:flex;min-width:0;align-items:center;overflow:hidden;padding:7px 9px;text-overflow:ellipsis;white-space:nowrap}.card-library-treegrid-row>[role=gridcell]+[role=gridcell],.card-library-treegrid-row>[role=columnheader]+[role=columnheader]{border-left:1px solid rgb(31 35 40 / 9%)}.card-library-treegrid-head{position:sticky;z-index:3;top:0;min-height:34px;border-bottom-color:#1f232833;background:#eef1f2;color:#3e525b;font-weight:700;letter-spacing:.045em}.card-library-treegrid-row:not(.card-library-treegrid-head):hover{background:#1f23280a}.card-library-treegrid-row.is-subject{background:#dfe8e5}.card-library-treegrid-row.is-level{background:#f5f8f8}.card-library-treegrid-row.is-series{background:#f9fbfb}.card-library-treegrid-row.is-card{min-height:42px;background:#fff}.card-library-treegrid-row.is-task{background:#fbfcfc}.card-library-treegrid-row.is-current{box-shadow:inset 3px 0 #1680a5;background:#e1f1f6}.card-library-tree-title{gap:6px;padding-left:calc(8px + (var(--card-library-depth, 0) * 21px))!important;font-family:system-ui,sans-serif}.card-library-tree-expander{display:inline-grid;width:24px;height:24px;flex:none;place-items:center;border:0;background:transparent;color:#405961;padding:0;font:18px/1 ui-monospace,monospace;cursor:pointer}.card-library-tree-expander:hover,.card-library-tree-expander:focus-visible{background:#165d6b1a;color:#165d6b;outline:1px solid rgb(22 93 107 / 28%)}.card-library-tree-expander.is-empty{cursor:default}.card-library-tree-link,.card-library-tree-label{display:flex;min-width:0;align-items:baseline;gap:7px;overflow:hidden;color:#10181c;text-decoration:none;white-space:nowrap}.card-library-tree-link:hover,.card-library-tree-link:focus-visible{color:#075d7c;outline:none;text-decoration:underline;text-underline-offset:2px}.card-library-tree-link strong,.card-library-tree-label strong{flex:none;color:inherit;font:700 16px/1.25 ui-monospace,monospace}.card-library-tree-link>span,.card-library-tree-label>span{min-width:0;overflow:hidden;color:inherit;text-overflow:ellipsis;white-space:nowrap;font:500 16px/1.25 system-ui,sans-serif}.card-library-treegrid-row.is-subject .card-library-tree-label strong,.card-library-treegrid-row.is-level .card-library-tree-label strong,.card-library-treegrid-row.is-series .card-library-tree-label strong{font-family:system-ui,sans-serif;font-weight:650}.card-library-tree-state{display:inline-flex;min-width:76px;min-height:24px;box-sizing:border-box;align-items:center;justify-content:center;border:1px solid transparent;border-radius:5px;color:#33474f;padding:2px 7px;font:650 14px/1 ui-monospace,monospace;white-space:nowrap}.card-library-tree-state[data-state=current]{border-color:#3184a0;background:#e9f5f8;color:#075d7c}.card-library-tree-state[data-state=online]{border-color:#4b9a7a;background:#edf8f2;color:#176144}.card-library-tree-state[data-state=plan]{border-color:#c59a49;background:#fff7e5;color:#775313}.card-library-treegrid-row.is-unavailable .card-library-tree-label,.card-library-treegrid-row.is-unavailable .card-library-tree-label strong{color:#10181c}.side-toc,.side-progress{min-height:0;flex:1;overflow-y:auto;background:#fff;color:#11191d}.side-toc>header,.side-progress>header{padding:16px 18px 13px;border-bottom:1px solid #bdc9ce;background:#f0f4f5}.side-toc>header small,.side-progress>header small{color:#53666f;font:750 9px/1 ui-monospace,monospace;letter-spacing:.08em}.side-toc>header h2,.side-progress>header h2{margin:4px 0 0;color:#10181c;font:750 21px/1.15 system-ui,sans-serif}.side-toc ol{margin:0;padding:7px 0 20px;list-style:none}.side-toc li{border-bottom:1px solid #e2e7e9}.side-toc a{display:grid;grid-template-columns:34px minmax(0,1fr);gap:9px;align-items:baseline;padding:10px 16px;color:#11191d;text-decoration:none}.side-toc a:hover,.side-toc a:focus-visible{background:#eaf5f8;outline:none}.side-toc a span{color:#267493;font:800 10px/1 ui-monospace,monospace}.side-toc a strong{font:650 13px/1.3 system-ui,sans-serif}.side-progress-summary{display:flex;align-items:center;justify-content:space-between;gap:16px;margin:16px;border:1px solid #b6c2c7;background:#f4f7f8;padding:14px;font:650 13px/1.3 system-ui,sans-serif}.side-progress-summary strong{color:#1d617b;font:850 20px/1 ui-monospace,monospace}.side-progress-links{display:grid;gap:8px;padding:0 16px 18px}.side-progress-links a{border:1px solid #87979e;border-radius:3px;background:#fff;color:#174f67;padding:10px 12px;text-decoration:none;font:700 12px/1.2 system-ui,sans-serif}.side-progress-links a:hover,.side-progress-links a:focus-visible{border-color:#167ca4;background:#edf7fa;outline:none}.side-progress-error{margin:0 16px 14px;border-left:3px solid #a52d2d;background:#fff1f1;color:#7d1f1f;padding:8px 10px;font:12px/1.35 system-ui,sans-serif}.classroom-panel{display:flex;min-height:0;flex:1;flex-direction:column;overflow:hidden;background:#f7f9fa;color:#11191d}.classroom-treegrid{min-height:0;flex:1;overflow:auto;margin:8px;border:1px solid rgb(31 35 40 / 18%);border-radius:6px;background:#fff;scrollbar-color:#93a2a8 #edf1f2;scrollbar-width:thin}.classroom-treegrid-row{display:grid;min-width:920px;box-sizing:border-box;grid-template-columns:minmax(410px,1fr) 100px 150px 150px 110px;align-items:center;border-bottom:1px solid rgb(31 35 40 / 8%);color:#273941;font:500 16px/1.25 ui-monospace,monospace}.classroom-treegrid-row>[role=gridcell],.classroom-treegrid-row>[role=columnheader]{min-width:0;overflow:hidden;padding:8px;text-overflow:ellipsis;white-space:nowrap}.classroom-treegrid-row>[role=gridcell]+[role=gridcell],.classroom-treegrid-row>[role=columnheader]+[role=columnheader]{border-left:1px solid rgb(31 35 40 / 8%)}.classroom-treegrid-head{position:sticky;z-index:2;top:0;border-bottom-color:#1f23282e;background:#eef1f2;color:#3e525b;font-weight:650;letter-spacing:.04em}.classroom-node-row:hover{background:#1f23280a}.classroom-node-row.is-class{background:#dfe8e5}.classroom-node-row.is-student{background:#f8faf9}.classroom-node-row.is-task{background:#edf3f5}.classroom-node-row.is-block,.classroom-node-row.is-exercises{background:#f5f7f8}.classroom-node-row.is-phase{background:#fafbfb}.classroom-node-title{display:flex;align-items:center;gap:6px;padding-left:calc(8px + (var(--classroom-depth, 0) * 20px))!important;font-family:system-ui,sans-serif}.classroom-node-title strong{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:16px;font-weight:500}.classroom-node-row.is-class .classroom-node-title strong,.classroom-node-row.is-student .classroom-node-title strong,.classroom-node-row.is-task .classroom-node-title strong{font-weight:650}.classroom-expander{display:inline-grid;width:24px;height:24px;flex:none;place-items:center;border:0;background:transparent;color:#405961;padding:0;font:18px/1 ui-monospace,monospace;cursor:pointer}.classroom-expander:hover,.classroom-expander:focus-visible{background:#165d6b1a;color:#165d6b;outline:1px solid rgb(22 93 107 / 28%)}.classroom-expander.is-empty{cursor:default}.classroom-status,.classroom-sync,.classroom-visit,.classroom-commit{display:inline-flex;min-width:92px;box-sizing:border-box;align-items:center;justify-content:center;border:1px solid;border-radius:5px;padding:4px 6px;font:550 16px/1 ui-monospace,monospace;letter-spacing:.015em}.classroom-status[data-status=online]{border-color:#6b9a87;background:#e7f4ee;color:#155e43}.classroom-status[data-status=away]{border-color:#baa06a;background:#fff5d9;color:#765510}.classroom-status[data-status=offline]{border-color:#a5afb3;background:#f0f2f3;color:#596970}.classroom-status[data-status=error]{border-color:#bd7b7b;background:#fff0f0;color:#8c2929}.classroom-sync[data-sync=follow]{border-color:#6c98aa;background:#e8f3f7;color:#155c77}.classroom-sync[data-sync=paused]{border-color:#baa06a;background:#fff6df;color:#765510}.classroom-sync[data-sync=local]{border-color:#9a86ae;background:#f4eef9;color:#65427c}.classroom-visit[data-visit=present],.classroom-commit[data-commit=committed]{border-color:#6b9a87;background:#e7f4ee;color:#155e43}.classroom-visit[data-visit=missed],.classroom-commit[data-commit=missing]{border-color:#bd7b7b;background:#fff0f0;color:#8c2929}.classroom-visit[data-visit=pending],.classroom-commit[data-commit=working]{border-color:#baa06a;background:#fff6df;color:#765510}.classroom-legend{display:flex;flex:none;flex-wrap:wrap;gap:7px 12px;border-top:1px solid #aebbc1;background:#edf1f2;padding:9px 11px;color:#485c65;font:500 16px/1.35 system-ui,sans-serif}.classroom-legend span{display:inline-flex;align-items:center;gap:4px}.classroom-legend i{width:12px;height:12px;border:1px solid #73858c;border-radius:50%;background:#aeb7bb}.classroom-legend i[data-status=online]{border-color:#3e7c63;background:#45a27b}.classroom-legend i[data-status=away]{border-color:#a0782d;background:#dcae51}.classroom-legend i[data-status=offline]{border-color:#859399;background:#b6c0c4}.classroom-legend b{color:#65427c;font:600 16px/1 ui-monospace,monospace}.viewer-chrome.is-nvim-fit{display:flex;width:100%;height:100vh;height:100dvh;max-height:100dvh;flex-direction:column;overflow:hidden;background:#11171a}.viewer-chrome.is-nvim-fit .topbar,.viewer-chrome.is-nvim-fit .viewpoint-bar,.viewer-chrome.is-nvim-fit .allocator-panel{flex:none}.viewer-chrome.is-nvim-fit .nvim-panel{display:flex;min-height:0;flex:1;flex-direction:column}.viewer-chrome.is-nvim-fit .nvim-screen-scroll{min-height:0;height:auto!important;flex:1}.viewer-chrome.is-nvim-fit .nvim-resize-handle{display:none}.viewer-chrome.is-nvim-fit .nvim-screen-stage{width:100%;height:100%;margin:0;zoom:1}.viewer-chrome.is-nvim-fit .nvim-screen-content{right:1mm;overflow:hidden;scrollbar-width:none}.viewer-chrome.is-nvim-fit .nvim-screen-grid{display:flex;width:100%;min-height:0;height:100%;align-items:center;justify-content:center}.viewer-chrome.is-nvim-fit .nvim-screen{width:auto!important;height:auto!important;max-width:100%;max-height:100%}.viewer-chrome.is-nvim-fit .nvim-screen-content::-webkit-scrollbar{display:none}.topbar-nvim-section{display:flex;align-items:center;min-width:0;gap:6px}.nvim-toolbar-boundary{flex:none;color:#6f7d83;font:700 14px/1 ui-monospace,monospace}.nvim-toolbar-context{flex:none;width:5ch;color:#263238;font:800 12px/1 ui-monospace,monospace;letter-spacing:.08em;text-align:center}.nvim-toolbar-actions{display:flex;align-items:center;gap:3px}.nvim-toolbar-button{display:inline-flex;align-items:center}.nvim-toolbar-key{flex:0 0 2ch;color:#267697;font:inherit;text-align:center}.nvim-toolbar-label{flex:0 0 5ch;max-width:5ch;overflow:hidden;text-align:left;white-space:nowrap}.topbar-nvim-meta{display:flex;align-items:baseline;min-width:0;max-width:min(44vw,720px);gap:6px}.topbar-nvim-meta strong,.topbar-nvim-meta small{overflow:auto;text-overflow:ellipsis;white-space:nowrap}.topbar-nvim-meta strong{color:#263238;font:700 12px/1.25 system-ui,sans-serif}.topbar-nvim-meta small{color:#66747a;font:500 10px/1.25 system-ui,sans-serif}.viewer-nvim-toggle{border:1px solid #68747a;border-radius:3px;background:#fff;color:#263238;padding:2px 8px;font:650 16px/1.3 system-ui,sans-serif;cursor:pointer}.viewer-nvim-toggle[aria-pressed=true]{border-color:#267697;background:#eaf6fb;color:#174d64}.allocator-panel{width:100%;box-sizing:border-box;border-top:1px solid #40515a;border-bottom:1px solid #40515a;background:#f7f9f5;color:#182127;box-shadow:0 4px 12px #0002;font:11px/1.25 system-ui,sans-serif}.allocator-panel>header{display:grid;grid-template-columns:125px minmax(260px,auto) 1fr;gap:8px;align-items:baseline;min-height:22px;padding:3px 8px;border-bottom:1px solid #b7c1c4;background:#e8eef0}.allocator-panel>header>span{color:#166987;font:800 9px/1.2 ui-monospace,monospace;letter-spacing:.06em}.allocator-panel>header>strong{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font:750 11px/1.2 ui-monospace,monospace}.allocator-panel>header>small{overflow:hidden;color:#536168;text-overflow:ellipsis;white-space:nowrap}.allocator-panel-body{display:grid;grid-template-columns:230px minmax(420px,1fr) minmax(310px,.8fr);gap:9px;align-items:stretch;padding:5px 8px 7px}.allocator-metrics{display:grid;grid-template-columns:1fr 1fr;gap:3px 8px;margin:0}.allocator-metrics>div{min-width:0;border-left:2px solid #8ea2ab;padding-left:5px}.allocator-metrics dt{color:#627077;font:750 7px/1.2 ui-monospace,monospace;letter-spacing:.05em}.allocator-metrics dd{margin:1px 0 0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font:700 10px/1.2 ui-monospace,monospace}.allocator-arena-view{min-width:0}.allocator-arena-view.is-inactive{opacity:.42}.allocator-arena-labels{display:flex;justify-content:space-between;gap:8px;margin-bottom:3px;color:#536168;font:700 8px/1.2 ui-monospace,monospace}.allocator-arena-labels strong{color:#075f80}.allocator-pinned-arena{position:relative;display:grid;grid-template-columns:repeat(var(--allocator-size),minmax(2px,1fr));height:32px;border:1px solid #28343a;background:#fff}.allocator-pinned-arena i{min-width:0;border-right:1px solid #e1e5e6;background:#fbfcfc}.allocator-pinned-arena i:nth-child(8n){border-right-color:#87969d}.allocator-pinned-arena i.is-allocated{border-right-color:#b2d8e6;background:#43a8ce}.allocator-cursor{position:absolute;z-index:2;top:-4px;bottom:-4px;width:2px;background:#d02d25;transform:translate(-1px);box-shadow:0 0 0 1px #fff9}.allocator-cursor:before{content:"allocp";position:absolute;top:1px;left:4px;color:#8d1d17;font:800 7px/1 ui-monospace,monospace}.allocator-facts{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:2px 7px;min-width:0}.allocator-facts>div{display:flex;min-width:0;justify-content:space-between;gap:5px;border-bottom:1px dotted #b4bec2}.allocator-facts span{overflow:hidden;color:#46565e;text-overflow:ellipsis;white-space:nowrap}.allocator-facts code{overflow:hidden;color:#142e39;text-overflow:ellipsis;white-space:nowrap;font:700 9px/1.3 ui-monospace,monospace}.allocator-facts p{grid-column:1 / -1;margin:0;color:#647278}.nvim-panel{width:100%;box-sizing:border-box;border-bottom:1px solid #52616a;background:var(--desk, #eee);color:#e7eef1;box-shadow:0 5px 16px #0004;font:12px/1.3 system-ui,sans-serif}.nvim-status{flex:none;border:1px solid #66757c;border-radius:999px;padding:1px 6px;color:#c9d3d8;font:750 9px/1.35 ui-monospace,monospace;letter-spacing:.04em}.nvim-status--connected,.nvim-status--ready{border-color:#31a86d;background:#173b2a;color:#8aefb7}.nvim-status--connecting,.nvim-status--replaying,.nvim-status--verifying{border-color:#c38f2a;background:#3e321b;color:#ffd47d}.nvim-status--failed,.nvim-status--offline,.nvim-status--unselected{border-color:#a34b4b;background:#3b2020;color:#faa}.nvim-control-indicator{flex:none;border:1px solid #60747e;border-radius:3px;background:#222e34;color:#b9c6cc;padding:3px 8px;font:700 10px/1.2 ui-monospace,monospace;letter-spacing:.04em;white-space:nowrap;cursor:pointer}.nvim-control-indicator.is-active{border-color:#3cb3e2;background:#17465a;color:#d9f5ff}.nvim-control-indicator.is-engaged{box-shadow:inset 0 0 0 1px #8ee4ff}.nvim-work-indicator{flex:none;border:1px solid #7a878d;border-radius:3px;background:#f4f6f7;color:#56646a;padding:3px 8px;font:700 10px/1.2 ui-monospace,monospace;letter-spacing:.03em;white-space:nowrap;cursor:pointer}.nvim-work-indicator.is-active{border-color:#cf3d31;background:#fff0ee;color:#9f241b}.nvim-work-indicator.is-engaged{box-shadow:inset 0 0 0 1px #cf3d31}.nvim-work-indicator:disabled{border-color:#a8b0b4;background:#e6e9ea;color:#7c878c;cursor:not-allowed;opacity:.8}.nvim-height-toggle{flex:none;border:1px solid #75848b;border-radius:3px;background:#f4f6f7;color:#425159;padding:3px 8px;font:700 10px/1.2 ui-monospace,monospace;letter-spacing:.03em;white-space:nowrap;cursor:pointer}.nvim-height-toggle.is-active{border-color:#267697;background:#eaf6fb;color:#174d64}.topbar-nvim-section .nvim-toolbar-button{flex:0 0 9.5ch;width:9.5ch;min-width:9.5ch;max-width:9.5ch;height:24px;box-sizing:border-box;justify-content:flex-start;gap:.55ch;padding:2px .55ch;font:750 12px/1 ui-monospace,monospace;letter-spacing:0}.nvim-shortcut-strip{flex:none;color:#536168;font:650 10px/1.2 ui-monospace,monospace;white-space:nowrap}.nvim-shortcut-strip kbd{color:#263238;font:inherit}.nvim-screen-scroll{position:relative;width:100%;box-sizing:border-box;height:var(--nvim-panel-height, 75vh);max-height:none;min-height:240px;overflow:auto;overscroll-behavior:contain;background:var(--desk, #eee);outline:none;scrollbar-color:#58666d #171d20}.nvim-screen-stage{position:relative;width:210mm;margin:0 auto;background:#fff;zoom:var(--viewer-canvas-scale)}.nvim-screen-surface{position:absolute;inset:0 4mm;box-sizing:border-box;padding:1mm;background:#fff}.nvim-screen-frame{position:relative;height:100%;box-sizing:border-box;border:1px solid #267697;background:#101315;box-shadow:0 0 0 3px #000}.nvim-screen-scroll[data-sync=on] .nvim-screen-frame{border-color:#35b9ef}.nvim-screen-scroll[data-control=true] .nvim-screen-frame{box-shadow:0 0 0 3px #cf3d31}.nvim-screen-scroll[data-control=true]{cursor:text}.nvim-screen-content{position:absolute;inset:1mm -5mm 1mm 1mm;overflow-x:hidden;overflow-y:scroll;overscroll-behavior:contain;background:transparent;scrollbar-width:thin;scrollbar-color:#829097 #fff}.nvim-screen-grid{width:calc(100% - 6mm);min-height:100%;background:#101315}.nvim-screen-content::-webkit-scrollbar{width:.8mm}.nvim-screen-content::-webkit-scrollbar-track{background:#fff}.nvim-screen-content::-webkit-scrollbar-thumb{border:.12mm solid #fff;border-radius:99px;background:#829097}.nvim-screen-content::-webkit-scrollbar-thumb:hover{background:#aeb9be}.nvim-screen{display:block;max-width:none;margin:0;outline:none;image-rendering:auto}.nvim-screen:focus{box-shadow:none}.nvim-screen-empty{position:absolute;inset:0;display:grid;place-content:center;gap:5px;padding:16px;color:#9cabb2;text-align:center}.nvim-screen-empty strong{color:#e0e8eb;font:750 11px/1.3 ui-monospace,monospace}.nvim-resize-handle{position:relative;width:100%;height:12px;border-top:1px solid #46565e;background:#182126;cursor:ns-resize;touch-action:none}.nvim-resize-handle:after{content:"";position:absolute;top:4px;left:50%;width:min(160px,22vw);height:3px;border-radius:999px;background:#6c7e87;transform:translate(-50%)}.nvim-resize-handle:hover,.nvim-resize-handle:focus-visible{background:#23323a;outline:none}.nvim-resize-handle:hover:after,.nvim-resize-handle:focus-visible:after{background:#35b9ef}.shortcut-help-backdrop{position:fixed;z-index:200;inset:0;display:grid;place-items:center;padding:20px;background:#10171dcc}.shortcut-help{width:min(680px,calc(100vw - 40px));max-height:calc(100vh - 40px);overflow:auto;border:1px solid #71818a;border-radius:6px;background:#f8fafb;color:#172127;box-shadow:0 18px 60px #0008;font:14px/1.4 system-ui,sans-serif}.shortcut-help>header{display:flex;align-items:start;justify-content:space-between;gap:16px;padding:16px 18px;border-bottom:1px solid #c8d1d5;background:#e8eef1}.shortcut-help header small{color:#52646d;font:750 10px/1.2 ui-monospace,monospace;letter-spacing:.08em}.shortcut-help h2{margin:4px 0 0;font-size:17px}.shortcut-help header button{width:32px;height:32px;border:1px solid #71818a;border-radius:3px;background:#fff;font:22px/1 system-ui,sans-serif;cursor:pointer}.shortcut-help dl{margin:0;padding:10px 18px}.shortcut-help dl>div{display:grid;grid-template-columns:minmax(180px,.8fr) 1.5fr;gap:14px;align-items:center;padding:8px 0;border-bottom:1px solid #dde3e6}.shortcut-help dt,.shortcut-help dd{margin:0}.shortcut-help kbd{display:inline-block;border:1px solid #839198;border-bottom-width:2px;border-radius:3px;background:#fff;padding:3px 7px;font:700 12px/1.2 ui-monospace,monospace}.shortcut-help>p{margin:0;padding:4px 18px 16px;color:#526068}.memory-react{border:1px solid #555;background:#fff;font:14px/1.35 system-ui,sans-serif;padding:10px;color:#1b1b1b}.memory-react>header{display:flex;align-items:center;justify-content:space-between;gap:12px;border-bottom:1px solid #bbb;padding-bottom:7px}.memory-react>header small{display:block;margin-bottom:2px;color:#555;font:700 10px/1.2 ui-monospace,monospace;letter-spacing:.08em}.memory-react h3{font-size:15px;margin:0}.memory-actions{display:flex;gap:5px;flex-wrap:wrap;justify-content:flex-end}.memory-actions button{border:1px solid #777;background:#fff;padding:4px 8px;cursor:pointer}.memory-actions button[aria-pressed=true]{background:#dff3fb;border-color:#237da1;font-weight:700}.memory-lanes{display:grid;grid-template-columns:repeat(auto-fit,minmax(125px,1fr));gap:6px;margin:8px 0}.memory-lane{min-width:0;display:flex;flex-direction:column;align-items:stretch;gap:3px;border:1px solid #999;background:#fafafa;padding:7px;text-align:left}.memory-lane.compile{background:#fff8dc}.memory-lane.bss{background:#edf7fb}.memory-lane.stack{background:#f3f8ef}.memory-lane.registers{background:#f4f4f4}.memory-lane.text{background:#f7f0fa}.memory-lane>b{font-size:11px;letter-spacing:.04em}.memory-lane button{border:1px solid transparent;background:transparent;padding:3px;text-align:left;cursor:pointer}.memory-lane button:hover,.memory-lane button.active{border-color:#238bb7;background:#fff}.memory-lane code{font-size:10px;white-space:normal}.arena-wrap{margin:12px 0 6px}.arena-label{display:flex;justify-content:space-between;margin-bottom:4px}.arena{--allocp: 0;--arena-size: 64;position:relative;display:grid;grid-template-columns:repeat(var(--arena-size),1fr);height:40px;border:1px solid #222;margin-bottom:28px}.arena i{border-right:1px solid #ddd}.arena .allocp{position:absolute;left:calc(var(--allocp) / var(--arena-size) * 100%);top:43px;transform:translate(-50%);color:#087da8;font:700 11px/1.2 ui-monospace,monospace;white-space:nowrap}.memory-stage{border-top:1px solid #ddd;padding-top:7px;margin:0}.memory-inspector{display:grid;grid-template-columns:auto 1fr;gap:2px 10px;margin-top:7px;padding:7px;border-left:3px solid #238bb7;background:#f5fbfd}.memory-inspector strong{grid-row:1/3}.memory-inspector code{font-size:11px}.memory-inspector span{font-size:12px}.asset-static-fallback{display:none}.uml-react{border:1px solid #555;background:#fff;font:13px/1.35 system-ui,sans-serif;color:#1b1b1b}.uml-react>header{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:6px 8px;border-bottom:1px solid #bbb;background:#fafafa}.uml-react>header small{display:block;color:#555;font:700 10px/1.2 ui-monospace,monospace;letter-spacing:.06em}.uml-react h3{margin:2px 0 0;font-size:15px}.uml-actions{display:flex;gap:3px;flex-wrap:wrap;justify-content:flex-end}.uml-actions button{border:1px solid #aaa;border-radius:2px;background:#fcfcfc;color:#444;padding:2px 6px;font:600 10px/1.25 ui-monospace,monospace;cursor:pointer}.uml-actions button:hover{border-color:#64879a;background:#f5fafc}.uml-actions button[data-completed=true]{border-color:#62a47f;background:#edf8f1;color:#14613a}.uml-actions button[aria-pressed=true]{border-color:#287495;background:#edf7fb;color:#174d64;box-shadow:inset 0 0 0 1px #b9dce9}.uml-canvas{display:block;overflow-x:hidden;overflow-y:visible;box-sizing:border-box;padding:8px 10px;text-align:center}.uml-svg-host{width:max-content;min-width:100%}.uml-canvas img,.uml-svg-host svg{display:block;width:auto!important;max-width:none!important;height:auto!important;max-height:none;margin-inline:auto;object-fit:contain}.uml-svg-host{cursor:pointer}.uml-svg-host.is-tiled{position:relative;width:var(--uml-tile-page-width);min-width:var(--uml-tile-page-width);height:var(--uml-tile-page-height);overflow:hidden;cursor:default}.uml-svg-host.is-tiled>svg{position:absolute;top:var(--uml-tile-top);left:var(--uml-tile-left);margin:0}.uml-static-crop{position:absolute;top:var(--uml-tile-top);left:var(--uml-tile-left);overflow:hidden}.uml-static-crop>img{display:block;max-width:none!important;max-height:none!important;margin:0!important;object-fit:fill!important;transform-origin:0 0}.uml-tile-part{display:inline-block;margin-left:.65em;color:#607985;font:650 9px/1.2 ui-monospace,monospace;letter-spacing:.03em;white-space:nowrap}.uml-phase-actions>span{display:inline-flex;align-items:center;border:1px solid #9eb2bd;border-radius:2px;background:#f1f5f7;color:#3d5967;padding:2px 6px;font:700 10px/1.25 ui-monospace,monospace}.uml-stage-region{cursor:pointer;transition:fill .14s ease,stroke .14s ease,stroke-width .14s ease}.uml-stage-region-completed.uml-stage-region-bg{fill:#e7f6ed!important;fill-opacity:1!important;stroke:#258154!important;stroke-width:3px!important}.uml-stage-region-completed.uml-stage-region-outline{stroke:#258154!important;stroke-width:3px!important}.uml-stage-region-active.uml-stage-region-bg{fill:#e7f6fc!important;fill-opacity:1!important;stroke:#187ea7!important;stroke-width:3px!important}.uml-stage-region-active.uml-stage-region-outline{stroke:#187ea7!important;stroke-width:3px!important}.uml-stage-region-active.uml-stage-region-completed.uml-stage-region-bg{fill:#e7f6ed!important}.uml-stage-region:focus{outline:none;stroke:#005f87!important;stroke-width:4px!important}.uml-inline-warning{display:block;padding-top:5px;color:#8b2d20;font-size:11px}.uml-stage{display:grid;grid-template-columns:auto 1fr;gap:3px 10px;margin:0 8px 8px;padding:8px;border-left:3px solid #315f78;background:#eef7fb}.uml-stage strong{grid-row:1/3}.uml-stage code{grid-column:2;font-size:11px}.uml-approval{display:flex;align-items:center;justify-content:space-between;gap:8px;margin:0 8px 8px;padding-top:6px;border-top:1px solid #d2d2d2;color:#555;font-size:11px}.uml-approval button{flex:0 0 auto;border:1px solid #477a5d;border-radius:2px;background:#edf8f1;color:#174e30;padding:3px 7px;font:600 10px/1.25 system-ui,sans-serif;cursor:pointer}.uml-approval button:disabled{border-color:#bbb;background:#f3f3f3;color:#888;cursor:not-allowed}.uml-react>.uml-snapshot-header{display:block;padding:5px 8px 4px}.uml-header-first-line{display:flex;align-items:center;justify-content:space-between;gap:10px}.uml-header-first-line h3{flex:1 1 auto;min-width:0;margin:0;color:#20282c;text-align:left;font-size:12px;line-height:1.25}.uml-header-first-line h3>span{color:#245f7a;font-family:ui-monospace,monospace;letter-spacing:.04em}.uml-header-description{max-width:620px;margin:2px 0 0;color:#555;text-align:left;font-size:8px}.uml-after-description{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:baseline;gap:4mm;margin-top:3mm;border:1px solid #b8c2c7;border-left:1.2mm solid #2b7898;background:#f7fafb;padding:2.2mm 3mm;color:#26363e;text-align:left}.uml-after-description strong{color:#245f7a;font:800 8px/1.25 ui-monospace,monospace;letter-spacing:.06em;text-transform:uppercase}.uml-after-description p{margin:0;font:400 10px/1.35 system-ui,sans-serif}.uml-header-navigation{display:flex;flex:0 0 auto;align-items:center;justify-content:flex-end;gap:6px}.uml-page-continuation{display:inline-flex;flex:0 0 auto;align-items:center;gap:2px;min-height:22px;border:1px solid #86a5b3;border-radius:3px;background:#edf7fa;padding:1px 5px;color:#126b8c;font:850 15px/1 ui-monospace,monospace;animation:uml-continuation-pulse 1.15s ease-in-out infinite alternate}.uml-page-continuation i{display:inline-grid;min-width:14px;place-items:center;font-style:normal}@keyframes uml-continuation-pulse{0%{border-color:#9fb5be;background:#f6fafb;color:#4c7180;box-shadow:none}to{border-color:#167ca4;background:#dff2f8;color:#075c7c;box-shadow:0 0 0 2px #8dcde433}}@media(prefers-reduced-motion:reduce){.uml-page-continuation{animation:none}}.uml-phase-actions,.uml-step-actions{display:flex;align-items:center;flex-wrap:wrap;gap:3px}.uml-phase-actions{flex:0 0 auto;flex-wrap:nowrap;justify-content:flex-end;white-space:nowrap}.uml-phase-actions button,.uml-step-actions button,.uml-edit-toggle,.uml-snapshot-cursor button{border:1px solid #aaa;border-radius:2px;background:#fff;color:#444;cursor:pointer;font:600 9px/1.2 ui-monospace,monospace}.uml-edit-toggle{min-width:42px;padding:3px 7px;border:1px solid #8a9ca5;border-radius:2px;background:#f7f9fa;color:#334d59;cursor:pointer;font:750 9px/1.2 ui-monospace,monospace;letter-spacing:.04em}.uml-edit-toggle.is-active{border-color:#b56b16;background:#fff3df;color:#713c00;box-shadow:inset 0 0 0 1px #f0c78f}.uml-phase-actions button{padding:3px 7px}.uml-phase-actions button[aria-pressed=true]{border-color:#287495;background:#edf7fb;color:#174d64}.uml-step-actions{min-height:0;padding:0;border:0;background:transparent}.uml-step-actions>span{margin-right:4px;color:#555;font:700 9px/1.2 ui-monospace,monospace}.uml-step-actions button{min-width:25px;padding:2px 4px}.uml-step-actions button[data-completed=true]{border-color:#62a47f;background:#edf8f1;color:#14613a}.uml-step-actions button[aria-pressed=true]{border-color:#287495;background:#287495;color:#fff}.uml-step-actions button[data-mode=CODE]:after,.uml-step-actions button[data-mode=RUN]:after{margin-left:3px;font-size:7px;letter-spacing:.02em}.uml-step-actions button[data-mode=CODE]:after{content:"C"}.uml-step-actions button[data-mode=RUN]:after{content:"R"}.uml-snapshot-layout{background:#fff;border-bottom:1px solid #ddd}.uml-step-canvas{min-width:0}.uml-step-canvas .uml-svg-host svg{max-height:none}.uml-step-hit{cursor:pointer;fill:transparent}.uml-step-hit-active{fill:#3ea6ce!important;fill-opacity:.08!important}.uml-step-element{transition:fill .12s ease,stroke .12s ease,stroke-width .12s ease}line.uml-step-element-completed:not(.uml-step-element-active){stroke:#258154!important;stroke-width:1.8px!important}polygon.uml-step-element-completed:not(.uml-step-element-active){fill:#258154!important;stroke:#258154!important}text.uml-step-element-completed:not(.uml-step-element-active){fill:#1d7049!important}line.uml-step-element-active{stroke:#087ca8!important;stroke-width:2.6px!important}polygon.uml-step-element-active{fill:#087ca8!important;stroke:#087ca8!important}text.uml-step-element-active{fill:#075d7d!important;font-weight:700!important}.uml-step-hit:focus{outline:none;stroke:#bd554d;stroke-width:.8px;stroke-dasharray:3 3}.uml-class-svg-active>g>*:not(.uml-class-focus-region):not(.uml-class-step-hit):not(.uml-layout-hit):not(.uml-layout-resize){opacity:.62;transition:opacity .12s ease}.uml-class-svg-active .uml-step-element:not(.uml-step-element-active){opacity:.98!important}.uml-class-svg-active text.uml-step-element-tone-a:not(.uml-step-element-active){fill:#174f69!important}.uml-class-svg-active text.uml-step-element-tone-b:not(.uml-step-element-active){fill:#586581!important}.uml-class-svg-active rect.uml-step-element-tone-a:not(.uml-step-element-active){fill:#eaf5f8!important;stroke:#3f7890!important}.uml-class-svg-active rect.uml-step-element-tone-b:not(.uml-step-element-active){fill:#f2eef8!important;stroke:#7b86a1!important}.uml-class-svg-active path.uml-step-element-tone-a:not(.uml-step-element-active),.uml-class-svg-active line.uml-step-element-tone-a:not(.uml-step-element-active),.uml-class-svg-active polygon.uml-step-element-tone-a:not(.uml-step-element-active){stroke:#3f7890!important}.uml-class-svg-active path.uml-step-element-tone-b:not(.uml-step-element-active),.uml-class-svg-active line.uml-step-element-tone-b:not(.uml-step-element-active),.uml-class-svg-active polygon.uml-step-element-tone-b:not(.uml-step-element-active){stroke:#7b86a1!important}.uml-class-svg-active .uml-step-element-active{opacity:1!important}.uml-class-svg-active text.uml-step-element-active{fill:#b42318!important;font-weight:700!important}.uml-class-svg-active path.uml-step-element-active,.uml-class-svg-active line.uml-step-element-active,.uml-class-svg-active polygon.uml-step-element-active,.uml-class-svg-active rect.uml-step-element-active{stroke:#bd554d!important;stroke-width:1.35px!important}.uml-class-svg-active polygon.uml-step-element-active{fill:#bd554d!important}.uml-class-focus-region{display:none}.uml-step-canvas.is-layout-editing{position:relative;touch-action:none;background-color:#fbfcfd;background-image:linear-gradient(#7d98a20d 1px,transparent 1px),linear-gradient(90deg,#7d98a20d 1px,transparent 1px);background-size:12px 12px}.uml-layout-editing .uml-step-hit,.uml-layout-editing .uml-class-focus-region{pointer-events:none}.uml-layout-hit{fill:#4e9ec4;fill-opacity:.035;stroke:#247a9e;stroke-width:1.1px;stroke-dasharray:5 3;vector-effect:non-scaling-stroke;cursor:grab;pointer-events:all}.uml-layout-hit:hover{fill-opacity:.09;stroke-width:1.6px}.uml-layout-hit.is-selected{fill:#f7a928;fill-opacity:.08;stroke:#b66b00;stroke-width:1.8px;stroke-dasharray:none}.uml-layout-hit:active{cursor:grabbing}.uml-layout-resize{fill:#fff;stroke:#b66b00;stroke-width:1.5px;vector-effect:non-scaling-stroke;cursor:nwse-resize;pointer-events:all}.uml-layout-editor{display:grid;grid-template-columns:minmax(140px,.8fr) minmax(240px,1.8fr) minmax(260px,1.4fr);gap:7px 10px;align-items:end;padding:8px 10px 9px;border-top:2px solid #b97822;background:#f7f5f0;color:#26343a;text-align:left;font:10px/1.3 system-ui,sans-serif}.uml-layout-editor-title{grid-column:1/-1;display:flex;align-items:baseline;gap:9px}.uml-layout-editor-title strong{color:#713c00;font:800 11px/1.2 ui-monospace,monospace;text-transform:uppercase}.uml-layout-editor-title span{color:#65737a}.uml-layout-editor-title b{margin-left:auto;color:#9c2f1b;font-size:9px}.uml-layout-editor label{display:grid;gap:2px;color:#52636b;font:700 8px/1.2 ui-monospace,monospace;text-transform:uppercase}.uml-layout-editor input,.uml-layout-editor select,.uml-layout-editor textarea{box-sizing:border-box;width:100%;min-width:0;border:1px solid #9ca9ae;border-radius:2px;background:#fff;color:#172126;padding:4px 5px;font:10px/1.25 ui-monospace,monospace;text-transform:none}.uml-layout-editor textarea{resize:vertical;line-height:1.35}.uml-layout-number-grid,.uml-layout-style-grid{display:grid;gap:5px}.uml-layout-number-grid{grid-template-columns:repeat(4,minmax(48px,1fr))}.uml-layout-style-grid{grid-template-columns:repeat(5,minmax(54px,1fr))}.uml-layout-editor-text{align-self:stretch}.uml-layout-editor input[type=color]{min-height:27px;padding:2px}.uml-layout-editor-actions{grid-column:1/-1;display:flex;gap:5px}.uml-layout-editor-actions button{border:1px solid #87979f;border-radius:2px;background:#fff;color:#283940;padding:4px 8px;cursor:pointer;font:700 9px/1.2 ui-monospace,monospace}.uml-layout-editor-actions button.is-primary{border-color:#287495;background:#287495;color:#fff}.uml-layout-editor-actions button.is-danger{margin-left:auto;border-color:#a26156;color:#812b1c}.uml-layout-editor-actions button:disabled{opacity:.45;cursor:not-allowed}.uml-layout-editor output{grid-column:1/-1;min-height:1.2em;color:#52636b;font:9px/1.25 ui-monospace,monospace}@media(max-width:900px){.uml-layout-editor{grid-template-columns:1fr}.uml-layout-editor-title,.uml-layout-editor-actions,.uml-layout-editor output{grid-column:1}}@media print{.uml-edit-toggle,.uml-layout-editor,.uml-layout-hit,.uml-layout-resize{display:none!important}}.uml-snapshot-panel{display:grid;gap:8px;min-width:0;padding:8px;background:#fafafa;font-size:10px}.uml-snapshot-panel>header{display:flex;justify-content:space-between;gap:8px;align-items:center}.uml-snapshot-panel>header>div:first-child>span,.uml-snapshot-panel>header>div:first-child>strong{display:block}.uml-snapshot-panel>header>div:first-child>span{color:#5a5a5a;font:700 9px/1.2 ui-monospace,monospace}.uml-snapshot-panel>header>div:first-child>strong{font-size:12px}.uml-snapshot-panel>header>div:first-child>strong code{display:inline-block;min-width:24px;color:#075d7d}.uml-snapshot-cursor{display:flex;align-items:center;gap:4px}.uml-snapshot-cursor button{width:23px;height:23px;padding:0}.uml-snapshot-cursor button:disabled{opacity:.35;cursor:default}.uml-snapshot-cursor output{min-width:34px;text-align:center;font:700 9px/1 ui-monospace,monospace}.uml-snapshot-description{margin:0;color:#333}.uml-snapshot-panel section{min-width:0;border:1px solid #d0d0d0;background:#fff;padding:7px}.uml-snapshot-panel h4{margin:0 0 4px;color:#315f78;font:700 9px/1.2 ui-monospace,monospace;text-transform:uppercase}.uml-state-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:7px;min-width:0}.uml-snapshot-registers dl{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:3px;margin:0}.uml-snapshot-registers dl>div{display:grid;grid-template-columns:auto 1fr;gap:5px;min-width:0;padding:2px 4px;border-left:2px solid #bbb;background:#f6f6f6}.uml-snapshot-registers dl>div.primary{grid-column:1/-1;border-color:#287495;background:#edf7fb}.uml-snapshot-registers dt{color:#555;font-weight:700}.uml-snapshot-registers dd,.uml-snapshot-variables dd,.uml-snapshot-memory dd{min-width:0;margin:0;overflow-wrap:anywhere;text-align:right;font:600 9px/1.25 ui-monospace,monospace}.uml-snapshot-variables dl{display:grid;gap:3px;margin:0}.uml-snapshot-variables dl>div{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:5px;padding:3px 5px;border-left:2px solid #5f899b;background:#f5f8f9}.uml-snapshot-variables dt{font-weight:700}.uml-snapshot-variables dt small{display:block;color:#777;font:8px/1.2 ui-monospace,monospace}.uml-snapshot-variables [data-state=uninitialised],.uml-stack-lane article[data-state=uninitialised]{color:#777;background:#f5f5f5}.uml-snapshot-variables [data-state=uninitialised] dt:after,.uml-stack-lane article[data-state=uninitialised]>strong:after{content:" ?";color:#9a6a00}.uml-arena-snapshot>div{position:relative;height:10px;border:1px solid #666;background:repeating-linear-gradient(90deg,#fff 0 7px,#eee 7px 8px)}.uml-arena-snapshot>div span{display:block;height:100%;background:#b8ddeb}.uml-arena-snapshot>div i{position:absolute;top:-3px;bottom:-3px;width:2px;background:#075d7d;transform:translate(-1px)}.uml-arena-snapshot>p{display:grid;grid-template-columns:1fr auto 1fr;gap:4px;margin:3px 0;font-size:8px}.uml-arena-snapshot>p code:last-child{text-align:right}.uml-arena-bytes{display:block;margin-bottom:4px;overflow-wrap:anywhere;color:#666;font-size:8px}.uml-snapshot-memory dl{display:grid;gap:2px;margin:0}.uml-snapshot-memory dl>div{display:grid;grid-template-columns:1fr auto;gap:4px;padding-top:2px;border-top:1px solid #eee}.uml-snapshot-memory dt{font-weight:700}.uml-snapshot-memory dt small{display:block;color:#777;font:8px/1.2 ui-monospace,monospace}.uml-snapshot-stack>header{display:flex;align-items:baseline;justify-content:space-between;gap:8px}.uml-snapshot-stack>header>p{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:4px 9px;margin:0;color:#555;font-size:8px}.uml-stack-axis{display:flex;justify-content:space-between;gap:8px;margin:3px 89px 2px;color:#777;font:8px/1.2 ui-monospace,monospace}.uml-stack-lane{display:flex;align-items:stretch;min-width:0;overflow-x:auto;border:1px solid #66757c;background:#eef1f2}.uml-stack-boundary{display:grid;place-content:center;flex:0 1 82px;min-width:64px;padding:5px;background:#273941;color:#fff;text-align:center;font:700 8px/1.25 ui-monospace,monospace}.uml-stack-boundary small{color:#a9d9eb;font-size:8px;text-transform:uppercase}.uml-stack-gap{display:grid;place-content:center;flex:.7 1 70px;min-width:60px;min-height:52px;border-right:1px dashed #9da8ad;color:#78858b;text-align:center;font:8px/1.2 ui-monospace,monospace}.uml-stack-gap strong,.uml-stack-gap small{display:block}.uml-stack-gap strong{color:#52636b}.uml-stack-gap small{color:#78858b;font-size:8px}.uml-stack-lane article{display:grid;align-content:center;flex:1 1 92px;min-width:76px;padding:5px 7px;border-right:1px solid #9da8ad;background:#fff;text-align:center}.uml-stack-lane article[data-state=initialised]{border-top:3px solid #2c8060}.uml-stack-lane article[data-state=saved]{border-top:3px solid #6d7196;background:#f7f6fb}.uml-stack-lane article strong,.uml-stack-lane article code,.uml-stack-lane article small{display:block;overflow-wrap:anywhere}.uml-stack-lane article strong{font:700 9px/1.2 ui-monospace,monospace}.uml-stack-lane article code{margin:2px 0;color:#1f4555;font-size:8px}.uml-stack-lane article small{color:#777;font:8px/1.2 ui-monospace,monospace}.uml-snapshot-observation p{margin:0 0 3px}.uml-snapshot-observation small{display:block;overflow-wrap:anywhere;color:#666;font:8px/1.3 ui-monospace,monospace}.task-conclusion{margin:8px 0 0;padding:7px 9px;border:1px solid #315f78;background:#f3f9fc}.task-conclusion>strong{display:block;margin-bottom:3px;color:#315f78;font:700 10px/1.2 ui-monospace,monospace}.task-conclusion p{margin:0}.section-sheet--asset .section-heading{align-items:baseline;margin:0 0 1.5mm}.section-sheet--asset .section-heading .section-index{margin-right:4mm;color:#68757b;font-size:10px;font-weight:600}.section-sheet--asset .section-heading .section-title{color:#20282c;font:750 13px/1.2 system-ui,sans-serif}.section-sheet--asset .card-section>p{max-width:110ch;margin:0 0 2mm;color:#58656b;font:9px/1.3 system-ui,sans-serif}.section-sheet--asset .card-asset{margin-top:2mm}.lesson-progress-control{display:inline-flex;align-items:center;margin-right:7px;padding:2px 7px;border:1px solid #8c8c8c;border-radius:12px;background:#fff;cursor:pointer}.lesson-progress-control:disabled{cursor:wait;opacity:.6}.lesson-progress-control[data-status=approved]{background:#e7f6ed;border-color:#18794e}.lesson-progress-topbar{display:flex;flex:none;align-items:center;gap:5px;min-width:0;padding-left:7px;border-left:1px solid #a9b3b8;color:#33444c;font:650 10px/1.2 system-ui,sans-serif;white-space:nowrap}.lesson-progress-topbar strong{color:#52636b;font:800 9px/1 ui-monospace,monospace;letter-spacing:.05em}.lesson-progress-topbar output{min-width:3.8ch;border:1px solid #91a1a8;border-radius:999px;background:#fff;padding:2px 6px;color:#1e566e;text-align:center;font:800 9px/1 ui-monospace,monospace}.lesson-progress-topbar a{color:#245f7a;text-decoration:none}.lesson-progress-topbar a:hover,.lesson-progress-topbar a:focus-visible{text-decoration:underline}.lesson-progress-error{color:#9b1c1c;font-weight:900}.step-row{display:flex;align-items:center;margin:4px 0}.section-anchor{position:relative;top:-45px}.app-load-error{max-width:760px;margin:10vh auto;padding:24px;border:1px solid #9b1c1c;background:#fff;font-family:system-ui,sans-serif}.app-load-error pre{white-space:pre-wrap}@media(max-width:800px){.viewpoint-bar{grid-template-columns:repeat(4,minmax(0,1fr))}.viewpoint-bar button{min-height:28px}.card-library-toggle>span:last-child{display:none}.card-library-toggle{gap:4px;padding-inline:6px}.topbar-nvim-meta{display:none}.topbar-nvim-section .nvim-control-indicator{max-width:42vw;overflow:hidden;text-overflow:ellipsis}.nvim-shortcut-strip,.nvim-work-indicator{display:none}.allocator-panel>header{grid-template-columns:auto 1fr}.allocator-panel>header>small{display:none}.allocator-panel-body{grid-template-columns:1fr}.allocator-metrics,.allocator-facts{display:none}.memory-lanes{grid-template-columns:1fr 1fr}.memory-react>header,.uml-react>header{align-items:flex-start;flex-direction:column}.uml-header-first-line,.uml-header-navigation{width:100%;align-items:flex-start;flex-direction:column}.uml-header-navigation{gap:4px}.memory-actions{justify-content:flex-start}.uml-snapshot-layout{display:block}.uml-step-canvas{border:0}.uml-phase-actions{width:100%;justify-content:flex-end}.uml-state-grid{grid-template-columns:1fr}.uml-snapshot-stack>header{align-items:flex-start;flex-direction:column}.uml-snapshot-stack>header>p{justify-content:flex-start}.uml-stack-axis{margin-right:0;margin-left:0}}@media print{@page card-portrait{size:A4 portrait;margin:0}@page card-landscape{size:A4 landscape;margin:0}.sheet--portrait{page:card-portrait}.sheet--landscape{page:card-landscape}.paper{display:block;gap:0}.paper>.sheet,.paper>.sheet>.sheet-content,.paper>.sheet-spread>.sheet,.paper>.sheet-spread>.sheet>.sheet-content{height:auto;min-height:0;max-height:none;overflow:visible}.sheet-spread{display:contents!important}.viewer-chrome,.side-panel-dock,.memory-react{display:none!important}.asset-static-fallback{display:block!important;width:100%}.uml-actions,.uml-phase-actions,.uml-step-actions,.uml-snapshot-panel,.uml-stage,.uml-approval,.lesson-progress-topbar,.lesson-progress-control,.uml-page-continuation{display:none!important}.uml-after-description{break-inside:avoid}} diff --git a/web/app.js b/web/app.js index c1573ef..77bf0cb 100644 --- a/web/app.js +++ b/web/app.js @@ -1,18 +1,18 @@ -var Pp=Object.create;var ks=Object.defineProperty;var Tp=Object.getOwnPropertyDescriptor;var Mp=Object.getOwnPropertyNames;var Rp=Object.getPrototypeOf,Op=Object.prototype.hasOwnProperty;var $t=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var $p=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of Mp(t))!Op.call(e,o)&&o!==n&&ks(e,o,{get:()=>t[o],enumerable:!(r=Tp(t,o))||r.enumerable});return e};var bo=(e,t,n)=>(n=e!=null?Pp(Rp(e)):{},$p(t||!e||!e.__esModule?ks(n,"default",{value:e,enumerable:!0}):n,e));var Rs=$t(W=>{"use strict";var xr=Symbol.for("react.element"),Ip=Symbol.for("react.portal"),Fp=Symbol.for("react.fragment"),Dp=Symbol.for("react.strict_mode"),jp=Symbol.for("react.profiler"),Up=Symbol.for("react.provider"),Vp=Symbol.for("react.context"),Bp=Symbol.for("react.forward_ref"),Hp=Symbol.for("react.suspense"),Kp=Symbol.for("react.memo"),Wp=Symbol.for("react.lazy"),Ss=Symbol.iterator;function Gp(e){return e===null||typeof e!="object"?null:(e=Ss&&e[Ss]||e["@@iterator"],typeof e=="function"?e:null)}var _s={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},Cs=Object.assign,Ls={};function Vn(e,t,n){this.props=e,this.context=t,this.refs=Ls,this.updater=n||_s}Vn.prototype.isReactComponent={};Vn.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};Vn.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function zs(){}zs.prototype=Vn.prototype;function Qi(e,t,n){this.props=e,this.context=t,this.refs=Ls,this.updater=n||_s}var qi=Qi.prototype=new zs;qi.constructor=Qi;Cs(qi,Vn.prototype);qi.isPureReactComponent=!0;var Ns=Array.isArray,As=Object.prototype.hasOwnProperty,Xi={current:null},Ps={key:!0,ref:!0,__self:!0,__source:!0};function Ts(e,t,n){var r,o={},i=null,l=null;if(t!=null)for(r in t.ref!==void 0&&(l=t.ref),t.key!==void 0&&(i=""+t.key),t)As.call(t,r)&&!Ps.hasOwnProperty(r)&&(o[r]=t[r]);var s=arguments.length-2;if(s===1)o.children=n;else if(1{"use strict";Os.exports=Rs()});var Ks=$t(le=>{"use strict";function nl(e,t){var n=e.length;e.push(t);e:for(;0>>1,o=e[r];if(0>>1;rEo(s,n))uEo(d,s)?(e[r]=d,e[u]=n,r=u):(e[r]=s,e[l]=n,r=l);else if(uEo(d,n))e[r]=d,e[u]=n,r=u;else break e}}return t}function Eo(e,t){var n=e.sortIndex-t.sortIndex;return n!==0?n:e.id-t.id}typeof performance=="object"&&typeof performance.now=="function"?($s=performance,le.unstable_now=function(){return $s.now()}):(Ji=Date,Is=Ji.now(),le.unstable_now=function(){return Ji.now()-Is});var $s,Ji,Is,At=[],Zt=[],Zp=1,mt=null,Oe=3,Lo=!1,kn=!1,wr=!1,js=typeof setTimeout=="function"?setTimeout:null,Us=typeof clearTimeout=="function"?clearTimeout:null,Fs=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function rl(e){for(var t=wt(Zt);t!==null;){if(t.callback===null)Co(Zt);else if(t.startTime<=e)Co(Zt),t.sortIndex=t.expirationTime,nl(At,t);else break;t=wt(Zt)}}function ol(e){if(wr=!1,rl(e),!kn)if(wt(At)!==null)kn=!0,ll(il);else{var t=wt(Zt);t!==null&&al(ol,t.startTime-e)}}function il(e,t){kn=!1,wr&&(wr=!1,Us(kr),kr=-1),Lo=!0;var n=Oe;try{for(rl(t),mt=wt(At);mt!==null&&(!(mt.expirationTime>t)||e&&!Hs());){var r=mt.callback;if(typeof r=="function"){mt.callback=null,Oe=mt.priorityLevel;var o=r(mt.expirationTime<=t);t=le.unstable_now(),typeof o=="function"?mt.callback=o:mt===wt(At)&&Co(At),rl(t)}else Co(At);mt=wt(At)}if(mt!==null)var i=!0;else{var l=wt(Zt);l!==null&&al(ol,l.startTime-t),i=!1}return i}finally{mt=null,Oe=n,Lo=!1}}var zo=!1,_o=null,kr=-1,Vs=5,Bs=-1;function Hs(){return!(le.unstable_now()-Bse||125r?(e.sortIndex=n,nl(Zt,e),wt(At)===null&&e===wt(Zt)&&(wr?(Us(kr),kr=-1):wr=!0,al(ol,n-r))):(e.sortIndex=o,nl(At,e),kn||Lo||(kn=!0,ll(il))),e};le.unstable_shouldYield=Hs;le.unstable_wrapCallback=function(e){var t=Oe;return function(){var n=Oe;Oe=t;try{return e.apply(this,arguments)}finally{Oe=n}}}});var Gs=$t((uh,Ws)=>{"use strict";Ws.exports=Ks()});var Xd=$t(lt=>{"use strict";var Jp=No(),ot=Gs();function z(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Al=Object.prototype.hasOwnProperty,em=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,Ys={},Qs={};function tm(e){return Al.call(Qs,e)?!0:Al.call(Ys,e)?!1:em.test(e)?Qs[e]=!0:(Ys[e]=!0,!1)}function nm(e,t,n,r){if(n!==null&&n.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return r?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function rm(e,t,n,r){if(t===null||typeof t>"u"||nm(e,t,n,r))return!0;if(r)return!1;if(n!==null)switch(n.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function We(e,t,n,r,o,i,l){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=o,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=i,this.removeEmptyString=l}var Me={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){Me[e]=new We(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];Me[t]=new We(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){Me[e]=new We(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){Me[e]=new We(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){Me[e]=new We(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){Me[e]=new We(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){Me[e]=new We(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){Me[e]=new We(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){Me[e]=new We(e,5,!1,e.toLowerCase(),null,!1,!1)});var ka=/[\-:]([a-z])/g;function Sa(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(ka,Sa);Me[t]=new We(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(ka,Sa);Me[t]=new We(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(ka,Sa);Me[t]=new We(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){Me[e]=new We(e,1,!1,e.toLowerCase(),null,!1,!1)});Me.xlinkHref=new We("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){Me[e]=new We(e,1,!1,e.toLowerCase(),null,!0,!0)});function Na(e,t,n,r){var o=Me.hasOwnProperty(t)?Me[t]:null;(o!==null?o.type!==0:r||!(2()=>(t||e((t={exports:{}}).exports,t),t.exports);var Up=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of Fp(t))!jp.call(e,o)&&o!==n&&Ss(e,o,{get:()=>t[o],enumerable:!(r=$p(t,o))||r.enumerable});return e};var wo=(e,t,n)=>(n=e!=null?Op(Dp(e)):{},Up(t||!e||!e.__esModule?Ss(n,"default",{value:e,enumerable:!0}):n,e));var Is=jt(Y=>{"use strict";var xr=Symbol.for("react.element"),Vp=Symbol.for("react.portal"),Bp=Symbol.for("react.fragment"),Hp=Symbol.for("react.strict_mode"),Kp=Symbol.for("react.profiler"),Wp=Symbol.for("react.provider"),Gp=Symbol.for("react.context"),Yp=Symbol.for("react.forward_ref"),Qp=Symbol.for("react.suspense"),qp=Symbol.for("react.memo"),Xp=Symbol.for("react.lazy"),Ns=Symbol.iterator;function Zp(e){return e===null||typeof e!="object"?null:(e=Ns&&e[Ns]||e["@@iterator"],typeof e=="function"?e:null)}var Cs={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},Ls=Object.assign,zs={};function Un(e,t,n){this.props=e,this.context=t,this.refs=zs,this.updater=n||Cs}Un.prototype.isReactComponent={};Un.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};Un.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function As(){}As.prototype=Un.prototype;function Xi(e,t,n){this.props=e,this.context=t,this.refs=zs,this.updater=n||Cs}var Zi=Xi.prototype=new As;Zi.constructor=Xi;Ls(Zi,Un.prototype);Zi.isPureReactComponent=!0;var Es=Array.isArray,Ps=Object.prototype.hasOwnProperty,Ji={current:null},Ts={key:!0,ref:!0,__self:!0,__source:!0};function Rs(e,t,n){var r,o={},i=null,l=null;if(t!=null)for(r in t.ref!==void 0&&(l=t.ref),t.key!==void 0&&(i=""+t.key),t)Ps.call(t,r)&&!Ts.hasOwnProperty(r)&&(o[r]=t[r]);var s=arguments.length-2;if(s===1)o.children=n;else if(1{"use strict";Os.exports=Is()});var Ws=jt(ie=>{"use strict";function ol(e,t){var n=e.length;e.push(t);e:for(;0>>1,o=e[r];if(0<_o(o,t))e[r]=t,e[n]=o,n=r;else break e}}function Nt(e){return e.length===0?null:e[0]}function Lo(e){if(e.length===0)return null;var t=e[0],n=e.pop();if(n!==t){e[0]=n;e:for(var r=0,o=e.length,i=o>>>1;r_o(s,n))u_o(d,s)?(e[r]=d,e[u]=n,r=u):(e[r]=s,e[l]=n,r=l);else if(u_o(d,n))e[r]=d,e[u]=n,r=u;else break e}}return t}function _o(e,t){var n=e.sortIndex-t.sortIndex;return n!==0?n:e.id-t.id}typeof performance=="object"&&typeof performance.now=="function"?($s=performance,ie.unstable_now=function(){return $s.now()}):(tl=Date,Fs=tl.now(),ie.unstable_now=function(){return tl.now()-Fs});var $s,tl,Fs,Tt=[],en=[],rm=1,pt=null,De=3,zo=!1,Sn=!1,kr=!1,Us=typeof setTimeout=="function"?setTimeout:null,Vs=typeof clearTimeout=="function"?clearTimeout:null,Ds=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function il(e){for(var t=Nt(en);t!==null;){if(t.callback===null)Lo(en);else if(t.startTime<=e)Lo(en),t.sortIndex=t.expirationTime,ol(Tt,t);else break;t=Nt(en)}}function ll(e){if(kr=!1,il(e),!Sn)if(Nt(Tt)!==null)Sn=!0,sl(al);else{var t=Nt(en);t!==null&&ul(ll,t.startTime-e)}}function al(e,t){Sn=!1,kr&&(kr=!1,Vs(Sr),Sr=-1),zo=!0;var n=De;try{for(il(t),pt=Nt(Tt);pt!==null&&(!(pt.expirationTime>t)||e&&!Ks());){var r=pt.callback;if(typeof r=="function"){pt.callback=null,De=pt.priorityLevel;var o=r(pt.expirationTime<=t);t=ie.unstable_now(),typeof o=="function"?pt.callback=o:pt===Nt(Tt)&&Lo(Tt),il(t)}else Lo(Tt);pt=Nt(Tt)}if(pt!==null)var i=!0;else{var l=Nt(en);l!==null&&ul(ll,l.startTime-t),i=!1}return i}finally{pt=null,De=n,zo=!1}}var Ao=!1,Co=null,Sr=-1,Bs=5,Hs=-1;function Ks(){return!(ie.unstable_now()-Hse||125r?(e.sortIndex=n,ol(en,e),Nt(Tt)===null&&e===Nt(en)&&(kr?(Vs(Sr),Sr=-1):kr=!0,ul(ll,n-r))):(e.sortIndex=o,ol(Tt,e),Sn||zo||(Sn=!0,sl(al))),e};ie.unstable_shouldYield=Ks;ie.unstable_wrapCallback=function(e){var t=De;return function(){var n=De;De=t;try{return e.apply(this,arguments)}finally{De=n}}}});var Ys=jt((Sh,Gs)=>{"use strict";Gs.exports=Ws()});var Zd=jt(lt=>{"use strict";var om=Eo(),ot=Ys();function L(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Tl=Object.prototype.hasOwnProperty,im=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,Qs={},qs={};function lm(e){return Tl.call(qs,e)?!0:Tl.call(Qs,e)?!1:im.test(e)?qs[e]=!0:(Qs[e]=!0,!1)}function am(e,t,n,r){if(n!==null&&n.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return r?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function sm(e,t,n,r){if(t===null||typeof t>"u"||am(e,t,n,r))return!0;if(r)return!1;if(n!==null)switch(n.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function Qe(e,t,n,r,o,i,l){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=o,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=i,this.removeEmptyString=l}var Fe={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){Fe[e]=new Qe(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];Fe[t]=new Qe(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){Fe[e]=new Qe(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){Fe[e]=new Qe(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){Fe[e]=new Qe(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){Fe[e]=new Qe(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){Fe[e]=new Qe(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){Fe[e]=new Qe(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){Fe[e]=new Qe(e,5,!1,e.toLowerCase(),null,!1,!1)});var Na=/[\-:]([a-z])/g;function Ea(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(Na,Ea);Fe[t]=new Qe(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(Na,Ea);Fe[t]=new Qe(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(Na,Ea);Fe[t]=new Qe(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){Fe[e]=new Qe(e,1,!1,e.toLowerCase(),null,!1,!1)});Fe.xlinkHref=new Qe("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){Fe[e]=new Qe(e,1,!1,e.toLowerCase(),null,!0,!0)});function _a(e,t,n,r){var o=Fe.hasOwnProperty(t)?Fe[t]:null;(o!==null?o.type!==0:r||!(2s||o[l]!==i[s]){var u=` -`+o[l].replace(" at new "," at ");return e.displayName&&u.includes("")&&(u=u.replace("",e.displayName)),u}while(1<=l&&0<=s);break}}}finally{ul=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?Pr(e):""}function om(e){switch(e.tag){case 5:return Pr(e.type);case 16:return Pr("Lazy");case 13:return Pr("Suspense");case 19:return Pr("SuspenseList");case 0:case 2:case 15:return e=cl(e.type,!1),e;case 11:return e=cl(e.type.render,!1),e;case 1:return e=cl(e.type,!0),e;default:return""}}function Rl(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case Wn:return"Fragment";case Kn:return"Portal";case Pl:return"Profiler";case Ea:return"StrictMode";case Tl:return"Suspense";case Ml:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case nc:return(e.displayName||"Context")+".Consumer";case tc:return(e._context.displayName||"Context")+".Provider";case _a:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case Ca:return t=e.displayName||null,t!==null?t:Rl(e.type)||"Memo";case en:t=e._payload,e=e._init;try{return Rl(e(t))}catch{}}return null}function im(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return Rl(t);case 8:return t===Ea?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function gn(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function oc(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function lm(e){var t=oc(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var o=n.get,i=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return o.call(this)},set:function(l){r=""+l,i.call(this,l)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(l){r=""+l},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function Po(e){e._valueTracker||(e._valueTracker=lm(e))}function ic(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=oc(e)?e.checked?"true":"false":e.value),e=r,e!==n?(t.setValue(e),!0):!1}function ii(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function Ol(e,t){var n=t.checked;return ve({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function Xs(e,t){var n=t.defaultValue==null?"":t.defaultValue,r=t.checked!=null?t.checked:t.defaultChecked;n=gn(t.value!=null?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function lc(e,t){t=t.checked,t!=null&&Na(e,"checked",t,!1)}function $l(e,t){lc(e,t);var n=gn(t.value),r=t.type;if(n!=null)r==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?Il(e,t.type,n):t.hasOwnProperty("defaultValue")&&Il(e,t.type,gn(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function Zs(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!(r!=="submit"&&r!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function Il(e,t,n){(t!=="number"||ii(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var Tr=Array.isArray;function rr(e,t,n,r){if(e=e.options,t){t={};for(var o=0;o"+t.valueOf().toString()+"",t=To.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function Kr(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var Or={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},am=["Webkit","ms","Moz","O"];Object.keys(Or).forEach(function(e){am.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),Or[t]=Or[e]})});function cc(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||Or.hasOwnProperty(e)&&Or[e]?(""+t).trim():t+"px"}function dc(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=n.indexOf("--")===0,o=cc(n,t[n],r);n==="float"&&(n="cssFloat"),r?e.setProperty(n,o):e[n]=o}}var sm=ve({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function jl(e,t){if(t){if(sm[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(z(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(z(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(z(61))}if(t.style!=null&&typeof t.style!="object")throw Error(z(62))}}function Ul(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var Vl=null;function La(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var Bl=null,or=null,ir=null;function tu(e){if(e=uo(e)){if(typeof Bl!="function")throw Error(z(280));var t=e.stateNode;t&&(t=Mi(t),Bl(e.stateNode,e.type,t))}}function pc(e){or?ir?ir.push(e):ir=[e]:or=e}function mc(){if(or){var e=or,t=ir;if(ir=or=null,tu(e),t)for(e=0;e>>=0,e===0?32:31-(xm(e)/bm|0)|0}var Mo=64,Ro=4194304;function Mr(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function ui(e,t){var n=e.pendingLanes;if(n===0)return 0;var r=0,o=e.suspendedLanes,i=e.pingedLanes,l=n&268435455;if(l!==0){var s=l&~o;s!==0?r=Mr(s):(i&=l,i!==0&&(r=Mr(i)))}else l=n&~o,l!==0?r=Mr(l):i!==0&&(r=Mr(i));if(r===0)return 0;if(t!==0&&t!==r&&(t&o)===0&&(o=r&-r,i=t&-t,o>=i||o===16&&(i&4194240)!==0))return t;if((r&4)!==0&&(r|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=r;0n;n++)t.push(e);return t}function ao(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-_t(t),e[t]=n}function Nm(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=Ir),cu=" ",du=!1;function Mc(e,t){switch(e){case"keyup":return Zm.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Rc(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var Gn=!1;function ef(e,t){switch(e){case"compositionend":return Rc(t);case"keypress":return t.which!==32?null:(du=!0,cu);case"textInput":return e=t.data,e===cu&&du?null:e;default:return null}}function tf(e,t){if(Gn)return e==="compositionend"||!$a&&Mc(e,t)?(e=Pc(),qo=Ma=on=null,Gn=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=fu(n)}}function Fc(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Fc(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Dc(){for(var e=window,t=ii();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=ii(e.document)}return t}function Ia(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function df(e){var t=Dc(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&Fc(n.ownerDocument.documentElement,n)){if(r!==null&&Ia(n)){if(t=r.start,e=r.end,e===void 0&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var o=n.textContent.length,i=Math.min(r.start,o);r=r.end===void 0?i:Math.min(r.end,o),!e.extend&&i>r&&(o=r,r=i,i=o),o=gu(n,i);var l=gu(n,r);o&&l&&(e.rangeCount!==1||e.anchorNode!==o.node||e.anchorOffset!==o.offset||e.focusNode!==l.node||e.focusOffset!==l.offset)&&(t=t.createRange(),t.setStart(o.node,o.offset),e.removeAllRanges(),i>r?(e.addRange(t),e.extend(l.node,l.offset)):(t.setEnd(l.node,l.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus=="function"&&n.focus(),n=0;n=document.documentMode,Yn=null,Ql=null,Dr=null,ql=!1;function hu(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;ql||Yn==null||Yn!==ii(r)||(r=Yn,"selectionStart"in r&&Ia(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Dr&&Xr(Dr,r)||(Dr=r,r=pi(Ql,"onSelect"),0Xn||(e.current=na[Xn],na[Xn]=null,Xn--)}function ae(e,t){Xn++,na[Xn]=e.current,e.current=t}var hn={},De=vn(hn),Xe=vn(!1),An=hn;function cr(e,t){var n=e.type.contextTypes;if(!n)return hn;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var o={},i;for(i in n)o[i]=t[i];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=o),o}function Ze(e){return e=e.childContextTypes,e!=null}function fi(){de(Xe),de(De)}function Eu(e,t,n){if(De.current!==hn)throw Error(z(168));ae(De,t),ae(Xe,n)}function Yc(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,typeof r.getChildContext!="function")return n;r=r.getChildContext();for(var o in r)if(!(o in t))throw Error(z(108,im(e)||"Unknown",o));return ve({},n,r)}function gi(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||hn,An=De.current,ae(De,e),ae(Xe,Xe.current),!0}function _u(e,t,n){var r=e.stateNode;if(!r)throw Error(z(169));n?(e=Yc(e,t,An),r.__reactInternalMemoizedMergedChildContext=e,de(Xe),de(De),ae(De,e)):de(Xe),ae(Xe,n)}var Ft=null,Ri=!1,wl=!1;function Qc(e){Ft===null?Ft=[e]:Ft.push(e)}function wf(e){Ri=!0,Qc(e)}function xn(){if(!wl&&Ft!==null){wl=!0;var e=0,t=ee;try{var n=Ft;for(ee=1;e>=l,o-=l,Dt=1<<32-_t(t)+o|n<R?(j=T,T=null):j=T.sibling;var I=g(p,T,h[R],k);if(I===null){T===null&&(T=j);break}e&&T&&I.alternate===null&&t(p,T),c=i(I,c,R),P===null?C=I:P.sibling=I,P=I,T=j}if(R===h.length)return n(p,T),pe&&Sn(p,R),C;if(T===null){for(;RR?(j=T,T=null):j=T.sibling;var ke=g(p,T,I.value,k);if(ke===null){T===null&&(T=j);break}e&&T&&ke.alternate===null&&t(p,T),c=i(ke,c,R),P===null?C=ke:P.sibling=ke,P=ke,T=j}if(I.done)return n(p,T),pe&&Sn(p,R),C;if(T===null){for(;!I.done;R++,I=h.next())I=y(p,I.value,k),I!==null&&(c=i(I,c,R),P===null?C=I:P.sibling=I,P=I);return pe&&Sn(p,R),C}for(T=r(p,T);!I.done;R++,I=h.next())I=f(T,p,R,I.value,k),I!==null&&(e&&I.alternate!==null&&T.delete(I.key===null?R:I.key),c=i(I,c,R),P===null?C=I:P.sibling=I,P=I);return e&&T.forEach(function(re){return t(p,re)}),pe&&Sn(p,R),C}function _(p,c,h,k){if(typeof h=="object"&&h!==null&&h.type===Wn&&h.key===null&&(h=h.props.children),typeof h=="object"&&h!==null){switch(h.$$typeof){case Ao:e:{for(var C=h.key,P=c;P!==null;){if(P.key===C){if(C=h.type,C===Wn){if(P.tag===7){n(p,P.sibling),c=o(P,h.props.children),c.return=p,p=c;break e}}else if(P.elementType===C||typeof C=="object"&&C!==null&&C.$$typeof===en&&zu(C)===P.type){n(p,P.sibling),c=o(P,h.props),c.ref=Cr(p,P,h),c.return=p,p=c;break e}n(p,P);break}else t(p,P);P=P.sibling}h.type===Wn?(c=zn(h.props.children,p.mode,k,h.key),c.return=p,p=c):(k=oi(h.type,h.key,h.props,null,p.mode,k),k.ref=Cr(p,c,h),k.return=p,p=k)}return l(p);case Kn:e:{for(P=h.key;c!==null;){if(c.key===P)if(c.tag===4&&c.stateNode.containerInfo===h.containerInfo&&c.stateNode.implementation===h.implementation){n(p,c.sibling),c=o(c,h.children||[]),c.return=p,p=c;break e}else{n(p,c);break}else t(p,c);c=c.sibling}c=zl(h,p.mode,k),c.return=p,p=c}return l(p);case en:return P=h._init,_(p,c,P(h._payload),k)}if(Tr(h))return E(p,c,h,k);if(Sr(h))return b(p,c,h,k);Ko(p,h)}return typeof h=="string"&&h!==""||typeof h=="number"?(h=""+h,c!==null&&c.tag===6?(n(p,c.sibling),c=o(c,h),c.return=p,p=c):(n(p,c),c=Ll(h,p.mode,k),c.return=p,p=c),l(p)):n(p,c)}return _}var pr=Jc(!0),ed=Jc(!1),vi=vn(null),xi=null,er=null,Ua=null;function Va(){Ua=er=xi=null}function Ba(e){var t=vi.current;de(vi),e._currentValue=t}function ia(e,t,n){for(;e!==null;){var r=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,r!==null&&(r.childLanes|=t)):r!==null&&(r.childLanes&t)!==t&&(r.childLanes|=t),e===n)break;e=e.return}}function ar(e,t){xi=e,Ua=er=null,e=e.dependencies,e!==null&&e.firstContext!==null&&((e.lanes&t)!==0&&(qe=!0),e.firstContext=null)}function vt(e){var t=e._currentValue;if(Ua!==e)if(e={context:e,memoizedValue:t,next:null},er===null){if(xi===null)throw Error(z(308));er=e,xi.dependencies={lanes:0,firstContext:e}}else er=er.next=e;return t}var _n=null;function Ha(e){_n===null?_n=[e]:_n.push(e)}function td(e,t,n,r){var o=t.interleaved;return o===null?(n.next=n,Ha(t)):(n.next=o.next,o.next=n),t.interleaved=n,Ht(e,r)}function Ht(e,t){e.lanes|=t;var n=e.alternate;for(n!==null&&(n.lanes|=t),n=e,e=e.return;e!==null;)e.childLanes|=t,n=e.alternate,n!==null&&(n.childLanes|=t),n=e,e=e.return;return n.tag===3?n.stateNode:null}var tn=!1;function Ka(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function nd(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function Ut(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function dn(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,(Y&2)!==0){var o=r.pending;return o===null?t.next=t:(t.next=o.next,o.next=t),r.pending=t,Ht(e,n)}return o=r.interleaved,o===null?(t.next=t,Ha(r)):(t.next=o.next,o.next=t),r.interleaved=t,Ht(e,n)}function Zo(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,(n&4194240)!==0)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,Aa(e,n)}}function Au(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var o=null,i=null;if(n=n.firstBaseUpdate,n!==null){do{var l={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};i===null?o=i=l:i=i.next=l,n=n.next}while(n!==null);i===null?o=i=t:i=i.next=t}else o=i=t;n={baseState:r.baseState,firstBaseUpdate:o,lastBaseUpdate:i,shared:r.shared,effects:r.effects},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function bi(e,t,n,r){var o=e.updateQueue;tn=!1;var i=o.firstBaseUpdate,l=o.lastBaseUpdate,s=o.shared.pending;if(s!==null){o.shared.pending=null;var u=s,d=u.next;u.next=null,l===null?i=d:l.next=d,l=u;var m=e.alternate;m!==null&&(m=m.updateQueue,s=m.lastBaseUpdate,s!==l&&(s===null?m.firstBaseUpdate=d:s.next=d,m.lastBaseUpdate=u))}if(i!==null){var y=o.baseState;l=0,m=d=u=null,s=i;do{var g=s.lane,f=s.eventTime;if((r&g)===g){m!==null&&(m=m.next={eventTime:f,lane:0,tag:s.tag,payload:s.payload,callback:s.callback,next:null});e:{var E=e,b=s;switch(g=t,f=n,b.tag){case 1:if(E=b.payload,typeof E=="function"){y=E.call(f,y,g);break e}y=E;break e;case 3:E.flags=E.flags&-65537|128;case 0:if(E=b.payload,g=typeof E=="function"?E.call(f,y,g):E,g==null)break e;y=ve({},y,g);break e;case 2:tn=!0}}s.callback!==null&&s.lane!==0&&(e.flags|=64,g=o.effects,g===null?o.effects=[s]:g.push(s))}else f={eventTime:f,lane:g,tag:s.tag,payload:s.payload,callback:s.callback,next:null},m===null?(d=m=f,u=y):m=m.next=f,l|=g;if(s=s.next,s===null){if(s=o.shared.pending,s===null)break;g=s,s=g.next,g.next=null,o.lastBaseUpdate=g,o.shared.pending=null}}while(!0);if(m===null&&(u=y),o.baseState=u,o.firstBaseUpdate=d,o.lastBaseUpdate=m,t=o.shared.interleaved,t!==null){o=t;do l|=o.lane,o=o.next;while(o!==t)}else i===null&&(o.shared.lanes=0);Mn|=l,e.lanes=l,e.memoizedState=y}}function Pu(e,t,n){if(e=t.effects,t.effects=null,e!==null)for(t=0;tn?n:4,e(!0);var r=Sl.transition;Sl.transition={};try{e(!1),t()}finally{ee=n,Sl.transition=r}}function xd(){return xt().memoizedState}function Ef(e,t,n){var r=mn(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},bd(e))wd(t,n);else if(n=td(e,t,n,r),n!==null){var o=Ke();Ct(n,e,r,o),kd(n,t,r)}}function _f(e,t,n){var r=mn(e),o={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(bd(e))wd(t,o);else{var i=e.alternate;if(e.lanes===0&&(i===null||i.lanes===0)&&(i=t.lastRenderedReducer,i!==null))try{var l=t.lastRenderedState,s=i(l,n);if(o.hasEagerState=!0,o.eagerState=s,Lt(s,l)){var u=t.interleaved;u===null?(o.next=o,Ha(t)):(o.next=u.next,u.next=o),t.interleaved=o;return}}catch{}finally{}n=td(e,t,o,r),n!==null&&(o=Ke(),Ct(n,e,r,o),kd(n,t,r))}}function bd(e){var t=e.alternate;return e===ye||t!==null&&t===ye}function wd(e,t){jr=ki=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function kd(e,t,n){if((n&4194240)!==0){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,Aa(e,n)}}var Si={readContext:vt,useCallback:$e,useContext:$e,useEffect:$e,useImperativeHandle:$e,useInsertionEffect:$e,useLayoutEffect:$e,useMemo:$e,useReducer:$e,useRef:$e,useState:$e,useDebugValue:$e,useDeferredValue:$e,useTransition:$e,useMutableSource:$e,useSyncExternalStore:$e,useId:$e,unstable_isNewReconciler:!1},Cf={readContext:vt,useCallback:function(e,t){return Tt().memoizedState=[e,t===void 0?null:t],e},useContext:vt,useEffect:Mu,useImperativeHandle:function(e,t,n){return n=n!=null?n.concat([e]):null,ei(4194308,4,fd.bind(null,t,e),n)},useLayoutEffect:function(e,t){return ei(4194308,4,e,t)},useInsertionEffect:function(e,t){return ei(4,2,e,t)},useMemo:function(e,t){var n=Tt();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=Tt();return t=n!==void 0?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=Ef.bind(null,ye,e),[r.memoizedState,e]},useRef:function(e){var t=Tt();return e={current:e},t.memoizedState=e},useState:Tu,useDebugValue:Ja,useDeferredValue:function(e){return Tt().memoizedState=e},useTransition:function(){var e=Tu(!1),t=e[0];return e=Nf.bind(null,e[1]),Tt().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=ye,o=Tt();if(pe){if(n===void 0)throw Error(z(407));n=n()}else{if(n=t(),Ae===null)throw Error(z(349));(Tn&30)!==0||ld(r,t,n)}o.memoizedState=n;var i={value:n,getSnapshot:t};return o.queue=i,Mu(sd.bind(null,r,i,e),[e]),r.flags|=2048,io(9,ad.bind(null,r,i,n,t),void 0,null),n},useId:function(){var e=Tt(),t=Ae.identifierPrefix;if(pe){var n=jt,r=Dt;n=(r&~(1<<32-_t(r)-1)).toString(32)+n,t=":"+t+"R"+n,n=ro++,0")&&(u=u.replace("",e.displayName)),u}while(1<=l&&0<=s);break}}}finally{dl=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?Tr(e):""}function um(e){switch(e.tag){case 5:return Tr(e.type);case 16:return Tr("Lazy");case 13:return Tr("Suspense");case 19:return Tr("SuspenseList");case 0:case 2:case 15:return e=pl(e.type,!1),e;case 11:return e=pl(e.type.render,!1),e;case 1:return e=pl(e.type,!0),e;default:return""}}function Ol(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case Kn:return"Fragment";case Hn:return"Portal";case Rl:return"Profiler";case Ca:return"StrictMode";case Ml:return"Suspense";case Il:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case rc:return(e.displayName||"Context")+".Consumer";case nc:return(e._context.displayName||"Context")+".Provider";case La:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case za:return t=e.displayName||null,t!==null?t:Ol(e.type)||"Memo";case nn:t=e._payload,e=e._init;try{return Ol(e(t))}catch{}}return null}function cm(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return Ol(t);case 8:return t===Ca?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function yn(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function ic(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function dm(e){var t=ic(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var o=n.get,i=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return o.call(this)},set:function(l){r=""+l,i.call(this,l)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(l){r=""+l},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function To(e){e._valueTracker||(e._valueTracker=dm(e))}function lc(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=ic(e)?e.checked?"true":"false":e.value),e=r,e!==n?(t.setValue(e),!0):!1}function li(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function $l(e,t){var n=t.checked;return xe({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function Zs(e,t){var n=t.defaultValue==null?"":t.defaultValue,r=t.checked!=null?t.checked:t.defaultChecked;n=yn(t.value!=null?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function ac(e,t){t=t.checked,t!=null&&_a(e,"checked",t,!1)}function Fl(e,t){ac(e,t);var n=yn(t.value),r=t.type;if(n!=null)r==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?Dl(e,t.type,n):t.hasOwnProperty("defaultValue")&&Dl(e,t.type,yn(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function Js(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!(r!=="submit"&&r!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function Dl(e,t,n){(t!=="number"||li(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var Rr=Array.isArray;function nr(e,t,n,r){if(e=e.options,t){t={};for(var o=0;o"+t.valueOf().toString()+"",t=Ro.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function Wr(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var Or={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},pm=["Webkit","ms","Moz","O"];Object.keys(Or).forEach(function(e){pm.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),Or[t]=Or[e]})});function dc(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||Or.hasOwnProperty(e)&&Or[e]?(""+t).trim():t+"px"}function pc(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=n.indexOf("--")===0,o=dc(n,t[n],r);n==="float"&&(n="cssFloat"),r?e.setProperty(n,o):e[n]=o}}var mm=xe({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function Vl(e,t){if(t){if(mm[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(L(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(L(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(L(61))}if(t.style!=null&&typeof t.style!="object")throw Error(L(62))}}function Bl(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var Hl=null;function Aa(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var Kl=null,rr=null,or=null;function nu(e){if(e=co(e)){if(typeof Kl!="function")throw Error(L(280));var t=e.stateNode;t&&(t=Mi(t),Kl(e.stateNode,e.type,t))}}function mc(e){rr?or?or.push(e):or=[e]:rr=e}function fc(){if(rr){var e=rr,t=or;if(or=rr=null,nu(e),t)for(e=0;e>>=0,e===0?32:31-(Nm(e)/Em|0)|0}var Mo=64,Io=4194304;function Mr(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function ci(e,t){var n=e.pendingLanes;if(n===0)return 0;var r=0,o=e.suspendedLanes,i=e.pingedLanes,l=n&268435455;if(l!==0){var s=l&~o;s!==0?r=Mr(s):(i&=l,i!==0&&(r=Mr(i)))}else l=n&~o,l!==0?r=Mr(l):i!==0&&(r=Mr(i));if(r===0)return 0;if(t!==0&&t!==r&&(t&o)===0&&(o=r&-r,i=t&-t,o>=i||o===16&&(i&4194240)!==0))return t;if((r&4)!==0&&(r|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=r;0n;n++)t.push(e);return t}function so(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-zt(t),e[t]=n}function zm(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=Fr),du=" ",pu=!1;function Mc(e,t){switch(e){case"keyup":return rf.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Ic(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var Wn=!1;function lf(e,t){switch(e){case"compositionend":return Ic(t);case"keypress":return t.which!==32?null:(pu=!0,du);case"textInput":return e=t.data,e===du&&pu?null:e;default:return null}}function af(e,t){if(Wn)return e==="compositionend"||!Fa&&Mc(e,t)?(e=Tc(),Xo=Ia=an=null,Wn=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=gu(n)}}function Dc(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Dc(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function jc(){for(var e=window,t=li();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=li(e.document)}return t}function Da(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function hf(e){var t=jc(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&Dc(n.ownerDocument.documentElement,n)){if(r!==null&&Da(n)){if(t=r.start,e=r.end,e===void 0&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var o=n.textContent.length,i=Math.min(r.start,o);r=r.end===void 0?i:Math.min(r.end,o),!e.extend&&i>r&&(o=r,r=i,i=o),o=hu(n,i);var l=hu(n,r);o&&l&&(e.rangeCount!==1||e.anchorNode!==o.node||e.anchorOffset!==o.offset||e.focusNode!==l.node||e.focusOffset!==l.offset)&&(t=t.createRange(),t.setStart(o.node,o.offset),e.removeAllRanges(),i>r?(e.addRange(t),e.extend(l.node,l.offset)):(t.setEnd(l.node,l.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus=="function"&&n.focus(),n=0;n=document.documentMode,Gn=null,Xl=null,jr=null,Zl=!1;function yu(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Zl||Gn==null||Gn!==li(r)||(r=Gn,"selectionStart"in r&&Da(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),jr&&Zr(jr,r)||(jr=r,r=mi(Xl,"onSelect"),0qn||(e.current=oa[qn],oa[qn]=null,qn--)}function le(e,t){qn++,oa[qn]=e.current,e.current=t}var vn={},Be=xn(vn),Ze=xn(!1),Pn=vn;function ur(e,t){var n=e.type.contextTypes;if(!n)return vn;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var o={},i;for(i in n)o[i]=t[i];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=o),o}function Je(e){return e=e.childContextTypes,e!=null}function gi(){pe(Ze),pe(Be)}function _u(e,t,n){if(Be.current!==vn)throw Error(L(168));le(Be,t),le(Ze,n)}function Qc(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,typeof r.getChildContext!="function")return n;r=r.getChildContext();for(var o in r)if(!(o in t))throw Error(L(108,cm(e)||"Unknown",o));return xe({},n,r)}function hi(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||vn,Pn=Be.current,le(Be,e),le(Ze,Ze.current),!0}function Cu(e,t,n){var r=e.stateNode;if(!r)throw Error(L(169));n?(e=Qc(e,t,Pn),r.__reactInternalMemoizedMergedChildContext=e,pe(Ze),pe(Be),le(Be,e)):pe(Ze),le(Ze,n)}var Vt=null,Ii=!1,Sl=!1;function qc(e){Vt===null?Vt=[e]:Vt.push(e)}function _f(e){Ii=!0,qc(e)}function wn(){if(!Sl&&Vt!==null){Sl=!0;var e=0,t=ne;try{var n=Vt;for(ne=1;e>=l,o-=l,Bt=1<<32-zt(t)+o|n<z?(U=P,P=null):U=P.sibling;var F=g(p,P,h[z],w);if(F===null){P===null&&(P=U);break}e&&P&&F.alternate===null&&t(p,P),c=i(F,c,z),A===null?C=F:A.sibling=F,A=F,P=U}if(z===h.length)return n(p,P),fe&&Nn(p,z),C;if(P===null){for(;zz?(U=P,P=null):U=P.sibling;var ae=g(p,P,F.value,w);if(ae===null){P===null&&(P=U);break}e&&P&&ae.alternate===null&&t(p,P),c=i(ae,c,z),A===null?C=ae:A.sibling=ae,A=ae,P=U}if(F.done)return n(p,P),fe&&Nn(p,z),C;if(P===null){for(;!F.done;z++,F=h.next())F=y(p,F.value,w),F!==null&&(c=i(F,c,z),A===null?C=F:A.sibling=F,A=F);return fe&&Nn(p,z),C}for(P=r(p,P);!F.done;z++,F=h.next())F=f(P,p,z,F.value,w),F!==null&&(e&&F.alternate!==null&&P.delete(F.key===null?z:F.key),c=i(F,c,z),A===null?C=F:A.sibling=F,A=F);return e&&P.forEach(function(me){return t(p,me)}),fe&&Nn(p,z),C}function _(p,c,h,w){if(typeof h=="object"&&h!==null&&h.type===Kn&&h.key===null&&(h=h.props.children),typeof h=="object"&&h!==null){switch(h.$$typeof){case Po:e:{for(var C=h.key,A=c;A!==null;){if(A.key===C){if(C=h.type,C===Kn){if(A.tag===7){n(p,A.sibling),c=o(A,h.props.children),c.return=p,p=c;break e}}else if(A.elementType===C||typeof C=="object"&&C!==null&&C.$$typeof===nn&&Au(C)===A.type){n(p,A.sibling),c=o(A,h.props),c.ref=Lr(p,A,h),c.return=p,p=c;break e}n(p,A);break}else t(p,A);A=A.sibling}h.type===Kn?(c=An(h.props.children,p.mode,w,h.key),c.return=p,p=c):(w=ii(h.type,h.key,h.props,null,p.mode,w),w.ref=Lr(p,c,h),w.return=p,p=w)}return l(p);case Hn:e:{for(A=h.key;c!==null;){if(c.key===A)if(c.tag===4&&c.stateNode.containerInfo===h.containerInfo&&c.stateNode.implementation===h.implementation){n(p,c.sibling),c=o(c,h.children||[]),c.return=p,p=c;break e}else{n(p,c);break}else t(p,c);c=c.sibling}c=Pl(h,p.mode,w),c.return=p,p=c}return l(p);case nn:return A=h._init,_(p,c,A(h._payload),w)}if(Rr(h))return S(p,c,h,w);if(Nr(h))return b(p,c,h,w);Wo(p,h)}return typeof h=="string"&&h!==""||typeof h=="number"?(h=""+h,c!==null&&c.tag===6?(n(p,c.sibling),c=o(c,h),c.return=p,p=c):(n(p,c),c=Al(h,p.mode,w),c.return=p,p=c),l(p)):n(p,c)}return _}var dr=ed(!0),td=ed(!1),bi=xn(null),xi=null,Jn=null,Ba=null;function Ha(){Ba=Jn=xi=null}function Ka(e){var t=bi.current;pe(bi),e._currentValue=t}function aa(e,t,n){for(;e!==null;){var r=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,r!==null&&(r.childLanes|=t)):r!==null&&(r.childLanes&t)!==t&&(r.childLanes|=t),e===n)break;e=e.return}}function lr(e,t){xi=e,Ba=Jn=null,e=e.dependencies,e!==null&&e.firstContext!==null&&((e.lanes&t)!==0&&(Xe=!0),e.firstContext=null)}function yt(e){var t=e._currentValue;if(Ba!==e)if(e={context:e,memoizedValue:t,next:null},Jn===null){if(xi===null)throw Error(L(308));Jn=e,xi.dependencies={lanes:0,firstContext:e}}else Jn=Jn.next=e;return t}var Cn=null;function Wa(e){Cn===null?Cn=[e]:Cn.push(e)}function nd(e,t,n,r){var o=t.interleaved;return o===null?(n.next=n,Wa(t)):(n.next=o.next,o.next=n),t.interleaved=n,Yt(e,r)}function Yt(e,t){e.lanes|=t;var n=e.alternate;for(n!==null&&(n.lanes|=t),n=e,e=e.return;e!==null;)e.childLanes|=t,n=e.alternate,n!==null&&(n.childLanes|=t),n=e,e=e.return;return n.tag===3?n.stateNode:null}var rn=!1;function Ga(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function rd(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function Kt(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function mn(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,(X&2)!==0){var o=r.pending;return o===null?t.next=t:(t.next=o.next,o.next=t),r.pending=t,Yt(e,n)}return o=r.interleaved,o===null?(t.next=t,Wa(r)):(t.next=o.next,o.next=t),r.interleaved=t,Yt(e,n)}function Jo(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,(n&4194240)!==0)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,Ta(e,n)}}function Pu(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var o=null,i=null;if(n=n.firstBaseUpdate,n!==null){do{var l={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};i===null?o=i=l:i=i.next=l,n=n.next}while(n!==null);i===null?o=i=t:i=i.next=t}else o=i=t;n={baseState:r.baseState,firstBaseUpdate:o,lastBaseUpdate:i,shared:r.shared,effects:r.effects},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function wi(e,t,n,r){var o=e.updateQueue;rn=!1;var i=o.firstBaseUpdate,l=o.lastBaseUpdate,s=o.shared.pending;if(s!==null){o.shared.pending=null;var u=s,d=u.next;u.next=null,l===null?i=d:l.next=d,l=u;var m=e.alternate;m!==null&&(m=m.updateQueue,s=m.lastBaseUpdate,s!==l&&(s===null?m.firstBaseUpdate=d:s.next=d,m.lastBaseUpdate=u))}if(i!==null){var y=o.baseState;l=0,m=d=u=null,s=i;do{var g=s.lane,f=s.eventTime;if((r&g)===g){m!==null&&(m=m.next={eventTime:f,lane:0,tag:s.tag,payload:s.payload,callback:s.callback,next:null});e:{var S=e,b=s;switch(g=t,f=n,b.tag){case 1:if(S=b.payload,typeof S=="function"){y=S.call(f,y,g);break e}y=S;break e;case 3:S.flags=S.flags&-65537|128;case 0:if(S=b.payload,g=typeof S=="function"?S.call(f,y,g):S,g==null)break e;y=xe({},y,g);break e;case 2:rn=!0}}s.callback!==null&&s.lane!==0&&(e.flags|=64,g=o.effects,g===null?o.effects=[s]:g.push(s))}else f={eventTime:f,lane:g,tag:s.tag,payload:s.payload,callback:s.callback,next:null},m===null?(d=m=f,u=y):m=m.next=f,l|=g;if(s=s.next,s===null){if(s=o.shared.pending,s===null)break;g=s,s=g.next,g.next=null,o.lastBaseUpdate=g,o.shared.pending=null}}while(!0);if(m===null&&(u=y),o.baseState=u,o.firstBaseUpdate=d,o.lastBaseUpdate=m,t=o.shared.interleaved,t!==null){o=t;do l|=o.lane,o=o.next;while(o!==t)}else i===null&&(o.shared.lanes=0);Mn|=l,e.lanes=l,e.memoizedState=y}}function Tu(e,t,n){if(e=t.effects,t.effects=null,e!==null)for(t=0;tn?n:4,e(!0);var r=El.transition;El.transition={};try{e(!1),t()}finally{ne=n,El.transition=r}}function xd(){return vt().memoizedState}function Af(e,t,n){var r=gn(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},wd(e))kd(t,n);else if(n=nd(e,t,n,r),n!==null){var o=Ye();At(n,e,r,o),Sd(n,t,r)}}function Pf(e,t,n){var r=gn(e),o={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(wd(e))kd(t,o);else{var i=e.alternate;if(e.lanes===0&&(i===null||i.lanes===0)&&(i=t.lastRenderedReducer,i!==null))try{var l=t.lastRenderedState,s=i(l,n);if(o.hasEagerState=!0,o.eagerState=s,Pt(s,l)){var u=t.interleaved;u===null?(o.next=o,Wa(t)):(o.next=u.next,u.next=o),t.interleaved=o;return}}catch{}finally{}n=nd(e,t,o,r),n!==null&&(o=Ye(),At(n,e,r,o),Sd(n,t,r))}}function wd(e){var t=e.alternate;return e===be||t!==null&&t===be}function kd(e,t){Ur=Si=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Sd(e,t,n){if((n&4194240)!==0){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,Ta(e,n)}}var Ni={readContext:yt,useCallback:je,useContext:je,useEffect:je,useImperativeHandle:je,useInsertionEffect:je,useLayoutEffect:je,useMemo:je,useReducer:je,useRef:je,useState:je,useDebugValue:je,useDeferredValue:je,useTransition:je,useMutableSource:je,useSyncExternalStore:je,useId:je,unstable_isNewReconciler:!1},Tf={readContext:yt,useCallback:function(e,t){return Mt().memoizedState=[e,t===void 0?null:t],e},useContext:yt,useEffect:Mu,useImperativeHandle:function(e,t,n){return n=n!=null?n.concat([e]):null,ti(4194308,4,gd.bind(null,t,e),n)},useLayoutEffect:function(e,t){return ti(4194308,4,e,t)},useInsertionEffect:function(e,t){return ti(4,2,e,t)},useMemo:function(e,t){var n=Mt();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=Mt();return t=n!==void 0?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=Af.bind(null,be,e),[r.memoizedState,e]},useRef:function(e){var t=Mt();return e={current:e},t.memoizedState=e},useState:Ru,useDebugValue:ts,useDeferredValue:function(e){return Mt().memoizedState=e},useTransition:function(){var e=Ru(!1),t=e[0];return e=zf.bind(null,e[1]),Mt().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=be,o=Mt();if(fe){if(n===void 0)throw Error(L(407));n=n()}else{if(n=t(),Te===null)throw Error(L(349));(Rn&30)!==0||ad(r,t,n)}o.memoizedState=n;var i={value:n,getSnapshot:t};return o.queue=i,Mu(ud.bind(null,r,i,e),[e]),r.flags|=2048,lo(9,sd.bind(null,r,i,n,t),void 0,null),n},useId:function(){var e=Mt(),t=Te.identifierPrefix;if(fe){var n=Ht,r=Bt;n=(r&~(1<<32-zt(r)-1)).toString(32)+n,t=":"+t+"R"+n,n=oo++,0<\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=l.createElement(n,{is:r.is}):(e=l.createElement(n),n==="select"&&(l=e,r.multiple?l.multiple=!0:r.size&&(l.size=r.size))):e=l.createElementNS(e,n),e[Mt]=t,e[eo]=r,Td(e,t,!1,!1),t.stateNode=e;e:{switch(l=Ul(n,r),n){case"dialog":ce("cancel",e),ce("close",e),o=r;break;case"iframe":case"object":case"embed":ce("load",e),o=r;break;case"video":case"audio":for(o=0;ogr&&(t.flags|=128,r=!0,Lr(i,!1),t.lanes=4194304)}else{if(!r)if(e=wi(l),e!==null){if(t.flags|=128,r=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),Lr(i,!0),i.tail===null&&i.tailMode==="hidden"&&!l.alternate&&!pe)return Ie(t),null}else 2*we()-i.renderingStartTime>gr&&n!==1073741824&&(t.flags|=128,r=!0,Lr(i,!1),t.lanes=4194304);i.isBackwards?(l.sibling=t.child,t.child=l):(n=i.last,n!==null?n.sibling=l:t.child=l,i.last=l)}return i.tail!==null?(t=i.tail,i.rendering=t,i.tail=t.sibling,i.renderingStartTime=we(),t.sibling=null,n=he.current,ae(he,r?n&1|2:n&1),t):(Ie(t),null);case 22:case 23:return is(),r=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(t.flags|=8192),r&&(t.mode&1)!==0?(tt&1073741824)!==0&&(Ie(t),t.subtreeFlags&6&&(t.flags|=8192)):Ie(t),null;case 24:return null;case 25:return null}throw Error(z(156,t.tag))}function Of(e,t){switch(Da(t),t.tag){case 1:return Ze(t.type)&&fi(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return mr(),de(Xe),de(De),Ya(),e=t.flags,(e&65536)!==0&&(e&128)===0?(t.flags=e&-65537|128,t):null;case 5:return Ga(t),null;case 13:if(de(he),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(z(340));dr()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return de(he),null;case 4:return mr(),null;case 10:return Ba(t.type._context),null;case 22:case 23:return is(),null;case 24:return null;default:return null}}var Go=!1,Fe=!1,$f=typeof WeakSet=="function"?WeakSet:Set,$=null;function tr(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(r){be(e,t,r)}else n.current=null}function fa(e,t,n){try{n()}catch(r){be(e,t,r)}}var Hu=!1;function If(e,t){if(Xl=ci,e=Dc(),Ia(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var o=r.anchorOffset,i=r.focusNode;r=r.focusOffset;try{n.nodeType,i.nodeType}catch{n=null;break e}var l=0,s=-1,u=-1,d=0,m=0,y=e,g=null;t:for(;;){for(var f;y!==n||o!==0&&y.nodeType!==3||(s=l+o),y!==i||r!==0&&y.nodeType!==3||(u=l+r),y.nodeType===3&&(l+=y.nodeValue.length),(f=y.firstChild)!==null;)g=y,y=f;for(;;){if(y===e)break t;if(g===n&&++d===o&&(s=l),g===i&&++m===r&&(u=l),(f=y.nextSibling)!==null)break;y=g,g=y.parentNode}y=f}n=s===-1||u===-1?null:{start:s,end:u}}else n=null}n=n||{start:0,end:0}}else n=null;for(Zl={focusedElem:e,selectionRange:n},ci=!1,$=t;$!==null;)if(t=$,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,$=e;else for(;$!==null;){t=$;try{var E=t.alternate;if((t.flags&1024)!==0)switch(t.tag){case 0:case 11:case 15:break;case 1:if(E!==null){var b=E.memoizedProps,_=E.memoizedState,p=t.stateNode,c=p.getSnapshotBeforeUpdate(t.elementType===t.type?b:St(t.type,b),_);p.__reactInternalSnapshotBeforeUpdate=c}break;case 3:var h=t.stateNode.containerInfo;h.nodeType===1?h.textContent="":h.nodeType===9&&h.documentElement&&h.removeChild(h.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(z(163))}}catch(k){be(t,t.return,k)}if(e=t.sibling,e!==null){e.return=t.return,$=e;break}$=t.return}return E=Hu,Hu=!1,E}function Ur(e,t,n){var r=t.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var o=r=r.next;do{if((o.tag&e)===e){var i=o.destroy;o.destroy=void 0,i!==void 0&&fa(t,n,i)}o=o.next}while(o!==r)}}function Ii(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function ga(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}function Od(e){var t=e.alternate;t!==null&&(e.alternate=null,Od(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[Mt],delete t[eo],delete t[ta],delete t[xf],delete t[bf])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function $d(e){return e.tag===5||e.tag===3||e.tag===4}function Ku(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||$d(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function ha(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=mi));else if(r!==4&&(e=e.child,e!==null))for(ha(e,t,n),e=e.sibling;e!==null;)ha(e,t,n),e=e.sibling}function ya(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(ya(e,t,n),e=e.sibling;e!==null;)ya(e,t,n),e=e.sibling}var Pe=null,Nt=!1;function Jt(e,t,n){for(n=n.child;n!==null;)Id(e,t,n),n=n.sibling}function Id(e,t,n){if(Rt&&typeof Rt.onCommitFiberUnmount=="function")try{Rt.onCommitFiberUnmount(zi,n)}catch{}switch(n.tag){case 5:Fe||tr(n,t);case 6:var r=Pe,o=Nt;Pe=null,Jt(e,t,n),Pe=r,Nt=o,Pe!==null&&(Nt?(e=Pe,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):Pe.removeChild(n.stateNode));break;case 18:Pe!==null&&(Nt?(e=Pe,n=n.stateNode,e.nodeType===8?bl(e.parentNode,n):e.nodeType===1&&bl(e,n),Qr(e)):bl(Pe,n.stateNode));break;case 4:r=Pe,o=Nt,Pe=n.stateNode.containerInfo,Nt=!0,Jt(e,t,n),Pe=r,Nt=o;break;case 0:case 11:case 14:case 15:if(!Fe&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){o=r=r.next;do{var i=o,l=i.destroy;i=i.tag,l!==void 0&&((i&2)!==0||(i&4)!==0)&&fa(n,t,l),o=o.next}while(o!==r)}Jt(e,t,n);break;case 1:if(!Fe&&(tr(n,t),r=n.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(s){be(n,t,s)}Jt(e,t,n);break;case 21:Jt(e,t,n);break;case 22:n.mode&1?(Fe=(r=Fe)||n.memoizedState!==null,Jt(e,t,n),Fe=r):Jt(e,t,n);break;default:Jt(e,t,n)}}function Wu(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new $f),t.forEach(function(r){var o=Wf.bind(null,e,r);n.has(r)||(n.add(r),r.then(o,o))})}}function kt(e,t){var n=t.deletions;if(n!==null)for(var r=0;ro&&(o=l),r&=~i}if(r=o,r=we()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*Df(r/1960))-r,10e?16:e,ln===null)var r=!1;else{if(e=ln,ln=null,_i=0,(Y&6)!==0)throw Error(z(331));var o=Y;for(Y|=4,$=e.current;$!==null;){var i=$,l=i.child;if(($.flags&16)!==0){var s=i.deletions;if(s!==null){for(var u=0;uwe()-rs?Ln(e,0):ns|=n),Je(e,t)}function Kd(e,t){t===0&&((e.mode&1)===0?t=1:(t=Ro,Ro<<=1,(Ro&130023424)===0&&(Ro=4194304)));var n=Ke();e=Ht(e,t),e!==null&&(ao(e,t,n),Je(e,n))}function Kf(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),Kd(e,n)}function Wf(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,o=e.memoizedState;o!==null&&(n=o.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(z(314))}r!==null&&r.delete(t),Kd(e,n)}var Wd;Wd=function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||Xe.current)qe=!0;else{if((e.lanes&n)===0&&(t.flags&128)===0)return qe=!1,Mf(e,t,n);qe=(e.flags&131072)!==0}else qe=!1,pe&&(t.flags&1048576)!==0&&qc(t,yi,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;ti(e,t),e=t.pendingProps;var o=cr(t,De.current);ar(t,n),o=qa(null,t,r,e,o,n);var i=Xa();return t.flags|=1,typeof o=="object"&&o!==null&&typeof o.render=="function"&&o.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,Ze(r)?(i=!0,gi(t)):i=!1,t.memoizedState=o.state!==null&&o.state!==void 0?o.state:null,Ka(t),o.updater=$i,t.stateNode=o,o._reactInternals=t,aa(t,r,e,n),t=ca(null,t,r,!0,i,n)):(t.tag=0,pe&&i&&Fa(t),He(null,t,o,n),t=t.child),t;case 16:r=t.elementType;e:{switch(ti(e,t),e=t.pendingProps,o=r._init,r=o(r._payload),t.type=r,o=t.tag=Yf(r),e=St(r,e),o){case 0:t=ua(null,t,r,e,n);break e;case 1:t=Uu(null,t,r,e,n);break e;case 11:t=Du(null,t,r,e,n);break e;case 14:t=ju(null,t,r,St(r.type,e),n);break e}throw Error(z(306,r,""))}return t;case 0:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:St(r,o),ua(e,t,r,o,n);case 1:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:St(r,o),Uu(e,t,r,o,n);case 3:e:{if(zd(t),e===null)throw Error(z(387));r=t.pendingProps,i=t.memoizedState,o=i.element,nd(e,t),bi(t,r,null,n);var l=t.memoizedState;if(r=l.element,i.isDehydrated)if(i={element:r,isDehydrated:!1,cache:l.cache,pendingSuspenseBoundaries:l.pendingSuspenseBoundaries,transitions:l.transitions},t.updateQueue.baseState=i,t.memoizedState=i,t.flags&256){o=fr(Error(z(423)),t),t=Vu(e,t,r,n,o);break e}else if(r!==o){o=fr(Error(z(424)),t),t=Vu(e,t,r,n,o);break e}else for(nt=cn(t.stateNode.containerInfo.firstChild),rt=t,pe=!0,Et=null,n=ed(t,null,r,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if(dr(),r===o){t=Kt(e,t,n);break e}He(e,t,r,n)}t=t.child}return t;case 5:return rd(t),e===null&&oa(t),r=t.type,o=t.pendingProps,i=e!==null?e.memoizedProps:null,l=o.children,Jl(r,o)?l=null:i!==null&&Jl(r,i)&&(t.flags|=32),Ld(e,t),He(e,t,l,n),t.child;case 6:return e===null&&oa(t),null;case 13:return Ad(e,t,n);case 4:return Wa(t,t.stateNode.containerInfo),r=t.pendingProps,e===null?t.child=pr(t,null,r,n):He(e,t,r,n),t.child;case 11:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:St(r,o),Du(e,t,r,o,n);case 7:return He(e,t,t.pendingProps,n),t.child;case 8:return He(e,t,t.pendingProps.children,n),t.child;case 12:return He(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,o=t.pendingProps,i=t.memoizedProps,l=o.value,ae(vi,r._currentValue),r._currentValue=l,i!==null)if(Lt(i.value,l)){if(i.children===o.children&&!Xe.current){t=Kt(e,t,n);break e}}else for(i=t.child,i!==null&&(i.return=t);i!==null;){var s=i.dependencies;if(s!==null){l=i.child;for(var u=s.firstContext;u!==null;){if(u.context===r){if(i.tag===1){u=Ut(-1,n&-n),u.tag=2;var d=i.updateQueue;if(d!==null){d=d.shared;var m=d.pending;m===null?u.next=u:(u.next=m.next,m.next=u),d.pending=u}}i.lanes|=n,u=i.alternate,u!==null&&(u.lanes|=n),ia(i.return,n,t),s.lanes|=n;break}u=u.next}}else if(i.tag===10)l=i.type===t.type?null:i.child;else if(i.tag===18){if(l=i.return,l===null)throw Error(z(341));l.lanes|=n,s=l.alternate,s!==null&&(s.lanes|=n),ia(l,n,t),l=i.sibling}else l=i.child;if(l!==null)l.return=i;else for(l=i;l!==null;){if(l===t){l=null;break}if(i=l.sibling,i!==null){i.return=l.return,l=i;break}l=l.return}i=l}He(e,t,o.children,n),t=t.child}return t;case 9:return o=t.type,r=t.pendingProps.children,ar(t,n),o=vt(o),r=r(o),t.flags|=1,He(e,t,r,n),t.child;case 14:return r=t.type,o=St(r,t.pendingProps),o=St(r.type,o),ju(e,t,r,o,n);case 15:return _d(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:St(r,o),ti(e,t),t.tag=1,Ze(r)?(e=!0,gi(t)):e=!1,ar(t,n),Sd(t,r,o),aa(t,r,o,n),ca(null,t,r,!0,e,n);case 19:return Pd(e,t,n);case 22:return Cd(e,t,n)}throw Error(z(156,t.tag))};function Gd(e,t){return bc(e,t)}function Gf(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function ht(e,t,n,r){return new Gf(e,t,n,r)}function as(e){return e=e.prototype,!(!e||!e.isReactComponent)}function Yf(e){if(typeof e=="function")return as(e)?1:0;if(e!=null){if(e=e.$$typeof,e===_a)return 11;if(e===Ca)return 14}return 2}function fn(e,t){var n=e.alternate;return n===null?(n=ht(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function oi(e,t,n,r,o,i){var l=2;if(r=e,typeof e=="function")as(e)&&(l=1);else if(typeof e=="string")l=5;else e:switch(e){case Wn:return zn(n.children,o,i,t);case Ea:l=8,o|=8;break;case Pl:return e=ht(12,n,t,o|2),e.elementType=Pl,e.lanes=i,e;case Tl:return e=ht(13,n,t,o),e.elementType=Tl,e.lanes=i,e;case Ml:return e=ht(19,n,t,o),e.elementType=Ml,e.lanes=i,e;case rc:return Di(n,o,i,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case tc:l=10;break e;case nc:l=9;break e;case _a:l=11;break e;case Ca:l=14;break e;case en:l=16,r=null;break e}throw Error(z(130,e==null?e:typeof e,""))}return t=ht(l,n,t,o),t.elementType=e,t.type=r,t.lanes=i,t}function zn(e,t,n,r){return e=ht(7,e,r,t),e.lanes=n,e}function Di(e,t,n,r){return e=ht(22,e,r,t),e.elementType=rc,e.lanes=n,e.stateNode={isHidden:!1},e}function Ll(e,t,n){return e=ht(6,e,null,t),e.lanes=n,e}function zl(e,t,n){return t=ht(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function Qf(e,t,n,r,o){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=pl(0),this.expirationTimes=pl(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=pl(0),this.identifierPrefix=r,this.onRecoverableError=o,this.mutableSourceEagerHydrationData=null}function ss(e,t,n,r,o,i,l,s,u){return e=new Qf(e,t,n,s,u),t===1?(t=1,i===!0&&(t|=8)):t=0,i=ht(3,null,null,t),e.current=i,i.stateNode=e,i.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},Ka(i),e}function qf(e,t,n){var r=3{"use strict";function Zd(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(Zd)}catch(e){console.error(e)}}Zd(),Jd.exports=Xd()});var np=$t(ps=>{"use strict";var tp=ep();ps.createRoot=tp.createRoot,ps.hydrateRoot=tp.hydrateRoot;var ph});var op=$t(Hi=>{"use strict";var tg=No(),ng=Symbol.for("react.element"),rg=Symbol.for("react.fragment"),og=Object.prototype.hasOwnProperty,ig=tg.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,lg={key:!0,ref:!0,__self:!0,__source:!0};function rp(e,t,n){var r,o={},i=null,l=null;n!==void 0&&(i=""+n),t.key!==void 0&&(i=""+t.key),t.ref!==void 0&&(l=t.ref);for(r in t)og.call(t,r)&&!lg.hasOwnProperty(r)&&(o[r]=t[r]);if(e&&e.defaultProps)for(r in t=e.defaultProps,t)o[r]===void 0&&(o[r]=t[r]);return{$$typeof:ng,type:e,key:i,ref:l,props:o,_owner:ig.current}}Hi.Fragment=rg;Hi.jsx=rp;Hi.jsxs=rp});var ms=$t((yh,ip)=>{"use strict";ip.exports=op()});var N=bo(No(),1),bp=bo(np(),1);var a=bo(ms(),1),wp={hidden:"UKRYTY",connecting:"\u0141\u0104CZENIE",connected:"ONLINE \xB7 LIVE",replaying:"ONLINE \xB7 REPLAY",verifying:"ONLINE \xB7 WERYFIKACJA",ready:"ONLINE \xB7 GOTOWY",failed:"ONLINE \xB7 B\u0141\u0104D STANU",offline:"OFFLINE \xB7 ZAPIS",unselected:"OFFLINE \xB7 BRAK CELU"},lp=.25,Fn=1,ap=4;function ag(e){let t=window.getComputedStyle(e).overflowY;return t==="auto"||t==="scroll"||t==="hidden"||t==="clip"}function kp(e){let t=e.getBoundingClientRect(),n=e.offsetHeight||e.clientHeight,r=n>0?t.height/n:1,o=t.top+e.clientTop*r;return{top:o,bottom:o+e.clientHeight*r}}function Sp(e){let t=document.querySelector(".viewer-chrome");if(t?.classList.contains("is-nvim-fit"))return null;let n=0,r=window.innerHeight;if(t){let o=t.getBoundingClientRect(),i=e.getBoundingClientRect();o.lefti.left&&o.bottom>0&&o.topFn?{top:n,bottom:r}:null}function sg(e){let t=Sp(e);if(!t)return null;let{top:n,bottom:r}=t;for(let o=e.parentElement;o&&o!==document.body&&o!==document.documentElement;o=o.parentElement){if(!ag(o))continue;let i=kp(o);n=Math.max(n,i.top),r=Math.min(r,i.bottom)}return r-n>Fn?{top:n,bottom:r}:null}function Gi(){return document.scrollingElement??document.documentElement}function ug(e){let t=[];for(let r=e.parentElement;r&&r!==document.body&&r!==document.documentElement;r=r.parentElement){let o=window.getComputedStyle(r).overflowY;(o==="auto"||o==="scroll")&&r.scrollHeight-r.clientHeight>1&&t.push(r)}let n=Gi();return t.includes(n)||t.push(n),t}function cg(e){if(e===Gi())return 1;let t=e.getBoundingClientRect(),n=e.offsetHeight||e.clientHeight,r=n>0?t.height/n:1;return Number.isFinite(r)&&r>0?r:1}function Ki(e,t){let n=e.style.scrollBehavior;e.style.scrollBehavior="auto",t.left!=null&&(e.scrollLeft=t.left),t.top!=null&&(e.scrollTop=t.top),e.style.scrollBehavior=n}function dg(e,t){let n=e.closest(".sheet-content");if(!n)return 0;let r=kp(n),o=0;if(r.bottom<=t.top?o=r.bottom-t.bottom:r.top>=t.bottom&&(o=r.top-t.top),Math.abs(o)<=Fn)return 0;let i=Gi(),l=i.scrollTop,s=Math.max(0,i.scrollHeight-i.clientHeight);return Ki(i,{top:Math.max(0,Math.min(s,l+o))}),i.scrollTop-l}function sp(e,t){let n=t;for(let r of ug(e)){if(Math.abs(n)<=Fn)break;let o=cg(r),i=Math.max(0,r.scrollHeight-r.clientHeight),l=r.scrollTop,s=Math.max(0,Math.min(i,l+n/o));Ki(r,{top:s}),n-=(r.scrollTop-l)*o}return t-n}function up(e,t){let n=e.getBoundingClientRect(),r=(n.top+n.bottom)/2,o=t.bottom-t.top,i=t.top+o*lp,l=t.bottom-o*lp;return rl?r-l:0}var Yt=({html:e,className:t})=>(0,a.jsx)("div",{className:t,dangerouslySetInnerHTML:{__html:e}});function Np(e,t){e.setAttribute("preserveAspectRatio","xMinYMin meet"),t&&(e.setAttribute("viewBox",`${t.x} ${t.y} ${t.width} ${t.height}`),e.setAttribute("width",`${t.width}px`),e.setAttribute("height",`${t.height}px`),e.dataset.tileIndex=String(t.index),e.dataset.tileRow=String(t.row),e.dataset.tileColumn=String(t.column))}function pg(e){return e.normalize("NFKD").replace(/[\u0300-\u036f]/g,"").toLowerCase().replace(/[^a-z0-9_.:-]+/g,"-").replace(/^-+|-+$/g,"").slice(0,120)||"uml-element"}function gs(e){let t=e;if(typeof t.getBBox!="function")return null;try{let n=t.getBBox();return[n.x,n.y,n.width,n.height].every(Number.isFinite)?{x:n.x,y:n.y,width:n.width,height:n.height}:null}catch{return null}}function mg(e){let t=gs(e);if(!t)return null;let n=Number(e.dataset.umlLayoutOriginX),r=Number(e.dataset.umlLayoutOriginY),o=Number(e.dataset.umlLayoutDx),i=Number(e.dataset.umlLayoutDy),l=Number(e.dataset.umlLayoutSx),s=Number(e.dataset.umlLayoutSy);return[n,r,o,i,l,s].every(Number.isFinite)?{x:n+(t.x-n)*l+o,y:r+(t.y-r)*s+i,width:t.width*l,height:t.height*s}:t}function Ep(e){e.dataset.umlLayoutRemembered!=="true"&&(e.dataset.umlLayoutRemembered="true",e.dataset.umlLayoutOriginalTransform=e.getAttribute("transform")??"",e.dataset.umlLayoutOriginalVisibility=e.getAttribute("visibility")??"",e.dataset.umlLayoutOriginalStyle=e.getAttribute("style")??"",e instanceof SVGTextElement&&(e.dataset.umlLayoutOriginalText=e.textContent??"",e.dataset.umlLayoutOriginalX=e.getAttribute("x")??"",e.dataset.umlLayoutOriginalTextAnchor=e.getAttribute("text-anchor")??"",e.dataset.umlLayoutOriginalFontFamily=e.getAttribute("font-family")??"",e.dataset.umlLayoutOriginalFontSize=e.getAttribute("font-size")??"",e.dataset.umlLayoutOriginalFontWeight=e.getAttribute("font-weight")??""),e instanceof SVGRectElement&&(e.dataset.umlLayoutOriginalFill=e.getAttribute("fill")??"",e.dataset.umlLayoutOriginalStroke=e.getAttribute("stroke")??"",e.dataset.umlLayoutOriginalStrokeWidth=e.getAttribute("stroke-width")??""))}function fg(e){e.querySelectorAll(".uml-layout-hit,.uml-layout-resize,.uml-layout-generated").forEach(t=>t.remove()),e.querySelectorAll("[data-uml-layout-remembered='true']").forEach(t=>{let n=(r,o)=>{o?t.setAttribute(r,o):t.removeAttribute(r)};n("transform",t.dataset.umlLayoutOriginalTransform),n("visibility",t.dataset.umlLayoutOriginalVisibility),n("style",t.dataset.umlLayoutOriginalStyle),t instanceof SVGTextElement&&(t.textContent=t.dataset.umlLayoutOriginalText??"",n("x",t.dataset.umlLayoutOriginalX),n("text-anchor",t.dataset.umlLayoutOriginalTextAnchor),n("font-family",t.dataset.umlLayoutOriginalFontFamily),n("font-size",t.dataset.umlLayoutOriginalFontSize),n("font-weight",t.dataset.umlLayoutOriginalFontWeight)),t instanceof SVGRectElement&&(n("fill",t.dataset.umlLayoutOriginalFill),n("stroke",t.dataset.umlLayoutOriginalStroke),n("stroke-width",t.dataset.umlLayoutOriginalStrokeWidth)),delete t.dataset.umlLayoutOriginX,delete t.dataset.umlLayoutOriginY,delete t.dataset.umlLayoutDx,delete t.dataset.umlLayoutDy,delete t.dataset.umlLayoutSx,delete t.dataset.umlLayoutSy,delete t.dataset.umlLayoutId})}function gg(e,t){let n=e.querySelector(":scope > g")??e,r=Array.from(n.children).filter(s=>s instanceof SVGElement),o=r.filter(s=>s instanceof SVGRectElement).map(s=>({rect:s,box:gs(s)})).filter(s=>!!(s.box&&s.box.width>=30&&s.box.height>=14)).sort((s,u)=>s.box.width*s.box.height-u.box.width*u.box.height),i=new Map;for(let s of r){let u=gs(s);if(!u)continue;let d=u.x+u.width/2,m=u.y+u.height/2,y=o.find(({box:g})=>d>=g.x-.5&&d<=g.x+g.width+.5&&m>=g.y-.5&&m<=g.y+g.height+.5);y&&i.set(s,y.rect)}let l=new Set;return o.map(({rect:s,box:u},d)=>{let m=r.filter(c=>i.get(c)===s);m.includes(s)||m.unshift(s);let y=m.filter(c=>c instanceof SVGTextElement).sort((c,h)=>Number(c.getAttribute("y"))-Number(h.getAttribute("y"))),g=(y[0]?.textContent??s.id??`element-${d+1}`).trim(),f=/^(\d{1,3})\b/.exec(g)?.[1]?.padStart(2,"0"),E=s.id||(f?t.get(f):"")||g,b=pg(E),_=b,p=2;for(;l.has(_);)_=`${b}-${p++}`;return l.add(_),m.forEach(Ep),{id:_,box:u,rect:s,members:m,texts:y}})}function po(e){let t=e.texts[0],n=e.rect.getAttribute("style")??"",r=i=>new RegExp(`${i}\\s*:\\s*([^;]+)`,"i").exec(n)?.[1]?.trim(),o=Number(t?.getAttribute("font-size")??12);return{...e.box,z:0,scale:1,rotation:0,text:{title:(e.texts[0]?.textContent??"").trim(),description:e.texts.slice(1).map(i=>(i.textContent??"").trim()).join(` -`),lines:e.texts.map(i=>(i.textContent??"").trim()),font_family:t?.getAttribute("font-family")??"Monospace",font_size:Number.isFinite(o)?o:12,font_weight:Number(t?.getAttribute("font-weight")??400)||400,align:"left"},style:{fill:e.rect.getAttribute("fill")??r("fill")??"#edf6fa",stroke:e.rect.getAttribute("stroke")??r("stroke")??"#2c7794",stroke_width:Number(e.rect.getAttribute("stroke-width")??r("stroke-width")??1.5)}}}function hg(e,t){let n=Math.max(12,Number(t.width)||e.box.width),r=Math.max(12,Number(t.height)||e.box.height),o=Number.isFinite(Number(t.x))?Number(t.x):e.box.x,i=Number.isFinite(Number(t.y))?Number(t.y):e.box.y,l=n/Math.max(1,e.box.width),s=r/Math.max(1,e.box.height),u=o-e.box.x,d=i-e.box.y,m=`translate(${u} ${d}) translate(${e.box.x} ${e.box.y}) scale(${l} ${s}) translate(${-e.box.x} ${-e.box.y})`;e.members.forEach(f=>{Ep(f);let E=f.dataset.umlLayoutOriginalTransform??"";f.setAttribute("transform",`${m}${E?` ${E}`:""}`),f.dataset.umlLayoutOriginX=String(e.box.x),f.dataset.umlLayoutOriginY=String(e.box.y),f.dataset.umlLayoutDx=String(u),f.dataset.umlLayoutDy=String(d),f.dataset.umlLayoutSx=String(l),f.dataset.umlLayoutSy=String(s),f.dataset.umlLayoutId=e.id});let y=t.text??{},g=y.lines??[y.title??"",...y.description?y.description.split(` -`):[]];e.texts.forEach((f,E)=>{E(e.tile?.page_height??0)?"landscape":"portrait",scale:1},elements:{},relations:{}}}function hs(e){if(!e)return{};let t=e.column===1&&e.columns>1?e.page_width-e.width:e.column===e.columns?0:Math.max(0,(e.page_width-e.width)/2),n=e.row===1&&e.rows>1?e.page_height-e.height:e.row===e.rows?0:Math.max(0,(e.page_height-e.height)/2);return{"--uml-tile-page-width":`${e.page_width}px`,"--uml-tile-page-height":`${e.page_height}px`,"--uml-tile-left":`${t}px`,"--uml-tile-top":`${n}px`}}function yg({html:e}){return(0,a.jsx)(Yt,{html:e})}function vg(e){let t=e.spread_count??1;if(t<=1)return null;let n=Math.max(1,Math.min(t,e.spread_index??1)),r=Math.max(1,Math.min(t,e.spread_columns??1)),o=n-1,i=Math.floor(o/r),l=o%r;return{left:l>0,right:l+10,down:n+r<=t,index:n,count:t}}function _p({continuation:e}){if(!e)return null;let t=[e.left&&["left","\u2190","kontynuacja po lewej"],e.up&&["up","\u2191","kontynuacja powy\u017Cej"],e.down&&["down","\u2193","kontynuacja poni\u017Cej"],e.right&&["right","\u2192","kontynuacja po prawej"]].filter(Boolean);return(0,a.jsx)("span",{className:"uml-page-continuation","aria-label":`Logiczny diagram: strona ${e.index} z ${e.count}`,title:`Ten sam diagram \xB7 strona ${e.index}/${e.count}`,children:t.map(([n,r,o])=>(0,a.jsx)("i",{"data-direction":n,"aria-label":o,children:r},n))})}function cp({side:e,html:t}){return(0,a.jsx)("aside",{className:`pdf-margin ${e}`,dangerouslySetInnerHTML:{__html:t}})}function ys({header:e,left:t="",right:n="",children:r,className:o=""}){return(0,a.jsx)("article",{className:`sheet ${o}`,children:(0,a.jsxs)("div",{className:"sheet-content",children:[(0,a.jsx)(yg,{html:e}),(0,a.jsx)(cp,{side:"left",html:t}),(0,a.jsx)("section",{className:"pdf-main card-section",children:r}),(0,a.jsx)(cp,{side:"right",html:n})]})})}function xg({viewpoints:e}){let t=e.filter(i=>i.status==="enabled"&&i.target_id),[n,r]=(0,N.useState)(t[0]?.id??"");(0,N.useEffect)(()=>{if(!t.length)return;let i=0,l=()=>{window.cancelAnimationFrame(i),i=window.requestAnimationFrame(()=>{let s=document.querySelector(".viewer-chrome")?.getBoundingClientRect().bottom??0,u=t.map(m=>({viewpoint:m,element:document.getElementById(m.target_id)})).filter(m=>!!m.element);if(!u.length)return;let d=u.reduce((m,y)=>{let g=Math.abs(y.element.getBoundingClientRect().top-s-18);return g{window.cancelAnimationFrame(i),window.removeEventListener("scroll",l),window.removeEventListener("resize",l)}},[e]);let o=i=>{if(i.status!=="enabled"||!i.target_id)return;let l=document.getElementById(i.target_id);if(!l)return;let u=document.querySelector(".viewer-chrome")?.getBoundingClientRect().height??0;r(i.id),window.scrollTo({top:Math.max(0,window.scrollY+l.getBoundingClientRect().top-u-8),behavior:"smooth"})};return(0,a.jsx)("nav",{className:"viewpoint-bar","aria-label":"Perspektywy architektury A1\u2013A8",children:e.map(i=>{let l=i.status==="unavailable";return(0,a.jsxs)("button",{type:"button",className:l?"is-unavailable":"","aria-current":!l&&n===i.id?"location":void 0,disabled:l,title:l?i.reason:i.subtitle,onClick:()=>o(i),children:[(0,a.jsx)("span",{children:i.id}),(0,a.jsx)("strong",{children:i.label}),l&&(0,a.jsx)("small",{children:"N/D"})]},i.id)})})}function bg({toc:e,libraryAvailable:t,libraryOpen:n,setLibraryOpen:r,scale:o,setScale:i,nvimVisible:l,setNvimVisible:s,nvimSyncMode:u,setNvimSyncMode:d,nvimControlMode:m,setNvimControlMode:y,nvimExpanded:g,setNvimExpanded:f,nvimFit:E,setNvimFit:b,allocatorVisible:_,setAllocatorVisible:p,hasAllocatorModel:c,diagramSpread:h,setDiagramSpread:k,hasDiagramSpread:C,nvimSummary:P,progress:T,progressError:R}){return(0,a.jsx)("nav",{className:"topbar",children:(0,a.jsxs)("div",{className:"topbar-inner",children:[t&&(0,a.jsxs)("button",{type:"button",className:`card-library-toggle${n?" is-active":""}`,"aria-controls":"side-panel-left-library","aria-expanded":n,"aria-label":n?"Alt+0: zamknij serie i karty":"Alt+0: poka\u017C serie i karty",title:n?"Alt+0 \xB7 Zamknij serie i karty":"Alt+0 \xB7 Serie i karty",onClick:()=>r(!n),children:[(0,a.jsx)("span",{"aria-hidden":"true",className:"card-library-toggle-icon",children:"\u2630"}),(0,a.jsx)("kbd",{children:"A0"}),(0,a.jsx)("span",{children:"KARTY"})]}),(0,a.jsxs)("details",{children:[(0,a.jsx)("summary",{children:"Spis tre\u015Bci"}),(0,a.jsx)("div",{className:"toc-links",children:e.map(j=>(0,a.jsx)("a",{href:`#${j.id}`,children:j.label},j.id))})]}),(0,a.jsxs)("div",{className:"topbar-nvim-section","aria-label":"Panel Neovima",children:[(0,a.jsx)("span",{className:"nvim-toolbar-boundary","aria-hidden":"true",children:"|"}),(0,a.jsx)("span",{className:"nvim-toolbar-context",children:"NVIM"}),(0,a.jsxs)("div",{className:"nvim-toolbar-actions","aria-label":"Narz\u0119dzia okna Neovima",children:[(0,a.jsxs)("button",{className:"viewer-nvim-toggle nvim-toolbar-button","aria-label":l?"Alt+1: ukryj Neovim":"Alt+1: poka\u017C Neovim",title:l?"Alt+1 \xB7 Ukryj Neovim":"Alt+1 \xB7 Poka\u017C Neovim","aria-pressed":l,onClick:()=>s(!l),children:[(0,a.jsx)("kbd",{className:"nvim-toolbar-key",children:"A1"}),(0,a.jsx)("span",{className:"nvim-toolbar-label",children:"PANEL"})]}),(0,a.jsxs)("button",{type:"button",className:`nvim-control-indicator nvim-toolbar-button${P.syncMode?" is-active":""}${P.syncReady?" is-engaged":""}`,"aria-label":`Alt+2: synchronizacja ${u?"w\u0142\u0105czona":"wy\u0142\u0105czona"}`,title:`Alt+2 \xB7 SYNC ${u?"ON":"OFF"}`,"aria-pressed":u,onClick:()=>d(!u),children:[(0,a.jsx)("kbd",{className:"nvim-toolbar-key",children:"A2"}),(0,a.jsx)("span",{className:"nvim-toolbar-label",children:"SYNC"})]}),(0,a.jsxs)("button",{type:"button",className:`nvim-work-indicator nvim-toolbar-button${m?" is-active":""}${P.controlEnabled?" is-engaged":""}`,"aria-label":`Alt+3: sterowanie ${u?m?"w\u0142\u0105czone":"wy\u0142\u0105czone":"niedost\u0119pne"}`,title:u?`Alt+3 \xB7 Sterowanie ${m?"ON":"OFF"}`:"Alt+3 \xB7 Sterowanie wymaga SYNC ON","aria-pressed":m,disabled:!u,onClick:()=>y(!m),children:[(0,a.jsx)("kbd",{className:"nvim-toolbar-key",children:"A3"}),(0,a.jsx)("span",{className:"nvim-toolbar-label",children:"CTRL"})]}),(0,a.jsxs)("button",{type:"button",className:`nvim-height-toggle nvim-toolbar-button${g?" is-active":""}`,"aria-label":`Alt+4: ${g?"przywr\xF3\u0107 normaln\u0105 wysoko\u015B\u0107":"ustaw wysoki panel"}`,title:g?"Alt+4 \xB7 Normalna wysoko\u015B\u0107":"Alt+4 \xB7 Wysoki panel 90%","aria-pressed":g,onClick:()=>f(!g),children:[(0,a.jsx)("kbd",{className:"nvim-toolbar-key",children:"A4"}),(0,a.jsx)("span",{className:"nvim-toolbar-label",children:"HIGH"})]}),(0,a.jsxs)("button",{type:"button",className:`nvim-height-toggle nvim-toolbar-button${E?" is-active":""}`,"aria-label":`Alt+5: automatyczne dopasowanie ${E?"w\u0142\u0105czone":"wy\u0142\u0105czone"}`,title:E?"Alt+5 \xB7 Wy\u0142\u0105cz auto-fit":"Alt+5 \xB7 Poka\u017C ca\u0142y Neovim","aria-pressed":E,onClick:()=>b(!E),children:[(0,a.jsx)("kbd",{className:"nvim-toolbar-key",children:"A5"}),(0,a.jsx)("span",{className:"nvim-toolbar-label",children:"FIT"})]}),c&&(0,a.jsxs)("button",{type:"button",className:`nvim-height-toggle nvim-toolbar-button${_?" is-active":""}`,"aria-label":`Alt+6: model alokatora ${_?"przypi\u0119ty":"ukryty"}`,title:_?"Alt+6 \xB7 Ukryj model alokatora":"Alt+6 \xB7 Przypnij model alokatora","aria-pressed":_,onClick:()=>p(!_),children:[(0,a.jsx)("kbd",{className:"nvim-toolbar-key",children:"A6"}),(0,a.jsx)("span",{className:"nvim-toolbar-label",children:"MODEL"})]}),C&&(0,a.jsxs)("button",{type:"button",className:`nvim-height-toggle nvim-toolbar-button${h?" is-active":""}`,"aria-label":`Alt+7: diagram UML ${h?"jako osobne kartki A4":"jako po\u0142\u0105czony spread"}`,title:h?"Alt+7 \xB7 Osobne kartki A4":"Alt+7 \xB7 Po\u0142\u0105cz strony UML","aria-pressed":h,onClick:()=>k(!h),children:[(0,a.jsx)("kbd",{className:"nvim-toolbar-key",children:"A7"}),(0,a.jsx)("span",{className:"nvim-toolbar-label",children:"UML"})]})]}),(0,a.jsx)("span",{className:"nvim-toolbar-boundary","aria-hidden":"true",children:"|"}),l&&(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("span",{className:`nvim-status nvim-status--${P.state}`,children:wp[P.state]}),(0,a.jsxs)("span",{className:"topbar-nvim-meta",title:P.message,children:[(0,a.jsx)("strong",{children:P.instance??"Neovim MCP"}),P.detail&&(0,a.jsx)("small",{children:P.detail})]}),(0,a.jsxs)("span",{className:"nvim-shortcut-strip","aria-label":"Skr\xF3ty panelu Neovima",children:[(0,a.jsx)("kbd",{children:"F1"})," reset \xB7 ",(0,a.jsx)("kbd",{children:"F2"})," sync \xB7 ",(0,a.jsx)("kbd",{children:"Alt+W"})," okna \xB7 ",(0,a.jsx)("kbd",{children:"F12"})," skr\xF3ty"]})]})]}),(0,a.jsx)(Gg,{progress:T,error:R}),(0,a.jsxs)("div",{className:"viewer-zoom-controls",children:[(0,a.jsxs)("output",{className:"viewer-zoom-status",children:["P\u0142\xF3tno ",Math.round(o*100),"% \xB7 Tre\u015B\u0107 100%"]}),(0,a.jsx)("button",{className:"viewer-zoom-reset",onClick:()=>i(2.18),children:"Reset zoom"})]})]})})}function dp(e,t){for(let n of e.sections)for(let r of n.assets){let o=r.interactive;if(!(o?.kind!=="uml-sequence"||!o.phases?.length)&&!(t?.task.id&&o.task?.id!==t.task.id)&&!(t?.block.id&&o.block?.id!==t.block.id))for(let i of o.phases){if(t?.phase.id&&i.id!==t.phase.id)continue;let l=t?.step.id?i.steps.find(s=>s.id===t.step.id):i.steps[0];if(l)return{task:o.task??null,block:o.block??null,phase:{id:i.id,label:i.label},step:l,focusLevel:t?.focus_level??"step",activate:!1}}}return null}function wg({visible:e,model:t}){let[n,r]=(0,N.useState)(null);if((0,N.useEffect)(()=>{let g=f=>{r(f.detail??null)};return window.addEventListener("stem:nvim-step",g),r(dp(t)),fetch("/api/navigation/current",{cache:"no-store"}).then(f=>f.ok?f.json():Promise.reject()).then(f=>{let E=dp(t,f.current??null);E&&r(E)}).catch(()=>{}),()=>window.removeEventListener("stem:nvim-step",g)},[t]),!e)return null;let o=n?.focusLevel??"card",i=n?.step.snapshot?.memory.arena,l=!!(n&&o!=="card"&&o!=="task"),s=Math.max(1,Number(i?.size_bytes??64)),u=i?.offset==null?null:Math.max(0,Math.min(s,Number(i.offset))),d=i?.bytes.trim().split(/\s+/).filter(Boolean)??[],m=Math.min(s,64),y=n?[...(n.step.snapshot?.memory.items??[]).map(g=>({name:g.name,value:g.value})),...(n.step.snapshot?.frame.fields??[]).map(g=>({name:g.name,value:g.value}))].filter((g,f,E)=>E.findIndex(b=>b.name===g.name)===f).slice(0,8):[];return(0,a.jsxs)("section",{className:"allocator-panel","aria-label":"Przypi\u0119ty model alokatora",children:[(0,a.jsxs)("header",{children:[(0,a.jsx)("span",{children:"ALLOCATOR \xB7 PINNED"}),(0,a.jsx)("strong",{children:n?`${n.phase.label} \xB7 ${String(n.step.number).padStart(2,"0")} ${n.step.label}`:"Oczekiwanie na diagram UML"}),(0,a.jsx)("small",{children:l?n.step.snapshot?.description??n.step.description:"Wybierz co najmniej BLOCK. F2 wybierze jego pierwszy krok i wykona synchronizacj\u0119."})]}),(0,a.jsxs)("div",{className:"allocator-panel-body",children:[(0,a.jsxs)("dl",{className:"allocator-metrics",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)("dt",{children:"FOCUS"}),(0,a.jsx)("dd",{children:o.toUpperCase()})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("dt",{children:"BASE"}),(0,a.jsx)("dd",{children:i?.base??"\u2014"})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("dt",{children:"ALLOCP"}),(0,a.jsx)("dd",{children:i?.cursor??"\u2014"})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("dt",{children:"USED / FREE"}),(0,a.jsx)("dd",{children:u==null?"\u2014":`${u} / ${s-u} B`})]})]}),(0,a.jsxs)("div",{className:`allocator-arena-view${l?"":" is-inactive"}`,children:[(0,a.jsxs)("div",{className:"allocator-arena-labels",children:[(0,a.jsx)("span",{children:"allocbuf[0]"}),(0,a.jsx)("strong",{children:u==null?"allocp jeszcze nieustawiony":`offset ${u}`}),(0,a.jsxs)("span",{children:["allocbuf[",s-1,"]"]})]}),(0,a.jsxs)("div",{className:"allocator-pinned-arena",style:{"--allocator-size":m},children:[Array.from({length:m},(g,f)=>(0,a.jsx)("i",{className:u!=null&&f(0,a.jsxs)("div",{children:[(0,a.jsx)("span",{children:g.name}),(0,a.jsx)("code",{children:g.value})]},g.name)):(0,a.jsx)("p",{children:"Brak snapshotu."})})]})]})}var Wi=()=>({text:" ",highlight:0});function pp(e=1,t=1){return{width:e,height:t,cells:Array.from({length:t},()=>Array.from({length:e},Wi)),highlights:new Map,foreground:15263976,background:1053461,cursor:{row:0,column:0}}}function kg(e,t,n){if(t<=0||n<=0)return;let r=e.cells;e.width=t,e.height=n,e.cells=Array.from({length:n},(o,i)=>Array.from({length:t},(l,s)=>r[i]?.[s]??Wi()))}function Cp(e){return`stem-card:nvim-grid:${e}`}function Sg(e,t){if(t.width<=1||t.height<=1)return;let n={schema:"stem-nvim-grid.v1",snapshot_ref:e,saved_at:new Date().toISOString(),width:t.width,height:t.height,cells:t.cells.map(r=>r.map(o=>[o.text,o.highlight])),highlights:Array.from(t.highlights.entries()),foreground:t.foreground,background:t.background,cursor:{...t.cursor}};try{localStorage.setItem(Cp(e),JSON.stringify(n))}catch{}}function Lp(e,t){try{return e?.schema!=="stem-nvim-grid.v1"||e.snapshot_ref!==t||!Number.isInteger(e.width)||!Number.isInteger(e.height)||e.width<2||e.height<2||e.width>400||e.height>200||e.cells.length!==e.height?null:{width:e.width,height:e.height,cells:e.cells.map(n=>n.map(([r,o])=>({text:typeof r=="string"?r:" ",highlight:Number.isInteger(o)?o:0}))),highlights:new Map(e.highlights),foreground:e.foreground,background:e.background,cursor:e.cursor}}catch{return null}}function Ng(e){try{return Lp(JSON.parse(localStorage.getItem(Cp(e))??"null"),e)}catch{return null}}async function mp(e){let t=e.snapshot_ref;if(!t)return null;let n=Ng(t);if(n)return n;let r=e.view?.recorded_grid_ref;if(!r||/^(?:[a-z]+:|\/\/)/i.test(r))return null;try{let o=await fetch(r,{cache:"no-store"});return o.ok?Lp(await o.json(),t):null}catch{return null}}var Eg=[1842207,12590120,3064446,16106001,1997028,9978299,702940,12631996,6184036,15545147,5759881,16311388,5349887,12607947,5231357,16184820];function go(e){let t=Number(e);if(!Number.isInteger(t)||t<0||t>255)return;if(t<16)return Eg[t];if(t<232){let r=t-16,o=[0,95,135,175,215,255],i=o[Math.floor(r/36)],l=o[Math.floor(r%36/6)],s=o[r%6];return i<<16|l<<8|s}let n=8+(t-232)*10;return n<<16|n<<8|n}function _g(e){if(!e||typeof e!="object")return null;let t=e;return Object.keys(t).length?{...t,foreground:go(t.foreground),background:go(t.background),special:go(t.special)}:null}function Cg(e){if(!e||typeof e!="object")return null;let t=e;return Object.keys(t).length?{...t}:null}function Lg(e,t){for(let n of t){if(!Array.isArray(n)||typeof n[0]!="string")continue;let r=n[0],o=n.slice(1);for(let i of o)if(Array.isArray(i)){if(r==="grid_resize"){let[l,s,u]=i.map(Number);l===1&&kg(e,s,u)}else if(r==="default_colors_set"){let l=Number(i[0]),s=Number(i[1]),u=l>=0?l:go(i[3]),d=s>=0?s:go(i[4]);typeof u=="number"&&Number.isFinite(u)&&u>=0&&(e.foreground=u),typeof d=="number"&&Number.isFinite(d)&&d>=0&&(e.background=d)}else if(r==="hl_attr_define"){let l=Number(i[0]),s=_g(i[2])??Cg(i[1]);Number.isInteger(l)&&s&&typeof s=="object"&&e.highlights.set(l,s)}else if(r==="grid_clear"&&Number(i[0])===1)e.cells=Array.from({length:e.height},()=>Array.from({length:e.width},Wi));else if(r==="grid_cursor_goto"&&Number(i[0])===1)e.cursor={row:Number(i[1]),column:Number(i[2])};else if(r==="grid_line"&&Number(i[0])===1){let l=Number(i[1]),s=Number(i[2]),u=i[3];if(!e.cells[l]||!Array.isArray(u))continue;let d=0;for(let m of u){if(!Array.isArray(m))continue;let y=typeof m[0]=="string"?m[0]:" ";Number.isInteger(m[1])&&(d=Number(m[1]));let g=Number.isInteger(m[2])?Number(m[2]):1;for(let f=0;f=0&&(e.cells[l][s]={text:y,highlight:d}),s+=1}}else if(r==="grid_scroll"&&Number(i[0])===1){let l=Number(i[1]),s=Number(i[2]),u=Number(i[3]),d=Number(i[4]),m=Number(i[5]),y=Number(i[6]),g=e.cells.map(f=>f.map(E=>({...E})));for(let f=l;f=l&&b=u&&_i.text||" ").join(""),r=[],o=0;for(;o=n&&t.cursor.rowR.column-T.column||T.row-R.row):["asm","reg","memory"].includes(C??"")&&k.sort((T,R)=>T.column-R.column||T.row-R.row);let P=k[Math.max(0,Number(d.occurrence??1)-1)];m=P?.row??-1,y=P?.column??-1,f=d.text.length}if(m<0||y<0||m>=t.height||y>=t.width)continue;let E=Math.max(0,Number(d.padding_cells??1)),b=Math.max(0,y-E)*i,_=Math.max(0,m-E)*l,p=Math.min(t.width-y+E,f+E*2)*i,c=Math.min(t.height-m+E,g+E*2)*l,h=s[u.tone??"danger"];if(o.strokeStyle=h,o.lineWidth=2,u.shape==="underline"?(o.beginPath(),o.moveTo(b,_+c-2),o.lineTo(b+p,_+c-2),o.stroke()):o.strokeRect(b+1,_+1,Math.max(1,p-2),Math.max(1,c-2)),u.label){o.font="700 10px system-ui, sans-serif";let k=o.measureText(u.label).width+8;o.fillStyle=h,o.fillRect(b+1,Math.max(0,_-15),k,14),o.fillStyle="#fff",o.fillText(u.label,b+5,Math.max(10,_-4))}}}function Tg(e){if(e.nativeEvent.isComposing||e.metaKey)return null;let n={Enter:"CR",Escape:"Esc",Backspace:"BS",Delete:"Del",Tab:"Tab",ArrowLeft:"Left",ArrowRight:"Right",ArrowUp:"Up",ArrowDown:"Down",Home:"Home",End:"End",PageUp:"PageUp",PageDown:"PageDown",Insert:"Insert"}[e.key]??(/^F\d{1,2}$/.test(e.key)?e.key:null),r=[e.ctrlKey?"C":"",e.altKey?"M":"",e.shiftKey&&n?"S":""].filter(Boolean).join("-");return n?`<${r?`${r}-`:""}${n}>`:e.key.length!==1?null:e.ctrlKey||e.altKey?`<${r}-${e.key==="<"?"lt":e.key}>`:e.key==="<"?"":e.key}function Mg({visible:e,syncMode:t,controlMode:n,expanded:r,fit:o,scale:i,onSummaryChange:l}){let s=(0,N.useRef)(null),u=(0,N.useRef)(null),d=(0,N.useRef)(null),m=(0,N.useRef)(0),y=(0,N.useRef)(0),g=(0,N.useRef)(0),f=(0,N.useRef)(pp()),E=(0,N.useRef)(null),b=(0,N.useRef)(null),_=(0,N.useRef)(null),p=(0,N.useRef)(0),c=(0,N.useRef)(null),h=(0,N.useRef)(null),[k,C]=(0,N.useState)(null),[P,T]=(0,N.useState)(!1),[R,j]=(0,N.useState)(0),[I,ke]=(0,N.useState)(!1),[re,G]=(0,N.useState)(()=>{let A=Number(localStorage.getItem("stem-card-nvim-height-vh"));return Number.isFinite(A)&&A>=25&&A<=90?A:75}),[U,Le]=(0,N.useState)({state:"hidden"}),[Ne,Q]=(0,N.useState)({state:"idle"}),et=Ne.state==="replaying"||Ne.state==="verifying",Ge=t&&U.state==="connected"&&!et,je=n&&I&&U.state==="connected"&&!et,me=()=>{s.current&&Pg(s.current,f.current,_.current===b.current?.step.snapshot_ref?b.current?.step.view?.annotations??[]:[])},Dn=()=>{m.current||(m.current=window.requestAnimationFrame(()=>{m.current=0,me()}))};if((0,N.useEffect)(()=>{let A=F=>{let B=F.detail;b.current=B,C(B),_.current=null;let te=B.step.snapshot_ref;if(U.state!=="connected"&&te&&mp(B.step).then(ie=>{!ie||b.current?.step.snapshot_ref!==te||(f.current=ie,T(!0),_.current=te,Q({state:"idle",snapshot_ref:te,message:"Pokazano ostatni zapisany, zweryfikowany ekran."}),me())}),me(),!B.activate)return;let at=B.step.mode??"RUN",zt=async()=>{if(!B.step.code_ref)return null;let ie=await fetch("/api/nvim/open",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({code_ref:B.step.code_ref,actor:document.documentElement.dataset.cardClientId??"browser"})}),q=await ie.json().catch(()=>({}));if(!ie.ok)throw new Error(q.message??q.error??`HTTP ${ie.status}`);return q};if(at==="CODE"||!te){zt().then(()=>{Q({state:"ready",phase:"code",message:B.step.code_ref?`Otwarto ${B.step.code_ref}; program nie zosta\u0142 zrestartowany.`:"Krok CODE nie ma przypisanego code_ref."})}).catch(ie=>{Q({state:"failed",phase:"code",message:ie instanceof Error?ie.message:String(ie)})});return}if(!e||U.state!=="connected"){Q({state:"failed",snapshot_ref:te,message:"Cel jest offline; pozostaje zapisany wynik tego kroku."});return}let Ee=zt(),ne=Math.max(p.current+1,Date.now());p.current=ne,c.current?.abort();let st=new AbortController;c.current=st,Q({state:"replaying",phase:"dispatch",generation:ne,snapshot_ref:te,message:"Resetuj\u0119 cel i odtwarzam wykonanie do wybranego kroku."});let Ye=0,wn=async()=>{try{let ie=await fetch("/api/checkpoint/status",{cache:"no-store",signal:st.signal});if(!ie.ok)return;let q=await ie.json(),bt=q.active?.generation===ne?q.active:null;if(!bt||p.current!==ne)return;Q({state:bt.phase==="verify"?"verifying":"replaying",phase:bt.phase,generation:ne,snapshot_ref:te,message:bt.message})}catch{}};Ye=window.setInterval(wn,120),wn(),Ee.then(()=>fetch("/api/checkpoint/activate",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({snapshot_ref:te,generation:ne}),signal:st.signal})).then(async ie=>{let q=await ie.json();if(p.current!==ne)return;if(!ie.ok||q.status!=="ready")throw new Error(q.message??`Replay zako\u0144czy\u0142 si\u0119 kodem HTTP ${ie.status}.`);let bt=d.current;if(bt?.readyState!==WebSocket.OPEN)throw new Error("Replay zako\u0144czony, ale most Neovima jest offline.");let fe=y.current;bt.send(JSON.stringify({type:"refresh"}));let Qt=Date.now()+1800;for(;y.current<=fe&&Date.now()window.setTimeout(qt,20));if(y.current<=fe)throw new Error("Neovim nie potwierdzi\u0142 pe\u0142nego redraw po replay.");if(p.current!==ne)return;_.current=te,Q({state:"ready",phase:q.phase,generation:ne,snapshot_ref:te,message:q.message??"Stan maszyny zosta\u0142 odtworzony i zweryfikowany."}),Sg(te,f.current),me(),await new Promise(qt=>window.requestAnimationFrame(()=>qt()));let jn=s.current;if(jn&&b.current?.step.snapshot_ref===te)try{fetch("/api/evidence",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({actor:document.documentElement.dataset.cardClientId??"browser",snapshot_ref:te,event_id:B.step.event_id??null,strategy_ref:B.step.strategy_ref??null,code_ref:B.step.code_ref??null,caption:`${String(B.step.number).padStart(2,"0")} ${B.step.label}`,data_url:jn.toDataURL("image/png")})}).catch(()=>{})}catch{}}).catch(ie=>{st.signal.aborted||p.current!==ne||(mp(B.step).then(q=>{!q||b.current?.step.snapshot_ref!==te||(f.current=q,T(!0),_.current=te,me())}),Q({state:"failed",generation:ne,snapshot_ref:te,message:ie instanceof Error?ie.message:String(ie)}))}).finally(()=>{window.clearInterval(Ye),c.current===st&&(c.current=null)})};return window.addEventListener("stem:nvim-step",A),()=>{window.removeEventListener("stem:nvim-step",A),c.current?.abort()}},[U.state,e]),(0,N.useEffect)(()=>{localStorage.setItem("stem-card-nvim-height-vh",re.toFixed(2))},[re]),(0,N.useEffect)(()=>{let A=window.requestAnimationFrame(me);return()=>window.cancelAnimationFrame(A)},[r,o,i]),(0,N.useEffect)(()=>{let A=()=>{let F=d.current;F?.readyState===WebSocket.OPEN&&F.send(JSON.stringify({type:"refresh"})),me()};return window.addEventListener("stem:nvim-refresh",A),()=>window.removeEventListener("stem:nvim-refresh",A)},[]),(0,N.useEffect)(()=>{let A=U.state;U.state==="connected"&&(A=Ne.state==="idle"?"connected":Ne.state),l({state:A,message:Ne.message??U.message,instance:U.target?.instance??U.target?.container_name,detail:[U.target?.profile??k?.step.view?.connection_ref,k?`${String(k.step.number).padStart(2,"0")} ${k.step.label}`:void 0,Ne.phase].filter(Boolean).join(" \xB7 "),syncMode:t,syncReady:Ge,controlMode:n,controlEnabled:je,screenCursor:{...f.current.cursor},grid:{columns:f.current.width,rows:f.current.height}})},[k,Ne,je,n,R,l,U,t,Ge]),(0,N.useEffect)(()=>()=>window.clearTimeout(g.current),[]),(0,N.useEffect)(()=>{if(!je)return;let A=F=>{let B=d.current;if(B?.readyState!==WebSocket.OPEN)return;if(F.altKey&&!F.ctrlKey&&!F.metaKey&&F.key.toLowerCase()==="w"){F.preventDefault(),F.stopImmediatePropagation(),F.repeat||B.send(JSON.stringify({type:"input",keys:""}));return}let te={ArrowLeft:"h",ArrowDown:"j",ArrowUp:"k",ArrowRight:"l"};F.altKey&&!F.ctrlKey&&!F.metaKey&&te[F.key]&&(F.preventDefault(),F.stopImmediatePropagation(),F.repeat||B.send(JSON.stringify({type:"input",keys:`${te[F.key]}`})))};return window.addEventListener("keydown",A,!0),()=>window.removeEventListener("keydown",A,!0)},[je]),(0,N.useEffect)(()=>{if(!e||!t){d.current?.close(),d.current=null,ke(!1),Le(e?{state:"offline",message:"SYNC OFF: pokazuj\u0119 zapisany ekran bez po\u0142\u0105czenia z kontenerem."}:{state:"hidden"});return}let A=!1,F=0,B=()=>{if(A)return;let te=window.location.protocol==="https:"?"wss:":"ws:",at=new WebSocket(`${te}//${window.location.host}/api/nvim-ui`);d.current=at,Le({state:"connecting"}),at.addEventListener("message",zt=>{try{let Ee=JSON.parse(String(zt.data));if(Ee.type==="status"){typeof Ee.epoch=="string"&&E.current&&E.current!==Ee.epoch&&(f.current=pp(),T(!1),_.current=null),typeof Ee.epoch=="string"&&(E.current=Ee.epoch),Le(Ee);return}Ee.type==="redraw"&&Array.isArray(Ee.events)&&(Lg(f.current,Ee.events),f.current.width>1&&f.current.height>1&&T(!0),Ee.events.some(ne=>Array.isArray(ne)&&ne[0]==="flush")&&(y.current+=1,Dn(),g.current||(g.current=window.setTimeout(()=>{g.current=0,j(ne=>ne+1)},120))))}catch{}}),at.addEventListener("close",()=>{d.current===at&&(d.current=null),A||(F=window.setTimeout(B,1200))}),at.addEventListener("error",()=>{Le(zt=>({...zt,state:"offline",message:"Most Neovima jest chwilowo niedost\u0119pny."}))})};return B(),()=>{A=!0,window.clearTimeout(F),window.cancelAnimationFrame(m.current),m.current=0,d.current?.close(),d.current=null}},[t,e]),!e)return null;let xe=A=>{let F=d.current;F?.readyState===WebSocket.OPEN&&F.send(JSON.stringify(A))},bn=A=>{let F=A.currentTarget.getBoundingClientRect();return{row:Math.max(0,Math.min(f.current.height-1,Math.floor((A.clientY-F.top)/F.height*f.current.height))),column:Math.max(0,Math.min(f.current.width-1,Math.floor((A.clientX-F.left)/F.width*f.current.width)))}},se=A=>[A.shiftKey?"S":"",A.ctrlKey?"C":"",A.altKey?"A":""].filter(Boolean).join("-");return(0,a.jsxs)("section",{className:"nvim-panel","aria-label":"Neovim po\u0142\u0105czony z kontenerem",onWheel:A=>{A.stopPropagation();let F=A.target;(!(F instanceof Element)||!F.closest(".nvim-screen-scroll"))&&A.preventDefault()},children:[(0,a.jsxs)("div",{ref:u,className:"nvim-screen-scroll",style:o?void 0:{height:`${r?90:re}vh`},"data-sync":t?"on":"off","data-control":je?"true":"false",tabIndex:0,onPointerEnter:A=>{ke(!0),A.currentTarget.focus({preventScroll:!0})},onPointerLeave:A=>{ke(!1),A.currentTarget.blur()},onMouseDown:A=>A.currentTarget.focus({preventScroll:!0}),onKeyDown:A=>{if(!je)return;let F=Tg(A);F&&(A.preventDefault(),A.stopPropagation(),xe({type:"input",keys:F}))},children:[(0,a.jsx)("div",{className:"nvim-screen-stage",style:o?void 0:{height:`${(r?90:re)/Math.max(i,.25)}vh`},children:(0,a.jsx)("div",{className:"nvim-screen-surface",children:(0,a.jsx)("div",{className:"nvim-screen-frame",children:(0,a.jsx)("div",{className:"nvim-screen-content",children:(0,a.jsx)("div",{className:"nvim-screen-grid",children:(0,a.jsx)("canvas",{ref:s,className:"nvim-screen",tabIndex:-1,"aria-label":je?"Interaktywny ekran Neovima":"Ekran Neovima",onMouseDown:A=>{if(!je||U.state!=="connected")return;A.preventDefault();let F=bn(A),B=A.button===1?"middle":A.button===2?"right":"left";xe({type:"mouse",button:B,action:"press",modifier:se(A),...F})},onMouseUp:A=>{if(!je||U.state!=="connected")return;A.preventDefault();let F=bn(A),B=A.button===1?"middle":A.button===2?"right":"left";xe({type:"mouse",button:B,action:"release",modifier:se(A),...F})},onWheel:A=>{if(!je||U.state!=="connected")return;A.preventDefault();let F=bn(A);xe({type:"mouse",button:"wheel",action:A.deltaY<0?"up":"down",modifier:se(A),...F})},onContextMenu:A=>je&&A.preventDefault()})})})})})}),!P&&(0,a.jsxs)("div",{className:"nvim-screen-empty",children:[(0,a.jsx)("strong",{children:wp[U.state]}),(0,a.jsx)("span",{children:U.message??"Oczekiwanie na ekran Neovima lub zapisany stan kroku."})]})]}),(0,a.jsx)("div",{className:"nvim-resize-handle",role:"separator","aria-label":"Zmie\u0144 wysoko\u015B\u0107 panelu Neovima","aria-orientation":"horizontal","aria-valuemin":25,"aria-valuemax":90,"aria-valuenow":Math.round(re),tabIndex:0,title:"Przeci\u0105gnij, aby zmieni\u0107 wysoko\u015B\u0107. Dwuklik: 75%.",onPointerDown:A=>{A.preventDefault(),h.current={y:A.clientY,heightVh:re},A.currentTarget.setPointerCapture(A.pointerId)},onPointerMove:A=>{let F=h.current;if(!F)return;let B=(A.clientY-F.y)/window.innerHeight*100;G(Math.max(25,Math.min(90,F.heightVh+B)))},onPointerUp:A=>{h.current=null,A.currentTarget.hasPointerCapture(A.pointerId)&&A.currentTarget.releasePointerCapture(A.pointerId)},onPointerCancel:()=>{h.current=null},onDoubleClick:()=>G(75),onKeyDown:A=>{if(A.key==="ArrowUp"||A.key==="ArrowDown"){A.preventDefault();let F=A.key==="ArrowUp"?-2:2;G(B=>Math.max(25,Math.min(90,B+F)))}else A.key==="Home"&&(A.preventDefault(),G(75))}})]})}function Rg({column:e,row:t}){return e==="chapter"||e==="task"||e==="version"?(0,a.jsx)("td",{children:(0,a.jsx)("code",{children:t[e]})}):e==="idea"?(0,a.jsx)("td",{dangerouslySetInnerHTML:{__html:t.idea_html}}):e==="status"?(0,a.jsx)("td",{children:(0,a.jsx)("span",{className:"scope-status","data-status":t.status,title:t.status,children:t.status_label})}):(0,a.jsx)("td",{children:t[e]})}function Og({front:e}){let t=e.scope_columns??["chapter","task","idea","priority"];return(0,a.jsxs)(ys,{header:e.header_html,left:e.left_margin_html,right:e.right_margin_html,className:"front-sheet",children:[(0,a.jsxs)("section",{className:"front-scope front-goal",children:[(0,a.jsx)("h2",{children:e.goal_title}),(0,a.jsx)(Yt,{html:e.goal_html})]}),(0,a.jsxs)("section",{className:"front-scope front-card-scope",children:[(0,a.jsx)("h2",{children:e.scope_title}),e.scope_html&&(0,a.jsx)(Yt,{html:e.scope_html}),(0,a.jsx)("div",{className:"scope-table-wrap",children:(0,a.jsxs)("table",{className:"scope-table scope-table--task",children:[(0,a.jsx)("thead",{children:(0,a.jsx)("tr",{children:e.scope_headers.map(n=>(0,a.jsx)("th",{children:n},n))})}),(0,a.jsx)("tbody",{children:e.scope_rows.map(n=>(0,a.jsx)("tr",{className:n.key?"scope-row--key":"",children:t.map(r=>(0,a.jsx)(Rg,{column:r,row:n},r))},`${n.chapter}-${n.task}`))})]})})]})]})}function $g({taskRef:e,step:t}){return(0,a.jsxs)("li",{id:`${e}-${t.id}`,children:[(0,a.jsx)("strong",{children:t.title}),(0,a.jsx)(Yt,{html:t.content_html})]})}function Ig({taskRef:e,block:t}){let n=t.kind==="exercise"?"\u0106wiczenie":"Block";return(0,a.jsxs)("section",{className:`task-block task-block--${t.kind}`,id:`${e}-${t.id}`,"data-stem-nav":"block",children:[(0,a.jsxs)("header",{children:[(0,a.jsx)("span",{children:n}),(0,a.jsx)("h4",{children:t.title})]}),(0,a.jsx)(Yt,{html:t.content_html}),t.steps.length>0&&(0,a.jsx)("ol",{className:"block-steps",children:t.steps.map(r=>(0,a.jsx)($g,{taskRef:e,step:r},r.id))})]})}function Fg({task:e}){return e.flow.length?(0,a.jsxs)("article",{className:"task-flow",id:e.ref,"data-stem-nav":"task",children:[(0,a.jsxs)("header",{className:"task-flow-header",children:[(0,a.jsx)("span",{children:e.ref.toUpperCase()}),(0,a.jsx)("h3",{children:e.title}),e.uuid&&(0,a.jsx)("code",{children:e.uuid})]}),e.flow.map(t=>(0,a.jsx)(Ig,{taskRef:e.ref,block:t},t.id)),(0,a.jsxs)("footer",{children:[(0,a.jsx)("strong",{children:"Task acceptance:"})," ",e.criterion]})]}):(0,a.jsxs)("article",{className:"task-legacy",id:e.ref,"data-stem-nav":"task",children:[(0,a.jsx)("strong",{children:e.ref.toUpperCase()}),(0,a.jsx)(Yt,{html:e.prompt_html??""}),(0,a.jsxs)("footer",{children:[(0,a.jsx)("strong",{children:"Task acceptance:"})," ",e.criterion]})]})}var fp={compile:"KOMPILACJA",bss:".BSS",stack:"STOS",registers:"REJESTRY",text:".TEXT"},gp=["#9bcfe2","#c4dfc0","#f4c889","#d2b6dc"];function Dg({config:e,title:t}){let n=e.arena_size??64,r=e.allocations??[5,7],o=e.symbols??[],i=`${e.storage_key??"allocator-memory-flow"}-stage`,[l,s]=(0,N.useState)(()=>Math.min(r.length,Number(localStorage.getItem(i)??0))),[u,d]=(0,N.useState)(o[0]?.id??"");(0,N.useEffect)(()=>localStorage.setItem(i,String(l)),[l,i]);let m=r.slice(0,l).reduce((_,p)=>_+p,0),y=o.find(_=>_.id===u)??o[0],g=Array.from({length:n},(_,p)=>p),f=_=>{let p=0;for(let c=0;co.some(p=>p.area===_));return(0,a.jsxs)("div",{className:"memory-react","aria-label":`Interaktywny diagram: ${t}`,children:[(0,a.jsxs)("header",{children:[(0,a.jsxs)("div",{children:[(0,a.jsx)("small",{children:"INTERAKTYWNY MODEL PAMI\u0118CI"}),(0,a.jsx)("h3",{children:t})]}),(0,a.jsxs)("div",{className:"memory-actions",children:[(0,a.jsx)("button",{"aria-pressed":l===0,onClick:()=>s(0),children:"definicje / reset"}),r.map((_,p)=>(0,a.jsxs)("button",{"aria-pressed":l===p+1,onClick:()=>s(p+1),children:["alloc(",_,")"]},`${_}-${p}`))]})]}),(0,a.jsx)("div",{className:"memory-lanes",children:b.map(_=>(0,a.jsxs)("section",{className:`memory-lane ${_}`,children:[(0,a.jsx)("b",{children:fp[_]}),o.filter(p=>p.area===_).map(p=>(0,a.jsx)("button",{className:u===p.id?"active":"",onClick:()=>d(p.id),children:(0,a.jsx)("code",{children:p.declaration})},p.id))]},_))}),(0,a.jsxs)("div",{className:"arena-wrap",children:[(0,a.jsxs)("div",{className:"arena-label",children:[(0,a.jsxs)("code",{children:["allocbuf[",n,"]"]}),(0,a.jsxs)("span",{children:["u\u017Cyte ",m," B / wolne ",n-m," B"]})]}),(0,a.jsxs)("div",{className:"arena",style:{"--allocp":m,"--arena-size":n},children:[g.map(_=>{let p=f(_);return(0,a.jsx)("i",{style:p>=0?{background:gp[p%gp.length]}:void 0},_)}),(0,a.jsxs)("span",{className:"allocp",children:["allocp \u2191 ",m]})]})]}),(0,a.jsxs)("p",{className:"memory-stage",children:[(0,a.jsxs)("strong",{children:[l+1,"/",r.length+1]})," ",(0,a.jsx)("code",{children:E})]}),y&&(0,a.jsxs)("aside",{className:"memory-inspector",children:[(0,a.jsx)("strong",{children:y.id}),(0,a.jsx)("code",{children:y.declaration}),(0,a.jsx)("span",{children:y.description})]})]})}function jg({config:e,asset:t,progress:n,onSetStatus:r}){let o=e.stages??[],i=`${e.storage_key??t.label}-uml-stage`,l=(0,N.useRef)(null),[s,u]=(0,N.useState)(""),[d,m]=(0,N.useState)(!1),[y,g]=(0,N.useState)(!1),[f,E]=(0,N.useState)(()=>Math.max(0,Math.min(o.length-1,Number(localStorage.getItem(i)??0))));(0,N.useEffect)(()=>localStorage.setItem(i,String(f)),[f,i]),(0,N.useEffect)(()=>{let c=!0;return m(!1),fetch(t.href,{cache:"no-store"}).then(h=>{if(!h.ok)throw new Error(`HTTP ${h.status}`);return h.text()}).then(h=>{let k=new DOMParser().parseFromString(h,"image/svg+xml"),C=k.documentElement;if(C.nodeName.toLowerCase()!=="svg"||k.querySelector("parsererror"))throw new Error("Niepoprawny SVG");k.querySelectorAll("script, foreignObject").forEach(P=>P.remove()),Np(C,t.tile),c&&u(C.outerHTML)}).catch(()=>{c&&m(!0)}),()=>{c=!1}},[t.href,t.tile]),(0,N.useEffect)(()=>{let c=l.current?.querySelector("svg");if(!c)return;c.setAttribute("role","img"),c.setAttribute("aria-label",t.alt),c.querySelectorAll("[data-uml-stage]").forEach(C=>{C.classList.remove("uml-stage-region","uml-stage-region-bg","uml-stage-region-outline","uml-stage-region-active","uml-stage-region-completed"),C.removeAttribute("data-uml-stage"),C.removeAttribute("data-uml-stage-label"),C.removeAttribute("role"),C.removeAttribute("tabindex"),C.removeAttribute("aria-label")});let h=Array.from(c.querySelectorAll("text")),k=Array.from(c.querySelectorAll("rect"));o.forEach((C,P)=>{if(!C.svg_label)return;let T=h.find(G=>(G.textContent??"").trim().startsWith(C.svg_label)),R=Number(T?.getAttribute("y"));if(!T||!Number.isFinite(R))return;let j=k.map(G=>{let U=Number(G.getAttribute("y")),Le=Number(G.getAttribute("height")),Ne=Number(G.getAttribute("width")),Q=G.getAttribute("style")??"",et=Number(Q.match(/stroke-width:\s*([\d.]+)/)?.[1]??G.getAttribute("stroke-width")??0);return{rect:G,y:U,height:Le,width:Ne,strokeWidth:et,area:Ne*Le}}).filter(({y:G,height:U,width:Le,strokeWidth:Ne})=>Number.isFinite(G)&&Number.isFinite(U)&&Number.isFinite(Le)&&Ne>=2&&G<=R&&G+U>=R).sort((G,U)=>G.area-U.area),I=j[0];if(!I)return;let ke=j.filter(({y:G,height:U,width:Le})=>Math.abs(G-I.y)<.1&&Math.abs(U-I.height)<.1&&Math.abs(Le-I.width)<.1),re=!!(C.progress_id&&n?.items?.[C.progress_id]?.status==="approved");ke.forEach(({rect:G},U)=>{let Le=G.getAttribute("fill")!=="none";G.dataset.umlStage=String(P),G.dataset.umlStageLabel=C.label,G.classList.add("uml-stage-region",Le?"uml-stage-region-bg":"uml-stage-region-outline"),G.classList.toggle("uml-stage-region-active",P===f),G.classList.toggle("uml-stage-region-completed",re),U===0&&(G.setAttribute("role","button"),G.setAttribute("tabindex","0"),G.setAttribute("aria-label",`Poka\u017C etap ${C.label}`))})})},[t.alt,n,f,o,s]);let b=(c,h)=>{let k=l.current?.querySelector("svg");if(!k)return;let C=Array.from(k.querySelectorAll(".uml-stage-region-bg[data-uml-stage]")).filter(T=>{let R=T.getBoundingClientRect();return c>=R.left&&c<=R.right&&h>=R.top&&h<=R.bottom}).sort((T,R)=>{let j=T.getBoundingClientRect(),I=R.getBoundingClientRect();return j.width*j.height-I.width*I.height})[0],P=Number(C?.dataset.umlStage);Number.isInteger(P)&&E(P)},_=c=>{if(c.key!=="Enter"&&c.key!==" ")return;let h=c.target,k=Number(h.dataset?.umlStage);Number.isInteger(k)&&(c.preventDefault(),E(k))},p=o[f];return(0,a.jsxs)("div",{className:"uml-react",children:[(0,a.jsxs)("header",{children:[(0,a.jsxs)("div",{children:[(0,a.jsx)("small",{children:"KANONICZNY DIAGRAM UML \xB7 PLANTUML"}),(0,a.jsx)("h3",{children:"Reset i dwa przydzia\u0142y liniowe"})]}),(0,a.jsx)("div",{className:"uml-actions",children:o.map((c,h)=>(0,a.jsxs)("button",{"aria-pressed":f===h,"data-completed":c.progress_id&&n?.items?.[c.progress_id]?.status==="approved"?"true":"false",onClick:()=>E(h),children:[c.progress_id&&n?.items?.[c.progress_id]?.status==="approved"&&(0,a.jsx)("span",{"aria-hidden":"true",children:"\u2713 "}),c.label]},c.id))})]}),(0,a.jsxs)("div",{ref:l,className:"uml-canvas",onClick:c=>b(c.clientX,c.clientY),onKeyDown:_,children:[s?(0,a.jsx)("div",{className:`uml-svg-host${t.tile?" is-tiled":""}`,style:hs(t.tile),dangerouslySetInnerHTML:{__html:s}}):(0,a.jsx)("img",{src:t.href,alt:t.alt}),d&&(0,a.jsx)("span",{className:"uml-inline-warning",children:"Widok statyczny \u2014 nie uda\u0142o si\u0119 wczyta\u0107 interaktywnego SVG."})]}),p&&(0,a.jsxs)("aside",{className:"uml-stage",children:[(0,a.jsx)("strong",{children:p.label}),(0,a.jsx)("span",{children:p.description}),p.code_ref&&(0,a.jsx)("code",{children:p.code_ref})]}),p?.progress_id&&(0,a.jsxs)("footer",{className:"uml-approval",children:[(0,a.jsx)("span",{children:n?.items?.[p.progress_id]?.status==="approved"?"Ten stan jest zatwierdzony i zapisany w JSON-ie zaj\u0119\u0107.":"Kursor wybiera stan; zatwierdzenie zapisuje go w JSON-ie zaj\u0119\u0107."}),(0,a.jsx)("button",{disabled:!n||y,onClick:async()=>{if(!p.progress_id||!n)return;let c=n.items?.[p.progress_id]?.status==="approved";g(!0);try{await r(p.progress_id,c?"pending":"approved")}finally{g(!1)}},children:y?"Zapisywanie\u2026":n?.items?.[p.progress_id]?.status==="approved"?"Cofnij zatwierdzenie":"Zatwierd\u017A stan"})]})]})}function Ug({config:e,asset:t,progress:n,onSetStatus:r,continuation:o}){let i=e.phases??[],l=i.flatMap(x=>x.steps.map(S=>({phase:x,step:S}))),s=`${e.storage_key??t.label}-uml-step`,u=`${e.storage_key??t.label}-navigation-level`,d=(0,N.useRef)(null),m=(0,N.useRef)(null),y=(0,N.useRef)(new Map),g=(0,N.useRef)(null),f=(0,N.useRef)(0),E=(0,N.useRef)(!1),b=(0,N.useRef)(null),_=(0,N.useRef)(!0),[p,c]=(0,N.useState)(""),[h,k]=(0,N.useState)(!1),[C,P]=(0,N.useState)(!1),[T,R]=(0,N.useState)(null),[j,I]=(0,N.useState)(null),[ke,re]=(0,N.useState)(!1),[G,U]=(0,N.useState)(""),[Le,Ne]=(0,N.useState)(!1),[Q,et]=(0,N.useState)(null),[Ge,je]=(0,N.useState)([]),[me,Dn]=(0,N.useState)(0),[xe,bn]=(0,N.useState)(()=>Math.max(0,Math.min(l.length-1,Number(localStorage.getItem(s)??0)))),[se,A]=(0,N.useState)(()=>{let x=localStorage.getItem(u);return x==="card"||x==="task"||x==="block"||x==="phase"||x==="step"||x==="snapshot"?x:"step"});(0,N.useEffect)(()=>localStorage.setItem(s,String(xe)),[xe,s]),(0,N.useEffect)(()=>localStorage.setItem(u,se),[se,u]),(0,N.useEffect)(()=>{let x=!0;return k(!1),fetch(t.href,{cache:"no-store"}).then(S=>{if(!S.ok)throw new Error(`HTTP ${S.status}`);return S.text()}).then(S=>{let M=new DOMParser().parseFromString(S,"image/svg+xml"),O=M.documentElement;if(O.nodeName.toLowerCase()!=="svg"||M.querySelector("parsererror"))throw new Error("Niepoprawny SVG");M.querySelectorAll("script, foreignObject").forEach(v=>v.remove()),Np(O,t.tile),x&&c(O.outerHTML)}).catch(()=>{x&&k(!0)}),()=>{x=!1}},[t.href,t.tile]),(0,N.useEffect)(()=>{let x=!0,S=fs(t,e);if(U("Wczytywanie uk\u0142adu\u2026"),Ne(!1),!t.source_href)return R(S),I(S),U("Brak \u017Ar\xF3d\u0142a PlantUML \u2014 zapis wy\u0142\u0105czony."),()=>{x=!1};let M=t.source_href.replace(/\.puml(?:\?.*)?$/,".layout.json");return fetch(`/api/uml-layout?source=${encodeURIComponent(t.source_href)}`,{cache:"no-store"}).then(async O=>{if(!O.ok)throw new Error(`HTTP ${O.status}`);return O.json()}).catch(async()=>{let O=await fetch(M,{cache:"no-store"});return O.ok?{layout:await O.json(),source_digest:"",stale:!1}:{layout:null,source_digest:"",stale:!1}}).then(O=>{if(!x)return;let v=O.layout??fs(t,e,O.source_digest??"");R(v),I(v),re(!1),Ne(!!O.stale),U(O.layout?"Uk\u0142ad wczytany z JSON.":"Uk\u0142ad PlantUML \u2014 brak r\u0119cznych zmian.")}).catch(O=>{x&&(R(S),I(S),U(`Nie wczytano uk\u0142adu: ${O instanceof Error?O.message:String(O)}`))}),()=>{x=!1}},[t.source_href,t.label,e.block?.id,e.task?.id]),(0,N.useEffect)(()=>{let x=m.current?.querySelector("svg");if(!x||!j)return;fg(x);let S=new Map(l.map(({step:L})=>[String(L.number).padStart(2,"0"),L.id])),M=gg(x,S),O=new Map(M.map(L=>[L.id,L]));y.current=O;let v=M.map(L=>L.id);je(L=>L.join("\0")===v.join("\0")?L:v),M.forEach(L=>{let H=j.elements[L.id];H&&hg(L,H)});let w=x.viewBox.baseVal;(j.canvas.width<=0||j.canvas.height<=0)&&I(L=>L&&{...L,canvas:{...L.canvas,width:w?.width||Number(x.getAttribute("width")?.replace("px",""))||0,height:w?.height||Number(x.getAttribute("height")?.replace("px",""))||0}})},[l,p,j]),(0,N.useEffect)(()=>{let x=m.current?.querySelector("svg");if(!x)return;let S=e.kind==="uml-class"&&x.contains(document.activeElement);x.setAttribute("role","img"),x.setAttribute("aria-label",t.alt),x.classList.toggle("uml-class-svg",e.kind==="uml-class"),x.classList.toggle("uml-class-svg-active",e.kind==="uml-class"&&se!=="card"),x.querySelectorAll(".uml-step-hit, .uml-class-focus-region").forEach(K=>K.remove()),x.querySelectorAll("[data-uml-step-element]").forEach(K=>{K.classList.remove("uml-step-element","uml-step-element-active","uml-step-element-completed","uml-step-element-tone-a","uml-step-element-tone-b"),K.removeAttribute("data-uml-step-element"),K.removeAttribute("data-uml-step-claim-area")});let M=Array.from(x.querySelectorAll("text")),O=Array.from(x.querySelectorAll("line")),v=Array.from(x.querySelectorAll("polygon"));if(e.kind==="uml-class"){let K=V=>V?mg(V):null,X=V=>{if(!V.length)return null;let oe=Math.min(...V.map(J=>J.x)),ct=Math.min(...V.map(J=>J.y)),Ue=Math.max(...V.map(J=>J.x+J.width)),ue=Math.max(...V.map(J=>J.y+J.height));return{x:oe,y:ct,width:Ue-oe,height:ue-ct}},D=Array.from(x.querySelectorAll("g > *")),Z=Array.from(x.querySelectorAll("[id]"));l.forEach(({step:V},oe)=>{let ct=V.svg_label??String(V.number).padStart(2,"0"),Ue=M.find(ge=>(ge.textContent??"").trim().startsWith(ct));if(!Ue)return;let ue=K(Ue);if(!ue)return;let J=Number(Ue.getAttribute("y")),Re=M.filter(ge=>Number.isFinite(J)&&Math.abs(Number(ge.getAttribute("y"))-J)<.8),Ve=V.svg_target?Z.find(ge=>ge.id===V.svg_target||ge.id.startsWith(`${V.svg_target}-`))??null:null,dt=K(Ve)??X(Re.map(ge=>K(ge)).filter(ge=>ge!==null))??ue,vr=Ve?.tagName.toLowerCase()==="rect",vs=Ve?[Ve,Ue]:Re;vr&&D.forEach(ge=>{let Xt=K(ge);if(!Xt||ge===Ve)return;let bs=Xt.x+Xt.width/2,ws=Xt.y+Xt.height/2;bs>=dt.x&&bs<=dt.x+dt.width&&ws>=dt.y&&ws<=dt.y+dt.height&&vs.push(ge)});let Ap=!!(V.progress_id&&n?.items?.[V.progress_id]?.status==="approved"),xs=Math.max(1,dt.width*dt.height);vs.forEach(ge=>{let Xt=Number(ge.dataset.umlStepClaimArea);Number.isFinite(Xt)&&Xt{let D=K.svg_label??String(K.number).padStart(2,"0"),Z=M.find(J=>(J.textContent??"").trim()===D),V=Number(Z?.getAttribute("y"));if(!Z||!Number.isFinite(V))return;let oe=V+5,ct=!!(K.progress_id&&n?.items?.[K.progress_id]?.status==="approved"),Ue=M.filter(J=>Math.abs(Number(J.getAttribute("y"))-V)<.8);Ue.push(...O.filter(J=>{let Re=Number(J.getAttribute("y1")),Ve=Number(J.getAttribute("y2"));return Number.isFinite(Re)&&Number.isFinite(Ve)&&Math.abs(Re-Ve)<.8&&Math.abs((Re+Ve)/2-oe)<=14})),Ue.push(...v.filter(J=>{let Re=(J.getAttribute("points")??"").trim().split(/\s+/).map(vr=>Number(vr.split(",")[1])).filter(Number.isFinite);if(!Re.length)return!1;let Ve=Math.min(...Re),dt=Math.max(...Re);return dt-Ve<=16&&Math.abs((Ve+dt)/2-oe)<=14})),Ue.forEach(J=>{J.dataset.umlStepElement=String(X),J.classList.add("uml-step-element"),J.classList.toggle("uml-step-element-active",X===xe),J.classList.toggle("uml-step-element-completed",ct)});let ue=document.createElementNS("http://www.w3.org/2000/svg","rect");ue.setAttribute("x",String(L)),ue.setAttribute("y",String(V-12)),ue.setAttribute("width",String(H)),ue.setAttribute("height","31"),ue.setAttribute("fill","transparent"),ue.setAttribute("pointer-events","all"),ue.setAttribute("role","button"),ue.setAttribute("tabindex","0"),ue.setAttribute("aria-label",`Poka\u017C krok ${String(K.number).padStart(2,"0")}: ${K.label}`),ue.dataset.umlStep=String(X),ue.classList.add("uml-step-hit"),ue.classList.toggle("uml-step-hit-active",se!=="card"&&X===xe),ue.classList.toggle("uml-step-hit-completed",ct),x.appendChild(ue)})},[t.alt,e.kind,l,se,n,xe,p,j]),(0,N.useEffect)(()=>{let x=m.current?.querySelector("svg");if(x&&(x.querySelectorAll(".uml-layout-hit,.uml-layout-resize").forEach(S=>S.remove()),x.classList.toggle("uml-layout-editing",C),!(!C||!j)))for(let S of y.current.values()){let M=j.elements[S.id]??po(S),O=document.createElementNS("http://www.w3.org/2000/svg","rect");O.setAttribute("x",String(M.x)),O.setAttribute("y",String(M.y)),O.setAttribute("width",String(Math.max(12,M.width))),O.setAttribute("height",String(Math.max(12,M.height))),O.setAttribute("tabindex","0"),O.setAttribute("role","button"),O.setAttribute("aria-label",`Edytuj element UML ${S.id}`),O.dataset.umlLayoutId=S.id,O.dataset.umlLayoutAction="move",O.classList.add("uml-layout-hit"),S.id===Q&&O.classList.add("is-selected");let v=document.createElementNS("http://www.w3.org/2000/svg","title");if(v.textContent=`${S.id} \xB7 przeci\u0105gnij, aby zmieni\u0107 po\u0142o\u017Cenie`,O.appendChild(v),x.appendChild(O),S.id===Q){let w=Math.max(8,Math.min(14,Math.min(M.width,M.height)*.1)),L=document.createElementNS("http://www.w3.org/2000/svg","rect");L.setAttribute("x",String(M.x+M.width-w/2)),L.setAttribute("y",String(M.y+M.height-w/2)),L.setAttribute("width",String(w)),L.setAttribute("height",String(w)),L.dataset.umlLayoutId=S.id,L.dataset.umlLayoutAction="resize",L.classList.add("uml-layout-resize"),x.appendChild(L)}}},[p,C,j,Q,Ge]),(0,N.useEffect)(()=>{C&&(!Q||!y.current.has(Q))&&et(Ge[0]??null)},[C,Ge,Q]),(0,N.useEffect)(()=>{if(me===0||f.current===me)return;let x=!1,S=0,M=v=>{if(x)return;let w=m.current?.querySelector(`.uml-step-hit[data-uml-step="${xe}"]`);if(!w)return;if(document.querySelector(".viewer-chrome")?.classList.contains("is-nvim-fit")){f.current=me;return}let H=Sp(w);if(!H){f.current=me;return}let K=sg(w);if(!K){let Z=dg(w,H),V=Z===0?up(w,H):0,oe=Z===0?sp(w,V):Z;if(vFn){S=window.requestAnimationFrame(()=>M(v+1));return}f.current=me;return}let X=up(w,K);if(Math.abs(X)<=Fn){f.current=me;return}let D=sp(w,X);if(vFn){S=window.requestAnimationFrame(()=>M(v+1));return}f.current=me},O=window.requestAnimationFrame(()=>M(0));return()=>{x=!0,window.cancelAnimationFrame(O),window.cancelAnimationFrame(S)}},[me,xe,p]);let F=(x,S,M=se,O=!0)=>{let v={task:e.task??null,block:e.block??null,phase:{id:x.phase.id,label:x.phase.label},step:x.step,focusLevel:M,activate:S&&document.documentElement.dataset.nvimSyncMode==="on"},w=()=>{window.dispatchEvent(new CustomEvent("stem:nvim-step",{detail:v}))};if(!O){w();return}let L=fetch("/api/navigation/current",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({task:v.task,block:v.block,phase:v.phase,step:{id:v.step.id,number:v.step.number,label:v.step.label,mode:v.step.mode??(v.step.snapshot_ref?"RUN":"CODE"),code_ref:v.step.code_ref??null,event_id:v.step.event_id??null,strategy_ref:v.step.strategy_ref??null},snapshot_ref:v.step.snapshot_ref??null,focus_level:v.focusLevel,sync_requested:!!v.activate,actor:document.documentElement.dataset.cardClientId??"browser"})});v.activate?L.then(w,w):(w(),L.catch(()=>{}))},B=(x,S=!1,M=se,O=!0)=>{let v=Math.max(0,Math.min(l.length-1,x)),w=l[v];if(w){if(A(M),v===xe){F(w,S,M,O);return}Dn(L=>L+1),E.current=S,b.current=M,_.current=O,bn(v)}},te=(x,S)=>{let M=m.current?.querySelector("svg"),O=M?.getScreenCTM();if(!M||!O)return null;let v=M.createSVGPoint();return v.x=x,v.y=S,v.matrixTransform(O.inverse())},at=x=>{if(!C||!j)return;let S=x.target?.closest(".uml-layout-hit[data-uml-layout-id],.uml-layout-resize[data-uml-layout-id]"),M=S?.dataset.umlLayoutId,O=M?y.current.get(M):null,v=te(x.clientX,x.clientY);if(!M||!O||!v)return;x.preventDefault(),x.stopPropagation();let w=j.elements[M]??po(O);g.current={id:M,action:S?.dataset.umlLayoutAction==="resize"?"resize":"move",pointerId:x.pointerId,startX:v.x,startY:v.y,initial:w},et(M),I(L=>L&&{...L,elements:{...L.elements,[M]:w}}),x.currentTarget.setPointerCapture(x.pointerId)},zt=x=>{let S=g.current;if(!S||S.pointerId!==x.pointerId)return;let M=te(x.clientX,x.clientY);if(!M)return;x.preventDefault();let O=M.x-S.startX,v=M.y-S.startY,w=S.action==="resize"?{...S.initial,width:Math.max(24,S.initial.width+O),height:Math.max(18,S.initial.height+v)}:{...S.initial,x:S.initial.x+O,y:S.initial.y+v};I(L=>L&&{...L,elements:{...L.elements,[S.id]:w}}),re(!0)},Ee=x=>{let S=g.current;!S||S.pointerId!==x.pointerId||(g.current=null,x.currentTarget.hasPointerCapture(x.pointerId)&&x.currentTarget.releasePointerCapture(x.pointerId))},ne=(x,S)=>{let M=y.current.get(x);M&&(I(O=>{if(!O)return O;let v=O.elements[x]??po(M);return{...O,elements:{...O.elements,[x]:S(v)}}}),re(!0))},st=async()=>{if(!j||!t.source_href)return;let x=Object.fromEntries(Array.from(y.current.values()).map(M=>[M.id,j.elements[M.id]??po(M)])),S={...j,elements:x};U("Zapisywanie uk\u0142adu\u2026");try{let M=await fetch("/api/uml-layout",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({source:t.source_href,layout:S,actor:document.documentElement.dataset.cardClientId??"browser"})});if(!M.ok)throw new Error((await M.json().catch(()=>null))?.message??`HTTP ${M.status}`);let O=await M.json();R(O.layout),I(O.layout),re(!1),Ne(!1),U(`Zapisano ${Object.keys(O.layout.elements).length} element\xF3w w JSON.`)}catch(M){U(`B\u0142\u0105d zapisu: ${M instanceof Error?M.message:String(M)}`)}},Ye=()=>{T&&(I(T),re(!1),U("Przywr\xF3cono ostatnio zapisany uk\u0142ad."))},wn=async()=>{if(!(!t.source_href||!window.confirm("Usun\u0105\u0107 r\u0119czny uk\u0142ad i wr\xF3ci\u0107 do geometrii PlantUML?"))){U("Resetowanie uk\u0142adu\u2026");try{let x=await fetch(`/api/uml-layout?source=${encodeURIComponent(t.source_href)}&actor=${encodeURIComponent(document.documentElement.dataset.cardClientId??"browser")}`,{method:"DELETE"});if(!x.ok)throw new Error(`HTTP ${x.status}`);let S=fs(t,e,T?.source_digest??"");R(S),I(S),re(!1),et(null),U("Przywr\xF3cono automatyczny uk\u0142ad PlantUML.")}catch(x){U(`B\u0142\u0105d resetu: ${x instanceof Error?x.message:String(x)}`)}}},ie=(x,S)=>{if(C)return;let M=Array.from(m.current?.querySelectorAll(".uml-step-hit[data-uml-step]")??[]).filter(v=>{let w=v.getBoundingClientRect();return x>=w.left&&x<=w.right&&S>=w.top&&S<=w.bottom}).sort((v,w)=>{let L=v.getBoundingClientRect(),H=w.getBoundingClientRect();return Math.abs(S-(L.top+L.bottom)/2)-Math.abs(S-(H.top+H.bottom)/2)}),O=Number(M[0]?.dataset.umlStep);Number.isInteger(O)&&B(O,!1,"step")},q=x=>{if(C||x.key!=="Enter"&&x.key!==" ")return;let S=x.target,M=Number(S.dataset?.umlStep);Number.isInteger(M)&&(x.preventDefault(),B(M,x.key==="Enter","step"))},bt=x=>{let S=l.findIndex(M=>M.phase.id===x.id);S>=0&&B(S,!1,"phase")},fe=l[xe];if((0,N.useEffect)(()=>{fe&&(F(fe,E.current,b.current??se,_.current),E.current=!1,b.current=null,_.current=!0)},[fe?.phase.id,fe?.step.id,e.block]),(0,N.useEffect)(()=>{let x=S=>{let M=S.detail;if(!M||e.task?.id&&M.task.id!==e.task.id||e.block?.id&&M.block.id!==e.block.id)return;let O=l.findIndex(v=>v.phase.id===M.phase.id&&v.step.id===M.step.id);if(O<0){A("card");return}B(O,!1,M.focus_level,!1)};return window.addEventListener("stem:navigation-command",x),()=>window.removeEventListener("stem:navigation-command",x)},[e.block?.id,e.task?.id,l,se,xe]),(0,N.useEffect)(()=>{let x=S=>{if(S.metaKey||C||S.target?.closest("input, textarea, select, [contenteditable='true']"))return;let O=d.current;if(!O)return;let v=Array.from(document.querySelectorAll("[data-stem-nav='uml-block']")),w=window.innerHeight/2;if(v.sort((D,Z)=>{let V=D.getBoundingClientRect(),oe=Z.getBoundingClientRect();return Math.abs((V.top+V.bottom)/2-w)-Math.abs((oe.top+oe.bottom)/2-w)})[0]!==O)return;if(S.key==="Enter"&&S.ctrlKey&&!S.altKey&&!S.shiftKey){if(!fe?.step.progress_id||!n)return;S.preventDefault(),S.stopPropagation();let D=n.items?.[fe.step.progress_id]?.status==="approved";r(fe.step.progress_id,D?"pending":"approved");return}if(S.key==="Enter"&&!S.altKey&&!S.shiftKey){if(!fe)return;S.preventDefault(),S.stopPropagation(),F(fe,!0,se);return}let H=["card","task","block","phase","step","snapshot"];if((S.key==="ArrowLeft"||S.key==="ArrowRight"||S.key==="Escape")&&!S.altKey&&!S.ctrlKey&&!S.shiftKey){let D=S.key==="ArrowRight"?1:-1,Z=H[Math.max(0,Math.min(H.length-1,H.indexOf(se)+D))];S.preventDefault(),S.stopPropagation(),A(Z),fe&&F(fe,!1,Z);return}if(S.key!=="ArrowUp"&&S.key!=="ArrowDown"||se==="card"&&!S.altKey&&!S.ctrlKey&&!S.shiftKey)return;let K=S.key==="ArrowUp"?-1:1,X=se;if(S.altKey&&S.shiftKey&&!S.ctrlKey)X="snapshot";else if(S.ctrlKey&&S.shiftKey&&!S.altKey)X="step";else if(S.altKey&&!S.ctrlKey&&!S.shiftKey)X="task";else if(S.ctrlKey&&!S.altKey&&!S.shiftKey)X="block";else if(S.shiftKey&&!S.altKey&&!S.ctrlKey)X="phase";else if(S.altKey||S.ctrlKey||S.shiftKey)return;S.preventDefault(),S.stopPropagation(),fetch("/api/navigation/move",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({level:X,delta:K,sync_requested:!1,actor:document.documentElement.dataset.cardClientId??"browser"})}).then(D=>D.ok?D.json():Promise.reject(new Error(`HTTP ${D.status}`))).then(D=>{D.current&&window.dispatchEvent(new CustomEvent("stem:navigation-command",{detail:D.current}))}).catch(()=>{})};return window.addEventListener("keydown",x),()=>window.removeEventListener("keydown",x)},[fe,l,se,r,n,C]),!fe)return null;let{phase:Qt,step:jn}=fe,qt=l.filter(x=>x.phase.id===Qt.id),ho=e.block?.label.match(/^A[1-8]\b/)?.[0]??"UML",yo=(e.title??e.block?.label??t.caption).replace(/^A[1-8]\s*[·—:-]\s*/i,""),Un=Q?y.current.get(Q)??null:null,ut=Un?j?.elements[Un.id]??po(Un):null;return(0,a.jsxs)("div",{ref:d,className:"uml-react uml-snapshot-react","data-stem-nav":"uml-block","data-task-id":e.task?.id,"data-block-id":e.block?.id,"data-navigation-level":se,children:[(0,a.jsxs)("header",{className:"uml-snapshot-header",children:[(0,a.jsxs)("div",{className:"uml-header-first-line",children:[(0,a.jsxs)("h3",{children:[(0,a.jsx)("span",{children:ho})," \u2014 ",yo,t.tile&&(0,a.jsxs)("small",{className:"uml-tile-part",children:["cz\u0119\u015B\u0107 ",t.tile.index,"/",t.tile.count," \xB7 r",t.tile.row," c",t.tile.column]})]}),(0,a.jsxs)("div",{className:"uml-header-navigation",children:[(0,a.jsx)(_p,{continuation:o}),t.source_href&&(0,a.jsx)("button",{className:`uml-edit-toggle${C?" is-active":""}`,"aria-pressed":C,title:"R\u0119czna edycja po\u0142o\u017Cenia i parametr\xF3w blok\xF3w UML",onClick:()=>P(x=>!x),children:C?"ZAMKNIJ EDIT":"EDIT"}),(0,a.jsx)("div",{className:"uml-phase-actions","aria-label":"Fazy diagramu",children:i.map(x=>(0,a.jsx)("button",{"aria-pressed":Qt.id===x.id,onClick:()=>bt(x),children:x.label},x.id))}),(0,a.jsx)("div",{className:"uml-step-actions","aria-label":`Checkpointy fazy ${Qt.label}`,children:qt.map(x=>{let S=l.indexOf(x),M=!!(x.step.progress_id&&n?.items?.[x.step.progress_id]?.status==="approved");return(0,a.jsx)("button",{"aria-label":`Krok ${x.step.number}: ${x.step.label}`,"aria-pressed":se!=="card"&&S===xe,"data-completed":M?"true":"false","data-mode":x.step.mode??"RUN",title:`${x.step.mode??"RUN"} \xB7 ${x.step.label}`,onClick:()=>B(S),children:String(x.step.number).padStart(2,"0")},x.step.id)})})]})]}),e.block?.description&&(0,a.jsx)("p",{className:"uml-header-description",children:e.block.description})]}),(0,a.jsxs)("div",{className:"uml-snapshot-layout",children:[(0,a.jsxs)("div",{ref:m,className:`uml-canvas uml-step-canvas${C?" is-layout-editing":""}`,onClick:x=>ie(x.clientX,x.clientY),onKeyDown:q,onPointerDown:at,onPointerMove:zt,onPointerUp:Ee,onPointerCancel:Ee,children:[p?(0,a.jsx)("div",{className:`uml-svg-host${t.tile?" is-tiled":""}`,style:hs(t.tile),dangerouslySetInnerHTML:{__html:p}}):(0,a.jsx)("img",{src:t.href,alt:t.alt}),h&&(0,a.jsx)("span",{className:"uml-inline-warning",children:"Widok statyczny \u2014 wybierz krok przyciskiem nad diagramem."})]}),C&&j&&(0,a.jsxs)("aside",{className:"uml-layout-editor","aria-label":"Edytor uk\u0142adu UML",children:[(0,a.jsxs)("div",{className:"uml-layout-editor-title",children:[(0,a.jsx)("strong",{children:"UML layout"}),(0,a.jsx)("span",{children:ke?"niezapisane zmiany":"zapisany"}),Le&&(0,a.jsx)("b",{children:"\u0179r\xF3d\u0142o PlantUML zmieni\u0142o si\u0119"})]}),(0,a.jsxs)("label",{children:["Element",(0,a.jsx)("select",{value:Q??"",onChange:x=>et(x.target.value||null),children:Ge.map(x=>(0,a.jsx)("option",{value:x,children:x},x))})]}),Q&&ut&&(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("div",{className:"uml-layout-number-grid",children:["x","y","width","height"].map(x=>(0,a.jsxs)("label",{children:[x,(0,a.jsx)("input",{type:"number",step:"1",min:x==="width"||x==="height"?12:void 0,value:Math.round(ut[x]*100)/100,onChange:S=>ne(Q,M=>({...M,[x]:Number(S.target.value)}))})]},x))}),(0,a.jsxs)("label",{className:"uml-layout-editor-text",children:["Tekst bloku \u2014 jeden wiersz SVG na lini\u0119",(0,a.jsx)("textarea",{rows:Math.max(3,Math.min(10,ut.text?.lines?.length??3)),value:(ut.text?.lines??[]).join(` -`),onChange:x=>ne(Q,S=>({...S,text:{...S.text,title:x.target.value.split(` -`)[0]??"",description:x.target.value.split(` +`+i.stack}return{value:e,source:t,stack:o,digest:null}}function Ll(e,t,n){return{value:e,source:null,stack:n??null,digest:t??null}}function ca(e,t){try{console.error(t.value)}catch(n){setTimeout(function(){throw n})}}var If=typeof WeakMap=="function"?WeakMap:Map;function Ed(e,t,n){n=Kt(-1,n),n.tag=3,n.payload={element:null};var r=t.value;return n.callback=function(){_i||(_i=!0,xa=r),ca(e,t)},n}function _d(e,t,n){n=Kt(-1,n),n.tag=3;var r=e.type.getDerivedStateFromError;if(typeof r=="function"){var o=t.value;n.payload=function(){return r(o)},n.callback=function(){ca(e,t)}}var i=e.stateNode;return i!==null&&typeof i.componentDidCatch=="function"&&(n.callback=function(){ca(e,t),typeof r!="function"&&(fn===null?fn=new Set([this]):fn.add(this));var l=t.stack;this.componentDidCatch(t.value,{componentStack:l!==null?l:""})}),n}function $u(e,t,n){var r=e.pingCache;if(r===null){r=e.pingCache=new If;var o=new Set;r.set(t,o)}else o=r.get(t),o===void 0&&(o=new Set,r.set(t,o));o.has(n)||(o.add(n),e=Qf.bind(null,e,t,n),t.then(e,e))}function Fu(e){do{var t;if((t=e.tag===13)&&(t=e.memoizedState,t=t!==null?t.dehydrated!==null:!0),t)return e;e=e.return}while(e!==null);return null}function Du(e,t,n,r,o){return(e.mode&1)===0?(e===t?e.flags|=65536:(e.flags|=128,n.flags|=131072,n.flags&=-52805,n.tag===1&&(n.alternate===null?n.tag=17:(t=Kt(-1,1),t.tag=2,mn(n,t,1))),n.lanes|=1),e):(e.flags|=65536,e.lanes=o,e)}var Of=qt.ReactCurrentOwner,Xe=!1;function Ge(e,t,n,r){t.child=e===null?td(t,null,n,r):dr(t,e.child,n,r)}function ju(e,t,n,r,o){n=n.render;var i=t.ref;return lr(t,o),r=Za(e,t,n,r,i,o),n=Ja(),e!==null&&!Xe?(t.updateQueue=e.updateQueue,t.flags&=-2053,e.lanes&=~o,Qt(e,t,o)):(fe&&n&&ja(t),t.flags|=1,Ge(e,t,r,o),t.child)}function Uu(e,t,n,r,o){if(e===null){var i=n.type;return typeof i=="function"&&!us(i)&&i.defaultProps===void 0&&n.compare===null&&n.defaultProps===void 0?(t.tag=15,t.type=i,Cd(e,t,i,r,o)):(e=ii(n.type,null,r,t,t.mode,o),e.ref=t.ref,e.return=t,t.child=e)}if(i=e.child,(e.lanes&o)===0){var l=i.memoizedProps;if(n=n.compare,n=n!==null?n:Zr,n(l,r)&&e.ref===t.ref)return Qt(e,t,o)}return t.flags|=1,e=hn(i,r),e.ref=t.ref,e.return=t,t.child=e}function Cd(e,t,n,r,o){if(e!==null){var i=e.memoizedProps;if(Zr(i,r)&&e.ref===t.ref)if(Xe=!1,t.pendingProps=r=i,(e.lanes&o)!==0)(e.flags&131072)!==0&&(Xe=!0);else return t.lanes=e.lanes,Qt(e,t,o)}return da(e,t,n,r,o)}function Ld(e,t,n){var r=t.pendingProps,o=r.children,i=e!==null?e.memoizedState:null;if(r.mode==="hidden")if((t.mode&1)===0)t.memoizedState={baseLanes:0,cachePool:null,transitions:null},le(tr,tt),tt|=n;else{if((n&1073741824)===0)return e=i!==null?i.baseLanes|n:n,t.lanes=t.childLanes=1073741824,t.memoizedState={baseLanes:e,cachePool:null,transitions:null},t.updateQueue=null,le(tr,tt),tt|=e,null;t.memoizedState={baseLanes:0,cachePool:null,transitions:null},r=i!==null?i.baseLanes:n,le(tr,tt),tt|=r}else i!==null?(r=i.baseLanes|n,t.memoizedState=null):r=n,le(tr,tt),tt|=r;return Ge(e,t,o,n),t.child}function zd(e,t){var n=t.ref;(e===null&&n!==null||e!==null&&e.ref!==n)&&(t.flags|=512,t.flags|=2097152)}function da(e,t,n,r,o){var i=Je(n)?Pn:Be.current;return i=ur(t,i),lr(t,o),n=Za(e,t,n,r,i,o),r=Ja(),e!==null&&!Xe?(t.updateQueue=e.updateQueue,t.flags&=-2053,e.lanes&=~o,Qt(e,t,o)):(fe&&r&&ja(t),t.flags|=1,Ge(e,t,n,o),t.child)}function Vu(e,t,n,r,o){if(Je(n)){var i=!0;hi(t)}else i=!1;if(lr(t,o),t.stateNode===null)ni(e,t),Nd(t,n,r),ua(t,n,r,o),r=!0;else if(e===null){var l=t.stateNode,s=t.memoizedProps;l.props=s;var u=l.context,d=n.contextType;typeof d=="object"&&d!==null?d=yt(d):(d=Je(n)?Pn:Be.current,d=ur(t,d));var m=n.getDerivedStateFromProps,y=typeof m=="function"||typeof l.getSnapshotBeforeUpdate=="function";y||typeof l.UNSAFE_componentWillReceiveProps!="function"&&typeof l.componentWillReceiveProps!="function"||(s!==r||u!==d)&&Ou(t,l,r,d),rn=!1;var g=t.memoizedState;l.state=g,wi(t,r,l,o),u=t.memoizedState,s!==r||g!==u||Ze.current||rn?(typeof m=="function"&&(sa(t,n,m,r),u=t.memoizedState),(s=rn||Iu(t,n,s,r,g,u,d))?(y||typeof l.UNSAFE_componentWillMount!="function"&&typeof l.componentWillMount!="function"||(typeof l.componentWillMount=="function"&&l.componentWillMount(),typeof l.UNSAFE_componentWillMount=="function"&&l.UNSAFE_componentWillMount()),typeof l.componentDidMount=="function"&&(t.flags|=4194308)):(typeof l.componentDidMount=="function"&&(t.flags|=4194308),t.memoizedProps=r,t.memoizedState=u),l.props=r,l.state=u,l.context=d,r=s):(typeof l.componentDidMount=="function"&&(t.flags|=4194308),r=!1)}else{l=t.stateNode,rd(e,t),s=t.memoizedProps,d=t.type===t.elementType?s:_t(t.type,s),l.props=d,y=t.pendingProps,g=l.context,u=n.contextType,typeof u=="object"&&u!==null?u=yt(u):(u=Je(n)?Pn:Be.current,u=ur(t,u));var f=n.getDerivedStateFromProps;(m=typeof f=="function"||typeof l.getSnapshotBeforeUpdate=="function")||typeof l.UNSAFE_componentWillReceiveProps!="function"&&typeof l.componentWillReceiveProps!="function"||(s!==y||g!==u)&&Ou(t,l,r,u),rn=!1,g=t.memoizedState,l.state=g,wi(t,r,l,o);var S=t.memoizedState;s!==y||g!==S||Ze.current||rn?(typeof f=="function"&&(sa(t,n,f,r),S=t.memoizedState),(d=rn||Iu(t,n,d,r,g,S,u)||!1)?(m||typeof l.UNSAFE_componentWillUpdate!="function"&&typeof l.componentWillUpdate!="function"||(typeof l.componentWillUpdate=="function"&&l.componentWillUpdate(r,S,u),typeof l.UNSAFE_componentWillUpdate=="function"&&l.UNSAFE_componentWillUpdate(r,S,u)),typeof l.componentDidUpdate=="function"&&(t.flags|=4),typeof l.getSnapshotBeforeUpdate=="function"&&(t.flags|=1024)):(typeof l.componentDidUpdate!="function"||s===e.memoizedProps&&g===e.memoizedState||(t.flags|=4),typeof l.getSnapshotBeforeUpdate!="function"||s===e.memoizedProps&&g===e.memoizedState||(t.flags|=1024),t.memoizedProps=r,t.memoizedState=S),l.props=r,l.state=S,l.context=u,r=d):(typeof l.componentDidUpdate!="function"||s===e.memoizedProps&&g===e.memoizedState||(t.flags|=4),typeof l.getSnapshotBeforeUpdate!="function"||s===e.memoizedProps&&g===e.memoizedState||(t.flags|=1024),r=!1)}return pa(e,t,n,r,i,o)}function pa(e,t,n,r,o,i){zd(e,t);var l=(t.flags&128)!==0;if(!r&&!l)return o&&Cu(t,n,!1),Qt(e,t,i);r=t.stateNode,Of.current=t;var s=l&&typeof n.getDerivedStateFromError!="function"?null:r.render();return t.flags|=1,e!==null&&l?(t.child=dr(t,e.child,null,i),t.child=dr(t,null,s,i)):Ge(e,t,s,i),t.memoizedState=r.state,o&&Cu(t,n,!0),t.child}function Ad(e){var t=e.stateNode;t.pendingContext?_u(e,t.pendingContext,t.pendingContext!==t.context):t.context&&_u(e,t.context,!1),Ya(e,t.containerInfo)}function Bu(e,t,n,r,o){return cr(),Va(o),t.flags|=256,Ge(e,t,n,r),t.child}var ma={dehydrated:null,treeContext:null,retryLane:0};function fa(e){return{baseLanes:e,cachePool:null,transitions:null}}function Pd(e,t,n){var r=t.pendingProps,o=ve.current,i=!1,l=(t.flags&128)!==0,s;if((s=l)||(s=e!==null&&e.memoizedState===null?!1:(o&2)!==0),s?(i=!0,t.flags&=-129):(e===null||e.memoizedState!==null)&&(o|=1),le(ve,o&1),e===null)return la(t),e=t.memoizedState,e!==null&&(e=e.dehydrated,e!==null)?((t.mode&1)===0?t.lanes=1:e.data==="$!"?t.lanes=8:t.lanes=1073741824,null):(l=r.children,e=r.fallback,i?(r=t.mode,i=t.child,l={mode:"hidden",children:l},(r&1)===0&&i!==null?(i.childLanes=0,i.pendingProps=l):i=ji(l,r,0,null),e=An(e,r,n,null),i.return=t,e.return=t,i.sibling=e,t.child=i,t.child.memoizedState=fa(n),t.memoizedState=ma,e):ns(t,l));if(o=e.memoizedState,o!==null&&(s=o.dehydrated,s!==null))return $f(e,t,l,r,s,o,n);if(i){i=r.fallback,l=t.mode,o=e.child,s=o.sibling;var u={mode:"hidden",children:r.children};return(l&1)===0&&t.child!==o?(r=t.child,r.childLanes=0,r.pendingProps=u,t.deletions=null):(r=hn(o,u),r.subtreeFlags=o.subtreeFlags&14680064),s!==null?i=hn(s,i):(i=An(i,l,n,null),i.flags|=2),i.return=t,r.return=t,r.sibling=i,t.child=r,r=i,i=t.child,l=e.child.memoizedState,l=l===null?fa(n):{baseLanes:l.baseLanes|n,cachePool:null,transitions:l.transitions},i.memoizedState=l,i.childLanes=e.childLanes&~n,t.memoizedState=ma,r}return i=e.child,e=i.sibling,r=hn(i,{mode:"visible",children:r.children}),(t.mode&1)===0&&(r.lanes=n),r.return=t,r.sibling=null,e!==null&&(n=t.deletions,n===null?(t.deletions=[e],t.flags|=16):n.push(e)),t.child=r,t.memoizedState=null,r}function ns(e,t){return t=ji({mode:"visible",children:t},e.mode,0,null),t.return=e,e.child=t}function Go(e,t,n,r){return r!==null&&Va(r),dr(t,e.child,null,n),e=ns(t,t.pendingProps.children),e.flags|=2,t.memoizedState=null,e}function $f(e,t,n,r,o,i,l){if(n)return t.flags&256?(t.flags&=-257,r=Ll(Error(L(422))),Go(e,t,l,r)):t.memoizedState!==null?(t.child=e.child,t.flags|=128,null):(i=r.fallback,o=t.mode,r=ji({mode:"visible",children:r.children},o,0,null),i=An(i,o,l,null),i.flags|=2,r.return=t,i.return=t,r.sibling=i,t.child=r,(t.mode&1)!==0&&dr(t,e.child,null,l),t.child.memoizedState=fa(l),t.memoizedState=ma,i);if((t.mode&1)===0)return Go(e,t,l,null);if(o.data==="$!"){if(r=o.nextSibling&&o.nextSibling.dataset,r)var s=r.dgst;return r=s,i=Error(L(419)),r=Ll(i,r,void 0),Go(e,t,l,r)}if(s=(l&e.childLanes)!==0,Xe||s){if(r=Te,r!==null){switch(l&-l){case 4:o=2;break;case 16:o=8;break;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:o=32;break;case 536870912:o=268435456;break;default:o=0}o=(o&(r.suspendedLanes|l))!==0?0:o,o!==0&&o!==i.retryLane&&(i.retryLane=o,Yt(e,o),At(r,e,o,-1))}return ss(),r=Ll(Error(L(421))),Go(e,t,l,r)}return o.data==="$?"?(t.flags|=128,t.child=e.child,t=qf.bind(null,e),o._reactRetry=t,null):(e=i.treeContext,nt=pn(o.nextSibling),rt=t,fe=!0,Lt=null,e!==null&&(mt[ft++]=Bt,mt[ft++]=Ht,mt[ft++]=Tn,Bt=e.id,Ht=e.overflow,Tn=t),t=ns(t,r.children),t.flags|=4096,t)}function Hu(e,t,n){e.lanes|=t;var r=e.alternate;r!==null&&(r.lanes|=t),aa(e.return,t,n)}function zl(e,t,n,r,o){var i=e.memoizedState;i===null?e.memoizedState={isBackwards:t,rendering:null,renderingStartTime:0,last:r,tail:n,tailMode:o}:(i.isBackwards=t,i.rendering=null,i.renderingStartTime=0,i.last=r,i.tail=n,i.tailMode=o)}function Td(e,t,n){var r=t.pendingProps,o=r.revealOrder,i=r.tail;if(Ge(e,t,r.children,n),r=ve.current,(r&2)!==0)r=r&1|2,t.flags|=128;else{if(e!==null&&(e.flags&128)!==0)e:for(e=t.child;e!==null;){if(e.tag===13)e.memoizedState!==null&&Hu(e,n,t);else if(e.tag===19)Hu(e,n,t);else if(e.child!==null){e.child.return=e,e=e.child;continue}if(e===t)break e;for(;e.sibling===null;){if(e.return===null||e.return===t)break e;e=e.return}e.sibling.return=e.return,e=e.sibling}r&=1}if(le(ve,r),(t.mode&1)===0)t.memoizedState=null;else switch(o){case"forwards":for(n=t.child,o=null;n!==null;)e=n.alternate,e!==null&&ki(e)===null&&(o=n),n=n.sibling;n=o,n===null?(o=t.child,t.child=null):(o=n.sibling,n.sibling=null),zl(t,!1,o,n,i);break;case"backwards":for(n=null,o=t.child,t.child=null;o!==null;){if(e=o.alternate,e!==null&&ki(e)===null){t.child=o;break}e=o.sibling,o.sibling=n,n=o,o=e}zl(t,!0,n,null,i);break;case"together":zl(t,!1,null,null,void 0);break;default:t.memoizedState=null}return t.child}function ni(e,t){(t.mode&1)===0&&e!==null&&(e.alternate=null,t.alternate=null,t.flags|=2)}function Qt(e,t,n){if(e!==null&&(t.dependencies=e.dependencies),Mn|=t.lanes,(n&t.childLanes)===0)return null;if(e!==null&&t.child!==e.child)throw Error(L(153));if(t.child!==null){for(e=t.child,n=hn(e,e.pendingProps),t.child=n,n.return=t;e.sibling!==null;)e=e.sibling,n=n.sibling=hn(e,e.pendingProps),n.return=t;n.sibling=null}return t.child}function Ff(e,t,n){switch(t.tag){case 3:Ad(t),cr();break;case 5:od(t);break;case 1:Je(t.type)&&hi(t);break;case 4:Ya(t,t.stateNode.containerInfo);break;case 10:var r=t.type._context,o=t.memoizedProps.value;le(bi,r._currentValue),r._currentValue=o;break;case 13:if(r=t.memoizedState,r!==null)return r.dehydrated!==null?(le(ve,ve.current&1),t.flags|=128,null):(n&t.child.childLanes)!==0?Pd(e,t,n):(le(ve,ve.current&1),e=Qt(e,t,n),e!==null?e.sibling:null);le(ve,ve.current&1);break;case 19:if(r=(n&t.childLanes)!==0,(e.flags&128)!==0){if(r)return Td(e,t,n);t.flags|=128}if(o=t.memoizedState,o!==null&&(o.rendering=null,o.tail=null,o.lastEffect=null),le(ve,ve.current),r)break;return null;case 22:case 23:return t.lanes=0,Ld(e,t,n)}return Qt(e,t,n)}var Rd,ga,Md,Id;Rd=function(e,t){for(var n=t.child;n!==null;){if(n.tag===5||n.tag===6)e.appendChild(n.stateNode);else if(n.tag!==4&&n.child!==null){n.child.return=n,n=n.child;continue}if(n===t)break;for(;n.sibling===null;){if(n.return===null||n.return===t)return;n=n.return}n.sibling.return=n.return,n=n.sibling}};ga=function(){};Md=function(e,t,n,r){var o=e.memoizedProps;if(o!==r){e=t.stateNode,Ln($t.current);var i=null;switch(n){case"input":o=$l(e,o),r=$l(e,r),i=[];break;case"select":o=xe({},o,{value:void 0}),r=xe({},r,{value:void 0}),i=[];break;case"textarea":o=jl(e,o),r=jl(e,r),i=[];break;default:typeof o.onClick!="function"&&typeof r.onClick=="function"&&(e.onclick=fi)}Vl(n,r);var l;n=null;for(d in o)if(!r.hasOwnProperty(d)&&o.hasOwnProperty(d)&&o[d]!=null)if(d==="style"){var s=o[d];for(l in s)s.hasOwnProperty(l)&&(n||(n={}),n[l]="")}else d!=="dangerouslySetInnerHTML"&&d!=="children"&&d!=="suppressContentEditableWarning"&&d!=="suppressHydrationWarning"&&d!=="autoFocus"&&(Kr.hasOwnProperty(d)?i||(i=[]):(i=i||[]).push(d,null));for(d in r){var u=r[d];if(s=o?.[d],r.hasOwnProperty(d)&&u!==s&&(u!=null||s!=null))if(d==="style")if(s){for(l in s)!s.hasOwnProperty(l)||u&&u.hasOwnProperty(l)||(n||(n={}),n[l]="");for(l in u)u.hasOwnProperty(l)&&s[l]!==u[l]&&(n||(n={}),n[l]=u[l])}else n||(i||(i=[]),i.push(d,n)),n=u;else d==="dangerouslySetInnerHTML"?(u=u?u.__html:void 0,s=s?s.__html:void 0,u!=null&&s!==u&&(i=i||[]).push(d,u)):d==="children"?typeof u!="string"&&typeof u!="number"||(i=i||[]).push(d,""+u):d!=="suppressContentEditableWarning"&&d!=="suppressHydrationWarning"&&(Kr.hasOwnProperty(d)?(u!=null&&d==="onScroll"&&de("scroll",e),i||s===u||(i=[])):(i=i||[]).push(d,u))}n&&(i=i||[]).push("style",n);var d=i;(t.updateQueue=d)&&(t.flags|=4)}};Id=function(e,t,n,r){n!==r&&(t.flags|=4)};function zr(e,t){if(!fe)switch(e.tailMode){case"hidden":t=e.tail;for(var n=null;t!==null;)t.alternate!==null&&(n=t),t=t.sibling;n===null?e.tail=null:n.sibling=null;break;case"collapsed":n=e.tail;for(var r=null;n!==null;)n.alternate!==null&&(r=n),n=n.sibling;r===null?t||e.tail===null?e.tail=null:e.tail.sibling=null:r.sibling=null}}function Ue(e){var t=e.alternate!==null&&e.alternate.child===e.child,n=0,r=0;if(t)for(var o=e.child;o!==null;)n|=o.lanes|o.childLanes,r|=o.subtreeFlags&14680064,r|=o.flags&14680064,o.return=e,o=o.sibling;else for(o=e.child;o!==null;)n|=o.lanes|o.childLanes,r|=o.subtreeFlags,r|=o.flags,o.return=e,o=o.sibling;return e.subtreeFlags|=r,e.childLanes=n,t}function Df(e,t,n){var r=t.pendingProps;switch(Ua(t),t.tag){case 2:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return Ue(t),null;case 1:return Je(t.type)&&gi(),Ue(t),null;case 3:return r=t.stateNode,pr(),pe(Ze),pe(Be),qa(),r.pendingContext&&(r.context=r.pendingContext,r.pendingContext=null),(e===null||e.child===null)&&(Ko(t)?t.flags|=4:e===null||e.memoizedState.isDehydrated&&(t.flags&256)===0||(t.flags|=1024,Lt!==null&&(Sa(Lt),Lt=null))),ga(e,t),Ue(t),null;case 5:Qa(t);var o=Ln(ro.current);if(n=t.type,e!==null&&t.stateNode!=null)Md(e,t,n,r,o),e.ref!==t.ref&&(t.flags|=512,t.flags|=2097152);else{if(!r){if(t.stateNode===null)throw Error(L(166));return Ue(t),null}if(e=Ln($t.current),Ko(t)){r=t.stateNode,n=t.type;var i=t.memoizedProps;switch(r[It]=t,r[to]=i,e=(t.mode&1)!==0,n){case"dialog":de("cancel",r),de("close",r);break;case"iframe":case"object":case"embed":de("load",r);break;case"video":case"audio":for(o=0;o<\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=l.createElement(n,{is:r.is}):(e=l.createElement(n),n==="select"&&(l=e,r.multiple?l.multiple=!0:r.size&&(l.size=r.size))):e=l.createElementNS(e,n),e[It]=t,e[to]=r,Rd(e,t,!1,!1),t.stateNode=e;e:{switch(l=Bl(n,r),n){case"dialog":de("cancel",e),de("close",e),o=r;break;case"iframe":case"object":case"embed":de("load",e),o=r;break;case"video":case"audio":for(o=0;ofr&&(t.flags|=128,r=!0,zr(i,!1),t.lanes=4194304)}else{if(!r)if(e=ki(l),e!==null){if(t.flags|=128,r=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),zr(i,!0),i.tail===null&&i.tailMode==="hidden"&&!l.alternate&&!fe)return Ue(t),null}else 2*ke()-i.renderingStartTime>fr&&n!==1073741824&&(t.flags|=128,r=!0,zr(i,!1),t.lanes=4194304);i.isBackwards?(l.sibling=t.child,t.child=l):(n=i.last,n!==null?n.sibling=l:t.child=l,i.last=l)}return i.tail!==null?(t=i.tail,i.rendering=t,i.tail=t.sibling,i.renderingStartTime=ke(),t.sibling=null,n=ve.current,le(ve,r?n&1|2:n&1),t):(Ue(t),null);case 22:case 23:return as(),r=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(t.flags|=8192),r&&(t.mode&1)!==0?(tt&1073741824)!==0&&(Ue(t),t.subtreeFlags&6&&(t.flags|=8192)):Ue(t),null;case 24:return null;case 25:return null}throw Error(L(156,t.tag))}function jf(e,t){switch(Ua(t),t.tag){case 1:return Je(t.type)&&gi(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return pr(),pe(Ze),pe(Be),qa(),e=t.flags,(e&65536)!==0&&(e&128)===0?(t.flags=e&-65537|128,t):null;case 5:return Qa(t),null;case 13:if(pe(ve),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(L(340));cr()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return pe(ve),null;case 4:return pr(),null;case 10:return Ka(t.type._context),null;case 22:case 23:return as(),null;case 24:return null;default:return null}}var Yo=!1,Ve=!1,Uf=typeof WeakSet=="function"?WeakSet:Set,O=null;function er(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(r){we(e,t,r)}else n.current=null}function ha(e,t,n){try{n()}catch(r){we(e,t,r)}}var Ku=!1;function Vf(e,t){if(Jl=di,e=jc(),Da(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var o=r.anchorOffset,i=r.focusNode;r=r.focusOffset;try{n.nodeType,i.nodeType}catch{n=null;break e}var l=0,s=-1,u=-1,d=0,m=0,y=e,g=null;t:for(;;){for(var f;y!==n||o!==0&&y.nodeType!==3||(s=l+o),y!==i||r!==0&&y.nodeType!==3||(u=l+r),y.nodeType===3&&(l+=y.nodeValue.length),(f=y.firstChild)!==null;)g=y,y=f;for(;;){if(y===e)break t;if(g===n&&++d===o&&(s=l),g===i&&++m===r&&(u=l),(f=y.nextSibling)!==null)break;y=g,g=y.parentNode}y=f}n=s===-1||u===-1?null:{start:s,end:u}}else n=null}n=n||{start:0,end:0}}else n=null;for(ea={focusedElem:e,selectionRange:n},di=!1,O=t;O!==null;)if(t=O,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,O=e;else for(;O!==null;){t=O;try{var S=t.alternate;if((t.flags&1024)!==0)switch(t.tag){case 0:case 11:case 15:break;case 1:if(S!==null){var b=S.memoizedProps,_=S.memoizedState,p=t.stateNode,c=p.getSnapshotBeforeUpdate(t.elementType===t.type?b:_t(t.type,b),_);p.__reactInternalSnapshotBeforeUpdate=c}break;case 3:var h=t.stateNode.containerInfo;h.nodeType===1?h.textContent="":h.nodeType===9&&h.documentElement&&h.removeChild(h.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(L(163))}}catch(w){we(t,t.return,w)}if(e=t.sibling,e!==null){e.return=t.return,O=e;break}O=t.return}return S=Ku,Ku=!1,S}function Vr(e,t,n){var r=t.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var o=r=r.next;do{if((o.tag&e)===e){var i=o.destroy;o.destroy=void 0,i!==void 0&&ha(t,n,i)}o=o.next}while(o!==r)}}function Fi(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function ya(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}function Od(e){var t=e.alternate;t!==null&&(e.alternate=null,Od(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[It],delete t[to],delete t[ra],delete t[Nf],delete t[Ef])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function $d(e){return e.tag===5||e.tag===3||e.tag===4}function Wu(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||$d(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function va(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=fi));else if(r!==4&&(e=e.child,e!==null))for(va(e,t,n),e=e.sibling;e!==null;)va(e,t,n),e=e.sibling}function ba(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(ba(e,t,n),e=e.sibling;e!==null;)ba(e,t,n),e=e.sibling}var Oe=null,Ct=!1;function tn(e,t,n){for(n=n.child;n!==null;)Fd(e,t,n),n=n.sibling}function Fd(e,t,n){if(Ot&&typeof Ot.onCommitFiberUnmount=="function")try{Ot.onCommitFiberUnmount(Ai,n)}catch{}switch(n.tag){case 5:Ve||er(n,t);case 6:var r=Oe,o=Ct;Oe=null,tn(e,t,n),Oe=r,Ct=o,Oe!==null&&(Ct?(e=Oe,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):Oe.removeChild(n.stateNode));break;case 18:Oe!==null&&(Ct?(e=Oe,n=n.stateNode,e.nodeType===8?kl(e.parentNode,n):e.nodeType===1&&kl(e,n),qr(e)):kl(Oe,n.stateNode));break;case 4:r=Oe,o=Ct,Oe=n.stateNode.containerInfo,Ct=!0,tn(e,t,n),Oe=r,Ct=o;break;case 0:case 11:case 14:case 15:if(!Ve&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){o=r=r.next;do{var i=o,l=i.destroy;i=i.tag,l!==void 0&&((i&2)!==0||(i&4)!==0)&&ha(n,t,l),o=o.next}while(o!==r)}tn(e,t,n);break;case 1:if(!Ve&&(er(n,t),r=n.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(s){we(n,t,s)}tn(e,t,n);break;case 21:tn(e,t,n);break;case 22:n.mode&1?(Ve=(r=Ve)||n.memoizedState!==null,tn(e,t,n),Ve=r):tn(e,t,n);break;default:tn(e,t,n)}}function Gu(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new Uf),t.forEach(function(r){var o=Xf.bind(null,e,r);n.has(r)||(n.add(r),r.then(o,o))})}}function Et(e,t){var n=t.deletions;if(n!==null)for(var r=0;ro&&(o=l),r&=~i}if(r=o,r=ke()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*Hf(r/1960))-r,10e?16:e,sn===null)var r=!1;else{if(e=sn,sn=null,Ci=0,(X&6)!==0)throw Error(L(331));var o=X;for(X|=4,O=e.current;O!==null;){var i=O,l=i.child;if((O.flags&16)!==0){var s=i.deletions;if(s!==null){for(var u=0;uke()-is?zn(e,0):os|=n),et(e,t)}function Wd(e,t){t===0&&((e.mode&1)===0?t=1:(t=Io,Io<<=1,(Io&130023424)===0&&(Io=4194304)));var n=Ye();e=Yt(e,t),e!==null&&(so(e,t,n),et(e,n))}function qf(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),Wd(e,n)}function Xf(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,o=e.memoizedState;o!==null&&(n=o.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(L(314))}r!==null&&r.delete(t),Wd(e,n)}var Gd;Gd=function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||Ze.current)Xe=!0;else{if((e.lanes&n)===0&&(t.flags&128)===0)return Xe=!1,Ff(e,t,n);Xe=(e.flags&131072)!==0}else Xe=!1,fe&&(t.flags&1048576)!==0&&Xc(t,vi,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;ni(e,t),e=t.pendingProps;var o=ur(t,Be.current);lr(t,n),o=Za(null,t,r,e,o,n);var i=Ja();return t.flags|=1,typeof o=="object"&&o!==null&&typeof o.render=="function"&&o.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,Je(r)?(i=!0,hi(t)):i=!1,t.memoizedState=o.state!==null&&o.state!==void 0?o.state:null,Ga(t),o.updater=$i,t.stateNode=o,o._reactInternals=t,ua(t,r,e,n),t=pa(null,t,r,!0,i,n)):(t.tag=0,fe&&i&&ja(t),Ge(null,t,o,n),t=t.child),t;case 16:r=t.elementType;e:{switch(ni(e,t),e=t.pendingProps,o=r._init,r=o(r._payload),t.type=r,o=t.tag=Jf(r),e=_t(r,e),o){case 0:t=da(null,t,r,e,n);break e;case 1:t=Vu(null,t,r,e,n);break e;case 11:t=ju(null,t,r,e,n);break e;case 14:t=Uu(null,t,r,_t(r.type,e),n);break e}throw Error(L(306,r,""))}return t;case 0:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:_t(r,o),da(e,t,r,o,n);case 1:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:_t(r,o),Vu(e,t,r,o,n);case 3:e:{if(Ad(t),e===null)throw Error(L(387));r=t.pendingProps,i=t.memoizedState,o=i.element,rd(e,t),wi(t,r,null,n);var l=t.memoizedState;if(r=l.element,i.isDehydrated)if(i={element:r,isDehydrated:!1,cache:l.cache,pendingSuspenseBoundaries:l.pendingSuspenseBoundaries,transitions:l.transitions},t.updateQueue.baseState=i,t.memoizedState=i,t.flags&256){o=mr(Error(L(423)),t),t=Bu(e,t,r,n,o);break e}else if(r!==o){o=mr(Error(L(424)),t),t=Bu(e,t,r,n,o);break e}else for(nt=pn(t.stateNode.containerInfo.firstChild),rt=t,fe=!0,Lt=null,n=td(t,null,r,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if(cr(),r===o){t=Qt(e,t,n);break e}Ge(e,t,r,n)}t=t.child}return t;case 5:return od(t),e===null&&la(t),r=t.type,o=t.pendingProps,i=e!==null?e.memoizedProps:null,l=o.children,ta(r,o)?l=null:i!==null&&ta(r,i)&&(t.flags|=32),zd(e,t),Ge(e,t,l,n),t.child;case 6:return e===null&&la(t),null;case 13:return Pd(e,t,n);case 4:return Ya(t,t.stateNode.containerInfo),r=t.pendingProps,e===null?t.child=dr(t,null,r,n):Ge(e,t,r,n),t.child;case 11:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:_t(r,o),ju(e,t,r,o,n);case 7:return Ge(e,t,t.pendingProps,n),t.child;case 8:return Ge(e,t,t.pendingProps.children,n),t.child;case 12:return Ge(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,o=t.pendingProps,i=t.memoizedProps,l=o.value,le(bi,r._currentValue),r._currentValue=l,i!==null)if(Pt(i.value,l)){if(i.children===o.children&&!Ze.current){t=Qt(e,t,n);break e}}else for(i=t.child,i!==null&&(i.return=t);i!==null;){var s=i.dependencies;if(s!==null){l=i.child;for(var u=s.firstContext;u!==null;){if(u.context===r){if(i.tag===1){u=Kt(-1,n&-n),u.tag=2;var d=i.updateQueue;if(d!==null){d=d.shared;var m=d.pending;m===null?u.next=u:(u.next=m.next,m.next=u),d.pending=u}}i.lanes|=n,u=i.alternate,u!==null&&(u.lanes|=n),aa(i.return,n,t),s.lanes|=n;break}u=u.next}}else if(i.tag===10)l=i.type===t.type?null:i.child;else if(i.tag===18){if(l=i.return,l===null)throw Error(L(341));l.lanes|=n,s=l.alternate,s!==null&&(s.lanes|=n),aa(l,n,t),l=i.sibling}else l=i.child;if(l!==null)l.return=i;else for(l=i;l!==null;){if(l===t){l=null;break}if(i=l.sibling,i!==null){i.return=l.return,l=i;break}l=l.return}i=l}Ge(e,t,o.children,n),t=t.child}return t;case 9:return o=t.type,r=t.pendingProps.children,lr(t,n),o=yt(o),r=r(o),t.flags|=1,Ge(e,t,r,n),t.child;case 14:return r=t.type,o=_t(r,t.pendingProps),o=_t(r.type,o),Uu(e,t,r,o,n);case 15:return Cd(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:_t(r,o),ni(e,t),t.tag=1,Je(r)?(e=!0,hi(t)):e=!1,lr(t,n),Nd(t,r,o),ua(t,r,o,n),pa(null,t,r,!0,e,n);case 19:return Td(e,t,n);case 22:return Ld(e,t,n)}throw Error(L(156,t.tag))};function Yd(e,t){return wc(e,t)}function Zf(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function gt(e,t,n,r){return new Zf(e,t,n,r)}function us(e){return e=e.prototype,!(!e||!e.isReactComponent)}function Jf(e){if(typeof e=="function")return us(e)?1:0;if(e!=null){if(e=e.$$typeof,e===La)return 11;if(e===za)return 14}return 2}function hn(e,t){var n=e.alternate;return n===null?(n=gt(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function ii(e,t,n,r,o,i){var l=2;if(r=e,typeof e=="function")us(e)&&(l=1);else if(typeof e=="string")l=5;else e:switch(e){case Kn:return An(n.children,o,i,t);case Ca:l=8,o|=8;break;case Rl:return e=gt(12,n,t,o|2),e.elementType=Rl,e.lanes=i,e;case Ml:return e=gt(13,n,t,o),e.elementType=Ml,e.lanes=i,e;case Il:return e=gt(19,n,t,o),e.elementType=Il,e.lanes=i,e;case oc:return ji(n,o,i,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case nc:l=10;break e;case rc:l=9;break e;case La:l=11;break e;case za:l=14;break e;case nn:l=16,r=null;break e}throw Error(L(130,e==null?e:typeof e,""))}return t=gt(l,n,t,o),t.elementType=e,t.type=r,t.lanes=i,t}function An(e,t,n,r){return e=gt(7,e,r,t),e.lanes=n,e}function ji(e,t,n,r){return e=gt(22,e,r,t),e.elementType=oc,e.lanes=n,e.stateNode={isHidden:!1},e}function Al(e,t,n){return e=gt(6,e,null,t),e.lanes=n,e}function Pl(e,t,n){return t=gt(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function eg(e,t,n,r,o){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=fl(0),this.expirationTimes=fl(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=fl(0),this.identifierPrefix=r,this.onRecoverableError=o,this.mutableSourceEagerHydrationData=null}function cs(e,t,n,r,o,i,l,s,u){return e=new eg(e,t,n,s,u),t===1?(t=1,i===!0&&(t|=8)):t=0,i=gt(3,null,null,t),e.current=i,i.stateNode=e,i.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},Ga(i),e}function tg(e,t,n){var r=3{"use strict";function Jd(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(Jd)}catch(e){console.error(e)}}Jd(),ep.exports=Zd()});var rp=jt(fs=>{"use strict";var np=tp();fs.createRoot=np.createRoot,fs.hydrateRoot=np.hydrateRoot;var _h});var ip=jt(Ki=>{"use strict";var lg=Eo(),ag=Symbol.for("react.element"),sg=Symbol.for("react.fragment"),ug=Object.prototype.hasOwnProperty,cg=lg.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,dg={key:!0,ref:!0,__self:!0,__source:!0};function op(e,t,n){var r,o={},i=null,l=null;n!==void 0&&(i=""+n),t.key!==void 0&&(i=""+t.key),t.ref!==void 0&&(l=t.ref);for(r in t)ug.call(t,r)&&!dg.hasOwnProperty(r)&&(o[r]=t[r]);if(e&&e.defaultProps)for(r in t=e.defaultProps,t)o[r]===void 0&&(o[r]=t[r]);return{$$typeof:ag,type:e,key:i,ref:l,props:o,_owner:cg.current}}Ki.Fragment=sg;Ki.jsx=op;Ki.jsxs=op});var gs=jt((Ph,lp)=>{"use strict";lp.exports=ip()});var k=wo(Eo(),1),Sp=wo(rp(),1);var a=wo(gs(),1),Wi=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,pg="http://localhost:8080",Np="https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl",ap=["localhost","k3s_localhost","k3s_vps"],mg={localhost:"LOCALHOST",k3s_localhost:"K3S@LOCALHOST",k3s_vps:"K3S@VPS"};function sp(e){try{let t=new URL(String(e??""));return["http:","https:"].includes(t.protocol)?(t.search="",t.hash="",t.href.replace(/\/$/,"")):""}catch{return""}}function fg(){return window.location.pathname.split("/").filter(Boolean).find(e=>Wi.test(e))?.toLowerCase()??""}function gg(){let e=new URL(Np).host;return window.location.host===e?"k3s_vps":["localhost","127.0.0.1","::1"].includes(window.location.hostname)&&window.location.port==="8080"?"localhost":"k3s_localhost"}function hg(){let e=window.__STEM_CARD_RUNTIME__,t=ap.includes(e?.active_source)?e?.active_source:gg(),n=new Map(Array.isArray(e?.sources)?e.sources.map(o=>[o?.id,o]):[]),r=ap.map(o=>{let i=n.get(o),l=o==="localhost"?t===o?window.location.origin:pg:o==="k3s_vps"?Np:t===o?window.location.origin:"",s=sp(i?.base_url)||sp(l),u=t===o;return{id:o,label:String(i?.label||mg[o]),base_url:s,available:u||!!s&&i?.available!==!1,reason:String(i?.reason||(s?"":"\u0179r\xF3d\u0142o nie ma skonfigurowanego adresu"))}});return{schema:"stem.card-runtime/v1",default_source:"localhost",active_source:t,current_resource_uuid:String(e?.current_resource_uuid||fg()).toLowerCase(),sources:r}}function Ep(e,t,n=""){return!e.available||!e.base_url||!Wi.test(t)?"":`${e.base_url}/${t.toLowerCase()}/${n}`}function yg(e){let t=String(e.resource_uuid??"").toLowerCase();if(Wi.test(t))return t;for(let n of[e.local_href,e.href])try{let r=new URL(String(n??""),window.location.href).pathname.split("/").filter(Boolean).find(o=>Wi.test(o));if(r)return r.toLowerCase()}catch{}return""}function vg(e,t){return Ep(t,yg(e))||e.local_href||e.href}var _p={hidden:"UKRYTY",connecting:"\u0141\u0104CZENIE",connected:"ONLINE \xB7 LIVE",replaying:"ONLINE \xB7 REPLAY",verifying:"ONLINE \xB7 WERYFIKACJA",ready:"ONLINE \xB7 GOTOWY",failed:"ONLINE \xB7 B\u0141\u0104D STANU",offline:"OFFLINE \xB7 ZAPIS",unselected:"OFFLINE \xB7 BRAK CELU"},up=.25,Dn=1,cp=4;function bg(e){let t=window.getComputedStyle(e).overflowY;return t==="auto"||t==="scroll"||t==="hidden"||t==="clip"}function Cp(e){let t=e.getBoundingClientRect(),n=e.offsetHeight||e.clientHeight,r=n>0?t.height/n:1,o=t.top+e.clientTop*r;return{top:o,bottom:o+e.clientHeight*r}}function Lp(e){let t=document.querySelector(".viewer-chrome");if(t?.classList.contains("is-nvim-fit"))return null;let n=0,r=window.innerHeight;if(t){let o=t.getBoundingClientRect(),i=e.getBoundingClientRect();o.lefti.left&&o.bottom>0&&o.topDn?{top:n,bottom:r}:null}function xg(e){let t=Lp(e);if(!t)return null;let{top:n,bottom:r}=t;for(let o=e.parentElement;o&&o!==document.body&&o!==document.documentElement;o=o.parentElement){if(!bg(o))continue;let i=Cp(o);n=Math.max(n,i.top),r=Math.min(r,i.bottom)}return r-n>Dn?{top:n,bottom:r}:null}function Qi(){return document.scrollingElement??document.documentElement}function wg(e){let t=[];for(let r=e.parentElement;r&&r!==document.body&&r!==document.documentElement;r=r.parentElement){let o=window.getComputedStyle(r).overflowY;(o==="auto"||o==="scroll")&&r.scrollHeight-r.clientHeight>1&&t.push(r)}let n=Qi();return t.includes(n)||t.push(n),t}function kg(e){if(e===Qi())return 1;let t=e.getBoundingClientRect(),n=e.offsetHeight||e.clientHeight,r=n>0?t.height/n:1;return Number.isFinite(r)&&r>0?r:1}function Gi(e,t){let n=e.style.scrollBehavior;e.style.scrollBehavior="auto",t.left!=null&&(e.scrollLeft=t.left),t.top!=null&&(e.scrollTop=t.top),e.style.scrollBehavior=n}function Sg(e,t){let n=e.closest(".sheet-content");if(!n)return 0;let r=Cp(n),o=0;if(r.bottom<=t.top?o=r.bottom-t.bottom:r.top>=t.bottom&&(o=r.top-t.top),Math.abs(o)<=Dn)return 0;let i=Qi(),l=i.scrollTop,s=Math.max(0,i.scrollHeight-i.clientHeight);return Gi(i,{top:Math.max(0,Math.min(s,l+o))}),i.scrollTop-l}function dp(e,t){let n=t;for(let r of wg(e)){if(Math.abs(n)<=Dn)break;let o=kg(r),i=Math.max(0,r.scrollHeight-r.clientHeight),l=r.scrollTop,s=Math.max(0,Math.min(i,l+n/o));Gi(r,{top:s}),n-=(r.scrollTop-l)*o}return t-n}function pp(e,t){let n=e.getBoundingClientRect(),r=(n.top+n.bottom)/2,o=t.bottom-t.top,i=t.top+o*up,l=t.bottom-o*up;return rl?r-l:0}var Ft=({html:e,className:t})=>(0,a.jsx)("div",{className:t,dangerouslySetInnerHTML:{__html:e}});function zp(e,t){e.setAttribute("preserveAspectRatio","xMinYMin meet"),t&&(e.setAttribute("viewBox",`${t.x} ${t.y} ${t.width} ${t.height}`),e.setAttribute("width",`${t.width}px`),e.setAttribute("height",`${t.height}px`),e.dataset.tileIndex=String(t.index),e.dataset.tileRow=String(t.row),e.dataset.tileColumn=String(t.column))}function Ng(e){return e.normalize("NFKD").replace(/[\u0300-\u036f]/g,"").toLowerCase().replace(/[^a-z0-9_.:-]+/g,"-").replace(/^-+|-+$/g,"").slice(0,120)||"uml-element"}function ys(e){let t=e;if(typeof t.getBBox!="function")return null;try{let n=t.getBBox();return[n.x,n.y,n.width,n.height].every(Number.isFinite)?{x:n.x,y:n.y,width:n.width,height:n.height}:null}catch{return null}}function Eg(e){let t=ys(e);if(!t)return null;let n=Number(e.dataset.umlLayoutOriginX),r=Number(e.dataset.umlLayoutOriginY),o=Number(e.dataset.umlLayoutDx),i=Number(e.dataset.umlLayoutDy),l=Number(e.dataset.umlLayoutSx),s=Number(e.dataset.umlLayoutSy);return[n,r,o,i,l,s].every(Number.isFinite)?{x:n+(t.x-n)*l+o,y:r+(t.y-r)*s+i,width:t.width*l,height:t.height*s}:t}function Ap(e){e.dataset.umlLayoutRemembered!=="true"&&(e.dataset.umlLayoutRemembered="true",e.dataset.umlLayoutOriginalTransform=e.getAttribute("transform")??"",e.dataset.umlLayoutOriginalVisibility=e.getAttribute("visibility")??"",e.dataset.umlLayoutOriginalStyle=e.getAttribute("style")??"",e instanceof SVGTextElement&&(e.dataset.umlLayoutOriginalText=e.textContent??"",e.dataset.umlLayoutOriginalX=e.getAttribute("x")??"",e.dataset.umlLayoutOriginalTextAnchor=e.getAttribute("text-anchor")??"",e.dataset.umlLayoutOriginalFontFamily=e.getAttribute("font-family")??"",e.dataset.umlLayoutOriginalFontSize=e.getAttribute("font-size")??"",e.dataset.umlLayoutOriginalFontWeight=e.getAttribute("font-weight")??""),e instanceof SVGRectElement&&(e.dataset.umlLayoutOriginalFill=e.getAttribute("fill")??"",e.dataset.umlLayoutOriginalStroke=e.getAttribute("stroke")??"",e.dataset.umlLayoutOriginalStrokeWidth=e.getAttribute("stroke-width")??""))}function _g(e){e.querySelectorAll(".uml-layout-hit,.uml-layout-resize,.uml-layout-generated").forEach(t=>t.remove()),e.querySelectorAll("[data-uml-layout-remembered='true']").forEach(t=>{let n=(r,o)=>{o?t.setAttribute(r,o):t.removeAttribute(r)};n("transform",t.dataset.umlLayoutOriginalTransform),n("visibility",t.dataset.umlLayoutOriginalVisibility),n("style",t.dataset.umlLayoutOriginalStyle),t instanceof SVGTextElement&&(t.textContent=t.dataset.umlLayoutOriginalText??"",n("x",t.dataset.umlLayoutOriginalX),n("text-anchor",t.dataset.umlLayoutOriginalTextAnchor),n("font-family",t.dataset.umlLayoutOriginalFontFamily),n("font-size",t.dataset.umlLayoutOriginalFontSize),n("font-weight",t.dataset.umlLayoutOriginalFontWeight)),t instanceof SVGRectElement&&(n("fill",t.dataset.umlLayoutOriginalFill),n("stroke",t.dataset.umlLayoutOriginalStroke),n("stroke-width",t.dataset.umlLayoutOriginalStrokeWidth)),delete t.dataset.umlLayoutOriginX,delete t.dataset.umlLayoutOriginY,delete t.dataset.umlLayoutDx,delete t.dataset.umlLayoutDy,delete t.dataset.umlLayoutSx,delete t.dataset.umlLayoutSy,delete t.dataset.umlLayoutId})}function Cg(e,t){let n=e.querySelector(":scope > g")??e,r=Array.from(n.children).filter(s=>s instanceof SVGElement),o=r.filter(s=>s instanceof SVGRectElement).map(s=>({rect:s,box:ys(s)})).filter(s=>!!(s.box&&s.box.width>=30&&s.box.height>=14)).sort((s,u)=>s.box.width*s.box.height-u.box.width*u.box.height),i=new Map;for(let s of r){let u=ys(s);if(!u)continue;let d=u.x+u.width/2,m=u.y+u.height/2,y=o.find(({box:g})=>d>=g.x-.5&&d<=g.x+g.width+.5&&m>=g.y-.5&&m<=g.y+g.height+.5);y&&i.set(s,y.rect)}let l=new Set;return o.map(({rect:s,box:u},d)=>{let m=r.filter(c=>i.get(c)===s);m.includes(s)||m.unshift(s);let y=m.filter(c=>c instanceof SVGTextElement).sort((c,h)=>Number(c.getAttribute("y"))-Number(h.getAttribute("y"))),g=(y[0]?.textContent??s.id??`element-${d+1}`).trim(),f=/^(\d{1,3})\b/.exec(g)?.[1]?.padStart(2,"0"),S=s.id||(f?t.get(f):"")||g,b=Ng(S),_=b,p=2;for(;l.has(_);)_=`${b}-${p++}`;return l.add(_),m.forEach(Ap),{id:_,box:u,rect:s,members:m,texts:y}})}function mo(e){let t=e.texts[0],n=e.rect.getAttribute("style")??"",r=i=>new RegExp(`${i}\\s*:\\s*([^;]+)`,"i").exec(n)?.[1]?.trim(),o=Number(t?.getAttribute("font-size")??12);return{...e.box,z:0,scale:1,rotation:0,text:{title:(e.texts[0]?.textContent??"").trim(),description:e.texts.slice(1).map(i=>(i.textContent??"").trim()).join(` +`),lines:e.texts.map(i=>(i.textContent??"").trim()),font_family:t?.getAttribute("font-family")??"Monospace",font_size:Number.isFinite(o)?o:12,font_weight:Number(t?.getAttribute("font-weight")??400)||400,align:"left"},style:{fill:e.rect.getAttribute("fill")??r("fill")??"#edf6fa",stroke:e.rect.getAttribute("stroke")??r("stroke")??"#2c7794",stroke_width:Number(e.rect.getAttribute("stroke-width")??r("stroke-width")??1.5)}}}function Lg(e,t){let n=Math.max(12,Number(t.width)||e.box.width),r=Math.max(12,Number(t.height)||e.box.height),o=Number.isFinite(Number(t.x))?Number(t.x):e.box.x,i=Number.isFinite(Number(t.y))?Number(t.y):e.box.y,l=n/Math.max(1,e.box.width),s=r/Math.max(1,e.box.height),u=o-e.box.x,d=i-e.box.y,m=`translate(${u} ${d}) translate(${e.box.x} ${e.box.y}) scale(${l} ${s}) translate(${-e.box.x} ${-e.box.y})`;e.members.forEach(f=>{Ap(f);let S=f.dataset.umlLayoutOriginalTransform??"";f.setAttribute("transform",`${m}${S?` ${S}`:""}`),f.dataset.umlLayoutOriginX=String(e.box.x),f.dataset.umlLayoutOriginY=String(e.box.y),f.dataset.umlLayoutDx=String(u),f.dataset.umlLayoutDy=String(d),f.dataset.umlLayoutSx=String(l),f.dataset.umlLayoutSy=String(s),f.dataset.umlLayoutId=e.id});let y=t.text??{},g=y.lines??[y.title??"",...y.description?y.description.split(` +`):[]];e.texts.forEach((f,S)=>{S(e.tile?.page_height??0)?"landscape":"portrait",scale:1},elements:{},relations:{}}}function vs(e){if(!e)return{};let t=e.count===1,n=t?Math.max(0,(e.page_width-e.width)/2):e.column===1&&e.columns>1?e.page_width-e.width:e.column===e.columns?0:Math.max(0,(e.page_width-e.width)/2),r=t?0:e.row===1&&e.rows>1?e.page_height-e.height:e.row===e.rows?0:Math.max(0,(e.page_height-e.height)/2);return{"--uml-tile-page-width":`${e.page_width}px`,"--uml-tile-page-height":`${t?e.height:e.page_height}px`,"--uml-tile-left":`${n}px`,"--uml-tile-top":`${r}px`}}function zg({html:e}){return(0,a.jsx)(Ft,{html:e})}function Ag({html:e=""}){return e?(0,a.jsx)(Ft,{html:e}):null}function Pg(e){let t=e.spread_count??1;if(t<=1)return null;let n=Math.max(1,Math.min(t,e.spread_index??1)),r=Math.max(1,Math.min(t,e.spread_columns??1)),o=n-1,i=Math.floor(o/r),l=o%r;return{left:l>0,right:l+10,down:n+r<=t,index:n,count:t}}function Pp({continuation:e}){if(!e)return null;let t=[e.left&&["left","\u2190","kontynuacja po lewej"],e.up&&["up","\u2191","kontynuacja powy\u017Cej"],e.down&&["down","\u2193","kontynuacja poni\u017Cej"],e.right&&["right","\u2192","kontynuacja po prawej"]].filter(Boolean);return(0,a.jsx)("span",{className:"uml-page-continuation","aria-label":`Logiczny diagram: strona ${e.index} z ${e.count}`,title:`Ten sam diagram \xB7 strona ${e.index}/${e.count}`,children:t.map(([n,r,o])=>(0,a.jsx)("i",{"data-direction":n,"aria-label":o,children:r},n))})}function mp({side:e,html:t}){return(0,a.jsx)("aside",{className:`pdf-margin ${e}`,dangerouslySetInnerHTML:{__html:t}})}function bs({header:e,footer:t="",left:n="",right:r="",children:o,className:i=""}){return(0,a.jsx)("article",{className:`sheet ${i}`,children:(0,a.jsxs)("div",{className:"sheet-content",children:[(0,a.jsx)(zg,{html:e}),(0,a.jsx)(mp,{side:"left",html:n}),(0,a.jsx)("section",{className:"pdf-main card-section",children:o}),(0,a.jsx)(mp,{side:"right",html:r}),(0,a.jsx)(Ag,{html:t})]})})}function Tg({viewpoints:e}){let t=e.filter(i=>i.status==="enabled"&&i.target_id),[n,r]=(0,k.useState)(t[0]?.id??"");(0,k.useEffect)(()=>{if(!t.length)return;let i=0,l=()=>{window.cancelAnimationFrame(i),i=window.requestAnimationFrame(()=>{let s=document.querySelector(".viewer-chrome")?.getBoundingClientRect().bottom??0,u=t.map(m=>({viewpoint:m,element:document.getElementById(m.target_id)})).filter(m=>!!m.element);if(!u.length)return;let d=u.reduce((m,y)=>{let g=Math.abs(y.element.getBoundingClientRect().top-s-18);return g{window.cancelAnimationFrame(i),window.removeEventListener("scroll",l),window.removeEventListener("resize",l)}},[e]);let o=i=>{if(i.status!=="enabled"||!i.target_id)return;let l=document.getElementById(i.target_id);if(!l)return;let u=document.querySelector(".viewer-chrome")?.getBoundingClientRect().height??0;r(i.id),window.scrollTo({top:Math.max(0,window.scrollY+l.getBoundingClientRect().top-u-8),behavior:"smooth"})};return(0,a.jsx)("nav",{className:"viewpoint-bar","aria-label":"Perspektywy architektury A1\u2013A8",children:e.map(i=>{let l=i.status==="unavailable";return(0,a.jsxs)("button",{type:"button",className:l?"is-unavailable":"","aria-current":!l&&n===i.id?"location":void 0,disabled:l,title:l?i.reason:i.subtitle,onClick:()=>o(i),children:[(0,a.jsx)("span",{children:i.id}),(0,a.jsx)("strong",{children:i.label}),l&&(0,a.jsx)("small",{children:"N/D"})]},i.id)})})}function Rg({runtime:e,onSelect:t}){let n=e.sources.find(r=>r.id===e.active_source);return(0,a.jsxs)("label",{className:"runtime-source-selector","data-stem-source-selector":"true",title:n?.base_url||n?.reason||"Wyb\xF3r \u017Ar\xF3d\u0142a aplikacji",children:[(0,a.jsx)("span",{children:"\u0179R\xD3D\u0141O"}),(0,a.jsx)("select",{"aria-label":"\u0179r\xF3d\u0142o aplikacji",value:e.active_source,onChange:r=>t(r.currentTarget.value),children:e.sources.map(r=>(0,a.jsxs)("option",{value:r.id,disabled:!r.available,children:[r.label,r.available?"":" \xB7 BRAK"]},r.id))})]})}function Mg({toc:e,runtime:t,onSourceSelect:n,libraryAvailable:r,libraryOpen:o,setLibraryOpen:i,scale:l,setScale:s,nvimVisible:u,setNvimVisible:d,nvimSyncMode:m,setNvimSyncMode:y,nvimControlMode:g,setNvimControlMode:f,nvimExpanded:S,setNvimExpanded:b,nvimFit:_,setNvimFit:p,allocatorVisible:c,setAllocatorVisible:h,hasAllocatorModel:w,diagramSpread:C,setDiagramSpread:A,hasDiagramSpread:P,nvimSummary:z,progress:U,progressError:F}){return(0,a.jsx)("nav",{className:"topbar",children:(0,a.jsxs)("div",{className:"topbar-inner",children:[r&&(0,a.jsxs)("button",{type:"button",className:`card-library-toggle${o?" is-active":""}`,"aria-controls":"side-panel-left-library","aria-expanded":o,"aria-label":o?"Alt+0: zamknij serie i karty":"Alt+0: poka\u017C serie i karty",title:o?"Alt+0 \xB7 Zamknij serie i karty":"Alt+0 \xB7 Serie i karty",onClick:()=>i(!o),children:[(0,a.jsx)("span",{"aria-hidden":"true",className:"card-library-toggle-icon",children:"\u2630"}),(0,a.jsx)("kbd",{children:"A0"}),(0,a.jsx)("span",{children:"KARTY"})]}),(0,a.jsx)(Rg,{runtime:t,onSelect:n}),(0,a.jsxs)("details",{children:[(0,a.jsx)("summary",{children:"Spis tre\u015Bci"}),(0,a.jsx)("div",{className:"toc-links",children:e.map(ae=>(0,a.jsx)("a",{href:`#${ae.id}`,children:ae.label},ae.id))})]}),(0,a.jsxs)("div",{className:"topbar-nvim-section","aria-label":"Panel Neovima",children:[(0,a.jsx)("span",{className:"nvim-toolbar-boundary","aria-hidden":"true",children:"|"}),(0,a.jsx)("span",{className:"nvim-toolbar-context",children:"NVIM"}),(0,a.jsxs)("div",{className:"nvim-toolbar-actions","aria-label":"Narz\u0119dzia okna Neovima",children:[(0,a.jsxs)("button",{className:"viewer-nvim-toggle nvim-toolbar-button","aria-label":u?"Alt+1: ukryj Neovim":"Alt+1: poka\u017C Neovim",title:u?"Alt+1 \xB7 Ukryj Neovim":"Alt+1 \xB7 Poka\u017C Neovim","aria-pressed":u,onClick:()=>d(!u),children:[(0,a.jsx)("kbd",{className:"nvim-toolbar-key",children:"A1"}),(0,a.jsx)("span",{className:"nvim-toolbar-label",children:"PANEL"})]}),(0,a.jsxs)("button",{type:"button",className:`nvim-control-indicator nvim-toolbar-button${z.syncMode?" is-active":""}${z.syncReady?" is-engaged":""}`,"aria-label":`Alt+2: synchronizacja ${m?"w\u0142\u0105czona":"wy\u0142\u0105czona"}`,title:`Alt+2 \xB7 SYNC ${m?"ON":"OFF"}`,"aria-pressed":m,onClick:()=>y(!m),children:[(0,a.jsx)("kbd",{className:"nvim-toolbar-key",children:"A2"}),(0,a.jsx)("span",{className:"nvim-toolbar-label",children:"SYNC"})]}),(0,a.jsxs)("button",{type:"button",className:`nvim-work-indicator nvim-toolbar-button${g?" is-active":""}${z.controlEnabled?" is-engaged":""}`,"aria-label":`Alt+3: sterowanie ${m?g?"w\u0142\u0105czone":"wy\u0142\u0105czone":"niedost\u0119pne"}`,title:m?`Alt+3 \xB7 Sterowanie ${g?"ON":"OFF"}`:"Alt+3 \xB7 Sterowanie wymaga SYNC ON","aria-pressed":g,disabled:!m,onClick:()=>f(!g),children:[(0,a.jsx)("kbd",{className:"nvim-toolbar-key",children:"A3"}),(0,a.jsx)("span",{className:"nvim-toolbar-label",children:"CTRL"})]}),(0,a.jsxs)("button",{type:"button",className:`nvim-height-toggle nvim-toolbar-button${S?" is-active":""}`,"aria-label":`Alt+4: ${S?"przywr\xF3\u0107 normaln\u0105 wysoko\u015B\u0107":"ustaw wysoki panel"}`,title:S?"Alt+4 \xB7 Normalna wysoko\u015B\u0107":"Alt+4 \xB7 Wysoki panel 90%","aria-pressed":S,onClick:()=>b(!S),children:[(0,a.jsx)("kbd",{className:"nvim-toolbar-key",children:"A4"}),(0,a.jsx)("span",{className:"nvim-toolbar-label",children:"HIGH"})]}),(0,a.jsxs)("button",{type:"button",className:`nvim-height-toggle nvim-toolbar-button${_?" is-active":""}`,"aria-label":`Alt+5: automatyczne dopasowanie ${_?"w\u0142\u0105czone":"wy\u0142\u0105czone"}`,title:_?"Alt+5 \xB7 Wy\u0142\u0105cz auto-fit":"Alt+5 \xB7 Poka\u017C ca\u0142y Neovim","aria-pressed":_,onClick:()=>p(!_),children:[(0,a.jsx)("kbd",{className:"nvim-toolbar-key",children:"A5"}),(0,a.jsx)("span",{className:"nvim-toolbar-label",children:"FIT"})]}),w&&(0,a.jsxs)("button",{type:"button",className:`nvim-height-toggle nvim-toolbar-button${c?" is-active":""}`,"aria-label":`Alt+6: model alokatora ${c?"przypi\u0119ty":"ukryty"}`,title:c?"Alt+6 \xB7 Ukryj model alokatora":"Alt+6 \xB7 Przypnij model alokatora","aria-pressed":c,onClick:()=>h(!c),children:[(0,a.jsx)("kbd",{className:"nvim-toolbar-key",children:"A6"}),(0,a.jsx)("span",{className:"nvim-toolbar-label",children:"MODEL"})]}),P&&(0,a.jsxs)("button",{type:"button",className:`nvim-height-toggle nvim-toolbar-button${C?" is-active":""}`,"aria-label":`Alt+7: diagram UML ${C?"jako osobne kartki A4":"jako po\u0142\u0105czony spread"}`,title:C?"Alt+7 \xB7 Osobne kartki A4":"Alt+7 \xB7 Po\u0142\u0105cz strony UML","aria-pressed":C,onClick:()=>A(!C),children:[(0,a.jsx)("kbd",{className:"nvim-toolbar-key",children:"A7"}),(0,a.jsx)("span",{className:"nvim-toolbar-label",children:"UML"})]})]}),(0,a.jsx)("span",{className:"nvim-toolbar-boundary","aria-hidden":"true",children:"|"}),u&&(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("span",{className:`nvim-status nvim-status--${z.state}`,children:_p[z.state]}),(0,a.jsxs)("span",{className:"topbar-nvim-meta",title:z.message,children:[(0,a.jsx)("strong",{children:z.instance??"Neovim MCP"}),z.detail&&(0,a.jsx)("small",{children:z.detail})]}),(0,a.jsxs)("span",{className:"nvim-shortcut-strip","aria-label":"Skr\xF3ty panelu Neovima",children:[(0,a.jsx)("kbd",{children:"F1"})," reset \xB7 ",(0,a.jsx)("kbd",{children:"F2"})," sync \xB7 ",(0,a.jsx)("kbd",{children:"Alt+W"})," okna \xB7 ",(0,a.jsx)("kbd",{children:"F12"})," skr\xF3ty"]})]})]}),(0,a.jsx)(ah,{progress:U,error:F}),(0,a.jsxs)("div",{className:"viewer-zoom-controls",children:[(0,a.jsxs)("output",{className:"viewer-zoom-status",children:["P\u0142\xF3tno ",Math.round(l*100),"% \xB7 Tre\u015B\u0107 100%"]}),(0,a.jsx)("button",{className:"viewer-zoom-reset",onClick:()=>s(2.18),children:"Reset zoom"})]})]})})}function fp(e,t){for(let n of e.sections)for(let r of n.assets){let o=r.interactive;if(!(o?.kind!=="uml-sequence"||!o.phases?.length)&&!(t?.task.id&&o.task?.id!==t.task.id)&&!(t?.block.id&&o.block?.id!==t.block.id))for(let i of o.phases){if(t?.phase.id&&i.id!==t.phase.id)continue;let l=t?.step.id?i.steps.find(s=>s.id===t.step.id):i.steps[0];if(l)return{task:o.task??null,block:o.block??null,phase:{id:i.id,label:i.label},step:l,focusLevel:t?.focus_level??"step",activate:!1}}}return null}function Ig({visible:e,model:t}){let[n,r]=(0,k.useState)(null);if((0,k.useEffect)(()=>{let g=f=>{r(f.detail??null)};return window.addEventListener("stem:nvim-step",g),r(fp(t)),fetch("/api/navigation/current",{cache:"no-store"}).then(f=>f.ok?f.json():Promise.reject()).then(f=>{let S=fp(t,f.current??null);S&&r(S)}).catch(()=>{}),()=>window.removeEventListener("stem:nvim-step",g)},[t]),!e)return null;let o=n?.focusLevel??"card",i=n?.step.snapshot?.memory.arena,l=!!(n&&o!=="card"&&o!=="task"),s=Math.max(1,Number(i?.size_bytes??64)),u=i?.offset==null?null:Math.max(0,Math.min(s,Number(i.offset))),d=i?.bytes.trim().split(/\s+/).filter(Boolean)??[],m=Math.min(s,64),y=n?[...(n.step.snapshot?.memory.items??[]).map(g=>({name:g.name,value:g.value})),...(n.step.snapshot?.frame.fields??[]).map(g=>({name:g.name,value:g.value}))].filter((g,f,S)=>S.findIndex(b=>b.name===g.name)===f).slice(0,8):[];return(0,a.jsxs)("section",{className:"allocator-panel","aria-label":"Przypi\u0119ty model alokatora",children:[(0,a.jsxs)("header",{children:[(0,a.jsx)("span",{children:"ALLOCATOR \xB7 PINNED"}),(0,a.jsx)("strong",{children:n?`${n.phase.label} \xB7 ${String(n.step.number).padStart(2,"0")} ${n.step.label}`:"Oczekiwanie na diagram UML"}),(0,a.jsx)("small",{children:l?n.step.snapshot?.description??n.step.description:"Wybierz co najmniej BLOCK. F2 wybierze jego pierwszy krok i wykona synchronizacj\u0119."})]}),(0,a.jsxs)("div",{className:"allocator-panel-body",children:[(0,a.jsxs)("dl",{className:"allocator-metrics",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)("dt",{children:"FOCUS"}),(0,a.jsx)("dd",{children:o.toUpperCase()})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("dt",{children:"BASE"}),(0,a.jsx)("dd",{children:i?.base??"\u2014"})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("dt",{children:"ALLOCP"}),(0,a.jsx)("dd",{children:i?.cursor??"\u2014"})]}),(0,a.jsxs)("div",{children:[(0,a.jsx)("dt",{children:"USED / FREE"}),(0,a.jsx)("dd",{children:u==null?"\u2014":`${u} / ${s-u} B`})]})]}),(0,a.jsxs)("div",{className:`allocator-arena-view${l?"":" is-inactive"}`,children:[(0,a.jsxs)("div",{className:"allocator-arena-labels",children:[(0,a.jsx)("span",{children:"allocbuf[0]"}),(0,a.jsx)("strong",{children:u==null?"allocp jeszcze nieustawiony":`offset ${u}`}),(0,a.jsxs)("span",{children:["allocbuf[",s-1,"]"]})]}),(0,a.jsxs)("div",{className:"allocator-pinned-arena",style:{"--allocator-size":m},children:[Array.from({length:m},(g,f)=>(0,a.jsx)("i",{className:u!=null&&f(0,a.jsxs)("div",{children:[(0,a.jsx)("span",{children:g.name}),(0,a.jsx)("code",{children:g.value})]},g.name)):(0,a.jsx)("p",{children:"Brak snapshotu."})})]})]})}var Yi=()=>({text:" ",highlight:0});function gp(e=1,t=1){return{width:e,height:t,cells:Array.from({length:t},()=>Array.from({length:e},Yi)),highlights:new Map,foreground:15263976,background:1053461,cursor:{row:0,column:0}}}function Og(e,t,n){if(t<=0||n<=0)return;let r=e.cells;e.width=t,e.height=n,e.cells=Array.from({length:n},(o,i)=>Array.from({length:t},(l,s)=>r[i]?.[s]??Yi()))}function Tp(e){return`stem-card:nvim-grid:${e}`}function $g(e,t){if(t.width<=1||t.height<=1)return;let n={schema:"stem-nvim-grid.v1",snapshot_ref:e,saved_at:new Date().toISOString(),width:t.width,height:t.height,cells:t.cells.map(r=>r.map(o=>[o.text,o.highlight])),highlights:Array.from(t.highlights.entries()),foreground:t.foreground,background:t.background,cursor:{...t.cursor}};try{localStorage.setItem(Tp(e),JSON.stringify(n))}catch{}}function Rp(e,t){try{return e?.schema!=="stem-nvim-grid.v1"||e.snapshot_ref!==t||!Number.isInteger(e.width)||!Number.isInteger(e.height)||e.width<2||e.height<2||e.width>400||e.height>200||e.cells.length!==e.height?null:{width:e.width,height:e.height,cells:e.cells.map(n=>n.map(([r,o])=>({text:typeof r=="string"?r:" ",highlight:Number.isInteger(o)?o:0}))),highlights:new Map(e.highlights),foreground:e.foreground,background:e.background,cursor:e.cursor}}catch{return null}}function Fg(e){try{return Rp(JSON.parse(localStorage.getItem(Tp(e))??"null"),e)}catch{return null}}async function hp(e){let t=e.snapshot_ref;if(!t)return null;let n=Fg(t);if(n)return n;let r=e.view?.recorded_grid_ref;if(!r||/^(?:[a-z]+:|\/\/)/i.test(r))return null;try{let o=await fetch(r,{cache:"no-store"});return o.ok?Rp(await o.json(),t):null}catch{return null}}var Dg=[1842207,12590120,3064446,16106001,1997028,9978299,702940,12631996,6184036,15545147,5759881,16311388,5349887,12607947,5231357,16184820];function ho(e){let t=Number(e);if(!Number.isInteger(t)||t<0||t>255)return;if(t<16)return Dg[t];if(t<232){let r=t-16,o=[0,95,135,175,215,255],i=o[Math.floor(r/36)],l=o[Math.floor(r%36/6)],s=o[r%6];return i<<16|l<<8|s}let n=8+(t-232)*10;return n<<16|n<<8|n}function jg(e){if(!e||typeof e!="object")return null;let t=e;return Object.keys(t).length?{...t,foreground:ho(t.foreground),background:ho(t.background),special:ho(t.special)}:null}function Ug(e){if(!e||typeof e!="object")return null;let t=e;return Object.keys(t).length?{...t}:null}function Vg(e,t){for(let n of t){if(!Array.isArray(n)||typeof n[0]!="string")continue;let r=n[0],o=n.slice(1);for(let i of o)if(Array.isArray(i)){if(r==="grid_resize"){let[l,s,u]=i.map(Number);l===1&&Og(e,s,u)}else if(r==="default_colors_set"){let l=Number(i[0]),s=Number(i[1]),u=l>=0?l:ho(i[3]),d=s>=0?s:ho(i[4]);typeof u=="number"&&Number.isFinite(u)&&u>=0&&(e.foreground=u),typeof d=="number"&&Number.isFinite(d)&&d>=0&&(e.background=d)}else if(r==="hl_attr_define"){let l=Number(i[0]),s=jg(i[2])??Ug(i[1]);Number.isInteger(l)&&s&&typeof s=="object"&&e.highlights.set(l,s)}else if(r==="grid_clear"&&Number(i[0])===1)e.cells=Array.from({length:e.height},()=>Array.from({length:e.width},Yi));else if(r==="grid_cursor_goto"&&Number(i[0])===1)e.cursor={row:Number(i[1]),column:Number(i[2])};else if(r==="grid_line"&&Number(i[0])===1){let l=Number(i[1]),s=Number(i[2]),u=i[3];if(!e.cells[l]||!Array.isArray(u))continue;let d=0;for(let m of u){if(!Array.isArray(m))continue;let y=typeof m[0]=="string"?m[0]:" ";Number.isInteger(m[1])&&(d=Number(m[1]));let g=Number.isInteger(m[2])?Number(m[2]):1;for(let f=0;f=0&&(e.cells[l][s]={text:y,highlight:d}),s+=1}}else if(r==="grid_scroll"&&Number(i[0])===1){let l=Number(i[1]),s=Number(i[2]),u=Number(i[3]),d=Number(i[4]),m=Number(i[5]),y=Number(i[6]),g=e.cells.map(f=>f.map(S=>({...S})));for(let f=l;f=l&&b=u&&_i.text||" ").join(""),r=[],o=0;for(;o=n&&t.cursor.rowz.column-P.column||P.row-z.row):["asm","reg","memory"].includes(C??"")&&w.sort((P,z)=>P.column-z.column||P.row-z.row);let A=w[Math.max(0,Number(d.occurrence??1)-1)];m=A?.row??-1,y=A?.column??-1,f=d.text.length}if(m<0||y<0||m>=t.height||y>=t.width)continue;let S=Math.max(0,Number(d.padding_cells??1)),b=Math.max(0,y-S)*i,_=Math.max(0,m-S)*l,p=Math.min(t.width-y+S,f+S*2)*i,c=Math.min(t.height-m+S,g+S*2)*l,h=s[u.tone??"danger"];if(o.strokeStyle=h,o.lineWidth=2,u.shape==="underline"?(o.beginPath(),o.moveTo(b,_+c-2),o.lineTo(b+p,_+c-2),o.stroke()):o.strokeRect(b+1,_+1,Math.max(1,p-2),Math.max(1,c-2)),u.label){o.font="700 10px system-ui, sans-serif";let w=o.measureText(u.label).width+8;o.fillStyle=h,o.fillRect(b+1,Math.max(0,_-15),w,14),o.fillStyle="#fff",o.fillText(u.label,b+5,Math.max(10,_-4))}}}function Wg(e){if(e.nativeEvent.isComposing||e.metaKey)return null;let n={Enter:"CR",Escape:"Esc",Backspace:"BS",Delete:"Del",Tab:"Tab",ArrowLeft:"Left",ArrowRight:"Right",ArrowUp:"Up",ArrowDown:"Down",Home:"Home",End:"End",PageUp:"PageUp",PageDown:"PageDown",Insert:"Insert"}[e.key]??(/^F\d{1,2}$/.test(e.key)?e.key:null),r=[e.ctrlKey?"C":"",e.altKey?"M":"",e.shiftKey&&n?"S":""].filter(Boolean).join("-");return n?`<${r?`${r}-`:""}${n}>`:e.key.length!==1?null:e.ctrlKey||e.altKey?`<${r}-${e.key==="<"?"lt":e.key}>`:e.key==="<"?"":e.key}function Gg({visible:e,syncMode:t,controlMode:n,expanded:r,fit:o,scale:i,onSummaryChange:l}){let s=(0,k.useRef)(null),u=(0,k.useRef)(null),d=(0,k.useRef)(null),m=(0,k.useRef)(0),y=(0,k.useRef)(0),g=(0,k.useRef)(0),f=(0,k.useRef)(gp()),S=(0,k.useRef)(null),b=(0,k.useRef)(null),_=(0,k.useRef)(null),p=(0,k.useRef)(0),c=(0,k.useRef)(null),h=(0,k.useRef)(null),[w,C]=(0,k.useState)(null),[A,P]=(0,k.useState)(!1),[z,U]=(0,k.useState)(0),[F,ae]=(0,k.useState)(!1),[me,q]=(0,k.useState)(()=>{let T=Number(localStorage.getItem("stem-card-nvim-height-vh"));return Number.isFinite(T)&&T>=25&&T<=90?T:75}),[V,Re]=(0,k.useState)({state:"hidden"}),[Se,J]=(0,k.useState)({state:"idle"}),at=Se.state==="replaying"||Se.state==="verifying",bt=t&&V.state==="connected"&&!at,Me=n&&F&&V.state==="connected"&&!at,ge=()=>{s.current&&Kg(s.current,f.current,_.current===b.current?.step.snapshot_ref?b.current?.step.view?.annotations??[]:[])},yr=()=>{m.current||(m.current=window.requestAnimationFrame(()=>{m.current=0,ge()}))};if((0,k.useEffect)(()=>{let T=D=>{let G=D.detail;b.current=G,C(G),_.current=null;let te=G.step.snapshot_ref;if(V.state!=="connected"&&te&&hp(G.step).then(Q=>{!Q||b.current?.step.snapshot_ref!==te||(f.current=Q,P(!0),_.current=te,J({state:"idle",snapshot_ref:te,message:"Pokazano ostatni zapisany, zweryfikowany ekran."}),ge())}),ge(),!G.activate)return;let st=G.step.mode??"RUN",xt=async()=>{if(!G.step.code_ref)return null;let Q=await fetch("/api/nvim/open",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({code_ref:G.step.code_ref,actor:document.documentElement.dataset.cardClientId??"browser"})}),Ae=await Q.json().catch(()=>({}));if(!Q.ok)throw new Error(Ae.message??Ae.error??`HTTP ${Q.status}`);return Ae};if(st==="CODE"||!te){xt().then(()=>{J({state:"ready",phase:"code",message:G.step.code_ref?`Otwarto ${G.step.code_ref}; program nie zosta\u0142 zrestartowany.`:"Krok CODE nie ma przypisanego code_ref."})}).catch(Q=>{J({state:"failed",phase:"code",message:Q instanceof Error?Q.message:String(Q)})});return}if(!e||V.state!=="connected"){J({state:"failed",snapshot_ref:te,message:"Cel jest offline; pozostaje zapisany wynik tego kroku."});return}let ze=xt(),oe=Math.max(p.current+1,Date.now());p.current=oe,c.current?.abort();let wt=new AbortController;c.current=wt,J({state:"replaying",phase:"dispatch",generation:oe,snapshot_ref:te,message:"Resetuj\u0119 cel i odtwarzam wykonanie do wybranego kroku."});let kn=0,Dt=async()=>{try{let Q=await fetch("/api/checkpoint/status",{cache:"no-store",signal:wt.signal});if(!Q.ok)return;let Ae=await Q.json(),ut=Ae.active?.generation===oe?Ae.active:null;if(!ut||p.current!==oe)return;J({state:ut.phase==="verify"?"verifying":"replaying",phase:ut.phase,generation:oe,snapshot_ref:te,message:ut.message})}catch{}};kn=window.setInterval(Dt,120),Dt(),ze.then(()=>fetch("/api/checkpoint/activate",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({snapshot_ref:te,generation:oe}),signal:wt.signal})).then(async Q=>{let Ae=await Q.json();if(p.current!==oe)return;if(!Q.ok||Ae.status!=="ready")throw new Error(Ae.message??`Replay zako\u0144czy\u0142 si\u0119 kodem HTTP ${Q.status}.`);let ut=d.current;if(ut?.readyState!==WebSocket.OPEN)throw new Error("Replay zako\u0144czony, ale most Neovima jest offline.");let Ne=y.current;ut.send(JSON.stringify({type:"refresh"}));let Ee=Date.now()+1800;for(;y.current<=Ne&&Date.now()window.setTimeout(kt,20));if(y.current<=Ne)throw new Error("Neovim nie potwierdzi\u0142 pe\u0142nego redraw po replay.");if(p.current!==oe)return;_.current=te,J({state:"ready",phase:Ae.phase,generation:oe,snapshot_ref:te,message:Ae.message??"Stan maszyny zosta\u0142 odtworzony i zweryfikowany."}),$g(te,f.current),ge(),await new Promise(kt=>window.requestAnimationFrame(()=>kt()));let vr=s.current;if(vr&&b.current?.step.snapshot_ref===te)try{fetch("/api/evidence",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({actor:document.documentElement.dataset.cardClientId??"browser",snapshot_ref:te,event_id:G.step.event_id??null,strategy_ref:G.step.strategy_ref??null,code_ref:G.step.code_ref??null,caption:`${String(G.step.number).padStart(2,"0")} ${G.step.label}`,data_url:vr.toDataURL("image/png")})}).catch(()=>{})}catch{}}).catch(Q=>{wt.signal.aborted||p.current!==oe||(hp(G.step).then(Ae=>{!Ae||b.current?.step.snapshot_ref!==te||(f.current=Ae,P(!0),_.current=te,ge())}),J({state:"failed",generation:oe,snapshot_ref:te,message:Q instanceof Error?Q.message:String(Q)}))}).finally(()=>{window.clearInterval(kn),c.current===wt&&(c.current=null)})};return window.addEventListener("stem:nvim-step",T),()=>{window.removeEventListener("stem:nvim-step",T),c.current?.abort()}},[V.state,e]),(0,k.useEffect)(()=>{localStorage.setItem("stem-card-nvim-height-vh",me.toFixed(2))},[me]),(0,k.useEffect)(()=>{let T=window.requestAnimationFrame(ge);return()=>window.cancelAnimationFrame(T)},[r,o,i]),(0,k.useEffect)(()=>{let T=()=>{let D=d.current;D?.readyState===WebSocket.OPEN&&D.send(JSON.stringify({type:"refresh"})),ge()};return window.addEventListener("stem:nvim-refresh",T),()=>window.removeEventListener("stem:nvim-refresh",T)},[]),(0,k.useEffect)(()=>{let T=V.state;V.state==="connected"&&(T=Se.state==="idle"?"connected":Se.state),l({state:T,message:Se.message??V.message,instance:V.target?.instance??V.target?.container_name,detail:[V.target?.profile??w?.step.view?.connection_ref,w?`${String(w.step.number).padStart(2,"0")} ${w.step.label}`:void 0,Se.phase].filter(Boolean).join(" \xB7 "),syncMode:t,syncReady:bt,controlMode:n,controlEnabled:Me,screenCursor:{...f.current.cursor},grid:{columns:f.current.width,rows:f.current.height}})},[w,Se,Me,n,z,l,V,t,bt]),(0,k.useEffect)(()=>()=>window.clearTimeout(g.current),[]),(0,k.useEffect)(()=>{if(!Me)return;let T=D=>{let G=d.current;if(G?.readyState!==WebSocket.OPEN)return;if(D.altKey&&!D.ctrlKey&&!D.metaKey&&D.key.toLowerCase()==="w"){D.preventDefault(),D.stopImmediatePropagation(),D.repeat||G.send(JSON.stringify({type:"input",keys:""}));return}let te={ArrowLeft:"h",ArrowDown:"j",ArrowUp:"k",ArrowRight:"l"};D.altKey&&!D.ctrlKey&&!D.metaKey&&te[D.key]&&(D.preventDefault(),D.stopImmediatePropagation(),D.repeat||G.send(JSON.stringify({type:"input",keys:`${te[D.key]}`})))};return window.addEventListener("keydown",T,!0),()=>window.removeEventListener("keydown",T,!0)},[Me]),(0,k.useEffect)(()=>{if(!e||!t){d.current?.close(),d.current=null,ae(!1),Re(e?{state:"offline",message:"SYNC OFF: pokazuj\u0119 zapisany ekran bez po\u0142\u0105czenia z kontenerem."}:{state:"hidden"});return}let T=!1,D=0,G=()=>{if(T)return;let te=window.location.protocol==="https:"?"wss:":"ws:",st=new WebSocket(`${te}//${window.location.host}/api/nvim-ui`);d.current=st,Re({state:"connecting"}),st.addEventListener("message",xt=>{try{let ze=JSON.parse(String(xt.data));if(ze.type==="status"){typeof ze.epoch=="string"&&S.current&&S.current!==ze.epoch&&(f.current=gp(),P(!1),_.current=null),typeof ze.epoch=="string"&&(S.current=ze.epoch),Re(ze);return}ze.type==="redraw"&&Array.isArray(ze.events)&&(Vg(f.current,ze.events),f.current.width>1&&f.current.height>1&&P(!0),ze.events.some(oe=>Array.isArray(oe)&&oe[0]==="flush")&&(y.current+=1,yr(),g.current||(g.current=window.setTimeout(()=>{g.current=0,U(oe=>oe+1)},120))))}catch{}}),st.addEventListener("close",()=>{d.current===st&&(d.current=null),T||(D=window.setTimeout(G,1200))}),st.addEventListener("error",()=>{Re(xt=>({...xt,state:"offline",message:"Most Neovima jest chwilowo niedost\u0119pny."}))})};return G(),()=>{T=!0,window.clearTimeout(D),window.cancelAnimationFrame(m.current),m.current=0,d.current?.close(),d.current=null}},[t,e]),!e)return null;let se=T=>{let D=d.current;D?.readyState===WebSocket.OPEN&&D.send(JSON.stringify(T))},Zt=T=>{let D=T.currentTarget.getBoundingClientRect();return{row:Math.max(0,Math.min(f.current.height-1,Math.floor((T.clientY-D.top)/D.height*f.current.height))),column:Math.max(0,Math.min(f.current.width-1,Math.floor((T.clientX-D.left)/D.width*f.current.width)))}},ue=T=>[T.shiftKey?"S":"",T.ctrlKey?"C":"",T.altKey?"A":""].filter(Boolean).join("-");return(0,a.jsxs)("section",{className:"nvim-panel","aria-label":"Neovim po\u0142\u0105czony z kontenerem",onWheel:T=>{T.stopPropagation();let D=T.target;(!(D instanceof Element)||!D.closest(".nvim-screen-scroll"))&&T.preventDefault()},children:[(0,a.jsxs)("div",{ref:u,className:"nvim-screen-scroll",style:o?void 0:{height:`${r?90:me}vh`},"data-sync":t?"on":"off","data-control":Me?"true":"false",tabIndex:0,onPointerEnter:T=>{ae(!0),T.currentTarget.focus({preventScroll:!0})},onPointerLeave:T=>{ae(!1),T.currentTarget.blur()},onMouseDown:T=>T.currentTarget.focus({preventScroll:!0}),onKeyDown:T=>{if(!Me)return;let D=Wg(T);D&&(T.preventDefault(),T.stopPropagation(),se({type:"input",keys:D}))},children:[(0,a.jsx)("div",{className:"nvim-screen-stage",style:o?void 0:{height:`${(r?90:me)/Math.max(i,.25)}vh`},children:(0,a.jsx)("div",{className:"nvim-screen-surface",children:(0,a.jsx)("div",{className:"nvim-screen-frame",children:(0,a.jsx)("div",{className:"nvim-screen-content",children:(0,a.jsx)("div",{className:"nvim-screen-grid",children:(0,a.jsx)("canvas",{ref:s,className:"nvim-screen",tabIndex:-1,"aria-label":Me?"Interaktywny ekran Neovima":"Ekran Neovima",onMouseDown:T=>{if(!Me||V.state!=="connected")return;T.preventDefault();let D=Zt(T),G=T.button===1?"middle":T.button===2?"right":"left";se({type:"mouse",button:G,action:"press",modifier:ue(T),...D})},onMouseUp:T=>{if(!Me||V.state!=="connected")return;T.preventDefault();let D=Zt(T),G=T.button===1?"middle":T.button===2?"right":"left";se({type:"mouse",button:G,action:"release",modifier:ue(T),...D})},onWheel:T=>{if(!Me||V.state!=="connected")return;T.preventDefault();let D=Zt(T);se({type:"mouse",button:"wheel",action:T.deltaY<0?"up":"down",modifier:ue(T),...D})},onContextMenu:T=>Me&&T.preventDefault()})})})})})}),!A&&(0,a.jsxs)("div",{className:"nvim-screen-empty",children:[(0,a.jsx)("strong",{children:_p[V.state]}),(0,a.jsx)("span",{children:V.message??"Oczekiwanie na ekran Neovima lub zapisany stan kroku."})]})]}),(0,a.jsx)("div",{className:"nvim-resize-handle",role:"separator","aria-label":"Zmie\u0144 wysoko\u015B\u0107 panelu Neovima","aria-orientation":"horizontal","aria-valuemin":25,"aria-valuemax":90,"aria-valuenow":Math.round(me),tabIndex:0,title:"Przeci\u0105gnij, aby zmieni\u0107 wysoko\u015B\u0107. Dwuklik: 75%.",onPointerDown:T=>{T.preventDefault(),h.current={y:T.clientY,heightVh:me},T.currentTarget.setPointerCapture(T.pointerId)},onPointerMove:T=>{let D=h.current;if(!D)return;let G=(T.clientY-D.y)/window.innerHeight*100;q(Math.max(25,Math.min(90,D.heightVh+G)))},onPointerUp:T=>{h.current=null,T.currentTarget.hasPointerCapture(T.pointerId)&&T.currentTarget.releasePointerCapture(T.pointerId)},onPointerCancel:()=>{h.current=null},onDoubleClick:()=>q(75),onKeyDown:T=>{if(T.key==="ArrowUp"||T.key==="ArrowDown"){T.preventDefault();let D=T.key==="ArrowUp"?-2:2;q(G=>Math.max(25,Math.min(90,G+D)))}else T.key==="Home"&&(T.preventDefault(),q(75))}})]})}function Yg({column:e,row:t}){return e==="chapter"||e==="task"||e==="version"?(0,a.jsx)("td",{children:(0,a.jsx)("code",{children:t[e]})}):e==="idea"?(0,a.jsx)("td",{dangerouslySetInnerHTML:{__html:t.idea_html}}):e==="status"?(0,a.jsx)("td",{children:(0,a.jsx)("span",{className:"scope-status","data-status":t.status,title:t.status,children:t.status_label})}):(0,a.jsx)("td",{children:t[e]})}function Qg({front:e}){let t=e.scope_columns??["chapter","task","idea","priority"];return(0,a.jsxs)(bs,{header:e.header_html,footer:e.footer_html,left:e.left_margin_html,right:e.right_margin_html,className:"front-sheet",children:[(0,a.jsxs)("section",{className:"front-scope front-goal",children:[(0,a.jsx)("h2",{children:e.goal_title}),(0,a.jsx)(Ft,{html:e.goal_html})]}),(0,a.jsxs)("section",{className:"front-scope front-card-scope",children:[(0,a.jsx)("h2",{children:e.scope_title}),e.scope_html&&(0,a.jsx)(Ft,{html:e.scope_html}),(0,a.jsx)("div",{className:"scope-table-wrap",children:(0,a.jsxs)("table",{className:"scope-table scope-table--task",children:[(0,a.jsx)("thead",{children:(0,a.jsx)("tr",{children:e.scope_headers.map(n=>(0,a.jsx)("th",{children:n},n))})}),(0,a.jsx)("tbody",{children:e.scope_rows.map(n=>(0,a.jsx)("tr",{className:n.key?"scope-row--key":"",children:t.map(r=>(0,a.jsx)(Yg,{column:r,row:n},r))},`${n.chapter}-${n.task}`))})]})})]})]})}function qg({taskRef:e,step:t}){return(0,a.jsxs)("li",{id:`${e}-${t.id}`,children:[(0,a.jsx)("strong",{children:t.title}),(0,a.jsx)(Ft,{html:t.content_html})]})}function Xg({taskRef:e,block:t}){let n=t.kind==="exercise"?"\u0106wiczenie":"Block";return(0,a.jsxs)("section",{className:`task-block task-block--${t.kind}`,id:`${e}-${t.id}`,"data-stem-nav":"block",children:[(0,a.jsxs)("header",{children:[(0,a.jsx)("span",{children:n}),(0,a.jsx)("h4",{children:t.title})]}),(0,a.jsx)(Ft,{html:t.content_html}),t.steps.length>0&&(0,a.jsx)("ol",{className:"block-steps",children:t.steps.map(r=>(0,a.jsx)(qg,{taskRef:e,step:r},r.id))})]})}function Zg({task:e}){return e.flow.length?(0,a.jsxs)("article",{className:"task-flow",id:e.ref,"data-stem-nav":"task",children:[(0,a.jsxs)("header",{className:"task-flow-header",children:[(0,a.jsx)("span",{children:e.ref.toUpperCase()}),(0,a.jsx)("h3",{children:e.title}),e.uuid&&(0,a.jsx)("code",{children:e.uuid})]}),e.flow.map(t=>(0,a.jsx)(Xg,{taskRef:e.ref,block:t},t.id)),(0,a.jsxs)("footer",{children:[(0,a.jsx)("strong",{children:"Task acceptance:"})," ",e.criterion]})]}):(0,a.jsxs)("article",{className:"task-legacy",id:e.ref,"data-stem-nav":"task",children:[(0,a.jsx)("strong",{children:e.ref.toUpperCase()}),(0,a.jsx)(Ft,{html:e.prompt_html??""}),(0,a.jsxs)("footer",{children:[(0,a.jsx)("strong",{children:"Task acceptance:"})," ",e.criterion]})]})}var yp={compile:"KOMPILACJA",bss:".BSS",stack:"STOS",registers:"REJESTRY",text:".TEXT"},vp=["#9bcfe2","#c4dfc0","#f4c889","#d2b6dc"];function Jg({config:e,title:t}){let n=e.arena_size??64,r=e.allocations??[5,7],o=e.symbols??[],i=`${e.storage_key??"allocator-memory-flow"}-stage`,[l,s]=(0,k.useState)(()=>Math.min(r.length,Number(localStorage.getItem(i)??0))),[u,d]=(0,k.useState)(o[0]?.id??"");(0,k.useEffect)(()=>localStorage.setItem(i,String(l)),[l,i]);let m=r.slice(0,l).reduce((_,p)=>_+p,0),y=o.find(_=>_.id===u)??o[0],g=Array.from({length:n},(_,p)=>p),f=_=>{let p=0;for(let c=0;co.some(p=>p.area===_));return(0,a.jsxs)("div",{className:"memory-react","aria-label":`Interaktywny diagram: ${t}`,children:[(0,a.jsxs)("header",{children:[(0,a.jsxs)("div",{children:[(0,a.jsx)("small",{children:"INTERAKTYWNY MODEL PAMI\u0118CI"}),(0,a.jsx)("h3",{children:t})]}),(0,a.jsxs)("div",{className:"memory-actions",children:[(0,a.jsx)("button",{"aria-pressed":l===0,onClick:()=>s(0),children:"definicje / reset"}),r.map((_,p)=>(0,a.jsxs)("button",{"aria-pressed":l===p+1,onClick:()=>s(p+1),children:["alloc(",_,")"]},`${_}-${p}`))]})]}),(0,a.jsx)("div",{className:"memory-lanes",children:b.map(_=>(0,a.jsxs)("section",{className:`memory-lane ${_}`,children:[(0,a.jsx)("b",{children:yp[_]}),o.filter(p=>p.area===_).map(p=>(0,a.jsx)("button",{className:u===p.id?"active":"",onClick:()=>d(p.id),children:(0,a.jsx)("code",{children:p.declaration})},p.id))]},_))}),(0,a.jsxs)("div",{className:"arena-wrap",children:[(0,a.jsxs)("div",{className:"arena-label",children:[(0,a.jsxs)("code",{children:["allocbuf[",n,"]"]}),(0,a.jsxs)("span",{children:["u\u017Cyte ",m," B / wolne ",n-m," B"]})]}),(0,a.jsxs)("div",{className:"arena",style:{"--allocp":m,"--arena-size":n},children:[g.map(_=>{let p=f(_);return(0,a.jsx)("i",{style:p>=0?{background:vp[p%vp.length]}:void 0},_)}),(0,a.jsxs)("span",{className:"allocp",children:["allocp \u2191 ",m]})]})]}),(0,a.jsxs)("p",{className:"memory-stage",children:[(0,a.jsxs)("strong",{children:[l+1,"/",r.length+1]})," ",(0,a.jsx)("code",{children:S})]}),y&&(0,a.jsxs)("aside",{className:"memory-inspector",children:[(0,a.jsx)("strong",{children:y.id}),(0,a.jsx)("code",{children:y.declaration}),(0,a.jsx)("span",{children:y.description})]})]})}function eh({config:e,asset:t,progress:n,onSetStatus:r}){let o=e.stages??[],i=`${e.storage_key??t.label}-uml-stage`,l=(0,k.useRef)(null),[s,u]=(0,k.useState)(""),[d,m]=(0,k.useState)(!1),[y,g]=(0,k.useState)(!1),[f,S]=(0,k.useState)(()=>Math.max(0,Math.min(o.length-1,Number(localStorage.getItem(i)??0))));(0,k.useEffect)(()=>localStorage.setItem(i,String(f)),[f,i]),(0,k.useEffect)(()=>{let c=!0;return m(!1),fetch(t.href,{cache:"no-store"}).then(h=>{if(!h.ok)throw new Error(`HTTP ${h.status}`);return h.text()}).then(h=>{let w=new DOMParser().parseFromString(h,"image/svg+xml"),C=w.documentElement;if(C.nodeName.toLowerCase()!=="svg"||w.querySelector("parsererror"))throw new Error("Niepoprawny SVG");w.querySelectorAll("script, foreignObject").forEach(A=>A.remove()),zp(C,t.tile),c&&u(C.outerHTML)}).catch(()=>{c&&m(!0)}),()=>{c=!1}},[t.href,t.tile]),(0,k.useEffect)(()=>{let c=l.current?.querySelector("svg");if(!c)return;c.setAttribute("role","img"),c.setAttribute("aria-label",t.alt),c.querySelectorAll("[data-uml-stage]").forEach(C=>{C.classList.remove("uml-stage-region","uml-stage-region-bg","uml-stage-region-outline","uml-stage-region-active","uml-stage-region-completed"),C.removeAttribute("data-uml-stage"),C.removeAttribute("data-uml-stage-label"),C.removeAttribute("role"),C.removeAttribute("tabindex"),C.removeAttribute("aria-label")});let h=Array.from(c.querySelectorAll("text")),w=Array.from(c.querySelectorAll("rect"));o.forEach((C,A)=>{if(!C.svg_label)return;let P=h.find(q=>(q.textContent??"").trim().startsWith(C.svg_label)),z=Number(P?.getAttribute("y"));if(!P||!Number.isFinite(z))return;let U=w.map(q=>{let V=Number(q.getAttribute("y")),Re=Number(q.getAttribute("height")),Se=Number(q.getAttribute("width")),J=q.getAttribute("style")??"",at=Number(J.match(/stroke-width:\s*([\d.]+)/)?.[1]??q.getAttribute("stroke-width")??0);return{rect:q,y:V,height:Re,width:Se,strokeWidth:at,area:Se*Re}}).filter(({y:q,height:V,width:Re,strokeWidth:Se})=>Number.isFinite(q)&&Number.isFinite(V)&&Number.isFinite(Re)&&Se>=2&&q<=z&&q+V>=z).sort((q,V)=>q.area-V.area),F=U[0];if(!F)return;let ae=U.filter(({y:q,height:V,width:Re})=>Math.abs(q-F.y)<.1&&Math.abs(V-F.height)<.1&&Math.abs(Re-F.width)<.1),me=!!(C.progress_id&&n?.items?.[C.progress_id]?.status==="approved");ae.forEach(({rect:q},V)=>{let Re=q.getAttribute("fill")!=="none";q.dataset.umlStage=String(A),q.dataset.umlStageLabel=C.label,q.classList.add("uml-stage-region",Re?"uml-stage-region-bg":"uml-stage-region-outline"),q.classList.toggle("uml-stage-region-active",A===f),q.classList.toggle("uml-stage-region-completed",me),V===0&&(q.setAttribute("role","button"),q.setAttribute("tabindex","0"),q.setAttribute("aria-label",`Poka\u017C etap ${C.label}`))})})},[t.alt,n,f,o,s]);let b=(c,h)=>{let w=l.current?.querySelector("svg");if(!w)return;let C=Array.from(w.querySelectorAll(".uml-stage-region-bg[data-uml-stage]")).filter(P=>{let z=P.getBoundingClientRect();return c>=z.left&&c<=z.right&&h>=z.top&&h<=z.bottom}).sort((P,z)=>{let U=P.getBoundingClientRect(),F=z.getBoundingClientRect();return U.width*U.height-F.width*F.height})[0],A=Number(C?.dataset.umlStage);Number.isInteger(A)&&S(A)},_=c=>{if(c.key!=="Enter"&&c.key!==" ")return;let h=c.target,w=Number(h.dataset?.umlStage);Number.isInteger(w)&&(c.preventDefault(),S(w))},p=o[f];return(0,a.jsxs)("div",{className:"uml-react",children:[(0,a.jsxs)("header",{children:[(0,a.jsxs)("div",{children:[(0,a.jsx)("small",{children:"KANONICZNY DIAGRAM UML \xB7 PLANTUML"}),(0,a.jsx)("h3",{children:"Reset i dwa przydzia\u0142y liniowe"})]}),(0,a.jsx)("div",{className:"uml-actions",children:o.map((c,h)=>(0,a.jsxs)("button",{"aria-pressed":f===h,"data-completed":c.progress_id&&n?.items?.[c.progress_id]?.status==="approved"?"true":"false",onClick:()=>S(h),children:[c.progress_id&&n?.items?.[c.progress_id]?.status==="approved"&&(0,a.jsx)("span",{"aria-hidden":"true",children:"\u2713 "}),c.label]},c.id))})]}),(0,a.jsxs)("div",{ref:l,className:"uml-canvas",onClick:c=>b(c.clientX,c.clientY),onKeyDown:_,children:[s?(0,a.jsx)("div",{className:`uml-svg-host${t.tile?" is-tiled":""}`,style:vs(t.tile),dangerouslySetInnerHTML:{__html:s}}):(0,a.jsx)("img",{src:t.href,alt:t.alt}),d&&(0,a.jsx)("span",{className:"uml-inline-warning",children:"Widok statyczny \u2014 nie uda\u0142o si\u0119 wczyta\u0107 interaktywnego SVG."})]}),p&&(0,a.jsxs)("aside",{className:"uml-stage",children:[(0,a.jsx)("strong",{children:p.label}),(0,a.jsx)("span",{children:p.description}),p.code_ref&&(0,a.jsx)("code",{children:p.code_ref})]}),p?.progress_id&&(0,a.jsxs)("footer",{className:"uml-approval",children:[(0,a.jsx)("span",{children:n?.items?.[p.progress_id]?.status==="approved"?"Ten stan jest zatwierdzony i zapisany w JSON-ie zaj\u0119\u0107.":"Kursor wybiera stan; zatwierdzenie zapisuje go w JSON-ie zaj\u0119\u0107."}),(0,a.jsx)("button",{disabled:!n||y,onClick:async()=>{if(!p.progress_id||!n)return;let c=n.items?.[p.progress_id]?.status==="approved";g(!0);try{await r(p.progress_id,c?"pending":"approved")}finally{g(!1)}},children:y?"Zapisywanie\u2026":n?.items?.[p.progress_id]?.status==="approved"?"Cofnij zatwierdzenie":"Zatwierd\u017A stan"})]})]})}function th({config:e,asset:t,progress:n,onSetStatus:r,continuation:o}){let i=e.phases??[],l=i.flatMap(v=>v.steps.map(x=>({phase:v,step:x}))),s=`${e.storage_key??t.label}-uml-step`,u=`${e.storage_key??t.label}-navigation-level`,d=(0,k.useRef)(null),m=(0,k.useRef)(null),y=(0,k.useRef)(new Map),g=(0,k.useRef)(null),f=(0,k.useRef)(0),S=(0,k.useRef)(!1),b=(0,k.useRef)(null),_=(0,k.useRef)(!0),[p,c]=(0,k.useState)(""),[h,w]=(0,k.useState)(!1),[C,A]=(0,k.useState)(!1),[P,z]=(0,k.useState)(null),[U,F]=(0,k.useState)(null),[ae,me]=(0,k.useState)(!1),[q,V]=(0,k.useState)(""),[Re,Se]=(0,k.useState)(!1),[J,at]=(0,k.useState)(null),[bt,Me]=(0,k.useState)([]),[ge,yr]=(0,k.useState)(0),[se,Zt]=(0,k.useState)(()=>Math.max(0,Math.min(l.length-1,Number(localStorage.getItem(s)??0)))),[ue,T]=(0,k.useState)(()=>{let v=localStorage.getItem(u);return v==="card"||v==="task"||v==="block"||v==="phase"||v==="step"||v==="snapshot"?v:"step"});(0,k.useEffect)(()=>localStorage.setItem(s,String(se)),[se,s]),(0,k.useEffect)(()=>localStorage.setItem(u,ue),[ue,u]),(0,k.useEffect)(()=>{let v=!0;return w(!1),fetch(t.href,{cache:"no-store"}).then(x=>{if(!x.ok)throw new Error(`HTTP ${x.status}`);return x.text()}).then(x=>{let R=new DOMParser().parseFromString(x,"image/svg+xml"),M=R.documentElement;if(M.nodeName.toLowerCase()!=="svg"||R.querySelector("parsererror"))throw new Error("Niepoprawny SVG");R.querySelectorAll("script, foreignObject").forEach($=>$.remove()),zp(M,t.tile),v&&c(M.outerHTML)}).catch(()=>{v&&w(!0)}),()=>{v=!1}},[t.href,t.tile]),(0,k.useEffect)(()=>{let v=!0,x=hs(t,e);if(V("Wczytywanie uk\u0142adu\u2026"),Se(!1),!t.source_href)return z(x),F(x),V("Brak \u017Ar\xF3d\u0142a PlantUML \u2014 zapis wy\u0142\u0105czony."),()=>{v=!1};let R=t.source_href.replace(/\.puml(?:\?.*)?$/,".layout.json");return fetch(`/api/uml-layout?source=${encodeURIComponent(t.source_href)}`,{cache:"no-store"}).then(async M=>{if(!M.ok)throw new Error(`HTTP ${M.status}`);return M.json()}).catch(async()=>{let M=await fetch(R,{cache:"no-store"});return M.ok?{layout:await M.json(),source_digest:"",stale:!1}:{layout:null,source_digest:"",stale:!1}}).then(M=>{if(!v)return;let $=M.layout??hs(t,e,M.source_digest??"");z($),F($),me(!1),Se(!!M.stale),V(M.layout?"Uk\u0142ad wczytany z JSON.":"Uk\u0142ad PlantUML \u2014 brak r\u0119cznych zmian.")}).catch(M=>{v&&(z(x),F(x),V(`Nie wczytano uk\u0142adu: ${M instanceof Error?M.message:String(M)}`))}),()=>{v=!1}},[t.source_href,t.label,e.block?.id,e.task?.id]),(0,k.useEffect)(()=>{let v=m.current?.querySelector("svg");if(!v||!U)return;_g(v);let x=new Map(l.map(({step:j})=>[String(j.number).padStart(2,"0"),j.id])),R=Cg(v,x),M=new Map(R.map(j=>[j.id,j]));y.current=M;let $=R.map(j=>j.id);Me(j=>j.join("\0")===$.join("\0")?j:$),R.forEach(j=>{let E=U.elements[j.id];E&&Lg(j,E)});let H=v.viewBox.baseVal;(U.canvas.width<=0||U.canvas.height<=0)&&F(j=>j&&{...j,canvas:{...j.canvas,width:H?.width||Number(v.getAttribute("width")?.replace("px",""))||0,height:H?.height||Number(v.getAttribute("height")?.replace("px",""))||0}})},[l,p,U]),(0,k.useEffect)(()=>{let v=m.current?.querySelector("svg");if(!v)return;let x=e.kind==="uml-class"&&v.contains(document.activeElement);v.setAttribute("role","img"),v.setAttribute("aria-label",t.alt),v.classList.toggle("uml-class-svg",e.kind==="uml-class"),v.classList.toggle("uml-class-svg-active",e.kind==="uml-class"&&ue!=="card"),v.querySelectorAll(".uml-step-hit, .uml-class-focus-region").forEach(N=>N.remove()),v.querySelectorAll("[data-uml-step-element]").forEach(N=>{N.classList.remove("uml-step-element","uml-step-element-active","uml-step-element-completed","uml-step-element-tone-a","uml-step-element-tone-b"),N.removeAttribute("data-uml-step-element"),N.removeAttribute("data-uml-step-claim-area")});let R=Array.from(v.querySelectorAll("text")),M=Array.from(v.querySelectorAll("line")),$=Array.from(v.querySelectorAll("polygon"));if(e.kind==="uml-class"){let N=W=>W?Eg(W):null,I=W=>{if(!W.length)return null;let B=Math.min(...W.map(ee=>ee.x)),he=Math.min(...W.map(ee=>ee.y)),ce=Math.max(...W.map(ee=>ee.x+ee.width)),Z=Math.max(...W.map(ee=>ee.y+ee.height));return{x:B,y:he,width:ce-B,height:Z-he}},K=Array.from(v.querySelectorAll("g > *")),re=Array.from(v.querySelectorAll("[id]"));l.forEach(({step:W},B)=>{let he=W.svg_label??String(W.number).padStart(2,"0"),ce=R.find(ye=>(ye.textContent??"").trim().startsWith(he));if(!ce)return;let Z=N(ce);if(!Z)return;let ee=Number(ce.getAttribute("y")),He=R.filter(ye=>Number.isFinite(ee)&&Math.abs(Number(ye.getAttribute("y"))-ee)<.8),Ie=W.svg_target?re.find(ye=>ye.id===W.svg_target||ye.id.startsWith(`${W.svg_target}-`))??null:null,Ke=N(Ie)??I(He.map(ye=>N(ye)).filter(ye=>ye!==null))??Z,St=Ie?.tagName.toLowerCase()==="rect",br=Ie?[Ie,ce]:He;St&&K.forEach(ye=>{let Jt=N(ye);if(!Jt||ye===Ie)return;let ws=Jt.x+Jt.width/2,ks=Jt.y+Jt.height/2;ws>=Ke.x&&ws<=Ke.x+Ke.width&&ks>=Ke.y&&ks<=Ke.y+Ke.height&&br.push(ye)});let Ip=!!(W.progress_id&&n?.items?.[W.progress_id]?.status==="approved"),xs=Math.max(1,Ke.width*Ke.height);br.forEach(ye=>{let Jt=Number(ye.dataset.umlStepClaimArea);Number.isFinite(Jt)&&Jt{let K=N.svg_label??String(N.number).padStart(2,"0"),re=R.find(ee=>(ee.textContent??"").trim()===K),W=Number(re?.getAttribute("y"));if(!re||!Number.isFinite(W))return;let B=W+5,he=!!(N.progress_id&&n?.items?.[N.progress_id]?.status==="approved"),ce=R.filter(ee=>Math.abs(Number(ee.getAttribute("y"))-W)<.8);ce.push(...M.filter(ee=>{let He=Number(ee.getAttribute("y1")),Ie=Number(ee.getAttribute("y2"));return Number.isFinite(He)&&Number.isFinite(Ie)&&Math.abs(He-Ie)<.8&&Math.abs((He+Ie)/2-B)<=14})),ce.push(...$.filter(ee=>{let He=(ee.getAttribute("points")??"").trim().split(/\s+/).map(St=>Number(St.split(",")[1])).filter(Number.isFinite);if(!He.length)return!1;let Ie=Math.min(...He),Ke=Math.max(...He);return Ke-Ie<=16&&Math.abs((Ie+Ke)/2-B)<=14})),ce.forEach(ee=>{ee.dataset.umlStepElement=String(I),ee.classList.add("uml-step-element"),ee.classList.toggle("uml-step-element-active",I===se),ee.classList.toggle("uml-step-element-completed",he)});let Z=document.createElementNS("http://www.w3.org/2000/svg","rect");Z.setAttribute("x",String(j)),Z.setAttribute("y",String(W-12)),Z.setAttribute("width",String(E)),Z.setAttribute("height","31"),Z.setAttribute("fill","transparent"),Z.setAttribute("pointer-events","all"),Z.setAttribute("role","button"),Z.setAttribute("tabindex","0"),Z.setAttribute("aria-label",`Poka\u017C krok ${String(N.number).padStart(2,"0")}: ${N.label}`),Z.dataset.umlStep=String(I),Z.classList.add("uml-step-hit"),Z.classList.toggle("uml-step-hit-active",ue!=="card"&&I===se),Z.classList.toggle("uml-step-hit-completed",he),v.appendChild(Z)})},[t.alt,e.kind,l,ue,n,se,p,U]),(0,k.useEffect)(()=>{let v=m.current?.querySelector("svg");if(v&&(v.querySelectorAll(".uml-layout-hit,.uml-layout-resize").forEach(x=>x.remove()),v.classList.toggle("uml-layout-editing",C),!(!C||!U)))for(let x of y.current.values()){let R=U.elements[x.id]??mo(x),M=document.createElementNS("http://www.w3.org/2000/svg","rect");M.setAttribute("x",String(R.x)),M.setAttribute("y",String(R.y)),M.setAttribute("width",String(Math.max(12,R.width))),M.setAttribute("height",String(Math.max(12,R.height))),M.setAttribute("tabindex","0"),M.setAttribute("role","button"),M.setAttribute("aria-label",`Edytuj element UML ${x.id}`),M.dataset.umlLayoutId=x.id,M.dataset.umlLayoutAction="move",M.classList.add("uml-layout-hit"),x.id===J&&M.classList.add("is-selected");let $=document.createElementNS("http://www.w3.org/2000/svg","title");if($.textContent=`${x.id} \xB7 przeci\u0105gnij, aby zmieni\u0107 po\u0142o\u017Cenie`,M.appendChild($),v.appendChild(M),x.id===J){let H=Math.max(8,Math.min(14,Math.min(R.width,R.height)*.1)),j=document.createElementNS("http://www.w3.org/2000/svg","rect");j.setAttribute("x",String(R.x+R.width-H/2)),j.setAttribute("y",String(R.y+R.height-H/2)),j.setAttribute("width",String(H)),j.setAttribute("height",String(H)),j.dataset.umlLayoutId=x.id,j.dataset.umlLayoutAction="resize",j.classList.add("uml-layout-resize"),v.appendChild(j)}}},[p,C,U,J,bt]),(0,k.useEffect)(()=>{C&&(!J||!y.current.has(J))&&at(bt[0]??null)},[C,bt,J]),(0,k.useEffect)(()=>{if(ge===0||f.current===ge)return;let v=!1,x=0,R=$=>{if(v)return;let H=m.current?.querySelector(`.uml-step-hit[data-uml-step="${se}"]`);if(!H)return;if(document.querySelector(".viewer-chrome")?.classList.contains("is-nvim-fit")){f.current=ge;return}let E=Lp(H);if(!E){f.current=ge;return}let N=xg(H);if(!N){let re=Sg(H,E),W=re===0?pp(H,E):0,B=re===0?dp(H,W):re;if($Dn){x=window.requestAnimationFrame(()=>R($+1));return}f.current=ge;return}let I=pp(H,N);if(Math.abs(I)<=Dn){f.current=ge;return}let K=dp(H,I);if($Dn){x=window.requestAnimationFrame(()=>R($+1));return}f.current=ge},M=window.requestAnimationFrame(()=>R(0));return()=>{v=!0,window.cancelAnimationFrame(M),window.cancelAnimationFrame(x)}},[ge,se,p]);let D=(v,x,R=ue,M=!0)=>{let $={task:e.task??null,block:e.block??null,phase:{id:v.phase.id,label:v.phase.label},step:v.step,focusLevel:R,activate:x&&document.documentElement.dataset.nvimSyncMode==="on"},H=()=>{window.dispatchEvent(new CustomEvent("stem:nvim-step",{detail:$}))};if(!M){H();return}let j=fetch("/api/navigation/current",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({task:$.task,block:$.block,phase:$.phase,step:{id:$.step.id,number:$.step.number,label:$.step.label,mode:$.step.mode??($.step.snapshot_ref?"RUN":"CODE"),code_ref:$.step.code_ref??null,event_id:$.step.event_id??null,strategy_ref:$.step.strategy_ref??null},snapshot_ref:$.step.snapshot_ref??null,focus_level:$.focusLevel,sync_requested:!!$.activate,actor:document.documentElement.dataset.cardClientId??"browser"})});$.activate?j.then(H,H):(H(),j.catch(()=>{}))},G=(v,x=!1,R=ue,M=!0)=>{let $=Math.max(0,Math.min(l.length-1,v)),H=l[$];if(H){if(T(R),$===se){D(H,x,R,M);return}yr(j=>j+1),S.current=x,b.current=R,_.current=M,Zt($)}},te=(v,x)=>{let R=m.current?.querySelector("svg"),M=R?.getScreenCTM();if(!R||!M)return null;let $=R.createSVGPoint();return $.x=v,$.y=x,$.matrixTransform(M.inverse())},st=v=>{if(!C||!U)return;let x=v.target?.closest(".uml-layout-hit[data-uml-layout-id],.uml-layout-resize[data-uml-layout-id]"),R=x?.dataset.umlLayoutId,M=R?y.current.get(R):null,$=te(v.clientX,v.clientY);if(!R||!M||!$)return;v.preventDefault(),v.stopPropagation();let H=U.elements[R]??mo(M);g.current={id:R,action:x?.dataset.umlLayoutAction==="resize"?"resize":"move",pointerId:v.pointerId,startX:$.x,startY:$.y,initial:H},at(R),F(j=>j&&{...j,elements:{...j.elements,[R]:H}}),v.currentTarget.setPointerCapture(v.pointerId)},xt=v=>{let x=g.current;if(!x||x.pointerId!==v.pointerId)return;let R=te(v.clientX,v.clientY);if(!R)return;v.preventDefault();let M=R.x-x.startX,$=R.y-x.startY,H=x.action==="resize"?{...x.initial,width:Math.max(24,x.initial.width+M),height:Math.max(18,x.initial.height+$)}:{...x.initial,x:x.initial.x+M,y:x.initial.y+$};F(j=>j&&{...j,elements:{...j.elements,[x.id]:H}}),me(!0)},ze=v=>{let x=g.current;!x||x.pointerId!==v.pointerId||(g.current=null,v.currentTarget.hasPointerCapture(v.pointerId)&&v.currentTarget.releasePointerCapture(v.pointerId))},oe=(v,x)=>{let R=y.current.get(v);R&&(F(M=>{if(!M)return M;let $=M.elements[v]??mo(R);return{...M,elements:{...M.elements,[v]:x($)}}}),me(!0))},wt=async()=>{if(!U||!t.source_href)return;let v=Object.fromEntries(Array.from(y.current.values()).map(R=>[R.id,U.elements[R.id]??mo(R)])),x={...U,elements:v};V("Zapisywanie uk\u0142adu\u2026");try{let R=await fetch("/api/uml-layout",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({source:t.source_href,layout:x,actor:document.documentElement.dataset.cardClientId??"browser"})});if(!R.ok)throw new Error((await R.json().catch(()=>null))?.message??`HTTP ${R.status}`);let M=await R.json();z(M.layout),F(M.layout),me(!1),Se(!1),V(`Zapisano ${Object.keys(M.layout.elements).length} element\xF3w w JSON.`)}catch(R){V(`B\u0142\u0105d zapisu: ${R instanceof Error?R.message:String(R)}`)}},kn=()=>{P&&(F(P),me(!1),V("Przywr\xF3cono ostatnio zapisany uk\u0142ad."))},Dt=async()=>{if(!(!t.source_href||!window.confirm("Usun\u0105\u0107 r\u0119czny uk\u0142ad i wr\xF3ci\u0107 do geometrii PlantUML?"))){V("Resetowanie uk\u0142adu\u2026");try{let v=await fetch(`/api/uml-layout?source=${encodeURIComponent(t.source_href)}&actor=${encodeURIComponent(document.documentElement.dataset.cardClientId??"browser")}`,{method:"DELETE"});if(!v.ok)throw new Error(`HTTP ${v.status}`);let x=hs(t,e,P?.source_digest??"");z(x),F(x),me(!1),at(null),V("Przywr\xF3cono automatyczny uk\u0142ad PlantUML.")}catch(v){V(`B\u0142\u0105d resetu: ${v instanceof Error?v.message:String(v)}`)}}},Q=(v,x)=>{if(C)return;let R=Array.from(m.current?.querySelectorAll(".uml-step-hit[data-uml-step]")??[]).filter($=>{let H=$.getBoundingClientRect();return v>=H.left&&v<=H.right&&x>=H.top&&x<=H.bottom}).sort(($,H)=>{let j=$.getBoundingClientRect(),E=H.getBoundingClientRect();return Math.abs(x-(j.top+j.bottom)/2)-Math.abs(x-(E.top+E.bottom)/2)}),M=Number(R[0]?.dataset.umlStep);Number.isInteger(M)&&G(M,!1,"step")},Ae=v=>{if(C||v.key!=="Enter"&&v.key!==" ")return;let x=v.target,R=Number(x.dataset?.umlStep);Number.isInteger(R)&&(v.preventDefault(),G(R,v.key==="Enter","step"))},ut=v=>{let x=l.findIndex(R=>R.phase.id===v.id);x>=0&&G(x,!1,"phase")},Ne=l[se];if((0,k.useEffect)(()=>{Ne&&(D(Ne,S.current,b.current??ue,_.current),S.current=!1,b.current=null,_.current=!0)},[Ne?.phase.id,Ne?.step.id,e.block]),(0,k.useEffect)(()=>{let v=x=>{let R=x.detail;if(!R||e.task?.id&&R.task.id!==e.task.id||e.block?.id&&R.block.id!==e.block.id)return;let M=l.findIndex($=>$.phase.id===R.phase.id&&$.step.id===R.step.id);if(M<0){T("card");return}G(M,!1,R.focus_level,!1)};return window.addEventListener("stem:navigation-command",v),()=>window.removeEventListener("stem:navigation-command",v)},[e.block?.id,e.task?.id,l,ue,se]),(0,k.useEffect)(()=>{let v=x=>{if(x.metaKey||C||x.target?.closest("input, textarea, select, [contenteditable='true']"))return;let M=d.current;if(!M)return;let $=Array.from(document.querySelectorAll("[data-stem-nav='uml-block']")),H=window.innerHeight/2;if($.sort((K,re)=>{let W=K.getBoundingClientRect(),B=re.getBoundingClientRect();return Math.abs((W.top+W.bottom)/2-H)-Math.abs((B.top+B.bottom)/2-H)})[0]!==M)return;if(x.key==="Enter"&&x.ctrlKey&&!x.altKey&&!x.shiftKey){if(!Ne?.step.progress_id||!n)return;x.preventDefault(),x.stopPropagation();let K=n.items?.[Ne.step.progress_id]?.status==="approved";r(Ne.step.progress_id,K?"pending":"approved");return}if(x.key==="Enter"&&!x.altKey&&!x.shiftKey){if(!Ne)return;x.preventDefault(),x.stopPropagation(),D(Ne,!0,ue);return}let E=["card","task","block","phase","step","snapshot"];if((x.key==="ArrowLeft"||x.key==="ArrowRight"||x.key==="Escape")&&!x.altKey&&!x.ctrlKey&&!x.shiftKey){let K=x.key==="ArrowRight"?1:-1,re=E[Math.max(0,Math.min(E.length-1,E.indexOf(ue)+K))];x.preventDefault(),x.stopPropagation(),T(re),Ne&&D(Ne,!1,re);return}if(x.key!=="ArrowUp"&&x.key!=="ArrowDown"||ue==="card"&&!x.altKey&&!x.ctrlKey&&!x.shiftKey)return;let N=x.key==="ArrowUp"?-1:1,I=ue;if(x.altKey&&x.shiftKey&&!x.ctrlKey)I="snapshot";else if(x.ctrlKey&&x.shiftKey&&!x.altKey)I="step";else if(x.altKey&&!x.ctrlKey&&!x.shiftKey)I="task";else if(x.ctrlKey&&!x.altKey&&!x.shiftKey)I="block";else if(x.shiftKey&&!x.altKey&&!x.ctrlKey)I="phase";else if(x.altKey||x.ctrlKey||x.shiftKey)return;x.preventDefault(),x.stopPropagation(),fetch("/api/navigation/move",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({level:I,delta:N,sync_requested:!1,actor:document.documentElement.dataset.cardClientId??"browser"})}).then(K=>K.ok?K.json():Promise.reject(new Error(`HTTP ${K.status}`))).then(K=>{K.current&&window.dispatchEvent(new CustomEvent("stem:navigation-command",{detail:K.current}))}).catch(()=>{})};return window.addEventListener("keydown",v),()=>window.removeEventListener("keydown",v)},[Ne,l,ue,r,n,C]),!Ne)return null;let{phase:Ee,step:vr}=Ne,kt=l.filter(v=>v.phase.id===Ee.id),yo=e.block?.label.match(/^A[1-8]\b/)?.[0]??"UML",vo=(e.title??e.block?.label??t.caption).replace(/^A[1-8]\s*[·—:-]\s*/i,""),jn=J?y.current.get(J)??null:null,ct=jn?U?.elements[jn.id]??mo(jn):null;return(0,a.jsxs)("div",{ref:d,className:"uml-react uml-snapshot-react","data-stem-nav":"uml-block","data-task-id":e.task?.id,"data-block-id":e.block?.id,"data-navigation-level":ue,children:[(0,a.jsx)("header",{className:"uml-snapshot-header",children:(0,a.jsxs)("div",{className:"uml-header-first-line",children:[(0,a.jsxs)("h3",{children:[(0,a.jsx)("span",{children:yo})," \u2014 ",vo,t.tile&&(0,a.jsxs)("small",{className:"uml-tile-part",children:["cz\u0119\u015B\u0107 ",t.tile.index,"/",t.tile.count," \xB7 r",t.tile.row," c",t.tile.column]})]}),(0,a.jsxs)("div",{className:"uml-header-navigation",children:[(0,a.jsx)(Pp,{continuation:o}),t.source_href&&(0,a.jsx)("button",{className:`uml-edit-toggle${C?" is-active":""}`,"aria-pressed":C,title:"R\u0119czna edycja po\u0142o\u017Cenia i parametr\xF3w blok\xF3w UML",onClick:()=>A(v=>!v),children:C?"ZAMKNIJ EDIT":"EDIT"}),(0,a.jsx)("div",{className:"uml-phase-actions","aria-label":"Fazy diagramu",children:i.map(v=>(0,a.jsx)("button",{"aria-pressed":Ee.id===v.id,onClick:()=>ut(v),children:v.label},v.id))}),(0,a.jsx)("div",{className:"uml-step-actions","aria-label":`Checkpointy fazy ${Ee.label}`,children:kt.map(v=>{let x=l.indexOf(v),R=!!(v.step.progress_id&&n?.items?.[v.step.progress_id]?.status==="approved");return(0,a.jsx)("button",{"aria-label":`Krok ${v.step.number}: ${v.step.label}`,"aria-pressed":ue!=="card"&&x===se,"data-completed":R?"true":"false","data-mode":v.step.mode??"RUN",title:`${v.step.mode??"RUN"} \xB7 ${v.step.label}`,onClick:()=>G(x),children:String(v.step.number).padStart(2,"0")},v.step.id)})})]})]})}),(0,a.jsxs)("div",{className:"uml-snapshot-layout",children:[(0,a.jsxs)("div",{ref:m,className:`uml-canvas uml-step-canvas${C?" is-layout-editing":""}`,onClick:v=>Q(v.clientX,v.clientY),onKeyDown:Ae,onPointerDown:st,onPointerMove:xt,onPointerUp:ze,onPointerCancel:ze,children:[p?(0,a.jsx)("div",{className:`uml-svg-host${t.tile?" is-tiled":""}`,style:vs(t.tile),dangerouslySetInnerHTML:{__html:p}}):(0,a.jsx)("img",{src:t.href,alt:t.alt}),h&&(0,a.jsx)("span",{className:"uml-inline-warning",children:"Widok statyczny \u2014 wybierz krok przyciskiem nad diagramem."})]}),C&&U&&(0,a.jsxs)("aside",{className:"uml-layout-editor","aria-label":"Edytor uk\u0142adu UML",children:[(0,a.jsxs)("div",{className:"uml-layout-editor-title",children:[(0,a.jsx)("strong",{children:"UML layout"}),(0,a.jsx)("span",{children:ae?"niezapisane zmiany":"zapisany"}),Re&&(0,a.jsx)("b",{children:"\u0179r\xF3d\u0142o PlantUML zmieni\u0142o si\u0119"})]}),(0,a.jsxs)("label",{children:["Element",(0,a.jsx)("select",{value:J??"",onChange:v=>at(v.target.value||null),children:bt.map(v=>(0,a.jsx)("option",{value:v,children:v},v))})]}),J&&ct&&(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("div",{className:"uml-layout-number-grid",children:["x","y","width","height"].map(v=>(0,a.jsxs)("label",{children:[v,(0,a.jsx)("input",{type:"number",step:"1",min:v==="width"||v==="height"?12:void 0,value:Math.round(ct[v]*100)/100,onChange:x=>oe(J,R=>({...R,[v]:Number(x.target.value)}))})]},v))}),(0,a.jsxs)("label",{className:"uml-layout-editor-text",children:["Tekst bloku \u2014 jeden wiersz SVG na lini\u0119",(0,a.jsx)("textarea",{rows:Math.max(3,Math.min(10,ct.text?.lines?.length??3)),value:(ct.text?.lines??[]).join(` +`),onChange:v=>oe(J,x=>({...x,text:{...x.text,title:v.target.value.split(` +`)[0]??"",description:v.target.value.split(` `).slice(1).join(` -`),lines:x.target.value.split(` -`)}}))})]}),(0,a.jsxs)("div",{className:"uml-layout-style-grid",children:[(0,a.jsxs)("label",{children:["Font",(0,a.jsx)("input",{type:"number",min:"4",max:"96",step:"0.5",value:ut.text?.font_size??12,onChange:x=>ne(Q,S=>({...S,text:{...S.text,font_size:Number(x.target.value)}}))})]}),(0,a.jsxs)("label",{children:["Wyr\xF3wnanie",(0,a.jsxs)("select",{value:ut.text?.align??"left",onChange:x=>ne(Q,S=>({...S,text:{...S.text,align:x.target.value}})),children:[(0,a.jsx)("option",{value:"left",children:"left"}),(0,a.jsx)("option",{value:"center",children:"center"}),(0,a.jsx)("option",{value:"right",children:"right"})]})]}),(0,a.jsxs)("label",{children:["Wype\u0142nienie",(0,a.jsx)("input",{type:"color",value:ut.style?.fill??"#edf6fa",onChange:x=>ne(Q,S=>({...S,style:{...S.style,fill:x.target.value}}))})]}),(0,a.jsxs)("label",{children:["Obramowanie",(0,a.jsx)("input",{type:"color",value:ut.style?.stroke??"#2c7794",onChange:x=>ne(Q,S=>({...S,style:{...S.style,stroke:x.target.value}}))})]}),(0,a.jsxs)("label",{children:["Linia",(0,a.jsx)("input",{type:"number",min:"0.5",max:"12",step:"0.25",value:ut.style?.stroke_width??1.5,onChange:x=>ne(Q,S=>({...S,style:{...S.style,stroke_width:Number(x.target.value)}}))})]})]})]}),(0,a.jsxs)("div",{className:"uml-layout-editor-actions",children:[(0,a.jsx)("button",{className:"is-primary",disabled:!ke,onClick:()=>void st(),children:"Zapisz uk\u0142ad"}),(0,a.jsx)("button",{disabled:!ke,onClick:Ye,children:"Cofnij zmiany"}),(0,a.jsx)("button",{className:"is-danger",onClick:()=>void wn(),children:"Reset PlantUML"})]}),(0,a.jsx)("output",{children:G})]})]})]})}function Vg(e){return e.config.phases?.length?(0,a.jsx)(Ug,{...e}):(0,a.jsx)(jg,{...e})}function Bg({asset:e,continuation:t}){let n=e.tile;if(!n)return(0,a.jsx)("img",{src:e.href,alt:e.alt,loading:"lazy"});let r=e.diagram_block_label?.match(/^A[1-8]\b/)?.[0]??e.diagram_title?.match(/^A[1-8]\b/)?.[0]??e.caption.match(/^A[1-8]\b/)?.[0]??"UML",o=(e.diagram_title??e.caption).replace(/^A[1-8]\s*[·—:-]\s*/i,"");return(0,a.jsxs)("div",{className:"uml-react uml-snapshot-react uml-static-tile",children:[(0,a.jsxs)("header",{className:"uml-snapshot-header",children:[(0,a.jsxs)("div",{className:"uml-header-first-line",children:[(0,a.jsxs)("h3",{children:[(0,a.jsx)("span",{children:r})," \u2014 ",o,(0,a.jsxs)("small",{className:"uml-tile-part",children:["cz\u0119\u015B\u0107 ",n.index,"/",n.count," \xB7 r",n.row," c",n.column]})]}),(0,a.jsxs)("div",{className:"uml-header-navigation",children:[(0,a.jsx)(_p,{continuation:t}),(0,a.jsx)("div",{className:"uml-phase-actions","aria-label":"Fazy logicznego diagramu",children:(e.diagram_phase_labels??[]).map(i=>(0,a.jsx)("span",{children:i},i))})]})]}),e.diagram_description&&(0,a.jsx)("p",{className:"uml-header-description",children:e.diagram_description})]}),(0,a.jsx)("div",{className:"uml-snapshot-layout",children:(0,a.jsx)("div",{className:"uml-canvas uml-step-canvas",children:(0,a.jsx)("div",{className:"uml-svg-host is-tiled is-static",style:hs(n),children:(0,a.jsx)("div",{className:"uml-static-crop",style:{width:`${n.width}px`,height:`${n.height}px`},children:(0,a.jsx)("img",{src:e.href,alt:e.alt,style:{width:`${n.full_width}px`,height:`${n.full_height}px`,transform:`translate(${-(n.x-n.full_x)}px, ${-(n.y-n.full_y)}px)`}})})})})})]})}function Hg({asset:e,number:t,progress:n,onSetStatus:r,continuation:o}){let i=e.interactive?.kind,l=!!i;return(0,a.jsxs)("figure",{className:`card-asset asset-${e.kind} ${l?"asset-interactive":""}`,id:e.label.replace(":","-"),children:[i==="uml-sequence"||i==="uml-class"?(0,a.jsx)(Vg,{config:e.interactive,asset:e,progress:n,onSetStatus:r,continuation:o}):i==="allocator-memory-flow"?(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(Dg,{config:e.interactive,title:e.caption}),(0,a.jsx)("img",{className:"asset-static-fallback",src:e.href,alt:e.alt})]}):e.tile?(0,a.jsx)(Bg,{asset:e,continuation:o}):(0,a.jsx)("a",{href:e.href,target:"_blank",rel:"noopener",children:(0,a.jsx)("img",{src:e.href,alt:e.alt,loading:"lazy",style:{width:`${e.width*100}%`}})}),e.source_href&&(0,a.jsx)("a",{className:"asset-source-link",href:e.source_href,target:"_blank",rel:"noopener",children:"\u0179r\xF3d\u0142o PlantUML"}),(0,a.jsxs)("figcaption",{children:["Rys. ",e.figure_number??t,". ",e.caption]})]})}function Kg({steps:e,progress:t,onCycle:n}){if(!e.length)return null;let r={pending:"\u25CB niezatwierdzony",approved:"\u25CF zatwierdzony"};return(0,a.jsx)("div",{className:"step-map",children:e.map(o=>{let i=t?.items?.[o.id]?.status??"pending";return(0,a.jsxs)("div",{className:`step-row ${i==="approved"?"lesson-progress-completed":""}`,children:[(0,a.jsx)("button",{className:"lesson-progress-control","data-status":i,onClick:()=>n(o.id,i),disabled:!t,children:r[i]}),(0,a.jsx)("span",{className:"step-title",children:o.title})]},o.id)})})}function Wg({section:e,progress:t,onCycle:n,onSetStatus:r,figureOffset:o}){let i=vg(e);return(0,a.jsxs)(ys,{header:e.header_html,left:e.left_margin_html,right:e.right_margin_html,className:`section-sheet${e.assets.length?" section-sheet--asset":""} sheet--${e.page_orientation||"portrait"}`,children:[(0,a.jsx)("div",{id:e.id,className:"section-anchor"}),e.show_heading&&(0,a.jsxs)("h2",{className:"section-heading",children:[(0,a.jsx)("span",{className:"section-index",children:e.index}),(0,a.jsx)("span",{className:"section-title",children:e.title})]}),(0,a.jsx)(Kg,{steps:e.steps,progress:t,onCycle:n}),e.content_html&&(0,a.jsx)(Yt,{html:e.content_html}),(0,a.jsx)("div",{className:"tasks",children:e.tasks.map(l=>(0,a.jsx)(Fg,{task:l},l.ref))}),e.assets.map((l,s)=>(0,a.jsx)(Hg,{asset:l,number:o+s+1,progress:t,onSetStatus:r,continuation:i},l.label)),e.tasks.map(l=>l.conclusion_html&&(0,a.jsxs)("aside",{className:"task-conclusion",children:[(0,a.jsx)("strong",{children:"WNIOSEK"}),(0,a.jsx)(Yt,{html:l.conclusion_html})]},`${l.ref}-conclusion`))]})}function Gg({progress:e,error:t}){if(!e?.summary&&!t)return null;let n=e?.summary.counts;return(0,a.jsxs)("section",{className:"lesson-progress-topbar","aria-label":"Przebieg zaj\u0119\u0107",children:[(0,a.jsx)("strong",{children:"PRZEBIEG"}),n&&(0,a.jsxs)("output",{title:"Zatwierdzone kroki",children:[n.approved,"/",e.summary.total]}),t&&(0,a.jsx)("span",{className:"lesson-progress-error",title:t,children:"!"}),(0,a.jsx)("a",{href:"/api/report/teams.md",target:"_blank",rel:"noopener",title:"Otw\xF3rz raport do Teams",children:"Teams"}),(0,a.jsx)("a",{href:"/api/report/lesson.html",target:"_blank",rel:"noopener",title:"Otw\xF3rz \u015Blad lekcji ze zrzutami",children:"\u015Alad"})]})}var In=[{id:"u01",name:"Alicja Nowak",laptop:3,connection:"online",sync:"follow",position:"A5\xB708"},{id:"u02",name:"Bartosz Kowalski",laptop:7,connection:"online",sync:"follow",position:"A5\xB708"},{id:"u03",name:"Celina Wi\u015Bniewska",laptop:11,connection:"away",sync:"paused",position:"A5\xB705"},{id:"u04",name:"Dawid W\xF3jcik",laptop:14,connection:"offline",sync:"follow",position:"\u2014"},{id:"u05",name:"Emilia Kami\u0144ska",laptop:18,connection:"online",sync:"local",position:"A3\xB702"},{id:"u06",name:"Filip Lewandowski",laptop:22,connection:"error",sync:"follow",position:"A5\xB706"},{id:"u07",name:"Gabriela Zieli\u0144ska",laptop:24,connection:"online",sync:"follow",position:"A5\xB708"}];function Yg(e){let t=new Map,n=(r,o)=>{let i=r.trim()||"task",l=t.get(i);return l||(l={id:i,label:o.trim()||i.toUpperCase(),blocks:[],exercises:[]},t.set(i,l)),l};for(let r of e.sections){for(let o of r.assets){let i=o.interactive;if(!i?.task||!i.block)continue;let l=n(i.task.id,i.task.label),s=`diagram:${i.block.id}`,u=l.blocks.find(d=>d.id===s);u||(u={id:s,label:i.block.label,kind:"diagram",phases:[],steps:[]},l.blocks.push(u));for(let d of i.phases??[]){let m=u.phases.find(y=>y.id===d.id);m||(m={...d,steps:[]},u.phases.push(m));for(let y of d.steps)m.steps.some(g=>g.id===y.id)||m.steps.push(y)}}for(let o of r.tasks){let i=n(o.ref,o.title);i.label=o.title||i.label;for(let l of o.flow){if(l.kind==="exercise"){i.exercises.some(u=>u.id===l.id)||i.exercises.push(l);continue}let s=`flow:${l.id}`;i.blocks.some(u=>u.id===s)||i.blocks.push({id:s,label:l.title,kind:"flow",phases:[],steps:l.steps.map((u,d)=>({id:u.id,number:d+1,label:u.title,description:u.title,mode:"RUN"}))})}}}return[...t.values()]}function hp({side:e,panels:t,activeId:n,pinnedId:r,onActiveChange:o,onPinnedChange:i}){let l=(0,N.useRef)(0),s=t.find(f=>f.id===n)??null,u=(0,N.useCallback)(()=>{window.clearTimeout(l.current)},[]),d=(0,N.useCallback)(()=>{u(),!r&&(l.current=window.setTimeout(()=>o(null),150))},[u,o,r]),m=(0,N.useCallback)(f=>{u(),r||o(f)},[u,o,r]),y=(0,N.useCallback)(f=>{if(u(),r===f){i(null),o(null);return}i(f),o(f)},[u,o,i,r]),g=(0,N.useCallback)(()=>{u(),i(null),o(null)},[u,o,i]);return(0,N.useEffect)(()=>()=>window.clearTimeout(l.current),[]),t.length?(0,a.jsxs)("div",{className:`side-panel-dock side-panel-dock--${e}`,"data-side":e,children:[(0,a.jsx)("nav",{className:"side-panel-rail","aria-label":`Panele ${e==="left"?"lewe":"prawe"}`,children:t.map(f=>{let E=n===f.id,b=r===f.id;return(0,a.jsx)("button",{type:"button",className:`side-panel-trigger${E?" is-open":""}${b?" is-pinned":""}`,style:{"--side-panel-accent":f.accent},"aria-controls":`side-panel-${e}-${f.id}`,"aria-expanded":E,"aria-pressed":b,"aria-label":`${f.title}: ${b?"odpnij":"przypnij"} panel`,title:`${f.title} \xB7 ${b?"Fixed":"Auto"}`,onMouseEnter:()=>m(f.id),onMouseLeave:d,onFocus:()=>m(f.id),onClick:()=>y(f.id),children:(0,a.jsx)("span",{children:f.railLabel})},f.id)})}),(0,a.jsx)("aside",{id:s?`side-panel-${e}-${s.id}`:void 0,className:`side-panel${s?" is-open":""}`,"aria-hidden":!s,"aria-label":s?.title,style:s?{"--side-panel-accent":s.accent}:void 0,onMouseEnter:u,onMouseLeave:d,onFocusCapture:u,children:s&&(0,a.jsxs)(a.Fragment,{children:[(0,a.jsxs)("header",{className:"side-panel-header",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)("small",{children:e==="left"?"LEWY PANEL":"PRAWY PANEL"}),(0,a.jsx)("strong",{children:s.title})]}),(0,a.jsxs)("div",{className:"side-panel-actions",children:[(0,a.jsx)("button",{type:"button",className:r===s.id?"is-pinned":"",onClick:()=>y(s.id),title:r===s.id?"Tryb Fixed \u2014 kliknij, aby przej\u015B\u0107 do Auto":"Tryb Auto \u2014 kliknij, aby przypi\u0105\u0107",children:r===s.id?"Fixed":"Auto"}),(0,a.jsx)("button",{type:"button",onClick:g,"aria-label":`Zamknij ${s.title}`,children:"\xD7"})]})]}),(0,a.jsx)("div",{className:"side-panel-body",children:s.content})]})})]}):null}function fo({id:e,depth:t,kind:n,title:r,label:o,refValue:i,stateValue:l,stateKind:s,hasChildren:u=!1,expanded:d=!1,onToggle:m,href:y,current:g=!1,unavailable:f=!1,onNavigate:E}){let b=y?(0,a.jsx)("a",{className:"card-library-tree-link",href:y,onClick:E,"aria-current":g?"page":void 0,title:g?"Poka\u017C bie\u017C\u0105c\u0105 kart\u0119":`Otw\xF3rz: ${r}`,children:o}):(0,a.jsx)("span",{className:"card-library-tree-label",title:r,children:o});return(0,a.jsxs)("div",{className:`card-library-treegrid-row is-${n}${g?" is-current":""}${f?" is-unavailable":""}`,role:"row","aria-level":t+1,"aria-expanded":u?d:void 0,"aria-disabled":f||void 0,"data-node-id":e,style:{"--card-library-depth":t},children:[(0,a.jsxs)("span",{className:"card-library-tree-title",role:"gridcell",children:[u?(0,a.jsx)("button",{className:"card-library-tree-expander",type:"button",onClick:m,"aria-label":`${d?"Zwi\u0144":"Rozwi\u0144"}: ${r}`,children:d?"\u25BE":"\u25B8"}):(0,a.jsx)("span",{className:"card-library-tree-expander is-empty","aria-hidden":"true"}),b]}),(0,a.jsx)("span",{role:"gridcell",children:i}),(0,a.jsx)("span",{role:"gridcell",children:(0,a.jsx)("b",{className:"card-library-tree-state","data-state":s,children:l})})]})}function Qg({library:e,onNavigate:t}){if(!e)return null;let n=e.subjects.reduce((d,m)=>d+m.levels.reduce((y,g)=>y+g.series.length,0),0),r=e.subjects.reduce((d,m)=>d+m.levels.reduce((y,g)=>y+g.series.reduce((f,E)=>f+E.cards.filter(b=>b.available).length,0),0),0),o=e.subjects.reduce((d,m)=>d+m.levels.reduce((y,g)=>y+g.series.reduce((f,E)=>f+E.cards.length,0),0),0),[i,l]=(0,N.useState)(()=>{let d=new Set;return e.subjects.forEach(m=>{let y=`subject:${m.id}`;m.current&&d.add(y),m.levels.forEach(g=>{let f=`${y}:level:${g.id}`;g.current&&d.add(f),g.series.forEach(E=>{let b=`${f}:series:${E.id}`;E.current&&d.add(b),E.cards.forEach(_=>{_.current&&(_.tasks?.length??0)>0&&d.add(`${b}:card:${_.id}`)})})})}),d}),s=d=>i.has(d),u=d=>{l(m=>{let y=new Set(m);return y.has(d)?y.delete(d):y.add(d),y})};return(0,a.jsxs)("div",{className:"card-library-panel",children:[(0,a.jsxs)("div",{className:"card-library-treegrid",role:"treegrid","aria-label":"Serie, karty i taski","aria-colcount":3,children:[(0,a.jsxs)("div",{className:"card-library-treegrid-row card-library-treegrid-head",role:"row",children:[(0,a.jsx)("span",{role:"columnheader",children:"DRZEWO"}),(0,a.jsx)("span",{role:"columnheader",children:"REF"}),(0,a.jsx)("span",{role:"columnheader",children:"STATUS"})]}),e.subjects.map(d=>{let m=`subject:${d.id}`;return(0,a.jsxs)(N.default.Fragment,{children:[(0,a.jsx)(fo,{id:m,depth:0,kind:"subject",title:d.title,label:(0,a.jsx)("strong",{children:d.title}),refValue:"PRZEDMIOT",stateValue:`${d.levels.length} POZ.`,hasChildren:d.levels.length>0,expanded:s(m),onToggle:()=>u(m)}),s(m)&&d.levels.map(y=>{let g=`${m}:level:${y.id}`;return(0,a.jsxs)(N.default.Fragment,{children:[(0,a.jsx)(fo,{id:g,depth:1,kind:"level",title:y.title,label:(0,a.jsx)("strong",{children:y.title}),refValue:"ROK",stateValue:`${y.series.length} SERII`,hasChildren:y.series.length>0,expanded:s(g),onToggle:()=>u(g)}),s(g)&&y.series.map(f=>{let E=`${g}:series:${f.id}`;return(0,a.jsxs)(N.default.Fragment,{children:[(0,a.jsx)(fo,{id:E,depth:2,kind:"series",title:f.title,label:(0,a.jsx)("strong",{children:f.title}),refValue:f.role==="reference"?"REF.":"SERIA",stateValue:`${f.cards.length} KART`,hasChildren:f.cards.length>0,expanded:s(E),onToggle:()=>u(E)}),s(E)&&f.cards.map(b=>{let _=`${E}:card:${b.id}`,p=b.tasks??[],c=b.current||b.available,h=b.current?"current":b.available?"online":"plan";return(0,a.jsxs)(N.default.Fragment,{children:[(0,a.jsx)(fo,{id:_,depth:3,kind:"card",title:`${b.id} \xB7 ${b.title}`,label:(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("strong",{children:b.id}),(0,a.jsx)("span",{children:b.title})]}),refValue:b.version||"\u2014",stateValue:b.current?"BIE\u017B\u0104CA":b.available?"ONLINE":"PLAN",stateKind:h,hasChildren:p.length>0,expanded:s(_),onToggle:()=>u(_),href:c?b.current?"#":b.href:void 0,current:b.current,unavailable:!c,onNavigate:t}),s(_)&&p.map(k=>{let C=b.current?`#${k.id}`:`${b.href}#${k.id}`;return(0,a.jsx)(fo,{id:`${_}:task:${k.id}`,depth:4,kind:"task",title:`${k.id.toUpperCase()} \xB7 ${k.title}`,label:(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("strong",{children:k.id.toUpperCase()}),(0,a.jsx)("span",{children:k.title})]}),refValue:"TASK",stateValue:c?"GOTOWY":"PLAN",stateKind:c?"online":"plan",href:c?C:void 0,unavailable:!c,onNavigate:t},`${_}:task:${k.id}`)})]},_)})]},E)})]},g)})]},m)})]}),(0,a.jsxs)("footer",{className:"card-library-footer",children:[(0,a.jsx)("span",{children:e.workspace||"STEM"}),(0,a.jsxs)("span",{children:[n," serii"]}),(0,a.jsxs)("span",{children:[(0,a.jsx)("i",{className:"is-online"})," ",r,"/",o," online"]}),(0,a.jsx)("kbd",{children:"Esc"})]})]})}function qg({toc:e,onNavigate:t}){return(0,a.jsxs)("nav",{className:"side-toc","aria-label":"Spis tre\u015Bci karty",children:[(0,a.jsxs)("header",{children:[(0,a.jsx)("small",{children:"KARTA PRACY"}),(0,a.jsx)("h2",{children:"Spis tre\u015Bci"})]}),(0,a.jsx)("ol",{children:e.map((n,r)=>(0,a.jsx)("li",{children:(0,a.jsxs)("a",{href:`#${n.id}`,onClick:t,children:[(0,a.jsx)("span",{children:String(r+1).padStart(2,"0")}),(0,a.jsx)("strong",{children:n.label})]})},n.id))})]})}function Xg({progress:e,error:t}){let n=e?.summary?.counts;return(0,a.jsxs)("section",{className:"side-progress","aria-label":"Przebieg zaj\u0119\u0107 i raport",children:[(0,a.jsxs)("header",{children:[(0,a.jsx)("small",{children:"DOWODY I RAPORT"}),(0,a.jsx)("h2",{children:"Przebieg zaj\u0119\u0107"})]}),(0,a.jsxs)("div",{className:"side-progress-summary",children:[(0,a.jsx)("span",{children:"Zatwierdzone kroki"}),(0,a.jsx)("strong",{children:n?`${n.approved}/${e.summary.total}`:"\u2014"})]}),t&&(0,a.jsx)("p",{className:"side-progress-error",children:t}),(0,a.jsxs)("div",{className:"side-progress-links",children:[(0,a.jsx)("a",{href:"/api/report/teams.md",target:"_blank",rel:"noopener",children:"Raport do Teams"}),(0,a.jsx)("a",{href:"/api/report/lesson.html",target:"_blank",rel:"noopener",children:"\u015Alad lekcji ze zrzutami"})]})]})}var Zg={online:"ONLINE",away:"ZAJ\u0118TY",offline:"OFFLINE",error:"B\u0141\u0104D"},Jg={follow:"SYNC",paused:"PAUZA",local:"LOKAL."},yp={present:"BY\u0141",missed:"NIE BY\u0141",pending:"OCZEK."},eh={committed:"COMMIT",working:"PRACA",missing:"BRAK"};function zp(e){let t=2166136261;for(let n=0;n>>0}function vp(e,t,n){let r=zp(`${e.id}:step:${t}`),o=r%8,i=o===0?"missed":o===1?"pending":"present",l=8+n*4+r%3,s=10+Math.floor(l/60),u=l%60,d=(e.laptop*7+r)%60;return{state:i,timestamp:i==="present"?`${String(s).padStart(2,"0")}:${String(u).padStart(2,"0")}:${String(d).padStart(2,"0")}`:"\u2014"}}function xp(e,t){let n=zp(`${e.id}:exercise:${t}`),r=n%6,o=r===0?"missing":r===1?"working":"committed";return{state:o,commit:o==="committed"?n.toString(16).padStart(8,"0").slice(0,7):"\u2014"}}function Gt({id:e,depth:t,title:n,kind:r,refValue:o,session:i,evidence:l,state:s,hasChildren:u=!1,expanded:d=!1,onToggle:m}){return(0,a.jsxs)("div",{className:`classroom-treegrid-row classroom-node-row is-${r}`,role:"row","aria-level":t+1,"aria-expanded":u?d:void 0,"data-node-id":e,style:{"--classroom-depth":t},children:[(0,a.jsxs)("span",{className:"classroom-node-title",role:"gridcell",title:n,children:[u?(0,a.jsx)("button",{className:"classroom-expander",type:"button",onClick:m,"aria-label":`${d?"Zwi\u0144":"Rozwi\u0144"}: ${n}`,children:d?"\u25BE":"\u25B8"}):(0,a.jsx)("span",{className:"classroom-expander is-empty","aria-hidden":"true"}),(0,a.jsx)("strong",{children:n})]}),(0,a.jsx)("span",{role:"gridcell",children:o}),(0,a.jsx)("span",{role:"gridcell",children:i}),(0,a.jsx)("span",{role:"gridcell",children:l}),(0,a.jsx)("span",{role:"gridcell",children:s})]})}function th({model:e}){let t=Yg(e),n=In[0]?.id,r=t[0]?.id,[o,i]=(0,N.useState)(()=>new Set(["class",...n?[`student:${n}`]:[],...n&&r?[`student:${n}:task:${r}`]:[]])),l=m=>o.has(m),s=m=>{i(y=>{let g=new Set(y);return g.has(m)?g.delete(m):g.add(m),g})},u=In.filter(m=>m.connection==="online"||m.connection==="away").length,d=In.filter(m=>m.sync==="follow").length;return(0,a.jsxs)("section",{className:"classroom-panel","aria-label":"Klasa i stanowiska uczni\xF3w",children:[(0,a.jsxs)("div",{className:"classroom-treegrid",role:"treegrid","aria-label":"Uczniowie, struktura karty, obecno\u015B\u0107 i commity","aria-colcount":5,children:[(0,a.jsxs)("div",{className:"classroom-treegrid-row classroom-treegrid-head",role:"row",children:[(0,a.jsx)("span",{role:"columnheader",children:"DRZEWO"}),(0,a.jsx)("span",{role:"columnheader",children:"REF"}),(0,a.jsx)("span",{role:"columnheader",children:"SESJA"}),(0,a.jsx)("span",{role:"columnheader",children:"DOW\xD3D"}),(0,a.jsx)("span",{role:"columnheader",children:"STAN"})]}),(0,a.jsx)(Gt,{id:"class",depth:0,kind:"class",title:"2TP \xB7 grupa A",refValue:`${In.length} ucz.`,session:`${u}/${In.length}`,evidence:`${d}/${In.length} SYNC`,state:`${t.length} TASK`,hasChildren:!0,expanded:l("class"),onToggle:()=>s("class")}),l("class")&&In.map(m=>{let y=`student:${m.id}`;return(0,a.jsxs)(N.default.Fragment,{children:[(0,a.jsx)(Gt,{id:y,depth:1,kind:"student",title:m.name,refValue:`L${String(m.laptop).padStart(2,"0")}`,session:(0,a.jsx)("b",{className:"classroom-status","data-status":m.connection,children:Zg[m.connection]}),evidence:(0,a.jsx)("b",{className:"classroom-sync","data-sync":m.sync,children:Jg[m.sync]}),state:m.position,hasChildren:t.length>0,expanded:l(y),onToggle:()=>s(y)}),l(y)&&t.map(g=>{let f=`${y}:task:${g.id}`,E=g.exercises.filter(b=>xp(m,b.id).state==="committed").length;return(0,a.jsxs)(N.default.Fragment,{children:[(0,a.jsx)(Gt,{id:f,depth:2,kind:"task",title:g.label,refValue:g.id.toUpperCase(),session:`${g.blocks.length} BLOCK`,evidence:`${E}/${g.exercises.length} COMMIT`,state:"TASK",hasChildren:g.blocks.length+g.exercises.length>0,expanded:l(f),onToggle:()=>s(f)}),l(f)&&g.blocks.map(b=>{let _=`${f}:block:${b.id}`,p=b.phases.length||b.steps.length;return(0,a.jsxs)(N.default.Fragment,{children:[(0,a.jsx)(Gt,{id:_,depth:3,kind:"block",title:b.label,refValue:b.kind==="diagram"?"BLOCK":"TASK BLOCK",session:`${p} ${b.phases.length?"PHASE":"STEP"}`,evidence:"\u2014",state:b.kind==="diagram"?"UML":"FLOW",hasChildren:p>0,expanded:l(_),onToggle:()=>s(_)}),l(_)&&b.phases.map(c=>{let h=`${_}:phase:${c.id}`;return(0,a.jsxs)(N.default.Fragment,{children:[(0,a.jsx)(Gt,{id:h,depth:4,kind:"phase",title:`PHASE \xB7 ${c.label}`,refValue:`${c.steps.length} STEP`,session:"\u2014",evidence:"\u2014",state:"PHASE",hasChildren:c.steps.length>0,expanded:l(h),onToggle:()=>s(h)}),l(h)&&c.steps.map(k=>{let C=vp(m,`${b.id}:${c.id}:${k.id}`,k.number);return(0,a.jsx)(Gt,{id:`${h}:step:${k.id}`,depth:5,kind:"step",title:`STEP ${String(k.number).padStart(2,"0")} \xB7 ${k.label}`,refValue:k.mode??"CODE",session:(0,a.jsx)("b",{className:"classroom-visit","data-visit":C.state,children:yp[C.state]}),evidence:C.timestamp,state:C.state==="present"?"OK":C.state==="missed"?"BRAK":"\u2014"},`${h}:step:${k.id}`)})]},h)}),l(_)&&b.steps.map(c=>{let h=vp(m,`${b.id}:${c.id}`,c.number);return(0,a.jsx)(Gt,{id:`${_}:step:${c.id}`,depth:4,kind:"step",title:`STEP ${String(c.number).padStart(2,"0")} \xB7 ${c.label}`,refValue:c.mode??"RUN",session:(0,a.jsx)("b",{className:"classroom-visit","data-visit":h.state,children:yp[h.state]}),evidence:h.timestamp,state:h.state==="present"?"OK":h.state==="missed"?"BRAK":"\u2014"},`${_}:step:${c.id}`)})]},_)}),l(f)&&g.exercises.length>0&&(()=>{let b=`${f}:exercises`;return(0,a.jsxs)(N.default.Fragment,{children:[(0,a.jsx)(Gt,{id:b,depth:3,kind:"exercises",title:"EXERCISES",refValue:`${g.exercises.length} EX`,session:`${E}/${g.exercises.length}`,evidence:"GIT",state:E===g.exercises.length?"DONE":"TODO",hasChildren:!0,expanded:l(b),onToggle:()=>s(b)}),l(b)&&g.exercises.map(_=>{let p=xp(m,_.id);return(0,a.jsx)(Gt,{id:`${b}:${_.id}`,depth:4,kind:"exercise",title:`EXERCISE \xB7 ${_.title}`,refValue:_.id,session:(0,a.jsx)("b",{className:"classroom-commit","data-commit":p.state,children:eh[p.state]}),evidence:p.commit,state:p.state==="committed"?"DONE":p.state==="working"?"W TOKU":"TODO"},`${b}:${_.id}`)})]},b)})()]},f)})]},m.id)})]}),(0,a.jsxs)("footer",{className:"classroom-legend",children:[(0,a.jsxs)("span",{children:[(0,a.jsx)("b",{children:"BY\u0141"})," obecny przy omawianym STEP"]}),(0,a.jsxs)("span",{children:[(0,a.jsx)("b",{children:"COMMIT"})," rozwi\u0105zanie EXERCISE zapisane w Git"]})]})]})}function nh({open:e,onClose:t}){return e?(0,a.jsx)("div",{className:"shortcut-help-backdrop",role:"presentation",onMouseDown:t,children:(0,a.jsxs)("section",{className:"shortcut-help",role:"dialog","aria-modal":"true","aria-labelledby":"shortcut-help-title",onMouseDown:r=>r.stopPropagation(),children:[(0,a.jsxs)("header",{children:[(0,a.jsxs)("div",{children:[(0,a.jsx)("small",{children:"F12 \xB7 NAWIGACJA DYDAKTYCZNA"}),(0,a.jsx)("h2",{id:"shortcut-help-title",children:"CARD \u2192 TASK \u2192 BLOCK \u2192 PHASE \u2192 STEP \u2192 SNAPSHOT"})]}),(0,a.jsx)("button",{onClick:t,"aria-label":"Zamknij skorowidz",children:"\xD7"})]}),(0,a.jsx)("dl",{children:[["Alt + \u2191 / \u2193","poprzedni / nast\u0119pny TASK"],["Ctrl + \u2191 / \u2193","poprzedni / nast\u0119pny BLOCK"],["Shift + \u2191 / \u2193","poprzednia / nast\u0119pna PHASE"],["Ctrl + Shift + \u2191 / \u2193","poprzedni / nast\u0119pny STEP"],["Alt + Shift + \u2191 / \u2193","poprzedni / nast\u0119pny unikalny SNAPSHOT"],["\u2191 / \u2193","poprzedni / nast\u0119pny element aktywnego poziomu"],["\u2192","zejd\u017A poziom ni\u017Cej"],["\u2190 / Esc","wr\xF3\u0107 poziom wy\u017Cej"],["Enter","wybierz element; przy SYNC ON odtw\xF3rz stan"],["F1","reset aktualnego celu Neovima/kontenera"],["F2","synchronizuj cel z kursorem drzewa UML"],["Ctrl + `","maksymalizuj pane, dopasuj siatk\u0119 i od\u015Bwie\u017C Neovima"],["Ctrl + Enter","zatwierd\u017A lub cofnij zatwierdzenie kroku"],["Alt + 0","wysu\u0144 lub schowaj panel serii i kart"],["Alt + 1","poka\u017C lub ukryj panel Neovima"],["Alt + 2","prze\u0142\u0105cz SYNC OFF / SYNC ON"],["Alt + 3","uzbr\xF3j lub rozbr\xF3j sterowanie Neovimem"],["Alt + 4","wysoki panel 90% / zapisana wysoko\u015B\u0107 normalna"],["Alt + 5","dopasuj ca\u0142y ekran Neovima; wy\u0142\u0105cz r\u0119czny suwak"],["Alt + 6","przypnij lub ukryj model alokatora"],["Alt + 7","po\u0142\u0105cz segmenty UML w szeroki spread / wr\xF3\u0107 do A4"],["Alt + 3, potem najed\u017A","przeka\u017C klawiatur\u0119 i mysz do aktywnej sesji"],["Alt + W","prefiks polece\u0144 okien Neovima ()"],["Alt + strza\u0142ka","przejd\u017A do s\u0105siedniego okna Neovima"],["F12","poka\u017C lub ukryj ten skorowidz"]].map(([r,o])=>(0,a.jsxs)("div",{children:[(0,a.jsx)("dt",{children:(0,a.jsx)("kbd",{children:r})}),(0,a.jsx)("dd",{children:o})]},r))}),(0,a.jsx)("p",{children:"Przy SYNC ON wyb\xF3r stepu odtwarza i weryfikuje przypi\u0119ty stan maszyny. SYNC OFF nie resetuje debuggera. Po najechaniu panel przekazuje do Neovima wy\u0142\u0105cznie kontrolowane zdarzenia klawiatury i myszy, wi\u0119c mo\u017Cna normalnie kontynuowa\u0107 debugowanie."})]})}):null}function rh({model:e}){let t=!!e.has_allocator_model,n=(0,N.useRef)(null),r=(0,N.useRef)(null),o=(0,N.useRef)(`browser-${globalThis.crypto?.randomUUID?.()??Math.random().toString(36).slice(2)}`),i=(0,N.useRef)(0),l=(0,N.useRef)(0),s=(0,N.useRef)(!1),u=(0,N.useRef)(!1),d=(0,N.useRef)(0),m=(0,N.useRef)(0),y=(0,N.useRef)(0),[g,f]=(0,N.useState)(2.18),[E,b]=(0,N.useState)(()=>localStorage.getItem("stem-card-nvim-visible")!=="false"),[_,p]=(0,N.useState)(()=>localStorage.getItem("stem-card-nvim-sync-mode")==="true"),[c,h]=(0,N.useState)(()=>localStorage.getItem("stem-card-nvim-sync-mode")==="true"&&localStorage.getItem("stem-card-nvim-control-mode")==="true"),[k,C]=(0,N.useState)(!1),[P,T]=(0,N.useState)(!1),[R,j]=(0,N.useState)(()=>t&&localStorage.getItem("stem-card-allocator-visible")!=="false"),[I,ke]=(0,N.useState)(()=>{let v=localStorage.getItem("stem-card-diagram-spread");return v===null?!!e.has_spread:v==="true"}),[re,G]=(0,N.useState)({state:"hidden",syncMode:!1,syncReady:!1,controlMode:!1,controlEnabled:!1}),[U,Le]=(0,N.useState)(null),[Ne,Q]=(0,N.useState)(""),[et,Ge]=(0,N.useState)(null),[je,me]=(0,N.useState)(null),[Dn,xe]=(0,N.useState)(null),[bn,se]=(0,N.useState)(null),[A,F]=(0,N.useState)(!1),[B,te]=(0,N.useState)(""),[at,zt]=(0,N.useState)(()=>window.innerWidth),Ee=et==="library",ne=!!(et||Dn),st=(0,N.useCallback)(v=>{if(v){Ge("library"),me("library");return}Ge(w=>w==="library"?null:w),me(w=>w==="library"?null:w)},[]),Ye=(0,N.useCallback)(v=>{window.clearTimeout(y.current),te(v),y.current=window.setTimeout(()=>te(""),4200)},[]),wn=(0,N.useCallback)(async v=>{Ye(`${v} \xB7 wykonywanie\u2026`);try{let L=await fetch(v==="F1"?"/api/nvim/reset":"/api/navigation/sync",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({actor:o.current})}),H=await L.json().catch(()=>({}));if(!L.ok)throw new Error(H.message??H.error??`HTTP ${L.status}`);v==="F2"&&H.current?(l.current=Math.max(l.current,Number(H.current.revision??0)),window.dispatchEvent(new CustomEvent("stem:navigation-command",{detail:H.current})),Ye(`F2 \xB7 ${String(H.current.step.number).padStart(2,"0")} ${H.current.step.label} \xB7 READY`)):Ye("F1 \xB7 reset przyj\u0119ty"),window.setTimeout(()=>window.dispatchEvent(new Event("stem:nvim-refresh")),120)}catch(w){Ye(`${v} \xB7 ${w instanceof Error?w.message:String(w)}`)}},[Ye]),ie=(0,N.useCallback)(async()=>{Ye("Ctrl+` \xB7 przeliczanie widoku\u2026");try{let v=await fetch("/api/nvim/redraw",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({actor:o.current})}),w=await v.json().catch(()=>({}));if(!v.ok)throw new Error(w.message??w.error??`HTTP ${v.status}`);let L=w.external_ui?.grid,H=L?` \xB7 ${L.width}\xD7${L.height}`:"";Ye(`Ctrl+\` \xB7 widok od\u015Bwie\u017Cony${H}`),window.dispatchEvent(new Event("stem:nvim-refresh"))}catch(v){Ye(`Ctrl+\` \xB7 ${v instanceof Error?v.message:String(v)}`)}},[Ye]),q=(0,N.useCallback)(async v=>{try{let w=await fetch("/api/viewer/state",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({actor:o.current,viewer:v})});if(!w.ok)return;let L=await w.json();i.current=Math.max(i.current,Number(L.viewer?.revision??0))}catch{}},[]),bt=v=>{let w=Math.max(.25,Math.min(3,v));f(w),q({scale:w})};(0,N.useEffect)(()=>{document.documentElement.style.setProperty("--viewer-canvas-scale",g.toFixed(3))},[g]),(0,N.useEffect)(()=>{if(!I)return;let v=r.current;if(!v)return;let w=0,L=()=>{window.cancelAnimationFrame(w),w=window.requestAnimationFrame(()=>{v.scrollLeft=Math.max(0,(v.scrollWidth-v.clientWidth)/2)})},H=window.requestAnimationFrame(L);return window.addEventListener("resize",L),()=>{window.cancelAnimationFrame(H),window.cancelAnimationFrame(w),window.removeEventListener("resize",L)}},[I,g,at]),(0,N.useEffect)(()=>{let v=()=>zt(window.innerWidth);return window.addEventListener("resize",v),()=>window.removeEventListener("resize",v)},[]),(0,N.useEffect)(()=>{document.documentElement.dataset.nvimSyncMode=_?"on":"off"},[_]),(0,N.useEffect)(()=>{document.documentElement.dataset.cardClientId=o.current},[]);let fe=v=>{b(v),v||(C(!1),T(!1)),localStorage.setItem("stem-card-nvim-visible",String(v)),q({nvim:{visible:v,...v?{}:{expanded:!1,fit:!1}}})},Qt=v=>{let w=v&&_;h(w),localStorage.setItem("stem-card-nvim-control-mode",String(w)),q({nvim:{control:w}})},jn=v=>{p(v),localStorage.setItem("stem-card-nvim-sync-mode",String(v)),v||(h(!1),localStorage.setItem("stem-card-nvim-control-mode","false")),q({nvim:{sync:v,control:v?c:!1}})},qt=v=>{v&&fe(!0),v&&T(!1),C(v),q({nvim:{visible:v||E,expanded:v,fit:!1}})},ho=v=>{v&&(fe(!0),C(!1)),T(v),q({nvim:{visible:v||E,fit:v,expanded:!1}})},yo=v=>{let w=t&&v;j(w),localStorage.setItem("stem-card-allocator-visible",String(w)),q({allocator:{visible:w}})},Un=v=>{let w=!!(e.has_spread&&v);ke(w),localStorage.setItem("stem-card-diagram-spread",String(w))};(0,N.useEffect)(()=>{let v=0,w=window.requestAnimationFrame(()=>{v=window.requestAnimationFrame(()=>{window.dispatchEvent(new Event("stem:nvim-refresh"))})});return()=>{window.cancelAnimationFrame(w),window.cancelAnimationFrame(v)}},[k,P]),(0,N.useEffect)(()=>{fetch("/api/progress").then(v=>v.ok?v.json():Promise.reject(new Error(`HTTP ${v.status}`))).then(v=>Le(v.progress)).catch(v=>Q(`Post\u0119p dzia\u0142a tylko przez serwer karty (${v.message}).`))},[]),(0,N.useEffect)(()=>{let v=!1,w=!1,L={scale:g,viewport:{width:window.innerWidth,height:window.innerHeight},nvim:{visible:E,sync:_,control:c,expanded:k,fit:P},allocator:{visible:R}},H=D=>{let Z=D.nvim.visible&&D.nvim.fit,V=D.nvim.visible&&!Z&&D.nvim.expanded;f(Math.max(.25,Math.min(3,D.scale))),b(D.nvim.visible),p(D.nvim.sync),h(D.nvim.sync&&D.nvim.control),C(V),T(Z);let oe=t&&(D.allocator?.visible??!0);j(oe),localStorage.setItem("stem-card-nvim-visible",String(D.nvim.visible)),localStorage.setItem("stem-card-nvim-sync-mode",String(D.nvim.sync)),localStorage.setItem("stem-card-nvim-control-mode",String(D.nvim.sync&&D.nvim.control)),localStorage.setItem("stem-card-allocator-visible",String(oe));let ct=++m.current;s.current=!0,window.cancelAnimationFrame(d.current),d.current=window.requestAnimationFrame(()=>{if(ct!==m.current)return;let Ue=Gi();Ki(Ue,{left:D.scroll.x,top:D.scroll.y});let ue=Array.from(document.querySelectorAll(".paper .sheet")),Re=ue[Math.max(0,Math.min(ue.length-1,D.scroll.page_index))]?.querySelector(".sheet-content");Re&&Number.isFinite(D.scroll.sheet_scroll_top)&&Ki(Re,{top:D.scroll.sheet_scroll_top??0}),d.current=window.requestAnimationFrame(()=>{ct===m.current&&(s.current=!1,u.current&&(u.current=!1,window.dispatchEvent(new Event("stem:viewer-scroll-settled"))))})})},K=async()=>{try{let D=await fetch("/api/control/state",{cache:"no-store"});if(!D.ok||v)return;let Z=await D.json(),V=Z.viewer;w||(w=!0,Number(V?.revision??0)===0&&q(L)),V&&V.revision>i.current&&(i.current=V.revision,V.actor!==o.current&&H(V));let oe=Z.navigation;oe&&oe.revision>l.current&&(l.current=oe.revision,oe.actor!==o.current&&(s.current&&(u.current=!0),window.dispatchEvent(new CustomEvent("stem:navigation-command",{detail:oe}))))}catch{}};K();let X=window.setInterval(K,300);return()=>{v=!0,window.clearInterval(X),m.current+=1,window.cancelAnimationFrame(d.current),s.current=!1,u.current=!1}},[]),(0,N.useEffect)(()=>{q({nvim:{connection:re.state,screen_cursor:re.screenCursor,grid:re.grid}})},[re.grid?.columns,re.grid?.rows,re.screenCursor?.column,re.screenCursor?.row,re.state,q]),(0,N.useEffect)(()=>{let v=0,w=null,L=Array.from(document.querySelectorAll(".paper .sheet")),H=L.map(X=>X.querySelector(".sheet-content")).filter(X=>!!X),K=X=>{if(s.current)return;let D=X?.currentTarget;D instanceof HTMLElement&&D.classList.contains("sheet-content")&&(w=D),window.clearTimeout(v),v=window.setTimeout(()=>{let Z=w?.closest(".sheet"),V=Z?L.indexOf(Z):-1,oe=V>=0?V:L.reduce((Ue,ue,J)=>{let Re=ue.getBoundingClientRect(),Ve=Math.abs((Re.top+Re.bottom)/2-window.innerHeight/2);return Ve=0?w:L[oe]?.querySelector(".sheet-content")??null;q({scroll:{x:window.scrollX,y:window.scrollY,page_index:oe,sheet_scroll_top:ct?.scrollTop??0},viewport:{width:window.innerWidth,height:window.innerHeight}}),w=null},120)};return window.addEventListener("scroll",K,{passive:!0}),window.addEventListener("resize",K),window.addEventListener("stem:viewer-scroll-settled",K),H.forEach(X=>X.addEventListener("scroll",K,{passive:!0})),K(),()=>{window.clearTimeout(v),window.removeEventListener("scroll",K),window.removeEventListener("resize",K),window.removeEventListener("stem:viewer-scroll-settled",K),H.forEach(X=>X.removeEventListener("scroll",K))}},[q]),(0,N.useEffect)(()=>{let v=w=>{if(w.repeat)return;let L=w.altKey&&!w.ctrlKey&&!w.metaKey?w.code:"";if(L==="Digit0"&&e.library){w.preventDefault(),w.stopImmediatePropagation(),F(!1),st(!Ee);return}if(L==="Digit1"){w.preventDefault(),w.stopImmediatePropagation(),fe(!E);return}if(L==="Digit2"){w.preventDefault(),w.stopImmediatePropagation(),jn(!_);return}if(L==="Digit3"){if(w.preventDefault(),w.stopImmediatePropagation(),!_)return;fe(!0),Qt(!c);return}if(L==="Digit4"){w.preventDefault(),w.stopImmediatePropagation(),qt(!k);return}if(L==="Digit5"){w.preventDefault(),w.stopImmediatePropagation(),ho(!P);return}if(L==="Digit6"&&t){w.preventDefault(),w.stopImmediatePropagation(),yo(!R);return}if(L==="Digit7"&&e.has_spread){w.preventDefault(),w.stopImmediatePropagation(),Un(!I);return}if((w.key==="F1"||w.key==="F2")&&!w.altKey&&!w.ctrlKey&&!w.metaKey&&!w.shiftKey){w.preventDefault(),w.stopImmediatePropagation(),wn(w.key);return}if(w.ctrlKey&&!w.altKey&&!w.metaKey&&!w.shiftKey&&(w.code==="Backquote"||w.key==="`")){w.preventDefault(),w.stopImmediatePropagation(),ie();return}if(w.key==="F12"){w.preventDefault(),w.stopImmediatePropagation(),st(!1),Ge(null),me(null),xe(null),se(null),F(H=>!H);return}if(w.key==="Escape"&&(ne||A)){w.preventDefault(),w.stopImmediatePropagation(),Ge(null),me(null),xe(null),se(null),F(!1);return}};return window.addEventListener("keydown",v,!0),()=>window.removeEventListener("keydown",v,!0)},[R,I,t,Ee,e.has_spread,e.library,c,k,P,_,E,wn,ie,A,ne]),(0,N.useEffect)(()=>{let v=n.current?.querySelector(".topbar");if(!v)return;let w=()=>{document.documentElement.style.setProperty("--side-panel-top",`${Math.ceil(v.getBoundingClientRect().bottom)}px`)};w();let L=new ResizeObserver(w);return L.observe(v),window.addEventListener("resize",w),()=>{L.disconnect(),window.removeEventListener("resize",w),document.documentElement.style.removeProperty("--side-panel-top")}},[]),(0,N.useEffect)(()=>()=>window.clearTimeout(y.current),[]),(0,N.useEffect)(()=>{let v=w=>{!w.altKey||w.ctrlKey||(w.preventDefault(),f(L=>{let H=Math.max(.25,Math.min(3,L*Math.exp(-Math.max(-120,Math.min(120,w.deltaY))*.001)));return q({scale:H}),H}))};return window.addEventListener("wheel",v,{passive:!1}),()=>window.removeEventListener("wheel",v)},[q]);let ut=async(v,w)=>{try{let L=await fetch(`/api/progress/${encodeURIComponent(v)}`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({status:w})});if(!L.ok)throw new Error(await L.text());Le((await L.json()).progress),Q("")}catch(L){Q(`Nie zapisano post\u0119pu: ${L instanceof Error?L.message:String(L)}`)}},x=(v,w)=>{ut(v,{pending:"approved",approved:"pending"}[w])},S=0,M=e.sections.map(v=>{let w=S;return S+=v.assets.length,{section:v,figureOffset:w}}),O=[];return M.forEach(v=>{let w=v.section.spread_group??"",L=O[O.length-1];if(w&&L?.spreadGroup===w){L.pages.push(v);return}O.push({key:w||v.section.id,spreadGroup:w,spreadLabel:v.section.spread_label??"",spreadColumns:v.section.spread_columns??1,pages:[v]})}),(0,a.jsxs)(a.Fragment,{children:[(0,a.jsxs)("div",{ref:n,className:`viewer-chrome${k?" is-nvim-expanded":""}${P?" is-nvim-fit":""}`,children:[(0,a.jsx)(bg,{toc:e.toc,libraryAvailable:!!e.library,libraryOpen:Ee,setLibraryOpen:st,scale:g,setScale:bt,nvimVisible:E,setNvimVisible:fe,nvimSyncMode:_,setNvimSyncMode:jn,nvimControlMode:c,setNvimControlMode:Qt,nvimExpanded:k,setNvimExpanded:qt,nvimFit:P,setNvimFit:ho,allocatorVisible:R,setAllocatorVisible:yo,hasAllocatorModel:t,diagramSpread:I,setDiagramSpread:Un,hasDiagramSpread:!!e.has_spread,nvimSummary:re,progress:U,progressError:Ne}),e.viewpoints?.length?(0,a.jsx)(xg,{viewpoints:e.viewpoints}):null,(0,a.jsx)(wg,{visible:t&&R,model:e}),(0,a.jsx)(Mg,{visible:E,syncMode:_,controlMode:c,expanded:k,fit:P,scale:g,onSummaryChange:G}),B&&(0,a.jsx)("output",{className:"viewer-action-toast",children:B})]}),(0,a.jsxs)("main",{ref:r,className:`paper${I?" is-diagram-spread":""}`,children:[(0,a.jsx)(Og,{front:e.front}),O.map(v=>{let w=Array.from({length:Math.ceil(v.pages.length/v.spreadColumns)},(D,Z)=>v.pages.slice(Z*v.spreadColumns,(Z+1)*v.spreadColumns)),H=Math.max(1,...w.map(D=>D.reduce((Z,V)=>Z+(V.section.page_orientation==="landscape"?297:210),Math.max(0,D.length-1)*2)))*(96/25.4)*g,K=Math.min(1,Math.max(.25,(at-24)/H)),X=v.pages.map(({section:D,figureOffset:Z})=>(0,a.jsx)(Wg,{section:D,progress:U,onCycle:x,onSetStatus:ut,figureOffset:Z},D.id));return v.spreadGroup?(0,a.jsx)("section",{className:"sheet-spread","data-spread-group":v.spreadGroup,"aria-label":v.spreadLabel||"Wielostronicowy diagram UML",style:{"--spread-columns":v.spreadColumns,"--spread-fit-scale":K},children:X},v.key):X[0]}),e.dictionary&&(0,a.jsxs)(ys,{header:e.dictionary.header_html,className:"dictionary-sheet",children:[(0,a.jsx)("h2",{children:"S\u0142ownik WE/EN/EK/KW"}),(0,a.jsx)(Yt,{html:e.dictionary.content_html})]})]}),(0,a.jsx)(hp,{side:"left",panels:[...e.library?[{id:"library",railLabel:"K",title:"Serie i karty",accent:"#167ca4",content:(0,a.jsx)(Qg,{library:e.library,onNavigate:()=>st(!1)})}]:[],{id:"contents",railLabel:"S",title:"Spis tre\u015Bci",accent:"#16805d",content:(0,a.jsx)(qg,{toc:e.toc,onNavigate:()=>{Ge(null),me(null)}})}],activeId:et,pinnedId:je,onActiveChange:Ge,onPinnedChange:me}),(0,a.jsx)(hp,{side:"right",panels:[{id:"classroom",railLabel:"U",title:"Klasa i stanowiska",accent:"#267357",content:(0,a.jsx)(th,{model:e})},{id:"progress",railLabel:"R",title:"Przebieg i raport",accent:"#b45b26",content:(0,a.jsx)(Xg,{progress:U,error:Ne})}],activeId:Dn,pinnedId:bn,onActiveChange:xe,onPinnedChange:se}),(0,a.jsx)(nh,{open:A,onClose:()=>F(!1)})]})}async function oh(){let e=(0,bp.createRoot)(document.getElementById("root"));try{let t=await fetch("./card-data.json",{cache:"no-store"});if(!t.ok)throw new Error(`Nie mo\u017Cna wczyta\u0107 card-data.json: ${t.status}`);let n=await t.json();e.render((0,a.jsx)(rh,{model:n}))}catch(t){e.render((0,a.jsxs)("main",{className:"app-load-error",children:[(0,a.jsx)("h1",{children:"Nie uda\u0142o si\u0119 uruchomi\u0107 karty"}),(0,a.jsx)("pre",{children:t instanceof Error?t.message:String(t)})]}))}}oh(); +`),lines:v.target.value.split(` +`)}}))})]}),(0,a.jsxs)("div",{className:"uml-layout-style-grid",children:[(0,a.jsxs)("label",{children:["Font",(0,a.jsx)("input",{type:"number",min:"4",max:"96",step:"0.5",value:ct.text?.font_size??12,onChange:v=>oe(J,x=>({...x,text:{...x.text,font_size:Number(v.target.value)}}))})]}),(0,a.jsxs)("label",{children:["Wyr\xF3wnanie",(0,a.jsxs)("select",{value:ct.text?.align??"left",onChange:v=>oe(J,x=>({...x,text:{...x.text,align:v.target.value}})),children:[(0,a.jsx)("option",{value:"left",children:"left"}),(0,a.jsx)("option",{value:"center",children:"center"}),(0,a.jsx)("option",{value:"right",children:"right"})]})]}),(0,a.jsxs)("label",{children:["Wype\u0142nienie",(0,a.jsx)("input",{type:"color",value:ct.style?.fill??"#edf6fa",onChange:v=>oe(J,x=>({...x,style:{...x.style,fill:v.target.value}}))})]}),(0,a.jsxs)("label",{children:["Obramowanie",(0,a.jsx)("input",{type:"color",value:ct.style?.stroke??"#2c7794",onChange:v=>oe(J,x=>({...x,style:{...x.style,stroke:v.target.value}}))})]}),(0,a.jsxs)("label",{children:["Linia",(0,a.jsx)("input",{type:"number",min:"0.5",max:"12",step:"0.25",value:ct.style?.stroke_width??1.5,onChange:v=>oe(J,x=>({...x,style:{...x.style,stroke_width:Number(v.target.value)}}))})]})]})]}),(0,a.jsxs)("div",{className:"uml-layout-editor-actions",children:[(0,a.jsx)("button",{className:"is-primary",disabled:!ae,onClick:()=>void wt(),children:"Zapisz uk\u0142ad"}),(0,a.jsx)("button",{disabled:!ae,onClick:kn,children:"Cofnij zmiany"}),(0,a.jsx)("button",{className:"is-danger",onClick:()=>void Dt(),children:"Reset PlantUML"})]}),(0,a.jsx)("output",{children:q})]})]})]})}function nh(e){return e.config.phases?.length?(0,a.jsx)(th,{...e}):(0,a.jsx)(eh,{...e})}function rh({asset:e,continuation:t}){let n=e.tile;if(!n)return(0,a.jsx)("img",{src:e.href,alt:e.alt,loading:"lazy"});let r=e.diagram_block_label?.match(/^A[1-8]\b/)?.[0]??e.diagram_title?.match(/^A[1-8]\b/)?.[0]??e.caption.match(/^A[1-8]\b/)?.[0]??"UML",o=(e.diagram_title??e.caption).replace(/^A[1-8]\s*[·—:-]\s*/i,"");return(0,a.jsxs)("div",{className:"uml-react uml-snapshot-react uml-static-tile",children:[(0,a.jsx)("header",{className:"uml-snapshot-header",children:(0,a.jsxs)("div",{className:"uml-header-first-line",children:[(0,a.jsxs)("h3",{children:[(0,a.jsx)("span",{children:r})," \u2014 ",o,(0,a.jsxs)("small",{className:"uml-tile-part",children:["cz\u0119\u015B\u0107 ",n.index,"/",n.count," \xB7 r",n.row," c",n.column]})]}),(0,a.jsxs)("div",{className:"uml-header-navigation",children:[(0,a.jsx)(Pp,{continuation:t}),(0,a.jsx)("div",{className:"uml-phase-actions","aria-label":"Fazy logicznego diagramu",children:(e.diagram_phase_labels??[]).map(i=>(0,a.jsx)("span",{children:i},i))})]})]})}),(0,a.jsx)("div",{className:"uml-snapshot-layout",children:(0,a.jsx)("div",{className:"uml-canvas uml-step-canvas",children:(0,a.jsx)("div",{className:"uml-svg-host is-tiled is-static",style:vs(n),children:(0,a.jsx)("div",{className:"uml-static-crop",style:{width:`${n.width}px`,height:`${n.height}px`},children:(0,a.jsx)("img",{src:e.href,alt:e.alt,style:{width:`${n.full_width}px`,height:`${n.full_height}px`,transform:`translate(${-(n.x-n.full_x)}px, ${-(n.y-n.full_y)}px)`}})})})})})]})}function oh({asset:e,number:t,progress:n,onSetStatus:r,continuation:o}){let i=e.interactive?.kind,l=!!i;return(0,a.jsxs)("figure",{className:`card-asset asset-${e.kind} ${l?"asset-interactive":""}`,id:e.label.replace(":","-"),children:[i==="uml-sequence"||i==="uml-class"?(0,a.jsx)(nh,{config:e.interactive,asset:e,progress:n,onSetStatus:r,continuation:o}):i==="allocator-memory-flow"?(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(Jg,{config:e.interactive,title:e.caption}),(0,a.jsx)("img",{className:"asset-static-fallback",src:e.href,alt:e.alt})]}):e.tile?(0,a.jsx)(rh,{asset:e,continuation:o}):(0,a.jsx)("a",{href:e.href,target:"_blank",rel:"noopener",children:(0,a.jsx)("img",{src:e.href,alt:e.alt,loading:"lazy",style:{width:`${e.width*100}%`}})}),(0,a.jsxs)("figcaption",{children:["Rys. ",e.figure_number??t,". ",e.caption]}),e.diagram_description&&(0,a.jsxs)("aside",{className:"uml-after-description",children:[(0,a.jsx)("strong",{children:"Interpretacja"}),(0,a.jsx)("p",{children:e.diagram_description})]})]})}function ih({steps:e,progress:t,onCycle:n}){if(!e.length)return null;let r={pending:"\u25CB niezatwierdzony",approved:"\u25CF zatwierdzony"};return(0,a.jsx)("div",{className:"step-map",children:e.map(o=>{let i=t?.items?.[o.id]?.status??"pending";return(0,a.jsxs)("div",{className:`step-row ${i==="approved"?"lesson-progress-completed":""}`,children:[(0,a.jsx)("button",{className:"lesson-progress-control","data-status":i,onClick:()=>n(o.id,i),disabled:!t,children:r[i]}),(0,a.jsx)("span",{className:"step-title",children:o.title})]},o.id)})})}function lh({section:e,progress:t,onCycle:n,onSetStatus:r,figureOffset:o}){let i=Pg(e);return(0,a.jsxs)(bs,{header:e.header_html,footer:e.footer_html,left:e.left_margin_html,right:e.right_margin_html,className:`section-sheet${e.assets.length?" section-sheet--asset":""} sheet--${e.page_orientation||"portrait"}`,children:[(0,a.jsx)("div",{id:e.id,className:"section-anchor"}),e.show_heading&&(0,a.jsxs)("h2",{className:"section-heading",children:[(0,a.jsx)("span",{className:"section-index",children:e.index}),(0,a.jsx)("span",{className:"section-title",children:e.title})]}),(0,a.jsx)(ih,{steps:e.steps,progress:t,onCycle:n}),e.content_html&&(0,a.jsx)(Ft,{html:e.content_html}),(0,a.jsx)("div",{className:"tasks",children:e.tasks.map(l=>(0,a.jsx)(Zg,{task:l},l.ref))}),e.assets.map((l,s)=>(0,a.jsx)(oh,{asset:l,number:o+s+1,progress:t,onSetStatus:r,continuation:i},l.label)),e.tasks.map(l=>l.conclusion_html&&(0,a.jsxs)("aside",{className:"task-conclusion",children:[(0,a.jsx)("strong",{children:"WNIOSEK"}),(0,a.jsx)(Ft,{html:l.conclusion_html})]},`${l.ref}-conclusion`))]})}function ah({progress:e,error:t}){if(!e?.summary&&!t)return null;let n=e?.summary.counts;return(0,a.jsxs)("section",{className:"lesson-progress-topbar","aria-label":"Przebieg zaj\u0119\u0107",children:[(0,a.jsx)("strong",{children:"PRZEBIEG"}),n&&(0,a.jsxs)("output",{title:"Zatwierdzone kroki",children:[n.approved,"/",e.summary.total]}),t&&(0,a.jsx)("span",{className:"lesson-progress-error",title:t,children:"!"}),(0,a.jsx)("a",{href:"/api/report/teams.md",target:"_blank",rel:"noopener",title:"Otw\xF3rz raport do Teams",children:"Teams"}),(0,a.jsx)("a",{href:"/api/report/lesson.html",target:"_blank",rel:"noopener",title:"Otw\xF3rz \u015Blad lekcji ze zrzutami",children:"\u015Alad"})]})}var Fn=[{id:"u01",name:"Alicja Nowak",laptop:3,connection:"online",sync:"follow",position:"A5\xB708"},{id:"u02",name:"Bartosz Kowalski",laptop:7,connection:"online",sync:"follow",position:"A5\xB708"},{id:"u03",name:"Celina Wi\u015Bniewska",laptop:11,connection:"away",sync:"paused",position:"A5\xB705"},{id:"u04",name:"Dawid W\xF3jcik",laptop:14,connection:"offline",sync:"follow",position:"\u2014"},{id:"u05",name:"Emilia Kami\u0144ska",laptop:18,connection:"online",sync:"local",position:"A3\xB702"},{id:"u06",name:"Filip Lewandowski",laptop:22,connection:"error",sync:"follow",position:"A5\xB706"},{id:"u07",name:"Gabriela Zieli\u0144ska",laptop:24,connection:"online",sync:"follow",position:"A5\xB708"}];function sh(e){let t=new Map,n=(r,o)=>{let i=r.trim()||"task",l=t.get(i);return l||(l={id:i,label:o.trim()||i.toUpperCase(),blocks:[],exercises:[]},t.set(i,l)),l};for(let r of e.sections){for(let o of r.assets){let i=o.interactive;if(!i?.task||!i.block)continue;let l=n(i.task.id,i.task.label),s=`diagram:${i.block.id}`,u=l.blocks.find(d=>d.id===s);u||(u={id:s,label:i.block.label,kind:"diagram",phases:[],steps:[]},l.blocks.push(u));for(let d of i.phases??[]){let m=u.phases.find(y=>y.id===d.id);m||(m={...d,steps:[]},u.phases.push(m));for(let y of d.steps)m.steps.some(g=>g.id===y.id)||m.steps.push(y)}}for(let o of r.tasks){let i=n(o.ref,o.title);i.label=o.title||i.label;for(let l of o.flow){if(l.kind==="exercise"){i.exercises.some(u=>u.id===l.id)||i.exercises.push(l);continue}let s=`flow:${l.id}`;i.blocks.some(u=>u.id===s)||i.blocks.push({id:s,label:l.title,kind:"flow",phases:[],steps:l.steps.map((u,d)=>({id:u.id,number:d+1,label:u.title,description:u.title,mode:"RUN"}))})}}}return[...t.values()]}function bp({side:e,panels:t,activeId:n,pinnedId:r,onActiveChange:o,onPinnedChange:i}){let l=(0,k.useRef)(0),s=t.find(f=>f.id===n)??null,u=(0,k.useCallback)(()=>{window.clearTimeout(l.current)},[]),d=(0,k.useCallback)(()=>{u(),!r&&(l.current=window.setTimeout(()=>o(null),150))},[u,o,r]),m=(0,k.useCallback)(f=>{u(),r||o(f)},[u,o,r]),y=(0,k.useCallback)(f=>{if(u(),r===f){i(null),o(null);return}i(f),o(f)},[u,o,i,r]),g=(0,k.useCallback)(()=>{u(),i(null),o(null)},[u,o,i]);return(0,k.useEffect)(()=>()=>window.clearTimeout(l.current),[]),t.length?(0,a.jsxs)("div",{className:`side-panel-dock side-panel-dock--${e}`,"data-side":e,children:[(0,a.jsx)("nav",{className:"side-panel-rail","aria-label":`Panele ${e==="left"?"lewe":"prawe"}`,children:t.map(f=>{let S=n===f.id,b=r===f.id;return(0,a.jsx)("button",{type:"button",className:`side-panel-trigger${S?" is-open":""}${b?" is-pinned":""}`,style:{"--side-panel-accent":f.accent},"aria-controls":`side-panel-${e}-${f.id}`,"aria-expanded":S,"aria-pressed":b,"aria-label":`${f.title}: ${b?"odpnij":"przypnij"} panel`,title:`${f.title} \xB7 ${b?"Fixed":"Auto"}`,onMouseEnter:()=>m(f.id),onMouseLeave:d,onFocus:()=>m(f.id),onClick:()=>y(f.id),children:(0,a.jsx)("span",{children:f.railLabel})},f.id)})}),(0,a.jsx)("aside",{id:s?`side-panel-${e}-${s.id}`:void 0,className:`side-panel${s?" is-open":""}`,"aria-hidden":!s,"aria-label":s?.title,style:s?{"--side-panel-accent":s.accent}:void 0,onMouseEnter:u,onMouseLeave:d,onFocusCapture:u,children:s&&(0,a.jsxs)(a.Fragment,{children:[(0,a.jsxs)("header",{className:"side-panel-header",children:[(0,a.jsxs)("div",{children:[(0,a.jsx)("small",{children:e==="left"?"LEWY PANEL":"PRAWY PANEL"}),(0,a.jsx)("strong",{children:s.title})]}),(0,a.jsxs)("div",{className:"side-panel-actions",children:[(0,a.jsx)("button",{type:"button",className:r===s.id?"is-pinned":"",onClick:()=>y(s.id),title:r===s.id?"Tryb Fixed \u2014 kliknij, aby przej\u015B\u0107 do Auto":"Tryb Auto \u2014 kliknij, aby przypi\u0105\u0107",children:r===s.id?"Fixed":"Auto"}),(0,a.jsx)("button",{type:"button",onClick:g,"aria-label":`Zamknij ${s.title}`,children:"\xD7"})]})]}),(0,a.jsx)("div",{className:"side-panel-body",children:s.content})]})})]}):null}function go({id:e,depth:t,kind:n,title:r,label:o,refValue:i,stateValue:l,stateKind:s,hasChildren:u=!1,expanded:d=!1,onToggle:m,href:y,current:g=!1,unavailable:f=!1,onNavigate:S}){let b=y?(0,a.jsx)("a",{className:"card-library-tree-link","data-stem-source-aware":"true",href:y,onClick:S,"aria-current":g?"page":void 0,title:g?"Poka\u017C bie\u017C\u0105c\u0105 kart\u0119":`Otw\xF3rz: ${r}`,children:o}):(0,a.jsx)("span",{className:"card-library-tree-label",title:r,children:o});return(0,a.jsxs)("div",{className:`card-library-treegrid-row is-${n}${g?" is-current":""}${f?" is-unavailable":""}`,role:"row","aria-level":t+1,"aria-expanded":u?d:void 0,"aria-disabled":f||void 0,"data-node-id":e,style:{"--card-library-depth":t},children:[(0,a.jsxs)("span",{className:"card-library-tree-title",role:"gridcell",children:[u?(0,a.jsx)("button",{className:"card-library-tree-expander",type:"button",onClick:m,"aria-label":`${d?"Zwi\u0144":"Rozwi\u0144"}: ${r}`,children:d?"\u25BE":"\u25B8"}):(0,a.jsx)("span",{className:"card-library-tree-expander is-empty","aria-hidden":"true"}),b]}),(0,a.jsx)("span",{role:"gridcell",children:i}),(0,a.jsx)("span",{role:"gridcell",children:(0,a.jsx)("b",{className:"card-library-tree-state","data-state":s,children:l})})]})}function uh({library:e,source:t,onNavigate:n}){if(!e)return null;let r=e.subjects.reduce((m,y)=>m+y.levels.reduce((g,f)=>g+f.series.length,0),0),o=e.subjects.reduce((m,y)=>m+y.levels.reduce((g,f)=>g+f.series.reduce((S,b)=>S+b.cards.filter(_=>_.available).length,0),0),0),i=e.subjects.reduce((m,y)=>m+y.levels.reduce((g,f)=>g+f.series.reduce((S,b)=>S+b.cards.length,0),0),0),[l,s]=(0,k.useState)(()=>{let m=new Set;return e.subjects.forEach(y=>{let g=`subject:${y.id}`;y.current&&m.add(g),y.levels.forEach(f=>{let S=`${g}:level:${f.id}`;f.current&&m.add(S),f.series.forEach(b=>{let _=`${S}:series:${b.id}`;b.current&&m.add(_),b.cards.forEach(p=>{p.current&&(p.tasks?.length??0)>0&&m.add(`${_}:card:${p.id}`)})})})}),m}),u=m=>l.has(m),d=m=>{s(y=>{let g=new Set(y);return g.has(m)?g.delete(m):g.add(m),g})};return(0,a.jsxs)("div",{className:"card-library-panel",children:[(0,a.jsxs)("div",{className:"card-library-treegrid",role:"treegrid","aria-label":"Serie, karty i taski","aria-colcount":3,children:[(0,a.jsxs)("div",{className:"card-library-treegrid-row card-library-treegrid-head",role:"row",children:[(0,a.jsx)("span",{role:"columnheader",children:"DRZEWO"}),(0,a.jsx)("span",{role:"columnheader",children:"REF"}),(0,a.jsx)("span",{role:"columnheader",children:"STATUS"})]}),e.subjects.map(m=>{let y=`subject:${m.id}`;return(0,a.jsxs)(k.default.Fragment,{children:[(0,a.jsx)(go,{id:y,depth:0,kind:"subject",title:m.title,label:(0,a.jsx)("strong",{children:m.title}),refValue:"PRZEDMIOT",stateValue:`${m.levels.length} POZ.`,hasChildren:m.levels.length>0,expanded:u(y),onToggle:()=>d(y)}),u(y)&&m.levels.map(g=>{let f=`${y}:level:${g.id}`;return(0,a.jsxs)(k.default.Fragment,{children:[(0,a.jsx)(go,{id:f,depth:1,kind:"level",title:g.title,label:(0,a.jsx)("strong",{children:g.title}),refValue:"ROK",stateValue:`${g.series.length} SERII`,hasChildren:g.series.length>0,expanded:u(f),onToggle:()=>d(f)}),u(f)&&g.series.map(S=>{let b=`${f}:series:${S.id}`;return(0,a.jsxs)(k.default.Fragment,{children:[(0,a.jsx)(go,{id:b,depth:2,kind:"series",title:S.title,label:(0,a.jsx)("strong",{children:S.title}),refValue:S.role==="reference"?"REF.":"SERIA",stateValue:`${S.cards.length} KART`,hasChildren:S.cards.length>0,expanded:u(b),onToggle:()=>d(b)}),u(b)&&S.cards.map(_=>{let p=`${b}:card:${_.id}`,c=_.tasks??[],h=_.current||_.available,w=vg(_,t),C=_.current?"current":_.available?"online":"plan";return(0,a.jsxs)(k.default.Fragment,{children:[(0,a.jsx)(go,{id:p,depth:3,kind:"card",title:`${_.id} \xB7 ${_.title}`,label:(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("strong",{children:_.id}),(0,a.jsx)("span",{children:_.title})]}),refValue:_.version||"\u2014",stateValue:_.current?"BIE\u017B\u0104CA":_.available?"ONLINE":"PLAN",stateKind:C,hasChildren:c.length>0,expanded:u(p),onToggle:()=>d(p),href:h?_.current?"#":w:void 0,current:_.current,unavailable:!h,onNavigate:n}),u(p)&&c.map(A=>{let P=_.current?`#${A.id}`:`${w}#${A.id}`;return(0,a.jsx)(go,{id:`${p}:task:${A.id}`,depth:4,kind:"task",title:`${A.id.toUpperCase()} \xB7 ${A.title}`,label:(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)("strong",{children:A.id.toUpperCase()}),(0,a.jsx)("span",{children:A.title})]}),refValue:"TASK",stateValue:h?"GOTOWY":"PLAN",stateKind:h?"online":"plan",href:h?P:void 0,unavailable:!h,onNavigate:n},`${p}:task:${A.id}`)})]},p)})]},b)})]},f)})]},y)})]}),(0,a.jsxs)("footer",{className:"card-library-footer",children:[(0,a.jsx)("span",{children:e.workspace||"STEM"}),(0,a.jsxs)("span",{children:[r," serii"]}),(0,a.jsxs)("span",{children:[(0,a.jsx)("i",{className:"is-online"})," ",o,"/",i," online"]}),(0,a.jsx)("kbd",{children:"Esc"})]})]})}function ch({toc:e,onNavigate:t}){return(0,a.jsxs)("nav",{className:"side-toc","aria-label":"Spis tre\u015Bci karty",children:[(0,a.jsxs)("header",{children:[(0,a.jsx)("small",{children:"KARTA PRACY"}),(0,a.jsx)("h2",{children:"Spis tre\u015Bci"})]}),(0,a.jsx)("ol",{children:e.map((n,r)=>(0,a.jsx)("li",{children:(0,a.jsxs)("a",{href:`#${n.id}`,onClick:t,children:[(0,a.jsx)("span",{children:String(r+1).padStart(2,"0")}),(0,a.jsx)("strong",{children:n.label})]})},n.id))})]})}function dh({progress:e,error:t}){let n=e?.summary?.counts;return(0,a.jsxs)("section",{className:"side-progress","aria-label":"Przebieg zaj\u0119\u0107 i raport",children:[(0,a.jsxs)("header",{children:[(0,a.jsx)("small",{children:"DOWODY I RAPORT"}),(0,a.jsx)("h2",{children:"Przebieg zaj\u0119\u0107"})]}),(0,a.jsxs)("div",{className:"side-progress-summary",children:[(0,a.jsx)("span",{children:"Zatwierdzone kroki"}),(0,a.jsx)("strong",{children:n?`${n.approved}/${e.summary.total}`:"\u2014"})]}),t&&(0,a.jsx)("p",{className:"side-progress-error",children:t}),(0,a.jsxs)("div",{className:"side-progress-links",children:[(0,a.jsx)("a",{href:"/api/report/teams.md",target:"_blank",rel:"noopener",children:"Raport do Teams"}),(0,a.jsx)("a",{href:"/api/report/lesson.html",target:"_blank",rel:"noopener",children:"\u015Alad lekcji ze zrzutami"})]})]})}var ph={online:"ONLINE",away:"ZAJ\u0118TY",offline:"OFFLINE",error:"B\u0141\u0104D"},mh={follow:"SYNC",paused:"PAUZA",local:"LOKAL."},xp={present:"BY\u0141",missed:"NIE BY\u0141",pending:"OCZEK."},fh={committed:"COMMIT",working:"PRACA",missing:"BRAK"};function Mp(e){let t=2166136261;for(let n=0;n>>0}function wp(e,t,n){let r=Mp(`${e.id}:step:${t}`),o=r%8,i=o===0?"missed":o===1?"pending":"present",l=8+n*4+r%3,s=10+Math.floor(l/60),u=l%60,d=(e.laptop*7+r)%60;return{state:i,timestamp:i==="present"?`${String(s).padStart(2,"0")}:${String(u).padStart(2,"0")}:${String(d).padStart(2,"0")}`:"\u2014"}}function kp(e,t){let n=Mp(`${e.id}:exercise:${t}`),r=n%6,o=r===0?"missing":r===1?"working":"committed";return{state:o,commit:o==="committed"?n.toString(16).padStart(8,"0").slice(0,7):"\u2014"}}function Xt({id:e,depth:t,title:n,kind:r,refValue:o,session:i,evidence:l,state:s,hasChildren:u=!1,expanded:d=!1,onToggle:m}){return(0,a.jsxs)("div",{className:`classroom-treegrid-row classroom-node-row is-${r}`,role:"row","aria-level":t+1,"aria-expanded":u?d:void 0,"data-node-id":e,style:{"--classroom-depth":t},children:[(0,a.jsxs)("span",{className:"classroom-node-title",role:"gridcell",title:n,children:[u?(0,a.jsx)("button",{className:"classroom-expander",type:"button",onClick:m,"aria-label":`${d?"Zwi\u0144":"Rozwi\u0144"}: ${n}`,children:d?"\u25BE":"\u25B8"}):(0,a.jsx)("span",{className:"classroom-expander is-empty","aria-hidden":"true"}),(0,a.jsx)("strong",{children:n})]}),(0,a.jsx)("span",{role:"gridcell",children:o}),(0,a.jsx)("span",{role:"gridcell",children:i}),(0,a.jsx)("span",{role:"gridcell",children:l}),(0,a.jsx)("span",{role:"gridcell",children:s})]})}function gh({model:e}){let t=sh(e),n=Fn[0]?.id,r=t[0]?.id,[o,i]=(0,k.useState)(()=>new Set(["class",...n?[`student:${n}`]:[],...n&&r?[`student:${n}:task:${r}`]:[]])),l=m=>o.has(m),s=m=>{i(y=>{let g=new Set(y);return g.has(m)?g.delete(m):g.add(m),g})},u=Fn.filter(m=>m.connection==="online"||m.connection==="away").length,d=Fn.filter(m=>m.sync==="follow").length;return(0,a.jsxs)("section",{className:"classroom-panel","aria-label":"Klasa i stanowiska uczni\xF3w",children:[(0,a.jsxs)("div",{className:"classroom-treegrid",role:"treegrid","aria-label":"Uczniowie, struktura karty, obecno\u015B\u0107 i commity","aria-colcount":5,children:[(0,a.jsxs)("div",{className:"classroom-treegrid-row classroom-treegrid-head",role:"row",children:[(0,a.jsx)("span",{role:"columnheader",children:"DRZEWO"}),(0,a.jsx)("span",{role:"columnheader",children:"REF"}),(0,a.jsx)("span",{role:"columnheader",children:"SESJA"}),(0,a.jsx)("span",{role:"columnheader",children:"DOW\xD3D"}),(0,a.jsx)("span",{role:"columnheader",children:"STAN"})]}),(0,a.jsx)(Xt,{id:"class",depth:0,kind:"class",title:"2TP \xB7 grupa A",refValue:`${Fn.length} ucz.`,session:`${u}/${Fn.length}`,evidence:`${d}/${Fn.length} SYNC`,state:`${t.length} TASK`,hasChildren:!0,expanded:l("class"),onToggle:()=>s("class")}),l("class")&&Fn.map(m=>{let y=`student:${m.id}`;return(0,a.jsxs)(k.default.Fragment,{children:[(0,a.jsx)(Xt,{id:y,depth:1,kind:"student",title:m.name,refValue:`L${String(m.laptop).padStart(2,"0")}`,session:(0,a.jsx)("b",{className:"classroom-status","data-status":m.connection,children:ph[m.connection]}),evidence:(0,a.jsx)("b",{className:"classroom-sync","data-sync":m.sync,children:mh[m.sync]}),state:m.position,hasChildren:t.length>0,expanded:l(y),onToggle:()=>s(y)}),l(y)&&t.map(g=>{let f=`${y}:task:${g.id}`,S=g.exercises.filter(b=>kp(m,b.id).state==="committed").length;return(0,a.jsxs)(k.default.Fragment,{children:[(0,a.jsx)(Xt,{id:f,depth:2,kind:"task",title:g.label,refValue:g.id.toUpperCase(),session:`${g.blocks.length} BLOCK`,evidence:`${S}/${g.exercises.length} COMMIT`,state:"TASK",hasChildren:g.blocks.length+g.exercises.length>0,expanded:l(f),onToggle:()=>s(f)}),l(f)&&g.blocks.map(b=>{let _=`${f}:block:${b.id}`,p=b.phases.length||b.steps.length;return(0,a.jsxs)(k.default.Fragment,{children:[(0,a.jsx)(Xt,{id:_,depth:3,kind:"block",title:b.label,refValue:b.kind==="diagram"?"BLOCK":"TASK BLOCK",session:`${p} ${b.phases.length?"PHASE":"STEP"}`,evidence:"\u2014",state:b.kind==="diagram"?"UML":"FLOW",hasChildren:p>0,expanded:l(_),onToggle:()=>s(_)}),l(_)&&b.phases.map(c=>{let h=`${_}:phase:${c.id}`;return(0,a.jsxs)(k.default.Fragment,{children:[(0,a.jsx)(Xt,{id:h,depth:4,kind:"phase",title:`PHASE \xB7 ${c.label}`,refValue:`${c.steps.length} STEP`,session:"\u2014",evidence:"\u2014",state:"PHASE",hasChildren:c.steps.length>0,expanded:l(h),onToggle:()=>s(h)}),l(h)&&c.steps.map(w=>{let C=wp(m,`${b.id}:${c.id}:${w.id}`,w.number);return(0,a.jsx)(Xt,{id:`${h}:step:${w.id}`,depth:5,kind:"step",title:`STEP ${String(w.number).padStart(2,"0")} \xB7 ${w.label}`,refValue:w.mode??"CODE",session:(0,a.jsx)("b",{className:"classroom-visit","data-visit":C.state,children:xp[C.state]}),evidence:C.timestamp,state:C.state==="present"?"OK":C.state==="missed"?"BRAK":"\u2014"},`${h}:step:${w.id}`)})]},h)}),l(_)&&b.steps.map(c=>{let h=wp(m,`${b.id}:${c.id}`,c.number);return(0,a.jsx)(Xt,{id:`${_}:step:${c.id}`,depth:4,kind:"step",title:`STEP ${String(c.number).padStart(2,"0")} \xB7 ${c.label}`,refValue:c.mode??"RUN",session:(0,a.jsx)("b",{className:"classroom-visit","data-visit":h.state,children:xp[h.state]}),evidence:h.timestamp,state:h.state==="present"?"OK":h.state==="missed"?"BRAK":"\u2014"},`${_}:step:${c.id}`)})]},_)}),l(f)&&g.exercises.length>0&&(()=>{let b=`${f}:exercises`;return(0,a.jsxs)(k.default.Fragment,{children:[(0,a.jsx)(Xt,{id:b,depth:3,kind:"exercises",title:"EXERCISES",refValue:`${g.exercises.length} EX`,session:`${S}/${g.exercises.length}`,evidence:"GIT",state:S===g.exercises.length?"DONE":"TODO",hasChildren:!0,expanded:l(b),onToggle:()=>s(b)}),l(b)&&g.exercises.map(_=>{let p=kp(m,_.id);return(0,a.jsx)(Xt,{id:`${b}:${_.id}`,depth:4,kind:"exercise",title:`EXERCISE \xB7 ${_.title}`,refValue:_.id,session:(0,a.jsx)("b",{className:"classroom-commit","data-commit":p.state,children:fh[p.state]}),evidence:p.commit,state:p.state==="committed"?"DONE":p.state==="working"?"W TOKU":"TODO"},`${b}:${_.id}`)})]},b)})()]},f)})]},m.id)})]}),(0,a.jsxs)("footer",{className:"classroom-legend",children:[(0,a.jsxs)("span",{children:[(0,a.jsx)("b",{children:"BY\u0141"})," obecny przy omawianym STEP"]}),(0,a.jsxs)("span",{children:[(0,a.jsx)("b",{children:"COMMIT"})," rozwi\u0105zanie EXERCISE zapisane w Git"]})]})]})}function hh({open:e,onClose:t}){return e?(0,a.jsx)("div",{className:"shortcut-help-backdrop",role:"presentation",onMouseDown:t,children:(0,a.jsxs)("section",{className:"shortcut-help",role:"dialog","aria-modal":"true","aria-labelledby":"shortcut-help-title",onMouseDown:r=>r.stopPropagation(),children:[(0,a.jsxs)("header",{children:[(0,a.jsxs)("div",{children:[(0,a.jsx)("small",{children:"F12 \xB7 NAWIGACJA DYDAKTYCZNA"}),(0,a.jsx)("h2",{id:"shortcut-help-title",children:"CARD \u2192 TASK \u2192 BLOCK \u2192 PHASE \u2192 STEP \u2192 SNAPSHOT"})]}),(0,a.jsx)("button",{onClick:t,"aria-label":"Zamknij skorowidz",children:"\xD7"})]}),(0,a.jsx)("dl",{children:[["Alt + \u2191 / \u2193","poprzedni / nast\u0119pny TASK"],["Ctrl + \u2191 / \u2193","poprzedni / nast\u0119pny BLOCK"],["Shift + \u2191 / \u2193","poprzednia / nast\u0119pna PHASE"],["Ctrl + Shift + \u2191 / \u2193","poprzedni / nast\u0119pny STEP"],["Alt + Shift + \u2191 / \u2193","poprzedni / nast\u0119pny unikalny SNAPSHOT"],["\u2191 / \u2193","poprzedni / nast\u0119pny element aktywnego poziomu"],["\u2192","zejd\u017A poziom ni\u017Cej"],["\u2190 / Esc","wr\xF3\u0107 poziom wy\u017Cej"],["Enter","wybierz element; przy SYNC ON odtw\xF3rz stan"],["F1","reset aktualnego celu Neovima/kontenera"],["F2","synchronizuj cel z kursorem drzewa UML"],["Ctrl + `","maksymalizuj pane, dopasuj siatk\u0119 i od\u015Bwie\u017C Neovima"],["Ctrl + Enter","zatwierd\u017A lub cofnij zatwierdzenie kroku"],["Alt + 0","wysu\u0144 lub schowaj panel serii i kart"],["Alt + 1","poka\u017C lub ukryj panel Neovima"],["Alt + 2","prze\u0142\u0105cz SYNC OFF / SYNC ON"],["Alt + 3","uzbr\xF3j lub rozbr\xF3j sterowanie Neovimem"],["Alt + 4","wysoki panel 90% / zapisana wysoko\u015B\u0107 normalna"],["Alt + 5","dopasuj ca\u0142y ekran Neovima; wy\u0142\u0105cz r\u0119czny suwak"],["Alt + 6","przypnij lub ukryj model alokatora"],["Alt + 7","po\u0142\u0105cz segmenty UML w szeroki spread / wr\xF3\u0107 do A4"],["Alt + 3, potem najed\u017A","przeka\u017C klawiatur\u0119 i mysz do aktywnej sesji"],["Alt + W","prefiks polece\u0144 okien Neovima ()"],["Alt + strza\u0142ka","przejd\u017A do s\u0105siedniego okna Neovima"],["F12","poka\u017C lub ukryj ten skorowidz"]].map(([r,o])=>(0,a.jsxs)("div",{children:[(0,a.jsx)("dt",{children:(0,a.jsx)("kbd",{children:r})}),(0,a.jsx)("dd",{children:o})]},r))}),(0,a.jsx)("p",{children:"Przy SYNC ON wyb\xF3r stepu odtwarza i weryfikuje przypi\u0119ty stan maszyny. SYNC OFF nie resetuje debuggera. Po najechaniu panel przekazuje do Neovima wy\u0142\u0105cznie kontrolowane zdarzenia klawiatury i myszy, wi\u0119c mo\u017Cna normalnie kontynuowa\u0107 debugowanie."})]})}):null}function yh({model:e}){let t=!!e.has_allocator_model,[n]=(0,k.useState)(hg),r=n.sources.find(E=>E.id===n.active_source)??n.sources[0],o=(0,k.useRef)(null),i=(0,k.useRef)(null),l=(0,k.useRef)(`browser-${globalThis.crypto?.randomUUID?.()??Math.random().toString(36).slice(2)}`),s=(0,k.useRef)(0),u=(0,k.useRef)(0),d=(0,k.useRef)(!1),m=(0,k.useRef)(!1),y=(0,k.useRef)(0),g=(0,k.useRef)(0),f=(0,k.useRef)(0),[S,b]=(0,k.useState)(2.18),[_,p]=(0,k.useState)(()=>localStorage.getItem("stem-card-nvim-visible")!=="false"),[c,h]=(0,k.useState)(()=>localStorage.getItem("stem-card-nvim-sync-mode")==="true"),[w,C]=(0,k.useState)(()=>localStorage.getItem("stem-card-nvim-sync-mode")==="true"&&localStorage.getItem("stem-card-nvim-control-mode")==="true"),[A,P]=(0,k.useState)(!1),[z,U]=(0,k.useState)(!1),[F,ae]=(0,k.useState)(()=>t&&localStorage.getItem("stem-card-allocator-visible")!=="false"),[me,q]=(0,k.useState)(()=>{let E=localStorage.getItem("stem-card-diagram-spread");return E===null?!!e.has_spread:E==="true"}),[V,Re]=(0,k.useState)({state:"hidden",syncMode:!1,syncReady:!1,controlMode:!1,controlEnabled:!1}),[Se,J]=(0,k.useState)(null),[at,bt]=(0,k.useState)(""),[Me,ge]=(0,k.useState)(null),[yr,se]=(0,k.useState)(null),[Zt,ue]=(0,k.useState)(null),[T,D]=(0,k.useState)(null),[G,te]=(0,k.useState)(!1),[st,xt]=(0,k.useState)(""),[ze,oe]=(0,k.useState)(()=>window.innerWidth),wt=Me==="library",kn=!!(Me||Zt),Dt=(0,k.useCallback)(E=>{if(E){ge("library"),se("library");return}ge(N=>N==="library"?null:N),se(N=>N==="library"?null:N)},[]),Q=(0,k.useCallback)(E=>{window.clearTimeout(f.current),xt(E),f.current=window.setTimeout(()=>xt(""),4200)},[]),Ae=(0,k.useCallback)(E=>{let N=n.sources.find(K=>K.id===E);if(!N?.available||!N.base_url){Q(`${N?.label??E} \xB7 \u017Ar\xF3d\u0142o niedost\u0119pne`);return}if(N.id===n.active_source)return;let I=Ep(N,n.current_resource_uuid,window.location.hash);if(!I){Q(`${N.label} \xB7 karta nie ma UUID zasobu`);return}window.location.assign(I)},[n,Q]),ut=(0,k.useCallback)(async E=>{Q(`${E} \xB7 wykonywanie\u2026`);try{let I=await fetch(E==="F1"?"/api/nvim/reset":"/api/navigation/sync",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({actor:l.current})}),K=await I.json().catch(()=>({}));if(!I.ok)throw new Error(K.message??K.error??`HTTP ${I.status}`);E==="F2"&&K.current?(u.current=Math.max(u.current,Number(K.current.revision??0)),window.dispatchEvent(new CustomEvent("stem:navigation-command",{detail:K.current})),Q(`F2 \xB7 ${String(K.current.step.number).padStart(2,"0")} ${K.current.step.label} \xB7 READY`)):Q("F1 \xB7 reset przyj\u0119ty"),window.setTimeout(()=>window.dispatchEvent(new Event("stem:nvim-refresh")),120)}catch(N){Q(`${E} \xB7 ${N instanceof Error?N.message:String(N)}`)}},[Q]),Ne=(0,k.useCallback)(async()=>{Q("Ctrl+` \xB7 przeliczanie widoku\u2026");try{let E=await fetch("/api/nvim/redraw",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({actor:l.current})}),N=await E.json().catch(()=>({}));if(!E.ok)throw new Error(N.message??N.error??`HTTP ${E.status}`);let I=N.external_ui?.grid,K=I?` \xB7 ${I.width}\xD7${I.height}`:"";Q(`Ctrl+\` \xB7 widok od\u015Bwie\u017Cony${K}`),window.dispatchEvent(new Event("stem:nvim-refresh"))}catch(E){Q(`Ctrl+\` \xB7 ${E instanceof Error?E.message:String(E)}`)}},[Q]),Ee=(0,k.useCallback)(async E=>{try{let N=await fetch("/api/viewer/state",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({actor:l.current,viewer:E})});if(!N.ok)return;let I=await N.json();s.current=Math.max(s.current,Number(I.viewer?.revision??0))}catch{}},[]),vr=E=>{let N=Math.max(.25,Math.min(3,E));b(N),Ee({scale:N})};(0,k.useEffect)(()=>{document.documentElement.style.setProperty("--viewer-canvas-scale",S.toFixed(3))},[S]),(0,k.useEffect)(()=>{if(!me)return;let E=i.current;if(!E)return;let N=0,I=()=>{window.cancelAnimationFrame(N),N=window.requestAnimationFrame(()=>{E.scrollLeft=Math.max(0,(E.scrollWidth-E.clientWidth)/2)})},K=window.requestAnimationFrame(I);return window.addEventListener("resize",I),()=>{window.cancelAnimationFrame(K),window.cancelAnimationFrame(N),window.removeEventListener("resize",I)}},[me,S,ze]),(0,k.useEffect)(()=>{let E=()=>oe(window.innerWidth);return window.addEventListener("resize",E),()=>window.removeEventListener("resize",E)},[]),(0,k.useEffect)(()=>{document.documentElement.dataset.nvimSyncMode=c?"on":"off"},[c]),(0,k.useEffect)(()=>{document.documentElement.dataset.cardClientId=l.current},[]);let kt=E=>{p(E),E||(P(!1),U(!1)),localStorage.setItem("stem-card-nvim-visible",String(E)),Ee({nvim:{visible:E,...E?{}:{expanded:!1,fit:!1}}})},yo=E=>{let N=E&&c;C(N),localStorage.setItem("stem-card-nvim-control-mode",String(N)),Ee({nvim:{control:N}})},vo=E=>{h(E),localStorage.setItem("stem-card-nvim-sync-mode",String(E)),E||(C(!1),localStorage.setItem("stem-card-nvim-control-mode","false")),Ee({nvim:{sync:E,control:E?w:!1}})},jn=E=>{E&&kt(!0),E&&U(!1),P(E),Ee({nvim:{visible:E||_,expanded:E,fit:!1}})},ct=E=>{E&&(kt(!0),P(!1)),U(E),Ee({nvim:{visible:E||_,fit:E,expanded:!1}})},v=E=>{let N=t&&E;ae(N),localStorage.setItem("stem-card-allocator-visible",String(N)),Ee({allocator:{visible:N}})},x=E=>{let N=!!(e.has_spread&&E);q(N),localStorage.setItem("stem-card-diagram-spread",String(N))};(0,k.useEffect)(()=>{let E=0,N=window.requestAnimationFrame(()=>{E=window.requestAnimationFrame(()=>{window.dispatchEvent(new Event("stem:nvim-refresh"))})});return()=>{window.cancelAnimationFrame(N),window.cancelAnimationFrame(E)}},[A,z]),(0,k.useEffect)(()=>{fetch("/api/progress").then(E=>E.ok?E.json():Promise.reject(new Error(`HTTP ${E.status}`))).then(E=>J(E.progress)).catch(E=>bt(`Post\u0119p dzia\u0142a tylko przez serwer karty (${E.message}).`))},[]),(0,k.useEffect)(()=>{let E=!1,N=!1,I={scale:S,viewport:{width:window.innerWidth,height:window.innerHeight},nvim:{visible:_,sync:c,control:w,expanded:A,fit:z},allocator:{visible:F}},K=B=>{let he=B.nvim.visible&&B.nvim.fit,ce=B.nvim.visible&&!he&&B.nvim.expanded;b(Math.max(.25,Math.min(3,B.scale))),p(B.nvim.visible),h(B.nvim.sync),C(B.nvim.sync&&B.nvim.control),P(ce),U(he);let Z=t&&(B.allocator?.visible??!0);ae(Z),localStorage.setItem("stem-card-nvim-visible",String(B.nvim.visible)),localStorage.setItem("stem-card-nvim-sync-mode",String(B.nvim.sync)),localStorage.setItem("stem-card-nvim-control-mode",String(B.nvim.sync&&B.nvim.control)),localStorage.setItem("stem-card-allocator-visible",String(Z));let ee=++g.current;d.current=!0,window.cancelAnimationFrame(y.current),y.current=window.requestAnimationFrame(()=>{if(ee!==g.current)return;let He=Qi();Gi(He,{left:B.scroll.x,top:B.scroll.y});let Ie=Array.from(document.querySelectorAll(".paper .sheet")),St=Ie[Math.max(0,Math.min(Ie.length-1,B.scroll.page_index))]?.querySelector(".sheet-content");St&&Number.isFinite(B.scroll.sheet_scroll_top)&&Gi(St,{top:B.scroll.sheet_scroll_top??0}),y.current=window.requestAnimationFrame(()=>{ee===g.current&&(d.current=!1,m.current&&(m.current=!1,window.dispatchEvent(new Event("stem:viewer-scroll-settled"))))})})},re=async()=>{try{let B=await fetch("/api/control/state",{cache:"no-store"});if(!B.ok||E)return;let he=await B.json(),ce=he.viewer;N||(N=!0,Number(ce?.revision??0)===0&&Ee(I)),ce&&ce.revision>s.current&&(s.current=ce.revision,ce.actor!==l.current&&K(ce));let Z=he.navigation;Z&&Z.revision>u.current&&(u.current=Z.revision,Z.actor!==l.current&&(d.current&&(m.current=!0),window.dispatchEvent(new CustomEvent("stem:navigation-command",{detail:Z}))))}catch{}};re();let W=window.setInterval(re,300);return()=>{E=!0,window.clearInterval(W),g.current+=1,window.cancelAnimationFrame(y.current),d.current=!1,m.current=!1}},[]),(0,k.useEffect)(()=>{Ee({nvim:{connection:V.state,screen_cursor:V.screenCursor,grid:V.grid}})},[V.grid?.columns,V.grid?.rows,V.screenCursor?.column,V.screenCursor?.row,V.state,Ee]),(0,k.useEffect)(()=>{let E=0,N=null,I=Array.from(document.querySelectorAll(".paper .sheet")),K=I.map(W=>W.querySelector(".sheet-content")).filter(W=>!!W),re=W=>{if(d.current)return;let B=W?.currentTarget;B instanceof HTMLElement&&B.classList.contains("sheet-content")&&(N=B),window.clearTimeout(E),E=window.setTimeout(()=>{let he=N?.closest(".sheet"),ce=he?I.indexOf(he):-1,Z=ce>=0?ce:I.reduce((He,Ie,Ke)=>{let St=Ie.getBoundingClientRect(),br=Math.abs((St.top+St.bottom)/2-window.innerHeight/2);return br=0?N:I[Z]?.querySelector(".sheet-content")??null;Ee({scroll:{x:window.scrollX,y:window.scrollY,page_index:Z,sheet_scroll_top:ee?.scrollTop??0},viewport:{width:window.innerWidth,height:window.innerHeight}}),N=null},120)};return window.addEventListener("scroll",re,{passive:!0}),window.addEventListener("resize",re),window.addEventListener("stem:viewer-scroll-settled",re),K.forEach(W=>W.addEventListener("scroll",re,{passive:!0})),re(),()=>{window.clearTimeout(E),window.removeEventListener("scroll",re),window.removeEventListener("resize",re),window.removeEventListener("stem:viewer-scroll-settled",re),K.forEach(W=>W.removeEventListener("scroll",re))}},[Ee]),(0,k.useEffect)(()=>{let E=N=>{if(N.repeat)return;let I=N.altKey&&!N.ctrlKey&&!N.metaKey?N.code:"";if(I==="Digit0"&&e.library){N.preventDefault(),N.stopImmediatePropagation(),te(!1),Dt(!wt);return}if(I==="Digit1"){N.preventDefault(),N.stopImmediatePropagation(),kt(!_);return}if(I==="Digit2"){N.preventDefault(),N.stopImmediatePropagation(),vo(!c);return}if(I==="Digit3"){if(N.preventDefault(),N.stopImmediatePropagation(),!c)return;kt(!0),yo(!w);return}if(I==="Digit4"){N.preventDefault(),N.stopImmediatePropagation(),jn(!A);return}if(I==="Digit5"){N.preventDefault(),N.stopImmediatePropagation(),ct(!z);return}if(I==="Digit6"&&t){N.preventDefault(),N.stopImmediatePropagation(),v(!F);return}if(I==="Digit7"&&e.has_spread){N.preventDefault(),N.stopImmediatePropagation(),x(!me);return}if((N.key==="F1"||N.key==="F2")&&!N.altKey&&!N.ctrlKey&&!N.metaKey&&!N.shiftKey){N.preventDefault(),N.stopImmediatePropagation(),ut(N.key);return}if(N.ctrlKey&&!N.altKey&&!N.metaKey&&!N.shiftKey&&(N.code==="Backquote"||N.key==="`")){N.preventDefault(),N.stopImmediatePropagation(),Ne();return}if(N.key==="F12"){N.preventDefault(),N.stopImmediatePropagation(),Dt(!1),ge(null),se(null),ue(null),D(null),te(K=>!K);return}if(N.key==="Escape"&&(kn||G)){N.preventDefault(),N.stopImmediatePropagation(),ge(null),se(null),ue(null),D(null),te(!1);return}};return window.addEventListener("keydown",E,!0),()=>window.removeEventListener("keydown",E,!0)},[F,me,t,wt,e.has_spread,e.library,w,A,z,c,_,ut,Ne,G,kn]),(0,k.useEffect)(()=>{let E=o.current?.querySelector(".topbar");if(!E)return;let N=()=>{document.documentElement.style.setProperty("--side-panel-top",`${Math.ceil(E.getBoundingClientRect().bottom)}px`)};N();let I=new ResizeObserver(N);return I.observe(E),window.addEventListener("resize",N),()=>{I.disconnect(),window.removeEventListener("resize",N),document.documentElement.style.removeProperty("--side-panel-top")}},[]),(0,k.useEffect)(()=>()=>window.clearTimeout(f.current),[]),(0,k.useEffect)(()=>{let E=N=>{!N.altKey||N.ctrlKey||(N.preventDefault(),b(I=>{let K=Math.max(.25,Math.min(3,I*Math.exp(-Math.max(-120,Math.min(120,N.deltaY))*.001)));return Ee({scale:K}),K}))};return window.addEventListener("wheel",E,{passive:!1}),()=>window.removeEventListener("wheel",E)},[Ee]);let R=async(E,N)=>{try{let I=await fetch(`/api/progress/${encodeURIComponent(E)}`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({status:N})});if(!I.ok)throw new Error(await I.text());J((await I.json()).progress),bt("")}catch(I){bt(`Nie zapisano post\u0119pu: ${I instanceof Error?I.message:String(I)}`)}},M=(E,N)=>{R(E,{pending:"approved",approved:"pending"}[N])},$=0,H=e.sections.map(E=>{let N=$;return $+=E.assets.length,{section:E,figureOffset:N}}),j=[];return H.forEach(E=>{let N=E.section.spread_group??"",I=j[j.length-1];if(N&&I?.spreadGroup===N){I.pages.push(E);return}j.push({key:N||E.section.id,spreadGroup:N,spreadLabel:E.section.spread_label??"",spreadColumns:E.section.spread_columns??1,pages:[E]})}),(0,a.jsxs)(a.Fragment,{children:[(0,a.jsxs)("div",{ref:o,className:`viewer-chrome${A?" is-nvim-expanded":""}${z?" is-nvim-fit":""}`,children:[(0,a.jsx)(Mg,{toc:e.toc,runtime:n,onSourceSelect:Ae,libraryAvailable:!!e.library,libraryOpen:wt,setLibraryOpen:Dt,scale:S,setScale:vr,nvimVisible:_,setNvimVisible:kt,nvimSyncMode:c,setNvimSyncMode:vo,nvimControlMode:w,setNvimControlMode:yo,nvimExpanded:A,setNvimExpanded:jn,nvimFit:z,setNvimFit:ct,allocatorVisible:F,setAllocatorVisible:v,hasAllocatorModel:t,diagramSpread:me,setDiagramSpread:x,hasDiagramSpread:!!e.has_spread,nvimSummary:V,progress:Se,progressError:at}),e.viewpoints?.length?(0,a.jsx)(Tg,{viewpoints:e.viewpoints}):null,(0,a.jsx)(Ig,{visible:t&&F,model:e}),(0,a.jsx)(Gg,{visible:_,syncMode:c,controlMode:w,expanded:A,fit:z,scale:S,onSummaryChange:Re}),st&&(0,a.jsx)("output",{className:"viewer-action-toast",children:st})]}),(0,a.jsxs)("main",{ref:i,className:`paper${me?" is-diagram-spread":""}`,children:[(0,a.jsx)(Qg,{front:e.front}),j.map(E=>{let N=Array.from({length:Math.ceil(E.pages.length/E.spreadColumns)},(B,he)=>E.pages.slice(he*E.spreadColumns,(he+1)*E.spreadColumns)),K=Math.max(1,...N.map(B=>B.reduce((he,ce)=>he+(ce.section.page_orientation==="landscape"?297:210),Math.max(0,B.length-1)*2)))*(96/25.4)*S,re=Math.min(1,Math.max(.25,(ze-24)/K)),W=E.pages.map(({section:B,figureOffset:he})=>(0,a.jsx)(lh,{section:B,progress:Se,onCycle:M,onSetStatus:R,figureOffset:he},B.id));return E.spreadGroup?(0,a.jsx)("section",{className:"sheet-spread","data-spread-group":E.spreadGroup,"aria-label":E.spreadLabel||"Wielostronicowy diagram UML",style:{"--spread-columns":E.spreadColumns,"--spread-fit-scale":re},children:W},E.key):W[0]}),e.dictionary&&(0,a.jsxs)(bs,{header:e.dictionary.header_html,footer:e.dictionary.footer_html,className:"dictionary-sheet",children:[(0,a.jsx)("h2",{children:"S\u0142ownik WE/EN/EK/KW"}),(0,a.jsx)(Ft,{html:e.dictionary.content_html})]})]}),(0,a.jsx)(bp,{side:"left",panels:[...e.library?[{id:"library",railLabel:"K",title:"Serie i karty",accent:"#167ca4",content:(0,a.jsx)(uh,{library:e.library,source:r,onNavigate:()=>Dt(!1)})}]:[],{id:"contents",railLabel:"S",title:"Spis tre\u015Bci",accent:"#16805d",content:(0,a.jsx)(ch,{toc:e.toc,onNavigate:()=>{ge(null),se(null)}})}],activeId:Me,pinnedId:yr,onActiveChange:ge,onPinnedChange:se}),(0,a.jsx)(bp,{side:"right",panels:[{id:"classroom",railLabel:"U",title:"Klasa i stanowiska",accent:"#267357",content:(0,a.jsx)(gh,{model:e})},{id:"progress",railLabel:"R",title:"Przebieg i raport",accent:"#b45b26",content:(0,a.jsx)(dh,{progress:Se,error:at})}],activeId:Zt,pinnedId:T,onActiveChange:ue,onPinnedChange:D}),(0,a.jsx)(hh,{open:G,onClose:()=>te(!1)})]})}async function vh(){let e=(0,Sp.createRoot)(document.getElementById("root"));try{let t=await fetch("./card-data.json",{cache:"no-store"});if(!t.ok)throw new Error(`Nie mo\u017Cna wczyta\u0107 card-data.json: ${t.status}`);let n=await t.json();e.render((0,a.jsx)(yh,{model:n}))}catch(t){e.render((0,a.jsxs)("main",{className:"app-load-error",children:[(0,a.jsx)("h1",{children:"Nie uda\u0142o si\u0119 uruchomi\u0107 karty"}),(0,a.jsx)("pre",{children:t instanceof Error?t.message:String(t)})]}))}}vh(); /*! Bundled license information: react/cjs/react.production.min.js: diff --git a/web/card-data.json b/web/card-data.json index 314f001..ef1a3f4 100644 --- a/web/card-data.json +++ b/web/card-data.json @@ -16,7 +16,7 @@ "status": "Gotowa", "version": "v00.01", "uuid": "87e48095-7793-54e3-9230-4e61d31bd459", - "author": "M. Pabiszczak", + "author": "Mateusz Pabiszczak", "year": "2026" }, "library": { @@ -46,6 +46,8 @@ "title": "BusyBox — the Swiss Army Knife", "repo": "lab-console-busybox", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "01", @@ -58,6 +60,8 @@ "title": "Tmux — sessions, windows and panes", "repo": "lab-console-tmux", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "02", @@ -70,6 +74,8 @@ "title": "Neovim — navigation and editing", "repo": "lab-console-neovim", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "03", @@ -82,6 +88,8 @@ "title": "Git Basics I — status, add and commit", "repo": "lab-console-git-basics-1", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "04", @@ -94,6 +102,8 @@ "title": "Git Basics II — log, diff and restore", "repo": "lab-console-git-basics-2", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "05", @@ -106,6 +116,8 @@ "title": "Git Branching I — branch, switch and merge", "repo": "lab-console-git-branching-1", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "06", @@ -118,6 +130,8 @@ "title": "Git Branching II — rebase and conflicts", "repo": "lab-console-git-branching-2", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "07", @@ -130,6 +144,8 @@ "title": "Docker Fundamentals", "repo": "lab-console-docker", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "08", @@ -152,6 +168,8 @@ "title": "Number Systems and Storage", "repo": "lab-rv32i-asm-number-systems", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "01", @@ -164,6 +182,8 @@ "title": "FPGA Bring-up and Programming", "repo": "lab-rv32i-asm-fpga-bringup", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "02", @@ -176,6 +196,8 @@ "title": "Blinker and Synchronous Logic", "repo": "lab-rv32i-asm-blinker", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "03", @@ -188,6 +210,8 @@ "title": "The RISC-V ISA and Instruction Decoder", "repo": "lab-rv32i-asm-decoder", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "04", @@ -200,6 +224,8 @@ "title": "ALU and the Verilog Assembler", "repo": "lab-rv32i-asm-alu", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "05", @@ -212,6 +238,8 @@ "title": "Control Flow — Jumps and Branches", "repo": "lab-rv32i-asm-control-flow", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "06", @@ -224,6 +252,8 @@ "title": "Addresses and Memory", "repo": "lab-rv32i-asm-addresses-memory", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "07", @@ -236,6 +266,8 @@ "title": "Subroutines and the RISC-V ABI", "repo": "lab-rv32i-asm-subroutines-abi", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "08", @@ -248,6 +280,8 @@ "title": "Load and Store", "repo": "lab-rv32i-asm-load-store", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "09", @@ -270,6 +304,8 @@ "title": "ASM, C and GCC", "repo": "lab-rv32i-strlen-asm-c-gcc", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/852fa3c7-8329-583a-a244-b639d2e04495", + "local_href": "/852fa3c7-8329-583a-a244-b639d2e04495/", + "resource_uuid": "852fa3c7-8329-583a-a244-b639d2e04495", "available": true, "current": false, "number": "01", @@ -295,6 +331,8 @@ "title": ".bss, .data and static storage", "repo": "lab-rv32i-strlen-bss-data-stack", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/74afa921-fb51-5017-bcdb-f6e84fb444d8", + "local_href": "/74afa921-fb51-5017-bcdb-f6e84fb444d8/", + "resource_uuid": "74afa921-fb51-5017-bcdb-f6e84fb444d8", "available": true, "current": false, "number": "02", @@ -324,6 +362,8 @@ "title": "ABI and Stack Frame", "repo": "lab-rv32i-strlen-abi-stack", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/72b22a0a-3297-5d75-a6ff-d1af48132d6c", + "local_href": "/72b22a0a-3297-5d75-a6ff-d1af48132d6c/", + "resource_uuid": "72b22a0a-3297-5d75-a6ff-d1af48132d6c", "available": true, "current": false, "number": "03", @@ -345,6 +385,8 @@ "title": "Types, Operators and Expressions", "repo": "lab-rv32i-c-types-operators-expressions", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/7818aa68-4983-5aca-bf7f-541cfce5c601", + "local_href": "/7818aa68-4983-5aca-bf7f-541cfce5c601/", + "resource_uuid": "7818aa68-4983-5aca-bf7f-541cfce5c601", "available": true, "current": false, "number": "04", @@ -406,6 +448,8 @@ "title": "Control Flow", "repo": "lab-rv32i-c-control-flow", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/7512361d-e5e6-5c08-ab18-8be29dacdc10", + "local_href": "/7512361d-e5e6-5c08-ab18-8be29dacdc10/", + "resource_uuid": "7512361d-e5e6-5c08-ab18-8be29dacdc10", "available": true, "current": false, "number": "05", @@ -451,6 +495,8 @@ "title": "Functions and Program Structure", "repo": "lab-rv32i-c-functions-program-structure", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/9667818d-b691-501d-817c-b58be4cbd594", + "local_href": "/9667818d-b691-501d-817c-b58be4cbd594/", + "resource_uuid": "9667818d-b691-501d-817c-b58be4cbd594", "available": true, "current": false, "number": "06", @@ -508,6 +554,8 @@ "title": "Pointers, Arrays and Linear Allocator", "repo": "lab-rv32i-c-pointers-arrays", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/98dbe323-c624-53d6-9fe2-4ee688c44b38", + "local_href": "/98dbe323-c624-53d6-9fe2-4ee688c44b38/", + "resource_uuid": "98dbe323-c624-53d6-9fe2-4ee688c44b38", "available": true, "current": false, "number": "07", @@ -569,6 +617,8 @@ "title": "Structures and Linked State", "repo": "lab-rv32i-c-structures", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/f60fbba3-a788-5f1e-bc24-52af82f227c9", + "local_href": "/f60fbba3-a788-5f1e-bc24-52af82f227c9/", + "resource_uuid": "f60fbba3-a788-5f1e-bc24-52af82f227c9", "available": true, "current": false, "number": "08", @@ -598,6 +648,8 @@ "title": "smalloc, sbrk and minimal libc", "repo": "lab-rv32i-c-smalloc-sbrk-libc", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/8e4f8bee-41f0-523b-8ea2-8926bd3d7ab0", + "local_href": "/8e4f8bee-41f0-523b-8ea2-8926bd3d7ab0/", + "resource_uuid": "8e4f8bee-41f0-523b-8ea2-8926bd3d7ab0", "available": true, "current": false, "number": "09", @@ -631,6 +683,8 @@ "title": "RV32I Traps and Interrupt Control", "repo": "lab-rv32i-c-interrupts", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/8fb9c110-557b-5081-8ae2-a56800f872e8", + "local_href": "/8fb9c110-557b-5081-8ae2-a56800f872e8/", + "resource_uuid": "8fb9c110-557b-5081-8ae2-a56800f872e8", "available": true, "current": false, "number": "10", @@ -656,6 +710,8 @@ "title": "Machine Timer and Periodic Work", "repo": "lab-rv32i-c-timer", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "11", @@ -668,6 +724,8 @@ "title": "UART — polling and interrupts", "repo": "lab-rv32i-c-uart", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/64f7c516-78b1-58ee-8619-a82d7061079f", + "local_href": "/64f7c516-78b1-58ee-8619-a82d7061079f/", + "resource_uuid": "64f7c516-78b1-58ee-8619-a82d7061079f", "available": true, "current": false, "number": "12", @@ -693,6 +751,8 @@ "title": "GPIO, Edges and Debounce", "repo": "lab-rv32i-c-gpio", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "13", @@ -722,6 +782,8 @@ "title": "Translation Units, Linkage and Namespaces", "repo": "lab-cpp-build-namespaces", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "01", @@ -734,6 +796,8 @@ "title": "Classes, Encapsulation and Invariants", "repo": "lab-cpp-classes-invariants", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "02", @@ -746,6 +810,8 @@ "title": "Construction, Destruction and RAII", "repo": "lab-cpp-lifetime-raii", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "03", @@ -758,6 +824,8 @@ "title": "References, const and Value Categories", "repo": "lab-cpp-references-const", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "04", @@ -770,6 +838,8 @@ "title": "Copy, Move and the Rule of Zero/Five", "repo": "lab-cpp-copy-move", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "05", @@ -782,6 +852,8 @@ "title": "Ownership and Resource Types", "repo": "lab-cpp-ownership", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "06", @@ -794,6 +866,8 @@ "title": "Function and Class Templates", "repo": "lab-cpp-templates", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "07", @@ -806,6 +880,8 @@ "title": "Static Polymorphism and CRTP", "repo": "lab-cpp-static-polymorphism", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "08", @@ -818,6 +894,8 @@ "title": "Inheritance, Interfaces and Dynamic Dispatch", "repo": "lab-cpp-dynamic-polymorphism", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "09", @@ -830,6 +908,8 @@ "title": "Operator Overloading and Strong Types", "repo": "lab-cpp-strong-types", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "10", @@ -842,6 +922,8 @@ "title": "Containers, Iterators and Algorithms", "repo": "lab-cpp-containers-iterators", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "11", @@ -854,6 +936,8 @@ "title": "Lambdas, Function Objects and Callables", "repo": "lab-cpp-lambdas-callables", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "12", @@ -866,6 +950,8 @@ "title": "Error Models with and without Exceptions", "repo": "lab-cpp-error-models", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "13", @@ -878,6 +964,8 @@ "title": "Object Layout, ABI and Binary Evidence", "repo": "lab-cpp-abi-evidence", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "14", @@ -890,6 +978,8 @@ "title": "Resource-type Integration Project", "repo": "lab-cpp-resource-integration", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "15", @@ -912,6 +1002,8 @@ "title": "heap_4: From Linear Cursor to Reusable Blocks", "repo": "lab-rv32i-freertos-heap4", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/aea09ab7-9bfd-5368-8d1b-c8724871c1a7", + "local_href": "/aea09ab7-9bfd-5368-8d1b-c8724871c1a7/", + "resource_uuid": "aea09ab7-9bfd-5368-8d1b-c8724871c1a7", "available": true, "current": true, "number": "01", @@ -929,6 +1021,8 @@ "title": "First Task, TCB and Task Stack", "repo": "lab-rv32i-freertos-c-first-task", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/a2538a1a-3c37-4c14-a6ea-db5aba8fd038", + "local_href": "/a2538a1a-3c37-4c14-a6ea-db5aba8fd038/", + "resource_uuid": "a2538a1a-3c37-4c14-a6ea-db5aba8fd038", "available": true, "current": false, "number": "02", @@ -946,6 +1040,8 @@ "title": "Tick, Scheduler, Priorities and Time Slicing", "repo": "lab-rv32i-freertos-c-scheduler", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/2214a13f-34c6-40a1-a561-70a00ec98285", + "local_href": "/2214a13f-34c6-40a1-a561-70a00ec98285/", + "resource_uuid": "2214a13f-34c6-40a1-a561-70a00ec98285", "available": true, "current": false, "number": "03", @@ -963,6 +1059,8 @@ "title": "Delay, Blocking and Task States", "repo": "lab-rv32i-freertos-c-delay-state", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/4a7ef04c-ab08-5783-9192-5b02a90f05f8", + "local_href": "/4a7ef04c-ab08-5783-9192-5b02a90f05f8/", + "resource_uuid": "4a7ef04c-ab08-5783-9192-5b02a90f05f8", "available": true, "current": false, "number": "04", @@ -980,6 +1078,8 @@ "title": "Queues and Byte-copy Semantics", "repo": "lab-rv32i-freertos-c-queue", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/8ee8f36a-471b-51bc-97b8-e204bd541c61", + "local_href": "/8ee8f36a-471b-51bc-97b8-e204bd541c61/", + "resource_uuid": "8ee8f36a-471b-51bc-97b8-e204bd541c61", "available": true, "current": false, "number": "05", @@ -997,6 +1097,8 @@ "title": "Software Timers and the Daemon Task", "repo": "lab-rv32i-freertos-c-software-timers", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/ab188300-f03d-5ddb-8316-b9534876a5bc", + "local_href": "/ab188300-f03d-5ddb-8316-b9534876a5bc/", + "resource_uuid": "ab188300-f03d-5ddb-8316-b9534876a5bc", "available": true, "current": false, "number": "06", @@ -1014,6 +1116,8 @@ "title": "Interrupt-safe API and Semaphore Handoff", "repo": "lab-rv32i-freertos-c-isr-semaphore", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/a6da1075-8d1f-5615-b0e6-0fc33e59e1e3", + "local_href": "/a6da1075-8d1f-5615-b0e6-0fc33e59e1e3/", + "resource_uuid": "a6da1075-8d1f-5615-b0e6-0fc33e59e1e3", "available": true, "current": false, "number": "07", @@ -1031,6 +1135,8 @@ "title": "Critical Sections, Mutexes and Priority Inheritance", "repo": "lab-rv32i-freertos-c-resource-management", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/2392f81a-ed6c-510b-86b5-06c5e2f1c6aa", + "local_href": "/2392f81a-ed6c-510b-86b5-06c5e2f1c6aa/", + "resource_uuid": "2392f81a-ed6c-510b-86b5-06c5e2f1c6aa", "available": true, "current": false, "number": "08", @@ -1048,6 +1154,8 @@ "title": "Event Groups and Multi-event Synchronization", "repo": "lab-rv32i-freertos-c-event-groups", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/3f4c1b8b-d54b-58d5-b92d-87a7233cbd9f", + "local_href": "/3f4c1b8b-d54b-58d5-b92d-87a7233cbd9f/", + "resource_uuid": "3f4c1b8b-d54b-58d5-b92d-87a7233cbd9f", "available": true, "current": false, "number": "09", @@ -1065,6 +1173,8 @@ "title": "Direct-to-task Notifications", "repo": "lab-rv32i-freertos-c-notifications", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/3b57334e-2c35-5207-a51d-9321906db078", + "local_href": "/3b57334e-2c35-5207-a51d-9321906db078/", + "resource_uuid": "3b57334e-2c35-5207-a51d-9321906db078", "available": true, "current": false, "number": "10", @@ -1082,6 +1192,8 @@ "title": "Static Allocation and Bounded Storage", "repo": "lab-rv32i-freertos-c-static-allocation", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/f4d7caf3-d665-5a2d-b9eb-39a120a64ff7", + "local_href": "/f4d7caf3-d665-5a2d-b9eb-39a120a64ff7/", + "resource_uuid": "f4d7caf3-d665-5a2d-b9eb-39a120a64ff7", "available": true, "current": false, "number": "11", @@ -1099,6 +1211,8 @@ "title": "Assertions, Hooks, Stack Checks and Runtime Diagnostics", "repo": "lab-rv32i-freertos-c-diagnostics", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/c3027314-85a4-5e4a-af13-0939c7467a62", + "local_href": "/c3027314-85a4-5e4a-af13-0939c7467a62/", + "resource_uuid": "c3027314-85a4-5e4a-af13-0939c7467a62", "available": true, "current": false, "number": "12", @@ -1116,6 +1230,8 @@ "title": "UART Interrupt-to-task Pipeline", "repo": "lab-rv32i-freertos-c-uart", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/6a838fd1-ab1b-52b6-baaf-659120a4d60a", + "local_href": "/6a838fd1-ab1b-52b6-baaf-659120a4d60a/", + "resource_uuid": "6a838fd1-ab1b-52b6-baaf-659120a4d60a", "available": true, "current": false, "number": "13", @@ -1133,6 +1249,8 @@ "title": "GPIO, Hardware Timer and Deferred Work", "repo": "lab-rv32i-freertos-c-gpio-timer", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/0cc561df-bf81-5bba-9df1-c872d5b42eb8", + "local_href": "/0cc561df-bf81-5bba-9df1-c872d5b42eb8/", + "resource_uuid": "0cc561df-bf81-5bba-9df1-c872d5b42eb8", "available": true, "current": false, "number": "14", @@ -1150,6 +1268,8 @@ "title": "Integrated Deterministic FreeRTOS C Application", "repo": "lab-rv32i-freertos-c-integration", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/fe92efeb-3c38-5975-86d8-ed630e1ad3bb", + "local_href": "/fe92efeb-3c38-5975-86d8-ed630e1ad3bb/", + "resource_uuid": "fe92efeb-3c38-5975-86d8-ed630e1ad3bb", "available": true, "current": false, "number": "15", @@ -1177,6 +1297,8 @@ "title": "C++ Task Wrapper, CRTP and Lifecycle", "repo": "lab-rv32i-freertos-task-stack-vector", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/948ce9fd-3d0c-5721-a0ae-ef422008fec8", + "local_href": "/948ce9fd-3d0c-5721-a0ae-ef422008fec8/", + "resource_uuid": "948ce9fd-3d0c-5721-a0ae-ef422008fec8", "available": true, "current": false, "number": "02", @@ -1194,6 +1316,8 @@ "title": "Vector V1 — Destructor, Move, Ownership and RAII", "repo": "lab-rv32i-freertos-vector-raii", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/de1a2818-4c30-5760-8b31-255114f82e90", + "local_href": "/de1a2818-4c30-5760-8b31-255114f82e90/", + "resource_uuid": "de1a2818-4c30-5760-8b31-255114f82e90", "available": true, "current": false, "number": "03", @@ -1211,6 +1335,8 @@ "title": "Scheduler States, Priorities and Typed Ticks", "repo": "lab-rv32i-freertos-scheduler-states", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/853a7dd7-b00b-4f4a-96e8-c160fc5bb04a", + "local_href": "/853a7dd7-b00b-4f4a-96e8-c160fc5bb04a/", + "resource_uuid": "853a7dd7-b00b-4f4a-96e8-c160fc5bb04a", "available": true, "current": false, "number": "04", @@ -1228,6 +1354,8 @@ "title": "C++ Heap Bridge, Heap Models and HeapStats", "repo": "lab-rv32i-freertos-heap-models", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/c456b505-dc5c-4894-b832-bb4c5afd0feb", + "local_href": "/c456b505-dc5c-4894-b832-bb4c5afd0feb/", + "resource_uuid": "c456b505-dc5c-4894-b832-bb4c5afd0feb", "available": true, "current": false, "number": "05", @@ -1245,6 +1373,8 @@ "title": "MemoryResource and FreeRtosAllocator", "repo": "lab-rv32i-freertos-allocator-resource", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/1af48a2e-8564-4e18-8115-b2c0208169d6", + "local_href": "/1af48a2e-8564-4e18-8115-b2c0208169d6/", + "resource_uuid": "1af48a2e-8564-4e18-8115-b2c0208169d6", "available": true, "current": false, "number": "06", @@ -1262,6 +1392,8 @@ "title": "TaskHandle_t, Explicit Start and Static Trampoline", "repo": "lab-rv32i-freertos-task-wrapper", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/9bffead0-4341-4350-806d-e975b1a3a08f", + "local_href": "/9bffead0-4341-4350-806d-e975b1a3a08f/", + "resource_uuid": "9bffead0-4341-4350-806d-e975b1a3a08f", "available": true, "current": false, "number": "07", @@ -1279,6 +1411,8 @@ "title": "DynamicTask, StaticTask, Deletion and Lifetime", "repo": "lab-rv32i-freertos-static-task", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/d9e45417-a37f-487c-813f-fc7a44d4b4f3", + "local_href": "/d9e45417-a37f-487c-813f-fc7a44d4b4f3/", + "resource_uuid": "d9e45417-a37f-487c-813f-fc7a44d4b4f3", "available": true, "current": false, "number": "08", @@ -1296,6 +1430,8 @@ "title": "Scheduler Facade and Scoped Kernel Guards", "repo": "lab-rv32i-freertos-kernel-facade", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/6a2ab068-17e7-4bfa-b726-2df37787ed69", + "local_href": "/6a2ab068-17e7-4bfa-b726-2df37787ed69/", + "resource_uuid": "6a2ab068-17e7-4bfa-b726-2df37787ed69", "available": true, "current": false, "number": "09", @@ -1313,6 +1449,8 @@ "title": "Queue and StaticQueue", "repo": "lab-rv32i-freertos-queue", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/66967c2d-bb34-4344-8064-f54d06cce47a", + "local_href": "/66967c2d-bb34-4344-8064-f54d06cce47a/", + "resource_uuid": "66967c2d-bb34-4344-8064-f54d06cce47a", "available": true, "current": false, "number": "10", @@ -1330,6 +1468,8 @@ "title": "Mutex, LockGuard and Priority Inheritance", "repo": "lab-rv32i-freertos-mutex", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/34d7ad61-6b03-4922-8e58-b8b98316e5f7", + "local_href": "/34d7ad61-6b03-4922-8e58-b8b98316e5f7/", + "resource_uuid": "34d7ad61-6b03-4922-8e58-b8b98316e5f7", "available": true, "current": false, "number": "11", @@ -1347,6 +1487,8 @@ "title": "Semaphores and Task Notifications", "repo": "lab-rv32i-freertos-semaphore-notify", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/fcb6107c-268f-4e86-a8cc-092e5875f6f0", + "local_href": "/fcb6107c-268f-4e86-a8cc-092e5875f6f0/", + "resource_uuid": "fcb6107c-268f-4e86-a8cc-092e5875f6f0", "available": true, "current": false, "number": "12", @@ -1364,6 +1506,8 @@ "title": "EventGroup and Coordinated State", "repo": "lab-rv32i-freertos-event-group", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/5fbcd7c6-3a73-4cd2-b76c-bdb016d1daaa", + "local_href": "/5fbcd7c6-3a73-4cd2-b76c-bdb016d1daaa/", + "resource_uuid": "5fbcd7c6-3a73-4cd2-b76c-bdb016d1daaa", "available": true, "current": false, "number": "13", @@ -1381,6 +1525,8 @@ "title": "Software Timer and the Timer Daemon Task", "repo": "lab-rv32i-freertos-sw-timer", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/78db37df-63e5-4c5b-80ce-f73a411f0b50", + "local_href": "/78db37df-63e5-4c5b-80ce-f73a411f0b50/", + "resource_uuid": "78db37df-63e5-4c5b-80ce-f73a411f0b50", "available": true, "current": false, "number": "14", @@ -1398,6 +1544,8 @@ "title": "Explicit FromISR, UART and GPIO Wrappers", "repo": "lab-rv32i-freertos-isr-drivers", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/02f6cd71-5c85-4883-a237-1d4ba08d9469", + "local_href": "/02f6cd71-5c85-4883-a237-1d4ba08d9469/", + "resource_uuid": "02f6cd71-5c85-4883-a237-1d4ba08d9469", "available": true, "current": false, "number": "15", @@ -1415,6 +1563,8 @@ "title": "Integrated Real-time Application and Evidence", "repo": "lab-rv32i-freertos-integration", "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/05b4f486-a27c-455d-a315-f4e51a4c66b3", + "local_href": "/05b4f486-a27c-455d-a315-f4e51a4c66b3/", + "resource_uuid": "05b4f486-a27c-455d-a315-f4e51a4c66b3", "available": true, "current": false, "number": "16", @@ -1442,6 +1592,8 @@ "title": "Process and Thread Execution Context", "repo": "lab-posix-process-thread", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "01", @@ -1454,6 +1606,8 @@ "title": "pthread_create, pthread_join and Lifecycle", "repo": "lab-posix-pthread-create-join", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "02", @@ -1466,6 +1620,8 @@ "title": "Arguments, Return Values and Ownership", "repo": "lab-posix-thread-arguments", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "03", @@ -1478,6 +1634,8 @@ "title": "Data Races and the Happens-before Question", "repo": "lab-posix-data-races", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "04", @@ -1490,6 +1648,8 @@ "title": "Mutex, Critical Section and Deadlock", "repo": "lab-posix-mutex", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "05", @@ -1502,6 +1662,8 @@ "title": "Condition Variables and Predicates", "repo": "lab-posix-condition-variable", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "06", @@ -1514,6 +1676,8 @@ "title": "Bounded Producer–Consumer Queue", "repo": "lab-posix-producer-consumer", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "07", @@ -1526,6 +1690,8 @@ "title": "POSIX Semaphores", "repo": "lab-posix-semaphore", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "08", @@ -1538,6 +1704,8 @@ "title": "Reader–Writer Lock", "repo": "lab-posix-rwlock", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "09", @@ -1550,6 +1718,8 @@ "title": "C Atomics and Memory Ordering", "repo": "lab-posix-atomics", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "10", @@ -1562,6 +1732,8 @@ "title": "Cancellation, Cleanup and Safe Shutdown", "repo": "lab-posix-cancellation-cleanup", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "11", @@ -1574,6 +1746,8 @@ "title": "Thread-local Storage", "repo": "lab-posix-thread-local", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "12", @@ -1586,6 +1760,8 @@ "title": "Scheduling Policy, Priority and Affinity", "repo": "lab-posix-scheduling", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "13", @@ -1598,6 +1774,8 @@ "title": "GDB, Sanitizers and Race Evidence", "repo": "lab-posix-thread-debugging", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "14", @@ -1610,6 +1788,8 @@ "title": "POSIX Threads vs FreeRTOS Integration", "repo": "lab-posix-freertos-comparison", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "15", @@ -1632,6 +1812,8 @@ "title": "Strategy — Replaceable Behaviour", "repo": "lab-cpp-oop-strategy", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "01", @@ -1644,6 +1826,8 @@ "title": "Adapter — Stable Boundary", "repo": "lab-cpp-oop-adapter", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "02", @@ -1656,6 +1840,8 @@ "title": "Template Method — Fixed Skeleton", "repo": "lab-cpp-oop-template-method", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "03", @@ -1668,6 +1854,8 @@ "title": "Static vs Dynamic Dispatch", "repo": "lab-cpp-oop-dispatch", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "04", @@ -1680,6 +1868,8 @@ "title": "RAII and Ownership", "repo": "lab-cpp-oop-raii", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "05", @@ -1692,6 +1882,8 @@ "title": "State — Explicit Behaviour", "repo": "lab-cpp-oop-state", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "06", @@ -1704,6 +1896,8 @@ "title": "Facade — Subsystem Boundary", "repo": "lab-cpp-oop-facade", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "07", @@ -1716,6 +1910,8 @@ "title": "Command — Request as Object", "repo": "lab-cpp-oop-command", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "08", @@ -1728,6 +1924,8 @@ "title": "Observer — Subscription and Telemetry", "repo": "lab-cpp-oop-observer", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "09", @@ -1740,6 +1938,8 @@ "title": "Factory Method — Resource Policy", "repo": "lab-cpp-oop-factory-method", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "10", @@ -1752,6 +1952,8 @@ "title": "Builder — Valid Configuration", "repo": "lab-cpp-oop-builder", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "11", @@ -1764,6 +1966,8 @@ "title": "Decorator — Measurement and Diagnostics", "repo": "lab-cpp-oop-decorator", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "12", @@ -1776,6 +1980,8 @@ "title": "Composite — Component Tree", "repo": "lab-cpp-oop-composite", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "13", @@ -1788,6 +1994,8 @@ "title": "Chain of Responsibility", "repo": "lab-cpp-oop-chain", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "14", @@ -1800,6 +2008,8 @@ "title": "Pattern-language Integration", "repo": "lab-cpp-oop-integration", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "15", @@ -1856,6 +2066,8 @@ "title": "Strategy — Replaceable Behaviour", "repo": "lab-cpp-oop-strategy", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "01", @@ -1868,6 +2080,8 @@ "title": "Adapter — Stable Boundary", "repo": "lab-cpp-oop-adapter", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "02", @@ -1880,6 +2094,8 @@ "title": "Template Method — Fixed Skeleton", "repo": "lab-cpp-oop-template-method", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "03", @@ -1892,6 +2108,8 @@ "title": "Static vs Dynamic Dispatch", "repo": "lab-cpp-oop-dispatch", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "04", @@ -1904,6 +2122,8 @@ "title": "RAII and Ownership", "repo": "lab-cpp-oop-raii", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "05", @@ -1916,6 +2136,8 @@ "title": "State — Explicit Behaviour", "repo": "lab-cpp-oop-state", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "06", @@ -1928,6 +2150,8 @@ "title": "Facade — Subsystem Boundary", "repo": "lab-cpp-oop-facade", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "07", @@ -1940,6 +2164,8 @@ "title": "Command — Request as Object", "repo": "lab-cpp-oop-command", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "08", @@ -1952,6 +2178,8 @@ "title": "Observer — Subscription and Telemetry", "repo": "lab-cpp-oop-observer", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "09", @@ -1964,6 +2192,8 @@ "title": "Factory Method — Resource Policy", "repo": "lab-cpp-oop-factory-method", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "10", @@ -1976,6 +2206,8 @@ "title": "Builder — Valid Configuration", "repo": "lab-cpp-oop-builder", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "11", @@ -1988,6 +2220,8 @@ "title": "Decorator — Measurement and Diagnostics", "repo": "lab-cpp-oop-decorator", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "12", @@ -2000,6 +2234,8 @@ "title": "Composite — Component Tree", "repo": "lab-cpp-oop-composite", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "13", @@ -2012,6 +2248,8 @@ "title": "Chain of Responsibility", "repo": "lab-cpp-oop-chain", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "14", @@ -2024,6 +2262,8 @@ "title": "Pattern-language Integration", "repo": "lab-cpp-oop-integration", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "15", @@ -2076,6 +2316,8 @@ "title": "Ruch 1D", "repo": "ruch-1d", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "", @@ -2088,6 +2330,8 @@ "title": "Ruch 2D", "repo": "ruch-2d", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "", @@ -2100,6 +2344,8 @@ "title": "Ruch po okręgu", "repo": "ruch-po-okregu", "href": "", + "local_href": "", + "resource_uuid": "", "available": false, "current": false, "number": "", @@ -2117,8 +2363,9 @@ }, "total_pages": 7, "front": { - "header_html": "
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
TITLEheap_4: From Linear Cursor to Reusable Blocks
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C nad FreeRTOS
SERIESFreeRTOS C
CARD01/15
SHEET1/7
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID87e48095-7793-54e3-9230-4e61d31bd459CARD UUIDaea09ab7-9bfd-5368-8d1b-c8724871c1a7AUTHOR  M. Pabiszczak
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
", - "left_margin_html": "
TECH
", + "header_html": "
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
TITLEheap_4: From Linear Cursor to Reusable Blocks
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C nad FreeRTOS
SERIESFreeRTOS C
CARD01/15
SHEET1/7
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID87e48095-7793-54e3-9230-4e61d31bd459CARD UUIDaea09ab7-9bfd-5368-8d1b-c8724871c1a7AUTHOR  Mateusz Pabiszczak
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
", + "footer_html": "", + "left_margin_html": "
TECH
", "right_margin_html": "
OG
", "goal_title": "Cel karty", "goal_html": "

Uczeń przechodzi od liniowego kursora z K&R 5.4 do wielokrotnego użycia tej samej areny: rozpoznaje nagłówek bloku, first-fit, split oraz dwustronne scalanie wolnych bloków w heap_4.

", @@ -2160,7 +2407,8 @@ "title": "A1 — Od liniowego kursora do odzyskiwalnej areny", "show_heading": false, "toc_entry": true, - "header_html": "
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
TITLEheap_4: From Linear Cursor to Reusable Blocks
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C nad FreeRTOS
SERIESFreeRTOS C
CARD01/15
SHEET2/7
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID87e48095-7793-54e3-9230-4e61d31bd459CARD UUIDaea09ab7-9bfd-5368-8d1b-c8724871c1a7AUTHOR  M. Pabiszczak
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
", + "header_html": "
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
TITLEheap_4: From Linear Cursor to Reusable Blocks
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C nad FreeRTOS
SERIESFreeRTOS C
CARD01/15
SHEET2/7
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID87e48095-7793-54e3-9230-4e61d31bd459CARD UUIDaea09ab7-9bfd-5368-8d1b-c8724871c1a7AUTHOR  Mateusz Pabiszczak
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
", + "footer_html": "", "left_margin_html": "
TECH
-
", "right_margin_html": "
OG
-
", "content_html": "", @@ -2199,9 +2447,9 @@ "number": 1, "label": "aplikacja żąda i zwalnia bajty", "mode": "CODE", - "strategy_ref": "code.heap4", + "strategy_ref": "code.boundary", "svg_label": "01", - "code_ref": "src/tasks/task03_freertos_heap4.c:78", + "code_ref": "src/tasks/task03_freertos_heap4.c:127", "description": "Aplikacja zna wyłącznie publiczne API i wskaźniki payloadu.", "evidence": "trzy żądania 24, 40 i 16 bajtów", "strategy": { @@ -2209,32 +2457,34 @@ "kind": "code", "action": "open", "expected_observations": [ - "heap_4 keeps metadata inside the arena", - "free blocks form one address-ordered intrusive list" + "application code calls only the public FreeRTOS allocation API", + "the selected heap implementation is linked below that API" ], "assertions": [ - "allocated bit is stored in the size field", - "xStart and pxEnd are sentinels" + "the application never edits allocator metadata", + "Hazard3 observes the same ucHeap object named by the ELF" ], "evidence_fields": [ - "symbol", - "list link", - "block size", - "arena address" + "code_ref", + "public symbol", + "arena symbol", + "target profile" ], "prerequisites": [ - "FreeRTOS-Kernel V11.3.0 available" + "K&R 5.4 linear allocator complete" ], "layout": [ + "application", + "FreeRTOS API", + "heap_4", "ucHeap", - "BlockLink_t", - "xStart", - "pxEnd" + "Hazard3" ], "commands": [ - "rg -n 'BlockLink_t|prvInsertBlockIntoFreeList|pvPortMalloc|vPortFree' vendor/FreeRTOS-Kernel/portable/MemMang/heap_4.c" + "rg -n 'pvPortMalloc|vPortFree|vPortGetHeapStats|ucHeap' src/tasks/task03_freertos_heap4.c", + "rg -n 'TASK03_KERNEL_SOURCES|HEAP4_SOURCE' Makefile" ], - "template_id": "code.heap4" + "template_id": "code.boundary" } }, { @@ -2242,9 +2492,9 @@ "number": 2, "label": "FreeRTOS wystawia malloc, free i statystyki", "mode": "CODE", - "strategy_ref": "code.heap4", + "strategy_ref": "code.boundary", "svg_label": "02", - "code_ref": "src/tasks/task03_freertos_heap4.c:90", + "code_ref": "src/tasks/task03_freertos_heap4.c:127", "description": "API oddziela eksperyment od prywatnej listy bloków.", "evidence": "pvPortMalloc, vPortFree, vPortGetHeapStats", "strategy": { @@ -2252,32 +2502,34 @@ "kind": "code", "action": "open", "expected_observations": [ - "heap_4 keeps metadata inside the arena", - "free blocks form one address-ordered intrusive list" + "application code calls only the public FreeRTOS allocation API", + "the selected heap implementation is linked below that API" ], "assertions": [ - "allocated bit is stored in the size field", - "xStart and pxEnd are sentinels" + "the application never edits allocator metadata", + "Hazard3 observes the same ucHeap object named by the ELF" ], "evidence_fields": [ - "symbol", - "list link", - "block size", - "arena address" + "code_ref", + "public symbol", + "arena symbol", + "target profile" ], "prerequisites": [ - "FreeRTOS-Kernel V11.3.0 available" + "K&R 5.4 linear allocator complete" ], "layout": [ + "application", + "FreeRTOS API", + "heap_4", "ucHeap", - "BlockLink_t", - "xStart", - "pxEnd" + "Hazard3" ], "commands": [ - "rg -n 'BlockLink_t|prvInsertBlockIntoFreeList|pvPortMalloc|vPortFree' vendor/FreeRTOS-Kernel/portable/MemMang/heap_4.c" + "rg -n 'pvPortMalloc|vPortFree|vPortGetHeapStats|ucHeap' src/tasks/task03_freertos_heap4.c", + "rg -n 'TASK03_KERNEL_SOURCES|HEAP4_SOURCE' Makefile" ], - "template_id": "code.heap4" + "template_id": "code.boundary" } }, { @@ -2287,9 +2539,9 @@ "mode": "CODE", "strategy_ref": "code.heap4", "svg_label": "03", - "code_ref": "src/tasks/task03_freertos_heap4.c:70", - "description": "Prywatny mechanizm wybiera, dzieli i scala wolne bloki.", - "evidence": "reset i inicjalizacja listy", + "code_ref": "UPSTREAM.md:1", + "description": "Prywatny mechanizm wybiera, dzieli i scala wolne bloki; strategia otwiera prawdziwy heap_4.c.", + "evidence": "prvHeapInit i prvInsertBlockIntoFreeList", "strategy": { "id": "task01/a1/boundary/allocator", "kind": "code", @@ -2318,7 +2570,7 @@ "pxEnd" ], "commands": [ - "rg -n 'BlockLink_t|prvInsertBlockIntoFreeList|pvPortMalloc|vPortFree' vendor/FreeRTOS-Kernel/portable/MemMang/heap_4.c" + "rg -n 'BlockLink_t|prvHeapInit|prvInsertBlockIntoFreeList|pvPortMalloc|vPortFree' ${FREERTOS_KERNEL_PATH:-/opt/FreeRTOS-Kernel}/portable/MemMang/heap_4.c" ], "template_id": "code.heap4" } @@ -2328,7 +2580,7 @@ "number": 4, "label": "ucHeap jest jedną ograniczoną areną", "mode": "CODE", - "strategy_ref": "code.heap4", + "strategy_ref": "code.boundary", "svg_label": "04", "code_ref": "src/tasks/task03_freertos_heap4.c:11", "description": "Metadane i payload znajdują się w tej samej statycznej tablicy.", @@ -2338,32 +2590,34 @@ "kind": "code", "action": "open", "expected_observations": [ - "heap_4 keeps metadata inside the arena", - "free blocks form one address-ordered intrusive list" + "application code calls only the public FreeRTOS allocation API", + "the selected heap implementation is linked below that API" ], "assertions": [ - "allocated bit is stored in the size field", - "xStart and pxEnd are sentinels" + "the application never edits allocator metadata", + "Hazard3 observes the same ucHeap object named by the ELF" ], "evidence_fields": [ - "symbol", - "list link", - "block size", - "arena address" + "code_ref", + "public symbol", + "arena symbol", + "target profile" ], "prerequisites": [ - "FreeRTOS-Kernel V11.3.0 available" + "K&R 5.4 linear allocator complete" ], "layout": [ + "application", + "FreeRTOS API", + "heap_4", "ucHeap", - "BlockLink_t", - "xStart", - "pxEnd" + "Hazard3" ], "commands": [ - "rg -n 'BlockLink_t|prvInsertBlockIntoFreeList|pvPortMalloc|vPortFree' vendor/FreeRTOS-Kernel/portable/MemMang/heap_4.c" + "rg -n 'pvPortMalloc|vPortFree|vPortGetHeapStats|ucHeap' src/tasks/task03_freertos_heap4.c", + "rg -n 'TASK03_KERNEL_SOURCES|HEAP4_SOURCE' Makefile" ], - "template_id": "code.heap4" + "template_id": "code.boundary" } }, { @@ -2386,7 +2640,8 @@ ], "assertions": [ "pvPortMalloc and vPortFree are present", - "prvInsertBlockIntoFreeList is present" + "prvInsertBlockIntoFreeList is present", + "all eight replay checkpoint symbols are present" ], "evidence_fields": [ "source blob", @@ -2460,7 +2715,8 @@ "title": "A2 — Nagłówek, payload i lista wolnych bloków", "show_heading": false, "toc_entry": true, - "header_html": "
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
TITLEheap_4: From Linear Cursor to Reusable Blocks
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C nad FreeRTOS
SERIESFreeRTOS C
CARD01/15
SHEET3/7
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID87e48095-7793-54e3-9230-4e61d31bd459CARD UUIDaea09ab7-9bfd-5368-8d1b-c8724871c1a7AUTHOR  M. Pabiszczak
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
", + "header_html": "
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
TITLEheap_4: From Linear Cursor to Reusable Blocks
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C nad FreeRTOS
SERIESFreeRTOS C
CARD01/15
SHEET3/7
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID87e48095-7793-54e3-9230-4e61d31bd459CARD UUIDaea09ab7-9bfd-5368-8d1b-c8724871c1a7AUTHOR  Mateusz Pabiszczak
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
", + "footer_html": "", "left_margin_html": "
TECH
-
", "right_margin_html": "
OG
-
", "content_html": "", @@ -2497,259 +2753,295 @@ { "id": "header", "number": 1, - "label": "nagłówek przechowuje next i size", + "label": "nagłówek RV32 przechowuje next i size", "mode": "CODE", - "strategy_ref": "code.model", + "strategy_ref": "code.heap4", "svg_label": "01", - "code_ref": "src/tasks/heap4_model.h:11", - "description": "ModelBlock pokazuje minimalny kontrakt metadanych heap_4.", - "evidence": "dwa słowa metadanych", + "code_ref": "UPSTREAM.md:1", + "description": "Prawdziwy BlockLink_t zawiera wskaźnik i size_t, po 4 bajty na RV32; port wyrównuje nagłówek do 16 bajtów.", + "evidence": "sizeof(BlockLink_t)=8; portBYTE_ALIGNMENT=16; xHeapStructSize=16", "strategy": { "id": "task01/a2/blocks/header", "kind": "code", "action": "open", "expected_observations": [ - "requested size includes header and alignment", - "free list is ordered by block address" + "heap_4 keeps metadata inside the arena", + "free blocks form one address-ordered intrusive list" ], "assertions": [ - "payload begins after the header", - "split preserves the total arena size" + "allocated bit is stored in the size field", + "xStart and pxEnd are sentinels" ], "evidence_fields": [ - "code_ref", - "header bytes", - "wanted bytes", - "block address" + "symbol", + "list link", + "block size", + "arena address" ], "prerequisites": [ - "K&R 5.4 linear allocator complete" + "FreeRTOS-Kernel V11.3.0 available" ], "layout": [ - "header", - "payload", - "remainder", - "address-ordered list" + "ucHeap", + "BlockLink_t", + "xStart", + "pxEnd" ], "commands": [ - "rg -n 'ModelBlock|align_up|insert_and_coalesce' src/tasks" + "rg -n 'BlockLink_t|prvHeapInit|prvInsertBlockIntoFreeList|pvPortMalloc|vPortFree' ${FREERTOS_KERNEL_PATH:-/opt/FreeRTOS-Kernel}/portable/MemMang/heap_4.c" ], - "template_id": "code.model" + "template_id": "code.heap4" } }, { "id": "alignment", "number": 2, - "label": "żądanie obejmuje nagłówek i wyrównanie", - "mode": "CODE", - "strategy_ref": "code.model", + "label": "A(24) obejmuje nagłówek i wyrównanie", + "mode": "RUN", + "event_id": "E02", + "strategy_ref": "run.timeline", "svg_label": "02", - "code_ref": "src/tasks/task01_first_fit_split.c:3", - "description": "13 bajtów payloadu zajmuje 32 bajty całego bloku.", - "evidence": "header=16, wanted=32", + "code_ref": "src/tasks/task03_freertos_heap4.c:137", + "snapshot_ref": "task01.alloc-a", + "description": "Różnica licznika wolnych bajtów mierzy cały blok, nie sam payload.", + "evidence": "g_a_consumed = 48; g_a_aligned = 1", "strategy": { "id": "task01/a2/blocks/alignment", - "kind": "code", - "action": "open", + "kind": "run", + "action": "replay", "expected_observations": [ - "requested size includes header and alignment", - "free list is ordered by block address" + "every checkpoint is reached from a clean reset with the same ELF", + "free bytes change by the aligned whole-block size, not by payload alone" ], "assertions": [ - "payload begins after the header", - "split preserves the total arena size" + "A, B and C are aligned", + "the free-byte sequence is strictly decreasing during allocation" ], "evidence_fields": [ - "code_ref", - "header bytes", - "wanted bytes", - "block address" + "payload pointer", + "consumed bytes", + "available bytes", + "free-list statistics" ], "prerequisites": [ - "K&R 5.4 linear allocator complete" + "clean Hazard3 RAM", + "task03 image loaded" ], "layout": [ - "header", - "payload", - "remainder", - "address-ordered list" + "current checkpoint", + "source call", + "heap statistics", + "ucHeap memory" ], "commands": [ - "rg -n 'ModelBlock|align_up|insert_and_coalesce' src/tasks" + "print g_initial_free", + "print g_after_a_free", + "print g_after_b_free", + "print g_after_allocations", + "print g_a_consumed", + "print g_b_consumed", + "print g_c_consumed" ], - "template_id": "code.model" + "template_id": "run.timeline" } }, { "id": "split", "number": 3, "label": "split pozostawia osobny wolny blok", - "mode": "CODE", - "strategy_ref": "code.model", + "mode": "RUN", + "event_id": "E02", + "strategy_ref": "run.timeline", "svg_label": "03", - "code_ref": "src/tasks/task01_first_fit_split.c:43", - "description": "Reszta zachowuje własny nagłówek i trafia na listę wolnych.", - "evidence": "32 + 224 = 256", + "code_ref": "src/tasks/task03_freertos_heap4.c:137", + "snapshot_ref": "task01.alloc-a", + "description": "Po pierwszym first-fit pozostała część areny nadal jest jednym wolnym blokiem.", + "evidence": "free = 4032; free blocks = 1", "strategy": { "id": "task01/a2/blocks/split", - "kind": "code", - "action": "open", + "kind": "run", + "action": "replay", "expected_observations": [ - "requested size includes header and alignment", - "free list is ordered by block address" + "every checkpoint is reached from a clean reset with the same ELF", + "free bytes change by the aligned whole-block size, not by payload alone" ], "assertions": [ - "payload begins after the header", - "split preserves the total arena size" + "A, B and C are aligned", + "the free-byte sequence is strictly decreasing during allocation" ], "evidence_fields": [ - "code_ref", - "header bytes", - "wanted bytes", - "block address" + "payload pointer", + "consumed bytes", + "available bytes", + "free-list statistics" ], "prerequisites": [ - "K&R 5.4 linear allocator complete" + "clean Hazard3 RAM", + "task03 image loaded" ], "layout": [ - "header", - "payload", - "remainder", - "address-ordered list" + "current checkpoint", + "source call", + "heap statistics", + "ucHeap memory" ], "commands": [ - "rg -n 'ModelBlock|align_up|insert_and_coalesce' src/tasks" + "print g_initial_free", + "print g_after_a_free", + "print g_after_b_free", + "print g_after_allocations", + "print g_a_consumed", + "print g_b_consumed", + "print g_c_consumed" ], - "template_id": "code.model" + "template_id": "run.timeline" } }, { "id": "address-order", "number": 4, "label": "lista jest uporządkowana rosnącymi adresami", - "mode": "CODE", - "strategy_ref": "code.model", + "mode": "RUN", + "event_id": "E06", + "strategy_ref": "run.fragmented", "svg_label": "04", - "code_ref": "src/tasks/task02_address_order_coalesce.c:29", + "code_ref": "src/tasks/task03_freertos_heap4.c:168", + "snapshot_ref": "task01.fragmented", "description": "Pozycja w liście ujawnia bezpośredniego poprzednika i następnika.", - "evidence": "previous < block < current", + "evidence": "g_a < g_b < g_c; dwa wolne obszary", "strategy": { "id": "task01/a2/blocks/address-order", - "kind": "code", - "action": "open", + "kind": "run", + "action": "replay", "expected_observations": [ - "requested size includes header and alignment", - "free list is ordered by block address" + "A and C are free while B remains allocated", + "the free list contains two blocks" ], "assertions": [ - "payload begins after the header", - "split preserves the total arena size" + "xNumberOfFreeBlocks equals 2", + "current free bytes exceed the largest free block" ], "evidence_fields": [ - "code_ref", - "header bytes", - "wanted bytes", - "block address" + "free blocks", + "largest block", + "free bytes", + "heap bytes" ], "prerequisites": [ - "K&R 5.4 linear allocator complete" + "clean Hazard3 RAM", + "task03 image loaded" ], "layout": [ - "header", - "payload", - "remainder", - "address-ordered list" + "source", + "free-list stats", + "ucHeap memory", + "registers" ], "commands": [ - "rg -n 'ModelBlock|align_up|insert_and_coalesce' src/tasks" + "break heap4_fragmented_checkpoint", + "print g_fragmented_stats", + "print g_fragmented_free", + "x/96bx ucHeap" ], - "template_id": "code.model" - } - }, - { - "id": "right-join", - "number": 5, - "label": "blok scala się z prawym sąsiadem", - "mode": "CODE", - "strategy_ref": "code.model", - "svg_label": "05", - "code_ref": "src/tasks/task02_address_order_coalesce.c:40", - "description": "Koniec zwalnianego bloku równy adresowi current oznacza ciągłość.", - "evidence": "block + size == current", - "strategy": { - "id": "task01/a2/blocks/right-join", - "kind": "code", - "action": "open", - "expected_observations": [ - "requested size includes header and alignment", - "free list is ordered by block address" - ], - "assertions": [ - "payload begins after the header", - "split preserves the total arena size" - ], - "evidence_fields": [ - "code_ref", - "header bytes", - "wanted bytes", - "block address" - ], - "prerequisites": [ - "K&R 5.4 linear allocator complete" - ], - "layout": [ - "header", - "payload", - "remainder", - "address-ordered list" - ], - "commands": [ - "rg -n 'ModelBlock|align_up|insert_and_coalesce' src/tasks" - ], - "template_id": "code.model" + "template_id": "run.fragmented" } }, { "id": "left-join", - "number": 6, - "label": "wynik scala się z lewym sąsiadem", - "mode": "CODE", - "strategy_ref": "code.model", - "svg_label": "06", - "code_ref": "src/tasks/task02_address_order_coalesce.c:48", - "description": "Drugi test domyka dwustronne scalanie w jeden blok.", - "evidence": "previous + size == block", + "number": 5, + "label": "heap_4 scala najpierw poprzedni blok", + "mode": "RUN", + "event_id": "E06", + "strategy_ref": "run.coalescing", + "svg_label": "05", + "code_ref": "src/tasks/task03_freertos_heap4.c:173", + "snapshot_ref": "task01.fragmented", + "description": "Replay E06, tymczasowy breakpoint i step w prywatnej funkcji pokazują pierwszy test ciągłości.", + "evidence": "previous + previous.size == inserted", "strategy": { "id": "task01/a2/blocks/left-join", - "kind": "code", - "action": "open", + "kind": "run", + "action": "replay", "expected_observations": [ - "requested size includes header and alignment", - "free list is ordered by block address" + "the replay stops after free(C), immediately before free(B)", + "inside prvInsertBlockIntoFreeList the previous block is merged before the next block" ], "assertions": [ - "payload begins after the header", - "split preserves the total arena size" + "pxIterator < pxBlockToInsert < pxIterator->pxNextFreeBlock", + "the left adjacency test is evaluated before the right adjacency test" ], "evidence_fields": [ - "code_ref", - "header bytes", - "wanted bytes", - "block address" + "pxIterator", + "pxBlockToInsert", + "left end address", + "right start address" ], "prerequisites": [ - "K&R 5.4 linear allocator complete" + "task01.fragmented replay ready" ], "layout": [ - "header", - "payload", - "remainder", - "address-ordered list" + "application call vPortFree(g_b)", + "prvInsertBlockIntoFreeList", + "free-list links", + "ucHeap addresses" ], "commands": [ - "rg -n 'ModelBlock|align_up|insert_and_coalesce' src/tasks" + "tbreak prvInsertBlockIntoFreeList", + "continue", + "print pxIterator", + "print pxBlockToInsert", + "next" ], - "template_id": "code.model" + "template_id": "run.coalescing" + } + }, + { + "id": "right-join", + "number": 6, + "label": "następnie scala prawy blok", + "mode": "RUN", + "event_id": "E06", + "strategy_ref": "run.coalescing", + "svg_label": "06", + "code_ref": "src/tasks/task03_freertos_heap4.c:173", + "snapshot_ref": "task01.fragmented", + "description": "Drugi test wykorzystuje już powiększony lewy blok i domyka scalenie areny.", + "evidence": "merged + merged.size == current", + "strategy": { + "id": "task01/a2/blocks/right-join", + "kind": "run", + "action": "replay", + "expected_observations": [ + "the replay stops after free(C), immediately before free(B)", + "inside prvInsertBlockIntoFreeList the previous block is merged before the next block" + ], + "assertions": [ + "pxIterator < pxBlockToInsert < pxIterator->pxNextFreeBlock", + "the left adjacency test is evaluated before the right adjacency test" + ], + "evidence_fields": [ + "pxIterator", + "pxBlockToInsert", + "left end address", + "right start address" + ], + "prerequisites": [ + "task01.fragmented replay ready" + ], + "layout": [ + "application call vPortFree(g_b)", + "prvInsertBlockIntoFreeList", + "free-list links", + "ucHeap addresses" + ], + "commands": [ + "tbreak prvInsertBlockIntoFreeList", + "continue", + "print pxIterator", + "print pxBlockToInsert", + "next" + ], + "template_id": "run.coalescing" } } ] @@ -2765,11 +3057,11 @@ "columns": 1, "x": 0.0, "y": 0.0, - "width": 295.0, + "width": 312.0, "height": 620.0, "full_x": 0.0, "full_y": 0.0, - "full_width": 295.0, + "full_width": 312.0, "full_height": 620.0, "page_width": 660.0, "page_height": 760.0, @@ -2805,7 +3097,8 @@ "title": "A5 — First-fit, fragmentacja i pełne scalenie", "show_heading": false, "toc_entry": true, - "header_html": "
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
TITLEheap_4: From Linear Cursor to Reusable Blocks
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C nad FreeRTOS
SERIESFreeRTOS C
CARD01/15
SHEET4/7
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID87e48095-7793-54e3-9230-4e61d31bd459CARD UUIDaea09ab7-9bfd-5368-8d1b-c8724871c1a7AUTHOR  M. Pabiszczak
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
", + "header_html": "
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
TITLEheap_4: From Linear Cursor to Reusable Blocks
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C nad FreeRTOS
SERIESFreeRTOS C
CARD01/15
SHEET4/7
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID87e48095-7793-54e3-9230-4e61d31bd459CARD UUIDaea09ab7-9bfd-5368-8d1b-c8724871c1a7AUTHOR  Mateusz Pabiszczak
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
", + "footer_html": "", "left_margin_html": "
TECH
-
", "right_margin_html": "
OG
-
", "content_html": "", @@ -2843,186 +3136,274 @@ "id": "reset", "number": 1, "label": "reset i inicjalizacja areny", - "mode": "CODE", - "strategy_ref": "code.heap4", + "mode": "RUN", + "event_id": "E01", + "strategy_ref": "run.timeline", "svg_label": "01", - "code_ref": "src/tasks/task03_freertos_heap4.c:70", - "description": "Pierwsze małe żądanie inicjalizuje sentinele i listę.", - "evidence": "initial free = 4080", + "code_ref": "src/tasks/task03_freertos_heap4.c:127", + "snapshot_ref": "task01.reset", + "description": "Próbne żądanie inicjalizuje sentinele; po jego zwolnieniu arena ma jeden blok.", + "evidence": "free = largest = 4080; blocks = 1", "strategy": { "id": "task01/a5/replay/reset", - "kind": "code", - "action": "open", + "kind": "run", + "action": "replay", "expected_observations": [ - "heap_4 keeps metadata inside the arena", - "free blocks form one address-ordered intrusive list" + "every checkpoint is reached from a clean reset with the same ELF", + "free bytes change by the aligned whole-block size, not by payload alone" ], "assertions": [ - "allocated bit is stored in the size field", - "xStart and pxEnd are sentinels" + "A, B and C are aligned", + "the free-byte sequence is strictly decreasing during allocation" ], "evidence_fields": [ - "symbol", - "list link", - "block size", - "arena address" + "payload pointer", + "consumed bytes", + "available bytes", + "free-list statistics" ], "prerequisites": [ - "FreeRTOS-Kernel V11.3.0 available" + "clean Hazard3 RAM", + "task03 image loaded" ], "layout": [ - "ucHeap", - "BlockLink_t", - "xStart", - "pxEnd" + "current checkpoint", + "source call", + "heap statistics", + "ucHeap memory" ], "commands": [ - "rg -n 'BlockLink_t|prvInsertBlockIntoFreeList|pvPortMalloc|vPortFree' vendor/FreeRTOS-Kernel/portable/MemMang/heap_4.c" + "print g_initial_free", + "print g_after_a_free", + "print g_after_b_free", + "print g_after_allocations", + "print g_a_consumed", + "print g_b_consumed", + "print g_c_consumed" ], - "template_id": "code.heap4" + "template_id": "run.timeline" } }, { "id": "alloc-a", "number": 2, "label": "first-fit przydziela A", - "mode": "CODE", - "strategy_ref": "code.heap4", + "mode": "RUN", + "event_id": "E02", + "strategy_ref": "run.timeline", "svg_label": "02", - "code_ref": "src/tasks/task03_freertos_heap4.c:78", + "code_ref": "src/tasks/task03_freertos_heap4.c:137", + "snapshot_ref": "task01.alloc-a", "description": "Pierwszy wystarczający blok zostaje rozdzielony.", - "evidence": "A payload = 24", + "evidence": "A=24; consumed=48; free=4032", "strategy": { "id": "task01/a5/replay/alloc-a", - "kind": "code", - "action": "open", + "kind": "run", + "action": "replay", "expected_observations": [ - "heap_4 keeps metadata inside the arena", - "free blocks form one address-ordered intrusive list" + "every checkpoint is reached from a clean reset with the same ELF", + "free bytes change by the aligned whole-block size, not by payload alone" ], "assertions": [ - "allocated bit is stored in the size field", - "xStart and pxEnd are sentinels" + "A, B and C are aligned", + "the free-byte sequence is strictly decreasing during allocation" ], "evidence_fields": [ - "symbol", - "list link", - "block size", - "arena address" + "payload pointer", + "consumed bytes", + "available bytes", + "free-list statistics" ], "prerequisites": [ - "FreeRTOS-Kernel V11.3.0 available" + "clean Hazard3 RAM", + "task03 image loaded" ], "layout": [ - "ucHeap", - "BlockLink_t", - "xStart", - "pxEnd" + "current checkpoint", + "source call", + "heap statistics", + "ucHeap memory" ], "commands": [ - "rg -n 'BlockLink_t|prvInsertBlockIntoFreeList|pvPortMalloc|vPortFree' vendor/FreeRTOS-Kernel/portable/MemMang/heap_4.c" + "print g_initial_free", + "print g_after_a_free", + "print g_after_b_free", + "print g_after_allocations", + "print g_a_consumed", + "print g_b_consumed", + "print g_c_consumed" ], - "template_id": "code.heap4" + "template_id": "run.timeline" } }, { - "id": "alloc-bc", + "id": "alloc-b", "number": 3, - "label": "kolejne split tworzą B i C", - "mode": "CODE", - "strategy_ref": "code.heap4", + "label": "kolejny split tworzy B", + "mode": "RUN", + "event_id": "E03", + "strategy_ref": "run.timeline", "svg_label": "03", - "code_ref": "src/tasks/task03_freertos_heap4.c:79", - "description": "B i C zajmują kolejne fragmenty tego samego wolnego bloku.", - "evidence": "after allocations = 3952", + "code_ref": "src/tasks/task03_freertos_heap4.c:145", + "snapshot_ref": "task01.alloc-b", + "description": "B zajmuje następny fragment tej samej reszty.", + "evidence": "B=40; consumed=64; free=3968", "strategy": { - "id": "task01/a5/replay/alloc-bc", - "kind": "code", - "action": "open", + "id": "task01/a5/replay/alloc-b", + "kind": "run", + "action": "replay", "expected_observations": [ - "heap_4 keeps metadata inside the arena", - "free blocks form one address-ordered intrusive list" + "every checkpoint is reached from a clean reset with the same ELF", + "free bytes change by the aligned whole-block size, not by payload alone" ], "assertions": [ - "allocated bit is stored in the size field", - "xStart and pxEnd are sentinels" + "A, B and C are aligned", + "the free-byte sequence is strictly decreasing during allocation" ], "evidence_fields": [ - "symbol", - "list link", - "block size", - "arena address" + "payload pointer", + "consumed bytes", + "available bytes", + "free-list statistics" ], "prerequisites": [ - "FreeRTOS-Kernel V11.3.0 available" + "clean Hazard3 RAM", + "task03 image loaded" ], "layout": [ - "ucHeap", - "BlockLink_t", - "xStart", - "pxEnd" + "current checkpoint", + "source call", + "heap statistics", + "ucHeap memory" ], "commands": [ - "rg -n 'BlockLink_t|prvInsertBlockIntoFreeList|pvPortMalloc|vPortFree' vendor/FreeRTOS-Kernel/portable/MemMang/heap_4.c" + "print g_initial_free", + "print g_after_a_free", + "print g_after_b_free", + "print g_after_allocations", + "print g_a_consumed", + "print g_b_consumed", + "print g_c_consumed" ], - "template_id": "code.heap4" + "template_id": "run.timeline" } }, { - "id": "free-ac", + "id": "alloc-c", "number": 4, - "label": "zwolnij A i C, pozostaw B", - "mode": "CODE", - "strategy_ref": "code.heap4", + "label": "trzeci split tworzy C", + "mode": "RUN", + "event_id": "E04", + "strategy_ref": "run.timeline", "svg_label": "04", - "code_ref": "src/tasks/task03_freertos_heap4.c:88", - "description": "C scala się z prawą resztą, ale B oddziela ją od A.", - "evidence": "dwa wolne bloki", + "code_ref": "src/tasks/task03_freertos_heap4.c:153", + "snapshot_ref": "task01.alloc-c", + "description": "A, B i C są wyrównane, a za nimi pozostaje jedna wolna reszta.", + "evidence": "C=16; consumed=32; free=3936", "strategy": { - "id": "task01/a5/replay/free-ac", - "kind": "code", - "action": "open", + "id": "task01/a5/replay/alloc-c", + "kind": "run", + "action": "replay", "expected_observations": [ - "heap_4 keeps metadata inside the arena", - "free blocks form one address-ordered intrusive list" + "every checkpoint is reached from a clean reset with the same ELF", + "free bytes change by the aligned whole-block size, not by payload alone" ], "assertions": [ - "allocated bit is stored in the size field", - "xStart and pxEnd are sentinels" + "A, B and C are aligned", + "the free-byte sequence is strictly decreasing during allocation" ], "evidence_fields": [ - "symbol", - "list link", - "block size", - "arena address" + "payload pointer", + "consumed bytes", + "available bytes", + "free-list statistics" ], "prerequisites": [ - "FreeRTOS-Kernel V11.3.0 available" + "clean Hazard3 RAM", + "task03 image loaded" ], "layout": [ - "ucHeap", - "BlockLink_t", - "xStart", - "pxEnd" + "current checkpoint", + "source call", + "heap statistics", + "ucHeap memory" ], "commands": [ - "rg -n 'BlockLink_t|prvInsertBlockIntoFreeList|pvPortMalloc|vPortFree' vendor/FreeRTOS-Kernel/portable/MemMang/heap_4.c" + "print g_initial_free", + "print g_after_a_free", + "print g_after_b_free", + "print g_after_allocations", + "print g_a_consumed", + "print g_b_consumed", + "print g_c_consumed" ], - "template_id": "code.heap4" + "template_id": "run.timeline" + } + }, + { + "id": "free-a", + "number": 5, + "label": "zwolnij A, pozostaw B i C", + "mode": "RUN", + "event_id": "E05", + "strategy_ref": "run.timeline", + "svg_label": "05", + "code_ref": "src/tasks/task03_freertos_heap4.c:163", + "snapshot_ref": "task01.free-a", + "description": "Wolny A i końcowa reszta są rozdzielone przez B i C.", + "evidence": "blocks=2; free=3984", + "strategy": { + "id": "task01/a5/replay/free-a", + "kind": "run", + "action": "replay", + "expected_observations": [ + "every checkpoint is reached from a clean reset with the same ELF", + "free bytes change by the aligned whole-block size, not by payload alone" + ], + "assertions": [ + "A, B and C are aligned", + "the free-byte sequence is strictly decreasing during allocation" + ], + "evidence_fields": [ + "payload pointer", + "consumed bytes", + "available bytes", + "free-list statistics" + ], + "prerequisites": [ + "clean Hazard3 RAM", + "task03 image loaded" + ], + "layout": [ + "current checkpoint", + "source call", + "heap statistics", + "ucHeap memory" + ], + "commands": [ + "print g_initial_free", + "print g_after_a_free", + "print g_after_b_free", + "print g_after_allocations", + "print g_a_consumed", + "print g_b_consumed", + "print g_c_consumed" + ], + "template_id": "run.timeline" } }, { "id": "fragmented", - "number": 5, - "label": "checkpoint fragmentacji", + "number": 6, + "label": "zwolnij C, pozostaw B", "mode": "RUN", - "event_id": "E01", + "event_id": "E06", "strategy_ref": "run.fragmented", - "svg_label": "05", - "code_ref": "src/tasks/task03_freertos_heap4.c:91", + "svg_label": "06", + "code_ref": "src/tasks/task03_freertos_heap4.c:168", "snapshot_ref": "task01.fragmented", - "description": "GDB zatrzymuje program przy dwóch wolnych blokach.", - "evidence": "xNumberOfFreeBlocks = 2", + "description": "C scala się z prawą resztą, ale B nadal rozdziela dwa wolne obszary.", + "evidence": "blocks=2; free=4016; free>largest", "strategy": { "id": "task01/a5/replay/fragmented", "kind": "run", @@ -3054,66 +3435,24 @@ "commands": [ "break heap4_fragmented_checkpoint", "print g_fragmented_stats", - "x/64bx ucHeap" + "print g_fragmented_free", + "x/96bx ucHeap" ], "template_id": "run.fragmented" } }, - { - "id": "free-b", - "number": 6, - "label": "zwolnij B między dwoma sąsiadami", - "mode": "CODE", - "strategy_ref": "code.heap4", - "svg_label": "06", - "code_ref": "src/tasks/task03_freertos_heap4.c:93", - "description": "Wstawienie adresowe umożliwia dwa testy ciągłości.", - "evidence": "A + B + C + reszta są ciągłe", - "strategy": { - "id": "task01/a5/replay/free-b", - "kind": "code", - "action": "open", - "expected_observations": [ - "heap_4 keeps metadata inside the arena", - "free blocks form one address-ordered intrusive list" - ], - "assertions": [ - "allocated bit is stored in the size field", - "xStart and pxEnd are sentinels" - ], - "evidence_fields": [ - "symbol", - "list link", - "block size", - "arena address" - ], - "prerequisites": [ - "FreeRTOS-Kernel V11.3.0 available" - ], - "layout": [ - "ucHeap", - "BlockLink_t", - "xStart", - "pxEnd" - ], - "commands": [ - "rg -n 'BlockLink_t|prvInsertBlockIntoFreeList|pvPortMalloc|vPortFree' vendor/FreeRTOS-Kernel/portable/MemMang/heap_4.c" - ], - "template_id": "code.heap4" - } - }, { "id": "coalesced", "number": 7, - "label": "arena wraca do jednego bloku", + "label": "zwolnij B i scal oba sąsiednie bloki", "mode": "RUN", - "event_id": "E02", + "event_id": "E07", "strategy_ref": "run.coalesced", "svg_label": "07", - "code_ref": "src/tasks/task03_freertos_heap4.c:96", + "code_ref": "src/tasks/task03_freertos_heap4.c:173", "snapshot_ref": "task01.coalesced", - "description": "Finalne statystyki dowodzą pełnego odzyskania areny.", - "evidence": "final free = initial free; blocks = 1", + "description": "Scalenie lewego, a potem prawego sąsiada przywraca jeden blok.", + "evidence": "free=largest=initial=4080; blocks=1", "strategy": { "id": "task01/a5/replay/coalesced", "kind": "run", @@ -3124,15 +3463,14 @@ ], "assertions": [ "final free equals initial free", - "minimum-ever does not rise after free", - "oversized allocation returns NULL and calls the hook once" + "one free block is also the largest block", + "minimum-ever does not rise after free" ], "evidence_fields": [ "final free", "largest block", "minimum-ever", - "OOM hook", - "PASS" + "free blocks" ], "prerequisites": [ "fragmented checkpoint reached" @@ -3144,9 +3482,10 @@ "PASS" ], "commands": [ - "break task03_debug_checkpoint", + "break heap4_coalesced_checkpoint", "print g_final_stats", - "print g_task03_pass" + "print g_final_free", + "print g_minimum_ever_free" ], "template_id": "run.coalesced" } @@ -3155,43 +3494,51 @@ "id": "oom", "number": 8, "label": "zbyt duże żądanie kończy się NULL", - "mode": "CODE", - "strategy_ref": "code.heap4", + "mode": "RUN", + "event_id": "E08", + "strategy_ref": "run.verified", "svg_label": "08", - "code_ref": "src/tasks/task03_freertos_heap4.c:98", + "code_ref": "src/tasks/task03_freertos_heap4.c:179", + "snapshot_ref": "task01.verified", "description": "Kontrolowany OOM nie narusza listy i wywołuje hook dokładnie raz.", - "evidence": "NULL, hooks=1, asserts=0", + "evidence": "NULL; hooks=1; asserts=0; PASS=1", "strategy": { "id": "task01/a5/replay/oom", - "kind": "code", - "action": "open", + "kind": "run", + "action": "replay", "expected_observations": [ - "heap_4 keeps metadata inside the arena", - "free blocks form one address-ordered intrusive list" + "the oversized request returns NULL", + "the malloc-failed hook runs once without corrupting the recovered arena" ], "assertions": [ - "allocated bit is stored in the size field", - "xStart and pxEnd are sentinels" + "g_oom_is_null equals 1", + "g_malloc_failed_hooks equals 1", + "g_assert_failures equals 0", + "g_task03_pass equals 1" ], "evidence_fields": [ - "symbol", - "list link", - "block size", - "arena address" + "OOM result", + "hook count", + "assert count", + "PASS" ], "prerequisites": [ - "FreeRTOS-Kernel V11.3.0 available" + "coalesced checkpoint reproducible" ], "layout": [ - "ucHeap", - "BlockLink_t", - "xStart", - "pxEnd" + "final stats", + "OOM result", + "hook", + "PASS" ], "commands": [ - "rg -n 'BlockLink_t|prvInsertBlockIntoFreeList|pvPortMalloc|vPortFree' vendor/FreeRTOS-Kernel/portable/MemMang/heap_4.c" + "break task03_debug_checkpoint", + "print g_too_large", + "print g_malloc_failed_hooks", + "print g_assert_failures", + "print g_task03_pass" ], - "template_id": "code.heap4" + "template_id": "run.verified" } } ] @@ -3207,22 +3554,22 @@ "columns": 1, "x": 0.0, "y": 0.0, - "width": 811.0, - "height": 263.0, + "width": 812.0, + "height": 236.0, "full_x": 0.0, "full_y": 0.0, - "full_width": 811.0, - "full_height": 263.0, + "full_width": 812.0, + "full_height": 236.0, "page_width": 940.0, "page_height": 560.0, "overview": true, "step_ids": [ "alloc-a", - "alloc-bc", + "alloc-b", + "alloc-c", "coalesced", "fragmented", - "free-ac", - "free-b", + "free-a", "oom", "reset" ] @@ -3249,7 +3596,8 @@ "title": "A6 — Stan bloku a stan statystyk", "show_heading": false, "toc_entry": true, - "header_html": "
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
TITLEheap_4: From Linear Cursor to Reusable Blocks
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C nad FreeRTOS
SERIESFreeRTOS C
CARD01/15
SHEET5/7
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID87e48095-7793-54e3-9230-4e61d31bd459CARD UUIDaea09ab7-9bfd-5368-8d1b-c8724871c1a7AUTHOR  M. Pabiszczak
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
", + "header_html": "
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
TITLEheap_4: From Linear Cursor to Reusable Blocks
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C nad FreeRTOS
SERIESFreeRTOS C
CARD01/15
SHEET5/7
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID87e48095-7793-54e3-9230-4e61d31bd459CARD UUIDaea09ab7-9bfd-5368-8d1b-c8724871c1a7AUTHOR  Mateusz Pabiszczak
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
", + "footer_html": "", "left_margin_html": "
TECH
-
", "right_margin_html": "
OG
-
", "content_html": "", @@ -3287,86 +3635,104 @@ "id": "free", "number": 1, "label": "wolny blok należy do listy", - "mode": "CODE", - "strategy_ref": "code.heap4", + "mode": "RUN", + "event_id": "E01", + "strategy_ref": "run.timeline", "svg_label": "01", - "code_ref": "src/tasks/task03_freertos_heap4.c:70", + "code_ref": "src/tasks/task03_freertos_heap4.c:127", + "snapshot_ref": "task01.reset", "description": "Stan początkowy zawiera jeden największy wolny blok.", - "evidence": "initial free = largest free", + "evidence": "initial free = largest free = 4080", "strategy": { "id": "task01/a6/state/free", - "kind": "code", - "action": "open", + "kind": "run", + "action": "replay", "expected_observations": [ - "heap_4 keeps metadata inside the arena", - "free blocks form one address-ordered intrusive list" + "every checkpoint is reached from a clean reset with the same ELF", + "free bytes change by the aligned whole-block size, not by payload alone" ], "assertions": [ - "allocated bit is stored in the size field", - "xStart and pxEnd are sentinels" + "A, B and C are aligned", + "the free-byte sequence is strictly decreasing during allocation" ], "evidence_fields": [ - "symbol", - "list link", - "block size", - "arena address" + "payload pointer", + "consumed bytes", + "available bytes", + "free-list statistics" ], "prerequisites": [ - "FreeRTOS-Kernel V11.3.0 available" + "clean Hazard3 RAM", + "task03 image loaded" ], "layout": [ - "ucHeap", - "BlockLink_t", - "xStart", - "pxEnd" + "current checkpoint", + "source call", + "heap statistics", + "ucHeap memory" ], "commands": [ - "rg -n 'BlockLink_t|prvInsertBlockIntoFreeList|pvPortMalloc|vPortFree' vendor/FreeRTOS-Kernel/portable/MemMang/heap_4.c" + "print g_initial_free", + "print g_after_a_free", + "print g_after_b_free", + "print g_after_allocations", + "print g_a_consumed", + "print g_b_consumed", + "print g_c_consumed" ], - "template_id": "code.heap4" + "template_id": "run.timeline" } }, { "id": "allocated", "number": 2, "label": "przydzielony blok znika z listy wolnych", - "mode": "CODE", - "strategy_ref": "code.heap4", + "mode": "RUN", + "event_id": "E04", + "strategy_ref": "run.timeline", "svg_label": "02", - "code_ref": "src/tasks/task03_freertos_heap4.c:78", + "code_ref": "src/tasks/task03_freertos_heap4.c:153", + "snapshot_ref": "task01.alloc-c", "description": "Payload jest wyrównany, a bieżąca wolna pamięć maleje.", - "evidence": "all payload pointers aligned", + "evidence": "all payload pointers aligned; free=3936", "strategy": { "id": "task01/a6/state/allocated", - "kind": "code", - "action": "open", + "kind": "run", + "action": "replay", "expected_observations": [ - "heap_4 keeps metadata inside the arena", - "free blocks form one address-ordered intrusive list" + "every checkpoint is reached from a clean reset with the same ELF", + "free bytes change by the aligned whole-block size, not by payload alone" ], "assertions": [ - "allocated bit is stored in the size field", - "xStart and pxEnd are sentinels" + "A, B and C are aligned", + "the free-byte sequence is strictly decreasing during allocation" ], "evidence_fields": [ - "symbol", - "list link", - "block size", - "arena address" + "payload pointer", + "consumed bytes", + "available bytes", + "free-list statistics" ], "prerequisites": [ - "FreeRTOS-Kernel V11.3.0 available" + "clean Hazard3 RAM", + "task03 image loaded" ], "layout": [ - "ucHeap", - "BlockLink_t", - "xStart", - "pxEnd" + "current checkpoint", + "source call", + "heap statistics", + "ucHeap memory" ], "commands": [ - "rg -n 'BlockLink_t|prvInsertBlockIntoFreeList|pvPortMalloc|vPortFree' vendor/FreeRTOS-Kernel/portable/MemMang/heap_4.c" + "print g_initial_free", + "print g_after_a_free", + "print g_after_b_free", + "print g_after_allocations", + "print g_a_consumed", + "print g_b_consumed", + "print g_c_consumed" ], - "template_id": "code.heap4" + "template_id": "run.timeline" } }, { @@ -3374,10 +3740,10 @@ "number": 3, "label": "dwa wolne bloki nie są jednym dużym blokiem", "mode": "RUN", - "event_id": "E01", + "event_id": "E06", "strategy_ref": "run.fragmented", "svg_label": "03", - "code_ref": "src/tasks/task03_freertos_heap4.c:90", + "code_ref": "src/tasks/task03_freertos_heap4.c:168", "snapshot_ref": "task01.fragmented", "description": "Suma wolnego miejsca nie gwarantuje jednego dużego przydziału.", "evidence": "free blocks = 2", @@ -3412,7 +3778,8 @@ "commands": [ "break heap4_fragmented_checkpoint", "print g_fragmented_stats", - "x/64bx ucHeap" + "print g_fragmented_free", + "x/96bx ucHeap" ], "template_id": "run.fragmented" } @@ -3422,10 +3789,10 @@ "number": 4, "label": "scalenie przywraca jeden największy blok", "mode": "RUN", - "event_id": "E02", + "event_id": "E07", "strategy_ref": "run.coalesced", "svg_label": "04", - "code_ref": "src/tasks/task03_freertos_heap4.c:94", + "code_ref": "src/tasks/task03_freertos_heap4.c:173", "snapshot_ref": "task01.coalesced", "description": "Current free i largest wracają do wartości początkowej.", "evidence": "free blocks = 1", @@ -3439,15 +3806,14 @@ ], "assertions": [ "final free equals initial free", - "minimum-ever does not rise after free", - "oversized allocation returns NULL and calls the hook once" + "one free block is also the largest block", + "minimum-ever does not rise after free" ], "evidence_fields": [ "final free", "largest block", "minimum-ever", - "OOM hook", - "PASS" + "free blocks" ], "prerequisites": [ "fragmented checkpoint reached" @@ -3459,9 +3825,10 @@ "PASS" ], "commands": [ - "break task03_debug_checkpoint", + "break heap4_coalesced_checkpoint", "print g_final_stats", - "print g_task03_pass" + "print g_final_free", + "print g_minimum_ever_free" ], "template_id": "run.coalesced" } @@ -3470,43 +3837,51 @@ "id": "minimum-ever", "number": 5, "label": "minimum-ever zachowuje najniższy poziom", - "mode": "CODE", - "strategy_ref": "code.heap4", + "mode": "RUN", + "event_id": "E08", + "strategy_ref": "run.verified", "svg_label": "05", - "code_ref": "src/tasks/task03_freertos_heap4.c:95", + "code_ref": "src/tasks/task03_freertos_heap4.c:179", + "snapshot_ref": "task01.verified", "description": "Historyczne minimum nie zwiększa się po odzyskaniu pamięci.", "evidence": "minimum-ever <= after allocations", "strategy": { "id": "task01/a6/state/minimum-ever", - "kind": "code", - "action": "open", + "kind": "run", + "action": "replay", "expected_observations": [ - "heap_4 keeps metadata inside the arena", - "free blocks form one address-ordered intrusive list" + "the oversized request returns NULL", + "the malloc-failed hook runs once without corrupting the recovered arena" ], "assertions": [ - "allocated bit is stored in the size field", - "xStart and pxEnd are sentinels" + "g_oom_is_null equals 1", + "g_malloc_failed_hooks equals 1", + "g_assert_failures equals 0", + "g_task03_pass equals 1" ], "evidence_fields": [ - "symbol", - "list link", - "block size", - "arena address" + "OOM result", + "hook count", + "assert count", + "PASS" ], "prerequisites": [ - "FreeRTOS-Kernel V11.3.0 available" + "coalesced checkpoint reproducible" ], "layout": [ - "ucHeap", - "BlockLink_t", - "xStart", - "pxEnd" + "final stats", + "OOM result", + "hook", + "PASS" ], "commands": [ - "rg -n 'BlockLink_t|prvInsertBlockIntoFreeList|pvPortMalloc|vPortFree' vendor/FreeRTOS-Kernel/portable/MemMang/heap_4.c" + "break task03_debug_checkpoint", + "print g_too_large", + "print g_malloc_failed_hooks", + "print g_assert_failures", + "print g_task03_pass" ], - "template_id": "code.heap4" + "template_id": "run.verified" } } ] @@ -3522,11 +3897,11 @@ "columns": 1, "x": 0.0, "y": 0.0, - "width": 346.0, + "width": 321.0, "height": 600.0, "full_x": 0.0, "full_y": 0.0, - "full_width": 346.0, + "full_width": 321.0, "full_height": 600.0, "page_width": 660.0, "page_height": 760.0, @@ -3561,7 +3936,8 @@ "title": "A7 — Dowód w Hazard3 i ELF", "show_heading": false, "toc_entry": true, - "header_html": "
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
TITLEheap_4: From Linear Cursor to Reusable Blocks
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C nad FreeRTOS
SERIESFreeRTOS C
CARD01/15
SHEET6/7
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID87e48095-7793-54e3-9230-4e61d31bd459CARD UUIDaea09ab7-9bfd-5368-8d1b-c8724871c1a7AUTHOR  M. Pabiszczak
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
", + "header_html": "
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
TITLEheap_4: From Linear Cursor to Reusable Blocks
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C nad FreeRTOS
SERIESFreeRTOS C
CARD01/15
SHEET6/7
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID87e48095-7793-54e3-9230-4e61d31bd459CARD UUIDaea09ab7-9bfd-5368-8d1b-c8724871c1a7AUTHOR  Mateusz Pabiszczak
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
", + "footer_html": "", "left_margin_html": "
TECH
-
", "right_margin_html": "
OG
-
", "content_html": "", @@ -3588,7 +3964,7 @@ "block": { "id": "a7", "label": "A7 RUNTIME", - "description": "Ten sam artefakt łączy źródło, symbole ELF, dwa checkpointy, pamięć ucHeap i końcowe asercje." + "description": "Ten sam artefakt łączy źródło, symbole ELF, osiem checkpointów, pamięć ucHeap i końcowe asercje." }, "phases": [ { @@ -3602,7 +3978,7 @@ "mode": "CODE", "strategy_ref": "code.identity", "svg_label": "01", - "code_ref": "src/tasks/task03_freertos_heap4.c:62", + "code_ref": "src/tasks/task03_freertos_heap4.c:127", "description": "Blob źródła jest częścią tożsamości karty.", "evidence": "source git blob", "strategy": { @@ -3615,7 +3991,8 @@ ], "assertions": [ "pvPortMalloc and vPortFree are present", - "prvInsertBlockIntoFreeList is present" + "prvInsertBlockIntoFreeList is present", + "all eight replay checkpoint symbols are present" ], "evidence_fields": [ "source blob", @@ -3657,7 +4034,8 @@ ], "assertions": [ "pvPortMalloc and vPortFree are present", - "prvInsertBlockIntoFreeList is present" + "prvInsertBlockIntoFreeList is present", + "all eight replay checkpoint symbols are present" ], "evidence_fields": [ "source blob", @@ -3684,13 +4062,13 @@ "number": 3, "label": "checkpoint pokazuje dwa wolne bloki", "mode": "RUN", - "event_id": "E01", + "event_id": "E06", "strategy_ref": "run.fragmented", "svg_label": "03", - "code_ref": "src/tasks/task03_freertos_heap4.c:91", + "code_ref": "src/tasks/task03_freertos_heap4.c:168", "snapshot_ref": "task01.fragmented", "description": "Neovim, GDB i pamięć zatrzymują się na tym samym stanie.", - "evidence": "blocks=2 and aligned=1", + "evidence": "blocks=2 and free>largest", "strategy": { "id": "task01/a7/evidence/fragmented-runtime", "kind": "run", @@ -3722,7 +4100,8 @@ "commands": [ "break heap4_fragmented_checkpoint", "print g_fragmented_stats", - "x/64bx ucHeap" + "print g_fragmented_free", + "x/96bx ucHeap" ], "template_id": "run.fragmented" } @@ -3731,43 +4110,49 @@ "id": "memory", "number": 4, "label": "ucHeap ujawnia nagłówki i payload", - "mode": "CODE", - "strategy_ref": "code.heap4", + "mode": "RUN", + "event_id": "E06", + "strategy_ref": "run.fragmented", "svg_label": "04", "code_ref": "src/tasks/task03_freertos_heap4.c:11", + "snapshot_ref": "task01.fragmented", "description": "Widok bajtów łączy diagram z realnym układem areny.", "evidence": "aligned arena and in-band metadata", "strategy": { "id": "task01/a7/evidence/memory", - "kind": "code", - "action": "open", + "kind": "run", + "action": "replay", "expected_observations": [ - "heap_4 keeps metadata inside the arena", - "free blocks form one address-ordered intrusive list" + "A and C are free while B remains allocated", + "the free list contains two blocks" ], "assertions": [ - "allocated bit is stored in the size field", - "xStart and pxEnd are sentinels" + "xNumberOfFreeBlocks equals 2", + "current free bytes exceed the largest free block" ], "evidence_fields": [ - "symbol", - "list link", - "block size", - "arena address" + "free blocks", + "largest block", + "free bytes", + "heap bytes" ], "prerequisites": [ - "FreeRTOS-Kernel V11.3.0 available" + "clean Hazard3 RAM", + "task03 image loaded" ], "layout": [ - "ucHeap", - "BlockLink_t", - "xStart", - "pxEnd" + "source", + "free-list stats", + "ucHeap memory", + "registers" ], "commands": [ - "rg -n 'BlockLink_t|prvInsertBlockIntoFreeList|pvPortMalloc|vPortFree' vendor/FreeRTOS-Kernel/portable/MemMang/heap_4.c" + "break heap4_fragmented_checkpoint", + "print g_fragmented_stats", + "print g_fragmented_free", + "x/96bx ucHeap" ], - "template_id": "code.heap4" + "template_id": "run.fragmented" } }, { @@ -3775,11 +4160,11 @@ "number": 5, "label": "checkpoint końcowy dowodzi odzyskania", "mode": "RUN", - "event_id": "E02", - "strategy_ref": "run.coalesced", + "event_id": "E08", + "strategy_ref": "run.verified", "svg_label": "05", - "code_ref": "src/tasks/task03_freertos_heap4.c:111", - "snapshot_ref": "task01.coalesced", + "code_ref": "src/tasks/task03_freertos_heap4.c:179", + "snapshot_ref": "task01.verified", "description": "Jedna ramka łączy stats, OOM, hook i PASS.", "evidence": "final=initial, blocks=1, pass=1", "strategy": { @@ -3787,36 +4172,38 @@ "kind": "run", "action": "replay", "expected_observations": [ - "freeing B joins both neighbours", - "the arena returns to one reusable block" + "the oversized request returns NULL", + "the malloc-failed hook runs once without corrupting the recovered arena" ], "assertions": [ - "final free equals initial free", - "minimum-ever does not rise after free", - "oversized allocation returns NULL and calls the hook once" + "g_oom_is_null equals 1", + "g_malloc_failed_hooks equals 1", + "g_assert_failures equals 0", + "g_task03_pass equals 1" ], "evidence_fields": [ - "final free", - "largest block", - "minimum-ever", - "OOM hook", + "OOM result", + "hook count", + "assert count", "PASS" ], "prerequisites": [ - "fragmented checkpoint reached" + "coalesced checkpoint reproducible" ], "layout": [ "final stats", - "minimum-ever", - "OOM hook", + "OOM result", + "hook", "PASS" ], "commands": [ "break task03_debug_checkpoint", - "print g_final_stats", + "print g_too_large", + "print g_malloc_failed_hooks", + "print g_assert_failures", "print g_task03_pass" ], - "template_id": "run.coalesced" + "template_id": "run.verified" } } ] @@ -3851,7 +4238,7 @@ }, "diagram_title": "A7 · dowód runtime heap_4", "diagram_block_label": "A7 RUNTIME", - "diagram_description": "Ten sam artefakt łączy źródło, symbole ELF, dwa checkpointy, pamięć ucHeap i końcowe asercje.", + "diagram_description": "Ten sam artefakt łączy źródło, symbole ELF, osiem checkpointów, pamięć ucHeap i końcowe asercje.", "diagram_phase_labels": [ "ARTIFACT / CHECKPOINT / MEMORY / ASSERTION" ] @@ -3871,7 +4258,8 @@ "title": "Task01 — mechanika heap_4", "show_heading": true, "toc_entry": true, - "header_html": "
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
TITLEheap_4: From Linear Cursor to Reusable Blocks
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C nad FreeRTOS
SERIESFreeRTOS C
CARD01/15
SHEET7/7
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID87e48095-7793-54e3-9230-4e61d31bd459CARD UUIDaea09ab7-9bfd-5368-8d1b-c8724871c1a7AUTHOR  M. Pabiszczak
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
", + "header_html": "
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
TITLEheap_4: From Linear Cursor to Reusable Blocks
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C nad FreeRTOS
SERIESFreeRTOS C
CARD01/15
SHEET7/7
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID87e48095-7793-54e3-9230-4e61d31bd459CARD UUIDaea09ab7-9bfd-5368-8d1b-c8724871c1a7AUTHOR  Mateusz Pabiszczak
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
", + "footer_html": "", "left_margin_html": "
TECH
-
", "right_margin_html": "
OG
-
", "content_html": "", @@ -3880,9 +4268,9 @@ "ref": "task01", "title": "Predict and prove reusable heap_4 blocks", "uuid": "aea09ab7-9bfd-5368-8d1b-c8724871c1a7", - "criterion": "Model 13 -> 32 bajty; poprawna predykcja dwóch wolnych bloków po free(A,C) i jednego po free(B); final free = initial free; minimum-ever nie rośnie; OOM zwraca NULL; PASS=1.", + "criterion": "Na RV32 BlockLink_t ma 8 bajtów, lecz 16-bajtowe wyrównanie portu daje xHeapStructSize=16; A/B/C zużywają 48/64/32 bajty; po free(A,C) są dwa wolne bloki, po free(B) jeden; final free = initial free; minimum-ever nie rośnie; OOM zwraca NULL; PASS=1.", "conclusion_html": "

heap_4 odzyskuje pamięć dzięki metadanym w arenie, adresowo uporządkowanej liście i scalaniu sąsiadów. Suma wolnych bajtów nie zastępuje informacji o największym bloku, a minimum-ever jest historią, nie bieżącym stanem.

", - "prompt_html": "

Przewidź układ bloków po alloc A/B/C, następnie po free(A,C) i free(B). Odtwórz oba checkpointy i udowodnij, że arena została scalona bez utraty minimum-ever.

", + "prompt_html": "

Przewidź układ bloków po alloc A/B/C, następnie po free(A), free(C) i free(B). Odtwórz checkpointy E01-E08 i udowodnij, że arena została scalona bez utraty minimum-ever.

", "flow": [ { "id": "predict", @@ -3892,8 +4280,8 @@ "steps": [ { "id": "size", - "title": "Policz rozmiar bloku.", - "content_html": "

Dodaj nagłówek do 13 bajtów i wyrównaj wynik do ośmiu.

" + "title": "Policz rozmiary całych bloków.", + "content_html": "

Rozróżnij surowy BlockLink_t (8 bajtów) od xHeapStructSize (16 bajtów), dodaj nagłówek do żądań 24, 40 i 16 bajtów, a następnie wyrównaj wynik do 16.

" }, { "id": "list", @@ -3906,17 +4294,22 @@ "id": "replay", "kind": "block", "title": "B — replay Hazard3", - "content_html": "

Powiąż diagram z dwoma deterministycznymi checkpointami.

", + "content_html": "

Powiąż każdy stan diagramu z deterministycznym checkpointem E01-E08.

", "steps": [ { - "id": "fragmented", - "title": "Sprawdź E01.", - "content_html": "

Porównaj liczbę wolnych bloków, największy blok i bieżące wolne bajty.

" + "id": "allocate", + "title": "Sprawdź E01--E04.", + "content_html": "

Potwierdź wartości 4080, 4032, 3968 i 3936 oraz zużycie 48/64/32 bajtów.

" }, { - "id": "coalesced", - "title": "Sprawdź E02.", - "content_html": "

Udowodnij pełne scalenie, zachowanie minimum-ever i kontrolowany OOM.

" + "id": "release", + "title": "Sprawdź E05--E07.", + "content_html": "

Porównaj liczbę wolnych bloków i udowodnij scalenie poprzedniego, a potem następnego sąsiada.

" + }, + { + "id": "verify", + "title": "Sprawdź E08.", + "content_html": "

Udowodnij zachowanie minimum-ever, kontrolowany OOM, brak asercji i PASS=1.

" } ] }, @@ -3952,7 +4345,7 @@ { "id": "A2", "label": "STRUCTURE", - "subtitle": "headers and address order", + "subtitle": "RV32 header, split and address order", "status": "enabled", "target_label": "fig:a2-structure", "target_id": "fig-a2-structure" @@ -3970,7 +4363,7 @@ "label": "APPLICATION", "subtitle": "experiment is already explicit", "status": "unavailable", - "reason": "The concrete A/B/C allocation experiment is completely represented by A5 and its two runtime checkpoints.", + "reason": "The concrete A/B/C allocation experiment is completely represented by the eight-state replay in A5.", "target_id": "" }, { diff --git a/web/figures/a2-structure.puml b/web/figures/a2-structure.puml index 262ad72..b8bcce8 100644 --- a/web/figures/a2-structure.puml +++ b/web/figures/a2-structure.puml @@ -8,41 +8,46 @@ skinparam defaultFontSize 10 skinparam classBorderColor #2c7794 skinparam classBackgroundColor #edf6fa skinparam ArrowColor #8095a1 -title A2 STRUCTURE — in-band metadata and address order +title A2 STRUCTURE — RV32 header, split and two-sided coalescing class "01 Block header" as HEADER { next : BlockLink_t* size : size_t + raw sizeof = 8 bytes on RV32 + aligned xHeapStructSize = 16 } class "Allocated block" as ALLOC { - 02 header + 13 byte request - aligned total = 32 bytes + 02 A: header + 24 byte request + aligned total = 48 bytes payload begins after header } class "03 Free remainder" as REM { own header - size = 224 bytes + free = 4032 bytes after A } HEADER *-- ALLOC : precedes payload -ALLOC -down-> REM : split preserves 256 +ALLOC -down-> REM : first-fit + split class "04 Address-ordered free list" as LIST { previous < inserted < current + A < B < C+tail } -class "05 Right neighbour" as RIGHT { - block + block.size == current +class "05 Previous / left neighbour" as LEFT { + previous + previous.size == inserted + merge previous first } -class "06 Left neighbour" as LEFT { - previous + previous.size == block +class "06 Next / right neighbour" as RIGHT { + merged + merged.size == current + merge next second } REM -down-> LIST : insert by address -LIST -down-> RIGHT : join first -RIGHT -down-> LEFT : then join left +LIST -down-> LEFT : heap_4 tests first +LEFT -down-> RIGHT : then tests next note right of LIST -Ordering makes both physical -neighbours locally visible. +Address order exposes both physical +neighbours without scanning the arena. end note @enduml diff --git a/web/figures/a2-structure.svg b/web/figures/a2-structure.svg index cc49cc7..bd54938 100644 --- a/web/figures/a2-structure.svg +++ b/web/figures/a2-structure.svg @@ -1,63 +1,68 @@ -A2 STRUCTURE — in-band metadata and address order01 Block headernext : BlockLink_t*size : size_tAllocated block02 header + 13 byte requestaligned total = 32 bytespayload begins after header03 Free remainderown headersize = 224 bytes04 Address-ordered free listprevious < inserted < current05 Right neighbourblock + block.size == current06 Left neighbourprevious + previous.size == blockOrdering makes both physicalneighbours locally visible.precedes payloadsplit preserves 256insert by addressjoin firstthen join left01 Block headernext : BlockLink_t*size : size_traw sizeof = 8 bytes on RV32aligned xHeapStructSize = 16Allocated block02 A: header + 24 byte requestaligned total = 48 bytespayload begins after header03 Free remainderown headerfree = 4032 bytes after A04 Address-ordered free listprevious < inserted < currentA < B < C+tail05 Previous / left neighbourprevious + previous.size == insertedmerge previous first06 Next / right neighbourmerged + merged.size == currentmerge next secondAddress order exposes both physicalneighbours without scanning the arena.precedes payloadfirst-fit + splitinsert by addressheap_4 tests firstthen tests next01 RESETinitial free = 408002 ALLOC A24 byte payloadfirst-fit + split03 ALLOC B / C40 + 16 byte payloadafter = 395204 FREE A / CB remains allocated05 E01 FRAGMENTED2 free blockscurrent > largest06 FREE Binsert by addressjoin right + left07 E02 COALESCED1 free blockfinal = initial08 OOM CHECKNULL · hook=1asserts=0 · PASS=1pvPortMallocsplit remaindervPortFreeheap statscontinuecoalesceoversized request01 E01 RESET1 block · free=4080raw header=8 · aligned=1602 E02 ALLOC A(24)consumed=48free=403203 E03 ALLOC B(40)consumed=64free=396804 E04 ALLOC C(16)consumed=32free=393605 E05 FREE A2 free blocksfree=398406 E06 FREE C2 blocks · fragmentedfree=401607 E07 FREE Bmerge left + right1 block · free=408008 E08 OOM / VERIFYNULL · hook=1asserts=0 · PASS=1pvPortMallocsplit remaindersplit remaindervPortFree(A)vPortFree(C)vPortFree(B)oversized request Free : 01 one list node -Free --> Allocated : 02 first-fit + split\ncurrent free decreases -Allocated --> Fragmented : free A and C -Fragmented : 03 two free blocks +[*] --> Free : 01 E01 one list node +Free --> Allocated : 02 E04 A+B+C allocated\ncurrent free = 3936 +Allocated --> Fragmented : E05 free A\nE06 free C +Fragmented : 03 E06 two free blocks Fragmented : sum free > largest block -Fragmented --> Coalesced : free B\naddress-order joins neighbours -Coalesced : 04 one free block -Coalesced : current free = initial free -Coalesced --> OOMChecked : request > arena -OOMChecked : NULL + hook once +Fragmented --> Coalesced : 04 E07 free B\nmerge previous, then next +Coalesced : one free block +Coalesced : current = largest = initial +Coalesced --> OOMChecked : 05 E08 request > arena +OOMChecked : NULL · hook=1 · PASS=1 OOMChecked --> [*] -state "05 minimum-ever" as MIN +state "minimum-ever" as MIN Allocated -right-> MIN : records low watermark Fragmented -right-> MIN : does not rise Coalesced -right-> MIN : history remains diff --git a/web/figures/a6-state.svg b/web/figures/a6-state.svg index 12a9095..8c07583 100644 --- a/web/figures/a6-state.svg +++ b/web/figures/a6-state.svg @@ -1,42 +1,42 @@ -A6 STATE — block state and heap statisticsFreeAllocatedFragmented03 two free blockssum free > largest blockCoalesced04 one free blockcurrent free = initial freeOOMCheckedNULL + hook once05 minimum-ever01 one list node02 first-fit + splitcurrent free decreasesfree A and Cfree Baddress-order joins neighboursrequest > arenarecords low watermarkdoes not risehistory remains01 E01 one list node02 E04 A+B+C allocatedcurrent free = 3936E05 free AE06 free C04 E07 free Bmerge previous, then next05 E08 request > arenarecords low watermarkdoes not risehistory remains ELF : compile + link ELF --> E1 : reset / load / replay diff --git a/web/figures/a7-runtime.svg b/web/figures/a7-runtime.svg index 62a80d5..0d55821 100644 --- a/web/figures/a7-runtime.svg +++ b/web/figures/a7-runtime.svg @@ -1,36 +1,36 @@ -A7 RUNTIME — one artifact, two checkpoints, one proof«source»01 task03 CA/B/C experiment«artifact»02 ELF + imageheap_4 symbols«checkpoint E01»03 fragmentedblocks=2 · aligned=1«memory»04 ucHeap[4096]headers + payload«checkpoint E02»05 coalescedfinal=initial · blocks=1OOM=1 · PASS=1compile + linkreset / load / replayinspect bytescontinue«source»01 task03 CA/B/C experiment«artifact»02 ELF + imageheap_4 symbols«checkpoint E06»03 fragmentedblocks=2 · free>largest«memory»04 ucHeap[4096]headers + payload«checkpoint E08»05 verifiedfinal=initial · blocks=1OOM=1 · PASS=1compile + linkreset / load / replayinspect bytescontinue