commit d522c15f7545bd901cb4cbd443f198861b9014af Author: user Date: Tue Jul 21 19:14:20 2026 +0200 feat: add lab-rv32i-c-smalloc-sbrk-libc card diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fb50895 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +/build/ +/host-build/ +__pycache__/ +*.pyc +/doc/generated/*.aux +/doc/generated/*.fdb_latexmk +/doc/generated/*.fls +/doc/generated/*.log +/doc/generated/*.out +/doc/generated/*.upa diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..468ec37 --- /dev/null +++ b/Makefile @@ -0,0 +1,161 @@ +RISCV_PREFIX ?= riscv64-unknown-elf- + +CC := $(RISCV_PREFIX)gcc +OBJCOPY := $(RISCV_PREFIX)objcopy +OBJDUMP := $(RISCV_PREFIX)objdump +READELF := $(RISCV_PREFIX)readelf +NM := $(RISCV_PREFIX)nm +SIZE := $(RISCV_PREFIX)size +HOST_CC ?= cc + +LOCAL_RV_ENV := $(abspath ../../../../../edu/rv32i-hazard3-student-env) +ifneq ($(wildcard /opt/rv-env/vendor/Hazard3/test/sim/common/init.S),) + RV_ENV_ROOT ?= /opt/rv-env +else + RV_ENV_ROOT ?= $(LOCAL_RV_ENV) +endif +H3_ROOT ?= $(RV_ENV_ROOT)/vendor/Hazard3 +H3_COMMON ?= $(H3_ROOT)/test/sim/common +H3_INIT ?= $(H3_COMMON)/init.S +LOCAL_H3_TB := $(H3_ROOT)/test/sim/tb_verilator/tb +PREBUILT_H3_TB := $(abspath ../../freertos/lab-rv32i-freertos-c-scheduler/vendor/Hazard3/test/sim/tb_verilator/tb) +H3_TB ?= $(if $(wildcard $(LOCAL_H3_TB)),$(LOCAL_H3_TB),$(if $(wildcard $(PREBUILT_H3_TB)),$(PREBUILT_H3_TB),$(LOCAL_H3_TB))) +H3_TB_DIR ?= $(dir $(H3_TB)) + +PROFILE ?= observe +ifeq ($(PROFILE),observe) + OPTFLAGS := -O0 -fno-omit-frame-pointer -fno-inline -fno-optimize-sibling-calls + DBGFLAGS := -g3 -ggdb +else ifeq ($(PROFILE),debug) + OPTFLAGS := -Og -fno-omit-frame-pointer -fno-optimize-sibling-calls + DBGFLAGS := -g3 -ggdb +else ifeq ($(PROFILE),release) + OPTFLAGS := -Os + DBGFLAGS := +else + $(error PROFILE must be observe, debug or release) +endif + +ARCH ?= rv32i_zicsr_zifencei +ABI ?= ilp32 +BUILD_ROOT ?= build +HOST_BUILD_ROOT ?= host-build +LINKER_SCRIPT := link/hazard3_c09.ld + +TASK01 := task01_libc_without_heap +TASK02 := task02_malloc_requires_sbrk +TASK03 := task03_bounded_sbrk +TASK04 := task04_smalloc +TASK05 := task05_picolibc_malloc +SUCCESS_TASKS := $(TASK01) $(TASK03) $(TASK04) $(TASK05) + +RV_CFLAGS := -std=c11 -march=$(ARCH) -mabi=$(ABI) -nostdlib -nostartfiles \ + -ffreestanding -fno-builtin -fno-stack-protector \ + -ffunction-sections -fdata-sections $(OPTFLAGS) $(DBGFLAGS) \ + -Wall -Wextra -Wpedantic -Werror -Isrc/runtime +RV_LDFLAGS := -Wl,--no-relax -Wl,--gc-sections -T$(LINKER_SCRIPT) +RV_LIBS := -Wl,--start-group -lc -lgcc -Wl,--end-group +HOST_CFLAGS := -std=c11 -DC09_HOST=1 -DHOST_PRINTF=1 -fno-builtin \ + $(OPTFLAGS) $(DBGFLAGS) -Wall -Wextra -Wpedantic -Werror -Isrc/runtime + +.PHONY: all tasks host check full-check clean check-support \ + task1 task2 task3 task4 task5 t1 t2 t3 t4 t5 \ + host-test expected-fail archive-map check-elf testbench hazard3-test card card-check + +all: tasks +tasks: $(SUCCESS_TASKS) +host: $(addprefix $(HOST_BUILD_ROOT)/,$(addsuffix /prog,$(SUCCESS_TASKS))) + +task1 t1: $(TASK01) +task2 t2: expected-fail +task3 t3: $(TASK03) +task4 t4: $(TASK04) +task5 t5: $(TASK05) + +check-support: + @test -f "$(H3_INIT)" || { echo "Missing Hazard3 init.S: $(H3_INIT)" >&2; exit 1; } + @test -f "$(LINKER_SCRIPT)" || { echo "Missing $(LINKER_SCRIPT)" >&2; exit 1; } + +define rv_task_rules +$(1): $(BUILD_ROOT)/$(1)/prog.bin $(BUILD_ROOT)/$(1)/prog.lst + +$(BUILD_ROOT)/$(1)/prog.elf: crt0.S $(H3_INIT) $(LINKER_SCRIPT) $(2) | check-support + mkdir -p $$(@D) + $(CC) $(RV_CFLAGS) $(RV_LDFLAGS) -Wl,-Map,$(BUILD_ROOT)/$(1)/prog.map \ + -o $$@ $(H3_INIT) crt0.S $(2) $(RV_LIBS) + $(SIZE) -A -x $$@ + +$(BUILD_ROOT)/$(1)/prog.bin: $(BUILD_ROOT)/$(1)/prog.elf + $(OBJCOPY) -O binary $$< $$@ + +$(BUILD_ROOT)/$(1)/prog.lst: $(BUILD_ROOT)/$(1)/prog.elf + $(OBJDUMP) -d -S -M no-aliases,numeric $$< > $$@ + +$(HOST_BUILD_ROOT)/$(1)/prog: $(2) + mkdir -p $$(@D) + $(HOST_CC) $(HOST_CFLAGS) -o $$@ $(2) +endef + +$(eval $(call rv_task_rules,$(TASK01),src/tasks/$(TASK01).c)) +$(eval $(call rv_task_rules,$(TASK03),src/tasks/$(TASK03).c src/runtime/c09_bounded_sbrk.c)) +$(eval $(call rv_task_rules,$(TASK04),src/tasks/$(TASK04).c src/runtime/c09_bounded_sbrk.c src/runtime/c09_smalloc.c)) +$(eval $(call rv_task_rules,$(TASK05),src/tasks/$(TASK05).c)) + +$(BUILD_ROOT)/$(TASK02)/task.o: src/tasks/$(TASK02).c + mkdir -p $(@D) + $(CC) $(RV_CFLAGS) -c -o $@ $< + +expected-fail: $(BUILD_ROOT)/$(TASK02)/task.o | check-support + @set -eu; \ + log="$(BUILD_ROOT)/$(TASK02)/expected-link-failure.log"; \ + elf="$(BUILD_ROOT)/$(TASK02)/must-not-exist.elf"; \ + rm -f "$$elf" "$$log"; \ + set +e; \ + $(CC) $(RV_CFLAGS) $(RV_LDFLAGS) -Wl,--wrap=sbrk \ + -Wl,-Map,$(BUILD_ROOT)/$(TASK02)/expected-link-failure.map \ + -o "$$elf" $(H3_INIT) crt0.S $(BUILD_ROOT)/$(TASK02)/task.o \ + $(RV_LIBS) >"$$log" 2>&1; \ + status=$$?; \ + set -e; \ + if [ "$$status" -eq 0 ]; then \ + echo "FAIL: Task02 unexpectedly linked" >&2; rm -f "$$elf"; exit 1; \ + fi; \ + test ! -e "$$elf"; \ + grep -q "undefined reference to.*__wrap_sbrk" "$$log"; \ + grep -q "libc_stdlib_malloc.c.o" "$$log"; \ + echo "PASS Task02: controlled link failure (__wrap_sbrk missing)" + +host-test: host + ./tests/test_host.sh --already-built + +archive-map: $(BUILD_ROOT)/$(TASK01)/prog.elf $(BUILD_ROOT)/$(TASK05)/prog.elf + ./tests/check_archive_maps.sh + +check-elf: tasks + ./tests/check_elf.sh + +testbench: + @if [ ! -x "$(H3_TB)" ]; then $(MAKE) -C "$(H3_TB_DIR)"; fi + @test -x "$(H3_TB)" + +hazard3-test: tasks testbench + @set -eu; \ + for task in $(SUCCESS_TASKS); do \ + echo "RUN Hazard3 $$task"; \ + "$(H3_TB)" --bin "$(abspath $(BUILD_ROOT))/$$task/prog.bin" \ + --cycles 1000000 --cpuret; \ + done + +card: + ./scripts/build_new_card.sh + GITEA_SHA=$${GITEA_SHA:-0000000000000000000000000000000000000000} \ + ./scripts/render_new_pdf.sh + +card-check: card + ./tests/check_card.sh + +check: host-test expected-fail archive-map check-elf +full-check: check hazard3-test card-check + +clean: + rm -rf $(BUILD_ROOT) $(HOST_BUILD_ROOT) diff --git a/README.md b/README.md new file mode 100644 index 0000000..f24138b --- /dev/null +++ b/README.md @@ -0,0 +1,59 @@ +# C09 — `smalloc`, `sbrk` i minimalne libc + +Pięć krótkich eksperymentów rozdziela trzy warstwy, które łatwo pomylić: +funkcję biblioteczną niewymagającą sterty, kontrakt `malloc` → `sbrk` oraz +politykę prostego alokatora przyrostowego. Karta używa rzeczywistego toolchaina +GCC 15.2 z picolibc dla RV32I/Hazard3. + +## Przykłady + +| Task | Pytanie rozstrzygane przez program | Wynik | +|---|---|---| +| 01 | Czy każda funkcja libc wymaga sterty? | `strlen.c.o` trafia do mapy, człony `malloc`/`sbrk` nie. | +| 02 | Co się stanie bez dostawcy `sbrk`? | Kontrolowany błąd linkera: brak `__wrap_sbrk`. | +| 03 | Jaki jest minimalny bezpieczny kontrakt przesuwania break? | `heap_start <= brk <= heap_end`; błąd nie przesuwa break. | +| 04 | Co naprawdę gwarantuje `smalloc`? | Nagłówek przed payloadem, 16 B alignment, append-only, tylko reset całej areny. | +| 05 | Jak zachowuje się prawdziwe `malloc/free` picolibc? | Dwa rozłączne bloki, zapis/odczyt, `free`; implementacja pozostaje czarną skrzynką. | + +Każdy przykład na karcie ma dokładnie widoki A1–A8. A3 jest oznaczony +`N/D`, bo w żadnym przykładzie nie ma callbacku, ISR ani dynamicznego wyboru +wykonawcy. Task02 nie ma A6 runtime, ponieważ zgodnie z celem nie powstaje ELF. + +## Ważne nazwy symboli + +`vendor/Hazard3/test/sim/common/init.S` definiuje `_sbrk` z podkreśleniem. +Picolibc w tym toolchainie definiuje i wywołuje `sbrk` bez podkreślenia. +Są to różne symbole; Task05 celowo zachowuje oba w jednym ELF-ie. Task03 i +Task04 używają nazwy `c09_sbrk`, aby nie podszywać się pod libc. + +Własny skrypt `link/hazard3_c09.ld` udostępnia picolibc symbole +`__heap_start` i `__heap_end`, rezerwuje 64 KiB na stos przy końcu 16 MiB RAM +i zatrzymuje linkowanie przez `ASSERT`, jeżeli sterta nachodzi na stos. + +## Budowanie i dowody + +```bash +make host-test +make expected-fail +make tasks archive-map check-elf +make hazard3-test +make card-check +``` + +`make task2` ma zakończyć się sukcesem jako test, ale zapisany w logu link +programu ma zakończyć się porażką. Nie jest to zepsuty build: flaga +`--wrap=sbrk` przekierowuje odwołanie picolibc na celowo niezdefiniowany +`__wrap_sbrk`, dzięki czemu zależność jest dowodzona deterministycznie. + +Udane obrazy RV32I znajdują się w `build//` jako ELF, BIN, listing i +mapa linkera. Task02 ma tylko obiekt, mapę częściowego linku i +`expected-link-failure.log`; plik `must-not-exist.elf` jest zabroniony przez +test. + +## Zakres modelu `smalloc` + +`c09_smalloc` jest celowo mały: wyrównuje całkowity blok do 16 B, zapisuje +16-bajtowy nagłówek bezpośrednio przed payloadem i dopisuje kolejny blok na +końcu. Nie ma `c09_sfree`, listy wolnych bloków, split ani coalescing. +`c09_smalloc_reset` unieważnia całą arenę naraz i służy tylko do kontrolowanego +ćwiczenia. Task05 nie wyciąga z tego modelu wniosków o wnętrzu picolibc. diff --git a/crt0.S b/crt0.S new file mode 100644 index 0000000..b6e3fb2 --- /dev/null +++ b/crt0.S @@ -0,0 +1,36 @@ + .section .text.startup,"ax",@progbits + .global _start + .type _start, @function + +_start: +.option push +.option norelax + la gp, __global_pointer$ +.option pop + + /* One static TLS block is enough for this single-hart lab. */ + la tp, __tls_start + + la a0, __tbss_start + la a1, __tbss_end +clear_tbss: + bgeu a0, a1, finish_tbss + sb zero, 0(a0) + addi a0, a0, 1 + j clear_tbss +finish_tbss: + + la a0, __bss_start + la a1, __bss_end +clear_bss: + bgeu a0, a1, finish_bss + sb zero, 0(a0) + addi a0, a0, 1 + j clear_bss +finish_bss: + + call main + tail _exit + + .size _start, .-_start + diff --git a/doc/generated/main.pdf b/doc/generated/main.pdf new file mode 100644 index 0000000..e5fa580 Binary files /dev/null and b/doc/generated/main.pdf differ diff --git a/doc/generated/main.tex b/doc/generated/main.tex new file mode 100644 index 0000000..f8f54d2 --- /dev/null +++ b/doc/generated/main.tex @@ -0,0 +1,593 @@ +% Generated from json/card_source.json by tools/render_card.py. +% Do not edit manually; update the JSON and regenerate. + +\documentclass[12pt,a4paper]{article} + +\usepackage[T1]{fontenc} +\usepackage{lmodern} +\usepackage[utf8]{inputenc} +\usepackage[polish]{babel} +\usepackage{csquotes} +\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{eso-pic} +\usepackage{marginnote} +\usepackage{array} +\usepackage{tabularx} +\usepackage{graphicx} +\usepackage{pdflscape} +\usepackage{float} +\usepackage{silence} +\WarningFilter{soulutf8}{This package is obsolete} +\usepackage{pdfcomment} +\usepackage{enumitem} +\usepackage{needspace} +\usepackage{fancyhdr} +\usepackage{lastpage} +\usepackage{microtype} +\usepackage[most]{tcolorbox} +\usepackage{qrcode} +\IfFileExists{references.bib}{% + \usepackage[backend=biber,style=numeric,sorting=none]{biblatex}% + \addbibresource{references.bib}% +}{} + +\hypersetup{hidelinks} + +\IfFileExists{build-meta.tex}{% + \input{build-meta.tex}% +}{% + \newcommand{\BuildCommit}{lokalna}% +} + +\newcommand{\DocumentAuthor}{M. Pabiszczak} +\newcommand{\DocumentYear}{2026} +\newcommand{\CardSeries}{c} +\newcommand{\CardNumber}{09} +\newcommand{\CardCount}{13} +\newcommand{\CardSlug}{smalloc-sbrk-libc} +\newcommand{\CardVersion}{v00.01} +\newcommand{\DocumentUUID}{47826ae5-6370-5ac2-bd91-9acb89116d40} + +\newcommand{\EmptyCheck}{\(\square\)} +\newcommand{\EscAnswerLines}[1][3]{\par\noindent\dotfill\par\noindent\dotfill\par\noindent\dotfill} +\newcommand{\EscWriteRow}[1][2.8em]{\rule{0pt}{#1}} +\setlength{\parindent}{0pt} +\setlength{\parskip}{0.45em} +\setlength{\headheight}{24mm} +\setlength{\headsep}{3mm} +\setlength{\footskip}{8mm} +\setlength{\marginparwidth}{1.5cm} +\setlength{\marginparsep}{0.25cm} +\renewcommand{\arraystretch}{1.22} +% Margin separator lines disabled for layout trial. + +\newcommand{\ESCPageResourceHeader}{% + \begingroup% + \setlength{\parskip}{0pt}% + \setlength{\fboxsep}{0pt}% + \setlength{\fboxrule}{0.35pt}% + \setlength{\arrayrulewidth}{0.35pt}% + \noindent\fbox{% + \begin{minipage}[c][23.5mm][c]{\dimexpr\textwidth-2\fboxrule\relax}% + \begin{minipage}[c][23mm][c]{24mm}\centering% + \href{https://zsl-gitea.mpabi.pl/edu-inf/lab-rv32i-c-smalloc-sbrk-libc}{\qrcode[level=L,height=22mm]{https://zsl-gitea.mpabi.pl/edu-inf/lab-rv32i-c-smalloc-sbrk-libc}}% + \end{minipage}% + \vrule width0.35pt% + \begin{minipage}[c][23mm][c]{\dimexpr\linewidth-48mm-0.7pt\relax}% + \setlength{\tabcolsep}{0pt}% + \renewcommand{\arraystretch}{0}% + \begin{tabularx}{\linewidth}{@{}p{\dimexpr0.50000000\linewidth-\arrayrulewidth\relax}|p{\dimexpr0.15126050\linewidth-\arrayrulewidth\relax}|X@{}}% + \parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.45mm}{\fontsize{3.2}{3.4}\selectfont\ttfamily\bfseries TITLE}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{7.7}{7.9}\selectfont\ttfamily\bfseries smalloc, sbrk i minimalne libc}\hspace{0.45mm}}\par} & \parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.45mm}{\fontsize{3.2}{3.4}\selectfont\ttfamily\bfseries VER.}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{6.6}{6.8}\selectfont\ttfamily\bfseries v00.01}\hspace{0.45mm}}\par} & \parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.45mm}{\fontsize{3.2}{3.4}\selectfont\ttfamily\bfseries DATETIME}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{6.4}{6.6}\selectfont\ttfamily\bfseries 2026-07-20T00:00:00+02:00}\hspace{0.45mm}}\par} \\% + \end{tabularx}% + \par\nointerlineskip% + \hrule height0.35pt% + \nointerlineskip% + \begin{tabularx}{\linewidth}{@{}p{\dimexpr0.50000000\linewidth-\arrayrulewidth\relax}|p{\dimexpr0.25210084\linewidth-\arrayrulewidth\relax}|p{\dimexpr0.14285714\linewidth-\arrayrulewidth\relax}|X@{}}% + \parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.45mm}{\fontsize{3.2}{3.4}\selectfont\ttfamily\bfseries PROJECT}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{7.7}{7.9}\selectfont\ttfamily\bfseries Freestanding C na RV32I}\hspace{0.45mm}}\par} & \parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.45mm}{\fontsize{3.2}{3.4}\selectfont\ttfamily\bfseries SERIES}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{6.4}{6.6}\selectfont\ttfamily\bfseries C · Freestanding RV32I and K\&R}\hspace{0.45mm}}\par} & \parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.45mm}{\fontsize{3.2}{3.4}\selectfont\ttfamily\bfseries CARD}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{6.4}{6.6}\selectfont\ttfamily\bfseries 09/13}\hspace{0.45mm}}\par} & \parbox[c][5.19414mm][c]{\linewidth}{\hspace{0.45mm}{\fontsize{3.2}{3.4}\selectfont\ttfamily\bfseries SHEET}\par\nointerlineskip\vspace{0.12mm}\noindent\makebox[\linewidth][r]{{\fontsize{6.4}{6.6}\selectfont\ttfamily\bfseries \thepage/\pageref{LastPage}}\hspace{0.45mm}}\par} \\% + \end{tabularx}% + \par\nointerlineskip% + \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 47826ae5-6370-5ac2-bd91-9acb89116d40}\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 8e4f8bee-41f0-523b-8ea2-8926bd3d7ab0}\hfill{\fontsize{3.4}{3.75}\selectfont\ttfamily\bfseries AUTHOR M. Pabiszczak}\hspace{0.35mm}}} \\% + \end{tabularx}% + \par\nointerlineskip% + \hrule height0.35pt% + \nointerlineskip% + \begin{tabularx}{\linewidth}{@{}X@{}}% + \parbox[c][3.46276mm][c]{\linewidth}{\hspace{0.45mm}{\fontsize{4.5}{4.85}\selectfont\ttfamily\bfseries GITEA} {\fontsize{4.5}{4.85}\selectfont\ttfamily\href{https://zsl-gitea.mpabi.pl/edu-inf/lab-rv32i-c-smalloc-sbrk-libc}{\nolinkurl{https://zsl-gitea.mpabi.pl/edu-inf/lab-rv32i-c-smalloc-sbrk-libc}}}} \\% + \end{tabularx}% + \par\nointerlineskip% + \hrule height0.35pt% + \nointerlineskip% + \begin{tabularx}{\linewidth}{@{}X@{}}% + \parbox[c][3.46276mm][c]{\linewidth}{\hspace{0.45mm}{\fontsize{4.5}{4.85}\selectfont\ttfamily\bfseries HTML} {\fontsize{4.5}{4.85}\selectfont\ttfamily\href{https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/8e4f8bee-41f0-523b-8ea2-8926bd3d7ab0}{\nolinkurl{https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/8e4f8bee-41f0-523b-8ea2-8926bd3d7ab0}}}} \\% + \end{tabularx}% + \end{minipage}% + \vrule width0.35pt% + \begin{minipage}[c][23mm][c]{24mm}\centering% + \href{https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/8e4f8bee-41f0-523b-8ea2-8926bd3d7ab0}{\qrcode[level=L,height=22mm]{https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/8e4f8bee-41f0-523b-8ea2-8926bd3d7ab0}}% + \end{minipage}% + \end{minipage}% + }% + \endgroup% +} + +\pagestyle{fancy} +\fancyhf{} +\fancyhead[C]{\ESCPageResourceHeader} +\renewcommand{\headrulewidth}{0pt} +\renewcommand{\footrulewidth}{0pt} + +\newcommand{\ESCMarginTag}[4]{% + \hspace*{#1}\textcolor{#2}{#3~#4}% +} +\newcommand{\ESCSectionBlockStart}{% + \Needspace{8\baselineskip}% + \par\vspace{0.35em}% + \noindent\textcolor{black!28}{\rule{\textwidth}{0.35pt}}% + \par\vspace{0.15em}% +} +\newcommand{\ESCSectionBlockEnd}{% + \par\vspace{0.45em}% +} +\newcommand{\ESCTinyStepSeparator}{% + \par\vspace{0.10em}% + \noindent{\color{black!18}\leaders\hbox{\rule{0.60em}{0.22pt}\hspace{0.38em}}\hfill\kern0pt}% + \par\vspace{0.10em}% +} +\newtcolorbox{ESCTaskFrame}[1]{enhanced,breakable,arc=0pt,boxrule=0.35pt,colback=white,colframe=black,boxsep=0pt,left=1.4mm,right=1.4mm,top=0.8mm,bottom=0.8mm,colbacktitle=black!7,coltitle=black,title={\ttfamily\bfseries TASK\quad #1}} +\newtcolorbox{ESCBlockFrame}[1]{enhanced,breakable,arc=0pt,boxrule=0.35pt,colback=white,colframe=black!55,boxsep=0pt,left=1.0mm,right=1.0mm,top=0.6mm,bottom=0.6mm,colbacktitle=black!4,coltitle=black,title={\ttfamily\bfseries BLOCK\quad #1}} +\newtcolorbox{ESCStepFrame}[1]{enhanced,breakable,arc=0pt,boxrule=0.35pt,colback=white,colframe=black!28,boxsep=0pt,left=0.8mm,right=0.8mm,top=0.45mm,bottom=0.45mm,colbacktitle=black!2,coltitle=black,title={\ttfamily STEP\quad #1}} +\newtcolorbox{ESCConclusionFrame}{enhanced,breakable,arc=0pt,boxrule=0.45pt,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 WNIOSEK}} + +\newcommand{\ESCLearningTreeWidget}{% + \reversemarginpar + \marginnote[% + \begin{minipage}{\marginparwidth}% + \raggedright + {\fontsize{3.55}{3.95}\selectfont\ttfamily + \begin{minipage}[t]{\marginparwidth}% + \raggedright + {\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~C}\textcolor{black!48}{\pdftooltip[width=\textwidth]{.01}{Uczeń porównuje mapę linkera, kontrolowany błąd symbolu, globalne checkpointy, wynik hosta i\textCR kod wyjścia Hazard3, a wnioski ogranicza do naprawdę zmierzonych własności.}}\par% + \hspace*{0.54em}\textcolor{blue!70!black}{KW~LOCAL~C}\textcolor{black!48}{\pdftooltip[width=\textwidth]{.01}{Kod, przewidywanie i pomiar tworzą jeden dowód.}}\par% + \end{minipage}% + }% + \end{minipage}% + ]{} + \normalmarginpar + + \marginnote{% + \begin{minipage}{\marginparwidth}% + \raggedright + {\fontsize{3.55}{3.95}\selectfont\ttfamily + \hspace*{0.06cm}% + \begin{minipage}[t]{\dimexpr\marginparwidth-0.06cm\relax}% + \raggedright + {\bfseries\textcolor{black!65}{OG}\par}% + \vspace{0.08em}% + \hspace*{0.00em}\textcolor{red}{WE~01}\textcolor{black!48}{}\par% + \hspace*{0.28em}\textcolor{green!50!black}{EN~LOCAL~EN~C}\textcolor{black!48}{\pdftooltip[width=\textwidth]{.01}{Uczeń wyprowadza osobno: wybór członu archiwum, wiązanie symbolu dostawcy pamięci oraz\textCR inwarianty polityki alokacji, zamiast nazywać wszystkie trzy mechanizmy stertą.}}\par% + \hspace*{0.54em}\textcolor{blue!70!black}{KW~LOCAL~KW~C}\textcolor{black!48}{\pdftooltip[width=\textwidth]{.01}{Kod, przewidywanie i pomiar tworzą jeden dowód.}}\par% + \end{minipage}% + }% + \end{minipage}% + } + +} + +\begin{document} +\sloppy + +\vspace{1.0em} +\noindent{\Large\bfseries Cel karty}\par +\vspace{0.35em} +Uczeń rozdziela wybór funkcji z archiwum libc, kontrakt dostawcy pamięci sbrk i politykę alokatora. Najpierw dowodzi, że strlen nie potrzebuje sterty, potem kontrolowanie zrywa zależność malloc do sbrk, buduje ograniczony model break i wyrównany smalloc, a na końcu traktuje prawdziwe malloc/free picolibc jako czarną skrzynkę sprawdzaną przez kontrakt. + +\vspace{0.8em} +\noindent\textcolor{black!25}{\rule{\textwidth}{0.35pt}} +\vspace{0.7em} +\noindent{\Large\bfseries Zakres i zachowane przykłady}\par +\vspace{0.35em} +Pięć zachowanych przykładów działa na hoście i RV32I tam, gdzie istnieje program uruchamialny. Task02 jest zamierzonym expected-fail linkera i nie ma obrazu runtime. W aktualnym GCC 15.2 biblioteka to picolibc: jej malloc odwołuje się do sbrk, podczas gdy vendorowy init.S Hazard3 definiuje inny symbol \_sbrk. Własny linker ogranicza stertę symbolami \_\_heap\_start i \_\_heap\_end oraz rezerwuje 64 KiB stosu.\par\textbf{Układ każdego przykładu:} pełny profil A1--A8; widok N/D ma jawny powód, a diagram nie jest wymagany, gdy tekst daje lepszy dowód. +\vspace{0.55em} +\small\begin{tabularx}{\textwidth}{@{}>{\ttfamily\raggedright\arraybackslash}p{1.10cm}>{\ttfamily\raggedright\arraybackslash}p{1.45cm}X>{\raggedright\arraybackslash}p{2.50cm}@{}} +\textbf{K\&R} & \textbf{Numer tasku} & \textbf{Najważniejsza idea} & \textbf{Priorytet} \\ \hline +\hline +\textbf{\texttt{7.8}} & \textbf{\texttt{Task01}} & \textbf{libc.a: wybór strlen.c.o} & \textbf{kluczowe} \\ \hline +\hline +\textbf{\texttt{5.4 + ABI}} & \textbf{\texttt{Task02}} & \textbf{expected-fail: malloc -> sbrk} & \textbf{kluczowe} \\ \hline +\hline +\textbf{\texttt{5.4}} & \textbf{\texttt{Task03}} & \textbf{ograniczony break i atomowy błąd} & \textbf{kluczowe} \\ \hline +\hline +\textbf{\texttt{5.4}} & \textbf{\texttt{Task04}} & \textbf{nagłówek, alignment i reset areny} & \textbf{kluczowe} \\ \hline +\hline +\textbf{\texttt{7.8 + ABI}} & \textbf{\texttt{Task05}} & \textbf{malloc/free picolibc jako black box} & \textbf{kluczowe} \\ \hline +\end{tabularx} +\normalsize + + +\vspace{0.8em} +\noindent\textcolor{black!25}{\rule{\textwidth}{0.35pt}} + +\clearpage + +\ESCSectionBlockStart +\section{1 — Funkcja z libc nie oznacza automatycznie sterty} +\reversemarginpar +\marginnote[% + \begin{minipage}{\marginparwidth}% + \raggedright + {\fontsize{3.55}{3.95}\selectfont\ttfamily + \begin{minipage}[t]{\marginparwidth}% + \raggedright + {\bfseries\textcolor{black!65}{TECH}\par}% + \vspace{0.08em}% + \hspace*{0.00em}\textcolor{red}{WE~01}\textcolor{black!48}{}\par% + \end{minipage}% + }% + \end{minipage}% +]{}[-3.1em] +\normalmarginpar + +\marginnote{% + \begin{minipage}{\marginparwidth}% + \raggedright + {\fontsize{3.55}{3.95}\selectfont\ttfamily + \hspace*{0.06cm}% + \begin{minipage}[t]{\dimexpr\marginparwidth-0.06cm\relax}% + \raggedright + {\bfseries\textcolor{black!65}{OG}\par}% + \vspace{0.08em}% + \hspace*{0.00em}\textcolor{red}{WE~01}\textcolor{black!48}{}\par% + \end{minipage}% + }% + \end{minipage}% +}[-3.1em] + + +Archiwum \texttt{libc.a} nie jest włączane do programu w całości. Linker pobiera człon, który rozwiązuje potrzebny symbol, a następne człony tylko wtedy, gdy pojawią się kolejne nierozwiązane odwołania. Dlatego bezpośrednie wywołanie \texttt{strlen} z opcją \texttt{-fno-builtin} wybiera \texttt{strlen.c.o}, lecz nie wybiera \texttt{libc\_stdlib\_malloc.c.o} ani \texttt{libc\_misc\_picosbrk.c.o}. Dowodem jest mapa linkera, a nie samo dołączenie nagłówka \texttt{string.h}. + +Task01 rozstrzyga wyłącznie tę zależność. Nie dowodzi, że każda funkcja tekstowa jest bezkosztowa ani że całe libc nie używa pamięci dynamicznej. +\ESCSectionBlockEnd + +\ESCSectionBlockStart +\section{2 — malloc potrzebuje sbrk, lecz \_sbrk to inna nazwa} +\reversemarginpar +\marginnote[% + \begin{minipage}{\marginparwidth}% + \raggedright + {\fontsize{3.55}{3.95}\selectfont\ttfamily + \begin{minipage}[t]{\marginparwidth}% + \raggedright + {\bfseries\textcolor{black!65}{TECH}\par}% + \vspace{0.08em}% + \hspace*{0.00em}\textcolor{red}{WE~01}\textcolor{black!48}{}\par% + \end{minipage}% + }% + \end{minipage}% +]{}[-3.1em] +\normalmarginpar + +\marginnote{% + \begin{minipage}{\marginparwidth}% + \raggedright + {\fontsize{3.55}{3.95}\selectfont\ttfamily + \hspace*{0.06cm}% + \begin{minipage}[t]{\dimexpr\marginparwidth-0.06cm\relax}% + \raggedright + {\bfseries\textcolor{black!65}{OG}\par}% + \vspace{0.08em}% + \hspace*{0.00em}\textcolor{red}{WE~01}\textcolor{black!48}{}\par% + \end{minipage}% + }% + \end{minipage}% +}[-3.1em] + + +W badanym GCC 15.2 używane jest \textbf{picolibc}, nie newlib. Człon \texttt{libc\_stdlib\_malloc.c.o} ma niezdefiniowane odwołanie do \texttt{sbrk}. Picolibc może dostarczyć je z \texttt{libc\_misc\_picosbrk.c.o}; ten kod opiera granice na symbolach linkera \texttt{\_\_heap\_start} i \texttt{\_\_heap\_end}. Z kolei \texttt{vendor/Hazard3/.../init.S} definiuje \texttt{\_sbrk} z jednym podkreśleniem. Dla linkera są to dwa różne symbole, więc mogą współistnieć w Task05. + +Task02 używa \texttt{--wrap=sbrk}: każde odwołanie do \texttt{sbrk} zostaje skierowane do celowo brakującego \texttt{\_\_wrap\_sbrk}. Oczekiwany błąd jest kontrolowanym testem krawędzi \texttt{malloc -> sbrk}, a nie awarią całego projektu. +\ESCSectionBlockEnd + +\ESCSectionBlockStart +\section{3 — Od alloc z K\&R 5.4 do bounded sbrk i smalloc} +\reversemarginpar +\marginnote[% + \begin{minipage}{\marginparwidth}% + \raggedright + {\fontsize{3.55}{3.95}\selectfont\ttfamily + \begin{minipage}[t]{\marginparwidth}% + \raggedright + {\bfseries\textcolor{black!65}{TECH}\par}% + \vspace{0.08em}% + \hspace*{0.00em}\textcolor{red}{WE~01}\textcolor{black!48}{}\par% + \end{minipage}% + }% + \end{minipage}% +]{}[-3.1em] +\normalmarginpar + +\marginnote{% + \begin{minipage}{\marginparwidth}% + \raggedright + {\fontsize{3.55}{3.95}\selectfont\ttfamily + \hspace*{0.06cm}% + \begin{minipage}[t]{\dimexpr\marginparwidth-0.06cm\relax}% + \raggedright + {\bfseries\textcolor{black!65}{OG}\par}% + \vspace{0.08em}% + \hspace*{0.00em}\textcolor{red}{WE~01}\textcolor{black!48}{}\par% + \end{minipage}% + }% + \end{minipage}% +}[-3.1em] + + +Liniowy \texttt{alloc} z K\&R 5.4 przesuwa wskaźnik w stałej tablicy. Jest prosty, ale nie odzyskuje dowolnego bloku, nie wybiera najlepszego dopasowania, nie dzieli i nie scala wolnych obszarów. \texttt{afree} może cofnąć wskaźnik jedynie do adresu należącego do areny, więc bez dyscypliny stosowej łatwo unieważnić późniejsze przydziały. Historyczna tablica bajtów nie jest też ogólną deklaracją wyrównania dla każdego typu. + +Task03 zachowuje istotę modelu, lecz jawnie wymusza \texttt{heap\_start <= brk <= heap\_end}; odrzucona operacja nie zmienia break. Task04 dodaje 16-bajtowe wyrównanie i 16-bajtowy nagłówek bezpośrednio przed payloadem. Nadal jest to alokator append-only: nie ma \texttt{sfree}, listy wolnych bloków, split ani coalescing. Jedyną operacją odzyskania jest reset całej areny, który unieważnia wszystkie wcześniejsze wskaźniki. +\ESCSectionBlockEnd + +\ESCSectionBlockStart +\section{4 — Prawdziwe malloc/free jako czarna skrzynka} +\reversemarginpar +\marginnote[% + \begin{minipage}{\marginparwidth}% + \raggedright + {\fontsize{3.55}{3.95}\selectfont\ttfamily + \begin{minipage}[t]{\marginparwidth}% + \raggedright + {\bfseries\textcolor{black!65}{TECH}\par}% + \vspace{0.08em}% + \hspace*{0.00em}\textcolor{red}{WE~01}\textcolor{black!48}{}\par% + \end{minipage}% + }% + \end{minipage}% +]{}[-3.1em] +\normalmarginpar + +\marginnote{% + \begin{minipage}{\marginparwidth}% + \raggedright + {\fontsize{3.55}{3.95}\selectfont\ttfamily + \hspace*{0.06cm}% + \begin{minipage}[t]{\dimexpr\marginparwidth-0.06cm\relax}% + \raggedright + {\bfseries\textcolor{black!65}{OG}\par}% + \vspace{0.08em}% + \hspace*{0.00em}\textcolor{red}{WE~01}\textcolor{black!48}{}\par% + \end{minipage}% + }% + \end{minipage}% +}[-3.1em] + + +Task05 nie zakłada, że picolibc ma taki sam nagłówek lub strategię jak \texttt{c09\_smalloc}. Program sprawdza tylko publiczny kontrakt potrzebny klientowi: dwa udane przydziały dają używalne, rozłączne obszary; zapisane bajty można odczytać; adresy spełniają mierzone wyrównanie; oba bloki są przekazane do \texttt{free}. Nie odczytuje pamięci po \texttt{free} i nie wymaga ponownego użycia tego samego adresu. + +Minimalny startup ustawia \texttt{gp}, pojedynczą bazę TLS \texttt{tp}, zeruje \texttt{.tbss} i \texttt{.bss}, a następnie wywołuje \texttt{main}. Skrypt linkera pozostawia \texttt{\_\_heap\_end} 64 KiB przed \texttt{\_\_stack\_top} i ma \texttt{ASSERT} zatrzymujący obraz, gdy sekcje zajmą zarezerwowany obszar. +\ESCSectionBlockEnd + +\clearpage +\ESCSectionBlockStart +\section{Zadania — zachowane przykłady w profilu A1–A8} +\reversemarginpar +\marginnote[% + \begin{minipage}{\marginparwidth}% + \raggedright + {\fontsize{3.55}{3.95}\selectfont\ttfamily + \begin{minipage}[t]{\marginparwidth}% + \raggedright + {\bfseries\textcolor{black!65}{TECH}\par}% + \vspace{0.08em}% + \hspace*{0.00em}\textcolor{red}{WE~01}\textcolor{black!48}{}\par% + \end{minipage}% + }% + \end{minipage}% +]{}[-3.1em] +\normalmarginpar + +\marginnote{% + \begin{minipage}{\marginparwidth}% + \raggedright + {\fontsize{3.55}{3.95}\selectfont\ttfamily + \hspace*{0.06cm}% + \begin{minipage}[t]{\dimexpr\marginparwidth-0.06cm\relax}% + \raggedright + {\bfseries\textcolor{black!65}{OG}\par}% + \vspace{0.08em}% + \hspace*{0.00em}\textcolor{red}{WE~01}\textcolor{black!48}{}\par% + \end{minipage}% + }% + \end{minipage}% +}[-3.1em] + + +\begin{ESCTaskFrame}{TASK01 · strlen z libc bez sterty} +{\scriptsize\ttfamily 839b8401-9f15-5edc-a214-176c06ba5cb1}\par +\begin{ESCBlockFrame}{A1 CONTEXT · AKTYWNE — klient, archiwum i brak dostawcy pamięci} +\textbf{Zachowany przykład:} \texttt{src/tasks/task01\_libc\_without\_heap.c}.\par Klient wywołuje publiczne \texttt{strlen}. Granicą systemu jest linker wybierający potrzebny człon \texttt{libc.a}; Task01 nie deklaruje ani nie wywołuje \texttt{malloc}, \texttt{free} lub \texttt{sbrk}. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A2 STRUCTURE · AKTYWNE — jedna krawędź symboliczna} +Przy \texttt{-fno-builtin} obiekt tasku zachowuje niezdefiniowany symbol \texttt{strlen}. Linker rozwiązuje go przez \texttt{strlen.c.o}. Ten człon nie tworzy następnej krawędzi do alokatora, dlatego graf zależności kończy się bez warstwy sterty. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A3 DISPATCH · N/D} +\textbf{N/D.} strlen i checkpoint są wywołaniami bezpośrednimi; program nie ma callbacku, ISR, wskaźnika funkcji ani dynamicznego wyboru implementacji. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A4 APPLICATION · AKTYWNE — dwa niezależne warunki sukcesu} +Warunek wykonania to długość 16 dla napisu \texttt{picolibc-no-heap}. Warunek obrazu to obecność wyłącznie potrzebnego członu tekstowego i brak trzech nazw członów związanych z przydziałem. Sam kod wyjścia nie zastępuje kontroli mapy. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A5 FLOW · AKTYWNE — kompilacja, selekcja archiwum, wywołanie} +Kompilator pozostawia call do \texttt{strlen}; linker przegląda archiwum i pobiera \texttt{strlen.c.o}; startup uruchamia \texttt{main}; funkcja oblicza 16; checkpoint publikuje wynik; \texttt{main} zwraca 0. Każdy etap ma inny artefakt dowodowy. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A6 STATE · N/D} +\textbf{N/D.} Program wykonuje jednorazowy, czysty pomiar długości i nie ma domenowego obiektu przechodzącego przez istotne stany ani zasobu o cyklu życia. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A7 RUNTIME · AKTYWNE — global i mapa odpowiadają na inne pytania} +W \texttt{task01\_debug\_checkpoint} global \texttt{g\_task01\_length} ma wartość 16, a \texttt{g\_task01\_pass} wartość 1. Osobno \texttt{prog.map} wskazuje \texttt{libc.a(strlen.c.o)}; test mapy odrzuca każdą nazwę członu heap. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A8 PATTERNS · AKTYWNE — płać za osiągalne symbole, nie za nagłówek} +Dla archiwum statycznego właściwym wzorcem audytu jest śledzenie nierozwiązanych symboli i pobranych członów. \texttt{\#include } dostarcza deklarację; nie jest poleceniem dołączenia całej implementacji libc. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{Ćwiczenie · Przewidywanie → wykonanie → wniosek} +Przed linkowaniem przewidź, które człony \texttt{libc.a} są potrzebne przez bezpośrednie \texttt{strlen}. Uruchom program, a potem w mapie udowodnij obecność \texttt{strlen.c.o} i nieobecność członów malloc, free oraz picosbrk. +\par\textbf{Evidence:} Przewidywany wynik, odczyt programu hostowego wraz z kodem powrotu, wartość obiektu wynikowego w obrazie RV32I oraz krótki wniosek wyjaśniający zgodność albo różnicę. +\par\textbf{Acceptance:} Host i Hazard3: length=16, pass=1, kod 0. Mapa RV32I zawiera libc.a(strlen.c.o), ale nie zawiera libc\_stdlib\_malloc.c.o, libc\_stdlib\_free.c.o ani libc\_misc\_picosbrk.c.o. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{TASK01 · Zapis dowodu ucznia} +\textbf{1. Przewidywanie przed uruchomieniem}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{2. Wynik programu hostowego}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{3. Wynik RV32I i kod wyjścia}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{4. Wniosek: reguła języka lub kontrakt targetu potwierdzony przez pomiar}\par\noindent\dotfill\par\noindent\dotfill +\end{ESCBlockFrame} +\end{ESCTaskFrame} +\clearpage +\begin{ESCTaskFrame}{TASK02 · Kontrolowany brak dostawcy sbrk} +{\scriptsize\ttfamily 9c55597f-3145-5744-b13e-f1c0ee83abc8}\par +\begin{ESCBlockFrame}{A1 CONTEXT · AKTYWNE — kontrolowane przecięcie granicy platformy} +\textbf{Zachowany przykład:} \texttt{src/tasks/task02\_malloc\_requires\_sbrk.c}.\par Kod klienta żąda 16 B przez \texttt{malloc}. Opcja linkera przechwytuje wyłącznie symbol dostawcy pamięci, dzięki czemu testuje granicę libc--platforma bez usuwania lub modyfikowania systemowego archiwum. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A2 STRUCTURE · AKTYWNE — caller, człon malloc i brakujący wrapper} +Obiekt tasku wnosi odwołanie do \texttt{malloc}; linker pobiera \texttt{libc\_stdlib\_malloc.c.o}. Jego odwołania do \texttt{sbrk} są przez \texttt{--wrap} przepisywane na \texttt{\_\_wrap\_sbrk}. Żaden obiekt celowo nie definiuje tej ostatniej nazwy. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A3 DISPATCH · N/D} +\textbf{N/D.} Wywołanie malloc jest bezpośrednie, a --wrap jest transformacją nazw podczas linkowania, nie mechanizmem callbacku, ISR ani dynamicznego dispatchu w programie. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A4 APPLICATION · AKTYWNE — porażka ma precyzyjną sygnaturę} +Sukces testu oznacza jednocześnie: obiekt C powstał, link zwrócił status różny od zera, diagnostyka zawiera \texttt{\_\_wrap\_sbrk} oraz nazwę członu malloc, a końcowy ELF nie istnieje. Inny błąd linkera nie spełnia kryterium. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A5 FLOW · AKTYWNE — expected-fail jako kontrolowany przebieg} +Skrypt usuwa stary artefakt, kompiluje task, uruchamia link w trybie dopuszczającym błąd, zapisuje status i log, po czym przywraca rygor \texttt{set -e}. Dopiero cztery asercje zamieniają oczekiwaną porażkę programu w sukces testu. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A6 STATE · N/D} +\textbf{N/D.} Linkowanie kończy się przed utworzeniem obrazu wykonywalnego, więc nie istnieje runtime, breakpoint ani obiekt domenowy zmieniający stan w czasie wykonania. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A7 RUNTIME · AKTYWNE — dowodem jest diagnostyka przed runtime} +Odczytaj \texttt{expected-link-failure.log}: cztery relokacje z \texttt{libc\_stdlib\_malloc.c.o} wskazują brak \texttt{\_\_wrap\_sbrk}. Następnie sprawdź nieobecność \texttt{must-not-exist.elf}; nie wolno wymyślać wartości runtime dla nieistniejącego programu. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A8 PATTERNS · AKTYWNE — test negatywny musi odrzucać zły powód} +Wzorzec expected-fail wymaga konkretnej sygnatury błędu i braku produktu końcowego. Sam warunek „polecenie nie przeszło” byłby za słaby, bo zaliczyłby literówkę, brak kompilatora lub błędny skrypt linkera. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{Ćwiczenie · Przewidywanie → wykonanie → wniosek} +Narysuj łańcuch \texttt{main -> malloc -> sbrk}. Następnie uruchom \texttt{make expected-fail} i wyjaśnij, dlaczego \texttt{--wrap=sbrk} zmienia ostatnią krawędź na \texttt{\_\_wrap\_sbrk}, dlaczego brak ELF jest wynikiem poprawnym oraz czego ten test nie mówi o runtime. +\par\textbf{Evidence:} Przewidywana brakująca nazwa, status kompilacji obiektu, niezerowy status linkera, cytat dwóch sygnatur z logu oraz sprawdzenie, że końcowy ELF nie istnieje. +\par\textbf{Acceptance:} Kompilacja task.o kończy się sukcesem. Link ma niezerowy status, log wymienia libc\_stdlib\_malloc.c.o i undefined reference to \_\_wrap\_sbrk, a must-not-exist.elf nie istnieje. Nie wykonuje się testu host ani Hazard3. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{TASK02 · Zapis dowodu ucznia} +\textbf{1. Przewidywanie przed uruchomieniem}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{2. Wynik kompilacji task.o}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{3. Status i sygnatury błędu linkera}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{4. Wniosek: reguła języka lub kontrakt targetu potwierdzony przez pomiar}\par\noindent\dotfill\par\noindent\dotfill +\end{ESCBlockFrame} +\end{ESCTaskFrame} +\clearpage +\begin{ESCTaskFrame}{TASK03 · Bounded sbrk i atomowy błąd} +{\scriptsize\ttfamily 5a69ff6d-bda9-5b20-a18c-a8da2f88c64a}\par +\begin{ESCBlockFrame}{A1 CONTEXT · AKTYWNE — model oddzielony od libc} +\textbf{Zachowane materiały:} \texttt{src/tasks/task03\_bounded\_sbrk.c}, \texttt{src/runtime/c09\_bounded\_sbrk.c}, \texttt{src/runtime/c09\_bounded\_sbrk.h}, \texttt{link/hazard3\_c09.ld}.\par Task03 eksportuje nazwę \texttt{c09\_sbrk}, aby nie przejąć symbolu \texttt{sbrk} picolibc. Na hoście granice obejmują statyczną arenę 512 B; na RV32I pochodzą z linkera. Ten sam algorytm widzi tylko trzy adresy. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A2 STRUCTURE · AKTYWNE — start, break i end} +Stan ma jedną zmienną \texttt{g\_c09\_break} oraz niezmienne granice \texttt{start} i \texttt{end}. Każdy poprawny stan spełnia \texttt{start <= break <= end}; wolny obszar ma rozmiar \texttt{end-break}, a zajęty prefiks \texttt{break-start}. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A3 DISPATCH · N/D} +\textbf{N/D.} Wszystkie operacje c09\_sbrk i gettery są wywoływane bezpośrednio; nie ma callbacku, ISR, tablicy funkcji ani wyboru implementacji w runtime. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A4 APPLICATION · AKTYWNE — tabela pięciu przejść} +Od offsetu 0 operacje dają kolejno: \texttt{+16 -> 16}, \texttt{+24 -> 40}, zbyt duży wzrost \texttt{-> 40}, \texttt{-8 -> 32}, zejście o 33 \texttt{-> 32}. Udany call zwraca stary break; porażka zwraca wszystkie bity ustawione. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A5 FLOW · AKTYWNE — najpierw zakres, potem commit} +Dla wzrostu kod porównuje wielkość z \texttt{end-current}; dla spadku oblicza bezpiecznie moduł także dla \texttt{PTRDIFF\_MIN} i porównuje go z \texttt{current-start}. Dopiero po zaliczeniu warunku zapisuje \texttt{g\_c09\_break=next}. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A6 STATE · AKTYWNE — VALID pozostaje VALID także po odrzuceniu} +Break przechodzi przez offsety \texttt{0 -> 16 -> 40 -> 40 -> 32 -> 32}. Obie porażki są samopętlą stanu: zmienia się wynik operacji, ale nie break. Nie ma przejścia do wartości poniżej start ani powyżej end. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A7 RUNTIME · AKTYWNE — offsety zamiast niestabilnych adresów} +Checkpoint publikuje cztery offsety \texttt{40,40,32,32} oraz flagi \texttt{preserved=1} i \texttt{bounds=1}. Adresy bezwzględne hosta mogą się zmieniać przez ASLR, dlatego dowód porównuje różnice względem startu. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A8 PATTERNS · AKTYWNE — validate then commit} +Wzorzec silnej gwarancji błędu brzmi: najpierw policz bez przepełnienia, następnie sprawdź granice, a dopiero potem zmień jedyny stan. Wskaźnik break pozostaje obserwowalnie niezmieniony po odrzuconej operacji. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{Ćwiczenie · Przewidywanie → wykonanie → wniosek} +Zapisz stan break po sekwencji \texttt{+16,+24,fail,-8,fail}. Dla obu porażek wskaż sprawdzaną granicę i udowodnij, że zwrot \texttt{(void *)-1} nie zmienia break. Porównaj stałe offsety hosta i RV32I. +\par\textbf{Evidence:} Przewidywany wynik, odczyt programu hostowego wraz z kodem powrotu, wartość obiektu wynikowego w obrazie RV32I oraz krótki wniosek wyjaśniający zgodność albo różnicę. +\par\textbf{Acceptance:} Host i Hazard3: grow=40, rejected\_grow=40, shrink=32, rejected\_shrink=32, preserved=1, bounds=1, pass=1 i kod 0. Linker: \_\_heap\_start oraz \_\_heap\_end są wyrównane do 16 B, \_\_heap\_end == \_\_stack\_bottom. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{TASK03 · Zapis dowodu ucznia} +\textbf{1. Przewidywanie przed uruchomieniem}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{2. Wynik programu hostowego}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{3. Wynik RV32I i kod wyjścia}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{4. Wniosek: reguła języka lub kontrakt targetu potwierdzony przez pomiar}\par\noindent\dotfill\par\noindent\dotfill +\end{ESCBlockFrame} +\end{ESCTaskFrame} +\clearpage +\begin{ESCTaskFrame}{TASK04 · Wyrównany smalloc append-only} +{\scriptsize\ttfamily e745e1ea-9494-5b75-9596-816022153237}\par +\begin{ESCBlockFrame}{A1 CONTEXT · AKTYWNE — API ma celowo małą władzę} +\textbf{Zachowane materiały:} \texttt{src/tasks/task04\_smalloc.c}, \texttt{src/runtime/c09\_smalloc.c}, \texttt{src/runtime/c09\_smalloc.h}, \texttt{src/runtime/c09\_bounded\_sbrk.c}, \texttt{src/runtime/c09\_bounded\_sbrk.h}.\par Klient może przydzielić payload i zresetować całą arenę. Nie może zwolnić jednego bloku ani przekazać modelowi wskaźnika do picolibc. \texttt{c09\_smalloc} pobiera surowy fragment wyłącznie przez ograniczone \texttt{c09\_sbrk}. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A2 STRUCTURE · AKTYWNE — 16 B metadanych bezpośrednio przed payloadem} +Nagłówek ma cztery pola \texttt{uint32\_t}: magic, requested, reserved i sequence. Jego rozmiar wynosi 16 B. Zwrócony adres to \texttt{header+1}; inspekcja kontrolnie cofa się o dokładnie jeden rzeczywisty nagłówek. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A3 DISPATCH · N/D} +\textbf{N/D.} smalloc, inspect, reset i c09\_sbrk są zwykłymi wywołaniami bezpośrednimi; przykład nie zawiera callbacku, ISR ani dynamicznie wybieranej strategii. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A4 APPLICATION · AKTYWNE — geometria dwóch bloków} +Żądanie 1 B daje \texttt{align16(16+1)=32}; żądanie 17 B daje \texttt{align16(16+17)=48}. Pierwszy payload leży 16 B od startu, drugi 48 B od startu, więc ich delta wynosi 32 B. Oba adresy są wielokrotnością 16. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A5 FLOW · AKTYWNE — size, align, reserve, header, payload} +Kod odrzuca zero i przepełnienie, zaokrągla sumę nagłówka i żądania, sprawdza reprezentowalność jako \texttt{ptrdiff\_t}, rezerwuje cały blok jednym \texttt{c09\_sbrk}, zapisuje cztery pola nagłówka i dopiero wtedy zwraca payload. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A6 STATE · AKTYWNE — EMPTY, TWO BLOCKS, RESET} +Arena przechodzi \texttt{EMPTY -> seq1 -> seq1+seq2}. Brak indywidualnego free oznacza, że break tylko rośnie. \texttt{c09\_smalloc\_reset} wykonuje jedno przejście z dowolnej zawartości do EMPTY i unieważnia oba wskaźniki naraz. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A7 RUNTIME · AKTYWNE — pamięć potwierdza header przed payloadem} +W checkpointcie odczytaj \texttt{first-16}: słowo magic to \texttt{0x534D414C}, requested=1, reserved=32, sequence=1. Pod \texttt{second-16} odpowiednie wartości to 17, 48 i 2. Globale potwierdzają deltę 32 i reset. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A8 PATTERNS · AKTYWNE — bump allocator z jawną granicą użycia} +Append-only arena jest wartościowa dla fazowego scratch storage, gdy wszystkie obiekty mają wspólny czas życia. Nie zastępuje ogólnego malloc: brak selekcji, ponownego użycia pojedynczych luk, split, coalescing i niezależnego free. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{Ćwiczenie · Przewidywanie → wykonanie → wniosek} +Dla żądań 1 B i 17 B wyprowadź rozmiar nagłówka, rezerwację po align-up, adres obu payloadów i zmianę break. Wskaż, dlaczego brak \texttt{c09\_sfree} jest częścią kontraktu, a reset areny nie jest odpowiednikiem \texttt{free(pointer)}. +\par\textbf{Evidence:} Przewidywany wynik, odczyt programu hostowego wraz z kodem powrotu, wartość obiektu wynikowego w obrazie RV32I oraz krótki wniosek wyjaśniający zgodność albo różnicę. +\par\textbf{Acceptance:} Host i Hazard3: header=16, first=32, second=48, delta=32, aligned=1, metadata=1, append=1, reset=1, pass=1 i kod 0. Nagłówki mają sequence 1 i 2; po resecie pierwszy payload wraca pod poprzedni pierwszy adres. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{TASK04 · Zapis dowodu ucznia} +\textbf{1. Przewidywanie przed uruchomieniem}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{2. Wynik programu hostowego}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{3. Wynik RV32I i kod wyjścia}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{4. Wniosek: reguła języka lub kontrakt targetu potwierdzony przez pomiar}\par\noindent\dotfill\par\noindent\dotfill +\end{ESCBlockFrame} +\end{ESCTaskFrame} +\clearpage +\begin{ESCTaskFrame}{TASK05 · malloc/free picolibc jako czarna skrzynka} +{\scriptsize\ttfamily 9a7174f1-efb7-5c18-afbe-1a34ee6da0b7}\par +\begin{ESCBlockFrame}{A1 CONTEXT · AKTYWNE — klient nie zna wnętrza picolibc} +\textbf{Zachowane materiały:} \texttt{src/tasks/task05\_picolibc\_malloc.c}, \texttt{crt0.S}, \texttt{link/hazard3\_c09.ld}.\par Kod tasku używa tylko \texttt{malloc} i \texttt{free}. Linker łączy picolibc z platformą przez \texttt{sbrk} oraz symbole granic. Vendorowe \texttt{\_sbrk} pozostaje osobnym, nieużywanym przez malloc symbolem startu Hazard3. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A2 STRUCTURE · AKTYWNE — obraz składa się z czterech warstw} +ELF zawiera klienta, człony \texttt{malloc/free}, człon \texttt{picosbrk} i platformowy startup. Skrypt linkera dostarcza \texttt{\_\_heap\_start/\_\_heap\_end}; crt0 ustawia \texttt{gp/tp} i zeruje BSS/TBSS. Mapa pokazuje, który obiekt wniósł każdy publiczny symbol. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A3 DISPATCH · N/D} +\textbf{N/D.} Klient wywołuje malloc i free bezpośrednio; badany przebieg nie przekazuje callbacku, nie obsługuje ISR i nie wybiera alokatora przez tablicę funkcji. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A4 APPLICATION · AKTYWNE — kontrakt dwóch niezależnych payloadów} +Program żąda 13 B i 29 B, zapisuje dwie różne sekwencje, sumuje odczytane bajty do 4612 i sprawdza rozłączność półotwartych zakresów adresów. Mierzy co najmniej 8-bajtowe wyrównanie, ale nie narzuca odległości między blokami. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A5 FLOW · AKTYWNE — allocate, use, verify, release} +Po dwóch udanych przydziałach kod zapisuje i natychmiast odczytuje oba zakresy, oblicza checksum i warunki adresowe, zwalnia najpierw drugi, potem pierwszy blok, ustawia \texttt{freed=1} i zatrzymuje się w checkpointcie. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A6 STATE · AKTYWNE — własność payloadu kończy się w free} +Każdy wskaźnik przechodzi od braku zasobu do stanu OWNED po udanym malloc, następnie USED po zapisie i RELEASED po free. Program nie dereferencjuje wskaźnika w RELEASED i nie bada, czy następny malloc odzyska ten sam adres. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A7 RUNTIME · AKTYWNE — wykonanie plus audyt ELF} +Hazard3 kończy program kodem 0; globale pokazują checksum 4612, rozłączność, alignment i oba free. \texttt{nm} musi równocześnie pokazać \texttt{\_sbrk} oraz \texttt{sbrk}, a mapa trzy człony picolibc związane z malloc, free i dostawcą pamięci. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A8 PATTERNS · AKTYWNE — test kontraktu bez zgadywania implementacji} +Poprawny test czarnej skrzynki wymusza własności API, ale nie zależy od prywatnego nagłówka, kierunku wzrostu sterty, dokładnej delty adresów ani ponownego użycia po free. Dzięki temu pozostaje wartościowy po zmianie implementacji libc. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{Ćwiczenie · Przewidywanie → wykonanie → wniosek} +Nie zakładając formatu nagłówka libc, wypisz własności możliwe do sprawdzenia przez klienta dwóch przydziałów. Uruchom host i Hazard3, sprawdź checksum oraz mapę, a w ELF wykaż współistnienie vendorowego \texttt{\_sbrk} i picolibc \texttt{sbrk}. +\par\textbf{Evidence:} Przewidywany wynik, odczyt programu hostowego wraz z kodem powrotu, wartość obiektu wynikowego w obrazie RV32I oraz krótki wniosek wyjaśniający zgodność albo różnicę. +\par\textbf{Acceptance:} Host i Hazard3: nonnull=1, delta\_nonzero=1, checksum=4612, nonoverlap=1, aligned=1, freed=1, pass=1 i kod 0. Mapa RV32I zawiera libc\_stdlib\_malloc.c.o, libc\_stdlib\_free.c.o i libc\_misc\_picosbrk.c.o. ELF definiuje \_sbrk, sbrk, malloc, free, \_\_heap\_start i \_\_heap\_end. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{TASK05 · Zapis dowodu ucznia} +\textbf{1. Przewidywanie przed uruchomieniem}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{2. Wynik programu hostowego}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{3. Wynik RV32I i kod wyjścia}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{4. Wniosek: reguła języka lub kontrakt targetu potwierdzony przez pomiar}\par\noindent\dotfill\par\noindent\dotfill +\end{ESCBlockFrame} +\end{ESCTaskFrame} +\ESCSectionBlockEnd + +\end{document} diff --git a/doc/generated/main.upb b/doc/generated/main.upb new file mode 100644 index 0000000..e69de29 diff --git a/doc/pdf/mpabi-inf-c-09-smalloc-sbrk-libc-v00.01-47826ae5-6370-5ac2-bd91-9acb89116d40.pdf b/doc/pdf/mpabi-inf-c-09-smalloc-sbrk-libc-v00.01-47826ae5-6370-5ac2-bd91-9acb89116d40.pdf new file mode 100644 index 0000000..af09662 Binary files /dev/null and b/doc/pdf/mpabi-inf-c-09-smalloc-sbrk-libc-v00.01-47826ae5-6370-5ac2-bd91-9acb89116d40.pdf differ diff --git a/json/card_source.json b/json/card_source.json new file mode 100644 index 0000000..4fcb244 --- /dev/null +++ b/json/card_source.json @@ -0,0 +1,962 @@ +{ + "$schema": "../../../tools/card-layouts/schemas/card-source.schema.json", + "schema": "esc-card-source.v1", + "card": { + "id": "mpabi-inf-c-09-smalloc-sbrk-libc", + "series": "c", + "series_title": "C · Freestanding RV32I and K&R", + "number": "09", + "count": "13", + "slug": "smalloc-sbrk-libc", + "title": "smalloc, sbrk i minimalne libc", + "topic": "K&R 5.4 i 7.8: granica libc, bounded sbrk, prosty smalloc oraz malloc/free picolibc", + "project": "Freestanding C na RV32I", + "subject": "Informatyka", + "level": "Rok 1 · C09 · RV32I/Hazard3", + "revision_date": "2026-07-20T00:00:00+02:00", + "status": "Gotowa", + "version": "v00.01", + "uuid": "47826ae5-6370-5ac2-bd91-9acb89116d40", + "author": "M. Pabiszczak", + "year": "2026" + }, + "generated": { + "tex": "doc/generated/main.tex", + "html": "web/index.html", + "html_css": "web/style.css", + "html_tree_inspector": false, + "react_app": true + }, + "render_dictionary": false, + "template": "templates/karta-klasyczna.json", + "title_block": { + "category": "KARTA PRACY · INFORMATYKA", + "prepared_by": "M. Pabiszczak", + "prepared_on": "2026-07-20T00:00:00+02:00", + "title": "smalloc, sbrk i minimalne libc", + "url": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/8e4f8bee-41f0-523b-8ea2-8926bd3d7ab0", + "repository_url": "https://zsl-gitea.mpabi.pl/edu-inf/lab-rv32i-c-smalloc-sbrk-libc", + "url_host_uuid": "dce7fb9d-7b2f-5d49-96a2-3a30d3070b84", + "url_domain": "mpabi.pl", + "doc_uuid": "8e4f8bee-41f0-523b-8ea2-8926bd3d7ab0", + "revision": "v00.01", + "issued_on": "2026-07-20T00:00:00+02:00", + "series": "C-09", + "document_type": "karta pracy", + "tool": "card-layouts", + "show_qr": true, + "show_repository_qr": true, + "height_cm": 2.6, + "repeat_on_every_page": true, + "replace_front_matter": true + }, + "front_page_break": true, + "front_page_scope": { + "title": "Cel karty", + "content_tex": "Uczeń rozdziela wybór funkcji z archiwum libc, kontrakt dostawcy pamięci sbrk i politykę alokatora. Najpierw dowodzi, że strlen nie potrzebuje sterty, potem kontrolowanie zrywa zależność malloc do sbrk, buduje ograniczony model break i wyrównany smalloc, a na końcu traktuje prawdziwe malloc/free picolibc jako czarną skrzynkę sprawdzaną przez kontrakt.", + "scope_title": "Zakres i zachowane przykłady", + "scope_content_tex": "Pięć zachowanych przykładów działa na hoście i RV32I tam, gdzie istnieje program uruchamialny. Task02 jest zamierzonym expected-fail linkera i nie ma obrazu runtime. W aktualnym GCC 15.2 biblioteka to picolibc: jej malloc odwołuje się do sbrk, podczas gdy vendorowy init.S Hazard3 definiuje inny symbol \\_sbrk. Własny linker ogranicza stertę symbolami \\_\\_heap\\_start i \\_\\_heap\\_end oraz rezerwuje 64 KiB stosu.\\par\\textbf{Układ każdego przykładu:} pełny profil A1--A8; widok N/D ma jawny powód, a diagram nie jest wymagany, gdy tekst daje lepszy dowód.", + "scope_table": { + "headers": [ + "K&R", + "Numer tasku", + "Najważniejsza idea", + "Priorytet" + ], + "rows": [ + { + "chapter": "7.8", + "task": "Task01", + "idea_tex": "libc.a: wybór strlen.c.o", + "priority": "kluczowe", + "key": true + }, + { + "chapter": "5.4 + ABI", + "task": "Task02", + "idea_tex": "expected-fail: malloc -> sbrk", + "priority": "kluczowe", + "key": true + }, + { + "chapter": "5.4", + "task": "Task03", + "idea_tex": "ograniczony break i atomowy błąd", + "priority": "kluczowe", + "key": true + }, + { + "chapter": "5.4", + "task": "Task04", + "idea_tex": "nagłówek, alignment i reset areny", + "priority": "kluczowe", + "key": true + }, + { + "chapter": "7.8 + ABI", + "task": "Task05", + "idea_tex": "malloc/free picolibc jako black box", + "priority": "kluczowe", + "key": true + } + ] + } + }, + "side_margin_tree_layout": { + "columns": [ + { + "id": "zawodowe", + "label": "TECH", + "side": "left", + "tree": "WE -> EK -> KW", + "description": "Kod C, ABI i obserwacja RV32I." + }, + { + "id": "ogolne", + "label": "OG", + "side": "right", + "tree": "WE -> EN -> KW", + "description": "Przewidywanie, pomiar i wniosek." + } + ] + }, + "learning_effects": { + "C09.EN01": { + "bloom_level": "Analiza", + "label": "Trzy warstwy jednego przydziału", + "text": "Uczeń wyprowadza osobno: wybór członu archiwum, wiązanie symbolu dostawcy pamięci oraz inwarianty polityki alokacji, zamiast nazywać wszystkie trzy mechanizmy stertą.", + "assessment_criteria": [ + "C09.KW01" + ] + }, + "C09.EK01": { + "bloom_level": "Zastosowanie", + "label": "Dowód z mapy, stanu i wykonania", + "text": "Uczeń porównuje mapę linkera, kontrolowany błąd symbolu, globalne checkpointy, wynik hosta i kod wyjścia Hazard3, a wnioski ogranicza do naprawdę zmierzonych własności.", + "assessment_criteria": [ + "C09.KW01" + ] + } + }, + "assessment_criteria": { + "C09.KW01": { + "text": "Task01: length=16, strlen.c.o obecny, człony malloc/free/picosbrk nieobecne. Task02: link kończy się niezerowo przez brak __wrap_sbrk, powstaje log, ale nie ELF. Task03: offset break 40 po wzroście, 40 po odrzuconym wzroście, 32 po skurczeniu i 32 po odrzuconym zejściu poniżej początku; granice są zachowane. Task04: header=16, rezerwacje 32 i 48, delta payloadów 32, alignment=16, kolejność append-only i reset całej areny. Task05: dwa niepuste, rozłączne i co najmniej 8-bajtowo wyrównane bloki, checksum=4612, oba free wykonane; mapa zawiera malloc/free/picosbrk, a ELF równocześnie _sbrk i sbrk. Wszystkie uruchamialne programy host i Hazard3 zwracają 0.", + "learning_effects": [ + "C09.EN01", + "C09.EK01" + ] + } + }, + "educational_requirements": { + "C09.WE01": { + "text": "Czytanie mapy linkera i symboli ELF, bezpieczna arytmetyka granic, wyrównanie bloków oraz rozróżnienie modelu dydaktycznego od kontraktu prawdziwej biblioteki.", + "label": "K&R 5.4 i 7.8: granica libc, bounded sbrk, prosty smalloc oraz malloc/free picolibc", + "learning_effects": [ + "C09.EN01", + "C09.EK01" + ], + "learning_tree": { + "schema": "we-learning-tree.v1", + "policy": "Najpierw przewidywanie, następnie wykonanie i odczyt dowodu.", + "ogolne": [ + { + "effect_ref": "C09.EN01", + "display": "EN C09 01", + "source": "LOCAL", + "official": "C", + "local": "01", + "kind": "EN", + "tree_id": "C09.WE01.OG.LOCAL.C.01", + "text": "Uczeń wyprowadza osobno: wybór członu archiwum, wiązanie symbolu dostawcy pamięci oraz inwarianty polityki alokacji, zamiast nazywać wszystkie trzy mechanizmy stertą.", + "kw": [ + { + "criterion_ref": "C09.KW01", + "display": "KW C09 01", + "source": "LOCAL", + "kind": "KW", + "official": "C", + "local": "01", + "text": "Kod, przewidywanie i pomiar tworzą jeden dowód." + } + ] + } + ], + "zawodowe": [ + { + "effect_ref": "C09.EK01", + "display": "EK C09 01", + "source": "LOCAL", + "official": "C", + "local": "01", + "kind": "EK", + "tree_id": "C09.WE01.TECH.LOCAL.C.01", + "text": "Uczeń porównuje mapę linkera, kontrolowany błąd symbolu, globalne checkpointy, wynik hosta i kod wyjścia Hazard3, a wnioski ogranicza do naprawdę zmierzonych własności.", + "kw": [ + { + "criterion_ref": "C09.KW01", + "display": "KW C09 01", + "source": "LOCAL", + "kind": "KW", + "official": "C", + "local": "01", + "text": "Kod, przewidywanie i pomiar tworzą jeden dowód." + } + ] + } + ] + } + } + }, + "sections": [ + { + "title": "1 — Funkcja z libc nie oznacza automatycznie sterty", + "order": 10, + "content_kind": "prose", + "page_orientation": "portrait", + "content_tex": "Archiwum \\texttt{libc.a} nie jest włączane do programu w całości. Linker pobiera człon, który rozwiązuje potrzebny symbol, a następne człony tylko wtedy, gdy pojawią się kolejne nierozwiązane odwołania. Dlatego bezpośrednie wywołanie \\texttt{strlen} z opcją \\texttt{-fno-builtin} wybiera \\texttt{strlen.c.o}, lecz nie wybiera \\texttt{libc\\_stdlib\\_malloc.c.o} ani \\texttt{libc\\_misc\\_picosbrk.c.o}. Dowodem jest mapa linkera, a nie samo dołączenie nagłówka \\texttt{string.h}.\n\nTask01 rozstrzyga wyłącznie tę zależność. Nie dowodzi, że każda funkcja tekstowa jest bezkosztowa ani że całe libc nie używa pamięci dynamicznej.", + "educational_requirement_refs": [ + "C09.WE01" + ], + "learning_effect_refs": [ + "C09.EN01", + "C09.EK01" + ], + "assessment_criterion_refs": [ + "C09.KW01" + ] + }, + { + "title": "2 — malloc potrzebuje sbrk, lecz _sbrk to inna nazwa", + "order": 20, + "content_kind": "prose", + "page_orientation": "portrait", + "content_tex": "W badanym GCC 15.2 używane jest \\textbf{picolibc}, nie newlib. Człon \\texttt{libc\\_stdlib\\_malloc.c.o} ma niezdefiniowane odwołanie do \\texttt{sbrk}. Picolibc może dostarczyć je z \\texttt{libc\\_misc\\_picosbrk.c.o}; ten kod opiera granice na symbolach linkera \\texttt{\\_\\_heap\\_start} i \\texttt{\\_\\_heap\\_end}. Z kolei \\texttt{vendor/Hazard3/.../init.S} definiuje \\texttt{\\_sbrk} z jednym podkreśleniem. Dla linkera są to dwa różne symbole, więc mogą współistnieć w Task05.\n\nTask02 używa \\texttt{--wrap=sbrk}: każde odwołanie do \\texttt{sbrk} zostaje skierowane do celowo brakującego \\texttt{\\_\\_wrap\\_sbrk}. Oczekiwany błąd jest kontrolowanym testem krawędzi \\texttt{malloc -> sbrk}, a nie awarią całego projektu.", + "educational_requirement_refs": [ + "C09.WE01" + ], + "learning_effect_refs": [ + "C09.EN01", + "C09.EK01" + ], + "assessment_criterion_refs": [ + "C09.KW01" + ] + }, + { + "title": "3 — Od alloc z K&R 5.4 do bounded sbrk i smalloc", + "order": 30, + "content_kind": "prose", + "page_orientation": "portrait", + "content_tex": "Liniowy \\texttt{alloc} z K\\&R 5.4 przesuwa wskaźnik w stałej tablicy. Jest prosty, ale nie odzyskuje dowolnego bloku, nie wybiera najlepszego dopasowania, nie dzieli i nie scala wolnych obszarów. \\texttt{afree} może cofnąć wskaźnik jedynie do adresu należącego do areny, więc bez dyscypliny stosowej łatwo unieważnić późniejsze przydziały. Historyczna tablica bajtów nie jest też ogólną deklaracją wyrównania dla każdego typu.\n\nTask03 zachowuje istotę modelu, lecz jawnie wymusza \\texttt{heap\\_start <= brk <= heap\\_end}; odrzucona operacja nie zmienia break. Task04 dodaje 16-bajtowe wyrównanie i 16-bajtowy nagłówek bezpośrednio przed payloadem. Nadal jest to alokator append-only: nie ma \\texttt{sfree}, listy wolnych bloków, split ani coalescing. Jedyną operacją odzyskania jest reset całej areny, który unieważnia wszystkie wcześniejsze wskaźniki.", + "educational_requirement_refs": [ + "C09.WE01" + ], + "learning_effect_refs": [ + "C09.EN01", + "C09.EK01" + ], + "assessment_criterion_refs": [ + "C09.KW01" + ] + }, + { + "title": "4 — Prawdziwe malloc/free jako czarna skrzynka", + "order": 40, + "content_kind": "prose", + "page_orientation": "portrait", + "content_tex": "Task05 nie zakłada, że picolibc ma taki sam nagłówek lub strategię jak \\texttt{c09\\_smalloc}. Program sprawdza tylko publiczny kontrakt potrzebny klientowi: dwa udane przydziały dają używalne, rozłączne obszary; zapisane bajty można odczytać; adresy spełniają mierzone wyrównanie; oba bloki są przekazane do \\texttt{free}. Nie odczytuje pamięci po \\texttt{free} i nie wymaga ponownego użycia tego samego adresu.\n\nMinimalny startup ustawia \\texttt{gp}, pojedynczą bazę TLS \\texttt{tp}, zeruje \\texttt{.tbss} i \\texttt{.bss}, a następnie wywołuje \\texttt{main}. Skrypt linkera pozostawia \\texttt{\\_\\_heap\\_end} 64 KiB przed \\texttt{\\_\\_stack\\_top} i ma \\texttt{ASSERT} zatrzymujący obraz, gdy sekcje zajmą zarezerwowany obszar.", + "educational_requirement_refs": [ + "C09.WE01" + ], + "learning_effect_refs": [ + "C09.EN01", + "C09.EK01" + ], + "assessment_criterion_refs": [ + "C09.KW01" + ] + }, + { + "title": "Zadania — zachowane przykłady w profilu A1–A8", + "order": 50, + "content_kind": "tasks", + "page_orientation": "portrait", + "task_refs": [ + "task01", + "task02", + "task03", + "task04", + "task05" + ], + "educational_requirement_refs": [ + "C09.WE01" + ], + "learning_effect_refs": [ + "C09.EN01", + "C09.EK01" + ], + "assessment_criterion_refs": [ + "C09.KW01" + ] + } + ], + "tasks": { + "task01": { + "title": "strlen z libc bez sterty", + "uuid": "839b8401-9f15-5edc-a214-176c06ba5cb1", + "prompt_tex": "Przed linkowaniem przewidź, które człony \\texttt{libc.a} są potrzebne przez bezpośrednie \\texttt{strlen}. Uruchom program, a potem w mapie udowodnij obecność \\texttt{strlen.c.o} i nieobecność członów malloc, free oraz picosbrk.", + "criterion": "Host i Hazard3: length=16, pass=1, kod 0. Mapa RV32I zawiera libc.a(strlen.c.o), ale nie zawiera libc_stdlib_malloc.c.o, libc_stdlib_free.c.o ani libc_misc_picosbrk.c.o.", + "conclusion_tex": "", + "render_task_acceptance": false, + "viewpoints": [ + { + "id": "A1", + "status": "enabled", + "title": "CONTEXT — klient, archiwum i brak dostawcy pamięci", + "content_tex": "Klient wywołuje publiczne \\texttt{strlen}. Granicą systemu jest linker wybierający potrzebny człon \\texttt{libc.a}; Task01 nie deklaruje ani nie wywołuje \\texttt{malloc}, \\texttt{free} lub \\texttt{sbrk}." + }, + { + "id": "A2", + "status": "enabled", + "title": "STRUCTURE — jedna krawędź symboliczna", + "content_tex": "Przy \\texttt{-fno-builtin} obiekt tasku zachowuje niezdefiniowany symbol \\texttt{strlen}. Linker rozwiązuje go przez \\texttt{strlen.c.o}. Ten człon nie tworzy następnej krawędzi do alokatora, dlatego graf zależności kończy się bez warstwy sterty." + }, + { + "id": "A3", + "status": "unavailable", + "title": "DISPATCH", + "reason": "strlen i checkpoint są wywołaniami bezpośrednimi; program nie ma callbacku, ISR, wskaźnika funkcji ani dynamicznego wyboru implementacji." + }, + { + "id": "A4", + "status": "enabled", + "title": "APPLICATION — dwa niezależne warunki sukcesu", + "content_tex": "Warunek wykonania to długość 16 dla napisu \\texttt{picolibc-no-heap}. Warunek obrazu to obecność wyłącznie potrzebnego członu tekstowego i brak trzech nazw członów związanych z przydziałem. Sam kod wyjścia nie zastępuje kontroli mapy." + }, + { + "id": "A5", + "status": "enabled", + "title": "FLOW — kompilacja, selekcja archiwum, wywołanie", + "content_tex": "Kompilator pozostawia call do \\texttt{strlen}; linker przegląda archiwum i pobiera \\texttt{strlen.c.o}; startup uruchamia \\texttt{main}; funkcja oblicza 16; checkpoint publikuje wynik; \\texttt{main} zwraca 0. Każdy etap ma inny artefakt dowodowy." + }, + { + "id": "A6", + "status": "unavailable", + "title": "STATE", + "reason": "Program wykonuje jednorazowy, czysty pomiar długości i nie ma domenowego obiektu przechodzącego przez istotne stany ani zasobu o cyklu życia." + }, + { + "id": "A7", + "status": "enabled", + "title": "RUNTIME — global i mapa odpowiadają na inne pytania", + "content_tex": "W \\texttt{task01\\_debug\\_checkpoint} global \\texttt{g\\_task01\\_length} ma wartość 16, a \\texttt{g\\_task01\\_pass} wartość 1. Osobno \\texttt{prog.map} wskazuje \\texttt{libc.a(strlen.c.o)}; test mapy odrzuca każdą nazwę członu heap." + }, + { + "id": "A8", + "status": "enabled", + "title": "PATTERNS — płać za osiągalne symbole, nie za nagłówek", + "content_tex": "Dla archiwum statycznego właściwym wzorcem audytu jest śledzenie nierozwiązanych symboli i pobranych członów. \\texttt{\\#include } dostarcza deklarację; nie jest poleceniem dołączenia całej implementacji libc." + } + ], + "flow": [ + { + "kind": "block", + "id": "task01.a1", + "title": "A1 CONTEXT · AKTYWNE — klient, archiwum i brak dostawcy pamięci", + "content_tex": "\\textbf{Zachowany przykład:} \\texttt{src/tasks/task01\\_libc\\_without\\_heap.c}.\\par Klient wywołuje publiczne \\texttt{strlen}. Granicą systemu jest linker wybierający potrzebny człon \\texttt{libc.a}; Task01 nie deklaruje ani nie wywołuje \\texttt{malloc}, \\texttt{free} lub \\texttt{sbrk}." + }, + { + "kind": "block", + "id": "task01.a2", + "title": "A2 STRUCTURE · AKTYWNE — jedna krawędź symboliczna", + "content_tex": "Przy \\texttt{-fno-builtin} obiekt tasku zachowuje niezdefiniowany symbol \\texttt{strlen}. Linker rozwiązuje go przez \\texttt{strlen.c.o}. Ten człon nie tworzy następnej krawędzi do alokatora, dlatego graf zależności kończy się bez warstwy sterty." + }, + { + "kind": "block", + "id": "task01.a3", + "title": "A3 DISPATCH · N/D", + "content_tex": "\\textbf{N/D.} strlen i checkpoint są wywołaniami bezpośrednimi; program nie ma callbacku, ISR, wskaźnika funkcji ani dynamicznego wyboru implementacji." + }, + { + "kind": "block", + "id": "task01.a4", + "title": "A4 APPLICATION · AKTYWNE — dwa niezależne warunki sukcesu", + "content_tex": "Warunek wykonania to długość 16 dla napisu \\texttt{picolibc-no-heap}. Warunek obrazu to obecność wyłącznie potrzebnego członu tekstowego i brak trzech nazw członów związanych z przydziałem. Sam kod wyjścia nie zastępuje kontroli mapy." + }, + { + "kind": "block", + "id": "task01.a5", + "title": "A5 FLOW · AKTYWNE — kompilacja, selekcja archiwum, wywołanie", + "content_tex": "Kompilator pozostawia call do \\texttt{strlen}; linker przegląda archiwum i pobiera \\texttt{strlen.c.o}; startup uruchamia \\texttt{main}; funkcja oblicza 16; checkpoint publikuje wynik; \\texttt{main} zwraca 0. Każdy etap ma inny artefakt dowodowy." + }, + { + "kind": "block", + "id": "task01.a6", + "title": "A6 STATE · N/D", + "content_tex": "\\textbf{N/D.} Program wykonuje jednorazowy, czysty pomiar długości i nie ma domenowego obiektu przechodzącego przez istotne stany ani zasobu o cyklu życia." + }, + { + "kind": "block", + "id": "task01.a7", + "title": "A7 RUNTIME · AKTYWNE — global i mapa odpowiadają na inne pytania", + "content_tex": "W \\texttt{task01\\_debug\\_checkpoint} global \\texttt{g\\_task01\\_length} ma wartość 16, a \\texttt{g\\_task01\\_pass} wartość 1. Osobno \\texttt{prog.map} wskazuje \\texttt{libc.a(strlen.c.o)}; test mapy odrzuca każdą nazwę członu heap." + }, + { + "kind": "block", + "id": "task01.a8", + "title": "A8 PATTERNS · AKTYWNE — płać za osiągalne symbole, nie za nagłówek", + "content_tex": "Dla archiwum statycznego właściwym wzorcem audytu jest śledzenie nierozwiązanych symboli i pobranych członów. \\texttt{\\#include } dostarcza deklarację; nie jest poleceniem dołączenia całej implementacji libc." + }, + { + "kind": "exercise", + "id": "task01.proof", + "title": "Przewidywanie → wykonanie → wniosek", + "prompt_tex": "Przed linkowaniem przewidź, które człony \\texttt{libc.a} są potrzebne przez bezpośrednie \\texttt{strlen}. Uruchom program, a potem w mapie udowodnij obecność \\texttt{strlen.c.o} i nieobecność członów malloc, free oraz picosbrk.", + "evidence_tex": "Przewidywany wynik, odczyt programu hostowego wraz z kodem powrotu, wartość obiektu wynikowego w obrazie RV32I oraz krótki wniosek wyjaśniający zgodność albo różnicę.", + "criterion": "Host i Hazard3: length=16, pass=1, kod 0. Mapa RV32I zawiera libc.a(strlen.c.o), ale nie zawiera libc_stdlib_malloc.c.o, libc_stdlib_free.c.o ani libc_misc_picosbrk.c.o." + }, + { + "kind": "block", + "id": "task01.worksheet", + "title": "TASK01 · Zapis dowodu ucznia", + "content_tex": "\\textbf{1. Przewidywanie przed uruchomieniem}\\par\\noindent\\dotfill\\par\\noindent\\dotfill\\par\\textbf{2. Wynik programu hostowego}\\par\\noindent\\dotfill\\par\\noindent\\dotfill\\par\\textbf{3. Wynik RV32I i kod wyjścia}\\par\\noindent\\dotfill\\par\\noindent\\dotfill\\par\\textbf{4. Wniosek: reguła języka lub kontrakt targetu potwierdzony przez pomiar}\\par\\noindent\\dotfill\\par\\noindent\\dotfill" + } + ], + "educational_requirement_refs": [ + "C09.WE01" + ], + "learning_effect_refs": [ + "C09.EN01", + "C09.EK01" + ], + "assessment_criterion_ref": "C09.KW01" + }, + "task02": { + "title": "Kontrolowany brak dostawcy sbrk", + "uuid": "9c55597f-3145-5744-b13e-f1c0ee83abc8", + "prompt_tex": "Narysuj łańcuch \\texttt{main -> malloc -> sbrk}. Następnie uruchom \\texttt{make expected-fail} i wyjaśnij, dlaczego \\texttt{--wrap=sbrk} zmienia ostatnią krawędź na \\texttt{\\_\\_wrap\\_sbrk}, dlaczego brak ELF jest wynikiem poprawnym oraz czego ten test nie mówi o runtime.", + "criterion": "Kompilacja task.o kończy się sukcesem. Link ma niezerowy status, log wymienia libc_stdlib_malloc.c.o i undefined reference to __wrap_sbrk, a must-not-exist.elf nie istnieje. Nie wykonuje się testu host ani Hazard3.", + "conclusion_tex": "", + "render_task_acceptance": false, + "viewpoints": [ + { + "id": "A1", + "status": "enabled", + "title": "CONTEXT — kontrolowane przecięcie granicy platformy", + "content_tex": "Kod klienta żąda 16 B przez \\texttt{malloc}. Opcja linkera przechwytuje wyłącznie symbol dostawcy pamięci, dzięki czemu testuje granicę libc--platforma bez usuwania lub modyfikowania systemowego archiwum." + }, + { + "id": "A2", + "status": "enabled", + "title": "STRUCTURE — caller, człon malloc i brakujący wrapper", + "content_tex": "Obiekt tasku wnosi odwołanie do \\texttt{malloc}; linker pobiera \\texttt{libc\\_stdlib\\_malloc.c.o}. Jego odwołania do \\texttt{sbrk} są przez \\texttt{--wrap} przepisywane na \\texttt{\\_\\_wrap\\_sbrk}. Żaden obiekt celowo nie definiuje tej ostatniej nazwy." + }, + { + "id": "A3", + "status": "unavailable", + "title": "DISPATCH", + "reason": "Wywołanie malloc jest bezpośrednie, a --wrap jest transformacją nazw podczas linkowania, nie mechanizmem callbacku, ISR ani dynamicznego dispatchu w programie." + }, + { + "id": "A4", + "status": "enabled", + "title": "APPLICATION — porażka ma precyzyjną sygnaturę", + "content_tex": "Sukces testu oznacza jednocześnie: obiekt C powstał, link zwrócił status różny od zera, diagnostyka zawiera \\texttt{\\_\\_wrap\\_sbrk} oraz nazwę członu malloc, a końcowy ELF nie istnieje. Inny błąd linkera nie spełnia kryterium." + }, + { + "id": "A5", + "status": "enabled", + "title": "FLOW — expected-fail jako kontrolowany przebieg", + "content_tex": "Skrypt usuwa stary artefakt, kompiluje task, uruchamia link w trybie dopuszczającym błąd, zapisuje status i log, po czym przywraca rygor \\texttt{set -e}. Dopiero cztery asercje zamieniają oczekiwaną porażkę programu w sukces testu." + }, + { + "id": "A6", + "status": "unavailable", + "title": "STATE", + "reason": "Linkowanie kończy się przed utworzeniem obrazu wykonywalnego, więc nie istnieje runtime, breakpoint ani obiekt domenowy zmieniający stan w czasie wykonania." + }, + { + "id": "A7", + "status": "enabled", + "title": "RUNTIME — dowodem jest diagnostyka przed runtime", + "content_tex": "Odczytaj \\texttt{expected-link-failure.log}: cztery relokacje z \\texttt{libc\\_stdlib\\_malloc.c.o} wskazują brak \\texttt{\\_\\_wrap\\_sbrk}. Następnie sprawdź nieobecność \\texttt{must-not-exist.elf}; nie wolno wymyślać wartości runtime dla nieistniejącego programu." + }, + { + "id": "A8", + "status": "enabled", + "title": "PATTERNS — test negatywny musi odrzucać zły powód", + "content_tex": "Wzorzec expected-fail wymaga konkretnej sygnatury błędu i braku produktu końcowego. Sam warunek „polecenie nie przeszło” byłby za słaby, bo zaliczyłby literówkę, brak kompilatora lub błędny skrypt linkera." + } + ], + "flow": [ + { + "kind": "block", + "id": "task02.a1", + "title": "A1 CONTEXT · AKTYWNE — kontrolowane przecięcie granicy platformy", + "content_tex": "\\textbf{Zachowany przykład:} \\texttt{src/tasks/task02\\_malloc\\_requires\\_sbrk.c}.\\par Kod klienta żąda 16 B przez \\texttt{malloc}. Opcja linkera przechwytuje wyłącznie symbol dostawcy pamięci, dzięki czemu testuje granicę libc--platforma bez usuwania lub modyfikowania systemowego archiwum." + }, + { + "kind": "block", + "id": "task02.a2", + "title": "A2 STRUCTURE · AKTYWNE — caller, człon malloc i brakujący wrapper", + "content_tex": "Obiekt tasku wnosi odwołanie do \\texttt{malloc}; linker pobiera \\texttt{libc\\_stdlib\\_malloc.c.o}. Jego odwołania do \\texttt{sbrk} są przez \\texttt{--wrap} przepisywane na \\texttt{\\_\\_wrap\\_sbrk}. Żaden obiekt celowo nie definiuje tej ostatniej nazwy." + }, + { + "kind": "block", + "id": "task02.a3", + "title": "A3 DISPATCH · N/D", + "content_tex": "\\textbf{N/D.} Wywołanie malloc jest bezpośrednie, a --wrap jest transformacją nazw podczas linkowania, nie mechanizmem callbacku, ISR ani dynamicznego dispatchu w programie." + }, + { + "kind": "block", + "id": "task02.a4", + "title": "A4 APPLICATION · AKTYWNE — porażka ma precyzyjną sygnaturę", + "content_tex": "Sukces testu oznacza jednocześnie: obiekt C powstał, link zwrócił status różny od zera, diagnostyka zawiera \\texttt{\\_\\_wrap\\_sbrk} oraz nazwę członu malloc, a końcowy ELF nie istnieje. Inny błąd linkera nie spełnia kryterium." + }, + { + "kind": "block", + "id": "task02.a5", + "title": "A5 FLOW · AKTYWNE — expected-fail jako kontrolowany przebieg", + "content_tex": "Skrypt usuwa stary artefakt, kompiluje task, uruchamia link w trybie dopuszczającym błąd, zapisuje status i log, po czym przywraca rygor \\texttt{set -e}. Dopiero cztery asercje zamieniają oczekiwaną porażkę programu w sukces testu." + }, + { + "kind": "block", + "id": "task02.a6", + "title": "A6 STATE · N/D", + "content_tex": "\\textbf{N/D.} Linkowanie kończy się przed utworzeniem obrazu wykonywalnego, więc nie istnieje runtime, breakpoint ani obiekt domenowy zmieniający stan w czasie wykonania." + }, + { + "kind": "block", + "id": "task02.a7", + "title": "A7 RUNTIME · AKTYWNE — dowodem jest diagnostyka przed runtime", + "content_tex": "Odczytaj \\texttt{expected-link-failure.log}: cztery relokacje z \\texttt{libc\\_stdlib\\_malloc.c.o} wskazują brak \\texttt{\\_\\_wrap\\_sbrk}. Następnie sprawdź nieobecność \\texttt{must-not-exist.elf}; nie wolno wymyślać wartości runtime dla nieistniejącego programu." + }, + { + "kind": "block", + "id": "task02.a8", + "title": "A8 PATTERNS · AKTYWNE — test negatywny musi odrzucać zły powód", + "content_tex": "Wzorzec expected-fail wymaga konkretnej sygnatury błędu i braku produktu końcowego. Sam warunek „polecenie nie przeszło” byłby za słaby, bo zaliczyłby literówkę, brak kompilatora lub błędny skrypt linkera." + }, + { + "kind": "exercise", + "id": "task02.proof", + "title": "Przewidywanie → wykonanie → wniosek", + "prompt_tex": "Narysuj łańcuch \\texttt{main -> malloc -> sbrk}. Następnie uruchom \\texttt{make expected-fail} i wyjaśnij, dlaczego \\texttt{--wrap=sbrk} zmienia ostatnią krawędź na \\texttt{\\_\\_wrap\\_sbrk}, dlaczego brak ELF jest wynikiem poprawnym oraz czego ten test nie mówi o runtime.", + "evidence_tex": "Przewidywana brakująca nazwa, status kompilacji obiektu, niezerowy status linkera, cytat dwóch sygnatur z logu oraz sprawdzenie, że końcowy ELF nie istnieje.", + "criterion": "Kompilacja task.o kończy się sukcesem. Link ma niezerowy status, log wymienia libc_stdlib_malloc.c.o i undefined reference to __wrap_sbrk, a must-not-exist.elf nie istnieje. Nie wykonuje się testu host ani Hazard3." + }, + { + "kind": "block", + "id": "task02.worksheet", + "title": "TASK02 · Zapis dowodu ucznia", + "content_tex": "\\textbf{1. Przewidywanie przed uruchomieniem}\\par\\noindent\\dotfill\\par\\noindent\\dotfill\\par\\textbf{2. Wynik kompilacji task.o}\\par\\noindent\\dotfill\\par\\noindent\\dotfill\\par\\textbf{3. Status i sygnatury błędu linkera}\\par\\noindent\\dotfill\\par\\noindent\\dotfill\\par\\textbf{4. Wniosek: reguła języka lub kontrakt targetu potwierdzony przez pomiar}\\par\\noindent\\dotfill\\par\\noindent\\dotfill" + } + ], + "educational_requirement_refs": [ + "C09.WE01" + ], + "learning_effect_refs": [ + "C09.EN01", + "C09.EK01" + ], + "assessment_criterion_ref": "C09.KW01" + }, + "task03": { + "title": "Bounded sbrk i atomowy błąd", + "uuid": "5a69ff6d-bda9-5b20-a18c-a8da2f88c64a", + "prompt_tex": "Zapisz stan break po sekwencji \\texttt{+16,+24,fail,-8,fail}. Dla obu porażek wskaż sprawdzaną granicę i udowodnij, że zwrot \\texttt{(void *)-1} nie zmienia break. Porównaj stałe offsety hosta i RV32I.", + "criterion": "Host i Hazard3: grow=40, rejected_grow=40, shrink=32, rejected_shrink=32, preserved=1, bounds=1, pass=1 i kod 0. Linker: __heap_start oraz __heap_end są wyrównane do 16 B, __heap_end == __stack_bottom.", + "conclusion_tex": "", + "render_task_acceptance": false, + "viewpoints": [ + { + "id": "A1", + "status": "enabled", + "title": "CONTEXT — model oddzielony od libc", + "content_tex": "Task03 eksportuje nazwę \\texttt{c09\\_sbrk}, aby nie przejąć symbolu \\texttt{sbrk} picolibc. Na hoście granice obejmują statyczną arenę 512 B; na RV32I pochodzą z linkera. Ten sam algorytm widzi tylko trzy adresy." + }, + { + "id": "A2", + "status": "enabled", + "title": "STRUCTURE — start, break i end", + "content_tex": "Stan ma jedną zmienną \\texttt{g\\_c09\\_break} oraz niezmienne granice \\texttt{start} i \\texttt{end}. Każdy poprawny stan spełnia \\texttt{start <= break <= end}; wolny obszar ma rozmiar \\texttt{end-break}, a zajęty prefiks \\texttt{break-start}." + }, + { + "id": "A3", + "status": "unavailable", + "title": "DISPATCH", + "reason": "Wszystkie operacje c09_sbrk i gettery są wywoływane bezpośrednio; nie ma callbacku, ISR, tablicy funkcji ani wyboru implementacji w runtime." + }, + { + "id": "A4", + "status": "enabled", + "title": "APPLICATION — tabela pięciu przejść", + "content_tex": "Od offsetu 0 operacje dają kolejno: \\texttt{+16 -> 16}, \\texttt{+24 -> 40}, zbyt duży wzrost \\texttt{-> 40}, \\texttt{-8 -> 32}, zejście o 33 \\texttt{-> 32}. Udany call zwraca stary break; porażka zwraca wszystkie bity ustawione." + }, + { + "id": "A5", + "status": "enabled", + "title": "FLOW — najpierw zakres, potem commit", + "content_tex": "Dla wzrostu kod porównuje wielkość z \\texttt{end-current}; dla spadku oblicza bezpiecznie moduł także dla \\texttt{PTRDIFF\\_MIN} i porównuje go z \\texttt{current-start}. Dopiero po zaliczeniu warunku zapisuje \\texttt{g\\_c09\\_break=next}." + }, + { + "id": "A6", + "status": "enabled", + "title": "STATE — VALID pozostaje VALID także po odrzuceniu", + "content_tex": "Break przechodzi przez offsety \\texttt{0 -> 16 -> 40 -> 40 -> 32 -> 32}. Obie porażki są samopętlą stanu: zmienia się wynik operacji, ale nie break. Nie ma przejścia do wartości poniżej start ani powyżej end." + }, + { + "id": "A7", + "status": "enabled", + "title": "RUNTIME — offsety zamiast niestabilnych adresów", + "content_tex": "Checkpoint publikuje cztery offsety \\texttt{40,40,32,32} oraz flagi \\texttt{preserved=1} i \\texttt{bounds=1}. Adresy bezwzględne hosta mogą się zmieniać przez ASLR, dlatego dowód porównuje różnice względem startu." + }, + { + "id": "A8", + "status": "enabled", + "title": "PATTERNS — validate then commit", + "content_tex": "Wzorzec silnej gwarancji błędu brzmi: najpierw policz bez przepełnienia, następnie sprawdź granice, a dopiero potem zmień jedyny stan. Wskaźnik break pozostaje obserwowalnie niezmieniony po odrzuconej operacji." + } + ], + "flow": [ + { + "kind": "block", + "id": "task03.a1", + "title": "A1 CONTEXT · AKTYWNE — model oddzielony od libc", + "content_tex": "\\textbf{Zachowane materiały:} \\texttt{src/tasks/task03\\_bounded\\_sbrk.c}, \\texttt{src/runtime/c09\\_bounded\\_sbrk.c}, \\texttt{src/runtime/c09\\_bounded\\_sbrk.h}, \\texttt{link/hazard3\\_c09.ld}.\\par Task03 eksportuje nazwę \\texttt{c09\\_sbrk}, aby nie przejąć symbolu \\texttt{sbrk} picolibc. Na hoście granice obejmują statyczną arenę 512 B; na RV32I pochodzą z linkera. Ten sam algorytm widzi tylko trzy adresy." + }, + { + "kind": "block", + "id": "task03.a2", + "title": "A2 STRUCTURE · AKTYWNE — start, break i end", + "content_tex": "Stan ma jedną zmienną \\texttt{g\\_c09\\_break} oraz niezmienne granice \\texttt{start} i \\texttt{end}. Każdy poprawny stan spełnia \\texttt{start <= break <= end}; wolny obszar ma rozmiar \\texttt{end-break}, a zajęty prefiks \\texttt{break-start}." + }, + { + "kind": "block", + "id": "task03.a3", + "title": "A3 DISPATCH · N/D", + "content_tex": "\\textbf{N/D.} Wszystkie operacje c09\\_sbrk i gettery są wywoływane bezpośrednio; nie ma callbacku, ISR, tablicy funkcji ani wyboru implementacji w runtime." + }, + { + "kind": "block", + "id": "task03.a4", + "title": "A4 APPLICATION · AKTYWNE — tabela pięciu przejść", + "content_tex": "Od offsetu 0 operacje dają kolejno: \\texttt{+16 -> 16}, \\texttt{+24 -> 40}, zbyt duży wzrost \\texttt{-> 40}, \\texttt{-8 -> 32}, zejście o 33 \\texttt{-> 32}. Udany call zwraca stary break; porażka zwraca wszystkie bity ustawione." + }, + { + "kind": "block", + "id": "task03.a5", + "title": "A5 FLOW · AKTYWNE — najpierw zakres, potem commit", + "content_tex": "Dla wzrostu kod porównuje wielkość z \\texttt{end-current}; dla spadku oblicza bezpiecznie moduł także dla \\texttt{PTRDIFF\\_MIN} i porównuje go z \\texttt{current-start}. Dopiero po zaliczeniu warunku zapisuje \\texttt{g\\_c09\\_break=next}." + }, + { + "kind": "block", + "id": "task03.a6", + "title": "A6 STATE · AKTYWNE — VALID pozostaje VALID także po odrzuceniu", + "content_tex": "Break przechodzi przez offsety \\texttt{0 -> 16 -> 40 -> 40 -> 32 -> 32}. Obie porażki są samopętlą stanu: zmienia się wynik operacji, ale nie break. Nie ma przejścia do wartości poniżej start ani powyżej end." + }, + { + "kind": "block", + "id": "task03.a7", + "title": "A7 RUNTIME · AKTYWNE — offsety zamiast niestabilnych adresów", + "content_tex": "Checkpoint publikuje cztery offsety \\texttt{40,40,32,32} oraz flagi \\texttt{preserved=1} i \\texttt{bounds=1}. Adresy bezwzględne hosta mogą się zmieniać przez ASLR, dlatego dowód porównuje różnice względem startu." + }, + { + "kind": "block", + "id": "task03.a8", + "title": "A8 PATTERNS · AKTYWNE — validate then commit", + "content_tex": "Wzorzec silnej gwarancji błędu brzmi: najpierw policz bez przepełnienia, następnie sprawdź granice, a dopiero potem zmień jedyny stan. Wskaźnik break pozostaje obserwowalnie niezmieniony po odrzuconej operacji." + }, + { + "kind": "exercise", + "id": "task03.proof", + "title": "Przewidywanie → wykonanie → wniosek", + "prompt_tex": "Zapisz stan break po sekwencji \\texttt{+16,+24,fail,-8,fail}. Dla obu porażek wskaż sprawdzaną granicę i udowodnij, że zwrot \\texttt{(void *)-1} nie zmienia break. Porównaj stałe offsety hosta i RV32I.", + "evidence_tex": "Przewidywany wynik, odczyt programu hostowego wraz z kodem powrotu, wartość obiektu wynikowego w obrazie RV32I oraz krótki wniosek wyjaśniający zgodność albo różnicę.", + "criterion": "Host i Hazard3: grow=40, rejected_grow=40, shrink=32, rejected_shrink=32, preserved=1, bounds=1, pass=1 i kod 0. Linker: __heap_start oraz __heap_end są wyrównane do 16 B, __heap_end == __stack_bottom." + }, + { + "kind": "block", + "id": "task03.worksheet", + "title": "TASK03 · Zapis dowodu ucznia", + "content_tex": "\\textbf{1. Przewidywanie przed uruchomieniem}\\par\\noindent\\dotfill\\par\\noindent\\dotfill\\par\\textbf{2. Wynik programu hostowego}\\par\\noindent\\dotfill\\par\\noindent\\dotfill\\par\\textbf{3. Wynik RV32I i kod wyjścia}\\par\\noindent\\dotfill\\par\\noindent\\dotfill\\par\\textbf{4. Wniosek: reguła języka lub kontrakt targetu potwierdzony przez pomiar}\\par\\noindent\\dotfill\\par\\noindent\\dotfill" + } + ], + "educational_requirement_refs": [ + "C09.WE01" + ], + "learning_effect_refs": [ + "C09.EN01", + "C09.EK01" + ], + "assessment_criterion_ref": "C09.KW01" + }, + "task04": { + "title": "Wyrównany smalloc append-only", + "uuid": "e745e1ea-9494-5b75-9596-816022153237", + "prompt_tex": "Dla żądań 1 B i 17 B wyprowadź rozmiar nagłówka, rezerwację po align-up, adres obu payloadów i zmianę break. Wskaż, dlaczego brak \\texttt{c09\\_sfree} jest częścią kontraktu, a reset areny nie jest odpowiednikiem \\texttt{free(pointer)}.", + "criterion": "Host i Hazard3: header=16, first=32, second=48, delta=32, aligned=1, metadata=1, append=1, reset=1, pass=1 i kod 0. Nagłówki mają sequence 1 i 2; po resecie pierwszy payload wraca pod poprzedni pierwszy adres.", + "conclusion_tex": "", + "render_task_acceptance": false, + "viewpoints": [ + { + "id": "A1", + "status": "enabled", + "title": "CONTEXT — API ma celowo małą władzę", + "content_tex": "Klient może przydzielić payload i zresetować całą arenę. Nie może zwolnić jednego bloku ani przekazać modelowi wskaźnika do picolibc. \\texttt{c09\\_smalloc} pobiera surowy fragment wyłącznie przez ograniczone \\texttt{c09\\_sbrk}." + }, + { + "id": "A2", + "status": "enabled", + "title": "STRUCTURE — 16 B metadanych bezpośrednio przed payloadem", + "content_tex": "Nagłówek ma cztery pola \\texttt{uint32\\_t}: magic, requested, reserved i sequence. Jego rozmiar wynosi 16 B. Zwrócony adres to \\texttt{header+1}; inspekcja kontrolnie cofa się o dokładnie jeden rzeczywisty nagłówek." + }, + { + "id": "A3", + "status": "unavailable", + "title": "DISPATCH", + "reason": "smalloc, inspect, reset i c09_sbrk są zwykłymi wywołaniami bezpośrednimi; przykład nie zawiera callbacku, ISR ani dynamicznie wybieranej strategii." + }, + { + "id": "A4", + "status": "enabled", + "title": "APPLICATION — geometria dwóch bloków", + "content_tex": "Żądanie 1 B daje \\texttt{align16(16+1)=32}; żądanie 17 B daje \\texttt{align16(16+17)=48}. Pierwszy payload leży 16 B od startu, drugi 48 B od startu, więc ich delta wynosi 32 B. Oba adresy są wielokrotnością 16." + }, + { + "id": "A5", + "status": "enabled", + "title": "FLOW — size, align, reserve, header, payload", + "content_tex": "Kod odrzuca zero i przepełnienie, zaokrągla sumę nagłówka i żądania, sprawdza reprezentowalność jako \\texttt{ptrdiff\\_t}, rezerwuje cały blok jednym \\texttt{c09\\_sbrk}, zapisuje cztery pola nagłówka i dopiero wtedy zwraca payload." + }, + { + "id": "A6", + "status": "enabled", + "title": "STATE — EMPTY, TWO BLOCKS, RESET", + "content_tex": "Arena przechodzi \\texttt{EMPTY -> seq1 -> seq1+seq2}. Brak indywidualnego free oznacza, że break tylko rośnie. \\texttt{c09\\_smalloc\\_reset} wykonuje jedno przejście z dowolnej zawartości do EMPTY i unieważnia oba wskaźniki naraz." + }, + { + "id": "A7", + "status": "enabled", + "title": "RUNTIME — pamięć potwierdza header przed payloadem", + "content_tex": "W checkpointcie odczytaj \\texttt{first-16}: słowo magic to \\texttt{0x534D414C}, requested=1, reserved=32, sequence=1. Pod \\texttt{second-16} odpowiednie wartości to 17, 48 i 2. Globale potwierdzają deltę 32 i reset." + }, + { + "id": "A8", + "status": "enabled", + "title": "PATTERNS — bump allocator z jawną granicą użycia", + "content_tex": "Append-only arena jest wartościowa dla fazowego scratch storage, gdy wszystkie obiekty mają wspólny czas życia. Nie zastępuje ogólnego malloc: brak selekcji, ponownego użycia pojedynczych luk, split, coalescing i niezależnego free." + } + ], + "flow": [ + { + "kind": "block", + "id": "task04.a1", + "title": "A1 CONTEXT · AKTYWNE — API ma celowo małą władzę", + "content_tex": "\\textbf{Zachowane materiały:} \\texttt{src/tasks/task04\\_smalloc.c}, \\texttt{src/runtime/c09\\_smalloc.c}, \\texttt{src/runtime/c09\\_smalloc.h}, \\texttt{src/runtime/c09\\_bounded\\_sbrk.c}, \\texttt{src/runtime/c09\\_bounded\\_sbrk.h}.\\par Klient może przydzielić payload i zresetować całą arenę. Nie może zwolnić jednego bloku ani przekazać modelowi wskaźnika do picolibc. \\texttt{c09\\_smalloc} pobiera surowy fragment wyłącznie przez ograniczone \\texttt{c09\\_sbrk}." + }, + { + "kind": "block", + "id": "task04.a2", + "title": "A2 STRUCTURE · AKTYWNE — 16 B metadanych bezpośrednio przed payloadem", + "content_tex": "Nagłówek ma cztery pola \\texttt{uint32\\_t}: magic, requested, reserved i sequence. Jego rozmiar wynosi 16 B. Zwrócony adres to \\texttt{header+1}; inspekcja kontrolnie cofa się o dokładnie jeden rzeczywisty nagłówek." + }, + { + "kind": "block", + "id": "task04.a3", + "title": "A3 DISPATCH · N/D", + "content_tex": "\\textbf{N/D.} smalloc, inspect, reset i c09\\_sbrk są zwykłymi wywołaniami bezpośrednimi; przykład nie zawiera callbacku, ISR ani dynamicznie wybieranej strategii." + }, + { + "kind": "block", + "id": "task04.a4", + "title": "A4 APPLICATION · AKTYWNE — geometria dwóch bloków", + "content_tex": "Żądanie 1 B daje \\texttt{align16(16+1)=32}; żądanie 17 B daje \\texttt{align16(16+17)=48}. Pierwszy payload leży 16 B od startu, drugi 48 B od startu, więc ich delta wynosi 32 B. Oba adresy są wielokrotnością 16." + }, + { + "kind": "block", + "id": "task04.a5", + "title": "A5 FLOW · AKTYWNE — size, align, reserve, header, payload", + "content_tex": "Kod odrzuca zero i przepełnienie, zaokrągla sumę nagłówka i żądania, sprawdza reprezentowalność jako \\texttt{ptrdiff\\_t}, rezerwuje cały blok jednym \\texttt{c09\\_sbrk}, zapisuje cztery pola nagłówka i dopiero wtedy zwraca payload." + }, + { + "kind": "block", + "id": "task04.a6", + "title": "A6 STATE · AKTYWNE — EMPTY, TWO BLOCKS, RESET", + "content_tex": "Arena przechodzi \\texttt{EMPTY -> seq1 -> seq1+seq2}. Brak indywidualnego free oznacza, że break tylko rośnie. \\texttt{c09\\_smalloc\\_reset} wykonuje jedno przejście z dowolnej zawartości do EMPTY i unieważnia oba wskaźniki naraz." + }, + { + "kind": "block", + "id": "task04.a7", + "title": "A7 RUNTIME · AKTYWNE — pamięć potwierdza header przed payloadem", + "content_tex": "W checkpointcie odczytaj \\texttt{first-16}: słowo magic to \\texttt{0x534D414C}, requested=1, reserved=32, sequence=1. Pod \\texttt{second-16} odpowiednie wartości to 17, 48 i 2. Globale potwierdzają deltę 32 i reset." + }, + { + "kind": "block", + "id": "task04.a8", + "title": "A8 PATTERNS · AKTYWNE — bump allocator z jawną granicą użycia", + "content_tex": "Append-only arena jest wartościowa dla fazowego scratch storage, gdy wszystkie obiekty mają wspólny czas życia. Nie zastępuje ogólnego malloc: brak selekcji, ponownego użycia pojedynczych luk, split, coalescing i niezależnego free." + }, + { + "kind": "exercise", + "id": "task04.proof", + "title": "Przewidywanie → wykonanie → wniosek", + "prompt_tex": "Dla żądań 1 B i 17 B wyprowadź rozmiar nagłówka, rezerwację po align-up, adres obu payloadów i zmianę break. Wskaż, dlaczego brak \\texttt{c09\\_sfree} jest częścią kontraktu, a reset areny nie jest odpowiednikiem \\texttt{free(pointer)}.", + "evidence_tex": "Przewidywany wynik, odczyt programu hostowego wraz z kodem powrotu, wartość obiektu wynikowego w obrazie RV32I oraz krótki wniosek wyjaśniający zgodność albo różnicę.", + "criterion": "Host i Hazard3: header=16, first=32, second=48, delta=32, aligned=1, metadata=1, append=1, reset=1, pass=1 i kod 0. Nagłówki mają sequence 1 i 2; po resecie pierwszy payload wraca pod poprzedni pierwszy adres." + }, + { + "kind": "block", + "id": "task04.worksheet", + "title": "TASK04 · Zapis dowodu ucznia", + "content_tex": "\\textbf{1. Przewidywanie przed uruchomieniem}\\par\\noindent\\dotfill\\par\\noindent\\dotfill\\par\\textbf{2. Wynik programu hostowego}\\par\\noindent\\dotfill\\par\\noindent\\dotfill\\par\\textbf{3. Wynik RV32I i kod wyjścia}\\par\\noindent\\dotfill\\par\\noindent\\dotfill\\par\\textbf{4. Wniosek: reguła języka lub kontrakt targetu potwierdzony przez pomiar}\\par\\noindent\\dotfill\\par\\noindent\\dotfill" + } + ], + "educational_requirement_refs": [ + "C09.WE01" + ], + "learning_effect_refs": [ + "C09.EN01", + "C09.EK01" + ], + "assessment_criterion_ref": "C09.KW01" + }, + "task05": { + "title": "malloc/free picolibc jako czarna skrzynka", + "uuid": "9a7174f1-efb7-5c18-afbe-1a34ee6da0b7", + "prompt_tex": "Nie zakładając formatu nagłówka libc, wypisz własności możliwe do sprawdzenia przez klienta dwóch przydziałów. Uruchom host i Hazard3, sprawdź checksum oraz mapę, a w ELF wykaż współistnienie vendorowego \\texttt{\\_sbrk} i picolibc \\texttt{sbrk}.", + "criterion": "Host i Hazard3: nonnull=1, delta_nonzero=1, checksum=4612, nonoverlap=1, aligned=1, freed=1, pass=1 i kod 0. Mapa RV32I zawiera libc_stdlib_malloc.c.o, libc_stdlib_free.c.o i libc_misc_picosbrk.c.o. ELF definiuje _sbrk, sbrk, malloc, free, __heap_start i __heap_end.", + "conclusion_tex": "", + "render_task_acceptance": false, + "viewpoints": [ + { + "id": "A1", + "status": "enabled", + "title": "CONTEXT — klient nie zna wnętrza picolibc", + "content_tex": "Kod tasku używa tylko \\texttt{malloc} i \\texttt{free}. Linker łączy picolibc z platformą przez \\texttt{sbrk} oraz symbole granic. Vendorowe \\texttt{\\_sbrk} pozostaje osobnym, nieużywanym przez malloc symbolem startu Hazard3." + }, + { + "id": "A2", + "status": "enabled", + "title": "STRUCTURE — obraz składa się z czterech warstw", + "content_tex": "ELF zawiera klienta, człony \\texttt{malloc/free}, człon \\texttt{picosbrk} i platformowy startup. Skrypt linkera dostarcza \\texttt{\\_\\_heap\\_start/\\_\\_heap\\_end}; crt0 ustawia \\texttt{gp/tp} i zeruje BSS/TBSS. Mapa pokazuje, który obiekt wniósł każdy publiczny symbol." + }, + { + "id": "A3", + "status": "unavailable", + "title": "DISPATCH", + "reason": "Klient wywołuje malloc i free bezpośrednio; badany przebieg nie przekazuje callbacku, nie obsługuje ISR i nie wybiera alokatora przez tablicę funkcji." + }, + { + "id": "A4", + "status": "enabled", + "title": "APPLICATION — kontrakt dwóch niezależnych payloadów", + "content_tex": "Program żąda 13 B i 29 B, zapisuje dwie różne sekwencje, sumuje odczytane bajty do 4612 i sprawdza rozłączność półotwartych zakresów adresów. Mierzy co najmniej 8-bajtowe wyrównanie, ale nie narzuca odległości między blokami." + }, + { + "id": "A5", + "status": "enabled", + "title": "FLOW — allocate, use, verify, release", + "content_tex": "Po dwóch udanych przydziałach kod zapisuje i natychmiast odczytuje oba zakresy, oblicza checksum i warunki adresowe, zwalnia najpierw drugi, potem pierwszy blok, ustawia \\texttt{freed=1} i zatrzymuje się w checkpointcie." + }, + { + "id": "A6", + "status": "enabled", + "title": "STATE — własność payloadu kończy się w free", + "content_tex": "Każdy wskaźnik przechodzi od braku zasobu do stanu OWNED po udanym malloc, następnie USED po zapisie i RELEASED po free. Program nie dereferencjuje wskaźnika w RELEASED i nie bada, czy następny malloc odzyska ten sam adres." + }, + { + "id": "A7", + "status": "enabled", + "title": "RUNTIME — wykonanie plus audyt ELF", + "content_tex": "Hazard3 kończy program kodem 0; globale pokazują checksum 4612, rozłączność, alignment i oba free. \\texttt{nm} musi równocześnie pokazać \\texttt{\\_sbrk} oraz \\texttt{sbrk}, a mapa trzy człony picolibc związane z malloc, free i dostawcą pamięci." + }, + { + "id": "A8", + "status": "enabled", + "title": "PATTERNS — test kontraktu bez zgadywania implementacji", + "content_tex": "Poprawny test czarnej skrzynki wymusza własności API, ale nie zależy od prywatnego nagłówka, kierunku wzrostu sterty, dokładnej delty adresów ani ponownego użycia po free. Dzięki temu pozostaje wartościowy po zmianie implementacji libc." + } + ], + "flow": [ + { + "kind": "block", + "id": "task05.a1", + "title": "A1 CONTEXT · AKTYWNE — klient nie zna wnętrza picolibc", + "content_tex": "\\textbf{Zachowane materiały:} \\texttt{src/tasks/task05\\_picolibc\\_malloc.c}, \\texttt{crt0.S}, \\texttt{link/hazard3\\_c09.ld}.\\par Kod tasku używa tylko \\texttt{malloc} i \\texttt{free}. Linker łączy picolibc z platformą przez \\texttt{sbrk} oraz symbole granic. Vendorowe \\texttt{\\_sbrk} pozostaje osobnym, nieużywanym przez malloc symbolem startu Hazard3." + }, + { + "kind": "block", + "id": "task05.a2", + "title": "A2 STRUCTURE · AKTYWNE — obraz składa się z czterech warstw", + "content_tex": "ELF zawiera klienta, człony \\texttt{malloc/free}, człon \\texttt{picosbrk} i platformowy startup. Skrypt linkera dostarcza \\texttt{\\_\\_heap\\_start/\\_\\_heap\\_end}; crt0 ustawia \\texttt{gp/tp} i zeruje BSS/TBSS. Mapa pokazuje, który obiekt wniósł każdy publiczny symbol." + }, + { + "kind": "block", + "id": "task05.a3", + "title": "A3 DISPATCH · N/D", + "content_tex": "\\textbf{N/D.} Klient wywołuje malloc i free bezpośrednio; badany przebieg nie przekazuje callbacku, nie obsługuje ISR i nie wybiera alokatora przez tablicę funkcji." + }, + { + "kind": "block", + "id": "task05.a4", + "title": "A4 APPLICATION · AKTYWNE — kontrakt dwóch niezależnych payloadów", + "content_tex": "Program żąda 13 B i 29 B, zapisuje dwie różne sekwencje, sumuje odczytane bajty do 4612 i sprawdza rozłączność półotwartych zakresów adresów. Mierzy co najmniej 8-bajtowe wyrównanie, ale nie narzuca odległości między blokami." + }, + { + "kind": "block", + "id": "task05.a5", + "title": "A5 FLOW · AKTYWNE — allocate, use, verify, release", + "content_tex": "Po dwóch udanych przydziałach kod zapisuje i natychmiast odczytuje oba zakresy, oblicza checksum i warunki adresowe, zwalnia najpierw drugi, potem pierwszy blok, ustawia \\texttt{freed=1} i zatrzymuje się w checkpointcie." + }, + { + "kind": "block", + "id": "task05.a6", + "title": "A6 STATE · AKTYWNE — własność payloadu kończy się w free", + "content_tex": "Każdy wskaźnik przechodzi od braku zasobu do stanu OWNED po udanym malloc, następnie USED po zapisie i RELEASED po free. Program nie dereferencjuje wskaźnika w RELEASED i nie bada, czy następny malloc odzyska ten sam adres." + }, + { + "kind": "block", + "id": "task05.a7", + "title": "A7 RUNTIME · AKTYWNE — wykonanie plus audyt ELF", + "content_tex": "Hazard3 kończy program kodem 0; globale pokazują checksum 4612, rozłączność, alignment i oba free. \\texttt{nm} musi równocześnie pokazać \\texttt{\\_sbrk} oraz \\texttt{sbrk}, a mapa trzy człony picolibc związane z malloc, free i dostawcą pamięci." + }, + { + "kind": "block", + "id": "task05.a8", + "title": "A8 PATTERNS · AKTYWNE — test kontraktu bez zgadywania implementacji", + "content_tex": "Poprawny test czarnej skrzynki wymusza własności API, ale nie zależy od prywatnego nagłówka, kierunku wzrostu sterty, dokładnej delty adresów ani ponownego użycia po free. Dzięki temu pozostaje wartościowy po zmianie implementacji libc." + }, + { + "kind": "exercise", + "id": "task05.proof", + "title": "Przewidywanie → wykonanie → wniosek", + "prompt_tex": "Nie zakładając formatu nagłówka libc, wypisz własności możliwe do sprawdzenia przez klienta dwóch przydziałów. Uruchom host i Hazard3, sprawdź checksum oraz mapę, a w ELF wykaż współistnienie vendorowego \\texttt{\\_sbrk} i picolibc \\texttt{sbrk}.", + "evidence_tex": "Przewidywany wynik, odczyt programu hostowego wraz z kodem powrotu, wartość obiektu wynikowego w obrazie RV32I oraz krótki wniosek wyjaśniający zgodność albo różnicę.", + "criterion": "Host i Hazard3: nonnull=1, delta_nonzero=1, checksum=4612, nonoverlap=1, aligned=1, freed=1, pass=1 i kod 0. Mapa RV32I zawiera libc_stdlib_malloc.c.o, libc_stdlib_free.c.o i libc_misc_picosbrk.c.o. ELF definiuje _sbrk, sbrk, malloc, free, __heap_start i __heap_end." + }, + { + "kind": "block", + "id": "task05.worksheet", + "title": "TASK05 · Zapis dowodu ucznia", + "content_tex": "\\textbf{1. Przewidywanie przed uruchomieniem}\\par\\noindent\\dotfill\\par\\noindent\\dotfill\\par\\textbf{2. Wynik programu hostowego}\\par\\noindent\\dotfill\\par\\noindent\\dotfill\\par\\textbf{3. Wynik RV32I i kod wyjścia}\\par\\noindent\\dotfill\\par\\noindent\\dotfill\\par\\textbf{4. Wniosek: reguła języka lub kontrakt targetu potwierdzony przez pomiar}\\par\\noindent\\dotfill\\par\\noindent\\dotfill" + } + ], + "educational_requirement_refs": [ + "C09.WE01" + ], + "learning_effect_refs": [ + "C09.EN01", + "C09.EK01" + ], + "assessment_criterion_ref": "C09.KW01" + } + }, + "tasks_order": [ + "task01", + "task02", + "task03", + "task04", + "task05" + ] +} diff --git a/json/card_spec.json b/json/card_spec.json new file mode 100644 index 0000000..64f2521 --- /dev/null +++ b/json/card_spec.json @@ -0,0 +1,366 @@ +{ + "card": { + "number": "09", + "slug": "smalloc-sbrk-libc", + "title": "smalloc, sbrk i minimalne libc", + "topic": "K&R 5.4 i 7.8: granica libc, bounded sbrk, prosty smalloc oraz malloc/free picolibc", + "status": "Gotowa", + "version": "v00.01", + "revision_date": "2026-07-20T00:00:00+02:00" + }, + "front": { + "goal": "Uczeń rozdziela wybór funkcji z archiwum libc, kontrakt dostawcy pamięci sbrk i politykę alokatora. Najpierw dowodzi, że strlen nie potrzebuje sterty, potem kontrolowanie zrywa zależność malloc do sbrk, buduje ograniczony model break i wyrównany smalloc, a na końcu traktuje prawdziwe malloc/free picolibc jako czarną skrzynkę sprawdzaną przez kontrakt.", + "scope": "Pięć zachowanych przykładów działa na hoście i RV32I tam, gdzie istnieje program uruchamialny. Task02 jest zamierzonym expected-fail linkera i nie ma obrazu runtime. W aktualnym GCC 15.2 biblioteka to picolibc: jej malloc odwołuje się do sbrk, podczas gdy vendorowy init.S Hazard3 definiuje inny symbol \\_sbrk. Własny linker ogranicza stertę symbolami \\_\\_heap\\_start i \\_\\_heap\\_end oraz rezerwuje 64 KiB stosu." + }, + "learning": { + "reasoning_label": "Trzy warstwy jednego przydziału", + "reasoning": "Uczeń wyprowadza osobno: wybór członu archiwum, wiązanie symbolu dostawcy pamięci oraz inwarianty polityki alokacji, zamiast nazywać wszystkie trzy mechanizmy stertą.", + "practice_label": "Dowód z mapy, stanu i wykonania", + "practice": "Uczeń porównuje mapę linkera, kontrolowany błąd symbolu, globalne checkpointy, wynik hosta i kod wyjścia Hazard3, a wnioski ogranicza do naprawdę zmierzonych własności.", + "criterion": "Task01: length=16, strlen.c.o obecny, człony malloc/free/picosbrk nieobecne. Task02: link kończy się niezerowo przez brak __wrap_sbrk, powstaje log, ale nie ELF. Task03: offset break 40 po wzroście, 40 po odrzuconym wzroście, 32 po skurczeniu i 32 po odrzuconym zejściu poniżej początku; granice są zachowane. Task04: header=16, rezerwacje 32 i 48, delta payloadów 32, alignment=16, kolejność append-only i reset całej areny. Task05: dwa niepuste, rozłączne i co najmniej 8-bajtowo wyrównane bloki, checksum=4612, oba free wykonane; mapa zawiera malloc/free/picosbrk, a ELF równocześnie _sbrk i sbrk. Wszystkie uruchamialne programy host i Hazard3 zwracają 0.", + "requirement": "Czytanie mapy linkera i symboli ELF, bezpieczna arytmetyka granic, wyrównanie bloków oraz rozróżnienie modelu dydaktycznego od kontraktu prawdziwej biblioteki." + }, + "sections": [ + { + "title": "1 — Funkcja z libc nie oznacza automatycznie sterty", + "content_tex": "Archiwum \\texttt{libc.a} nie jest włączane do programu w całości. Linker pobiera człon, który rozwiązuje potrzebny symbol, a następne człony tylko wtedy, gdy pojawią się kolejne nierozwiązane odwołania. Dlatego bezpośrednie wywołanie \\texttt{strlen} z opcją \\texttt{-fno-builtin} wybiera \\texttt{strlen.c.o}, lecz nie wybiera \\texttt{libc\\_stdlib\\_malloc.c.o} ani \\texttt{libc\\_misc\\_picosbrk.c.o}. Dowodem jest mapa linkera, a nie samo dołączenie nagłówka \\texttt{string.h}.\n\nTask01 rozstrzyga wyłącznie tę zależność. Nie dowodzi, że każda funkcja tekstowa jest bezkosztowa ani że całe libc nie używa pamięci dynamicznej." + }, + { + "title": "2 — malloc potrzebuje sbrk, lecz _sbrk to inna nazwa", + "content_tex": "W badanym GCC 15.2 używane jest \\textbf{picolibc}, nie newlib. Człon \\texttt{libc\\_stdlib\\_malloc.c.o} ma niezdefiniowane odwołanie do \\texttt{sbrk}. Picolibc może dostarczyć je z \\texttt{libc\\_misc\\_picosbrk.c.o}; ten kod opiera granice na symbolach linkera \\texttt{\\_\\_heap\\_start} i \\texttt{\\_\\_heap\\_end}. Z kolei \\texttt{vendor/Hazard3/.../init.S} definiuje \\texttt{\\_sbrk} z jednym podkreśleniem. Dla linkera są to dwa różne symbole, więc mogą współistnieć w Task05.\n\nTask02 używa \\texttt{--wrap=sbrk}: każde odwołanie do \\texttt{sbrk} zostaje skierowane do celowo brakującego \\texttt{\\_\\_wrap\\_sbrk}. Oczekiwany błąd jest kontrolowanym testem krawędzi \\texttt{malloc -> sbrk}, a nie awarią całego projektu." + }, + { + "title": "3 — Od alloc z K&R 5.4 do bounded sbrk i smalloc", + "content_tex": "Liniowy \\texttt{alloc} z K\\&R 5.4 przesuwa wskaźnik w stałej tablicy. Jest prosty, ale nie odzyskuje dowolnego bloku, nie wybiera najlepszego dopasowania, nie dzieli i nie scala wolnych obszarów. \\texttt{afree} może cofnąć wskaźnik jedynie do adresu należącego do areny, więc bez dyscypliny stosowej łatwo unieważnić późniejsze przydziały. Historyczna tablica bajtów nie jest też ogólną deklaracją wyrównania dla każdego typu.\n\nTask03 zachowuje istotę modelu, lecz jawnie wymusza \\texttt{heap\\_start <= brk <= heap\\_end}; odrzucona operacja nie zmienia break. Task04 dodaje 16-bajtowe wyrównanie i 16-bajtowy nagłówek bezpośrednio przed payloadem. Nadal jest to alokator append-only: nie ma \\texttt{sfree}, listy wolnych bloków, split ani coalescing. Jedyną operacją odzyskania jest reset całej areny, który unieważnia wszystkie wcześniejsze wskaźniki." + }, + { + "title": "4 — Prawdziwe malloc/free jako czarna skrzynka", + "content_tex": "Task05 nie zakłada, że picolibc ma taki sam nagłówek lub strategię jak \\texttt{c09\\_smalloc}. Program sprawdza tylko publiczny kontrakt potrzebny klientowi: dwa udane przydziały dają używalne, rozłączne obszary; zapisane bajty można odczytać; adresy spełniają mierzone wyrównanie; oba bloki są przekazane do \\texttt{free}. Nie odczytuje pamięci po \\texttt{free} i nie wymaga ponownego użycia tego samego adresu.\n\nMinimalny startup ustawia \\texttt{gp}, pojedynczą bazę TLS \\texttt{tp}, zeruje \\texttt{.tbss} i \\texttt{.bss}, a następnie wywołuje \\texttt{main}. Skrypt linkera pozostawia \\texttt{\\_\\_heap\\_end} 64 KiB przed \\texttt{\\_\\_stack\\_top} i ma \\texttt{ASSERT} zatrzymujący obraz, gdy sekcje zajmą zarezerwowany obszar." + } + ], + "tasks": [ + { + "id": "task01", + "chapter": "7.8", + "title": "strlen z libc bez sterty", + "idea_tex": "libc.a: wybór strlen.c.o", + "priority": "kluczowe", + "key": true, + "source": "src/tasks/task01_libc_without_heap.c", + "prompt_tex": "Przed linkowaniem przewidź, które człony \\texttt{libc.a} są potrzebne przez bezpośrednie \\texttt{strlen}. Uruchom program, a potem w mapie udowodnij obecność \\texttt{strlen.c.o} i nieobecność członów malloc, free oraz picosbrk.", + "criterion": "Host i Hazard3: length=16, pass=1, kod 0. Mapa RV32I zawiera libc.a(strlen.c.o), ale nie zawiera libc_stdlib_malloc.c.o, libc_stdlib_free.c.o ani libc_misc_picosbrk.c.o.", + "viewpoints": [ + { + "id": "A1", + "status": "enabled", + "title": "CONTEXT — klient, archiwum i brak dostawcy pamięci", + "content_tex": "Klient wywołuje publiczne \\texttt{strlen}. Granicą systemu jest linker wybierający potrzebny człon \\texttt{libc.a}; Task01 nie deklaruje ani nie wywołuje \\texttt{malloc}, \\texttt{free} lub \\texttt{sbrk}." + }, + { + "id": "A2", + "status": "enabled", + "title": "STRUCTURE — jedna krawędź symboliczna", + "content_tex": "Przy \\texttt{-fno-builtin} obiekt tasku zachowuje niezdefiniowany symbol \\texttt{strlen}. Linker rozwiązuje go przez \\texttt{strlen.c.o}. Ten człon nie tworzy następnej krawędzi do alokatora, dlatego graf zależności kończy się bez warstwy sterty." + }, + { + "id": "A3", + "status": "unavailable", + "title": "DISPATCH", + "reason": "strlen i checkpoint są wywołaniami bezpośrednimi; program nie ma callbacku, ISR, wskaźnika funkcji ani dynamicznego wyboru implementacji." + }, + { + "id": "A4", + "status": "enabled", + "title": "APPLICATION — dwa niezależne warunki sukcesu", + "content_tex": "Warunek wykonania to długość 16 dla napisu \\texttt{picolibc-no-heap}. Warunek obrazu to obecność wyłącznie potrzebnego członu tekstowego i brak trzech nazw członów związanych z przydziałem. Sam kod wyjścia nie zastępuje kontroli mapy." + }, + { + "id": "A5", + "status": "enabled", + "title": "FLOW — kompilacja, selekcja archiwum, wywołanie", + "content_tex": "Kompilator pozostawia call do \\texttt{strlen}; linker przegląda archiwum i pobiera \\texttt{strlen.c.o}; startup uruchamia \\texttt{main}; funkcja oblicza 16; checkpoint publikuje wynik; \\texttt{main} zwraca 0. Każdy etap ma inny artefakt dowodowy." + }, + { + "id": "A6", + "status": "unavailable", + "title": "STATE", + "reason": "Program wykonuje jednorazowy, czysty pomiar długości i nie ma domenowego obiektu przechodzącego przez istotne stany ani zasobu o cyklu życia." + }, + { + "id": "A7", + "status": "enabled", + "title": "RUNTIME — global i mapa odpowiadają na inne pytania", + "content_tex": "W \\texttt{task01\\_debug\\_checkpoint} global \\texttt{g\\_task01\\_length} ma wartość 16, a \\texttt{g\\_task01\\_pass} wartość 1. Osobno \\texttt{prog.map} wskazuje \\texttt{libc.a(strlen.c.o)}; test mapy odrzuca każdą nazwę członu heap." + }, + { + "id": "A8", + "status": "enabled", + "title": "PATTERNS — płać za osiągalne symbole, nie za nagłówek", + "content_tex": "Dla archiwum statycznego właściwym wzorcem audytu jest śledzenie nierozwiązanych symboli i pobranych członów. \\texttt{\\#include } dostarcza deklarację; nie jest poleceniem dołączenia całej implementacji libc." + } + ] + }, + { + "id": "task02", + "chapter": "5.4 + ABI", + "title": "Kontrolowany brak dostawcy sbrk", + "idea_tex": "expected-fail: malloc -> sbrk", + "priority": "kluczowe", + "key": true, + "source": "src/tasks/task02_malloc_requires_sbrk.c", + "prompt_tex": "Narysuj łańcuch \\texttt{main -> malloc -> sbrk}. Następnie uruchom \\texttt{make expected-fail} i wyjaśnij, dlaczego \\texttt{--wrap=sbrk} zmienia ostatnią krawędź na \\texttt{\\_\\_wrap\\_sbrk}, dlaczego brak ELF jest wynikiem poprawnym oraz czego ten test nie mówi o runtime.", + "evidence_tex": "Przewidywana brakująca nazwa, status kompilacji obiektu, niezerowy status linkera, cytat dwóch sygnatur z logu oraz sprawdzenie, że końcowy ELF nie istnieje.", + "worksheet_step2": "Wynik kompilacji task.o", + "worksheet_step3": "Status i sygnatury błędu linkera", + "criterion": "Kompilacja task.o kończy się sukcesem. Link ma niezerowy status, log wymienia libc_stdlib_malloc.c.o i undefined reference to __wrap_sbrk, a must-not-exist.elf nie istnieje. Nie wykonuje się testu host ani Hazard3.", + "viewpoints": [ + { + "id": "A1", + "status": "enabled", + "title": "CONTEXT — kontrolowane przecięcie granicy platformy", + "content_tex": "Kod klienta żąda 16 B przez \\texttt{malloc}. Opcja linkera przechwytuje wyłącznie symbol dostawcy pamięci, dzięki czemu testuje granicę libc--platforma bez usuwania lub modyfikowania systemowego archiwum." + }, + { + "id": "A2", + "status": "enabled", + "title": "STRUCTURE — caller, człon malloc i brakujący wrapper", + "content_tex": "Obiekt tasku wnosi odwołanie do \\texttt{malloc}; linker pobiera \\texttt{libc\\_stdlib\\_malloc.c.o}. Jego odwołania do \\texttt{sbrk} są przez \\texttt{--wrap} przepisywane na \\texttt{\\_\\_wrap\\_sbrk}. Żaden obiekt celowo nie definiuje tej ostatniej nazwy." + }, + { + "id": "A3", + "status": "unavailable", + "title": "DISPATCH", + "reason": "Wywołanie malloc jest bezpośrednie, a --wrap jest transformacją nazw podczas linkowania, nie mechanizmem callbacku, ISR ani dynamicznego dispatchu w programie." + }, + { + "id": "A4", + "status": "enabled", + "title": "APPLICATION — porażka ma precyzyjną sygnaturę", + "content_tex": "Sukces testu oznacza jednocześnie: obiekt C powstał, link zwrócił status różny od zera, diagnostyka zawiera \\texttt{\\_\\_wrap\\_sbrk} oraz nazwę członu malloc, a końcowy ELF nie istnieje. Inny błąd linkera nie spełnia kryterium." + }, + { + "id": "A5", + "status": "enabled", + "title": "FLOW — expected-fail jako kontrolowany przebieg", + "content_tex": "Skrypt usuwa stary artefakt, kompiluje task, uruchamia link w trybie dopuszczającym błąd, zapisuje status i log, po czym przywraca rygor \\texttt{set -e}. Dopiero cztery asercje zamieniają oczekiwaną porażkę programu w sukces testu." + }, + { + "id": "A6", + "status": "unavailable", + "title": "STATE", + "reason": "Linkowanie kończy się przed utworzeniem obrazu wykonywalnego, więc nie istnieje runtime, breakpoint ani obiekt domenowy zmieniający stan w czasie wykonania." + }, + { + "id": "A7", + "status": "enabled", + "title": "RUNTIME — dowodem jest diagnostyka przed runtime", + "content_tex": "Odczytaj \\texttt{expected-link-failure.log}: cztery relokacje z \\texttt{libc\\_stdlib\\_malloc.c.o} wskazują brak \\texttt{\\_\\_wrap\\_sbrk}. Następnie sprawdź nieobecność \\texttt{must-not-exist.elf}; nie wolno wymyślać wartości runtime dla nieistniejącego programu." + }, + { + "id": "A8", + "status": "enabled", + "title": "PATTERNS — test negatywny musi odrzucać zły powód", + "content_tex": "Wzorzec expected-fail wymaga konkretnej sygnatury błędu i braku produktu końcowego. Sam warunek „polecenie nie przeszło” byłby za słaby, bo zaliczyłby literówkę, brak kompilatora lub błędny skrypt linkera." + } + ] + }, + { + "id": "task03", + "chapter": "5.4", + "title": "Bounded sbrk i atomowy błąd", + "idea_tex": "ograniczony break i atomowy błąd", + "priority": "kluczowe", + "key": true, + "sources": [ + "src/tasks/task03_bounded_sbrk.c", + "src/runtime/c09_bounded_sbrk.c", + "src/runtime/c09_bounded_sbrk.h", + "link/hazard3_c09.ld" + ], + "prompt_tex": "Zapisz stan break po sekwencji \\texttt{+16,+24,fail,-8,fail}. Dla obu porażek wskaż sprawdzaną granicę i udowodnij, że zwrot \\texttt{(void *)-1} nie zmienia break. Porównaj stałe offsety hosta i RV32I.", + "criterion": "Host i Hazard3: grow=40, rejected_grow=40, shrink=32, rejected_shrink=32, preserved=1, bounds=1, pass=1 i kod 0. Linker: __heap_start oraz __heap_end są wyrównane do 16 B, __heap_end == __stack_bottom.", + "viewpoints": [ + { + "id": "A1", + "status": "enabled", + "title": "CONTEXT — model oddzielony od libc", + "content_tex": "Task03 eksportuje nazwę \\texttt{c09\\_sbrk}, aby nie przejąć symbolu \\texttt{sbrk} picolibc. Na hoście granice obejmują statyczną arenę 512 B; na RV32I pochodzą z linkera. Ten sam algorytm widzi tylko trzy adresy." + }, + { + "id": "A2", + "status": "enabled", + "title": "STRUCTURE — start, break i end", + "content_tex": "Stan ma jedną zmienną \\texttt{g\\_c09\\_break} oraz niezmienne granice \\texttt{start} i \\texttt{end}. Każdy poprawny stan spełnia \\texttt{start <= break <= end}; wolny obszar ma rozmiar \\texttt{end-break}, a zajęty prefiks \\texttt{break-start}." + }, + { + "id": "A3", + "status": "unavailable", + "title": "DISPATCH", + "reason": "Wszystkie operacje c09_sbrk i gettery są wywoływane bezpośrednio; nie ma callbacku, ISR, tablicy funkcji ani wyboru implementacji w runtime." + }, + { + "id": "A4", + "status": "enabled", + "title": "APPLICATION — tabela pięciu przejść", + "content_tex": "Od offsetu 0 operacje dają kolejno: \\texttt{+16 -> 16}, \\texttt{+24 -> 40}, zbyt duży wzrost \\texttt{-> 40}, \\texttt{-8 -> 32}, zejście o 33 \\texttt{-> 32}. Udany call zwraca stary break; porażka zwraca wszystkie bity ustawione." + }, + { + "id": "A5", + "status": "enabled", + "title": "FLOW — najpierw zakres, potem commit", + "content_tex": "Dla wzrostu kod porównuje wielkość z \\texttt{end-current}; dla spadku oblicza bezpiecznie moduł także dla \\texttt{PTRDIFF\\_MIN} i porównuje go z \\texttt{current-start}. Dopiero po zaliczeniu warunku zapisuje \\texttt{g\\_c09\\_break=next}." + }, + { + "id": "A6", + "status": "enabled", + "title": "STATE — VALID pozostaje VALID także po odrzuceniu", + "content_tex": "Break przechodzi przez offsety \\texttt{0 -> 16 -> 40 -> 40 -> 32 -> 32}. Obie porażki są samopętlą stanu: zmienia się wynik operacji, ale nie break. Nie ma przejścia do wartości poniżej start ani powyżej end." + }, + { + "id": "A7", + "status": "enabled", + "title": "RUNTIME — offsety zamiast niestabilnych adresów", + "content_tex": "Checkpoint publikuje cztery offsety \\texttt{40,40,32,32} oraz flagi \\texttt{preserved=1} i \\texttt{bounds=1}. Adresy bezwzględne hosta mogą się zmieniać przez ASLR, dlatego dowód porównuje różnice względem startu." + }, + { + "id": "A8", + "status": "enabled", + "title": "PATTERNS — validate then commit", + "content_tex": "Wzorzec silnej gwarancji błędu brzmi: najpierw policz bez przepełnienia, następnie sprawdź granice, a dopiero potem zmień jedyny stan. Wskaźnik break pozostaje obserwowalnie niezmieniony po odrzuconej operacji." + } + ] + }, + { + "id": "task04", + "chapter": "5.4", + "title": "Wyrównany smalloc append-only", + "idea_tex": "nagłówek, alignment i reset areny", + "priority": "kluczowe", + "key": true, + "sources": [ + "src/tasks/task04_smalloc.c", + "src/runtime/c09_smalloc.c", + "src/runtime/c09_smalloc.h", + "src/runtime/c09_bounded_sbrk.c", + "src/runtime/c09_bounded_sbrk.h" + ], + "prompt_tex": "Dla żądań 1 B i 17 B wyprowadź rozmiar nagłówka, rezerwację po align-up, adres obu payloadów i zmianę break. Wskaż, dlaczego brak \\texttt{c09\\_sfree} jest częścią kontraktu, a reset areny nie jest odpowiednikiem \\texttt{free(pointer)}.", + "criterion": "Host i Hazard3: header=16, first=32, second=48, delta=32, aligned=1, metadata=1, append=1, reset=1, pass=1 i kod 0. Nagłówki mają sequence 1 i 2; po resecie pierwszy payload wraca pod poprzedni pierwszy adres.", + "viewpoints": [ + { + "id": "A1", + "status": "enabled", + "title": "CONTEXT — API ma celowo małą władzę", + "content_tex": "Klient może przydzielić payload i zresetować całą arenę. Nie może zwolnić jednego bloku ani przekazać modelowi wskaźnika do picolibc. \\texttt{c09\\_smalloc} pobiera surowy fragment wyłącznie przez ograniczone \\texttt{c09\\_sbrk}." + }, + { + "id": "A2", + "status": "enabled", + "title": "STRUCTURE — 16 B metadanych bezpośrednio przed payloadem", + "content_tex": "Nagłówek ma cztery pola \\texttt{uint32\\_t}: magic, requested, reserved i sequence. Jego rozmiar wynosi 16 B. Zwrócony adres to \\texttt{header+1}; inspekcja kontrolnie cofa się o dokładnie jeden rzeczywisty nagłówek." + }, + { + "id": "A3", + "status": "unavailable", + "title": "DISPATCH", + "reason": "smalloc, inspect, reset i c09_sbrk są zwykłymi wywołaniami bezpośrednimi; przykład nie zawiera callbacku, ISR ani dynamicznie wybieranej strategii." + }, + { + "id": "A4", + "status": "enabled", + "title": "APPLICATION — geometria dwóch bloków", + "content_tex": "Żądanie 1 B daje \\texttt{align16(16+1)=32}; żądanie 17 B daje \\texttt{align16(16+17)=48}. Pierwszy payload leży 16 B od startu, drugi 48 B od startu, więc ich delta wynosi 32 B. Oba adresy są wielokrotnością 16." + }, + { + "id": "A5", + "status": "enabled", + "title": "FLOW — size, align, reserve, header, payload", + "content_tex": "Kod odrzuca zero i przepełnienie, zaokrągla sumę nagłówka i żądania, sprawdza reprezentowalność jako \\texttt{ptrdiff\\_t}, rezerwuje cały blok jednym \\texttt{c09\\_sbrk}, zapisuje cztery pola nagłówka i dopiero wtedy zwraca payload." + }, + { + "id": "A6", + "status": "enabled", + "title": "STATE — EMPTY, TWO BLOCKS, RESET", + "content_tex": "Arena przechodzi \\texttt{EMPTY -> seq1 -> seq1+seq2}. Brak indywidualnego free oznacza, że break tylko rośnie. \\texttt{c09\\_smalloc\\_reset} wykonuje jedno przejście z dowolnej zawartości do EMPTY i unieważnia oba wskaźniki naraz." + }, + { + "id": "A7", + "status": "enabled", + "title": "RUNTIME — pamięć potwierdza header przed payloadem", + "content_tex": "W checkpointcie odczytaj \\texttt{first-16}: słowo magic to \\texttt{0x534D414C}, requested=1, reserved=32, sequence=1. Pod \\texttt{second-16} odpowiednie wartości to 17, 48 i 2. Globale potwierdzają deltę 32 i reset." + }, + { + "id": "A8", + "status": "enabled", + "title": "PATTERNS — bump allocator z jawną granicą użycia", + "content_tex": "Append-only arena jest wartościowa dla fazowego scratch storage, gdy wszystkie obiekty mają wspólny czas życia. Nie zastępuje ogólnego malloc: brak selekcji, ponownego użycia pojedynczych luk, split, coalescing i niezależnego free." + } + ] + }, + { + "id": "task05", + "chapter": "7.8 + ABI", + "title": "malloc/free picolibc jako czarna skrzynka", + "idea_tex": "malloc/free picolibc jako black box", + "priority": "kluczowe", + "key": true, + "sources": [ + "src/tasks/task05_picolibc_malloc.c", + "crt0.S", + "link/hazard3_c09.ld" + ], + "prompt_tex": "Nie zakładając formatu nagłówka libc, wypisz własności możliwe do sprawdzenia przez klienta dwóch przydziałów. Uruchom host i Hazard3, sprawdź checksum oraz mapę, a w ELF wykaż współistnienie vendorowego \\texttt{\\_sbrk} i picolibc \\texttt{sbrk}.", + "criterion": "Host i Hazard3: nonnull=1, delta_nonzero=1, checksum=4612, nonoverlap=1, aligned=1, freed=1, pass=1 i kod 0. Mapa RV32I zawiera libc_stdlib_malloc.c.o, libc_stdlib_free.c.o i libc_misc_picosbrk.c.o. ELF definiuje _sbrk, sbrk, malloc, free, __heap_start i __heap_end.", + "viewpoints": [ + { + "id": "A1", + "status": "enabled", + "title": "CONTEXT — klient nie zna wnętrza picolibc", + "content_tex": "Kod tasku używa tylko \\texttt{malloc} i \\texttt{free}. Linker łączy picolibc z platformą przez \\texttt{sbrk} oraz symbole granic. Vendorowe \\texttt{\\_sbrk} pozostaje osobnym, nieużywanym przez malloc symbolem startu Hazard3." + }, + { + "id": "A2", + "status": "enabled", + "title": "STRUCTURE — obraz składa się z czterech warstw", + "content_tex": "ELF zawiera klienta, człony \\texttt{malloc/free}, człon \\texttt{picosbrk} i platformowy startup. Skrypt linkera dostarcza \\texttt{\\_\\_heap\\_start/\\_\\_heap\\_end}; crt0 ustawia \\texttt{gp/tp} i zeruje BSS/TBSS. Mapa pokazuje, który obiekt wniósł każdy publiczny symbol." + }, + { + "id": "A3", + "status": "unavailable", + "title": "DISPATCH", + "reason": "Klient wywołuje malloc i free bezpośrednio; badany przebieg nie przekazuje callbacku, nie obsługuje ISR i nie wybiera alokatora przez tablicę funkcji." + }, + { + "id": "A4", + "status": "enabled", + "title": "APPLICATION — kontrakt dwóch niezależnych payloadów", + "content_tex": "Program żąda 13 B i 29 B, zapisuje dwie różne sekwencje, sumuje odczytane bajty do 4612 i sprawdza rozłączność półotwartych zakresów adresów. Mierzy co najmniej 8-bajtowe wyrównanie, ale nie narzuca odległości między blokami." + }, + { + "id": "A5", + "status": "enabled", + "title": "FLOW — allocate, use, verify, release", + "content_tex": "Po dwóch udanych przydziałach kod zapisuje i natychmiast odczytuje oba zakresy, oblicza checksum i warunki adresowe, zwalnia najpierw drugi, potem pierwszy blok, ustawia \\texttt{freed=1} i zatrzymuje się w checkpointcie." + }, + { + "id": "A6", + "status": "enabled", + "title": "STATE — własność payloadu kończy się w free", + "content_tex": "Każdy wskaźnik przechodzi od braku zasobu do stanu OWNED po udanym malloc, następnie USED po zapisie i RELEASED po free. Program nie dereferencjuje wskaźnika w RELEASED i nie bada, czy następny malloc odzyska ten sam adres." + }, + { + "id": "A7", + "status": "enabled", + "title": "RUNTIME — wykonanie plus audyt ELF", + "content_tex": "Hazard3 kończy program kodem 0; globale pokazują checksum 4612, rozłączność, alignment i oba free. \\texttt{nm} musi równocześnie pokazać \\texttt{\\_sbrk} oraz \\texttt{sbrk}, a mapa trzy człony picolibc związane z malloc, free i dostawcą pamięci." + }, + { + "id": "A8", + "status": "enabled", + "title": "PATTERNS — test kontraktu bez zgadywania implementacji", + "content_tex": "Poprawny test czarnej skrzynki wymusza własności API, ale nie zależy od prywatnego nagłówka, kierunku wzrostu sterty, dokładnej delty adresów ani ponownego użycia po free. Dzięki temu pozostaje wartościowy po zmianie implementacji libc." + } + ] + } + ] +} diff --git a/link/hazard3_c09.ld b/link/hazard3_c09.ld new file mode 100644 index 0000000..2fb29d7 --- /dev/null +++ b/link/hazard3_c09.ld @@ -0,0 +1,93 @@ +OUTPUT_FORMAT("elf32-littleriscv") +OUTPUT_ARCH(riscv) +ENTRY(_start) + +MEMORY +{ + RAM (rwx) : ORIGIN = 0x80000000, LENGTH = 16M +} + +PHDRS +{ + text PT_LOAD FLAGS(5); /* read + execute */ + data PT_LOAD FLAGS(6); /* read + write */ + tls PT_TLS FLAGS(4); /* TLS template */ +} + +SECTIONS +{ + . = ORIGIN(RAM); + + .text : ALIGN(4) + { + KEEP(*(.vectors)) + *(.text.startup .text.startup.*) + *(.text .text.*) + } > RAM :text + + .rodata : ALIGN(4) + { + *(.rodata .rodata.*) + } > RAM :text + + .data : ALIGN(16) + { + __data_start = .; + *(.data .data.*) + *(.sdata .sdata.*) + __data_end = .; + } > RAM :data + + .tdata : ALIGN(16) + { + __tls_start = .; + *(.tdata .tdata.* .gnu.linkonce.td.*) + __tdata_end = .; + } > RAM :data :tls + + .tbss (NOLOAD) : ALIGN(16) + { + __tbss_start = .; + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon) + __tbss_end = .; + } > RAM :data :tls + + /* GNU ld does not advance the normal location counter for TLS NOBITS. */ + .tbss_space (NOLOAD) : ALIGN(16) + { + . = ADDR(.tbss) + SIZEOF(.tbss); + } > RAM :data + + .bss (NOLOAD) : ALIGN(16) + { + __bss_start = .; + *(.bss .bss.* COMMON) + *(.sbss .sbss.*) + __bss_end = .; + } > RAM :data + + . = ALIGN(16); + __heap_start = .; + _end = __heap_start; + PROVIDE(end = __heap_start); + + __stack_top = ORIGIN(RAM) + LENGTH(RAM); + __stack_reserve = 64K; + __stack_bottom = __stack_top - __stack_reserve; + __heap_end = __stack_bottom; + __global_pointer$ = __data_start + 0x800; + + /DISCARD/ : + { + *(.comment) + *(.note .note.*) + } +} + +ASSERT(__heap_start <= __heap_end, + "C09: heap overlaps the reserved 64 KiB stack") +ASSERT((__heap_start & 15) == 0, + "C09: __heap_start must be 16-byte aligned") +ASSERT((__heap_end & 15) == 0, + "C09: __heap_end must be 16-byte aligned") diff --git a/scripts/build_new_card.sh b/scripts/build_new_card.sh new file mode 100755 index 0000000..025f724 --- /dev/null +++ b/scripts/build_new_card.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env sh +set -eu + +script_dir=$(CDPATH= cd "$(dirname "$0")" && pwd) +repo_root=$(CDPATH= cd "$script_dir/.." && pwd) +layouts_root=$repo_root/../../../tools/card-layouts + +python3 "$layouts_root/tools/build_kr_c_card.py" "$repo_root" +exec "$script_dir/render_card_layouts.sh" diff --git a/scripts/render_card_layouts.sh b/scripts/render_card_layouts.sh new file mode 100755 index 0000000..3a5cdae --- /dev/null +++ b/scripts/render_card_layouts.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env sh +set -eu + +script_dir=$(CDPATH= cd "$(dirname "$0")" && pwd) +repo_root=$(CDPATH= cd "$script_dir/.." && pwd) +layouts_root=$repo_root/../../../tools/card-layouts + +exec python3 "$layouts_root/tools/render_card.py" "$repo_root" "$@" + diff --git a/scripts/render_new_pdf.sh b/scripts/render_new_pdf.sh new file mode 100755 index 0000000..f17b6b9 --- /dev/null +++ b/scripts/render_new_pdf.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env sh +set -eu + +script_dir=$(CDPATH= cd "$(dirname "$0")" && pwd) +repo_root=$(CDPATH= cd "$script_dir/.." && pwd) +layouts_root=$repo_root/../../../tools/card-layouts + +: "${GITEA_SHA:=0000000000000000000000000000000000000000}" +export GITEA_SHA +exec "$layouts_root/tools/render_card_pdf_preserving.sh" "$repo_root" + diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh new file mode 100755 index 0000000..c603363 --- /dev/null +++ b/scripts/run_tests.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env sh +set -eu + +script_dir=$(CDPATH= cd "$(dirname "$0")" && pwd) +repo_root=$(CDPATH= cd "$script_dir/.." && pwd) + +exec make -C "$repo_root" full-check + diff --git a/src/runtime/c09_bounded_sbrk.c b/src/runtime/c09_bounded_sbrk.c new file mode 100644 index 0000000..e2dd2f7 --- /dev/null +++ b/src/runtime/c09_bounded_sbrk.c @@ -0,0 +1,81 @@ +#include "c09_bounded_sbrk.h" + +#if defined(C09_HOST) +enum { C09_HOST_ARENA_BYTES = 512 }; + +static _Alignas(16) unsigned char g_c09_host_arena[C09_HOST_ARENA_BYTES]; +#else +extern unsigned char __heap_start[]; +extern unsigned char __heap_end[]; +#endif + +static uintptr_t g_c09_break; + +static uintptr_t arena_start(void) +{ +#if defined(C09_HOST) + return (uintptr_t)&g_c09_host_arena[0]; +#else + return (uintptr_t)__heap_start; +#endif +} + +static uintptr_t arena_end(void) +{ +#if defined(C09_HOST) + return (uintptr_t)&g_c09_host_arena[C09_HOST_ARENA_BYTES]; +#else + return (uintptr_t)__heap_end; +#endif +} + +void c09_sbrk_reset(void) +{ + g_c09_break = arena_start(); +} + +uintptr_t c09_sbrk_start_address(void) +{ + return arena_start(); +} + +uintptr_t c09_sbrk_end_address(void) +{ + return arena_end(); +} + +uintptr_t c09_sbrk_current_address(void) +{ + return g_c09_break == 0U ? arena_start() : g_c09_break; +} + +void *c09_sbrk(ptrdiff_t increment) +{ + const uintptr_t start = arena_start(); + const uintptr_t end = arena_end(); + const uintptr_t current = c09_sbrk_current_address(); + uintptr_t magnitude; + uintptr_t next; + + if (current < start || current > end) { + return (void *)(uintptr_t)-1; + } + + if (increment >= 0) { + magnitude = (uintptr_t)increment; + if (magnitude > end - current) { + return (void *)(uintptr_t)-1; + } + next = current + magnitude; + } else { + /* This form is defined even for PTRDIFF_MIN. */ + magnitude = (uintptr_t)(-(increment + 1)) + 1U; + if (magnitude > current - start) { + return (void *)(uintptr_t)-1; + } + next = current - magnitude; + } + + g_c09_break = next; + return (void *)current; +} diff --git a/src/runtime/c09_bounded_sbrk.h b/src/runtime/c09_bounded_sbrk.h new file mode 100644 index 0000000..e05b8cc --- /dev/null +++ b/src/runtime/c09_bounded_sbrk.h @@ -0,0 +1,18 @@ +#ifndef C09_BOUNDED_SBRK_H +#define C09_BOUNDED_SBRK_H + +#include +#include + +/* + * Model used by Task03 and Task04. Its name is deliberately not `sbrk`: + * Task05 must resolve the real picolibc symbol from libc.a. + */ +void c09_sbrk_reset(void); +void *c09_sbrk(ptrdiff_t increment); +uintptr_t c09_sbrk_start_address(void); +uintptr_t c09_sbrk_end_address(void); +uintptr_t c09_sbrk_current_address(void); + +#endif + diff --git a/src/runtime/c09_smalloc.c b/src/runtime/c09_smalloc.c new file mode 100644 index 0000000..2b6a55b --- /dev/null +++ b/src/runtime/c09_smalloc.c @@ -0,0 +1,83 @@ +#include "c09_smalloc.h" + +#include "c09_bounded_sbrk.h" + +typedef struct { + uint32_t magic; + uint32_t requested_bytes; + uint32_t reserved_bytes; + uint32_t sequence; +} C09SmallocHeader; + +typedef char c09_header_must_be_sixteen_bytes[ + sizeof(C09SmallocHeader) == C09_SMALLOC_HEADER_BYTES ? 1 : -1 +]; + +static uint32_t g_c09_sequence; + +static int aligned_total(size_t requested_bytes, size_t *result) +{ + const size_t header_bytes = sizeof(C09SmallocHeader); + const size_t mask = C09_SMALLOC_ALIGNMENT - 1U; + size_t unaligned; + + if (requested_bytes == 0U || requested_bytes > UINT32_MAX || + requested_bytes > (size_t)-1 - header_bytes) { + return 0; + } + unaligned = header_bytes + requested_bytes; + if (unaligned > (size_t)-1 - mask) { + return 0; + } + *result = (unaligned + mask) & ~mask; + return 1; +} + +void c09_smalloc_reset(void) +{ + c09_sbrk_reset(); + g_c09_sequence = 0U; +} + +void *c09_smalloc(size_t requested_bytes) +{ + C09SmallocHeader *header; + size_t reserved_bytes; + + if (!aligned_total(requested_bytes, &reserved_bytes) || + reserved_bytes > UINT32_MAX || reserved_bytes > (size_t)PTRDIFF_MAX) { + return (void *)0; + } + + header = (C09SmallocHeader *)c09_sbrk((ptrdiff_t)reserved_bytes); + if (header == (void *)(uintptr_t)-1) { + return (void *)0; + } + + header->magic = C09_SMALLOC_MAGIC; + header->requested_bytes = (uint32_t)requested_bytes; + header->reserved_bytes = (uint32_t)reserved_bytes; + header->sequence = ++g_c09_sequence; + return (void *)(header + 1); +} + +int c09_smalloc_inspect(const void *payload, C09SmallocInfo *result) +{ + const C09SmallocHeader *header; + + if (payload == (const void *)0 || result == (C09SmallocInfo *)0) { + return 0; + } + header = ((const C09SmallocHeader *)payload) - 1; + if (header->magic != C09_SMALLOC_MAGIC || + header->reserved_bytes < sizeof(C09SmallocHeader) || + (header->reserved_bytes % C09_SMALLOC_ALIGNMENT) != 0U) { + return 0; + } + + result->magic = header->magic; + result->requested_bytes = header->requested_bytes; + result->reserved_bytes = header->reserved_bytes; + result->sequence = header->sequence; + return 1; +} diff --git a/src/runtime/c09_smalloc.h b/src/runtime/c09_smalloc.h new file mode 100644 index 0000000..d89073b --- /dev/null +++ b/src/runtime/c09_smalloc.h @@ -0,0 +1,24 @@ +#ifndef C09_SMALLOC_H +#define C09_SMALLOC_H + +#include +#include + +enum { + C09_SMALLOC_ALIGNMENT = 16, + C09_SMALLOC_HEADER_BYTES = 16, + C09_SMALLOC_MAGIC = 0x534D414CU +}; + +typedef struct { + uint32_t magic; + uint32_t requested_bytes; + uint32_t reserved_bytes; + uint32_t sequence; +} C09SmallocInfo; + +void c09_smalloc_reset(void); +void *c09_smalloc(size_t requested_bytes); +int c09_smalloc_inspect(const void *payload, C09SmallocInfo *result); + +#endif diff --git a/src/tasks/task01_libc_without_heap.c b/src/tasks/task01_libc_without_heap.c new file mode 100644 index 0000000..2871044 --- /dev/null +++ b/src/tasks/task01_libc_without_heap.c @@ -0,0 +1,31 @@ +#include +#include + +#if defined(HOST_PRINTF) +#include +#endif + +char g_task01_text[] = "picolibc-no-heap"; +volatile size_t g_task01_length; +volatile int g_task01_pass; + +__attribute__((noinline)) void task01_debug_checkpoint(void) +{ +#if defined(__GNUC__) + __asm__ volatile("" ::: "memory"); +#endif +} + +int main(void) +{ + /* -fno-builtin makes this a real archive call, visible in prog.map. */ + g_task01_length = strlen(g_task01_text); + g_task01_pass = g_task01_length == 16U; + + task01_debug_checkpoint(); + +#if defined(HOST_PRINTF) + printf("length=%zu pass=%d\n", g_task01_length, g_task01_pass); +#endif + return g_task01_pass ? 0 : 1; +} diff --git a/src/tasks/task02_malloc_requires_sbrk.c b/src/tasks/task02_malloc_requires_sbrk.c new file mode 100644 index 0000000..36ca304 --- /dev/null +++ b/src/tasks/task02_malloc_requires_sbrk.c @@ -0,0 +1,12 @@ +#include +#include + +volatile void *g_task02_result; + +int main(void) +{ + /* This source is compiled, then deliberately linked with --wrap=sbrk. */ + g_task02_result = malloc(16U); + return g_task02_result == (void *)0; +} + diff --git a/src/tasks/task03_bounded_sbrk.c b/src/tasks/task03_bounded_sbrk.c new file mode 100644 index 0000000..64504fd --- /dev/null +++ b/src/tasks/task03_bounded_sbrk.c @@ -0,0 +1,93 @@ +#include +#include + +#include "c09_bounded_sbrk.h" + +#if defined(HOST_PRINTF) +#include +#endif + +volatile size_t g_task03_after_grow; +volatile size_t g_task03_after_failed_grow; +volatile size_t g_task03_after_shrink; +volatile size_t g_task03_after_failed_shrink; +volatile int g_task03_failures_preserve_break; +volatile int g_task03_bounds_hold; +volatile int g_task03_pass; + +__attribute__((noinline)) void task03_debug_checkpoint(void) +{ +#if defined(__GNUC__) + __asm__ volatile("" ::: "memory"); +#endif +} + +int main(void) +{ + const uintptr_t failed = (uintptr_t)-1; + uintptr_t start; + uintptr_t end; + uintptr_t before_failure; + uintptr_t before_underflow; + uintptr_t current; + size_t remaining; + size_t used; + void *first; + void *second; + void *rejected_grow; + void *old_break; + void *rejected_shrink; + + c09_sbrk_reset(); + start = c09_sbrk_start_address(); + end = c09_sbrk_end_address(); + + first = c09_sbrk(16); + second = c09_sbrk(24); + current = c09_sbrk_current_address(); + g_task03_after_grow = (size_t)(current - start); + + remaining = (size_t)(end - current); + before_failure = current; + rejected_grow = c09_sbrk((ptrdiff_t)(remaining + 1U)); + current = c09_sbrk_current_address(); + g_task03_after_failed_grow = (size_t)(current - start); + + old_break = c09_sbrk(-8); + current = c09_sbrk_current_address(); + g_task03_after_shrink = (size_t)(current - start); + + used = (size_t)(current - start); + before_underflow = current; + rejected_shrink = c09_sbrk(-(ptrdiff_t)(used + 1U)); + current = c09_sbrk_current_address(); + g_task03_after_failed_shrink = (size_t)(current - start); + + g_task03_failures_preserve_break = + (uintptr_t)rejected_grow == failed && + g_task03_after_failed_grow == (size_t)(before_failure - start) && + (uintptr_t)rejected_shrink == failed && + g_task03_after_failed_shrink == (size_t)(before_underflow - start); + g_task03_bounds_hold = start <= current && current <= end; + g_task03_pass = + (uintptr_t)first == start && + (uintptr_t)second == start + 16U && + (uintptr_t)old_break == start + 40U && + g_task03_after_grow == 40U && + g_task03_after_shrink == 32U && + g_task03_failures_preserve_break && + g_task03_bounds_hold; + + task03_debug_checkpoint(); + +#if defined(HOST_PRINTF) + printf( + "grow=%zu rejected_grow=%zu shrink=%zu rejected_shrink=%zu " + "preserved=%d bounds=%d pass=%d\n", + g_task03_after_grow, g_task03_after_failed_grow, + g_task03_after_shrink, g_task03_after_failed_shrink, + g_task03_failures_preserve_break, g_task03_bounds_hold, + g_task03_pass); +#endif + return g_task03_pass ? 0 : 1; +} diff --git a/src/tasks/task04_smalloc.c b/src/tasks/task04_smalloc.c new file mode 100644 index 0000000..dd8c7be --- /dev/null +++ b/src/tasks/task04_smalloc.c @@ -0,0 +1,110 @@ +#include +#include + +#include "c09_bounded_sbrk.h" +#include "c09_smalloc.h" + +#if defined(HOST_PRINTF) +#include +#endif + +volatile size_t g_task04_header_bytes; +volatile size_t g_task04_first_reserved; +volatile size_t g_task04_second_reserved; +volatile size_t g_task04_payload_delta; +volatile int g_task04_aligned; +volatile int g_task04_header_before_payload; +volatile int g_task04_reset_rewinds_arena; +volatile int g_task04_append_only; +volatile int g_task04_pass; + +__attribute__((noinline)) void task04_debug_checkpoint(void) +{ +#if defined(__GNUC__) + __asm__ volatile("" ::: "memory"); +#endif +} + +int main(void) +{ + C09SmallocInfo first_info; + C09SmallocInfo second_info; + unsigned char *first; + unsigned char *second; + unsigned char *after_reset; + uintptr_t break_before_reset; + uintptr_t break_after_reset; + size_t index; + int bytes_hold = 1; + + c09_smalloc_reset(); + first = (unsigned char *)c09_smalloc(1U); + second = (unsigned char *)c09_smalloc(17U); + if (first == (unsigned char *)0 || second == (unsigned char *)0) { + return 1; + } + + first[0] = 0x5AU; + for (index = 0U; index < 17U; ++index) { + second[index] = (unsigned char)(0x80U + index); + } + bytes_hold = first[0] == 0x5AU; + for (index = 0U; index < 17U; ++index) { + if (second[index] != (unsigned char)(0x80U + index)) { + bytes_hold = 0; + } + } + + if (!c09_smalloc_inspect(first, &first_info) || + !c09_smalloc_inspect(second, &second_info)) { + return 2; + } + + g_task04_header_bytes = C09_SMALLOC_HEADER_BYTES; + g_task04_first_reserved = first_info.reserved_bytes; + g_task04_second_reserved = second_info.reserved_bytes; + g_task04_payload_delta = (size_t)((uintptr_t)second - (uintptr_t)first); + g_task04_aligned = + ((uintptr_t)first % C09_SMALLOC_ALIGNMENT) == 0U && + ((uintptr_t)second % C09_SMALLOC_ALIGNMENT) == 0U; + g_task04_header_before_payload = + first_info.magic == C09_SMALLOC_MAGIC && + first_info.requested_bytes == 1U && + first_info.sequence == 1U && + second_info.magic == C09_SMALLOC_MAGIC && + second_info.requested_bytes == 17U && + second_info.sequence == 2U; + g_task04_append_only = + (uintptr_t)second > (uintptr_t)first && + g_task04_payload_delta == first_info.reserved_bytes; + + break_before_reset = c09_sbrk_current_address(); + c09_smalloc_reset(); + break_after_reset = c09_sbrk_current_address(); + after_reset = (unsigned char *)c09_smalloc(1U); + g_task04_reset_rewinds_arena = + break_before_reset > break_after_reset && after_reset == first; + + g_task04_pass = + g_task04_header_bytes == 16U && + g_task04_first_reserved == 32U && + g_task04_second_reserved == 48U && + g_task04_payload_delta == 32U && + g_task04_aligned && g_task04_header_before_payload && + g_task04_append_only && g_task04_reset_rewinds_arena && + bytes_hold; + + task04_debug_checkpoint(); + +#if defined(HOST_PRINTF) + printf( + "header=%zu first=%zu second=%zu delta=%zu aligned=%d " + "metadata=%d append=%d reset=%d pass=%d\n", + g_task04_header_bytes, g_task04_first_reserved, + g_task04_second_reserved, g_task04_payload_delta, + g_task04_aligned, g_task04_header_before_payload, + g_task04_append_only, g_task04_reset_rewinds_arena, + g_task04_pass); +#endif + return g_task04_pass ? 0 : 1; +} diff --git a/src/tasks/task05_picolibc_malloc.c b/src/tasks/task05_picolibc_malloc.c new file mode 100644 index 0000000..6783f0f --- /dev/null +++ b/src/tasks/task05_picolibc_malloc.c @@ -0,0 +1,88 @@ +#include +#include +#include + +#if defined(HOST_PRINTF) +#include +#endif + +volatile uintptr_t g_task05_first_address; +volatile uintptr_t g_task05_second_address; +volatile size_t g_task05_address_delta; +volatile uint32_t g_task05_checksum; +volatile int g_task05_nonoverlap; +volatile int g_task05_aligned; +volatile int g_task05_freed; +volatile int g_task05_pass; + +__attribute__((noinline)) void task05_debug_checkpoint(void) +{ +#if defined(__GNUC__) + __asm__ volatile("" ::: "memory"); +#endif +} + +int main(void) +{ + unsigned char *first = (unsigned char *)malloc(13U); + unsigned char *second = (unsigned char *)malloc(29U); + uintptr_t first_end; + uintptr_t second_end; + uint32_t checksum = 0U; + uint32_t expected = 0U; + size_t index; + + if (first == (unsigned char *)0 || second == (unsigned char *)0) { + free(second); + free(first); + return 1; + } + + for (index = 0U; index < 13U; ++index) { + first[index] = (unsigned char)(0x20U + index); + } + for (index = 0U; index < 29U; ++index) { + second[index] = (unsigned char)(0x80U + index); + } + for (index = 0U; index < 13U; ++index) { + checksum += first[index]; + expected += (uint32_t)(0x20U + index); + } + for (index = 0U; index < 29U; ++index) { + checksum += second[index]; + expected += (uint32_t)(0x80U + index); + } + + g_task05_first_address = (uintptr_t)first; + g_task05_second_address = (uintptr_t)second; + g_task05_address_delta = g_task05_first_address < g_task05_second_address + ? (size_t)(g_task05_second_address - g_task05_first_address) + : (size_t)(g_task05_first_address - g_task05_second_address); + first_end = g_task05_first_address + 13U; + second_end = g_task05_second_address + 29U; + g_task05_nonoverlap = + first_end <= g_task05_second_address || + second_end <= g_task05_first_address; + g_task05_aligned = + (g_task05_first_address % 8U) == 0U && + (g_task05_second_address % 8U) == 0U; + g_task05_checksum = checksum; + g_task05_pass = checksum == expected && + g_task05_nonoverlap && g_task05_aligned; + + free(second); + free(first); + g_task05_freed = 1; + + task05_debug_checkpoint(); + +#if defined(HOST_PRINTF) + printf( + "nonnull=1 delta_nonzero=%d checksum=%u nonoverlap=%d " + "aligned=%d freed=%d pass=%d\n", + g_task05_address_delta != 0U, g_task05_checksum, + g_task05_nonoverlap, g_task05_aligned, g_task05_freed, + g_task05_pass); +#endif + return g_task05_pass && g_task05_freed ? 0 : 2; +} diff --git a/tests/check_archive_maps.sh b/tests/check_archive_maps.sh new file mode 100755 index 0000000..80ab975 --- /dev/null +++ b/tests/check_archive_maps.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail + +root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)" +task01_map="$root/build/task01_libc_without_heap/prog.map" +task05_map="$root/build/task05_picolibc_malloc/prog.map" + +grep -q 'libc.a(strlen.c.o)' "$task01_map" +if grep -Eq 'libc_stdlib_malloc.c.o|libc_stdlib_free.c.o|libc_misc_picosbrk.c.o' "$task01_map"; then + echo 'FAIL Task01: heap-related archive member entered the image' >&2 + exit 1 +fi + +for member in libc_stdlib_malloc.c.o libc_stdlib_free.c.o libc_misc_picosbrk.c.o; do + grep -q "$member" "$task05_map" +done + +printf '%s\n' \ + 'PASS Task01 map: strlen.c.o present, malloc/free/picosbrk absent' \ + 'PASS Task05 map: malloc/free/picosbrk archive members present' + diff --git a/tests/check_card.sh b/tests/check_card.sh new file mode 100755 index 0000000..f4035b8 --- /dev/null +++ b/tests/check_card.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash +set -euo pipefail + +root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)" +pdf_count="$(find "$root/doc/pdf" -maxdepth 1 -type f -name '*.pdf' | wc -l)" +[[ "$pdf_count" -eq 1 ]] + +python3 - "$root/json/card_source.json" "$root/web/card-data.json" <<'PY' +import json +import sys + +with open(sys.argv[1], encoding="utf-8") as stream: + card = json.load(stream) +with open(sys.argv[2], encoding="utf-8") as stream: + web = json.load(stream) + +assert card["tasks_order"] == [f"task{number:02d}" for number in range(1, 6)] +blocks = [] +flow_ids = [] +for task_id in card["tasks_order"]: + task = card["tasks"][task_id] + viewpoints = task["viewpoints"] + assert [item["id"] for item in viewpoints] == [f"A{number}" for number in range(1, 9)] + assert len(viewpoints) == 8 + assert all(item["status"] in {"enabled", "unavailable"} for item in viewpoints) + assert all(item.get("id") for item in task["flow"]) + flow_ids.extend(item["id"] for item in task["flow"]) + blocks.extend(item for item in task["flow"] if item["id"].startswith(task_id + ".a")) +assert len(blocks) == 40 +assert len(flow_ids) == len(set(flow_ids)) +task02_proof = next( + item for item in card["tasks"]["task02"]["flow"] + if item["id"] == "task02.proof" +) +assert "programu hostowego" not in task02_proof["evidence_tex"] +assert "brakująca nazwa" in task02_proof["evidence_tex"] + +def viewpoint_ids(value): + if isinstance(value, dict): + identifier = value.get("id") + if isinstance(identifier, str) and identifier.rsplit(".", 1)[-1] in { + f"a{number}" for number in range(1, 9) + }: + yield identifier + for child in value.values(): + yield from viewpoint_ids(child) + elif isinstance(value, list): + for child in value: + yield from viewpoint_ids(child) + +web_ids = list(viewpoint_ids(web)) +assert len(web_ids) == 40 +assert len(set(web_ids)) == 40 +print("PASS card JSON: 5 tasks x exact A1-A8 = 40 viewpoint blocks") +PY + +tex_viewpoints="$(rg -o '\\begin\{ESCBlockFrame\}\{A[1-8] ' \ + "$root/doc/generated/main.tex" | wc -l)" +[[ "$tex_viewpoints" -eq 40 ]] +for viewpoint in {1..8}; do + count="$(rg -o "\\\\begin\\{ESCBlockFrame\\}\\{A${viewpoint} " \ + "$root/doc/generated/main.tex" | wc -l)" + [[ "$count" -eq 5 ]] +done + +tex_count="$(rg -o '\\textbf\{N/D\.\}' "$root/doc/generated/main.tex" | wc -l)" +[[ "$tex_count" -ge 6 ]] +qpdf --check "$root"/doc/pdf/*.pdf +rg -q 'task02\.a6' "$root/json/card_source.json" + +pdf_text="$(mktemp)" +trap 'rm -f -- "$pdf_text"' EXIT +pdftotext "$root"/doc/pdf/*.pdf "$pdf_text" +pdf_viewpoints="$(rg -o 'BLOCK A[1-8]' "$pdf_text" | wc -l)" +[[ "$pdf_viewpoints" -eq 40 ]] +if rg -qi 'anonymous|anonimowy|bez nazwy' "$pdf_text"; then + echo 'FAIL card: anonymous block marker found' >&2 + exit 1 +fi +printf 'PASS card artifacts: TeX, web and one valid PDF\n' diff --git a/tests/check_elf.sh b/tests/check_elf.sh new file mode 100755 index 0000000..1d60623 --- /dev/null +++ b/tests/check_elf.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -euo pipefail + +root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)" +nm_tool="${RISCV_PREFIX:-riscv64-unknown-elf-}nm" +readelf_tool="${RISCV_PREFIX:-riscv64-unknown-elf-}readelf" + +symbol_value() { + "$nm_tool" -n "$1" | awk -v wanted="$2" '$3 == wanted { print $1; exit }' +} + +for task in \ + task01_libc_without_heap \ + task03_bounded_sbrk \ + task04_smalloc \ + task05_picolibc_malloc; do + elf="$root/build/$task/prog.elf" + start_hex="$(symbol_value "$elf" __heap_start)" + end_hex="$(symbol_value "$elf" __heap_end)" + stack_bottom_hex="$(symbol_value "$elf" __stack_bottom)" + reset_hex="$(symbol_value "$elf" .reset_handler)" + [[ -n "$start_hex" && -n "$end_hex" && -n "$stack_bottom_hex" ]] + [[ "$reset_hex" == "80000040" ]] + (( 16#$start_hex <= 16#$end_hex )) + (( 16#$end_hex == 16#$stack_bottom_hex )) + (( (16#$start_hex & 15) == 0 )) + (( (16#$end_hex & 15) == 0 )) + "$readelf_tool" -h "$elf" | grep -q 'Class:.*ELF32' + if "$readelf_tool" -lW "$elf" | grep -Eq 'LOAD.*RWE'; then + echo "FAIL $task: writable and executable LOAD segment" >&2 + exit 1 + fi +done + +task05="$root/build/task05_picolibc_malloc/prog.elf" +for symbol in _sbrk sbrk malloc free __heap_start __heap_end; do + [[ -n "$(symbol_value "$task05" "$symbol")" ]] +done + +printf '%s\n' \ + 'PASS linker: reset=0x80000040; bounded aligned heap; no RWX LOAD segment' \ + 'PASS Task05 ELF: vendor _sbrk and picolibc sbrk coexist' diff --git a/tests/test_host.sh b/tests/test_host.sh new file mode 100755 index 0000000..6ceb790 --- /dev/null +++ b/tests/test_host.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +set -euo pipefail + +root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)" +if [[ "${1:-}" != "--already-built" ]]; then + make -C "$root" PROFILE=observe host >/dev/null +fi + +check_output() { + local program="$1" expected="$2" actual + actual="$($program)" + if [[ "$actual" != "$expected" ]]; then + printf 'FAIL %s\nexpected: %s\nactual: %s\n' \ + "$program" "$expected" "$actual" >&2 + return 1 + fi + printf 'PASS %s: %s\n' "$(basename -- "$(dirname -- "$program")")" "$actual" +} + +check_output "$root/host-build/task01_libc_without_heap/prog" \ + 'length=16 pass=1' +check_output "$root/host-build/task03_bounded_sbrk/prog" \ + 'grow=40 rejected_grow=40 shrink=32 rejected_shrink=32 preserved=1 bounds=1 pass=1' +check_output "$root/host-build/task04_smalloc/prog" \ + 'header=16 first=32 second=48 delta=32 aligned=1 metadata=1 append=1 reset=1 pass=1' +check_output "$root/host-build/task05_picolibc_malloc/prog" \ + 'nonnull=1 delta_nonzero=1 checksum=4612 nonoverlap=1 aligned=1 freed=1 pass=1' + diff --git a/web/app.css b/web/app.css new file mode 100644 index 0000000..eac8d78 --- /dev/null +++ b/web/app.css @@ -0,0 +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}} diff --git a/web/app.js b/web/app.js new file mode 100644 index 0000000..c1573ef --- /dev/null +++ b/web/app.js @@ -0,0 +1,61 @@ +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||!(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<\/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(` +`).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(); +/*! Bundled license information: + +react/cjs/react.production.min.js: + (** + * @license React + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + *) + +scheduler/cjs/scheduler.production.min.js: + (** + * @license React + * scheduler.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + *) + +react-dom/cjs/react-dom.production.min.js: + (** + * @license React + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + *) + +react/cjs/react-jsx-runtime.production.min.js: + (** + * @license React + * react-jsx-runtime.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + *) +*/ diff --git a/web/card-data.json b/web/card-data.json new file mode 100644 index 0000000..fa5fea8 --- /dev/null +++ b/web/card-data.json @@ -0,0 +1,2821 @@ +{ + "schema": "esc-card-react-view.v1", + "card": { + "id": "mpabi-inf-c-09-smalloc-sbrk-libc", + "series": "c", + "series_title": "C · Freestanding RV32I and K&R", + "number": "09", + "count": "13", + "slug": "smalloc-sbrk-libc", + "title": "smalloc, sbrk i minimalne libc", + "topic": "K&R 5.4 i 7.8: granica libc, bounded sbrk, prosty smalloc oraz malloc/free picolibc", + "project": "Freestanding C na RV32I", + "subject": "Informatyka", + "level": "Rok 1 · C09 · RV32I/Hazard3", + "revision_date": "2026-07-20T00:00:00+02:00", + "status": "Gotowa", + "version": "v00.01", + "uuid": "47826ae5-6370-5ac2-bd91-9acb89116d40", + "author": "M. Pabiszczak", + "year": "2026" + }, + "library": { + "schema": "stem-card-library.v2", + "workspace": "edu", + "subjects": [ + { + "id": "inf", + "title": "INF · Informatyka", + "current": true, + "levels": [ + { + "id": "year-1", + "title": "Rok 1", + "current": true, + "series": [ + { + "id": "console-bash", + "title": "Bash · Console Tools", + "current": false, + "catalog_only": true, + "role": "", + "status": "", + "cards": [ + { + "id": "L01", + "title": "BusyBox — the Swiss Army Knife", + "repo": "lab-console-busybox", + "href": "", + "available": false, + "current": false, + "number": "01", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "L02", + "title": "Tmux — sessions, windows and panes", + "repo": "lab-console-tmux", + "href": "", + "available": false, + "current": false, + "number": "02", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "L03", + "title": "Neovim — navigation and editing", + "repo": "lab-console-neovim", + "href": "", + "available": false, + "current": false, + "number": "03", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "L04", + "title": "Git Basics I — status, add and commit", + "repo": "lab-console-git-basics-1", + "href": "", + "available": false, + "current": false, + "number": "04", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "L05", + "title": "Git Basics II — log, diff and restore", + "repo": "lab-console-git-basics-2", + "href": "", + "available": false, + "current": false, + "number": "05", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "L06", + "title": "Git Branching I — branch, switch and merge", + "repo": "lab-console-git-branching-1", + "href": "", + "available": false, + "current": false, + "number": "06", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "L07", + "title": "Git Branching II — rebase and conflicts", + "repo": "lab-console-git-branching-2", + "href": "", + "available": false, + "current": false, + "number": "07", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "L08", + "title": "Docker Fundamentals", + "repo": "lab-console-docker", + "href": "", + "available": false, + "current": false, + "number": "08", + "version": "", + "status": "planned", + "tasks": [] + } + ] + }, + { + "id": "rv32i-asm", + "title": "ASM · RV32I From Blinker to RISC-V", + "current": false, + "catalog_only": true, + "role": "", + "status": "", + "cards": [ + { + "id": "L01", + "title": "Number Systems and Storage", + "repo": "lab-rv32i-asm-number-systems", + "href": "", + "available": false, + "current": false, + "number": "01", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "L02", + "title": "FPGA Bring-up and Programming", + "repo": "lab-rv32i-asm-fpga-bringup", + "href": "", + "available": false, + "current": false, + "number": "02", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "L03", + "title": "Blinker and Synchronous Logic", + "repo": "lab-rv32i-asm-blinker", + "href": "", + "available": false, + "current": false, + "number": "03", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "L04", + "title": "The RISC-V ISA and Instruction Decoder", + "repo": "lab-rv32i-asm-decoder", + "href": "", + "available": false, + "current": false, + "number": "04", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "L05", + "title": "ALU and the Verilog Assembler", + "repo": "lab-rv32i-asm-alu", + "href": "", + "available": false, + "current": false, + "number": "05", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "L06", + "title": "Control Flow — Jumps and Branches", + "repo": "lab-rv32i-asm-control-flow", + "href": "", + "available": false, + "current": false, + "number": "06", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "L07", + "title": "Addresses and Memory", + "repo": "lab-rv32i-asm-addresses-memory", + "href": "", + "available": false, + "current": false, + "number": "07", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "L08", + "title": "Subroutines and the RISC-V ABI", + "repo": "lab-rv32i-asm-subroutines-abi", + "href": "", + "available": false, + "current": false, + "number": "08", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "L09", + "title": "Load and Store", + "repo": "lab-rv32i-asm-load-store", + "href": "", + "available": false, + "current": false, + "number": "09", + "version": "", + "status": "planned", + "tasks": [] + } + ] + }, + { + "id": "c", + "title": "C · Freestanding RV32I and K&R", + "current": true, + "catalog_only": true, + "role": "", + "status": "", + "cards": [ + { + "id": "C01", + "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", + "available": true, + "current": false, + "number": "01", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Ręczna implementacja RV32I ASM" + }, + { + "id": "task02", + "title": "Referencyjna implementacja w C" + }, + { + "id": "task03", + "title": "ASM wyemitowany przez GCC" + } + ] + }, + { + "id": "C02", + "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", + "available": true, + "current": false, + "number": "02", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Wynik strlen w .bss" + }, + { + "id": "task02", + "title": "Wynik i napis w .data" + }, + { + "id": "task03", + "title": "Nieużyta tablica lokalna" + }, + { + "id": "task04", + "title": "Użyta tablica lokalna i stack frame" + } + ] + }, + { + "id": "C03", + "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", + "available": true, + "current": false, + "number": "03", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Argument i wynik bez powrotu z main" + }, + { + "id": "task02", + "title": "Pełny stack frame i zachowanie ra" + } + ] + }, + { + "id": "C04", + "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", + "available": true, + "current": false, + "number": "04", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Nazwy i stałe symboliczne" + }, + { + "id": "task02", + "title": "Typy i zakresy" + }, + { + "id": "task03", + "title": "Stałe, długość i enum" + }, + { + "id": "task04", + "title": "Deklaracje, inicjalizacja i const" + }, + { + "id": "task05", + "title": "Arytmetyka i rok przestępny" + }, + { + "id": "task06", + "title": "Porównania i logika" + }, + { + "id": "task07", + "title": "Konwersje: atoi, lower i htoi" + }, + { + "id": "task08", + "title": "Inkrementacja i operacje na napisach" + }, + { + "id": "task09", + "title": "Operatory bitowe" + }, + { + "id": "task10", + "title": "Przypisania i bitcount" + }, + { + "id": "task11", + "title": "Operator warunkowy" + }, + { + "id": "task12", + "title": "Priorytet i kolejność obliczeń" + } + ] + }, + { + "id": "C05", + "title": "Control Flow", + "repo": "lab-rv32i-c-control-flow", + "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/7512361d-e5e6-5c08-ab18-8be29dacdc10", + "available": true, + "current": false, + "number": "05", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Instrukcje i bloki" + }, + { + "id": "task02", + "title": "if-else i dangling else" + }, + { + "id": "task03", + "title": "else-if i wyszukiwanie binarne" + }, + { + "id": "task04", + "title": "switch: escape i unescape" + }, + { + "id": "task05", + "title": "while, for i Shell sort" + }, + { + "id": "task06", + "title": "do-while i itoa" + }, + { + "id": "task07", + "title": "break i continue" + }, + { + "id": "task08", + "title": "goto i etykiety" + } + ] + }, + { + "id": "C06", + "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", + "available": true, + "current": false, + "number": "06", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Funkcje i strindex" + }, + { + "id": "task02", + "title": "double i atof z wykładnikiem" + }, + { + "id": "task03", + "title": "Zewnętrzny stos RPN" + }, + { + "id": "task04", + "title": "Scope i extern" + }, + { + "id": "task05", + "title": "Nagłówki i prototypy" + }, + { + "id": "task06", + "title": "Static storage" + }, + { + "id": "task07", + "title": "Zmienne register" + }, + { + "id": "task08", + "title": "Struktura blokowa" + }, + { + "id": "task09", + "title": "Inicjalizacja" + }, + { + "id": "task10", + "title": "Rekurencja i quicksort" + }, + { + "id": "task11", + "title": "Preprocesor i makra" + } + ] + }, + { + "id": "C07", + "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", + "available": true, + "current": false, + "number": "07", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "task01" + }, + { + "id": "task02", + "title": "task02" + }, + { + "id": "task03", + "title": "task03" + }, + { + "id": "task04", + "title": "K&R 5.4 -- Linear Memory Allocator" + }, + { + "id": "task05", + "title": "task05" + }, + { + "id": "task06", + "title": "task06" + }, + { + "id": "task07", + "title": "task07" + }, + { + "id": "task08", + "title": "task08" + }, + { + "id": "task09", + "title": "task09" + }, + { + "id": "task10", + "title": "task10" + }, + { + "id": "task11", + "title": "task11" + }, + { + "id": "task12", + "title": "task12" + } + ] + }, + { + "id": "C08", + "title": "Structures and Linked State", + "repo": "lab-rv32i-c-structures", + "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/f60fbba3-a788-5f1e-bc24-52af82f227c9", + "available": true, + "current": false, + "number": "08", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Układ BlockHeader" + }, + { + "id": "task02", + "title": "Nagłówek, payload i odzyskanie właściciela" + }, + { + "id": "task03", + "title": "Intruzywna lista wolnych bloków" + }, + { + "id": "task04", + "title": "Wyrównana arena dwóch bloków" + } + ] + }, + { + "id": "C09", + "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", + "available": true, + "current": true, + "number": "09", + "version": "v00.01", + "status": "planned", + "tasks": [ + { + "id": "task01", + "title": "strlen z libc bez sterty" + }, + { + "id": "task02", + "title": "Kontrolowany brak dostawcy sbrk" + }, + { + "id": "task03", + "title": "Bounded sbrk i atomowy błąd" + }, + { + "id": "task04", + "title": "Wyrównany smalloc append-only" + }, + { + "id": "task05", + "title": "malloc/free picolibc jako czarna skrzynka" + } + ] + }, + { + "id": "C10", + "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", + "available": true, + "current": false, + "number": "10", + "version": "v00.01", + "status": "planned", + "tasks": [ + { + "id": "task01", + "title": "ECALL i wznowienie pod mepc+4" + }, + { + "id": "task02", + "title": "Machine software IRQ i clear źródła" + }, + { + "id": "task03", + "title": "Macierz pending, MSIE i MIE" + } + ] + }, + { + "id": "C11", + "title": "Machine Timer and Periodic Work", + "repo": "lab-rv32i-c-timer", + "href": "", + "available": false, + "current": false, + "number": "11", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "C12", + "title": "UART — polling and interrupts", + "repo": "lab-rv32i-c-uart", + "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/64f7c516-78b1-58ee-8619-a82d7061079f", + "available": true, + "current": false, + "number": "12", + "version": "v00.01", + "status": "planned", + "tasks": [ + { + "id": "task01", + "title": "Polling jednego bajtu" + }, + { + "id": "task02", + "title": "Odbiór R przez external IRQ 16" + }, + { + "id": "task03", + "title": "Jednokomórkowa skrzynka drop-newest" + } + ] + }, + { + "id": "C13", + "title": "GPIO, Edges and Debounce", + "repo": "lab-rv32i-c-gpio", + "href": "", + "available": false, + "current": false, + "number": "13", + "version": "", + "status": "planned", + "tasks": [] + } + ] + } + ] + }, + { + "id": "year-2", + "title": "Rok 2", + "current": false, + "series": [ + { + "id": "cpp", + "title": "C++", + "current": false, + "catalog_only": true, + "role": "", + "status": "", + "cards": [ + { + "id": "CPP01", + "title": "Translation Units, Linkage and Namespaces", + "repo": "lab-cpp-build-namespaces", + "href": "", + "available": false, + "current": false, + "number": "01", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "CPP02", + "title": "Classes, Encapsulation and Invariants", + "repo": "lab-cpp-classes-invariants", + "href": "", + "available": false, + "current": false, + "number": "02", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "CPP03", + "title": "Construction, Destruction and RAII", + "repo": "lab-cpp-lifetime-raii", + "href": "", + "available": false, + "current": false, + "number": "03", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "CPP04", + "title": "References, const and Value Categories", + "repo": "lab-cpp-references-const", + "href": "", + "available": false, + "current": false, + "number": "04", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "CPP05", + "title": "Copy, Move and the Rule of Zero/Five", + "repo": "lab-cpp-copy-move", + "href": "", + "available": false, + "current": false, + "number": "05", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "CPP06", + "title": "Ownership and Resource Types", + "repo": "lab-cpp-ownership", + "href": "", + "available": false, + "current": false, + "number": "06", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "CPP07", + "title": "Function and Class Templates", + "repo": "lab-cpp-templates", + "href": "", + "available": false, + "current": false, + "number": "07", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "CPP08", + "title": "Static Polymorphism and CRTP", + "repo": "lab-cpp-static-polymorphism", + "href": "", + "available": false, + "current": false, + "number": "08", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "CPP09", + "title": "Inheritance, Interfaces and Dynamic Dispatch", + "repo": "lab-cpp-dynamic-polymorphism", + "href": "", + "available": false, + "current": false, + "number": "09", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "CPP10", + "title": "Operator Overloading and Strong Types", + "repo": "lab-cpp-strong-types", + "href": "", + "available": false, + "current": false, + "number": "10", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "CPP11", + "title": "Containers, Iterators and Algorithms", + "repo": "lab-cpp-containers-iterators", + "href": "", + "available": false, + "current": false, + "number": "11", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "CPP12", + "title": "Lambdas, Function Objects and Callables", + "repo": "lab-cpp-lambdas-callables", + "href": "", + "available": false, + "current": false, + "number": "12", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "CPP13", + "title": "Error Models with and without Exceptions", + "repo": "lab-cpp-error-models", + "href": "", + "available": false, + "current": false, + "number": "13", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "CPP14", + "title": "Object Layout, ABI and Binary Evidence", + "repo": "lab-cpp-abi-evidence", + "href": "", + "available": false, + "current": false, + "number": "14", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "CPP15", + "title": "Resource-type Integration Project", + "repo": "lab-cpp-resource-integration", + "href": "", + "available": false, + "current": false, + "number": "15", + "version": "", + "status": "planned", + "tasks": [] + } + ] + }, + { + "id": "freertos-c", + "title": "FreeRTOS C", + "current": false, + "catalog_only": true, + "role": "", + "status": "", + "cards": [ + { + "id": "FC01", + "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", + "available": true, + "current": false, + "number": "01", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Predict and prove reusable heap_4 blocks" + } + ] + }, + { + "id": "FC02", + "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", + "available": true, + "current": false, + "number": "02", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Pierwszy task FreeRTOS — callback, context, TCB i stos" + } + ] + }, + { + "id": "FC03", + "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", + "available": true, + "current": false, + "number": "03", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Kontrolowany eksperyment schedulera FreeRTOS" + } + ] + }, + { + "id": "FC04", + "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", + "available": true, + "current": false, + "number": "04", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Delay, blokowanie, zawieszenie i self-delete" + } + ] + }, + { + "id": "FC05", + "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", + "available": true, + "current": false, + "number": "05", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Kolejka długości 1: empty, full, copy i FIFO" + } + ] + }, + { + "id": "FC06", + "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", + "available": true, + "current": false, + "number": "06", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "One-shot, auto-reload i timer daemon" + } + ] + }, + { + "id": "FC07", + "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", + "available": true, + "current": false, + "number": "07", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "External IRQ → FromISR semaphore → high-priority task" + } + ] + }, + { + "id": "FC08", + "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", + "available": true, + "current": false, + "number": "08", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Low/Medium/High: ownership i dziedziczenie priorytetu" + } + ] + }, + { + "id": "FC09", + "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", + "available": true, + "current": false, + "number": "09", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "ALL-ready i trzyosobowa bariera" + } + ] + }, + { + "id": "FC10", + "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", + "available": true, + "current": false, + "number": "10", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Count, overwrite i bit flags na jednym slocie" + } + ] + }, + { + "id": "FC11", + "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", + "available": true, + "current": false, + "number": "11", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Same behavior, two storage policies" + } + ] + }, + { + "id": "FC12", + "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", + "available": true, + "current": false, + "number": "12", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Diagnose before changing the program" + } + ] + }, + { + "id": "FC13", + "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", + "available": true, + "current": false, + "number": "13", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Build and prove a bounded UART RX pipeline" + } + ] + }, + { + "id": "FC14", + "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", + "available": true, + "current": false, + "number": "14", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Prove one machine-timer event from ISR to daemon GPIO work" + } + ] + }, + { + "id": "FC15", + "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", + "available": true, + "current": false, + "number": "15", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Prove one complete FreeRTOS C architecture" + } + ] + } + ] + }, + { + "id": "freertos-cpp", + "title": "FreeRTOS C++", + "current": false, + "catalog_only": true, + "role": "", + "status": "", + "cards": [ + { + "id": "K02", + "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", + "available": true, + "current": false, + "number": "02", + "version": "v00.04", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "C++ Task wrapper — OOP i debugowanie cyklu życia" + } + ] + }, + { + "id": "K03", + "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", + "available": true, + "current": false, + "number": "03", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Vector V1 — transfer własności i powrót heapu" + } + ] + }, + { + "id": "K04", + "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", + "available": true, + "current": false, + "number": "04", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Osiem snapshotów decyzji schedulera" + } + ] + }, + { + "id": "K05", + "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", + "available": true, + "current": false, + "number": "05", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Fragmentacja, koalescencja i historyczny watermark" + } + ] + }, + { + "id": "K06", + "title": "MemoryResource and FreeRtosAllocator", + "repo": "lab-rv32i-freertos-allocator-resource", + "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/1af48a2e-8564-4e18-8115-b2c0208169d6", + "available": true, + "current": false, + "number": "06", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Dwa zasoby, jeden typed allocator" + } + ] + }, + { + "id": "K07", + "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", + "available": true, + "current": false, + "number": "07", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Stabilny obiekt przez statyczny trampoline" + } + ] + }, + { + "id": "K08", + "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", + "available": true, + "current": false, + "number": "08", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Dwie polityki storage i pełna oś delete" + } + ] + }, + { + "id": "K09", + "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", + "available": true, + "current": false, + "number": "09", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Fasada kernela i restore na każdej ścieżce" + } + ] + }, + { + "id": "K10", + "title": "Queue and StaticQueue", + "repo": "lab-rv32i-freertos-queue", + "href": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/66967c2d-bb34-4344-8064-f54d06cce47a", + "available": true, + "current": false, + "number": "10", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Typed byte-copy queue z dwiema politykami storage" + } + ] + }, + { + "id": "K11", + "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", + "available": true, + "current": false, + "number": "11", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "LockGuard i zmierzone priority inheritance" + } + ] + }, + { + "id": "K12", + "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", + "available": true, + "current": false, + "number": "12", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Semaphore slots i jednoodbiorcza notification" + } + ] + }, + { + "id": "K13", + "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", + "available": true, + "current": false, + "number": "13", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Typed EventGroup i trzy źródła stanu" + } + ] + }, + { + "id": "K14", + "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", + "available": true, + "current": false, + "number": "14", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "Static one-shot i periodic timer na daemon tasku" + } + ] + }, + { + "id": "K15", + "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", + "available": true, + "current": false, + "number": "15", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "UART queue i GPIO notify z realnego IRQ" + } + ] + }, + { + "id": "K16", + "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", + "available": true, + "current": false, + "number": "16", + "version": "v00.01", + "status": "existing", + "tasks": [ + { + "id": "task01", + "title": "End-to-end RTOS service i evidence report" + } + ] + } + ] + }, + { + "id": "posix-threads", + "title": "POSIX Threads", + "current": false, + "catalog_only": true, + "role": "", + "status": "", + "cards": [ + { + "id": "PT01", + "title": "Process and Thread Execution Context", + "repo": "lab-posix-process-thread", + "href": "", + "available": false, + "current": false, + "number": "01", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "PT02", + "title": "pthread_create, pthread_join and Lifecycle", + "repo": "lab-posix-pthread-create-join", + "href": "", + "available": false, + "current": false, + "number": "02", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "PT03", + "title": "Arguments, Return Values and Ownership", + "repo": "lab-posix-thread-arguments", + "href": "", + "available": false, + "current": false, + "number": "03", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "PT04", + "title": "Data Races and the Happens-before Question", + "repo": "lab-posix-data-races", + "href": "", + "available": false, + "current": false, + "number": "04", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "PT05", + "title": "Mutex, Critical Section and Deadlock", + "repo": "lab-posix-mutex", + "href": "", + "available": false, + "current": false, + "number": "05", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "PT06", + "title": "Condition Variables and Predicates", + "repo": "lab-posix-condition-variable", + "href": "", + "available": false, + "current": false, + "number": "06", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "PT07", + "title": "Bounded Producer–Consumer Queue", + "repo": "lab-posix-producer-consumer", + "href": "", + "available": false, + "current": false, + "number": "07", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "PT08", + "title": "POSIX Semaphores", + "repo": "lab-posix-semaphore", + "href": "", + "available": false, + "current": false, + "number": "08", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "PT09", + "title": "Reader–Writer Lock", + "repo": "lab-posix-rwlock", + "href": "", + "available": false, + "current": false, + "number": "09", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "PT10", + "title": "C Atomics and Memory Ordering", + "repo": "lab-posix-atomics", + "href": "", + "available": false, + "current": false, + "number": "10", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "PT11", + "title": "Cancellation, Cleanup and Safe Shutdown", + "repo": "lab-posix-cancellation-cleanup", + "href": "", + "available": false, + "current": false, + "number": "11", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "PT12", + "title": "Thread-local Storage", + "repo": "lab-posix-thread-local", + "href": "", + "available": false, + "current": false, + "number": "12", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "PT13", + "title": "Scheduling Policy, Priority and Affinity", + "repo": "lab-posix-scheduling", + "href": "", + "available": false, + "current": false, + "number": "13", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "PT14", + "title": "GDB, Sanitizers and Race Evidence", + "repo": "lab-posix-thread-debugging", + "href": "", + "available": false, + "current": false, + "number": "14", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "PT15", + "title": "POSIX Threads vs FreeRTOS Integration", + "repo": "lab-posix-freertos-comparison", + "href": "", + "available": false, + "current": false, + "number": "15", + "version": "", + "status": "planned", + "tasks": [] + } + ] + }, + { + "id": "oop", + "title": "OOP and Design Patterns", + "current": false, + "catalog_only": true, + "role": "reference", + "status": "", + "cards": [ + { + "id": "OOP01", + "title": "Strategy — Replaceable Behaviour", + "repo": "lab-cpp-oop-strategy", + "href": "", + "available": false, + "current": false, + "number": "01", + "version": "", + "status": "design", + "tasks": [] + }, + { + "id": "OOP02", + "title": "Adapter — Stable Boundary", + "repo": "lab-cpp-oop-adapter", + "href": "", + "available": false, + "current": false, + "number": "02", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "OOP03", + "title": "Template Method — Fixed Skeleton", + "repo": "lab-cpp-oop-template-method", + "href": "", + "available": false, + "current": false, + "number": "03", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "OOP04", + "title": "Static vs Dynamic Dispatch", + "repo": "lab-cpp-oop-dispatch", + "href": "", + "available": false, + "current": false, + "number": "04", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "OOP05", + "title": "RAII and Ownership", + "repo": "lab-cpp-oop-raii", + "href": "", + "available": false, + "current": false, + "number": "05", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "OOP06", + "title": "State — Explicit Behaviour", + "repo": "lab-cpp-oop-state", + "href": "", + "available": false, + "current": false, + "number": "06", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "OOP07", + "title": "Facade — Subsystem Boundary", + "repo": "lab-cpp-oop-facade", + "href": "", + "available": false, + "current": false, + "number": "07", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "OOP08", + "title": "Command — Request as Object", + "repo": "lab-cpp-oop-command", + "href": "", + "available": false, + "current": false, + "number": "08", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "OOP09", + "title": "Observer — Subscription and Telemetry", + "repo": "lab-cpp-oop-observer", + "href": "", + "available": false, + "current": false, + "number": "09", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "OOP10", + "title": "Factory Method — Resource Policy", + "repo": "lab-cpp-oop-factory-method", + "href": "", + "available": false, + "current": false, + "number": "10", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "OOP11", + "title": "Builder — Valid Configuration", + "repo": "lab-cpp-oop-builder", + "href": "", + "available": false, + "current": false, + "number": "11", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "OOP12", + "title": "Decorator — Measurement and Diagnostics", + "repo": "lab-cpp-oop-decorator", + "href": "", + "available": false, + "current": false, + "number": "12", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "OOP13", + "title": "Composite — Component Tree", + "repo": "lab-cpp-oop-composite", + "href": "", + "available": false, + "current": false, + "number": "13", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "OOP14", + "title": "Chain of Responsibility", + "repo": "lab-cpp-oop-chain", + "href": "", + "available": false, + "current": false, + "number": "14", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "OOP15", + "title": "Pattern-language Integration", + "repo": "lab-cpp-oop-integration", + "href": "", + "available": false, + "current": false, + "number": "15", + "version": "", + "status": "planned", + "tasks": [] + } + ] + } + ] + }, + { + "id": "year-3", + "title": "Rok 3 · plan", + "current": false, + "series": [ + { + "id": "modern-cpp-stl", + "title": "Modern C++ / STL", + "current": false, + "catalog_only": true, + "role": "", + "status": "scope-reserved", + "cards": [] + }, + { + "id": "std-threads", + "title": "std::thread / std::jthread", + "current": false, + "catalog_only": true, + "role": "", + "status": "scope-reserved", + "cards": [] + }, + { + "id": "boost-asio", + "title": "Boost.Asio", + "current": false, + "catalog_only": true, + "role": "", + "status": "scope-reserved", + "cards": [] + }, + { + "id": "oop", + "title": "OOP and Design Patterns", + "current": false, + "catalog_only": true, + "role": "reference", + "status": "", + "cards": [ + { + "id": "OOP01", + "title": "Strategy — Replaceable Behaviour", + "repo": "lab-cpp-oop-strategy", + "href": "", + "available": false, + "current": false, + "number": "01", + "version": "", + "status": "design", + "tasks": [] + }, + { + "id": "OOP02", + "title": "Adapter — Stable Boundary", + "repo": "lab-cpp-oop-adapter", + "href": "", + "available": false, + "current": false, + "number": "02", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "OOP03", + "title": "Template Method — Fixed Skeleton", + "repo": "lab-cpp-oop-template-method", + "href": "", + "available": false, + "current": false, + "number": "03", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "OOP04", + "title": "Static vs Dynamic Dispatch", + "repo": "lab-cpp-oop-dispatch", + "href": "", + "available": false, + "current": false, + "number": "04", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "OOP05", + "title": "RAII and Ownership", + "repo": "lab-cpp-oop-raii", + "href": "", + "available": false, + "current": false, + "number": "05", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "OOP06", + "title": "State — Explicit Behaviour", + "repo": "lab-cpp-oop-state", + "href": "", + "available": false, + "current": false, + "number": "06", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "OOP07", + "title": "Facade — Subsystem Boundary", + "repo": "lab-cpp-oop-facade", + "href": "", + "available": false, + "current": false, + "number": "07", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "OOP08", + "title": "Command — Request as Object", + "repo": "lab-cpp-oop-command", + "href": "", + "available": false, + "current": false, + "number": "08", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "OOP09", + "title": "Observer — Subscription and Telemetry", + "repo": "lab-cpp-oop-observer", + "href": "", + "available": false, + "current": false, + "number": "09", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "OOP10", + "title": "Factory Method — Resource Policy", + "repo": "lab-cpp-oop-factory-method", + "href": "", + "available": false, + "current": false, + "number": "10", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "OOP11", + "title": "Builder — Valid Configuration", + "repo": "lab-cpp-oop-builder", + "href": "", + "available": false, + "current": false, + "number": "11", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "OOP12", + "title": "Decorator — Measurement and Diagnostics", + "repo": "lab-cpp-oop-decorator", + "href": "", + "available": false, + "current": false, + "number": "12", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "OOP13", + "title": "Composite — Component Tree", + "repo": "lab-cpp-oop-composite", + "href": "", + "available": false, + "current": false, + "number": "13", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "OOP14", + "title": "Chain of Responsibility", + "repo": "lab-cpp-oop-chain", + "href": "", + "available": false, + "current": false, + "number": "14", + "version": "", + "status": "planned", + "tasks": [] + }, + { + "id": "OOP15", + "title": "Pattern-language Integration", + "repo": "lab-cpp-oop-integration", + "href": "", + "available": false, + "current": false, + "number": "15", + "version": "", + "status": "planned", + "tasks": [] + } + ] + } + ] + }, + { + "id": "year-4", + "title": "Rok 4 · plan", + "current": false, + "series": [ + { + "id": "transformers-gpu", + "title": "Transformers on GPU", + "current": false, + "catalog_only": true, + "role": "", + "status": "scope-reserved", + "cards": [] + } + ] + } + ] + }, + { + "id": "fiz", + "title": "FIZ · Fizyka", + "current": false, + "levels": [ + { + "id": "all", + "title": "Katalog", + "current": false, + "series": [ + { + "id": "fiz", + "title": "Fizyka", + "current": false, + "catalog_only": false, + "role": "", + "status": "", + "cards": [ + { + "id": "ruch-1d", + "title": "Ruch 1D", + "repo": "ruch-1d", + "href": "", + "available": false, + "current": false, + "number": "", + "version": "", + "status": "", + "tasks": [] + }, + { + "id": "ruch-2d", + "title": "Ruch 2D", + "repo": "ruch-2d", + "href": "", + "available": false, + "current": false, + "number": "", + "version": "", + "status": "", + "tasks": [] + }, + { + "id": "ruch-po-okregu", + "title": "Ruch po okręgu", + "repo": "ruch-po-okregu", + "href": "", + "available": false, + "current": false, + "number": "", + "version": "", + "status": "", + "tasks": [] + } + ] + } + ] + } + ] + } + ] + }, + "total_pages": 10, + "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\n\n\n\n\n\n\n\n\n\n
TITLEsmalloc, sbrk i minimalne libc
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C na RV32I
SERIESC · Freestanding RV32I and K&R
CARD09/13
SHEET1/10
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID47826ae5-6370-5ac2-bd91-9acb89116d40CARD UUID8e4f8bee-41f0-523b-8ea2-8926bd3d7ab0AUTHOR  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\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
", + "left_margin_html": "
TECH
", + "right_margin_html": "
OG
", + "goal_title": "Cel karty", + "goal_html": "

Uczeń rozdziela wybór funkcji z archiwum libc, kontrakt dostawcy pamięci sbrk i politykę alokatora. Najpierw dowodzi, że strlen nie potrzebuje sterty, potem kontrolowanie zrywa zależność malloc do sbrk, buduje ograniczony model break i wyrównany smalloc, a na końcu traktuje prawdziwe malloc/free picolibc jako czarną skrzynkę sprawdzaną przez kontrakt.

", + "scope_title": "Zakres i zachowane przykłady", + "scope_html": "

Pięć zachowanych przykładów działa na hoście i RV32I tam, gdzie istnieje program uruchamialny. Task02 jest zamierzonym expected-fail linkera i nie ma obrazu runtime. W aktualnym GCC 15.2 biblioteka to picolibc: jej malloc odwołuje się do sbrk, podczas gdy vendorowy init.S Hazard3 definiuje inny symbol _sbrk. Własny linker ogranicza stertę symbolami __heap_start i __heap_end oraz rezerwuje 64 KiB stosu. Układ każdego przykładu: pełny profil A1-A8; widok N/D ma jawny powód, a diagram nie jest wymagany, gdy tekst daje lepszy dowód.

", + "scope_columns": [ + "chapter", + "task", + "idea", + "priority" + ], + "scope_headers": [ + "K&R", + "Numer tasku", + "Najważniejsza idea", + "Priorytet" + ], + "scope_rows": [ + { + "chapter": "7.8", + "task": "Task01", + "idea_html": "

libc.a: wybór strlen.c.o

", + "priority": "kluczowe", + "status": "", + "status_label": "", + "version": "", + "key": true + }, + { + "chapter": "5.4 + ABI", + "task": "Task02", + "idea_html": "

expected-fail: malloc -> sbrk

", + "priority": "kluczowe", + "status": "", + "status_label": "", + "version": "", + "key": true + }, + { + "chapter": "5.4", + "task": "Task03", + "idea_html": "

ograniczony break i atomowy błąd

", + "priority": "kluczowe", + "status": "", + "status_label": "", + "version": "", + "key": true + }, + { + "chapter": "5.4", + "task": "Task04", + "idea_html": "

nagłówek, alignment i reset areny

", + "priority": "kluczowe", + "status": "", + "status_label": "", + "version": "", + "key": true + }, + { + "chapter": "7.8 + ABI", + "task": "Task05", + "idea_html": "

malloc/free picolibc jako black box

", + "priority": "kluczowe", + "status": "", + "status_label": "", + "version": "", + "key": true + } + ] + }, + "sections": [ + { + "id": "section-1-content", + "index": 1, + "title": "1 — Funkcja z libc nie oznacza automatycznie sterty", + "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\n\n\n\n\n\n\n\n\n\n
TITLEsmalloc, sbrk i minimalne libc
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C na RV32I
SERIESC · Freestanding RV32I and K&R
CARD09/13
SHEET2/10
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID47826ae5-6370-5ac2-bd91-9acb89116d40CARD UUID8e4f8bee-41f0-523b-8ea2-8926bd3d7ab0AUTHOR  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\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
", + "left_margin_html": "
TECH
", + "right_margin_html": "
OG
", + "content_html": "

Archiwum libc.a nie jest włączane do programu w całości. Linker pobiera człon, który rozwiązuje potrzebny symbol, a następne człony tylko wtedy, gdy pojawią się kolejne nierozwiązane odwołania. Dlatego bezpośrednie wywołanie strlen z opcją -fno-builtin wybiera strlen.c.o, lecz nie wybiera libc_stdlib_malloc.c.o ani libc_misc_picosbrk.c.o. Dowodem jest mapa linkera, a nie samo dołączenie nagłówka string.h.

\n

Task01 rozstrzyga wyłącznie tę zależność. Nie dowodzi, że każda funkcja tekstowa jest bezkosztowa ani że całe libc nie używa pamięci dynamicznej.

", + "tasks": [], + "assets": [], + "steps": [], + "spread_group": "", + "spread_label": "", + "spread_columns": 1, + "spread_index": 1, + "spread_count": 1, + "page_orientation": "portrait" + }, + { + "id": "section-2-content", + "index": 2, + "title": "2 — malloc potrzebuje sbrk, lecz _sbrk to inna nazwa", + "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\n\n\n\n\n\n\n\n\n\n
TITLEsmalloc, sbrk i minimalne libc
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C na RV32I
SERIESC · Freestanding RV32I and K&R
CARD09/13
SHEET3/10
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID47826ae5-6370-5ac2-bd91-9acb89116d40CARD UUID8e4f8bee-41f0-523b-8ea2-8926bd3d7ab0AUTHOR  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\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
", + "left_margin_html": "
TECH
", + "right_margin_html": "
OG
", + "content_html": "

W badanym GCC 15.2 używane jest picolibc, nie newlib. Człon libc_stdlib_malloc.c.o ma niezdefiniowane odwołanie do sbrk. Picolibc może dostarczyć je z libc_misc_picosbrk.c.o; ten kod opiera granice na symbolach linkera __heap_start i __heap_end. Z kolei vendor/Hazard3/.../init.S definiuje _sbrk z jednym podkreśleniem. Dla linkera są to dwa różne symbole, więc mogą współistnieć w Task05.

\n

Task02 używa -wrap=sbrk: każde odwołanie do sbrk zostaje skierowane do celowo brakującego __wrap_sbrk. Oczekiwany błąd jest kontrolowanym testem krawędzi malloc -> sbrk, a nie awarią całego projektu.

", + "tasks": [], + "assets": [], + "steps": [], + "spread_group": "", + "spread_label": "", + "spread_columns": 1, + "spread_index": 1, + "spread_count": 1, + "page_orientation": "portrait" + }, + { + "id": "section-3-content", + "index": 3, + "title": "3 — Od alloc z K&R 5.4 do bounded sbrk i smalloc", + "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\n\n\n\n\n\n\n\n\n\n
TITLEsmalloc, sbrk i minimalne libc
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C na RV32I
SERIESC · Freestanding RV32I and K&R
CARD09/13
SHEET4/10
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID47826ae5-6370-5ac2-bd91-9acb89116d40CARD UUID8e4f8bee-41f0-523b-8ea2-8926bd3d7ab0AUTHOR  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\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
", + "left_margin_html": "
TECH
", + "right_margin_html": "
OG
", + "content_html": "

Liniowy alloc z K&R 5.4 przesuwa wskaźnik w stałej tablicy. Jest prosty, ale nie odzyskuje dowolnego bloku, nie wybiera najlepszego dopasowania, nie dzieli i nie scala wolnych obszarów. afree może cofnąć wskaźnik jedynie do adresu należącego do areny, więc bez dyscypliny stosowej łatwo unieważnić późniejsze przydziały. Historyczna tablica bajtów nie jest też ogólną deklaracją wyrównania dla każdego typu.

\n

Task03 zachowuje istotę modelu, lecz jawnie wymusza heap_start <= brk <= heap_end; odrzucona operacja nie zmienia break. Task04 dodaje 16-bajtowe wyrównanie i 16-bajtowy nagłówek bezpośrednio przed payloadem. Nadal jest to alokator append-only: nie ma sfree, listy wolnych bloków, split ani coalescing. Jedyną operacją odzyskania jest reset całej areny, który unieważnia wszystkie wcześniejsze wskaźniki.

", + "tasks": [], + "assets": [], + "steps": [], + "spread_group": "", + "spread_label": "", + "spread_columns": 1, + "spread_index": 1, + "spread_count": 1, + "page_orientation": "portrait" + }, + { + "id": "section-4-content", + "index": 4, + "title": "4 — Prawdziwe malloc/free jako czarna skrzynka", + "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\n\n\n\n\n\n\n\n\n\n
TITLEsmalloc, sbrk i minimalne libc
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C na RV32I
SERIESC · Freestanding RV32I and K&R
CARD09/13
SHEET5/10
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID47826ae5-6370-5ac2-bd91-9acb89116d40CARD UUID8e4f8bee-41f0-523b-8ea2-8926bd3d7ab0AUTHOR  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\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
", + "left_margin_html": "
TECH
", + "right_margin_html": "
OG
", + "content_html": "

Task05 nie zakłada, że picolibc ma taki sam nagłówek lub strategię jak c09_smalloc. Program sprawdza tylko publiczny kontrakt potrzebny klientowi: dwa udane przydziały dają używalne, rozłączne obszary; zapisane bajty można odczytać; adresy spełniają mierzone wyrównanie; oba bloki są przekazane do free. Nie odczytuje pamięci po free i nie wymaga ponownego użycia tego samego adresu.

\n

Minimalny startup ustawia gp, pojedynczą bazę TLS tp, zeruje .tbss i .bss, a następnie wywołuje main. Skrypt linkera pozostawia __heap_end 64 KiB przed __stack_top i ma ASSERT zatrzymujący obraz, gdy sekcje zajmą zarezerwowany obszar.

", + "tasks": [], + "assets": [], + "steps": [], + "spread_group": "", + "spread_label": "", + "spread_columns": 1, + "spread_index": 1, + "spread_count": 1, + "page_orientation": "portrait" + }, + { + "id": "section-5-task01", + "index": 5, + "title": "TASK01 — strlen z libc bez sterty", + "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\n\n\n\n\n\n\n\n\n\n
TITLEsmalloc, sbrk i minimalne libc
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C na RV32I
SERIESC · Freestanding RV32I and K&R
CARD09/13
SHEET6/10
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID47826ae5-6370-5ac2-bd91-9acb89116d40CARD UUID8e4f8bee-41f0-523b-8ea2-8926bd3d7ab0AUTHOR  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\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
", + "left_margin_html": "
TECH
", + "right_margin_html": "
OG
", + "content_html": "", + "tasks": [ + { + "ref": "task01", + "title": "strlen z libc bez sterty", + "uuid": "839b8401-9f15-5edc-a214-176c06ba5cb1", + "criterion": "Host i Hazard3: length=16, pass=1, kod 0. Mapa RV32I zawiera libc.a(strlen.c.o), ale nie zawiera libc_stdlib_malloc.c.o, libc_stdlib_free.c.o ani libc_misc_picosbrk.c.o.", + "conclusion_html": "", + "prompt_html": "

Przed linkowaniem przewidź, które człony libc.a są potrzebne przez bezpośrednie strlen. Uruchom program, a potem w mapie udowodnij obecność strlen.c.o i nieobecność członów malloc, free oraz picosbrk.

", + "flow": [ + { + "id": "task01.a1", + "kind": "block", + "title": "A1 CONTEXT · AKTYWNE — klient, archiwum i brak dostawcy pamięci", + "content_html": "

Zachowany przykład: src/tasks/task01_libc_without_heap.c. Klient wywołuje publiczne strlen. Granicą systemu jest linker wybierający potrzebny człon libc.a; Task01 nie deklaruje ani nie wywołuje malloc, free lub sbrk.

", + "steps": [] + }, + { + "id": "task01.a2", + "kind": "block", + "title": "A2 STRUCTURE · AKTYWNE — jedna krawędź symboliczna", + "content_html": "

Przy -fno-builtin obiekt tasku zachowuje niezdefiniowany symbol strlen. Linker rozwiązuje go przez strlen.c.o. Ten człon nie tworzy następnej krawędzi do alokatora, dlatego graf zależności kończy się bez warstwy sterty.

", + "steps": [] + }, + { + "id": "task01.a3", + "kind": "block", + "title": "A3 DISPATCH · N/D", + "content_html": "

N/D. strlen i checkpoint są wywołaniami bezpośrednimi; program nie ma callbacku, ISR, wskaźnika funkcji ani dynamicznego wyboru implementacji.

", + "steps": [] + }, + { + "id": "task01.a4", + "kind": "block", + "title": "A4 APPLICATION · AKTYWNE — dwa niezależne warunki sukcesu", + "content_html": "

Warunek wykonania to długość 16 dla napisu picolibc-no-heap. Warunek obrazu to obecność wyłącznie potrzebnego członu tekstowego i brak trzech nazw członów związanych z przydziałem. Sam kod wyjścia nie zastępuje kontroli mapy.

", + "steps": [] + }, + { + "id": "task01.a5", + "kind": "block", + "title": "A5 FLOW · AKTYWNE — kompilacja, selekcja archiwum, wywołanie", + "content_html": "

Kompilator pozostawia call do strlen; linker przegląda archiwum i pobiera strlen.c.o; startup uruchamia main; funkcja oblicza 16; checkpoint publikuje wynik; main zwraca 0. Każdy etap ma inny artefakt dowodowy.

", + "steps": [] + }, + { + "id": "task01.a6", + "kind": "block", + "title": "A6 STATE · N/D", + "content_html": "

N/D. Program wykonuje jednorazowy, czysty pomiar długości i nie ma domenowego obiektu przechodzącego przez istotne stany ani zasobu o cyklu życia.

", + "steps": [] + }, + { + "id": "task01.a7", + "kind": "block", + "title": "A7 RUNTIME · AKTYWNE — global i mapa odpowiadają na inne pytania", + "content_html": "

W task01_debug_checkpoint global g_task01_length ma wartość 16, a g_task01_pass wartość 1. Osobno prog.map wskazuje libc.a(strlen.c.o); test mapy odrzuca każdą nazwę członu heap.

", + "steps": [] + }, + { + "id": "task01.a8", + "kind": "block", + "title": "A8 PATTERNS · AKTYWNE — płać za osiągalne symbole, nie za nagłówek", + "content_html": "

Dla archiwum statycznego właściwym wzorcem audytu jest śledzenie nierozwiązanych symboli i pobranych członów. #include <string.h> dostarcza deklarację; nie jest poleceniem dołączenia całej implementacji libc.

", + "steps": [] + }, + { + "id": "task01.proof", + "kind": "exercise", + "title": "Przewidywanie → wykonanie → wniosek", + "content_html": "", + "steps": [] + }, + { + "id": "task01.worksheet", + "kind": "block", + "title": "TASK01 · Zapis dowodu ucznia", + "content_html": "

1. Przewidywanie przed uruchomieniem \\noindent \\noindent 2. Wynik programu hostowego \\noindent \\noindent 3. Wynik RV32I i kod wyjścia \\noindent \\noindent 4. Wniosek: reguła języka lub kontrakt targetu potwierdzony przez pomiar \\noindent \\noindent

", + "steps": [] + } + ] + } + ], + "assets": [], + "steps": [], + "spread_group": "", + "spread_label": "", + "spread_columns": 1, + "spread_index": 1, + "spread_count": 1, + "page_orientation": "portrait" + }, + { + "id": "section-6-task02", + "index": 6, + "title": "TASK02 — Kontrolowany brak dostawcy sbrk", + "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\n\n\n\n\n\n\n\n\n\n
TITLEsmalloc, sbrk i minimalne libc
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C na RV32I
SERIESC · Freestanding RV32I and K&R
CARD09/13
SHEET7/10
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID47826ae5-6370-5ac2-bd91-9acb89116d40CARD UUID8e4f8bee-41f0-523b-8ea2-8926bd3d7ab0AUTHOR  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\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
", + "left_margin_html": "
TECH
", + "right_margin_html": "
OG
", + "content_html": "", + "tasks": [ + { + "ref": "task02", + "title": "Kontrolowany brak dostawcy sbrk", + "uuid": "9c55597f-3145-5744-b13e-f1c0ee83abc8", + "criterion": "Kompilacja task.o kończy się sukcesem. Link ma niezerowy status, log wymienia libc_stdlib_malloc.c.o i undefined reference to __wrap_sbrk, a must-not-exist.elf nie istnieje. Nie wykonuje się testu host ani Hazard3.", + "conclusion_html": "", + "prompt_html": "

Narysuj łańcuch main -> malloc -> sbrk. Następnie uruchom make expected-fail i wyjaśnij, dlaczego -wrap=sbrk zmienia ostatnią krawędź na __wrap_sbrk, dlaczego brak ELF jest wynikiem poprawnym oraz czego ten test nie mówi o runtime.

", + "flow": [ + { + "id": "task02.a1", + "kind": "block", + "title": "A1 CONTEXT · AKTYWNE — kontrolowane przecięcie granicy platformy", + "content_html": "

Zachowany przykład: src/tasks/task02_malloc_requires_sbrk.c. Kod klienta żąda 16 B przez malloc. Opcja linkera przechwytuje wyłącznie symbol dostawcy pamięci, dzięki czemu testuje granicę libc-platforma bez usuwania lub modyfikowania systemowego archiwum.

", + "steps": [] + }, + { + "id": "task02.a2", + "kind": "block", + "title": "A2 STRUCTURE · AKTYWNE — caller, człon malloc i brakujący wrapper", + "content_html": "

Obiekt tasku wnosi odwołanie do malloc; linker pobiera libc_stdlib_malloc.c.o. Jego odwołania do sbrk są przez -wrap przepisywane na __wrap_sbrk. Żaden obiekt celowo nie definiuje tej ostatniej nazwy.

", + "steps": [] + }, + { + "id": "task02.a3", + "kind": "block", + "title": "A3 DISPATCH · N/D", + "content_html": "

N/D. Wywołanie malloc jest bezpośrednie, a -wrap jest transformacją nazw podczas linkowania, nie mechanizmem callbacku, ISR ani dynamicznego dispatchu w programie.

", + "steps": [] + }, + { + "id": "task02.a4", + "kind": "block", + "title": "A4 APPLICATION · AKTYWNE — porażka ma precyzyjną sygnaturę", + "content_html": "

Sukces testu oznacza jednocześnie: obiekt C powstał, link zwrócił status różny od zera, diagnostyka zawiera __wrap_sbrk oraz nazwę członu malloc, a końcowy ELF nie istnieje. Inny błąd linkera nie spełnia kryterium.

", + "steps": [] + }, + { + "id": "task02.a5", + "kind": "block", + "title": "A5 FLOW · AKTYWNE — expected-fail jako kontrolowany przebieg", + "content_html": "

Skrypt usuwa stary artefakt, kompiluje task, uruchamia link w trybie dopuszczającym błąd, zapisuje status i log, po czym przywraca rygor set -e. Dopiero cztery asercje zamieniają oczekiwaną porażkę programu w sukces testu.

", + "steps": [] + }, + { + "id": "task02.a6", + "kind": "block", + "title": "A6 STATE · N/D", + "content_html": "

N/D. Linkowanie kończy się przed utworzeniem obrazu wykonywalnego, więc nie istnieje runtime, breakpoint ani obiekt domenowy zmieniający stan w czasie wykonania.

", + "steps": [] + }, + { + "id": "task02.a7", + "kind": "block", + "title": "A7 RUNTIME · AKTYWNE — dowodem jest diagnostyka przed runtime", + "content_html": "

Odczytaj expected-link-failure.log: cztery relokacje z libc_stdlib_malloc.c.o wskazują brak __wrap_sbrk. Następnie sprawdź nieobecność must-not-exist.elf; nie wolno wymyślać wartości runtime dla nieistniejącego programu.

", + "steps": [] + }, + { + "id": "task02.a8", + "kind": "block", + "title": "A8 PATTERNS · AKTYWNE — test negatywny musi odrzucać zły powód", + "content_html": "

Wzorzec expected-fail wymaga konkretnej sygnatury błędu i braku produktu końcowego. Sam warunek „polecenie nie przeszło” byłby za słaby, bo zaliczyłby literówkę, brak kompilatora lub błędny skrypt linkera.

", + "steps": [] + }, + { + "id": "task02.proof", + "kind": "exercise", + "title": "Przewidywanie → wykonanie → wniosek", + "content_html": "", + "steps": [] + }, + { + "id": "task02.worksheet", + "kind": "block", + "title": "TASK02 · Zapis dowodu ucznia", + "content_html": "

1. Przewidywanie przed uruchomieniem \\noindent \\noindent 2. Wynik kompilacji task.o \\noindent \\noindent 3. Status i sygnatury błędu linkera \\noindent \\noindent 4. Wniosek: reguła języka lub kontrakt targetu potwierdzony przez pomiar \\noindent \\noindent

", + "steps": [] + } + ] + } + ], + "assets": [], + "steps": [], + "spread_group": "", + "spread_label": "", + "spread_columns": 1, + "spread_index": 1, + "spread_count": 1, + "page_orientation": "portrait" + }, + { + "id": "section-7-task03", + "index": 7, + "title": "TASK03 — Bounded sbrk i atomowy błąd", + "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\n\n\n\n\n\n\n\n\n\n
TITLEsmalloc, sbrk i minimalne libc
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C na RV32I
SERIESC · Freestanding RV32I and K&R
CARD09/13
SHEET8/10
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID47826ae5-6370-5ac2-bd91-9acb89116d40CARD UUID8e4f8bee-41f0-523b-8ea2-8926bd3d7ab0AUTHOR  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\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
", + "left_margin_html": "
TECH
", + "right_margin_html": "
OG
", + "content_html": "", + "tasks": [ + { + "ref": "task03", + "title": "Bounded sbrk i atomowy błąd", + "uuid": "5a69ff6d-bda9-5b20-a18c-a8da2f88c64a", + "criterion": "Host i Hazard3: grow=40, rejected_grow=40, shrink=32, rejected_shrink=32, preserved=1, bounds=1, pass=1 i kod 0. Linker: __heap_start oraz __heap_end są wyrównane do 16 B, __heap_end == __stack_bottom.", + "conclusion_html": "", + "prompt_html": "

Zapisz stan break po sekwencji +16,+24,fail,-8,fail. Dla obu porażek wskaż sprawdzaną granicę i udowodnij, że zwrot (void *)-1 nie zmienia break. Porównaj stałe offsety hosta i RV32I.

", + "flow": [ + { + "id": "task03.a1", + "kind": "block", + "title": "A1 CONTEXT · AKTYWNE — model oddzielony od libc", + "content_html": "

Zachowane materiały: src/tasks/task03_bounded_sbrk.c, src/runtime/c09_bounded_sbrk.c, src/runtime/c09_bounded_sbrk.h, link/hazard3_c09.ld. Task03 eksportuje nazwę c09_sbrk, aby nie przejąć symbolu sbrk picolibc. Na hoście granice obejmują statyczną arenę 512 B; na RV32I pochodzą z linkera. Ten sam algorytm widzi tylko trzy adresy.

", + "steps": [] + }, + { + "id": "task03.a2", + "kind": "block", + "title": "A2 STRUCTURE · AKTYWNE — start, break i end", + "content_html": "

Stan ma jedną zmienną g_c09_break oraz niezmienne granice start i end. Każdy poprawny stan spełnia start <= break <= end; wolny obszar ma rozmiar end-break, a zajęty prefiks break-start.

", + "steps": [] + }, + { + "id": "task03.a3", + "kind": "block", + "title": "A3 DISPATCH · N/D", + "content_html": "

N/D. Wszystkie operacje c09_sbrk i gettery są wywoływane bezpośrednio; nie ma callbacku, ISR, tablicy funkcji ani wyboru implementacji w runtime.

", + "steps": [] + }, + { + "id": "task03.a4", + "kind": "block", + "title": "A4 APPLICATION · AKTYWNE — tabela pięciu przejść", + "content_html": "

Od offsetu 0 operacje dają kolejno: +16 -> 16, +24 -> 40, zbyt duży wzrost -> 40, -8 -> 32, zejście o 33 -> 32. Udany call zwraca stary break; porażka zwraca wszystkie bity ustawione.

", + "steps": [] + }, + { + "id": "task03.a5", + "kind": "block", + "title": "A5 FLOW · AKTYWNE — najpierw zakres, potem commit", + "content_html": "

Dla wzrostu kod porównuje wielkość z end-current; dla spadku oblicza bezpiecznie moduł także dla PTRDIFF_MIN i porównuje go z current-start. Dopiero po zaliczeniu warunku zapisuje g_c09_break=next.

", + "steps": [] + }, + { + "id": "task03.a6", + "kind": "block", + "title": "A6 STATE · AKTYWNE — VALID pozostaje VALID także po odrzuceniu", + "content_html": "

Break przechodzi przez offsety 0 -> 16 -> 40 -> 40 -> 32 -> 32. Obie porażki są samopętlą stanu: zmienia się wynik operacji, ale nie break. Nie ma przejścia do wartości poniżej start ani powyżej end.

", + "steps": [] + }, + { + "id": "task03.a7", + "kind": "block", + "title": "A7 RUNTIME · AKTYWNE — offsety zamiast niestabilnych adresów", + "content_html": "

Checkpoint publikuje cztery offsety 40,40,32,32 oraz flagi preserved=1 i bounds=1. Adresy bezwzględne hosta mogą się zmieniać przez ASLR, dlatego dowód porównuje różnice względem startu.

", + "steps": [] + }, + { + "id": "task03.a8", + "kind": "block", + "title": "A8 PATTERNS · AKTYWNE — validate then commit", + "content_html": "

Wzorzec silnej gwarancji błędu brzmi: najpierw policz bez przepełnienia, następnie sprawdź granice, a dopiero potem zmień jedyny stan. Wskaźnik break pozostaje obserwowalnie niezmieniony po odrzuconej operacji.

", + "steps": [] + }, + { + "id": "task03.proof", + "kind": "exercise", + "title": "Przewidywanie → wykonanie → wniosek", + "content_html": "", + "steps": [] + }, + { + "id": "task03.worksheet", + "kind": "block", + "title": "TASK03 · Zapis dowodu ucznia", + "content_html": "

1. Przewidywanie przed uruchomieniem \\noindent \\noindent 2. Wynik programu hostowego \\noindent \\noindent 3. Wynik RV32I i kod wyjścia \\noindent \\noindent 4. Wniosek: reguła języka lub kontrakt targetu potwierdzony przez pomiar \\noindent \\noindent

", + "steps": [] + } + ] + } + ], + "assets": [], + "steps": [], + "spread_group": "", + "spread_label": "", + "spread_columns": 1, + "spread_index": 1, + "spread_count": 1, + "page_orientation": "portrait" + }, + { + "id": "section-8-task04", + "index": 8, + "title": "TASK04 — Wyrównany smalloc append-only", + "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\n\n\n\n\n\n\n\n\n\n
TITLEsmalloc, sbrk i minimalne libc
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C na RV32I
SERIESC · Freestanding RV32I and K&R
CARD09/13
SHEET9/10
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID47826ae5-6370-5ac2-bd91-9acb89116d40CARD UUID8e4f8bee-41f0-523b-8ea2-8926bd3d7ab0AUTHOR  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\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
", + "left_margin_html": "
TECH
", + "right_margin_html": "
OG
", + "content_html": "", + "tasks": [ + { + "ref": "task04", + "title": "Wyrównany smalloc append-only", + "uuid": "e745e1ea-9494-5b75-9596-816022153237", + "criterion": "Host i Hazard3: header=16, first=32, second=48, delta=32, aligned=1, metadata=1, append=1, reset=1, pass=1 i kod 0. Nagłówki mają sequence 1 i 2; po resecie pierwszy payload wraca pod poprzedni pierwszy adres.", + "conclusion_html": "", + "prompt_html": "

Dla żądań 1 B i 17 B wyprowadź rozmiar nagłówka, rezerwację po align-up, adres obu payloadów i zmianę break. Wskaż, dlaczego brak c09_sfree jest częścią kontraktu, a reset areny nie jest odpowiednikiem free(pointer).

", + "flow": [ + { + "id": "task04.a1", + "kind": "block", + "title": "A1 CONTEXT · AKTYWNE — API ma celowo małą władzę", + "content_html": "

Zachowane materiały: src/tasks/task04_smalloc.c, src/runtime/c09_smalloc.c, src/runtime/c09_smalloc.h, src/runtime/c09_bounded_sbrk.c, src/runtime/c09_bounded_sbrk.h. Klient może przydzielić payload i zresetować całą arenę. Nie może zwolnić jednego bloku ani przekazać modelowi wskaźnika do picolibc. c09_smalloc pobiera surowy fragment wyłącznie przez ograniczone c09_sbrk.

", + "steps": [] + }, + { + "id": "task04.a2", + "kind": "block", + "title": "A2 STRUCTURE · AKTYWNE — 16 B metadanych bezpośrednio przed payloadem", + "content_html": "

Nagłówek ma cztery pola uint32_t: magic, requested, reserved i sequence. Jego rozmiar wynosi 16 B. Zwrócony adres to header+1; inspekcja kontrolnie cofa się o dokładnie jeden rzeczywisty nagłówek.

", + "steps": [] + }, + { + "id": "task04.a3", + "kind": "block", + "title": "A3 DISPATCH · N/D", + "content_html": "

N/D. smalloc, inspect, reset i c09_sbrk są zwykłymi wywołaniami bezpośrednimi; przykład nie zawiera callbacku, ISR ani dynamicznie wybieranej strategii.

", + "steps": [] + }, + { + "id": "task04.a4", + "kind": "block", + "title": "A4 APPLICATION · AKTYWNE — geometria dwóch bloków", + "content_html": "

Żądanie 1 B daje align16(16+1)=32; żądanie 17 B daje align16(16+17)=48. Pierwszy payload leży 16 B od startu, drugi 48 B od startu, więc ich delta wynosi 32 B. Oba adresy są wielokrotnością 16.

", + "steps": [] + }, + { + "id": "task04.a5", + "kind": "block", + "title": "A5 FLOW · AKTYWNE — size, align, reserve, header, payload", + "content_html": "

Kod odrzuca zero i przepełnienie, zaokrągla sumę nagłówka i żądania, sprawdza reprezentowalność jako ptrdiff_t, rezerwuje cały blok jednym c09_sbrk, zapisuje cztery pola nagłówka i dopiero wtedy zwraca payload.

", + "steps": [] + }, + { + "id": "task04.a6", + "kind": "block", + "title": "A6 STATE · AKTYWNE — EMPTY, TWO BLOCKS, RESET", + "content_html": "

Arena przechodzi EMPTY -> seq1 -> seq1+seq2. Brak indywidualnego free oznacza, że break tylko rośnie. c09_smalloc_reset wykonuje jedno przejście z dowolnej zawartości do EMPTY i unieważnia oba wskaźniki naraz.

", + "steps": [] + }, + { + "id": "task04.a7", + "kind": "block", + "title": "A7 RUNTIME · AKTYWNE — pamięć potwierdza header przed payloadem", + "content_html": "

W checkpointcie odczytaj first-16: słowo magic to 0x534D414C, requested=1, reserved=32, sequence=1. Pod second-16 odpowiednie wartości to 17, 48 i 2. Globale potwierdzają deltę 32 i reset.

", + "steps": [] + }, + { + "id": "task04.a8", + "kind": "block", + "title": "A8 PATTERNS · AKTYWNE — bump allocator z jawną granicą użycia", + "content_html": "

Append-only arena jest wartościowa dla fazowego scratch storage, gdy wszystkie obiekty mają wspólny czas życia. Nie zastępuje ogólnego malloc: brak selekcji, ponownego użycia pojedynczych luk, split, coalescing i niezależnego free.

", + "steps": [] + }, + { + "id": "task04.proof", + "kind": "exercise", + "title": "Przewidywanie → wykonanie → wniosek", + "content_html": "", + "steps": [] + }, + { + "id": "task04.worksheet", + "kind": "block", + "title": "TASK04 · Zapis dowodu ucznia", + "content_html": "

1. Przewidywanie przed uruchomieniem \\noindent \\noindent 2. Wynik programu hostowego \\noindent \\noindent 3. Wynik RV32I i kod wyjścia \\noindent \\noindent 4. Wniosek: reguła języka lub kontrakt targetu potwierdzony przez pomiar \\noindent \\noindent

", + "steps": [] + } + ] + } + ], + "assets": [], + "steps": [], + "spread_group": "", + "spread_label": "", + "spread_columns": 1, + "spread_index": 1, + "spread_count": 1, + "page_orientation": "portrait" + }, + { + "id": "section-9-task05", + "index": 9, + "title": "TASK05 — malloc/free picolibc jako czarna skrzynka", + "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\n\n\n\n\n\n\n\n\n\n
TITLEsmalloc, sbrk i minimalne libc
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C na RV32I
SERIESC · Freestanding RV32I and K&R
CARD09/13
SHEET10/10
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID47826ae5-6370-5ac2-bd91-9acb89116d40CARD UUID8e4f8bee-41f0-523b-8ea2-8926bd3d7ab0AUTHOR  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\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
", + "left_margin_html": "
TECH
", + "right_margin_html": "
OG
", + "content_html": "", + "tasks": [ + { + "ref": "task05", + "title": "malloc/free picolibc jako czarna skrzynka", + "uuid": "9a7174f1-efb7-5c18-afbe-1a34ee6da0b7", + "criterion": "Host i Hazard3: nonnull=1, delta_nonzero=1, checksum=4612, nonoverlap=1, aligned=1, freed=1, pass=1 i kod 0. Mapa RV32I zawiera libc_stdlib_malloc.c.o, libc_stdlib_free.c.o i libc_misc_picosbrk.c.o. ELF definiuje _sbrk, sbrk, malloc, free, __heap_start i __heap_end.", + "conclusion_html": "", + "prompt_html": "

Nie zakładając formatu nagłówka libc, wypisz własności możliwe do sprawdzenia przez klienta dwóch przydziałów. Uruchom host i Hazard3, sprawdź checksum oraz mapę, a w ELF wykaż współistnienie vendorowego _sbrk i picolibc sbrk.

", + "flow": [ + { + "id": "task05.a1", + "kind": "block", + "title": "A1 CONTEXT · AKTYWNE — klient nie zna wnętrza picolibc", + "content_html": "

Zachowane materiały: src/tasks/task05_picolibc_malloc.c, crt0.S, link/hazard3_c09.ld. Kod tasku używa tylko malloc i free. Linker łączy picolibc z platformą przez sbrk oraz symbole granic. Vendorowe _sbrk pozostaje osobnym, nieużywanym przez malloc symbolem startu Hazard3.

", + "steps": [] + }, + { + "id": "task05.a2", + "kind": "block", + "title": "A2 STRUCTURE · AKTYWNE — obraz składa się z czterech warstw", + "content_html": "

ELF zawiera klienta, człony malloc/free, człon picosbrk i platformowy startup. Skrypt linkera dostarcza __heap_start/__heap_end; crt0 ustawia gp/tp i zeruje BSS/TBSS. Mapa pokazuje, który obiekt wniósł każdy publiczny symbol.

", + "steps": [] + }, + { + "id": "task05.a3", + "kind": "block", + "title": "A3 DISPATCH · N/D", + "content_html": "

N/D. Klient wywołuje malloc i free bezpośrednio; badany przebieg nie przekazuje callbacku, nie obsługuje ISR i nie wybiera alokatora przez tablicę funkcji.

", + "steps": [] + }, + { + "id": "task05.a4", + "kind": "block", + "title": "A4 APPLICATION · AKTYWNE — kontrakt dwóch niezależnych payloadów", + "content_html": "

Program żąda 13 B i 29 B, zapisuje dwie różne sekwencje, sumuje odczytane bajty do 4612 i sprawdza rozłączność półotwartych zakresów adresów. Mierzy co najmniej 8-bajtowe wyrównanie, ale nie narzuca odległości między blokami.

", + "steps": [] + }, + { + "id": "task05.a5", + "kind": "block", + "title": "A5 FLOW · AKTYWNE — allocate, use, verify, release", + "content_html": "

Po dwóch udanych przydziałach kod zapisuje i natychmiast odczytuje oba zakresy, oblicza checksum i warunki adresowe, zwalnia najpierw drugi, potem pierwszy blok, ustawia freed=1 i zatrzymuje się w checkpointcie.

", + "steps": [] + }, + { + "id": "task05.a6", + "kind": "block", + "title": "A6 STATE · AKTYWNE — własność payloadu kończy się w free", + "content_html": "

Każdy wskaźnik przechodzi od braku zasobu do stanu OWNED po udanym malloc, następnie USED po zapisie i RELEASED po free. Program nie dereferencjuje wskaźnika w RELEASED i nie bada, czy następny malloc odzyska ten sam adres.

", + "steps": [] + }, + { + "id": "task05.a7", + "kind": "block", + "title": "A7 RUNTIME · AKTYWNE — wykonanie plus audyt ELF", + "content_html": "

Hazard3 kończy program kodem 0; globale pokazują checksum 4612, rozłączność, alignment i oba free. nm musi równocześnie pokazać _sbrk oraz sbrk, a mapa trzy człony picolibc związane z malloc, free i dostawcą pamięci.

", + "steps": [] + }, + { + "id": "task05.a8", + "kind": "block", + "title": "A8 PATTERNS · AKTYWNE — test kontraktu bez zgadywania implementacji", + "content_html": "

Poprawny test czarnej skrzynki wymusza własności API, ale nie zależy od prywatnego nagłówka, kierunku wzrostu sterty, dokładnej delty adresów ani ponownego użycia po free. Dzięki temu pozostaje wartościowy po zmianie implementacji libc.

", + "steps": [] + }, + { + "id": "task05.proof", + "kind": "exercise", + "title": "Przewidywanie → wykonanie → wniosek", + "content_html": "", + "steps": [] + }, + { + "id": "task05.worksheet", + "kind": "block", + "title": "TASK05 · Zapis dowodu ucznia", + "content_html": "

1. Przewidywanie przed uruchomieniem \\noindent \\noindent 2. Wynik programu hostowego \\noindent \\noindent 3. Wynik RV32I i kod wyjścia \\noindent \\noindent 4. Wniosek: reguła języka lub kontrakt targetu potwierdzony przez pomiar \\noindent \\noindent

", + "steps": [] + } + ] + } + ], + "assets": [], + "steps": [], + "spread_group": "", + "spread_label": "", + "spread_columns": 1, + "spread_index": 1, + "spread_count": 1, + "page_orientation": "portrait" + } + ], + "viewpoints": [], + "has_spread": false, + "has_allocator_model": false, + "dictionary": null, + "toc": [ + { + "id": "section-1-content", + "label": "1. 1 — Funkcja z libc nie oznacza automatycznie sterty" + }, + { + "id": "section-2-content", + "label": "2. 2 — malloc potrzebuje sbrk, lecz _sbrk to inna nazwa" + }, + { + "id": "section-3-content", + "label": "3. 3 — Od alloc z K&R 5.4 do bounded sbrk i smalloc" + }, + { + "id": "section-4-content", + "label": "4. 4 — Prawdziwe malloc/free jako czarna skrzynka" + }, + { + "id": "section-5-task01", + "label": "5. TASK01 — strlen z libc bez sterty" + }, + { + "id": "section-6-task02", + "label": "6. TASK02 — Kontrolowany brak dostawcy sbrk" + }, + { + "id": "section-7-task03", + "label": "7. TASK03 — Bounded sbrk i atomowy błąd" + }, + { + "id": "section-8-task04", + "label": "8. TASK04 — Wyrównany smalloc append-only" + }, + { + "id": "section-9-task05", + "label": "9. TASK05 — malloc/free picolibc jako czarna skrzynka" + } + ] +} diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000..8f9f9f5 --- /dev/null +++ b/web/index.html @@ -0,0 +1,15 @@ + + + + + + + Karta pracy + + + + +
+ + + diff --git a/web/style.css b/web/style.css new file mode 100644 index 0000000..3b75b2b --- /dev/null +++ b/web/style.css @@ -0,0 +1,39 @@ + +:root{--ink:#111;--muted:#666;--line:#b9b9b9;--line-soft:#dddddd;--paper:#fff;--desk:#eeeeee;--og:#008000;--tech:#d36b00;--kw:#0018c8;--we:#e00000;--viewer-canvas-scale:1;--viewer-content-scale:1} +*{box-sizing:border-box} html{scroll-behavior:smooth} body{margin:0;background:var(--desk);color:var(--ink);font-family:"Latin Modern Roman","LM Roman 12",Georgia,"Times New Roman",serif;line-height:1.25} +.topbar{position:sticky;top:0;z-index:20;background:rgba(245,245,245,.94);border-bottom:1px solid #d0d0d0;padding:3px 0;font-family:system-ui,-apple-system,Segoe UI,sans-serif} +.topbar-inner{width:calc(100% - 8px);max-width:none;margin:0 4px;display:flex;align-items:center;justify-content:space-between;gap:6px}.topbar details{min-width:0;flex:1}.topbar summary{cursor:pointer;font-size:16px;line-height:1.35;font-weight:650}.toc-links{display:flex;flex-wrap:wrap;gap:6px;margin-top:5px}.toc-links a{font-size:16px;color:#333;text-decoration:none;border:1px solid #ccc;background:white;border-radius:3px;padding:2px 5px}.viewer-zoom-controls{display:flex;align-items:center;gap:7px;flex:none}.viewer-zoom-status{font:600 16px/1.4 ui-monospace,SFMono-Regular,Consolas,monospace;color:#444;white-space:nowrap}.viewer-zoom-reset{border:1px solid #bbb;border-radius:3px;background:#fff;color:#333;padding:1px 6px;font:600 16px/1.35 system-ui,-apple-system,Segoe UI,sans-serif;cursor:pointer}.viewer-zoom-reset:hover{background:#eee}.viewer-zoom-reset:focus-visible{outline:2px solid #555;outline-offset:1px} +.paper{padding:18px 12px 44px;overflow-x:auto}.sheet{position:relative;width:210mm;min-height:297mm;margin:0 auto 18px;background:var(--paper);box-shadow:0 2px 12px rgba(0,0,0,.13);display:block;padding:0;overflow:visible;zoom:var(--viewer-canvas-scale)}.sheet-content{position:relative;width:100%;min-height:297mm;padding:13mm 21.5mm 15mm;transform:scale(var(--sheet-effective-scale,1));transform-origin:top left}.resource-header-enabled .sheet-content{padding-top:5mm}.sheet-content>.page-resource-header{margin-bottom:3mm} +@media(max-width:900px){.sheet{height:auto}}@media print{.sheet{height:auto}} +.pdf-main{min-width:0;width:100%}.running-header{display:flex;justify-content:space-between;gap:18px;align-items:flex-end;border-bottom:1px solid #111;padding-bottom:3px;margin-bottom:26px;font-size:15px}.running-header span{white-space:nowrap} +.hero h1{font-size:24px;line-height:1.15;margin:0 0 4px;border-bottom:1px solid #111;padding-bottom:4px}.hero .byline{float:right;margin-top:-31px;font-size:15px} +.meta{clear:both;display:grid;grid-template-columns:148px minmax(0,1fr);gap:4px 18px;padding:34px 0 24px;border-bottom:1px solid #111;font-size:17px}.meta dt{color:#333}.meta dd{margin:0;font-family:"Latin Modern Mono",ui-monospace,SFMono-Regular,Consolas,monospace} +.front-scope{padding:0 0 3mm;border-bottom:1px solid var(--line-soft)}.front-scope h2{font-size:24px;line-height:1.15;margin:0 0 3mm}.front-scope p{font-size:16px} +.scope-table-wrap{margin:3mm 0;overflow:hidden}.scope-table{width:100%;border-collapse:collapse;font-family:"Latin Modern Mono",ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px;line-height:1.22}.scope-table th,.scope-table td{border:0;border-bottom:1px solid #888;padding:4px 7px;text-align:left;vertical-align:top}.scope-table th{border-bottom:2px solid #555;background:#f3f3f3;font-weight:700}.scope-table th:first-child,.scope-table td:first-child{width:7%}.scope-table--task th:nth-child(2),.scope-table--task td:nth-child(2){width:11%}.scope-table--task th:nth-child(4),.scope-table--task td:nth-child(4){width:19%}.scope-table--task th:nth-child(5),.scope-table--task td:nth-child(5){width:14%}.scope-table--task th:nth-child(6),.scope-table--task td:nth-child(6){width:10%}.scope-table tr.scope-row--key td{font-weight:700;background:#f4f4f4;border-top:2px solid #111;border-bottom:2px solid #111}.scope-table tr.scope-row--key td:first-child{border-left:2px solid #111}.scope-table tr.scope-row--key td:last-child{border-right:2px solid #111}.scope-table td p{font:inherit;margin:0}.scope-table code{font-size:inherit}.scope-status{display:inline-block;white-space:nowrap;border:1px solid #aaa;border-radius:2px;padding:1px 4px;font-weight:600;background:#f5f5f5}.scope-status[data-status="in-progress"]{border-color:#307da1;background:#eaf5fa;color:#174f69}.scope-status[data-status="ready"]{border-color:#4c7d56;background:#edf6ee;color:#295b33}.scope-status[data-status="draft"],.scope-status[data-status="review"]{border-color:#9a7932;background:#faf4e5;color:#694f16}.scope-status[data-status="blocked"]{border-color:#9c4b4b;background:#faeded;color:#712f2f} +.card-section h2{font-size:24px;line-height:1.15;margin:0 0 4mm}.section-heading{display:flex;align-items:flex-start;gap:0}.section-heading .section-index{font-family:"Latin Modern Mono",ui-monospace,SFMono-Regular,Consolas,monospace;font-size:23px;margin-right:12mm;font-weight:400}.section-heading .section-title{min-width:0}.task-identity{margin-left:auto;padding-left:22px;text-align:right;font-family:"Latin Modern Mono",ui-monospace,SFMono-Regular,Consolas,monospace;font-size:10px;line-height:1.25;color:#555;white-space:nowrap}.task-identity strong,.task-identity-name,.task-identity code{display:block}.task-identity strong{font-size:12px;color:#111}.task-identity-name{max-width:240px;overflow:hidden;text-overflow:ellipsis}.task-identity code{font-size:9px;color:#777} +p{font-size:16px;margin:0 0 3mm}.pdf-main ul{font-size:16px;margin:2mm 0 3mm 7mm;padding:0}.pdf-main li{margin:1.2mm 0} +.pdf-margin{position:absolute;top:34mm;width:18mm;font-family:"Latin Modern Mono",ui-monospace,SFMono-Regular,Consolas,monospace;font-size:5px;line-height:1.12;color:#333;max-height:245mm;overflow:hidden}.pdf-margin.left{left:2mm;text-align:left}.pdf-margin.right{right:2mm;text-align:left} +.margin-title{font-weight:700;color:#666;margin-bottom:3px;letter-spacing:.02em}.margin-list{display:flex;flex-direction:column;align-items:flex-start}.margin-tag{display:block;margin:0 0 1px;padding:0;border:0;background:transparent;font:inherit;line-height:inherit;text-align:left;cursor:pointer;margin-left:var(--indent)}.margin-tag.we{color:var(--we)}.margin-tag.og,.margin-tag.tech{color:var(--og)}.margin-tag.kw{color:var(--kw)}.margin-tag .local{color:#777}.margin-tag:hover{text-decoration:underline}.margin-empty{color:#aaa} +.step-map{font-family:"Latin Modern Mono",ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px;line-height:1.3;color:#5c5c5c;background:transparent;border:0;border-top:1px solid #cfcfcf;border-bottom:1px solid #e0e0e0;border-radius:0;padding:8px 0;margin:0 0 16px}.step-map summary{cursor:pointer;font-weight:400;color:#555} +.tree-legend{display:flex;flex-wrap:wrap;gap:4px;margin:7px 0}.steps{display:grid;gap:6px}.step-row{border-top:1px dashed #c9c9c9;padding-top:6px}.step-row:first-child{border-top:0}.step-title span{font-weight:700;margin-right:7px}.step-trees{display:flex;flex-wrap:wrap;gap:4px;margin-top:3px}.step-refs{display:flex;flex-wrap:wrap;gap:6px;margin-top:3px}.step-refs a{font-size:10px;color:#666} +.tree-token{font:10px/1 "Latin Modern Mono",ui-monospace,SFMono-Regular,Consolas,monospace;border:1px solid #c8c8c8;background:#fff;border-radius:3px;padding:3px 5px;cursor:pointer}.tree-token.active{background:#111;color:white;border-color:#111} +.equation{display:grid;grid-template-columns:1fr auto;align-items:center;gap:14px;margin:18px 0;padding:4px 0;background:transparent;border:0}.equation .display{font-size:17px}.equation-number{font-family:"Latin Modern Mono",ui-monospace,SFMono-Regular,Consolas,monospace;font-size:15px} +figure{margin:24px 0;text-align:center}figure img{max-width:100%;display:block;margin:0 auto;border:0;border-radius:0}figcaption{font-size:14px;color:#444;margin-top:8px;text-align:left}.card-asset.asset-screenshot img{border:1px solid #aaa}.card-asset a{display:block;cursor:zoom-in} +.table-wrap{overflow:auto;margin:14px 0}table{border-collapse:collapse;width:100%;font-size:16px}th,td{border:1px solid #111;padding:5px 8px;text-align:left;vertical-align:top}th{font-weight:400;background:white} +.empty-check{display:inline-block;width:1em;height:1em;border:1px solid #111;vertical-align:-.12em}.answer-line,.dotfill{display:block;border-bottom:1px dotted #111;height:1.45em;min-width:10em}.write-row{display:block;min-height:2.8em} +code{font-family:"Latin Modern Mono",ui-monospace,SFMono-Regular,Consolas,monospace}.tasks{font-size:16px}.task-legacy{margin:2.5mm 0}.task-legacy>strong{display:block;font:700 10px/1.2 "Latin Modern Mono",ui-monospace,monospace;color:#555}.task-flow{border:1px solid #222;margin:1mm 0 2mm;background:#fff}.task-flow-header{display:grid;grid-template-columns:auto 1fr auto;align-items:baseline;gap:6px;padding:5px 7px;background:#eaeaea;border-bottom:1px solid #222}.task-flow-header span{font:700 10px/1.2 "Latin Modern Mono",ui-monospace,monospace;color:#222}.task-flow-header h3{font-size:18px;margin:0}.task-flow-header code{font-size:8px;color:#555}.task-block{margin:6px 7px;padding:5px 6px;border:1px solid #777;background:#fff}.task-block header,.task-exercise header{display:flex;align-items:baseline;gap:5px;margin-bottom:3px}.task-block header span,.task-exercise header span{font:700 9px/1.2 "Latin Modern Mono",ui-monospace,monospace;text-transform:uppercase;color:#555}.task-block h4,.task-exercise h4{font-size:16px;margin:0}.block-steps{margin:4px 0 0 16px!important;padding:0;display:grid;gap:3px}.block-steps li{margin:0;border:1px solid #b9b9b9;padding:4px 5px;background:#fff}.block-steps li::marker{font-family:"Latin Modern Mono",ui-monospace,monospace;font-weight:700}.block-steps li p:last-child{margin-bottom:0}.task-exercise{margin:6px 7px;border:1px solid #777;border-left:1px solid #222;padding:5px 6px;background:#fafafa}.task-exercise header{flex-wrap:wrap}.exercise-based-on{margin-left:auto;font-size:8px;color:#777}.exercise-evidence{border-top:1px dashed #bbb;margin-top:5px;padding-top:4px}.exercise-evidence>strong{font-size:11px;text-transform:uppercase}.exercise-criterion{font-size:13px;margin:4px 0 0}.task-flow>footer{padding:5px 7px;border-top:1px solid #222;font-size:12px;background:#f6f6f6}.task-conclusion{margin:8px 0;padding:7px 9px;border:1px solid #315f78;background:#f3f9fc}.task-conclusion>strong{display:block;margin-bottom:3px;font:700 10px/1.2 "Latin Modern Mono",ui-monospace,monospace;color:#315f78}.task-conclusion p{margin:0}.we-block{border-top:1px solid #ddd;padding:8px 0}.we-block summary{cursor:pointer}.dictionary-sheet .pdf-margin{display:none} +.inspector{position:fixed;right:14px;bottom:14px;width:min(360px,calc(100vw - 28px));max-height:46vh;overflow:auto;background:white;border:1px solid #cfcfcf;box-shadow:0 4px 18px rgba(0,0,0,.18);border-radius:6px;padding:12px;font-family:system-ui,-apple-system,Segoe UI,sans-serif;font-size:13px;z-index:30}.inspector h2{font-size:14px;margin:0 0 8px}.inspector .empty{color:#777}.tree-card h3{font-size:15px;margin:6px 0}.tree-card code{display:inline-block;margin:4px 0}.tree-card .line{font-weight:700}.tree-card .line.OG{color:var(--og)}.tree-card .line.TECH{color:var(--tech)}.kw-list{padding-left:18px}.kw-list code{color:var(--kw)} +@media(max-width:900px){.sheet{display:block;min-height:0}.sheet-content{min-height:0;padding:26px 18px}.pdf-margin{position:static;max-height:none;overflow:visible;margin:10px 0;padding:8px;border:1px solid #ddd}.pdf-margin.left{border-left:3px solid var(--tech)}.pdf-margin.right{border-left:3px solid var(--og)}.hero .byline{float:none;margin:0 0 14px}.meta{grid-template-columns:1fr}.section-heading{flex-wrap:wrap}.task-identity{width:100%;padding:6px 0 0}.inspector{position:static;width:auto;max-height:none;margin:0 12px 18px}.topbar{position:sticky;top:0}.viewer-zoom-status{font-size:16px}} +@media print{html,body{background:white}.topbar,.inspector{display:none}.paper{padding:0}.sheet{position:relative;display:block;width:auto;min-height:0;margin:0;box-shadow:none;break-after:page;padding:0;overflow:visible;zoom:1!important}.sheet-content{position:relative;width:auto;min-height:0;padding:0;transform:none!important}.sheet:last-child{break-after:auto}.resource-header-enabled .sheet-content{padding:0}.sheet-content>.page-resource-header,.sheet-content>.page-resource-footer{display:none!important}.pdf-margin{position:absolute;top:0;width:18mm;max-height:none;overflow:hidden;margin:0;padding:0;border:0}.pdf-margin.left{left:-19.5mm}.pdf-margin.right{right:-19.5mm}.task-block,.task-exercise,.block-steps li,figure{break-inside:avoid}} + +.page-resource-header{width:100%;height:24mm;min-height:24mm;max-height:24mm;background:#fff;color:#111;overflow:hidden;font-family:ui-monospace,SFMono-Regular,"Latin Modern Mono",Consolas,monospace;line-height:1.08} +.resource-header-table{width:100%;height:100%;border-collapse:collapse;table-layout:fixed;border:1px solid #111}.resource-header-table>tbody>tr{height:100%}.resource-header-center{height:100%;padding:0;vertical-align:middle;overflow:hidden}.resource-header-grid{display:grid;grid-template-rows:3fr 3fr 3fr 2fr 2fr;width:100%;height:100%}.resource-header-row{display:grid;min-width:0;min-height:0}.resource-header-field{display:flex;flex-direction:column;align-items:stretch;justify-content:space-between;gap:.08mm;min-width:0;padding:.28mm .55mm;border-right:1px solid #888;border-bottom:1px solid #aaa;overflow:hidden;white-space:nowrap}.resource-header-row .resource-header-field:last-child{border-right:0}.resource-header-row:last-child .resource-header-field{border-bottom:0}.resource-header-field a{display:flex;flex-direction:column;align-items:flex-start;gap:.08mm;min-width:0;color:#111;text-decoration:none}.resource-label{align-self:flex-start;font:800 3.2pt/1 ui-monospace,SFMono-Regular,"Latin Modern Mono",Consolas,monospace;text-transform:uppercase;flex:none}.resource-value{align-self:flex-end;max-width:100%;text-align:right;font:700 6.4pt/1 ui-monospace,SFMono-Regular,"Latin Modern Mono",Consolas,monospace;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.resource-header-field--title .resource-value{font-size:7.7pt;font-weight:800}.resource-header-field--emphasis .resource-value{font-size:6.6pt;font-weight:800}.resource-header-field--compact{gap:.05mm;padding:.2mm .2mm}.resource-header-field--compact .resource-label{font-size:2.85pt}.resource-header-field--compact .resource-value{font-size:4.45pt}.resource-header-field--identity{display:flex;flex-direction:column;align-items:stretch;justify-content:center;gap:.15mm;padding:.12mm .45mm;font:700 3.55pt/1.1 ui-monospace,SFMono-Regular,"Latin Modern Mono",Consolas,monospace}.resource-header-field--identity>span{display:flex;align-items:baseline;gap:.3mm;min-width:0}.resource-header-field--identity b{font-weight:800;flex:none}.resource-header-field--identity .resource-identity-value{margin-left:auto;text-align:right}.resource-header-field--identity .resource-author{margin-left:auto;text-align:right}.resource-header-field--url-row{display:flex;align-items:stretch;justify-content:center;padding:.2mm .55mm}.resource-header-field--url-row a{display:block;overflow:hidden;text-overflow:clip;font:700 4.9pt/1.05 ui-monospace,SFMono-Regular,"Latin Modern Mono",Consolas,monospace}.resource-header-field--url-row b{font-weight:800} +.resource-qr-cell{height:100%;padding:0;vertical-align:middle;overflow:hidden}.resource-qr-cell--left{border-right:1px solid #777}.resource-qr-cell--right{border-left:1px solid #777}.resource-qr{box-sizing:border-box;width:100%;height:100%;display:flex;align-items:center;justify-content:center;padding:.4mm;color:#333;text-decoration:none}.resource-qr .title-qr{display:block;width:22mm;height:22mm;max-width:22mm;max-height:22mm;flex:none}.resource-qr-empty{text-align:center}.resource-qr-empty span,.resource-qr-empty strong{display:block;font:600 5pt/1.15 ui-monospace,SFMono-Regular,Consolas,monospace} + +@page{ + size:A4; + margin:29mm 21.5mm 5mm; + @top-left{content:"";width:24mm;height:24mm;box-sizing:border-box;padding:0;border:1px solid #111;background-color:#fff;background-repeat:no-repeat;background-position:center;background-size:22mm 22mm;vertical-align:middle;text-align:center;font:0/0 sans-serif;color:transparent;background-image:url("data:image/svg+xml;base64,PHN2ZyBjbGFzcz0idGl0bGUtcXIiIHJvbGU9ImltZyIgYXJpYS1sYWJlbD0iS29kIFFSOiBodHRwczovL3pzbC1naXRlYS5tcGFiaS5wbC9lZHUtaW5mL2xhYi1ydjMyaS1jLXNtYWxsb2Mtc2Jyay1saWJjIiB2ZXJzaW9uPScxLjEnIHhtbG5zPSdodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZycgeG1sbnM6eGxpbms9J2h0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsnIHdpZHRoPSc4NS4wMzkxOTZwdCcgaGVpZ2h0PSc4NS4wMzkxOTZwdCcgdmlld0JveD0nLTcyLjAwMDAwNCAtNzIuMDAwMDA0IDg1LjAzOTE5NiA4NS4wMzkxOTYnPgo8ZyBpZD0ncGFnZTEnPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSctNzIuMDAwMDA0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY5LjQyMzA1OScgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02Ni44NDYxMTQnIHk9Jy03Mi4wMDAwMDQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjQuMjY5MTY4JyB5PSctNzIuMDAwMDA0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTYxLjY5MjIyMycgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01OS4xMTUyNzgnIHk9Jy03Mi4wMDAwMDQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTYuNTM4MzMyJyB5PSctNzIuMDAwMDA0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTUxLjM4NDQ0MicgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00OC44MDc0OTYnIHk9Jy03Mi4wMDAwMDQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDYuMjMwNTUxJyB5PSctNzIuMDAwMDA0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQzLjY1MzYwNScgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zNS45MjI3NjknIHk9Jy03Mi4wMDAwMDQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzAuNzY4ODc5JyB5PSctNzIuMDAwMDA0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTI1LjYxNDk4OCcgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xNy44ODQxNTInIHk9Jy03Mi4wMDAwMDQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTUuMzA3MjA3JyB5PSctNzIuMDAwMDA0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQuOTk5NDI1JyB5PSctNzIuMDAwMDA0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIuNDIyNDgnIHk9Jy03Mi4wMDAwMDQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScuMTU0NDY1JyB5PSctNzIuMDAwMDA0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nMi43MzE0MTEnIHk9Jy03Mi4wMDAwMDQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSc1LjMwODM1NicgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzcuODg1MzAxJyB5PSctNzIuMDAwMDA0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nMTAuNDYyMjQ3JyB5PSctNzIuMDAwMDA0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nLTY5LjQyMzA1OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01Ni41MzgzMzInIHk9Jy02OS40MjMwNTknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDMuNjUzNjA1JyB5PSctNjkuNDIzMDU5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQxLjA3NjY2JyB5PSctNjkuNDIzMDU5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTM4LjQ5OTcxNScgeT0nLTY5LjQyMzA1OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zMC43Njg4NzknIHk9Jy02OS40MjMwNTknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjUuNjE0OTg4JyB5PSctNjkuNDIzMDU5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIzLjAzODA0MycgeT0nLTY5LjQyMzA1OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yMC40NjEwOTcnIHk9Jy02OS40MjMwNTknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTUuMzA3MjA3JyB5PSctNjkuNDIzMDU5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQuOTk5NDI1JyB5PSctNjkuNDIzMDU5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nMTAuNDYyMjQ3JyB5PSctNjkuNDIzMDU5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nLTY2Ljg0NjExNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02Ni44NDYxMTQnIHk9Jy02Ni44NDYxMTQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjQuMjY5MTY4JyB5PSctNjYuODQ2MTE0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTYxLjY5MjIyMycgeT0nLTY2Ljg0NjExNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01Ni41MzgzMzInIHk9Jy02Ni44NDYxMTQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDguODA3NDk2JyB5PSctNjYuODQ2MTE0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQzLjY1MzYwNScgeT0nLTY2Ljg0NjExNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zOC40OTk3MTUnIHk9Jy02Ni44NDYxMTQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzUuOTIyNzY5JyB5PSctNjYuODQ2MTE0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTMwLjc2ODg3OScgeT0nLTY2Ljg0NjExNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xNy44ODQxNTInIHk9Jy02Ni44NDYxMTQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTIuNzMwMjYxJyB5PSctNjYuODQ2MTE0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQuOTk5NDI1JyB5PSctNjYuODQ2MTE0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLjE1NDQ2NScgeT0nLTY2Ljg0NjExNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzIuNzMxNDExJyB5PSctNjYuODQ2MTE0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nNS4zMDgzNTYnIHk9Jy02Ni44NDYxMTQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScxMC40NjIyNDcnIHk9Jy02Ni44NDYxMTQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSctNjQuMjY5MTY4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY2Ljg0NjExNCcgeT0nLTY0LjI2OTE2OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02NC4yNjkxNjgnIHk9Jy02NC4yNjkxNjgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjEuNjkyMjIzJyB5PSctNjQuMjY5MTY4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTU2LjUzODMzMicgeT0nLTY0LjI2OTE2OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00Ni4yMzA1NTEnIHk9Jy02NC4yNjkxNjgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDMuNjUzNjA1JyB5PSctNjQuMjY5MTY4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTM4LjQ5OTcxNScgeT0nLTY0LjI2OTE2OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zMy4zNDU4MjQnIHk9Jy02NC4yNjkxNjgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzAuNzY4ODc5JyB5PSctNjQuMjY5MTY4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTI4LjE5MTkzMycgeT0nLTY0LjI2OTE2OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yNS42MTQ5ODgnIHk9Jy02NC4yNjkxNjgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTcuODg0MTUyJyB5PSctNjQuMjY5MTY4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTEyLjczMDI2MScgeT0nLTY0LjI2OTE2OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xMC4xNTMzMTYnIHk9Jy02NC4yNjkxNjgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNC45OTk0MjUnIHk9Jy02NC4yNjkxNjgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScuMTU0NDY1JyB5PSctNjQuMjY5MTY4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nMi43MzE0MTEnIHk9Jy02NC4yNjkxNjgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSc1LjMwODM1NicgeT0nLTY0LjI2OTE2OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzEwLjQ2MjI0NycgeT0nLTY0LjI2OTE2OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy02MS42OTIyMjMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjYuODQ2MTE0JyB5PSctNjEuNjkyMjIzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY0LjI2OTE2OCcgeT0nLTYxLjY5MjIyMycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02MS42OTIyMjMnIHk9Jy02MS42OTIyMjMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTYuNTM4MzMyJyB5PSctNjEuNjkyMjIzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQ2LjIzMDU1MScgeT0nLTYxLjY5MjIyMycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00My42NTM2MDUnIHk9Jy02MS42OTIyMjMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDEuMDc2NjYnIHk9Jy02MS42OTIyMjMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzguNDk5NzE1JyB5PSctNjEuNjkyMjIzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTM1LjkyMjc2OScgeT0nLTYxLjY5MjIyMycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zMC43Njg4NzknIHk9Jy02MS42OTIyMjMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjUuNjE0OTg4JyB5PSctNjEuNjkyMjIzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIzLjAzODA0MycgeT0nLTYxLjY5MjIyMycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yMC40NjEwOTcnIHk9Jy02MS42OTIyMjMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTcuODg0MTUyJyB5PSctNjEuNjkyMjIzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTEwLjE1MzMxNicgeT0nLTYxLjY5MjIyMycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00Ljk5OTQyNScgeT0nLTYxLjY5MjIyMycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy4xNTQ0NjUnIHk9Jy02MS42OTIyMjMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScyLjczMTQxMScgeT0nLTYxLjY5MjIyMycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzUuMzA4MzU2JyB5PSctNjEuNjkyMjIzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nMTAuNDYyMjQ3JyB5PSctNjEuNjkyMjIzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nLTU5LjExNTI3OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01Ni41MzgzMzInIHk9Jy01OS4xMTUyNzgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDguODA3NDk2JyB5PSctNTkuMTE1Mjc4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQzLjY1MzYwNScgeT0nLTU5LjExNTI3OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zNS45MjI3NjknIHk9Jy01OS4xMTUyNzgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzAuNzY4ODc5JyB5PSctNTkuMTE1Mjc4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTI4LjE5MTkzMycgeT0nLTU5LjExNTI3OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yMC40NjEwOTcnIHk9Jy01OS4xMTUyNzgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTIuNzMwMjYxJyB5PSctNTkuMTE1Mjc4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTEwLjE1MzMxNicgeT0nLTU5LjExNTI3OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00Ljk5OTQyNScgeT0nLTU5LjExNTI3OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzEwLjQ2MjI0NycgeT0nLTU5LjExNTI3OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy01Ni41MzgzMzInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjkuNDIzMDU5JyB5PSctNTYuNTM4MzMyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY2Ljg0NjExNCcgeT0nLTU2LjUzODMzMicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02NC4yNjkxNjgnIHk9Jy01Ni41MzgzMzInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjEuNjkyMjIzJyB5PSctNTYuNTM4MzMyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTU5LjExNTI3OCcgeT0nLTU2LjUzODMzMicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01Ni41MzgzMzInIHk9Jy01Ni41MzgzMzInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTEuMzg0NDQyJyB5PSctNTYuNTM4MzMyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQ2LjIzMDU1MScgeT0nLTU2LjUzODMzMicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00MS4wNzY2NicgeT0nLTU2LjUzODMzMicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zNS45MjI3NjknIHk9Jy01Ni41MzgzMzInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzAuNzY4ODc5JyB5PSctNTYuNTM4MzMyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTI1LjYxNDk4OCcgeT0nLTU2LjUzODMzMicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yMC40NjEwOTcnIHk9Jy01Ni41MzgzMzInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTUuMzA3MjA3JyB5PSctNTYuNTM4MzMyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTEwLjE1MzMxNicgeT0nLTU2LjUzODMzMicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00Ljk5OTQyNScgeT0nLTU2LjUzODMzMicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yLjQyMjQ4JyB5PSctNTYuNTM4MzMyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLjE1NDQ2NScgeT0nLTU2LjUzODMzMicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzIuNzMxNDExJyB5PSctNTYuNTM4MzMyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nNS4zMDgzNTYnIHk9Jy01Ni41MzgzMzInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSc3Ljg4NTMwMScgeT0nLTU2LjUzODMzMicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzEwLjQ2MjI0NycgeT0nLTU2LjUzODMzMicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01MS4zODQ0NDInIHk9Jy01My45NjEzODcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDguODA3NDk2JyB5PSctNTMuOTYxMzg3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQxLjA3NjY2JyB5PSctNTMuOTYxMzg3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTM4LjQ5OTcxNScgeT0nLTUzLjk2MTM4NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zNS45MjI3NjknIHk9Jy01My45NjEzODcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzMuMzQ1ODI0JyB5PSctNTMuOTYxMzg3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIwLjQ2MTA5NycgeT0nLTUzLjk2MTM4NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy01MS4zODQ0NDInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjkuNDIzMDU5JyB5PSctNTEuMzg0NDQyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY0LjI2OTE2OCcgeT0nLTUxLjM4NDQ0MicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02MS42OTIyMjMnIHk9Jy01MS4zODQ0NDInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTYuNTM4MzMyJyB5PSctNTEuMzg0NDQyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQ4LjgwNzQ5NicgeT0nLTUxLjM4NDQ0MicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00MS4wNzY2NicgeT0nLTUxLjM4NDQ0MicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zNS45MjI3NjknIHk9Jy01MS4zODQ0NDInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzMuMzQ1ODI0JyB5PSctNTEuMzg0NDQyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTI4LjE5MTkzMycgeT0nLTUxLjM4NDQ0MicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yMy4wMzgwNDMnIHk9Jy01MS4zODQ0NDInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjAuNDYxMDk3JyB5PSctNTEuMzg0NDQyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTEyLjczMDI2MScgeT0nLTUxLjM4NDQ0MicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xMC4xNTMzMTYnIHk9Jy01MS4zODQ0NDInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNC45OTk0MjUnIHk9Jy01MS4zODQ0NDInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScxMC40NjIyNDcnIHk9Jy01MS4zODQ0NDInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjkuNDIzMDU5JyB5PSctNDguODA3NDk2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY2Ljg0NjExNCcgeT0nLTQ4LjgwNzQ5NicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02MS42OTIyMjMnIHk9Jy00OC44MDc0OTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTkuMTE1Mjc4JyB5PSctNDguODA3NDk2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQ2LjIzMDU1MScgeT0nLTQ4LjgwNzQ5NicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zOC40OTk3MTUnIHk9Jy00OC44MDc0OTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzUuOTIyNzY5JyB5PSctNDguODA3NDk2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTMzLjM0NTgyNCcgeT0nLTQ4LjgwNzQ5NicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yNS42MTQ5ODgnIHk9Jy00OC44MDc0OTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjMuMDM4MDQzJyB5PSctNDguODA3NDk2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIwLjQ2MTA5NycgeT0nLTQ4LjgwNzQ5NicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xMi43MzAyNjEnIHk9Jy00OC44MDc0OTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMi40MjI0OCcgeT0nLTQ4LjgwNzQ5NicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy4xNTQ0NjUnIHk9Jy00OC44MDc0OTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSc1LjMwODM1NicgeT0nLTQ4LjgwNzQ5NicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzcuODg1MzAxJyB5PSctNDguODA3NDk2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nLTQ2LjIzMDU1MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02OS40MjMwNTknIHk9Jy00Ni4yMzA1NTEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjYuODQ2MTE0JyB5PSctNDYuMjMwNTUxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTU5LjExNTI3OCcgeT0nLTQ2LjIzMDU1MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01Ni41MzgzMzInIHk9Jy00Ni4yMzA1NTEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTMuOTYxMzg3JyB5PSctNDYuMjMwNTUxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQ4LjgwNzQ5NicgeT0nLTQ2LjIzMDU1MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00MS4wNzY2NicgeT0nLTQ2LjIzMDU1MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zNS45MjI3NjknIHk9Jy00Ni4yMzA1NTEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzMuMzQ1ODI0JyB5PSctNDYuMjMwNTUxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTI1LjYxNDk4OCcgeT0nLTQ2LjIzMDU1MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yMC40NjEwOTcnIHk9Jy00Ni4yMzA1NTEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTcuODg0MTUyJyB5PSctNDYuMjMwNTUxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTE1LjMwNzIwNycgeT0nLTQ2LjIzMDU1MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xMi43MzAyNjEnIHk9Jy00Ni4yMzA1NTEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTAuMTUzMzE2JyB5PSctNDYuMjMwNTUxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTcuNTc2MzcxJyB5PSctNDYuMjMwNTUxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQuOTk5NDI1JyB5PSctNDYuMjMwNTUxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIuNDIyNDgnIHk9Jy00Ni4yMzA1NTEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSc3Ljg4NTMwMScgeT0nLTQ2LjIzMDU1MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzEwLjQ2MjI0NycgeT0nLTQ2LjIzMDU1MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy00My42NTM2MDUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjYuODQ2MTE0JyB5PSctNDMuNjUzNjA1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTU5LjExNTI3OCcgeT0nLTQzLjY1MzYwNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01MS4zODQ0NDInIHk9Jy00My42NTM2MDUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzUuOTIyNzY5JyB5PSctNDMuNjUzNjA1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTMzLjM0NTgyNCcgeT0nLTQzLjY1MzYwNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zMC43Njg4NzknIHk9Jy00My42NTM2MDUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjguMTkxOTMzJyB5PSctNDMuNjUzNjA1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIzLjAzODA0MycgeT0nLTQzLjY1MzYwNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yMC40NjEwOTcnIHk9Jy00My42NTM2MDUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTIuNzMwMjYxJyB5PSctNDMuNjUzNjA1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTEwLjE1MzMxNicgeT0nLTQzLjY1MzYwNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy03LjU3NjM3MScgeT0nLTQzLjY1MzYwNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yLjQyMjQ4JyB5PSctNDMuNjUzNjA1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLjE1NDQ2NScgeT0nLTQzLjY1MzYwNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzIuNzMxNDExJyB5PSctNDMuNjUzNjA1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nNS4zMDgzNTYnIHk9Jy00My42NTM2MDUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSctNDEuMDc2NjYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjkuNDIzMDU5JyB5PSctNDEuMDc2NjYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjYuODQ2MTE0JyB5PSctNDEuMDc2NjYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjEuNjkyMjIzJyB5PSctNDEuMDc2NjYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTYuNTM4MzMyJyB5PSctNDEuMDc2NjYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTMuOTYxMzg3JyB5PSctNDEuMDc2NjYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTEuMzg0NDQyJyB5PSctNDEuMDc2NjYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDguODA3NDk2JyB5PSctNDEuMDc2NjYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDYuMjMwNTUxJyB5PSctNDEuMDc2NjYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzMuMzQ1ODI0JyB5PSctNDEuMDc2NjYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzAuNzY4ODc5JyB5PSctNDEuMDc2NjYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjUuNjE0OTg4JyB5PSctNDEuMDc2NjYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjMuMDM4MDQzJyB5PSctNDEuMDc2NjYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTUuMzA3MjA3JyB5PSctNDEuMDc2NjYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTIuNzMwMjYxJyB5PSctNDEuMDc2NjYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNC45OTk0MjUnIHk9Jy00MS4wNzY2NicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzcuODg1MzAxJyB5PSctNDEuMDc2NjYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScxMC40NjIyNDcnIHk9Jy00MS4wNzY2NicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy0zOC40OTk3MTUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjQuMjY5MTY4JyB5PSctMzguNDk5NzE1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTYxLjY5MjIyMycgeT0nLTM4LjQ5OTcxNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01OS4xMTUyNzgnIHk9Jy0zOC40OTk3MTUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDYuMjMwNTUxJyB5PSctMzguNDk5NzE1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQxLjA3NjY2JyB5PSctMzguNDk5NzE1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTM4LjQ5OTcxNScgeT0nLTM4LjQ5OTcxNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zNS45MjI3NjknIHk9Jy0zOC40OTk3MTUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzMuMzQ1ODI0JyB5PSctMzguNDk5NzE1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTMwLjc2ODg3OScgeT0nLTM4LjQ5OTcxNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yOC4xOTE5MzMnIHk9Jy0zOC40OTk3MTUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjUuNjE0OTg4JyB5PSctMzguNDk5NzE1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTE3Ljg4NDE1MicgeT0nLTM4LjQ5OTcxNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xMi43MzAyNjEnIHk9Jy0zOC40OTk3MTUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNy41NzYzNzEnIHk9Jy0zOC40OTk3MTUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMi40MjI0OCcgeT0nLTM4LjQ5OTcxNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02OS40MjMwNTknIHk9Jy0zNS45MjI3NjknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjYuODQ2MTE0JyB5PSctMzUuOTIyNzY5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTYxLjY5MjIyMycgeT0nLTM1LjkyMjc2OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01OS4xMTUyNzgnIHk9Jy0zNS45MjI3NjknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTYuNTM4MzMyJyB5PSctMzUuOTIyNzY5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTUxLjM4NDQ0MicgeT0nLTM1LjkyMjc2OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zMy4zNDU4MjQnIHk9Jy0zNS45MjI3NjknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjMuMDM4MDQzJyB5PSctMzUuOTIyNzY5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTE3Ljg4NDE1MicgeT0nLTM1LjkyMjc2OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xMC4xNTMzMTYnIHk9Jy0zNS45MjI3NjknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNy41NzYzNzEnIHk9Jy0zNS45MjI3NjknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScuMTU0NDY1JyB5PSctMzUuOTIyNzY5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nLTMzLjM0NTgyNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02OS40MjMwNTknIHk9Jy0zMy4zNDU4MjQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjQuMjY5MTY4JyB5PSctMzMuMzQ1ODI0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTYxLjY5MjIyMycgeT0nLTMzLjM0NTgyNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01OS4xMTUyNzgnIHk9Jy0zMy4zNDU4MjQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTMuOTYxMzg3JyB5PSctMzMuMzQ1ODI0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQ4LjgwNzQ5NicgeT0nLTMzLjM0NTgyNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00Ni4yMzA1NTEnIHk9Jy0zMy4zNDU4MjQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDEuMDc2NjYnIHk9Jy0zMy4zNDU4MjQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzUuOTIyNzY5JyB5PSctMzMuMzQ1ODI0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTMzLjM0NTgyNCcgeT0nLTMzLjM0NTgyNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zMC43Njg4NzknIHk9Jy0zMy4zNDU4MjQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjMuMDM4MDQzJyB5PSctMzMuMzQ1ODI0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIwLjQ2MTA5NycgeT0nLTMzLjM0NTgyNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xMi43MzAyNjEnIHk9Jy0zMy4zNDU4MjQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNy41NzYzNzEnIHk9Jy0zMy4zNDU4MjQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNC45OTk0MjUnIHk9Jy0zMy4zNDU4MjQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSc1LjMwODM1NicgeT0nLTMzLjM0NTgyNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzEwLjQ2MjI0NycgeT0nLTMzLjM0NTgyNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy0zMC43Njg4NzknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTYuNTM4MzMyJyB5PSctMzAuNzY4ODc5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTUzLjk2MTM4NycgeT0nLTMwLjc2ODg3OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01MS4zODQ0NDInIHk9Jy0zMC43Njg4NzknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDguODA3NDk2JyB5PSctMzAuNzY4ODc5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQzLjY1MzYwNScgeT0nLTMwLjc2ODg3OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00MS4wNzY2NicgeT0nLTMwLjc2ODg3OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zOC40OTk3MTUnIHk9Jy0zMC43Njg4NzknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzMuMzQ1ODI0JyB5PSctMzAuNzY4ODc5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTMwLjc2ODg3OScgeT0nLTMwLjc2ODg3OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xNS4zMDcyMDcnIHk9Jy0zMC43Njg4NzknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTAuMTUzMzE2JyB5PSctMzAuNzY4ODc5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQuOTk5NDI1JyB5PSctMzAuNzY4ODc5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIuNDIyNDgnIHk9Jy0zMC43Njg4NzknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScuMTU0NDY1JyB5PSctMzAuNzY4ODc5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nMi43MzE0MTEnIHk9Jy0zMC43Njg4NzknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSc3Ljg4NTMwMScgeT0nLTMwLjc2ODg3OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzEwLjQ2MjI0NycgeT0nLTMwLjc2ODg3OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02NC4yNjkxNjgnIHk9Jy0yOC4xOTE5MzMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjEuNjkyMjIzJyB5PSctMjguMTkxOTMzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQ4LjgwNzQ5NicgeT0nLTI4LjE5MTkzMycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00My42NTM2MDUnIHk9Jy0yOC4xOTE5MzMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzMuMzQ1ODI0JyB5PSctMjguMTkxOTMzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTI4LjE5MTkzMycgeT0nLTI4LjE5MTkzMycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yMy4wMzgwNDMnIHk9Jy0yOC4xOTE5MzMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjAuNDYxMDk3JyB5PSctMjguMTkxOTMzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTE3Ljg4NDE1MicgeT0nLTI4LjE5MTkzMycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xNS4zMDcyMDcnIHk9Jy0yOC4xOTE5MzMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTAuMTUzMzE2JyB5PSctMjguMTkxOTMzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQuOTk5NDI1JyB5PSctMjguMTkxOTMzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIuNDIyNDgnIHk9Jy0yOC4xOTE5MzMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScuMTU0NDY1JyB5PSctMjguMTkxOTMzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nNy44ODUzMDEnIHk9Jy0yOC4xOTE5MzMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScxMC40NjIyNDcnIHk9Jy0yOC4xOTE5MzMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjQuMjY5MTY4JyB5PSctMjUuNjE0OTg4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTU2LjUzODMzMicgeT0nLTI1LjYxNDk4OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00OC44MDc0OTYnIHk9Jy0yNS42MTQ5ODgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDEuMDc2NjYnIHk9Jy0yNS42MTQ5ODgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzUuOTIyNzY5JyB5PSctMjUuNjE0OTg4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTMzLjM0NTgyNCcgeT0nLTI1LjYxNDk4OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yNS42MTQ5ODgnIHk9Jy0yNS42MTQ5ODgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjMuMDM4MDQzJyB5PSctMjUuNjE0OTg4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTE3Ljg4NDE1MicgeT0nLTI1LjYxNDk4OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xNS4zMDcyMDcnIHk9Jy0yNS42MTQ5ODgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTIuNzMwMjYxJyB5PSctMjUuNjE0OTg4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nMTAuNDYyMjQ3JyB5PSctMjUuNjE0OTg4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nLTIzLjAzODA0MycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02OS40MjMwNTknIHk9Jy0yMy4wMzgwNDMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjEuNjkyMjIzJyB5PSctMjMuMDM4MDQzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTUxLjM4NDQ0MicgeT0nLTIzLjAzODA0MycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00OC44MDc0OTYnIHk9Jy0yMy4wMzgwNDMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDMuNjUzNjA1JyB5PSctMjMuMDM4MDQzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTM4LjQ5OTcxNScgeT0nLTIzLjAzODA0MycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zMC43Njg4NzknIHk9Jy0yMy4wMzgwNDMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjMuMDM4MDQzJyB5PSctMjMuMDM4MDQzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTE1LjMwNzIwNycgeT0nLTIzLjAzODA0MycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xMC4xNTMzMTYnIHk9Jy0yMy4wMzgwNDMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNy41NzYzNzEnIHk9Jy0yMy4wMzgwNDMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMi40MjI0OCcgeT0nLTIzLjAzODA0MycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzUuMzA4MzU2JyB5PSctMjMuMDM4MDQzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nNy44ODUzMDEnIHk9Jy0yMy4wMzgwNDMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScxMC40NjIyNDcnIHk9Jy0yMy4wMzgwNDMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSctMjAuNDYxMDk3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY5LjQyMzA1OScgeT0nLTIwLjQ2MTA5NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02NC4yNjkxNjgnIHk9Jy0yMC40NjEwOTcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjEuNjkyMjIzJyB5PSctMjAuNDYxMDk3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTU2LjUzODMzMicgeT0nLTIwLjQ2MTA5NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01My45NjEzODcnIHk9Jy0yMC40NjEwOTcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDguODA3NDk2JyB5PSctMjAuNDYxMDk3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQzLjY1MzYwNScgeT0nLTIwLjQ2MTA5NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zOC40OTk3MTUnIHk9Jy0yMC40NjEwOTcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzAuNzY4ODc5JyB5PSctMjAuNDYxMDk3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTI4LjE5MTkzMycgeT0nLTIwLjQ2MTA5NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xMi43MzAyNjEnIHk9Jy0yMC40NjEwOTcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTAuMTUzMzE2JyB5PSctMjAuNDYxMDk3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIuNDIyNDgnIHk9Jy0yMC40NjEwOTcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSctMTcuODg0MTUyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY5LjQyMzA1OScgeT0nLTE3Ljg4NDE1MicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02MS42OTIyMjMnIHk9Jy0xNy44ODQxNTInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTMuOTYxMzg3JyB5PSctMTcuODg0MTUyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQ4LjgwNzQ5NicgeT0nLTE3Ljg4NDE1MicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00MS4wNzY2NicgeT0nLTE3Ljg4NDE1MicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zOC40OTk3MTUnIHk9Jy0xNy44ODQxNTInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzUuOTIyNzY5JyB5PSctMTcuODg0MTUyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTMzLjM0NTgyNCcgeT0nLTE3Ljg4NDE1MicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zMC43Njg4NzknIHk9Jy0xNy44ODQxNTInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjguMTkxOTMzJyB5PSctMTcuODg0MTUyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTI1LjYxNDk4OCcgeT0nLTE3Ljg4NDE1MicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yMy4wMzgwNDMnIHk9Jy0xNy44ODQxNTInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjAuNDYxMDk3JyB5PSctMTcuODg0MTUyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTE3Ljg4NDE1MicgeT0nLTE3Ljg4NDE1MicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xNS4zMDcyMDcnIHk9Jy0xNy44ODQxNTInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTIuNzMwMjYxJyB5PSctMTcuODg0MTUyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIuNDIyNDgnIHk9Jy0xNy44ODQxNTInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScuMTU0NDY1JyB5PSctMTcuODg0MTUyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nMi43MzE0MTEnIHk9Jy0xNy44ODQxNTInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSc3Ljg4NTMwMScgeT0nLTE3Ljg4NDE1MicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy0xNS4zMDcyMDcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTkuMTE1Mjc4JyB5PSctMTUuMzA3MjA3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTU2LjUzODMzMicgeT0nLTE1LjMwNzIwNycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00Ni4yMzA1NTEnIHk9Jy0xNS4zMDcyMDcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDMuNjUzNjA1JyB5PSctMTUuMzA3MjA3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTM4LjQ5OTcxNScgeT0nLTE1LjMwNzIwNycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zMy4zNDU4MjQnIHk9Jy0xNS4zMDcyMDcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzAuNzY4ODc5JyB5PSctMTUuMzA3MjA3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTI4LjE5MTkzMycgeT0nLTE1LjMwNzIwNycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yMC40NjEwOTcnIHk9Jy0xNS4zMDcyMDcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTUuMzA3MjA3JyB5PSctMTUuMzA3MjA3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTEyLjczMDI2MScgeT0nLTE1LjMwNzIwNycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xMC4xNTMzMTYnIHk9Jy0xNS4zMDcyMDcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNy41NzYzNzEnIHk9Jy0xNS4zMDcyMDcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSc3Ljg4NTMwMScgeT0nLTE1LjMwNzIwNycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzEwLjQ2MjI0NycgeT0nLTE1LjMwNzIwNycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy0xMi43MzAyNjEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjQuMjY5MTY4JyB5PSctMTIuNzMwMjYxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTUzLjk2MTM4NycgeT0nLTEyLjczMDI2MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00OC44MDc0OTYnIHk9Jy0xMi43MzAyNjEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDMuNjUzNjA1JyB5PSctMTIuNzMwMjYxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQxLjA3NjY2JyB5PSctMTIuNzMwMjYxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTM4LjQ5OTcxNScgeT0nLTEyLjczMDI2MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zMy4zNDU4MjQnIHk9Jy0xMi43MzAyNjEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzAuNzY4ODc5JyB5PSctMTIuNzMwMjYxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTI4LjE5MTkzMycgeT0nLTEyLjczMDI2MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yMy4wMzgwNDMnIHk9Jy0xMi43MzAyNjEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTUuMzA3MjA3JyB5PSctMTIuNzMwMjYxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTEwLjE1MzMxNicgeT0nLTEyLjczMDI2MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy03LjU3NjM3MScgeT0nLTEyLjczMDI2MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yLjQyMjQ4JyB5PSctMTIuNzMwMjYxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nNS4zMDgzNTYnIHk9Jy0xMi43MzAyNjEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSctMTAuMTUzMzE2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY5LjQyMzA1OScgeT0nLTEwLjE1MzMxNicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02NC4yNjkxNjgnIHk9Jy0xMC4xNTMzMTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTkuMTE1Mjc4JyB5PSctMTAuMTUzMzE2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTU2LjUzODMzMicgeT0nLTEwLjE1MzMxNicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00Ni4yMzA1NTEnIHk9Jy0xMC4xNTMzMTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDMuNjUzNjA1JyB5PSctMTAuMTUzMzE2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQxLjA3NjY2JyB5PSctMTAuMTUzMzE2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTM4LjQ5OTcxNScgeT0nLTEwLjE1MzMxNicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zMy4zNDU4MjQnIHk9Jy0xMC4xNTMzMTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzAuNzY4ODc5JyB5PSctMTAuMTUzMzE2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIzLjAzODA0MycgeT0nLTEwLjE1MzMxNicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yMC40NjEwOTcnIHk9Jy0xMC4xNTMzMTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTIuNzMwMjYxJyB5PSctMTAuMTUzMzE2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTEwLjE1MzMxNicgeT0nLTEwLjE1MzMxNicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy03LjU3NjM3MScgeT0nLTEwLjE1MzMxNicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00Ljk5OTQyNScgeT0nLTEwLjE1MzMxNicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yLjQyMjQ4JyB5PSctMTAuMTUzMzE2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLjE1NDQ2NScgeT0nLTEwLjE1MzMxNicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzcuODg1MzAxJyB5PSctMTAuMTUzMzE2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTUxLjM4NDQ0MicgeT0nLTcuNTc2MzcxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTM4LjQ5OTcxNScgeT0nLTcuNTc2MzcxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTM1LjkyMjc2OScgeT0nLTcuNTc2MzcxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTMzLjM0NTgyNCcgeT0nLTcuNTc2MzcxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTMwLjc2ODg3OScgeT0nLTcuNTc2MzcxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTI1LjYxNDk4OCcgeT0nLTcuNTc2MzcxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTEwLjE1MzMxNicgeT0nLTcuNTc2MzcxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLjE1NDQ2NScgeT0nLTcuNTc2MzcxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nNy44ODUzMDEnIHk9Jy03LjU3NjM3MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy00Ljk5OTQyNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02OS40MjMwNTknIHk9Jy00Ljk5OTQyNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02Ni44NDYxMTQnIHk9Jy00Ljk5OTQyNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02NC4yNjkxNjgnIHk9Jy00Ljk5OTQyNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02MS42OTIyMjMnIHk9Jy00Ljk5OTQyNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01OS4xMTUyNzgnIHk9Jy00Ljk5OTQyNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01Ni41MzgzMzInIHk9Jy00Ljk5OTQyNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00Ni4yMzA1NTEnIHk9Jy00Ljk5OTQyNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00My42NTM2MDUnIHk9Jy00Ljk5OTQyNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00MS4wNzY2NicgeT0nLTQuOTk5NDI1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTM4LjQ5OTcxNScgeT0nLTQuOTk5NDI1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTMzLjM0NTgyNCcgeT0nLTQuOTk5NDI1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTI1LjYxNDk4OCcgeT0nLTQuOTk5NDI1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIzLjAzODA0MycgeT0nLTQuOTk5NDI1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIwLjQ2MTA5NycgeT0nLTQuOTk5NDI1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTEyLjczMDI2MScgeT0nLTQuOTk5NDI1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTEwLjE1MzMxNicgeT0nLTQuOTk5NDI1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQuOTk5NDI1JyB5PSctNC45OTk0MjUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScuMTU0NDY1JyB5PSctNC45OTk0MjUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSctMi40MjI0OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01Ni41MzgzMzInIHk9Jy0yLjQyMjQ4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQ4LjgwNzQ5NicgeT0nLTIuNDIyNDgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDYuMjMwNTUxJyB5PSctMi40MjI0OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00My42NTM2MDUnIHk9Jy0yLjQyMjQ4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTMzLjM0NTgyNCcgeT0nLTIuNDIyNDgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjAuNDYxMDk3JyB5PSctMi40MjI0OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xNS4zMDcyMDcnIHk9Jy0yLjQyMjQ4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTEyLjczMDI2MScgeT0nLTIuNDIyNDgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTAuMTUzMzE2JyB5PSctMi40MjI0OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy4xNTQ0NjUnIHk9Jy0yLjQyMjQ4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nMi43MzE0MTEnIHk9Jy0yLjQyMjQ4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nNS4zMDgzNTYnIHk9Jy0yLjQyMjQ4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nMTAuNDYyMjQ3JyB5PSctMi40MjI0OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy4xNTQ0NjUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjYuODQ2MTE0JyB5PScuMTU0NDY1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY0LjI2OTE2OCcgeT0nLjE1NDQ2NScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02MS42OTIyMjMnIHk9Jy4xNTQ0NjUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTYuNTM4MzMyJyB5PScuMTU0NDY1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTUxLjM4NDQ0MicgeT0nLjE1NDQ2NScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00OC44MDc0OTYnIHk9Jy4xNTQ0NjUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzUuOTIyNzY5JyB5PScuMTU0NDY1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIwLjQ2MTA5NycgeT0nLjE1NDQ2NScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xMi43MzAyNjEnIHk9Jy4xNTQ0NjUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTAuMTUzMzE2JyB5PScuMTU0NDY1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTcuNTc2MzcxJyB5PScuMTU0NDY1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQuOTk5NDI1JyB5PScuMTU0NDY1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIuNDIyNDgnIHk9Jy4xNTQ0NjUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScuMTU0NDY1JyB5PScuMTU0NDY1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nMTAuNDYyMjQ3JyB5PScuMTU0NDY1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nMi43MzE0MTEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjYuODQ2MTE0JyB5PScyLjczMTQxMScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02NC4yNjkxNjgnIHk9JzIuNzMxNDExJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTYxLjY5MjIyMycgeT0nMi43MzE0MTEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTYuNTM4MzMyJyB5PScyLjczMTQxMScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01MS4zODQ0NDInIHk9JzIuNzMxNDExJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQ2LjIzMDU1MScgeT0nMi43MzE0MTEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDMuNjUzNjA1JyB5PScyLjczMTQxMScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00MS4wNzY2NicgeT0nMi43MzE0MTEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzguNDk5NzE1JyB5PScyLjczMTQxMScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zNS45MjI3NjknIHk9JzIuNzMxNDExJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTMzLjM0NTgyNCcgeT0nMi43MzE0MTEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjUuNjE0OTg4JyB5PScyLjczMTQxMScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yMy4wMzgwNDMnIHk9JzIuNzMxNDExJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIwLjQ2MTA5NycgeT0nMi43MzE0MTEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTcuODg0MTUyJyB5PScyLjczMTQxMScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xNS4zMDcyMDcnIHk9JzIuNzMxNDExJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTEwLjE1MzMxNicgeT0nMi43MzE0MTEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNy41NzYzNzEnIHk9JzIuNzMxNDExJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nMi43MzE0MTEnIHk9JzIuNzMxNDExJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nNS4zMDgzNTYnIHk9JzIuNzMxNDExJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nNS4zMDgzNTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjYuODQ2MTE0JyB5PSc1LjMwODM1NicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02NC4yNjkxNjgnIHk9JzUuMzA4MzU2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTYxLjY5MjIyMycgeT0nNS4zMDgzNTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTYuNTM4MzMyJyB5PSc1LjMwODM1NicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00OC44MDc0OTYnIHk9JzUuMzA4MzU2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQ2LjIzMDU1MScgeT0nNS4zMDgzNTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDMuNjUzNjA1JyB5PSc1LjMwODM1NicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zMy4zNDU4MjQnIHk9JzUuMzA4MzU2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTMwLjc2ODg3OScgeT0nNS4zMDgzNTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjguMTkxOTMzJyB5PSc1LjMwODM1NicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yMy4wMzgwNDMnIHk9JzUuMzA4MzU2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIwLjQ2MTA5NycgeT0nNS4zMDgzNTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTIuNzMwMjYxJyB5PSc1LjMwODM1NicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xMC4xNTMzMTYnIHk9JzUuMzA4MzU2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIuNDIyNDgnIHk9JzUuMzA4MzU2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLjE1NDQ2NScgeT0nNS4zMDgzNTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScxMC40NjIyNDcnIHk9JzUuMzA4MzU2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nNy44ODUzMDEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTYuNTM4MzMyJyB5PSc3Ljg4NTMwMScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01MS4zODQ0NDInIHk9JzcuODg1MzAxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQxLjA3NjY2JyB5PSc3Ljg4NTMwMScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zNS45MjI3NjknIHk9JzcuODg1MzAxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTMwLjc2ODg3OScgeT0nNy44ODUzMDEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjUuNjE0OTg4JyB5PSc3Ljg4NTMwMScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yMy4wMzgwNDMnIHk9JzcuODg1MzAxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTE1LjMwNzIwNycgeT0nNy44ODUzMDEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNy41NzYzNzEnIHk9JzcuODg1MzAxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQuOTk5NDI1JyB5PSc3Ljg4NTMwMScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzIuNzMxNDExJyB5PSc3Ljg4NTMwMScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzUuMzA4MzU2JyB5PSc3Ljg4NTMwMScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzcuODg1MzAxJyB5PSc3Ljg4NTMwMScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzEwLjQ2MjI0NycgeT0nNy44ODUzMDEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PScxMC40NjIyNDcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjkuNDIzMDU5JyB5PScxMC40NjIyNDcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjYuODQ2MTE0JyB5PScxMC40NjIyNDcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjQuMjY5MTY4JyB5PScxMC40NjIyNDcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjEuNjkyMjIzJyB5PScxMC40NjIyNDcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTkuMTE1Mjc4JyB5PScxMC40NjIyNDcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTYuNTM4MzMyJyB5PScxMC40NjIyNDcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTEuMzg0NDQyJyB5PScxMC40NjIyNDcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDguODA3NDk2JyB5PScxMC40NjIyNDcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDYuMjMwNTUxJyB5PScxMC40NjIyNDcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDEuMDc2NjYnIHk9JzEwLjQ2MjI0NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zOC40OTk3MTUnIHk9JzEwLjQ2MjI0NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zNS45MjI3NjknIHk9JzEwLjQ2MjI0NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zMC43Njg4NzknIHk9JzEwLjQ2MjI0NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yOC4xOTE5MzMnIHk9JzEwLjQ2MjI0NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xMi43MzAyNjEnIHk9JzEwLjQ2MjI0NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xMC4xNTMzMTYnIHk9JzEwLjQ2MjI0NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy03LjU3NjM3MScgeT0nMTAuNDYyMjQ3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPC9nPgo8L3N2Zz4=")} + @top-center{content:" TITLE VER. DATETIME \A \A smalloc, sbrk i minimalne libc v00.01 2026-07-20T00:00:00+02:00 \A PROJECT SERIES CARD SHEET \A \A Freestanding C na RV32I C · Freestanding RV32I and K&R 09/13 " counter(page) "/" counter(pages) " \A SUBJ. PROG. CORE SCOPE LEVEL POS. GITEA UUID 47826ae5-6370-5ac2-bd91-9acb89116d40\A CARD UUID 8e4f8bee-41f0-523b-8ea2-8926bd3d7ab0 AUTHOR M. Pabiszczak\A Inf. — — — — — \A \A GITEA https://zsl-gitea.mpabi.pl/edu-inf/lab-rv32i-c-smalloc-sbrk-libc \A \A HTML https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/8e4f8bee-41f0-523b-8ea2-8926bd3d7ab0 ";width:119mm;height:24mm;box-sizing:border-box;padding:.2mm .7mm 0;border-block:1px solid #111;background-color:#fff;background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMTkgMjQiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPjxyZWN0IHdpZHRoPSIxMTkiIGhlaWdodD0iMjQiIGZpbGw9IndoaXRlIi8+PHBhdGggZD0iTTAgNS41Mzg0NkgxMTkgTTAgMTEuMDc2OUgxMTkgTTAgMTYuNjE1NEgxMTkgTTAgMjAuMzA3N0gxMTkgTTU5LjUgMFY1LjUzODQ2IE03Ny41IDBWNS41Mzg0NiBNNTkuNSA1LjUzODQ2VjExLjA3NjkgTTg5LjUgNS41Mzg0NlYxMS4wNzY5IE0xMDYuNSA1LjUzODQ2VjExLjA3NjkgTTcgMTEuMDc2OVYxNi42MTU0IE0xMyAxMS4wNzY5VjE2LjYxNTQgTTMwLjUgMTEuMDc2OVYxNi42MTU0IE00MS41IDExLjA3NjlWMTYuNjE1NCBNNTAuNSAxMS4wNzY5VjE2LjYxNTQgTTU5LjUgMTEuMDc2OVYxNi42MTU0IiBmaWxsPSJub25lIiBzdHJva2U9IiM4ODgiIHN0cm9rZS13aWR0aD0iMC4xNCIvPjwvc3ZnPg==");background-repeat:no-repeat;background-position:center;background-size:100% 100%;white-space:pre;vertical-align:top;text-align:left;font:700 5.2px/1.81538mm ui-monospace,SFMono-Regular,Consolas,monospace;letter-spacing:-.02px;color:#111;overflow:hidden} + @top-right{content:"";width:24mm;height:24mm;box-sizing:border-box;padding:0;border:1px solid #111;background-color:#fff;background-repeat:no-repeat;background-position:center;background-size:22mm 22mm;vertical-align:middle;text-align:center;font:0/0 sans-serif;color:transparent;background-image:url("data:image/svg+xml;base64,PHN2ZyBjbGFzcz0idGl0bGUtcXIiIHJvbGU9ImltZyIgYXJpYS1sYWJlbD0iS29kIFFSOiBodHRwczovL2RjZTdmYjlkLTdiMmYtNWQ0OS05NmEyLTNhMzBkMzA3MGI4NC5tcGFiaS5wbC84ZTRmOGJlZS00MWYwLTUyM2ItOGVhMi04OTI2YmQzZDdhYjAiIHZlcnNpb249JzEuMScgeG1sbnM9J2h0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnJyB4bWxuczp4bGluaz0naHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluaycgd2lkdGg9Jzg1LjAzOTIyN3B0JyBoZWlnaHQ9Jzg1LjAzOTIyN3B0JyB2aWV3Qm94PSctNzIuMDAwMDA0IC03Mi4wMDAwMDQgODUuMDM5MjI3IDg1LjAzOTIyNyc+CjxnIGlkPSdwYWdlMSc+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy03Mi4wMDAwMDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjkuNzAxNjQ3JyB5PSctNzIuMDAwMDA0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY3LjQwMzI4OScgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02NS4xMDQ5MzInIHk9Jy03Mi4wMDAwMDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjIuODA2NTc0JyB5PSctNzIuMDAwMDA0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTYwLjUwODIxNycgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01OC4yMDk4NTknIHk9Jy03Mi4wMDAwMDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDkuMDE2NDI5JyB5PSctNzIuMDAwMDA0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ0LjQxOTcxNScgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zOS44MjMnIHk9Jy03Mi4wMDAwMDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjguMzMxMjEyJyB5PSctNzIuMDAwMDA0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE5LjEzNzc4MicgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xNi44Mzk0MjUnIHk9Jy03Mi4wMDAwMDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTIuMjQyNzEnIHk9Jy03Mi4wMDAwMDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMy4wNDkyOCcgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0uNzUwOTIyJyB5PSctNzIuMDAwMDA0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMS41NDc0MzUnIHk9Jy03Mi4wMDAwMDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSczLjg0NTc5MycgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzYuMTQ0MTUnIHk9Jy03Mi4wMDAwMDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSc4LjQ0MjUwNycgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEwLjc0MDg2NScgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy02OS43MDE2NDcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTguMjA5ODU5JyB5PSctNjkuNzAxNjQ3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUzLjYxMzE0NCcgeT0nLTY5LjcwMTY0NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00OS4wMTY0MjknIHk9Jy02OS43MDE2NDcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDIuMTIxMzU3JyB5PSctNjkuNzAxNjQ3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM5LjgyMycgeT0nLTY5LjcwMTY0NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zNy41MjQ2NDInIHk9Jy02OS43MDE2NDcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjYuMDMyODU1JyB5PSctNjkuNzAxNjQ3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTIxLjQzNjE0JyB5PSctNjkuNzAxNjQ3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE0LjU0MTA2NycgeT0nLTY5LjcwMTY0NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy05Ljk0NDM1MicgeT0nLTY5LjcwMTY0NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03LjY0NTk5NScgeT0nLTY5LjcwMTY0NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zLjA0OTI4JyB5PSctNjkuNzAxNjQ3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMTAuNzQwODY1JyB5PSctNjkuNzAxNjQ3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nLTY3LjQwMzI4OScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02Ny40MDMyODknIHk9Jy02Ny40MDMyODknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjUuMTA0OTMyJyB5PSctNjcuNDAzMjg5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTYyLjgwNjU3NCcgeT0nLTY3LjQwMzI4OScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01OC4yMDk4NTknIHk9Jy02Ny40MDMyODknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDQuNDE5NzE1JyB5PSctNjcuNDAzMjg5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM5LjgyMycgeT0nLTY3LjQwMzI4OScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zNy41MjQ2NDInIHk9Jy02Ny40MDMyODknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzUuMjI2Mjg1JyB5PSctNjcuNDAzMjg5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTI2LjAzMjg1NScgeT0nLTY3LjQwMzI4OScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yMy43MzQ0OTcnIHk9Jy02Ny40MDMyODknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTYuODM5NDI1JyB5PSctNjcuNDAzMjg5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTEyLjI0MjcxJyB5PSctNjcuNDAzMjg5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTkuOTQ0MzUyJyB5PSctNjcuNDAzMjg5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcuNjQ1OTk1JyB5PSctNjcuNDAzMjg5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMuMDQ5MjgnIHk9Jy02Ny40MDMyODknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PScxLjU0NzQzNScgeT0nLTY3LjQwMzI4OScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzMuODQ1NzkzJyB5PSctNjcuNDAzMjg5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nNi4xNDQxNScgeT0nLTY3LjQwMzI4OScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEwLjc0MDg2NScgeT0nLTY3LjQwMzI4OScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy02NS4xMDQ5MzInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjcuNDAzMjg5JyB5PSctNjUuMTA0OTMyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY1LjEwNDkzMicgeT0nLTY1LjEwNDkzMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02Mi44MDY1NzQnIHk9Jy02NS4xMDQ5MzInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTguMjA5ODU5JyB5PSctNjUuMTA0OTMyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUzLjYxMzE0NCcgeT0nLTY1LjEwNDkzMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01MS4zMTQ3ODcnIHk9Jy02NS4xMDQ5MzInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDkuMDE2NDI5JyB5PSctNjUuMTA0OTMyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ0LjQxOTcxNScgeT0nLTY1LjEwNDkzMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00Mi4xMjEzNTcnIHk9Jy02NS4xMDQ5MzInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzkuODIzJyB5PSctNjUuMTA0OTMyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM3LjUyNDY0MicgeT0nLTY1LjEwNDkzMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zMi45Mjc5MjcnIHk9Jy02NS4xMDQ5MzInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzAuNjI5NTcnIHk9Jy02NS4xMDQ5MzInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjguMzMxMjEyJyB5PSctNjUuMTA0OTMyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTIxLjQzNjE0JyB5PSctNjUuMTA0OTMyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE5LjEzNzc4MicgeT0nLTY1LjEwNDkzMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xNi44Mzk0MjUnIHk9Jy02NS4xMDQ5MzInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTQuNTQxMDY3JyB5PSctNjUuMTA0OTMyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTEyLjI0MjcxJyB5PSctNjUuMTA0OTMyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMuMDQ5MjgnIHk9Jy02NS4xMDQ5MzInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PScxLjU0NzQzNScgeT0nLTY1LjEwNDkzMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzMuODQ1NzkzJyB5PSctNjUuMTA0OTMyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nNi4xNDQxNScgeT0nLTY1LjEwNDkzMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEwLjc0MDg2NScgeT0nLTY1LjEwNDkzMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy02Mi44MDY1NzQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjcuNDAzMjg5JyB5PSctNjIuODA2NTc0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY1LjEwNDkzMicgeT0nLTYyLjgwNjU3NCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02Mi44MDY1NzQnIHk9Jy02Mi44MDY1NzQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTguMjA5ODU5JyB5PSctNjIuODA2NTc0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUxLjMxNDc4NycgeT0nLTYyLjgwNjU3NCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zNS4yMjYyODUnIHk9Jy02Mi44MDY1NzQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjguMzMxMjEyJyB5PSctNjIuODA2NTc0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTIzLjczNDQ5NycgeT0nLTYyLjgwNjU3NCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yMS40MzYxNCcgeT0nLTYyLjgwNjU3NCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xOS4xMzc3ODInIHk9Jy02Mi44MDY1NzQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMy4wNDkyOCcgeT0nLTYyLjgwNjU3NCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEuNTQ3NDM1JyB5PSctNjIuODA2NTc0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMy44NDU3OTMnIHk9Jy02Mi44MDY1NzQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSc2LjE0NDE1JyB5PSctNjIuODA2NTc0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMTAuNzQwODY1JyB5PSctNjIuODA2NTc0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nLTYwLjUwODIxNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01OC4yMDk4NTknIHk9Jy02MC41MDgyMTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTMuNjEzMTQ0JyB5PSctNjAuNTA4MjE3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUxLjMxNDc4NycgeT0nLTYwLjUwODIxNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00Ni43MTgwNzInIHk9Jy02MC41MDgyMTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDQuNDE5NzE1JyB5PSctNjAuNTA4MjE3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM3LjUyNDY0MicgeT0nLTYwLjUwODIxNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zNS4yMjYyODUnIHk9Jy02MC41MDgyMTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzIuOTI3OTI3JyB5PSctNjAuNTA4MjE3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMwLjYyOTU3JyB5PSctNjAuNTA4MjE3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTIzLjczNDQ5NycgeT0nLTYwLjUwODIxNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xNi44Mzk0MjUnIHk9Jy02MC41MDgyMTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctOS45NDQzNTInIHk9Jy02MC41MDgyMTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMy4wNDkyOCcgeT0nLTYwLjUwODIxNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEwLjc0MDg2NScgeT0nLTYwLjUwODIxNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy01OC4yMDk4NTknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjkuNzAxNjQ3JyB5PSctNTguMjA5ODU5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY3LjQwMzI4OScgeT0nLTU4LjIwOTg1OScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02NS4xMDQ5MzInIHk9Jy01OC4yMDk4NTknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjIuODA2NTc0JyB5PSctNTguMjA5ODU5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTYwLjUwODIxNycgeT0nLTU4LjIwOTg1OScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01OC4yMDk4NTknIHk9Jy01OC4yMDk4NTknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTMuNjEzMTQ0JyB5PSctNTguMjA5ODU5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ5LjAxNjQyOScgeT0nLTU4LjIwOTg1OScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00NC40MTk3MTUnIHk9Jy01OC4yMDk4NTknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzkuODIzJyB5PSctNTguMjA5ODU5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM1LjIyNjI4NScgeT0nLTU4LjIwOTg1OScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zMC42Mjk1NycgeT0nLTU4LjIwOTg1OScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yNi4wMzI4NTUnIHk9Jy01OC4yMDk4NTknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjEuNDM2MTQnIHk9Jy01OC4yMDk4NTknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTYuODM5NDI1JyB5PSctNTguMjA5ODU5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTEyLjI0MjcxJyB5PSctNTguMjA5ODU5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcuNjQ1OTk1JyB5PSctNTguMjA5ODU5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMuMDQ5MjgnIHk9Jy01OC4yMDk4NTknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctLjc1MDkyMicgeT0nLTU4LjIwOTg1OScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEuNTQ3NDM1JyB5PSctNTguMjA5ODU5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMy44NDU3OTMnIHk9Jy01OC4yMDk4NTknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSc2LjE0NDE1JyB5PSctNTguMjA5ODU5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nOC40NDI1MDcnIHk9Jy01OC4yMDk4NTknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PScxMC43NDA4NjUnIHk9Jy01OC4yMDk4NTknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTEuMzE0Nzg3JyB5PSctNTUuOTExNTAyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ5LjAxNjQyOScgeT0nLTU1LjkxMTUwMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00Ni43MTgwNzInIHk9Jy01NS45MTE1MDInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzkuODIzJyB5PSctNTUuOTExNTAyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMwLjYyOTU3JyB5PSctNTUuOTExNTAyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTIzLjczNDQ5NycgeT0nLTU1LjkxMTUwMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xOS4xMzc3ODInIHk9Jy01NS45MTE1MDInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTYuODM5NDI1JyB5PSctNTUuOTExNTAyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTEyLjI0MjcxJyB5PSctNTUuOTExNTAyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nLTUzLjYxMzE0NCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02OS43MDE2NDcnIHk9Jy01My42MTMxNDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjcuNDAzMjg5JyB5PSctNTMuNjEzMTQ0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY1LjEwNDkzMicgeT0nLTUzLjYxMzE0NCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02Mi44MDY1NzQnIHk9Jy01My42MTMxNDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTguMjA5ODU5JyB5PSctNTMuNjEzMTQ0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTU1LjkxMTUwMicgeT0nLTUzLjYxMzE0NCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01My42MTMxNDQnIHk9Jy01My42MTMxNDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTEuMzE0Nzg3JyB5PSctNTMuNjEzMTQ0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ2LjcxODA3MicgeT0nLTUzLjYxMzE0NCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00Mi4xMjEzNTcnIHk9Jy01My42MTMxNDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzkuODIzJyB5PSctNTMuNjEzMTQ0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM3LjUyNDY0MicgeT0nLTUzLjYxMzE0NCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zNS4yMjYyODUnIHk9Jy01My42MTMxNDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzIuOTI3OTI3JyB5PSctNTMuNjEzMTQ0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMwLjYyOTU3JyB5PSctNTMuNjEzMTQ0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTI2LjAzMjg1NScgeT0nLTUzLjYxMzE0NCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yMS40MzYxNCcgeT0nLTUzLjYxMzE0NCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xNi44Mzk0MjUnIHk9Jy01My42MTMxNDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTQuNTQxMDY3JyB5PSctNTMuNjEzMTQ0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTkuOTQ0MzUyJyB5PSctNTMuNjEzMTQ0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcuNjQ1OTk1JyB5PSctNTMuNjEzMTQ0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUuMzQ3NjM3JyB5PSctNTMuNjEzMTQ0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLS43NTA5MjInIHk9Jy01My42MTMxNDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSczLjg0NTc5MycgeT0nLTUzLjYxMzE0NCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzguNDQyNTA3JyB5PSctNTMuNjEzMTQ0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY5LjcwMTY0NycgeT0nLTUxLjMxNDc4NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02Mi44MDY1NzQnIHk9Jy01MS4zMTQ3ODcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjAuNTA4MjE3JyB5PSctNTEuMzE0Nzg3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUzLjYxMzE0NCcgeT0nLTUxLjMxNDc4NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00OS4wMTY0MjknIHk9Jy01MS4zMTQ3ODcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDQuNDE5NzE1JyB5PSctNTEuMzE0Nzg3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTI4LjMzMTIxMicgeT0nLTUxLjMxNDc4NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xOS4xMzc3ODInIHk9Jy01MS4zMTQ3ODcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTIuMjQyNzEnIHk9Jy01MS4zMTQ3ODcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctLjc1MDkyMicgeT0nLTUxLjMxNDc4NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzMuODQ1NzkzJyB5PSctNTEuMzE0Nzg3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nNi4xNDQxNScgeT0nLTUxLjMxNDc4NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzguNDQyNTA3JyB5PSctNTEuMzE0Nzg3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY5LjcwMTY0NycgeT0nLTQ5LjAxNjQyOScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02Ny40MDMyODknIHk9Jy00OS4wMTY0MjknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjIuODA2NTc0JyB5PSctNDkuMDE2NDI5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTYwLjUwODIxNycgeT0nLTQ5LjAxNjQyOScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01OC4yMDk4NTknIHk9Jy00OS4wMTY0MjknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTUuOTExNTAyJyB5PSctNDkuMDE2NDI5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUzLjYxMzE0NCcgeT0nLTQ5LjAxNjQyOScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00OS4wMTY0MjknIHk9Jy00OS4wMTY0MjknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDIuMTIxMzU3JyB5PSctNDkuMDE2NDI5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM3LjUyNDY0MicgeT0nLTQ5LjAxNjQyOScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zMi45Mjc5MjcnIHk9Jy00OS4wMTY0MjknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzAuNjI5NTcnIHk9Jy00OS4wMTY0MjknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjMuNzM0NDk3JyB5PSctNDkuMDE2NDI5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTIxLjQzNjE0JyB5PSctNDkuMDE2NDI5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE0LjU0MTA2NycgeT0nLTQ5LjAxNjQyOScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy05Ljk0NDM1MicgeT0nLTQ5LjAxNjQyOScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03LjY0NTk5NScgeT0nLTQ5LjAxNjQyOScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zLjA0OTI4JyB5PSctNDkuMDE2NDI5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLS43NTA5MjInIHk9Jy00OS4wMTY0MjknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PScxLjU0NzQzNScgeT0nLTQ5LjAxNjQyOScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzMuODQ1NzkzJyB5PSctNDkuMDE2NDI5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nNi4xNDQxNScgeT0nLTQ5LjAxNjQyOScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEwLjc0MDg2NScgeT0nLTQ5LjAxNjQyOScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy00Ni43MTgwNzInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjUuMTA0OTMyJyB5PSctNDYuNzE4MDcyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTYwLjUwODIxNycgeT0nLTQ2LjcxODA3MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01NS45MTE1MDInIHk9Jy00Ni43MTgwNzInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTMuNjEzMTQ0JyB5PSctNDYuNzE4MDcyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUxLjMxNDc4NycgeT0nLTQ2LjcxODA3MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00NC40MTk3MTUnIHk9Jy00Ni43MTgwNzInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzcuNTI0NjQyJyB5PSctNDYuNzE4MDcyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM1LjIyNjI4NScgeT0nLTQ2LjcxODA3MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yOC4zMzEyMTInIHk9Jy00Ni43MTgwNzInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjYuMDMyODU1JyB5PSctNDYuNzE4MDcyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTIzLjczNDQ5NycgeT0nLTQ2LjcxODA3MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xNi44Mzk0MjUnIHk9Jy00Ni43MTgwNzInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTIuMjQyNzEnIHk9Jy00Ni43MTgwNzInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctOS45NDQzNTInIHk9Jy00Ni43MTgwNzInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctLjc1MDkyMicgeT0nLTQ2LjcxODA3MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzMuODQ1NzkzJyB5PSctNDYuNzE4MDcyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nOC40NDI1MDcnIHk9Jy00Ni43MTgwNzInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSctNDQuNDE5NzE1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY3LjQwMzI4OScgeT0nLTQ0LjQxOTcxNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02Mi44MDY1NzQnIHk9Jy00NC40MTk3MTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjAuNTA4MjE3JyB5PSctNDQuNDE5NzE1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTU4LjIwOTg1OScgeT0nLTQ0LjQxOTcxNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01MS4zMTQ3ODcnIHk9Jy00NC40MTk3MTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDkuMDE2NDI5JyB5PSctNDQuNDE5NzE1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ0LjQxOTcxNScgeT0nLTQ0LjQxOTcxNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00Mi4xMjEzNTcnIHk9Jy00NC40MTk3MTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzcuNTI0NjQyJyB5PSctNDQuNDE5NzE1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMyLjkyNzkyNycgeT0nLTQ0LjQxOTcxNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xNi44Mzk0MjUnIHk9Jy00NC40MTk3MTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTQuNTQxMDY3JyB5PSctNDQuNDE5NzE1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTkuOTQ0MzUyJyB5PSctNDQuNDE5NzE1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMuMDQ5MjgnIHk9Jy00NC40MTk3MTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctLjc1MDkyMicgeT0nLTQ0LjQxOTcxNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEuNTQ3NDM1JyB5PSctNDQuNDE5NzE1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMy44NDU3OTMnIHk9Jy00NC40MTk3MTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSc2LjE0NDE1JyB5PSctNDQuNDE5NzE1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMTAuNzQwODY1JyB5PSctNDQuNDE5NzE1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY5LjcwMTY0NycgeT0nLTQyLjEyMTM1NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02NS4xMDQ5MzInIHk9Jy00Mi4xMjEzNTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjIuODA2NTc0JyB5PSctNDIuMTIxMzU3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTYwLjUwODIxNycgeT0nLTQyLjEyMTM1NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00OS4wMTY0MjknIHk9Jy00Mi4xMjEzNTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzkuODIzJyB5PSctNDIuMTIxMzU3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM1LjIyNjI4NScgeT0nLTQyLjEyMTM1NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zMC42Mjk1NycgeT0nLTQyLjEyMTM1NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yOC4zMzEyMTInIHk9Jy00Mi4xMjEzNTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjYuMDMyODU1JyB5PSctNDIuMTIxMzU3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE5LjEzNzc4MicgeT0nLTQyLjEyMTM1NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xMi4yNDI3MScgeT0nLTQyLjEyMTM1NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03LjY0NTk5NScgeT0nLTQyLjEyMTM1NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01LjM0NzYzNycgeT0nLTQyLjEyMTM1NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzYuMTQ0MTUnIHk9Jy00Mi4xMjEzNTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSc4LjQ0MjUwNycgeT0nLTQyLjEyMTM1NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy0zOS44MjMnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjkuNzAxNjQ3JyB5PSctMzkuODIzJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY3LjQwMzI4OScgeT0nLTM5LjgyMycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02NS4xMDQ5MzInIHk9Jy0zOS44MjMnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjAuNTA4MjE3JyB5PSctMzkuODIzJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTU4LjIwOTg1OScgeT0nLTM5LjgyMycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01My42MTMxNDQnIHk9Jy0zOS44MjMnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTEuMzE0Nzg3JyB5PSctMzkuODIzJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ5LjAxNjQyOScgeT0nLTM5LjgyMycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00Ni43MTgwNzInIHk9Jy0zOS44MjMnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDQuNDE5NzE1JyB5PSctMzkuODIzJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM3LjUyNDY0MicgeT0nLTM5LjgyMycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zMi45Mjc5MjcnIHk9Jy0zOS44MjMnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzAuNjI5NTcnIHk9Jy0zOS44MjMnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjYuMDMyODU1JyB5PSctMzkuODIzJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTIxLjQzNjE0JyB5PSctMzkuODIzJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE2LjgzOTQyNScgeT0nLTM5LjgyMycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy05Ljk0NDM1MicgeT0nLTM5LjgyMycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zLjA0OTI4JyB5PSctMzkuODIzJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLS43NTA5MjInIHk9Jy0zOS44MjMnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSc2LjE0NDE1JyB5PSctMzkuODIzJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nOC40NDI1MDcnIHk9Jy0zOS44MjMnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PScxMC43NDA4NjUnIHk9Jy0zOS44MjMnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSctMzcuNTI0NjQyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY3LjQwMzI4OScgeT0nLTM3LjUyNDY0MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02MC41MDgyMTcnIHk9Jy0zNy41MjQ2NDInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTUuOTExNTAyJyB5PSctMzcuNTI0NjQyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUzLjYxMzE0NCcgeT0nLTM3LjUyNDY0MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01MS4zMTQ3ODcnIHk9Jy0zNy41MjQ2NDInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDYuNzE4MDcyJyB5PSctMzcuNTI0NjQyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMwLjYyOTU3JyB5PSctMzcuNTI0NjQyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTIzLjczNDQ5NycgeT0nLTM3LjUyNDY0MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yMS40MzYxNCcgeT0nLTM3LjUyNDY0MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xNi44Mzk0MjUnIHk9Jy0zNy41MjQ2NDInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNy42NDU5OTUnIHk9Jy0zNy41MjQ2NDInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctLjc1MDkyMicgeT0nLTM3LjUyNDY0MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEuNTQ3NDM1JyB5PSctMzcuNTI0NjQyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMy44NDU3OTMnIHk9Jy0zNy41MjQ2NDInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PScxMC43NDA4NjUnIHk9Jy0zNy41MjQ2NDInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSctMzUuMjI2Mjg1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY3LjQwMzI4OScgeT0nLTM1LjIyNjI4NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02Mi44MDY1NzQnIHk9Jy0zNS4yMjYyODUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjAuNTA4MjE3JyB5PSctMzUuMjI2Mjg1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTU4LjIwOTg1OScgeT0nLTM1LjIyNjI4NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01NS45MTE1MDInIHk9Jy0zNS4yMjYyODUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTMuNjEzMTQ0JyB5PSctMzUuMjI2Mjg1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUxLjMxNDc4NycgeT0nLTM1LjIyNjI4NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00OS4wMTY0MjknIHk9Jy0zNS4yMjYyODUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDYuNzE4MDcyJyB5PSctMzUuMjI2Mjg1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM3LjUyNDY0MicgeT0nLTM1LjIyNjI4NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zMi45Mjc5MjcnIHk9Jy0zNS4yMjYyODUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzAuNjI5NTcnIHk9Jy0zNS4yMjYyODUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjYuMDMyODU1JyB5PSctMzUuMjI2Mjg1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE0LjU0MTA2NycgeT0nLTM1LjIyNjI4NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xMi4yNDI3MScgeT0nLTM1LjIyNjI4NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy05Ljk0NDM1MicgeT0nLTM1LjIyNjI4NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03LjY0NTk5NScgeT0nLTM1LjIyNjI4NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01LjM0NzYzNycgeT0nLTM1LjIyNjI4NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zLjA0OTI4JyB5PSctMzUuMjI2Mjg1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMS41NDc0MzUnIHk9Jy0zNS4yMjYyODUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSczLjg0NTc5MycgeT0nLTM1LjIyNjI4NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzYuMTQ0MTUnIHk9Jy0zNS4yMjYyODUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PScxMC43NDA4NjUnIHk9Jy0zNS4yMjYyODUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSctMzIuOTI3OTI3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY5LjcwMTY0NycgeT0nLTMyLjkyNzkyNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01NS45MTE1MDInIHk9Jy0zMi45Mjc5MjcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTMuNjEzMTQ0JyB5PSctMzIuOTI3OTI3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ0LjQxOTcxNScgeT0nLTMyLjkyNzkyNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00Mi4xMjEzNTcnIHk9Jy0zMi45Mjc5MjcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzUuMjI2Mjg1JyB5PSctMzIuOTI3OTI3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMyLjkyNzkyNycgeT0nLTMyLjkyNzkyNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zMC42Mjk1NycgeT0nLTMyLjkyNzkyNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yOC4zMzEyMTInIHk9Jy0zMi45Mjc5MjcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjEuNDM2MTQnIHk9Jy0zMi45Mjc5MjcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTkuMTM3NzgyJyB5PSctMzIuOTI3OTI3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nNi4xNDQxNScgeT0nLTMyLjkyNzkyNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzguNDQyNTA3JyB5PSctMzIuOTI3OTI3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nLTMwLjYyOTU3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY5LjcwMTY0NycgeT0nLTMwLjYyOTU3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY3LjQwMzI4OScgeT0nLTMwLjYyOTU3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY1LjEwNDkzMicgeT0nLTMwLjYyOTU3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTU4LjIwOTg1OScgeT0nLTMwLjYyOTU3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTU1LjkxMTUwMicgeT0nLTMwLjYyOTU3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUzLjYxMzE0NCcgeT0nLTMwLjYyOTU3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ5LjAxNjQyOScgeT0nLTMwLjYyOTU3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQyLjEyMTM1NycgeT0nLTMwLjYyOTU3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM5LjgyMycgeT0nLTMwLjYyOTU3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM3LjUyNDY0MicgeT0nLTMwLjYyOTU3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTIzLjczNDQ5NycgeT0nLTMwLjYyOTU3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTEyLjI0MjcxJyB5PSctMzAuNjI5NTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctOS45NDQzNTInIHk9Jy0zMC42Mjk1NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03LjY0NTk5NScgeT0nLTMwLjYyOTU3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUuMzQ3NjM3JyB5PSctMzAuNjI5NTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMy4wNDkyOCcgeT0nLTMwLjYyOTU3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nNi4xNDQxNScgeT0nLTMwLjYyOTU3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nOC40NDI1MDcnIHk9Jy0zMC42Mjk1NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEwLjc0MDg2NScgeT0nLTMwLjYyOTU3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nLTI4LjMzMTIxMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02OS43MDE2NDcnIHk9Jy0yOC4zMzEyMTInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjAuNTA4MjE3JyB5PSctMjguMzMxMjEyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTU1LjkxMTUwMicgeT0nLTI4LjMzMTIxMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01My42MTMxNDQnIHk9Jy0yOC4zMzEyMTInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDQuNDE5NzE1JyB5PSctMjguMzMxMjEyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQyLjEyMTM1NycgeT0nLTI4LjMzMTIxMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zNS4yMjYyODUnIHk9Jy0yOC4zMzEyMTInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjYuMDMyODU1JyB5PSctMjguMzMxMjEyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTIzLjczNDQ5NycgeT0nLTI4LjMzMTIxMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy05Ljk0NDM1MicgeT0nLTI4LjMzMTIxMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0uNzUwOTIyJyB5PSctMjguMzMxMjEyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMTAuNzQwODY1JyB5PSctMjguMzMxMjEyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY1LjEwNDkzMicgeT0nLTI2LjAzMjg1NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02MC41MDgyMTcnIHk9Jy0yNi4wMzI4NTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTguMjA5ODU5JyB5PSctMjYuMDMyODU1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTU1LjkxMTUwMicgeT0nLTI2LjAzMjg1NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01My42MTMxNDQnIHk9Jy0yNi4wMzI4NTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTEuMzE0Nzg3JyB5PSctMjYuMDMyODU1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ0LjQxOTcxNScgeT0nLTI2LjAzMjg1NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zOS44MjMnIHk9Jy0yNi4wMzI4NTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzcuNTI0NjQyJyB5PSctMjYuMDMyODU1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM1LjIyNjI4NScgeT0nLTI2LjAzMjg1NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zMi45Mjc5MjcnIHk9Jy0yNi4wMzI4NTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzAuNjI5NTcnIHk9Jy0yNi4wMzI4NTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjYuMDMyODU1JyB5PSctMjYuMDMyODU1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTIxLjQzNjE0JyB5PSctMjYuMDMyODU1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE5LjEzNzc4MicgeT0nLTI2LjAzMjg1NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xNi44Mzk0MjUnIHk9Jy0yNi4wMzI4NTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTQuNTQxMDY3JyB5PSctMjYuMDMyODU1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcuNjQ1OTk1JyB5PSctMjYuMDMyODU1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMuMDQ5MjgnIHk9Jy0yNi4wMzI4NTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PScxLjU0NzQzNScgeT0nLTI2LjAzMjg1NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzMuODQ1NzkzJyB5PSctMjYuMDMyODU1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nNi4xNDQxNScgeT0nLTI2LjAzMjg1NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzguNDQyNTA3JyB5PSctMjYuMDMyODU1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMTAuNzQwODY1JyB5PSctMjYuMDMyODU1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTYwLjUwODIxNycgeT0nLTIzLjczNDQ5NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01NS45MTE1MDInIHk9Jy0yMy43MzQ0OTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTMuNjEzMTQ0JyB5PSctMjMuNzM0NDk3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUxLjMxNDc4NycgeT0nLTIzLjczNDQ5NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00OS4wMTY0MjknIHk9Jy0yMy43MzQ0OTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzIuOTI3OTI3JyB5PSctMjMuNzM0NDk3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTI4LjMzMTIxMicgeT0nLTIzLjczNDQ5NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yMy43MzQ0OTcnIHk9Jy0yMy43MzQ0OTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTkuMTM3NzgyJyB5PSctMjMuNzM0NDk3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTEyLjI0MjcxJyB5PSctMjMuNzM0NDk3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLS43NTA5MjInIHk9Jy0yMy43MzQ0OTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSc4LjQ0MjUwNycgeT0nLTIzLjczNDQ5NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy0yMS40MzYxNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02Ny40MDMyODknIHk9Jy0yMS40MzYxNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02Mi44MDY1NzQnIHk9Jy0yMS40MzYxNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02MC41MDgyMTcnIHk9Jy0yMS40MzYxNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01OC4yMDk4NTknIHk9Jy0yMS40MzYxNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01NS45MTE1MDInIHk9Jy0yMS40MzYxNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01MS4zMTQ3ODcnIHk9Jy0yMS40MzYxNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00OS4wMTY0MjknIHk9Jy0yMS40MzYxNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00Ni43MTgwNzInIHk9Jy0yMS40MzYxNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00NC40MTk3MTUnIHk9Jy0yMS40MzYxNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zNy41MjQ2NDInIHk9Jy0yMS40MzYxNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zMC42Mjk1NycgeT0nLTIxLjQzNjE0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTI2LjAzMjg1NScgeT0nLTIxLjQzNjE0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTIzLjczNDQ5NycgeT0nLTIxLjQzNjE0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTIxLjQzNjE0JyB5PSctMjEuNDM2MTQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTYuODM5NDI1JyB5PSctMjEuNDM2MTQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTQuNTQxMDY3JyB5PSctMjEuNDM2MTQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctOS45NDQzNTInIHk9Jy0yMS40MzYxNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03LjY0NTk5NScgeT0nLTIxLjQzNjE0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUuMzQ3NjM3JyB5PSctMjEuNDM2MTQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctLjc1MDkyMicgeT0nLTIxLjQzNjE0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMy44NDU3OTMnIHk9Jy0yMS40MzYxNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzguNDQyNTA3JyB5PSctMjEuNDM2MTQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PScxMC43NDA4NjUnIHk9Jy0yMS40MzYxNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy0xOS4xMzc3ODInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjcuNDAzMjg5JyB5PSctMTkuMTM3NzgyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY1LjEwNDkzMicgeT0nLTE5LjEzNzc4MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02Mi44MDY1NzQnIHk9Jy0xOS4xMzc3ODInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTUuOTExNTAyJyB5PSctMTkuMTM3NzgyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ5LjAxNjQyOScgeT0nLTE5LjEzNzc4MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00Ni43MTgwNzInIHk9Jy0xOS4xMzc3ODInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzkuODIzJyB5PSctMTkuMTM3NzgyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMwLjYyOTU3JyB5PSctMTkuMTM3NzgyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTI2LjAzMjg1NScgeT0nLTE5LjEzNzc4MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yMy43MzQ0OTcnIHk9Jy0xOS4xMzc3ODInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjEuNDM2MTQnIHk9Jy0xOS4xMzc3ODInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTkuMTM3NzgyJyB5PSctMTkuMTM3NzgyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTEyLjI0MjcxJyB5PSctMTkuMTM3NzgyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTkuOTQ0MzUyJyB5PSctMTkuMTM3NzgyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcuNjQ1OTk1JyB5PSctMTkuMTM3NzgyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUuMzQ3NjM3JyB5PSctMTkuMTM3NzgyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMuMDQ5MjgnIHk9Jy0xOS4xMzc3ODInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PScxLjU0NzQzNScgeT0nLTE5LjEzNzc4MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEwLjc0MDg2NScgeT0nLTE5LjEzNzc4MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy0xNi44Mzk0MjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjkuNzAxNjQ3JyB5PSctMTYuODM5NDI1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY3LjQwMzI4OScgeT0nLTE2LjgzOTQyNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02NS4xMDQ5MzInIHk9Jy0xNi44Mzk0MjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjIuODA2NTc0JyB5PSctMTYuODM5NDI1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTYwLjUwODIxNycgeT0nLTE2LjgzOTQyNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01OC4yMDk4NTknIHk9Jy0xNi44Mzk0MjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTMuNjEzMTQ0JyB5PSctMTYuODM5NDI1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUxLjMxNDc4NycgeT0nLTE2LjgzOTQyNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00OS4wMTY0MjknIHk9Jy0xNi44Mzk0MjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDYuNzE4MDcyJyB5PSctMTYuODM5NDI1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM3LjUyNDY0MicgeT0nLTE2LjgzOTQyNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zNS4yMjYyODUnIHk9Jy0xNi44Mzk0MjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzIuOTI3OTI3JyB5PSctMTYuODM5NDI1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTI4LjMzMTIxMicgeT0nLTE2LjgzOTQyNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xOS4xMzc3ODInIHk9Jy0xNi44Mzk0MjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTYuODM5NDI1JyB5PSctMTYuODM5NDI1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE0LjU0MTA2NycgeT0nLTE2LjgzOTQyNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zLjA0OTI4JyB5PSctMTYuODM5NDI1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLS43NTA5MjInIHk9Jy0xNi44Mzk0MjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PScxLjU0NzQzNScgeT0nLTE2LjgzOTQyNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzMuODQ1NzkzJyB5PSctMTYuODM5NDI1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nNi4xNDQxNScgeT0nLTE2LjgzOTQyNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzguNDQyNTA3JyB5PSctMTYuODM5NDI1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMTAuNzQwODY1JyB5PSctMTYuODM5NDI1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nLTE0LjU0MTA2NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02OS43MDE2NDcnIHk9Jy0xNC41NDEwNjcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjUuMTA0OTMyJyB5PSctMTQuNTQxMDY3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTYwLjUwODIxNycgeT0nLTE0LjU0MTA2NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01NS45MTE1MDInIHk9Jy0xNC41NDEwNjcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTEuMzE0Nzg3JyB5PSctMTQuNTQxMDY3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ5LjAxNjQyOScgeT0nLTE0LjU0MTA2NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00NC40MTk3MTUnIHk9Jy0xNC41NDEwNjcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDIuMTIxMzU3JyB5PSctMTQuNTQxMDY3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM5LjgyMycgeT0nLTE0LjU0MTA2NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zMC42Mjk1NycgeT0nLTE0LjU0MTA2NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yOC4zMzEyMTInIHk9Jy0xNC41NDEwNjcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjMuNzM0NDk3JyB5PSctMTQuNTQxMDY3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTIxLjQzNjE0JyB5PSctMTQuNTQxMDY3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE5LjEzNzc4MicgeT0nLTE0LjU0MTA2NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xNi44Mzk0MjUnIHk9Jy0xNC41NDEwNjcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTIuMjQyNzEnIHk9Jy0xNC41NDEwNjcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNS4zNDc2MzcnIHk9Jy0xNC41NDEwNjcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSczLjg0NTc5MycgeT0nLTE0LjU0MTA2NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzguNDQyNTA3JyB5PSctMTQuNTQxMDY3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nLTEyLjI0MjcxJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY3LjQwMzI4OScgeT0nLTEyLjI0MjcxJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTYwLjUwODIxNycgeT0nLTEyLjI0MjcxJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTU4LjIwOTg1OScgeT0nLTEyLjI0MjcxJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTU1LjkxMTUwMicgeT0nLTEyLjI0MjcxJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQyLjEyMTM1NycgeT0nLTEyLjI0MjcxJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM5LjgyMycgeT0nLTEyLjI0MjcxJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM3LjUyNDY0MicgeT0nLTEyLjI0MjcxJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM1LjIyNjI4NScgeT0nLTEyLjI0MjcxJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTI2LjAzMjg1NScgeT0nLTEyLjI0MjcxJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTIzLjczNDQ5NycgeT0nLTEyLjI0MjcxJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTIxLjQzNjE0JyB5PSctMTIuMjQyNzEnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTYuODM5NDI1JyB5PSctMTIuMjQyNzEnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctOS45NDQzNTInIHk9Jy0xMi4yNDI3MScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03LjY0NTk5NScgeT0nLTEyLjI0MjcxJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUuMzQ3NjM3JyB5PSctMTIuMjQyNzEnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMy4wNDkyOCcgeT0nLTEyLjI0MjcxJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMS41NDc0MzUnIHk9Jy0xMi4yNDI3MScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzYuMTQ0MTUnIHk9Jy0xMi4yNDI3MScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzguNDQyNTA3JyB5PSctMTIuMjQyNzEnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PScxMC43NDA4NjUnIHk9Jy0xMi4yNDI3MScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy05Ljk0NDM1MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02MC41MDgyMTcnIHk9Jy05Ljk0NDM1MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01My42MTMxNDQnIHk9Jy05Ljk0NDM1MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00OS4wMTY0MjknIHk9Jy05Ljk0NDM1MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00NC40MTk3MTUnIHk9Jy05Ljk0NDM1MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00Mi4xMjEzNTcnIHk9Jy05Ljk0NDM1MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zNy41MjQ2NDInIHk9Jy05Ljk0NDM1MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yNi4wMzI4NTUnIHk9Jy05Ljk0NDM1MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yMy43MzQ0OTcnIHk9Jy05Ljk0NDM1MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy05Ljk0NDM1MicgeT0nLTkuOTQ0MzUyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUuMzQ3NjM3JyB5PSctOS45NDQzNTInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMy4wNDkyOCcgeT0nLTkuOTQ0MzUyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMTAuNzQwODY1JyB5PSctOS45NDQzNTInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSctNy42NDU5OTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjcuNDAzMjg5JyB5PSctNy42NDU5OTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjUuMTA0OTMyJyB5PSctNy42NDU5OTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjAuNTA4MjE3JyB5PSctNy42NDU5OTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTguMjA5ODU5JyB5PSctNy42NDU5OTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTUuOTExNTAyJyB5PSctNy42NDU5OTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDQuNDE5NzE1JyB5PSctNy42NDU5OTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzkuODIzJyB5PSctNy42NDU5OTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzUuMjI2Mjg1JyB5PSctNy42NDU5OTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzIuOTI3OTI3JyB5PSctNy42NDU5OTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjEuNDM2MTQnIHk9Jy03LjY0NTk5NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xNC41NDEwNjcnIHk9Jy03LjY0NTk5NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03LjY0NTk5NScgeT0nLTcuNjQ1OTk1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUuMzQ3NjM3JyB5PSctNy42NDU5OTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMy4wNDkyOCcgeT0nLTcuNjQ1OTk1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLS43NTA5MjInIHk9Jy03LjY0NTk5NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEuNTQ3NDM1JyB5PSctNy42NDU5OTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSczLjg0NTc5MycgeT0nLTcuNjQ1OTk1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nNi4xNDQxNScgeT0nLTcuNjQ1OTk1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUzLjYxMzE0NCcgeT0nLTUuMzQ3NjM3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ5LjAxNjQyOScgeT0nLTUuMzQ3NjM3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMwLjYyOTU3JyB5PSctNS4zNDc2MzcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjguMzMxMjEyJyB5PSctNS4zNDc2MzcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjYuMDMyODU1JyB5PSctNS4zNDc2MzcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjMuNzM0NDk3JyB5PSctNS4zNDc2MzcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTkuMTM3NzgyJyB5PSctNS4zNDc2MzcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTYuODM5NDI1JyB5PSctNS4zNDc2MzcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTIuMjQyNzEnIHk9Jy01LjM0NzYzNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03LjY0NTk5NScgeT0nLTUuMzQ3NjM3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMS41NDc0MzUnIHk9Jy01LjM0NzYzNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy0zLjA0OTI4JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY5LjcwMTY0NycgeT0nLTMuMDQ5MjgnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjcuNDAzMjg5JyB5PSctMy4wNDkyOCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02NS4xMDQ5MzInIHk9Jy0zLjA0OTI4JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTYyLjgwNjU3NCcgeT0nLTMuMDQ5MjgnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjAuNTA4MjE3JyB5PSctMy4wNDkyOCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01OC4yMDk4NTknIHk9Jy0zLjA0OTI4JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUzLjYxMzE0NCcgeT0nLTMuMDQ5MjgnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDYuNzE4MDcyJyB5PSctMy4wNDkyOCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00NC40MTk3MTUnIHk9Jy0zLjA0OTI4JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM3LjUyNDY0MicgeT0nLTMuMDQ5MjgnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzAuNjI5NTcnIHk9Jy0zLjA0OTI4JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTI2LjAzMjg1NScgeT0nLTMuMDQ5MjgnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjEuNDM2MTQnIHk9Jy0zLjA0OTI4JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE2LjgzOTQyNScgeT0nLTMuMDQ5MjgnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTQuNTQxMDY3JyB5PSctMy4wNDkyOCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xMi4yNDI3MScgeT0nLTMuMDQ5MjgnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNy42NDU5OTUnIHk9Jy0zLjA0OTI4JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMuMDQ5MjgnIHk9Jy0zLjA0OTI4JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMS41NDc0MzUnIHk9Jy0zLjA0OTI4JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nOC40NDI1MDcnIHk9Jy0zLjA0OTI4JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMTAuNzQwODY1JyB5PSctMy4wNDkyOCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy0uNzUwOTIyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTU4LjIwOTg1OScgeT0nLS43NTA5MjInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDYuNzE4MDcyJyB5PSctLjc1MDkyMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zOS44MjMnIHk9Jy0uNzUwOTIyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM3LjUyNDY0MicgeT0nLS43NTA5MjInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjYuMDMyODU1JyB5PSctLjc1MDkyMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yMy43MzQ0OTcnIHk9Jy0uNzUwOTIyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE2LjgzOTQyNScgeT0nLS43NTA5MjInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTIuMjQyNzEnIHk9Jy0uNzUwOTIyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTkuOTQ0MzUyJyB5PSctLjc1MDkyMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03LjY0NTk5NScgeT0nLS43NTA5MjInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PScxLjU0NzQzNScgeT0nLS43NTA5MjInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSczLjg0NTc5MycgeT0nLS43NTA5MjInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PScxLjU0NzQzNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02Ny40MDMyODknIHk9JzEuNTQ3NDM1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY1LjEwNDkzMicgeT0nMS41NDc0MzUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjIuODA2NTc0JyB5PScxLjU0NzQzNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01OC4yMDk4NTknIHk9JzEuNTQ3NDM1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUzLjYxMzE0NCcgeT0nMS41NDc0MzUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTEuMzE0Nzg3JyB5PScxLjU0NzQzNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00Ni43MTgwNzInIHk9JzEuNTQ3NDM1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM1LjIyNjI4NScgeT0nMS41NDc0MzUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzIuOTI3OTI3JyB5PScxLjU0NzQzNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zMC42Mjk1NycgeT0nMS41NDc0MzUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTkuMTM3NzgyJyB5PScxLjU0NzQzNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xNC41NDEwNjcnIHk9JzEuNTQ3NDM1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTkuOTQ0MzUyJyB5PScxLjU0NzQzNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03LjY0NTk5NScgeT0nMS41NDc0MzUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNS4zNDc2MzcnIHk9JzEuNTQ3NDM1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMuMDQ5MjgnIHk9JzEuNTQ3NDM1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLS43NTA5MjInIHk9JzEuNTQ3NDM1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMS41NDc0MzUnIHk9JzEuNTQ3NDM1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nNi4xNDQxNScgeT0nMS41NDc0MzUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSczLjg0NTc5MycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02Ny40MDMyODknIHk9JzMuODQ1NzkzJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY1LjEwNDkzMicgeT0nMy44NDU3OTMnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjIuODA2NTc0JyB5PSczLjg0NTc5MycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01OC4yMDk4NTknIHk9JzMuODQ1NzkzJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUzLjYxMzE0NCcgeT0nMy44NDU3OTMnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTEuMzE0Nzg3JyB5PSczLjg0NTc5MycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00NC40MTk3MTUnIHk9JzMuODQ1NzkzJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQyLjEyMTM1NycgeT0nMy44NDU3OTMnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzkuODIzJyB5PSczLjg0NTc5MycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yOC4zMzEyMTInIHk9JzMuODQ1NzkzJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTI2LjAzMjg1NScgeT0nMy44NDU3OTMnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjEuNDM2MTQnIHk9JzMuODQ1NzkzJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE5LjEzNzc4MicgeT0nMy44NDU3OTMnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTYuODM5NDI1JyB5PSczLjg0NTc5MycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xMi4yNDI3MScgeT0nMy44NDU3OTMnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctOS45NDQzNTInIHk9JzMuODQ1NzkzJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUuMzQ3NjM3JyB5PSczLjg0NTc5MycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zLjA0OTI4JyB5PSczLjg0NTc5MycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEuNTQ3NDM1JyB5PSczLjg0NTc5MycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzguNDQyNTA3JyB5PSczLjg0NTc5MycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEwLjc0MDg2NScgeT0nMy44NDU3OTMnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSc2LjE0NDE1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY3LjQwMzI4OScgeT0nNi4xNDQxNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02NS4xMDQ5MzInIHk9JzYuMTQ0MTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjIuODA2NTc0JyB5PSc2LjE0NDE1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTU4LjIwOTg1OScgeT0nNi4xNDQxNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01My42MTMxNDQnIHk9JzYuMTQ0MTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTEuMzE0Nzg3JyB5PSc2LjE0NDE1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ5LjAxNjQyOScgeT0nNi4xNDQxNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00Mi4xMjEzNTcnIHk9JzYuMTQ0MTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzkuODIzJyB5PSc2LjE0NDE1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM3LjUyNDY0MicgeT0nNi4xNDQxNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zNS4yMjYyODUnIHk9JzYuMTQ0MTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzIuOTI3OTI3JyB5PSc2LjE0NDE1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMwLjYyOTU3JyB5PSc2LjE0NDE1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTIzLjczNDQ5NycgeT0nNi4xNDQxNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xNi44Mzk0MjUnIHk9JzYuMTQ0MTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctLjc1MDkyMicgeT0nNi4xNDQxNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzYuMTQ0MTUnIHk9JzYuMTQ0MTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSc4LjQ0MjUwNycgeT0nNi4xNDQxNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEwLjc0MDg2NScgeT0nNi4xNDQxNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9JzguNDQyNTA3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTU4LjIwOTg1OScgeT0nOC40NDI1MDcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTMuNjEzMTQ0JyB5PSc4LjQ0MjUwNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01MS4zMTQ3ODcnIHk9JzguNDQyNTA3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ0LjQxOTcxNScgeT0nOC40NDI1MDcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDIuMTIxMzU3JyB5PSc4LjQ0MjUwNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zNy41MjQ2NDInIHk9JzguNDQyNTA3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM1LjIyNjI4NScgeT0nOC40NDI1MDcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzAuNjI5NTcnIHk9JzguNDQyNTA3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTI4LjMzMTIxMicgeT0nOC40NDI1MDcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjMuNzM0NDk3JyB5PSc4LjQ0MjUwNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xOS4xMzc3ODInIHk9JzguNDQyNTA3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE2LjgzOTQyNScgeT0nOC40NDI1MDcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNy42NDU5OTUnIHk9JzguNDQyNTA3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUuMzQ3NjM3JyB5PSc4LjQ0MjUwNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zLjA0OTI4JyB5PSc4LjQ0MjUwNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEuNTQ3NDM1JyB5PSc4LjQ0MjUwNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEwLjc0MDg2NScgeT0nOC40NDI1MDcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjkuNzAxNjQ3JyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjcuNDAzMjg5JyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjUuMTA0OTMyJyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjIuODA2NTc0JyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjAuNTA4MjE3JyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTguMjA5ODU5JyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTMuNjEzMTQ0JyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTEuMzE0Nzg3JyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDkuMDE2NDI5JyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDQuNDE5NzE1JyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzkuODIzJyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzIuOTI3OTI3JyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzAuNjI5NTcnIHk9JzEwLjc0MDg2NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yMS40MzYxNCcgeT0nMTAuNzQwODY1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE2LjgzOTQyNScgeT0nMTAuNzQwODY1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE0LjU0MTA2NycgeT0nMTAuNzQwODY1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTEyLjI0MjcxJyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctOS45NDQzNTInIHk9JzEwLjc0MDg2NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zLjA0OTI4JyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctLjc1MDkyMicgeT0nMTAuNzQwODY1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMy44NDU3OTMnIHk9JzEwLjc0MDg2NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzYuMTQ0MTUnIHk9JzEwLjc0MDg2NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzguNDQyNTA3JyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PScxMC43NDA4NjUnIHk9JzEwLjc0MDg2NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjwvZz4KPC9zdmc+")} +}