commit 6af8fa6da8cb4f3b97ba52a5e8a24aa4beea54c6 Author: user Date: Tue Jul 21 19:14:20 2026 +0200 feat: add lab-rv32i-c-gpio-edges-debounce card diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f3f3d03 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +/build/ +/doc/generated/* +!/doc/generated/.gitkeep +!/doc/generated/main.tex +*.aux +*.fdb_latexmk +*.fls +*.log +*.out +*.upa +*.upb + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..42f8458 --- /dev/null +++ b/Makefile @@ -0,0 +1,65 @@ +RISCV_PREFIX ?= riscv64-unknown-elf- +CC := $(RISCV_PREFIX)gcc +OBJCOPY := $(RISCV_PREFIX)objcopy +OBJDUMP := $(RISCV_PREFIX)objdump +SIZE := $(RISCV_PREFIX)size + +RV_ENV_ROOT ?= /home/user/dev/edu/rv32i-hazard3-student-env +H3_COMMON ?= $(RV_ENV_ROOT)/vendor/Hazard3/test/sim/common +H3_INIT ?= $(H3_COMMON)/init.S +H3_IRQ_DISPATCH ?= $(H3_COMMON)/irq_dispatch.S +LDSCRIPT ?= $(H3_COMMON)/link_hazard3.ld +MEMOPS ?= $(RV_ENV_ROOT)/vendor/lab-runtime/memops.c + +BUILD_ROOT ?= build +TASKS := task01_gpio_polling task02_gpio_rising_irq task03_gpio_quiet_window task04_raw_c_superloop +ARCH ?= rv32i_zicsr_zifencei +ABI ?= ilp32 +CFLAGS := -std=gnu11 -march=$(ARCH) -mabi=$(ABI) -nostdlib -nostartfiles \ + -ffreestanding -fno-builtin -fno-stack-protector -fno-pic -mno-relax \ + -O0 -g3 -fno-omit-frame-pointer -Wall -Wextra \ + -Isrc/tasks -isystem $(H3_COMMON) +LDFLAGS := -Wl,--no-relax -T$(LDSCRIPT) +LIBS := -lgcc + +.PHONY: all tasks test card-test clean check-support task1 task2 task3 task4 +all: tasks +tasks: $(TASKS) +task1: $(word 1,$(TASKS)) +task2: $(word 2,$(TASKS)) +task3: $(word 3,$(TASKS)) +task4: $(word 4,$(TASKS)) +test: tasks + ./tests/test_hazard3.sh +card-test: + ./tests/test_card.sh + +check-support: + @test -f "$(H3_INIT)" + @test -f "$(H3_IRQ_DISPATCH)" + @test -f "$(H3_COMMON)/tb_gpio_io.h" + @test -f "$(H3_COMMON)/tb_uart_io.h" + @test -f "$(LDSCRIPT)" + @test -f "$(MEMOPS)" + +define TASK_RULES +$(1): $(BUILD_ROOT)/$(1)/prog.bin $(BUILD_ROOT)/$(1)/prog.lst + +$(BUILD_ROOT)/$(1)/prog.elf: crt0.S src/tasks/$(1).c src/tasks/c13_common.h $(H3_INIT) $(H3_IRQ_DISPATCH) $(LDSCRIPT) $(MEMOPS) | check-support + mkdir -p $$(@D) + $(CC) $(CFLAGS) $(LDFLAGS) -Wl,-Map,$(BUILD_ROOT)/$(1)/prog.map \ + -o $$@ $(H3_INIT) $(H3_IRQ_DISPATCH) crt0.S $(MEMOPS) src/tasks/$(1).c $(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 $$< > $$@ +endef + +$(foreach task,$(TASKS),$(eval $(call TASK_RULES,$(task)))) + +clean: + rm -rf $(BUILD_ROOT) + diff --git a/README.md b/README.md new file mode 100644 index 0000000..fdf8d4b --- /dev/null +++ b/README.md @@ -0,0 +1,67 @@ +# C13 — GPIO, zbocza i debounce na RV32I/Hazard3 + +Karta zamyka serię raw C czterema wykonywalnymi przykładami: + +1. polling `DIR`, `OUT` i `IN` z kontrolowanym `TEST_IN`; +2. rising edge → GPIO `PENDING` → external IRQ18 → dispatcher → W1C; +3. bounce `1 → 0 → 1` i akceptacja dopiero po quiet window mierzonym `mtime`; +4. superloop łączący machine timer, UART RX IRQ16 i GPIO IRQ18. + +Programy są freestanding RV32I+Zicsr+Zifencei i wykonują się w RTL +Hazard3/Verilator. Nie ma modelu hostowego, RTOS, kolejki ani semafora. + +## Rejestry modelu + +GPIO zaczyna się pod `0xc0000300` i udostępnia `OUT`, `OUT_SET`, `OUT_CLR`, +`IN`, `TEST_IN`, `RISE_EN`, `FALL_EN`, `PENDING` W1C oraz `DIR`. GPIO używa +external IRQ18. UART0 używa external IRQ16, a machine timer standardowego +machine timer interrupt o `mcause=0x80000007`. + +`TEST_IN` i UART `TEST_RX` są wyłącznie bodźcami testbencha. Symulują zmianę +otoczenia bez TCP lub fizycznego pinu. Nie są rejestrami produkcyjnego GPIO, +nie opisują RP2350 i nie mogą znaleźć się w sterowniku fizycznej płytki. + +## Budowanie i test + +```sh +make tasks +./tests/test_hazard3.sh +``` + +Oracle sprawdza kod wyjścia, timeout, nieobsłużone pułapki i raportowane +rejestry. Dodatkowo niezależnie przelicza odstępy bounce, granicę quiet window +i obecność `mret` w handlerze machine timer. + +Bieżący pomiar RTL: + +- Task01: `DIR=1`, wejście zewnętrzne `2`, po ustawieniu wyjścia `IN=3`, + po wyzerowaniu `IN=0`; +- Task02: jeden IRQ18, `PENDING=0x4` w ISR, W1C usuwa źródło i ponowny wysoki + poziom nie tworzy nowego zbocza; +- Task03: czasy low `0x591`, `0x8ea`, `0xc43`, odstępy po `0x359`, quiet + `0x7d0`, akceptacja po `0x878`, bez wczesnej akceptacji; +- Task04: po jednym timer IRQ, UART16 i GPIO18, bajt `U`, trzy działania main, + `OUT=0x7`, widoczne `IN=0x17`. + +Wartości czasowe zależą od bieżącego RTL i buildu. Kontraktem są relacje: +dwa odstępy bounce są dodatnie i krótsze od quiet window, a akceptacja następuje +nie wcześniej niż quiet po ostatnim zboczu. + +## Podział odpowiedzialności + +W Task02–Task04 ISR potwierdza źródło i publikuje minimalny stan. Debounce oraz +aktualizacja wyjść należą do kodu normalnego. Task04 używa prostych flag +jednozdarzeniowych; nie jest odporną na dowolne przeciążenie kolejką zdarzeń. +To świadoma granica między raw C a kolejną serią FreeRTOS. + +## Karta + +```sh +./scripts/render_card_layouts.sh +./scripts/render_new_pdf.sh +./tests/test_card.sh +``` + +Każdy przykład ma dokładnie A1–A8. Tylko Task01.A3 jest N/D, ponieważ polling +nie ma mechanizmu dispatchu. + diff --git a/crt0.S b/crt0.S new file mode 100644 index 0000000..8521cf7 --- /dev/null +++ b/crt0.S @@ -0,0 +1,24 @@ + .text + .global _start + .type _start, @function + +_start: +.option push +.option norelax + la gp, __global_pointer$ +.option pop + + # common/init.S installed sp and mtvec before entering this startup. + la a0, __bss_start + la a1, __bss_end +1: + bgeu a0, a1, 2f + sb zero, 0(a0) + addi a0, a0, 1 + j 1b +2: + call main + tail _exit + + .size _start, .-_start + diff --git a/doc/generated/.gitkeep b/doc/generated/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/doc/generated/.gitkeep @@ -0,0 +1 @@ + diff --git a/doc/generated/main.tex b/doc/generated/main.tex new file mode 100644 index 0000000..0f10080 --- /dev/null +++ b/doc/generated/main.tex @@ -0,0 +1,553 @@ +% 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}{13} +\newcommand{\CardCount}{13} +\newcommand{\CardSlug}{gpio-edges-debounce} +\newcommand{\CardVersion}{v00.01} +\newcommand{\DocumentUUID}{72e2cbba-4658-5de2-a0dc-8b600ee3f7b0} + +\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-gpio-edges-debounce}{\qrcode[level=L,height=22mm]{https://zsl-gitea.mpabi.pl/edu-inf/lab-rv32i-c-gpio-edges-debounce}}% + \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 GPIO, zbocza i quiet-window debounce}\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 13/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 72e2cbba-4658-5de2-a0dc-8b600ee3f7b0}\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 29e6021a-d033-5fbe-a5fc-ec03442ac68a}\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-gpio-edges-debounce}{\nolinkurl{https://zsl-gitea.mpabi.pl/edu-inf/lab-rv32i-c-gpio-edges-debounce}}}} \\% + \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/29e6021a-d033-5fbe-a5fc-ec03442ac68a}{\nolinkurl{https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/29e6021a-d033-5fbe-a5fc-ec03442ac68a}}}} \\% + \end{tabularx}% + \end{minipage}% + \vrule width0.35pt% + \begin{minipage}[c][23mm][c]{24mm}\centering% + \href{https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/29e6021a-d033-5fbe-a5fc-ec03442ac68a}{\qrcode[level=L,height=22mm]{https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/29e6021a-d033-5fbe-a5fc-ec03442ac68a}}% + \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ń uruchamia obrazy RV32I z limitem cykli, odczytuje rejestry MMIO i kontrolera przerwań,\textCR przelicza czasy bounce i sprawdza, że main, a nie ISR, wykonuje politykę debounce oraz\textCR aktualizuje wyjścia.}}\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ń dla każdego zdarzenia wskazuje osobno source, pending, enable, decyzję dispatchera,\textCR minimalny efekt ISR i późniejszy efekt normalnego kodu.}}\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 fizyczny lub modelowany poziom wejścia, detekcję zbocza, zatrzaśnięty pending, maskowanie kontrolera, wybór handlera i efekt wykonywany później przez main. Potrafi zrealizować quiet-window debounce oraz połączyć timer, UART i GPIO w końcowym superloop bez RTOS. + +\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} +Cztery przykłady wykonują się na centralnym modelu RTL Hazard3. TEST\_IN i UART TEST\_RX są jawnie wyłącznie bodźcami testbencha. Karta nie udaje modelu RP2350 ani fizycznego pinu. Task01 dowodzi DIR/OUT/IN przez polling, Task02 pełnej ścieżki rising-edge IRQ18 z W1C, Task03 krótkiego ISR i decyzji debounce w main, a Task04 współpracy machine timer, UART IRQ16 i GPIO IRQ18.\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{Typ} & \textbf{Task} & \textbf{Idea} & \textbf{Waga} \\ \hline +\hline +\textbf{\texttt{POLL}} & \textbf{\texttt{Task01}} & \textbf{kierunek, latch wyjścia i testbench-only bodziec wejścia} & \textbf{kluczowe} \\ \hline +\hline +\textbf{\texttt{IRQ18}} & \textbf{\texttt{Task02}} & \textbf{zbocze, pending peryferium, kontroler i resume} & \textbf{kluczowe} \\ \hline +\hline +\textbf{\texttt{DBNC}} & \textbf{\texttt{Task03}} & \textbf{krótki ISR, mtime i decyzja stabilności w main} & \textbf{kluczowe} \\ \hline +\hline +\textbf{\texttt{LOOP}} & \textbf{\texttt{Task04}} & \textbf{trzy źródła, dwa dispatchery, flagi i efekty main} & \textbf{kluczowe} \\ \hline +\end{tabularx} +\normalsize + + +\vspace{0.8em} +\noindent\textcolor{black!25}{\rule{\textwidth}{0.35pt}} + +\clearpage + +\ESCSectionBlockStart +\section{1 — Rejestr modelu nie jest fizycznym pinem} +\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] + + +GPIO modelu zaczyna się pod adresem \texttt{0xc0000300}. \texttt{DIR} wybiera kierunek, \texttt{OUT/OUT\_SET/OUT\_CLR} sterują zatrzaśnięciem wyjściowym, a \texttt{IN} pokazuje wyjścia dla pinów ustawionych jako output i bodziec zewnętrzny dla pinów input. \texttt{RISE\_EN} i \texttt{FALL\_EN} wybierają wykrywane zbocza, a \texttt{PENDING} zatrzaskuje je do zapisu W1C. + +\texttt{TEST\_IN} istnieje tylko po stronie laboratorium. Pozwala programowi testowemu wywołać zmianę otoczenia bez fizycznego przewodu. Produkcyjny sterownik czyta \texttt{IN}; nie powinien zawierać zapisu do takiego fixture'u. +\ESCSectionBlockEnd + +\ESCSectionBlockStart +\section{2 — Source, pending i enable to trzy różne fakty} +\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] + + +Zmiana 0 na 1 jest source dla detektora rising edge. Włączony bit \texttt{RISE\_EN} pozwala zatrzasnąć bit w \texttt{PENDING}; ten bit utrzymuje poziomową linię GPIO external IRQ18. Kontroler Hazard3 osobno ma per-line enable, priorytet oraz globalne bramki \texttt{mie.MEIE} i \texttt{mstatus.MIE}. Dispatcher odczytuje aktywny numer i wywołuje handler z tablicy. + +W1C usuwa źródło poziomowego żądania po stronie peryferium. Sam powrót z handlera, odczyt \texttt{PENDING} ani zamknięcie maski nie potwierdzają zdarzenia. +\ESCSectionBlockEnd + +\ESCSectionBlockStart +\section{3 — Debounce jest decyzją czasu w main} +\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] + + +ISR Task03 robi tylko trzy rzeczy: zapisuje czas i poziom, potwierdza pending przez W1C oraz na końcu publikuje licznik. Main obserwuje kandydata i akceptuje go dopiero wtedy, gdy od ostatniego zbocza minęło quiet window oraz bieżący poziom nadal odpowiada kandydatowi. Każde nowe zbocze przesuwa początek okna. + +Sekwencja \texttt{1--0--1} jest kontrolowanym bounce. Oba odstępy są krótsze od 2000 taktów, dlatego żaden z trzech bezpośrednich odczytów nie może zaakceptować stanu. To polityka aplikacji, nie funkcja kontrolera przerwań. +\ESCSectionBlockEnd + +\ESCSectionBlockStart +\section{4 — Superloop jest granicą serii raw C} +\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] + + +Task04 łączy machine timer, UART0 RX external IRQ16 i GPIO external IRQ18. ISR-y publikują flagi, a main konsumuje je i ustawia trzy różne bity wyjściowe. Flaga może skleić wiele produkcji, więc nie jest kolejką; zachowanie liczby i kolejności zdarzeń należy do następnej serii FreeRTOS. +\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 · Polling DIR, OUT i IN} +{\scriptsize\ttfamily 223fada6-43e4-532a-9c9b-e17445857214}\par +\begin{ESCBlockFrame}{A1 CONTEXT · AKTYWNE — dwa źródła widocznego IN} +\textbf{Zachowany przykład:} \nolinkurl{src/tasks/task01_gpio_polling.c}.\par Dla bitu z \texttt{DIR=1} widoczne \texttt{IN} pochodzi z latcha \texttt{OUT}; dla \texttt{DIR=0} pochodzi z modelowanego wejścia. \texttt{TEST\_IN} zmienia tylko tę drugą część i jest bodźcem laboratorium, nie pinem RP2350. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A2 STRUCTURE · AKTYWNE — pin0 output, pin1 input} +Maska 0x1 wybiera pin wyjściowy, a 0x2 wejściowy. Rejestry SET i CLR modyfikują latch bez read--modify--write. Jeden odczyt \texttt{IN} składa oba widoki, dlatego przy obu stanach wysokich wynosi 0x3. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A3 DISPATCH · N/D} +\textbf{N/D.} Task01 wyłącza detektory zboczy i przerwania; każdy krok jest bezpośrednim pollingiem MMIO, bez ISR, callbacku ani wyboru handlera. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A4 APPLICATION · AKTYWNE — kontrolowany round trip poziomów} +Po external high program widzi 0x2. SET pinu0 daje OUT=0x1 i IN=0x3. CLR pinu0 oraz TEST\_IN=0 kończą sekwencję IN=0. Te liczby są bitowymi relacjami modelu, nie numerami pinów konkretnej płytki. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A5 FLOW · AKTYWNE — configure, stimulate, sample, clear} +Program wyłącza edge enable, czyści pending, ustawia kierunek i stan początkowy. Następnie podaje bodziec wejściowy, próbkuje, ustawia output, próbkuje ponownie i zeruje oba źródła. Każdy pomiar następuje po odpowiadającym mu zapisie MMIO. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A6 STATE · AKTYWNE — 0x2 → 0x3 → 0x0} +Widoczny stan portu przechodzi kolejno przez tylko input high, oba bity high i oba low. Kierunek pozostaje 0x1 przez cały eksperyment, a pending pozostaje pusty. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A7 RUNTIME · AKTYWNE — rzeczywiste transakcje pod 0xc0000300} +Log RTL raportuje 1,2,1,3,0 i pass=1. Listing powinien pokazać osobne zapisy do offsetów DIR, TEST\_IN, OUT\_SET i OUT\_CLR oraz odczyty IN; nie ma wejścia do wspólnego dispatchera external IRQ. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A8 PATTERNS · AKTYWNE — polling z jawną granicą fixture} +Wzorzec produkcyjny konfiguruje kierunek i czyta wejście lub steruje wyjściem. Warstwa testowa może dostarczyć osobny mechanizm wstrzyknięcia, ale jego nazwa, dokumentacja i lokalizacja muszą uniemożliwiać pomylenie z rejestrem sprzętu. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{Ćwiczenie · Przewidywanie → wykonanie → wniosek} +Przewidź cztery wartości: IN po ustawieniu zewnętrznego pinu 1, OUT po ustawieniu pinu 0, IN przy obu wysokich i IN po wyzerowaniu. Wyjaśnij, dlaczego zapis TEST\_IN jest dozwolony tylko w fixture testbencha. +\par\textbf{Evidence:} Tabela DIR/OUT/IN przed uruchomieniem, log wykonania RTL Hazard3 z kodem wyjścia, odczyt rejestrów MMIO i wniosek oddzielający fixture TEST\_IN od produkcyjnego API GPIO. +\par\textbf{Acceptance:} Oracle: dir=1, external\_high=2, out\_after\_set=1, both\_high=3, final\_in=0, pass=1 i kod wyjścia 0. PENDING pozostaje 0, ponieważ detektory zboczy są wyłączone. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{TASK01 · Zapis dowodu ucznia} +\textbf{1. Przewidywanie przed uruchomieniem}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{2. Log RTL: DIR, OUT i kolejne wartości IN}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{3. Granica modelu: TEST\_IN kontra fizyczny pin}\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 · Rising edge, IRQ18 i W1C} +{\scriptsize\ttfamily 93fb66db-d0ac-5fc2-811e-5b28e072a346}\par +\begin{ESCBlockFrame}{A1 CONTEXT · AKTYWNE — zbocze tworzy zatrzaśnięty fakt} +\textbf{Zachowany przykład:} \nolinkurl{src/tasks/task02_gpio_rising_irq.c}.\par Bodziec TEST\_IN zmienia pin2 z 0 na 1. Włączony bit RISE\_EN tworzy bit 0x4 w GPIO PENDING, a ten utrzymuje external IRQ18. TEST\_IN jest sztuczny, lecz dalsza ścieżka przez kontroler i rdzeń jest rzeczywistą ścieżką modelu RTL. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A2 STRUCTURE · AKTYWNE — dwa pending i tablica handlerów} +Pierwszy pending leży w peryferium jako maska pinów. Drugi jest widokiem aktywnej linii 18 w kontrolerze Hazard3. Tablica \texttt{\_external\_irq\_table[18]} przechowuje adres zwykłej funkcji handlera. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A3 DISPATCH · AKTYWNE — external vector wybiera linię 18} +\texttt{mtvec} wybiera wspólny vector machine external interrupt. \texttt{irq\_dispatch.S} odczytuje aktywną linię z \texttt{meinext}, indeksuje tablicę i wykonuje pośredni \texttt{jalr} do handlera GPIO. Handler potwierdza, że bieżący numer to 18. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A4 APPLICATION · AKTYWNE — jedno zbocze, jedno wznowienie} +Program celowo generuje edge przy zamkniętym globalnym MIE. Dzięki temu może najpierw zmierzyć oba pending jako 1. Po otwarciu MIE oczekuje dokładnie jednego handlera, W1C, obu pending równych 0 i wykonania kodu resume. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A5 FLOW · AKTYWNE — source → pending → enable → dispatch → W1C} +0→1 ustawia GPIO PENDING. Włączona linia18, MEIE i później MIE dopuszczają trap. Dispatcher wybiera handler18; ISR próbkuje maskę i poziom, zapisuje tę maskę do PENDING jako W1C, a dopiero potem publikuje count. Main wraca i mierzy stan 0. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A6 STATE · AKTYWNE — IDLE, LATCHED, HANDLING, ACKED, RESUMED} +IDLE ma input low i pending 0. Rising edge tworzy LATCHED. Otwarcie MIE prowadzi do HANDLING. Zapis W1C tworzy ACKED, a powrót dispatchera RESUMED. Ponowne high pozostaje ACKED, ponieważ nie zaszła zmiana 0→1. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A7 RUNTIME · AKTYWNE — 0x4 w GPIO i 18 w kontrolerze} +Raport daje count=1, irq=0x12, source/controller przed 1, pending w ISR 0x4, oba pending po 0 i same-level 0. Listing ma zawierać handler GPIO oraz wspólny dispatcher zakończony \texttt{mret}. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A8 PATTERNS · AKTYWNE — acknowledge peripheral before publish} +Dla poziomowego IRQ najpierw ustal i usuń przyczynę po stronie peryferium, a dopiero potem publikuj zakończenie dla main. Zamknięcie maski może odłożyć obsługę, ale nie jest potwierdzeniem zdarzenia. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{Ćwiczenie · Przewidywanie → wykonanie → wniosek} +Rozpisz ścieżkę od zmiany TEST\_IN 0→1 do wznowienia main. Zaznacz GPIO PENDING, pending linii 18 w kontrolerze, dwa poziomy enable, decyzję dispatchera, zapis W1C i efekt ponownego podania tego samego poziomu. +\par\textbf{Evidence:} Przewidywany łańcuch source--pending--enable--dispatch--effect, log RTL z IRQ18 i stanami przed/po, listing wspólnego dispatchera oraz wniosek wyjaśniający W1C i brak drugiego zbocza dla high→high. +\par\textbf{Acceptance:} Jeden handler IRQ18 widzi PENDING=0x4 i poziom high. GPIO source oraz controller pending są 1 przed globalnym enable i 0 po W1C; high→high nie tworzy nowego pending, resume=1, pass=1. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{TASK02 · Zapis dowodu ucznia} +\textbf{1. Przewidywanie przed uruchomieniem}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{2. Log RTL: pending GPIO i kontrolera przed/po ISR}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{3. Dowód dispatchu IRQ18 i zapisu W1C}\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 · Quiet-window debounce po trzech zboczach} +{\scriptsize\ttfamily a2e3b023-04f1-5863-a4e0-360b5ec69b89}\par +\begin{ESCBlockFrame}{A1 CONTEXT · AKTYWNE — IRQ rejestruje zmianę, nie intencję użytkownika} +\textbf{Zachowany przykład:} \nolinkurl{src/tasks/task03_gpio_quiet_window.c}.\par Trzy przejścia TEST\_IN modelują bounce, nie trzy świadome naciśnięcia. Kontroler potrafi zgłosić rising i falling edge, lecz nie zna quiet window ani znaczenia stabilnego przycisku. Ta semantyka należy do kodu normalnego. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A2 STRUCTURE · AKTYWNE — historia ISR i kandydat main} +ISR zapisuje trzy pary \texttt{level,time}, a osobno publikuje ostatni poziom, ostatni czas i count. Main utrzymuje seen count, candidate level oraz candidate time. Krytyczna sekcja chroni snapshot 64-bitowego czasu na RV32. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A3 DISPATCH · AKTYWNE — każde włączone zbocze wybiera GPIO18} +RISE\_EN i FALL\_EN pozwalają trzem przejściom utworzyć pending. External dispatcher trzy razy wybiera wpis 18 i wywołuje ten sam krótki handler. Numer ostatniego handlera oraz count=3 są dowodem decyzji, nie sam fakt zapisu TEST\_IN. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A4 APPLICATION · AKTYWNE — restart okna po każdym bounce} +Po każdym nowym count main zastępuje candidate time czasem ostatniego zbocza. Natychmiastowe próby dają early=0. Dopiero stabilny high utrzymany przez co najmniej 2000 taktów daje accepted=1. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A5 FLOW · AKTYWNE — ISR publish, main observe, wait, validate} +ISR czyta pending, poziom i mtime, zapisuje rekord, wykonuje W1C i na końcu zwiększa count. Main atomowo pobiera publikację, aktualizuje kandydata, mierzy wiek oraz porównuje bieżący IN. Nowe zbocze wraca do początku okna. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A6 STATE · AKTYWNE — HIGH?, LOW?, HIGH?, STABLE\_HIGH} +Pierwsze high jest kandydatem, low unieważnia go, a drugie high tworzy nowego kandydata. Żaden stan z wiekiem mniejszym niż quiet nie jest zaakceptowany. STABLE\_HIGH powstaje dopiero po pełnym oknie bez kolejnego IRQ. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A7 RUNTIME · AKTYWNE — dwa bounce gapy krótsze od 0x7d0} +Bieżący RTL raportuje czasy low 0x591, 0x8ea, 0xc43, czyli oba gapy 0x359. Akceptacja następuje po 0x878 od ostatniego edge. Konkretne czasy zależą od buildu; oracle niezależnie sprawdza tylko relacje gap=quiet. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A8 PATTERNS · AKTYWNE — timestamp in ISR, policy in consumer} +ISR powinien szybko potwierdzić sprzęt i opublikować minimalne dane. Konsument może wtedy zmieniać quiet window, politykę akceptacji lub raportowanie bez wydłużania czasu blokowania innych przerwań. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{Ćwiczenie · Przewidywanie → wykonanie → wniosek} +Dla sekwencji poziomów 1,0,1 oblicz oba odstępy i porównaj z quiet=2000. Wyjaśnij, dlaczego ISR publikuje czas, lecz nie akceptuje przycisku, oraz jak nowe zbocze restartuje okno ciszy. +\par\textbf{Evidence:} Przewidywana sekwencja kandydatów, log RTL z trzema czasami i poziomami, niezależne przeliczenie gapów oraz accepted\_after i wniosek przypisujący politykę debounce do main. +\par\textbf{Acceptance:} Poziomy 1,0,1, count=3 i IRQ18. Oba gapy są dodatnie i mniejsze od quiet=2000; early=0, accepted=1, zaakceptowany poziom high, accepted\_after >= quiet i pass=1. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{TASK03 · Zapis dowodu ucznia} +\textbf{1. Przewidywanie przed uruchomieniem}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{2. Log RTL: trzy poziomy, czasy i gapy}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{3. Dowód quiet window i miejsca decyzji w main}\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 · Timer + UART16 + GPIO18 bez RTOS} +{\scriptsize\ttfamily ebb18b6a-cf31-5595-9901-ac2ac870296f}\par +\begin{ESCBlockFrame}{A1 CONTEXT · AKTYWNE — trzy usługi, wspólny czas CPU} +\textbf{Zachowany przykład:} \nolinkurl{src/tasks/task04_raw_c_superloop.c}.\par Machine timer pochodzi z mtime>=mtimecmp, UART16 z niepustego RX FIFO przy włączonym RX IRQ, a GPIO18 z rising edge zatrzaśniętego w PENDING. TEST\_RX i TEST\_IN tworzą tylko bodźce; logika timer/UART/GPIO po nich jest rzeczywistym modelem RTL. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A2 STRUCTURE · AKTYWNE — trzy publikacje i trzy bity efektu} +Każda usługa ma licznik ISR, payload i flagę. Main ma osobny licznik konsumpcji. Bity OUT 0,1,2 reprezentują odpowiednio efekt GPIO, UART i timera, więc końcowe 0x7 dowodzi wykonania trzech gałęzi bez ukrywania ich w jednej sumie. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A3 DISPATCH · AKTYWNE — slot 7 oraz external 16/18} +Machine timer cause 7 trafia bezpośrednio do \texttt{isr\_machine\_timer} i wraca przez \texttt{mret}. Machine external vector trafia do wspólnego dispatchera; \texttt{meinext} wybiera wpis 16 dla UART albo 18 dla GPIO i wykonuje \texttt{jalr}. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A4 APPLICATION · AKTYWNE — efekt dopiero po konsumpcji flagi} +UART handler publikuje U, GPIO handler high, a timer handler tick. Żaden ISR nie ustawia aplikacyjnego bitu OUT. Superloop atomowo zabiera flagę i dopiero jego trzy gałęzie ustawiają 0x2, 0x1 i 0x4. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A5 FLOW · AKTYWNE — source → pending → dispatch → ISR → main} +Timer: comparator→MTIP→slot7→tick flag→bit2. UART: RX FIFO→IRQ16→external dispatcher→read DATA i flag→bit1. GPIO: edge→PENDING→IRQ18→dispatcher→W1C i flag→bit0. Main używa WFI tylko wtedy, gdy nadal brakuje któregoś efektu. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A6 STATE · AKTYWNE — trzy niezależne PRODUCED/CONSUMED} +Każda usługa przechodzi IDLE→PRODUCED w ISR i PRODUCED→CONSUMED w main. Stan końcowy wymaga trzech liczników konsumpcji równych 1. Flaga wraca do 0, ale licznik zachowuje dowód przejścia. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A7 RUNTIME · AKTYWNE — cause 7, linie 16/18 i OUT 0x7} +Raport daje timer count 1 i mcause 0x80000007, UART count 1/irq 0x10/byte 0x55, GPIO count 1/irq 0x12/high oraz trzy main actions po 1. OUT=0x7, a IN=0x17 dodaje widoczny wysoki pin wejściowy 0x10. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{A8 PATTERNS · AKTYWNE — ISR-to-main flags with an explicit ceiling} +Jednokomórkowa flaga jest poprawna tylko wtedy, gdy wystarcza informacja co najmniej jedno zdarzenie. Nie zachowuje liczby ani kolejności wielu produkcji. Ten sufit jest powodem przejścia do kolejek i tasków FreeRTOS, a nie pretekstem do nazywania flagi kolejką. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{Ćwiczenie · Przewidywanie → wykonanie → wniosek} +Dla timer tick, bajtu U i rising edge narysuj trzy osobne ścieżki source--pending--enable--dispatcher--ISR--flag--main effect. Wyjaśnij, dlaczego trzy flagi nie są kolejką i jakie ograniczenie przechodzi do serii FreeRTOS. +\par\textbf{Evidence:} Trzy przewidywane ścieżki zdarzeń, log RTL z numerami przerwań i licznikami, listing machine-timer oraz external dispatchera, końcowe OUT/IN i wniosek o granicy flag jednozdarzeniowych. +\par\textbf{Acceptance:} Po jednym timer IRQ z mcause=0x80000007, UART IRQ16 z bajtem 0x55 i GPIO IRQ18 z high. Main konsumuje każdą flagę raz, ustawia trzy bity, OUT=0x7, IN=0x17, pass=1. +\end{ESCBlockFrame} +\begin{ESCBlockFrame}{TASK04 · Zapis dowodu ucznia} +\textbf{1. Przewidywanie przed uruchomieniem}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{2. Log RTL: timer, UART16, GPIO18 i efekty main}\par\noindent\dotfill\par\noindent\dotfill\par\textbf{3. Dowód dwóch dispatcherów i końcowego OUT/IN}\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/pdf/.gitkeep b/doc/pdf/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/doc/pdf/.gitkeep @@ -0,0 +1 @@ + diff --git a/doc/pdf/mpabi-inf-c-13-gpio-edges-debounce-v00.01-72e2cbba-4658-5de2-a0dc-8b600ee3f7b0.pdf b/doc/pdf/mpabi-inf-c-13-gpio-edges-debounce-v00.01-72e2cbba-4658-5de2-a0dc-8b600ee3f7b0.pdf new file mode 100644 index 0000000..5fcd992 Binary files /dev/null and b/doc/pdf/mpabi-inf-c-13-gpio-edges-debounce-v00.01-72e2cbba-4658-5de2-a0dc-8b600ee3f7b0.pdf differ diff --git a/json/card_source.json b/json/card_source.json new file mode 100644 index 0000000..2cc8c1a --- /dev/null +++ b/json/card_source.json @@ -0,0 +1,823 @@ +{ + "$schema": "../../../tools/card-layouts/schemas/card-source.schema.json", + "schema": "esc-card-source.v1", + "card": { + "id": "mpabi-inf-c-13-gpio-edges-debounce", + "series": "c", + "series_title": "C · Freestanding RV32I and K&R", + "number": "13", + "count": "13", + "slug": "gpio-edges-debounce", + "title": "GPIO, zbocza i quiet-window debounce", + "topic": "RV32I/Hazard3: polling GPIO, external IRQ18, debounce i końcowy superloop raw C", + "project": "Freestanding C na RV32I", + "subject": "Informatyka", + "level": "Rok 1 · C13 · RV32I/Hazard3", + "revision_date": "2026-07-20T00:00:00+02:00", + "status": "Gotowa", + "version": "v00.01", + "uuid": "72e2cbba-4658-5de2-a0dc-8b600ee3f7b0", + "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": "GPIO, zbocza i quiet-window debounce", + "url": "https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/29e6021a-d033-5fbe-a5fc-ec03442ac68a", + "repository_url": "https://zsl-gitea.mpabi.pl/edu-inf/lab-rv32i-c-gpio-edges-debounce", + "url_host_uuid": "dce7fb9d-7b2f-5d49-96a2-3a30d3070b84", + "url_domain": "mpabi.pl", + "doc_uuid": "29e6021a-d033-5fbe-a5fc-ec03442ac68a", + "revision": "v00.01", + "issued_on": "2026-07-20T00:00:00+02:00", + "series": "C-13", + "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 fizyczny lub modelowany poziom wejścia, detekcję zbocza, zatrzaśnięty pending, maskowanie kontrolera, wybór handlera i efekt wykonywany później przez main. Potrafi zrealizować quiet-window debounce oraz połączyć timer, UART i GPIO w końcowym superloop bez RTOS.", + "scope_title": "Zakres i zachowane przykłady", + "scope_content_tex": "Cztery przykłady wykonują się na centralnym modelu RTL Hazard3. TEST\\_IN i UART TEST\\_RX są jawnie wyłącznie bodźcami testbencha. Karta nie udaje modelu RP2350 ani fizycznego pinu. Task01 dowodzi DIR/OUT/IN przez polling, Task02 pełnej ścieżki rising-edge IRQ18 z W1C, Task03 krótkiego ISR i decyzji debounce w main, a Task04 współpracy machine timer, UART IRQ16 i GPIO IRQ18.\\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": [ + "Typ", + "Task", + "Idea", + "Waga" + ], + "rows": [ + { + "chapter": "POLL", + "task": "Task01", + "idea_tex": "kierunek, latch wyjścia i testbench-only bodziec wejścia", + "priority": "kluczowe", + "key": true + }, + { + "chapter": "IRQ18", + "task": "Task02", + "idea_tex": "zbocze, pending peryferium, kontroler i resume", + "priority": "kluczowe", + "key": true + }, + { + "chapter": "DBNC", + "task": "Task03", + "idea_tex": "krótki ISR, mtime i decyzja stabilności w main", + "priority": "kluczowe", + "key": true + }, + { + "chapter": "LOOP", + "task": "Task04", + "idea_tex": "trzy źródła, dwa dispatchery, flagi i efekty main", + "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": { + "C13.EN01": { + "bloom_level": "Analiza", + "label": "Od poziomu wejścia do efektu aplikacji", + "text": "Uczeń dla każdego zdarzenia wskazuje osobno source, pending, enable, decyzję dispatchera, minimalny efekt ISR i późniejszy efekt normalnego kodu.", + "assessment_criteria": [ + "C13.KW01" + ] + }, + "C13.EK01": { + "bloom_level": "Zastosowanie", + "label": "Dowód na GPIO/UART/timer RTL", + "text": "Uczeń uruchamia obrazy RV32I z limitem cykli, odczytuje rejestry MMIO i kontrolera przerwań, przelicza czasy bounce i sprawdza, że main, a nie ISR, wykonuje politykę debounce oraz aktualizuje wyjścia.", + "assessment_criteria": [ + "C13.KW01" + ] + } + }, + "assessment_criteria": { + "C13.KW01": { + "text": "Cztery programy kończą się kodem 0 bez timeoutu i nieobsłużonej pułapki. Task01 daje DIR=1 oraz sekwencję IN 2,3,0. Task02 ma jeden IRQ18, PENDING=0x4 w handlerze, source i controller pending 1 przed obsługą oraz 0 po W1C. Task03 zapisuje poziomy 1,0,1, oba odstępy dodatnie i krótsze od quiet=2000, zero wczesnych akceptacji i jedną akceptację po co najmniej quiet. Task04 ma po jednym timer IRQ, UART16 i GPIO18, trzy efekty main, OUT=0x7 oraz IN=0x17.", + "learning_effects": [ + "C13.EN01", + "C13.EK01" + ] + } + }, + "educational_requirements": { + "C13.WE01": { + "text": "Obsługa GPIO i zdarzeń w raw C z jawną granicą bodźca testbench, krótkim ISR, W1C, synchronizacją z main i bez przypisywania modelowi właściwości RP2350.", + "label": "RV32I/Hazard3: polling GPIO, external IRQ18, debounce i końcowy superloop raw C", + "learning_effects": [ + "C13.EN01", + "C13.EK01" + ], + "learning_tree": { + "schema": "we-learning-tree.v1", + "policy": "Najpierw przewidywanie, następnie wykonanie i odczyt dowodu.", + "ogolne": [ + { + "effect_ref": "C13.EN01", + "display": "EN C13 01", + "source": "LOCAL", + "official": "C", + "local": "01", + "kind": "EN", + "tree_id": "C13.WE01.OG.LOCAL.C.01", + "text": "Uczeń dla każdego zdarzenia wskazuje osobno source, pending, enable, decyzję dispatchera, minimalny efekt ISR i późniejszy efekt normalnego kodu.", + "kw": [ + { + "criterion_ref": "C13.KW01", + "display": "KW C13 01", + "source": "LOCAL", + "kind": "KW", + "official": "C", + "local": "01", + "text": "Kod, przewidywanie i pomiar tworzą jeden dowód." + } + ] + } + ], + "zawodowe": [ + { + "effect_ref": "C13.EK01", + "display": "EK C13 01", + "source": "LOCAL", + "official": "C", + "local": "01", + "kind": "EK", + "tree_id": "C13.WE01.TECH.LOCAL.C.01", + "text": "Uczeń uruchamia obrazy RV32I z limitem cykli, odczytuje rejestry MMIO i kontrolera przerwań, przelicza czasy bounce i sprawdza, że main, a nie ISR, wykonuje politykę debounce oraz aktualizuje wyjścia.", + "kw": [ + { + "criterion_ref": "C13.KW01", + "display": "KW C13 01", + "source": "LOCAL", + "kind": "KW", + "official": "C", + "local": "01", + "text": "Kod, przewidywanie i pomiar tworzą jeden dowód." + } + ] + } + ] + } + } + }, + "sections": [ + { + "title": "1 — Rejestr modelu nie jest fizycznym pinem", + "order": 10, + "content_kind": "prose", + "page_orientation": "portrait", + "content_tex": "GPIO modelu zaczyna się pod adresem \\texttt{0xc0000300}. \\texttt{DIR} wybiera kierunek, \\texttt{OUT/OUT\\_SET/OUT\\_CLR} sterują zatrzaśnięciem wyjściowym, a \\texttt{IN} pokazuje wyjścia dla pinów ustawionych jako output i bodziec zewnętrzny dla pinów input. \\texttt{RISE\\_EN} i \\texttt{FALL\\_EN} wybierają wykrywane zbocza, a \\texttt{PENDING} zatrzaskuje je do zapisu W1C.\n\n\\texttt{TEST\\_IN} istnieje tylko po stronie laboratorium. Pozwala programowi testowemu wywołać zmianę otoczenia bez fizycznego przewodu. Produkcyjny sterownik czyta \\texttt{IN}; nie powinien zawierać zapisu do takiego fixture'u.", + "educational_requirement_refs": [ + "C13.WE01" + ], + "learning_effect_refs": [ + "C13.EN01", + "C13.EK01" + ], + "assessment_criterion_refs": [ + "C13.KW01" + ] + }, + { + "title": "2 — Source, pending i enable to trzy różne fakty", + "order": 20, + "content_kind": "prose", + "page_orientation": "portrait", + "content_tex": "Zmiana 0 na 1 jest source dla detektora rising edge. Włączony bit \\texttt{RISE\\_EN} pozwala zatrzasnąć bit w \\texttt{PENDING}; ten bit utrzymuje poziomową linię GPIO external IRQ18. Kontroler Hazard3 osobno ma per-line enable, priorytet oraz globalne bramki \\texttt{mie.MEIE} i \\texttt{mstatus.MIE}. Dispatcher odczytuje aktywny numer i wywołuje handler z tablicy.\n\nW1C usuwa źródło poziomowego żądania po stronie peryferium. Sam powrót z handlera, odczyt \\texttt{PENDING} ani zamknięcie maski nie potwierdzają zdarzenia.", + "educational_requirement_refs": [ + "C13.WE01" + ], + "learning_effect_refs": [ + "C13.EN01", + "C13.EK01" + ], + "assessment_criterion_refs": [ + "C13.KW01" + ] + }, + { + "title": "3 — Debounce jest decyzją czasu w main", + "order": 30, + "content_kind": "prose", + "page_orientation": "portrait", + "content_tex": "ISR Task03 robi tylko trzy rzeczy: zapisuje czas i poziom, potwierdza pending przez W1C oraz na końcu publikuje licznik. Main obserwuje kandydata i akceptuje go dopiero wtedy, gdy od ostatniego zbocza minęło quiet window oraz bieżący poziom nadal odpowiada kandydatowi. Każde nowe zbocze przesuwa początek okna.\n\nSekwencja \\texttt{1--0--1} jest kontrolowanym bounce. Oba odstępy są krótsze od 2000 taktów, dlatego żaden z trzech bezpośrednich odczytów nie może zaakceptować stanu. To polityka aplikacji, nie funkcja kontrolera przerwań.", + "educational_requirement_refs": [ + "C13.WE01" + ], + "learning_effect_refs": [ + "C13.EN01", + "C13.EK01" + ], + "assessment_criterion_refs": [ + "C13.KW01" + ] + }, + { + "title": "4 — Superloop jest granicą serii raw C", + "order": 40, + "content_kind": "prose", + "page_orientation": "portrait", + "content_tex": "Task04 łączy machine timer, UART0 RX external IRQ16 i GPIO external IRQ18. ISR-y publikują flagi, a main konsumuje je i ustawia trzy różne bity wyjściowe. Flaga może skleić wiele produkcji, więc nie jest kolejką; zachowanie liczby i kolejności zdarzeń należy do następnej serii FreeRTOS.", + "educational_requirement_refs": [ + "C13.WE01" + ], + "learning_effect_refs": [ + "C13.EN01", + "C13.EK01" + ], + "assessment_criterion_refs": [ + "C13.KW01" + ] + }, + { + "title": "Zadania — zachowane przykłady w profilu A1–A8", + "order": 50, + "content_kind": "tasks", + "page_orientation": "portrait", + "task_refs": [ + "task01", + "task02", + "task03", + "task04" + ], + "educational_requirement_refs": [ + "C13.WE01" + ], + "learning_effect_refs": [ + "C13.EN01", + "C13.EK01" + ], + "assessment_criterion_refs": [ + "C13.KW01" + ] + } + ], + "tasks": { + "task01": { + "title": "Polling DIR, OUT i IN", + "uuid": "223fada6-43e4-532a-9c9b-e17445857214", + "prompt_tex": "Przewidź cztery wartości: IN po ustawieniu zewnętrznego pinu 1, OUT po ustawieniu pinu 0, IN przy obu wysokich i IN po wyzerowaniu. Wyjaśnij, dlaczego zapis TEST\\_IN jest dozwolony tylko w fixture testbencha.", + "criterion": "Oracle: dir=1, external_high=2, out_after_set=1, both_high=3, final_in=0, pass=1 i kod wyjścia 0. PENDING pozostaje 0, ponieważ detektory zboczy są wyłączone.", + "conclusion_tex": "", + "render_task_acceptance": false, + "viewpoints": [ + { + "id": "A1", + "status": "enabled", + "title": "CONTEXT — dwa źródła widocznego IN", + "content_tex": "Dla bitu z \\texttt{DIR=1} widoczne \\texttt{IN} pochodzi z latcha \\texttt{OUT}; dla \\texttt{DIR=0} pochodzi z modelowanego wejścia. \\texttt{TEST\\_IN} zmienia tylko tę drugą część i jest bodźcem laboratorium, nie pinem RP2350." + }, + { + "id": "A2", + "status": "enabled", + "title": "STRUCTURE — pin0 output, pin1 input", + "content_tex": "Maska 0x1 wybiera pin wyjściowy, a 0x2 wejściowy. Rejestry SET i CLR modyfikują latch bez read--modify--write. Jeden odczyt \\texttt{IN} składa oba widoki, dlatego przy obu stanach wysokich wynosi 0x3." + }, + { + "id": "A3", + "status": "unavailable", + "title": "DISPATCH", + "reason": "Task01 wyłącza detektory zboczy i przerwania; każdy krok jest bezpośrednim pollingiem MMIO, bez ISR, callbacku ani wyboru handlera." + }, + { + "id": "A4", + "status": "enabled", + "title": "APPLICATION — kontrolowany round trip poziomów", + "content_tex": "Po external high program widzi 0x2. SET pinu0 daje OUT=0x1 i IN=0x3. CLR pinu0 oraz TEST\\_IN=0 kończą sekwencję IN=0. Te liczby są bitowymi relacjami modelu, nie numerami pinów konkretnej płytki." + }, + { + "id": "A5", + "status": "enabled", + "title": "FLOW — configure, stimulate, sample, clear", + "content_tex": "Program wyłącza edge enable, czyści pending, ustawia kierunek i stan początkowy. Następnie podaje bodziec wejściowy, próbkuje, ustawia output, próbkuje ponownie i zeruje oba źródła. Każdy pomiar następuje po odpowiadającym mu zapisie MMIO." + }, + { + "id": "A6", + "status": "enabled", + "title": "STATE — 0x2 → 0x3 → 0x0", + "content_tex": "Widoczny stan portu przechodzi kolejno przez tylko input high, oba bity high i oba low. Kierunek pozostaje 0x1 przez cały eksperyment, a pending pozostaje pusty." + }, + { + "id": "A7", + "status": "enabled", + "title": "RUNTIME — rzeczywiste transakcje pod 0xc0000300", + "content_tex": "Log RTL raportuje 1,2,1,3,0 i pass=1. Listing powinien pokazać osobne zapisy do offsetów DIR, TEST\\_IN, OUT\\_SET i OUT\\_CLR oraz odczyty IN; nie ma wejścia do wspólnego dispatchera external IRQ." + }, + { + "id": "A8", + "status": "enabled", + "title": "PATTERNS — polling z jawną granicą fixture", + "content_tex": "Wzorzec produkcyjny konfiguruje kierunek i czyta wejście lub steruje wyjściem. Warstwa testowa może dostarczyć osobny mechanizm wstrzyknięcia, ale jego nazwa, dokumentacja i lokalizacja muszą uniemożliwiać pomylenie z rejestrem sprzętu." + } + ], + "flow": [ + { + "kind": "block", + "id": "task01.a1", + "title": "A1 CONTEXT · AKTYWNE — dwa źródła widocznego IN", + "content_tex": "\\textbf{Zachowany przykład:} \\nolinkurl{src/tasks/task01_gpio_polling.c}.\\par Dla bitu z \\texttt{DIR=1} widoczne \\texttt{IN} pochodzi z latcha \\texttt{OUT}; dla \\texttt{DIR=0} pochodzi z modelowanego wejścia. \\texttt{TEST\\_IN} zmienia tylko tę drugą część i jest bodźcem laboratorium, nie pinem RP2350." + }, + { + "kind": "block", + "id": "task01.a2", + "title": "A2 STRUCTURE · AKTYWNE — pin0 output, pin1 input", + "content_tex": "Maska 0x1 wybiera pin wyjściowy, a 0x2 wejściowy. Rejestry SET i CLR modyfikują latch bez read--modify--write. Jeden odczyt \\texttt{IN} składa oba widoki, dlatego przy obu stanach wysokich wynosi 0x3." + }, + { + "kind": "block", + "id": "task01.a3", + "title": "A3 DISPATCH · N/D", + "content_tex": "\\textbf{N/D.} Task01 wyłącza detektory zboczy i przerwania; każdy krok jest bezpośrednim pollingiem MMIO, bez ISR, callbacku ani wyboru handlera." + }, + { + "kind": "block", + "id": "task01.a4", + "title": "A4 APPLICATION · AKTYWNE — kontrolowany round trip poziomów", + "content_tex": "Po external high program widzi 0x2. SET pinu0 daje OUT=0x1 i IN=0x3. CLR pinu0 oraz TEST\\_IN=0 kończą sekwencję IN=0. Te liczby są bitowymi relacjami modelu, nie numerami pinów konkretnej płytki." + }, + { + "kind": "block", + "id": "task01.a5", + "title": "A5 FLOW · AKTYWNE — configure, stimulate, sample, clear", + "content_tex": "Program wyłącza edge enable, czyści pending, ustawia kierunek i stan początkowy. Następnie podaje bodziec wejściowy, próbkuje, ustawia output, próbkuje ponownie i zeruje oba źródła. Każdy pomiar następuje po odpowiadającym mu zapisie MMIO." + }, + { + "kind": "block", + "id": "task01.a6", + "title": "A6 STATE · AKTYWNE — 0x2 → 0x3 → 0x0", + "content_tex": "Widoczny stan portu przechodzi kolejno przez tylko input high, oba bity high i oba low. Kierunek pozostaje 0x1 przez cały eksperyment, a pending pozostaje pusty." + }, + { + "kind": "block", + "id": "task01.a7", + "title": "A7 RUNTIME · AKTYWNE — rzeczywiste transakcje pod 0xc0000300", + "content_tex": "Log RTL raportuje 1,2,1,3,0 i pass=1. Listing powinien pokazać osobne zapisy do offsetów DIR, TEST\\_IN, OUT\\_SET i OUT\\_CLR oraz odczyty IN; nie ma wejścia do wspólnego dispatchera external IRQ." + }, + { + "kind": "block", + "id": "task01.a8", + "title": "A8 PATTERNS · AKTYWNE — polling z jawną granicą fixture", + "content_tex": "Wzorzec produkcyjny konfiguruje kierunek i czyta wejście lub steruje wyjściem. Warstwa testowa może dostarczyć osobny mechanizm wstrzyknięcia, ale jego nazwa, dokumentacja i lokalizacja muszą uniemożliwiać pomylenie z rejestrem sprzętu." + }, + { + "kind": "exercise", + "id": "task01.proof", + "title": "Przewidywanie → wykonanie → wniosek", + "prompt_tex": "Przewidź cztery wartości: IN po ustawieniu zewnętrznego pinu 1, OUT po ustawieniu pinu 0, IN przy obu wysokich i IN po wyzerowaniu. Wyjaśnij, dlaczego zapis TEST\\_IN jest dozwolony tylko w fixture testbencha.", + "evidence_tex": "Tabela DIR/OUT/IN przed uruchomieniem, log wykonania RTL Hazard3 z kodem wyjścia, odczyt rejestrów MMIO i wniosek oddzielający fixture TEST\\_IN od produkcyjnego API GPIO.", + "criterion": "Oracle: dir=1, external_high=2, out_after_set=1, both_high=3, final_in=0, pass=1 i kod wyjścia 0. PENDING pozostaje 0, ponieważ detektory zboczy są wyłączone." + }, + { + "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. Log RTL: DIR, OUT i kolejne wartości IN}\\par\\noindent\\dotfill\\par\\noindent\\dotfill\\par\\textbf{3. Granica modelu: TEST\\_IN kontra fizyczny pin}\\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": [ + "C13.WE01" + ], + "learning_effect_refs": [ + "C13.EN01", + "C13.EK01" + ], + "assessment_criterion_ref": "C13.KW01" + }, + "task02": { + "title": "Rising edge, IRQ18 i W1C", + "uuid": "93fb66db-d0ac-5fc2-811e-5b28e072a346", + "prompt_tex": "Rozpisz ścieżkę od zmiany TEST\\_IN 0→1 do wznowienia main. Zaznacz GPIO PENDING, pending linii 18 w kontrolerze, dwa poziomy enable, decyzję dispatchera, zapis W1C i efekt ponownego podania tego samego poziomu.", + "criterion": "Jeden handler IRQ18 widzi PENDING=0x4 i poziom high. GPIO source oraz controller pending są 1 przed globalnym enable i 0 po W1C; high→high nie tworzy nowego pending, resume=1, pass=1.", + "conclusion_tex": "", + "render_task_acceptance": false, + "viewpoints": [ + { + "id": "A1", + "status": "enabled", + "title": "CONTEXT — zbocze tworzy zatrzaśnięty fakt", + "content_tex": "Bodziec TEST\\_IN zmienia pin2 z 0 na 1. Włączony bit RISE\\_EN tworzy bit 0x4 w GPIO PENDING, a ten utrzymuje external IRQ18. TEST\\_IN jest sztuczny, lecz dalsza ścieżka przez kontroler i rdzeń jest rzeczywistą ścieżką modelu RTL." + }, + { + "id": "A2", + "status": "enabled", + "title": "STRUCTURE — dwa pending i tablica handlerów", + "content_tex": "Pierwszy pending leży w peryferium jako maska pinów. Drugi jest widokiem aktywnej linii 18 w kontrolerze Hazard3. Tablica \\texttt{\\_external\\_irq\\_table[18]} przechowuje adres zwykłej funkcji handlera." + }, + { + "id": "A3", + "status": "enabled", + "title": "DISPATCH — external vector wybiera linię 18", + "content_tex": "\\texttt{mtvec} wybiera wspólny vector machine external interrupt. \\texttt{irq\\_dispatch.S} odczytuje aktywną linię z \\texttt{meinext}, indeksuje tablicę i wykonuje pośredni \\texttt{jalr} do handlera GPIO. Handler potwierdza, że bieżący numer to 18." + }, + { + "id": "A4", + "status": "enabled", + "title": "APPLICATION — jedno zbocze, jedno wznowienie", + "content_tex": "Program celowo generuje edge przy zamkniętym globalnym MIE. Dzięki temu może najpierw zmierzyć oba pending jako 1. Po otwarciu MIE oczekuje dokładnie jednego handlera, W1C, obu pending równych 0 i wykonania kodu resume." + }, + { + "id": "A5", + "status": "enabled", + "title": "FLOW — source → pending → enable → dispatch → W1C", + "content_tex": "0→1 ustawia GPIO PENDING. Włączona linia18, MEIE i później MIE dopuszczają trap. Dispatcher wybiera handler18; ISR próbkuje maskę i poziom, zapisuje tę maskę do PENDING jako W1C, a dopiero potem publikuje count. Main wraca i mierzy stan 0." + }, + { + "id": "A6", + "status": "enabled", + "title": "STATE — IDLE, LATCHED, HANDLING, ACKED, RESUMED", + "content_tex": "IDLE ma input low i pending 0. Rising edge tworzy LATCHED. Otwarcie MIE prowadzi do HANDLING. Zapis W1C tworzy ACKED, a powrót dispatchera RESUMED. Ponowne high pozostaje ACKED, ponieważ nie zaszła zmiana 0→1." + }, + { + "id": "A7", + "status": "enabled", + "title": "RUNTIME — 0x4 w GPIO i 18 w kontrolerze", + "content_tex": "Raport daje count=1, irq=0x12, source/controller przed 1, pending w ISR 0x4, oba pending po 0 i same-level 0. Listing ma zawierać handler GPIO oraz wspólny dispatcher zakończony \\texttt{mret}." + }, + { + "id": "A8", + "status": "enabled", + "title": "PATTERNS — acknowledge peripheral before publish", + "content_tex": "Dla poziomowego IRQ najpierw ustal i usuń przyczynę po stronie peryferium, a dopiero potem publikuj zakończenie dla main. Zamknięcie maski może odłożyć obsługę, ale nie jest potwierdzeniem zdarzenia." + } + ], + "flow": [ + { + "kind": "block", + "id": "task02.a1", + "title": "A1 CONTEXT · AKTYWNE — zbocze tworzy zatrzaśnięty fakt", + "content_tex": "\\textbf{Zachowany przykład:} \\nolinkurl{src/tasks/task02_gpio_rising_irq.c}.\\par Bodziec TEST\\_IN zmienia pin2 z 0 na 1. Włączony bit RISE\\_EN tworzy bit 0x4 w GPIO PENDING, a ten utrzymuje external IRQ18. TEST\\_IN jest sztuczny, lecz dalsza ścieżka przez kontroler i rdzeń jest rzeczywistą ścieżką modelu RTL." + }, + { + "kind": "block", + "id": "task02.a2", + "title": "A2 STRUCTURE · AKTYWNE — dwa pending i tablica handlerów", + "content_tex": "Pierwszy pending leży w peryferium jako maska pinów. Drugi jest widokiem aktywnej linii 18 w kontrolerze Hazard3. Tablica \\texttt{\\_external\\_irq\\_table[18]} przechowuje adres zwykłej funkcji handlera." + }, + { + "kind": "block", + "id": "task02.a3", + "title": "A3 DISPATCH · AKTYWNE — external vector wybiera linię 18", + "content_tex": "\\texttt{mtvec} wybiera wspólny vector machine external interrupt. \\texttt{irq\\_dispatch.S} odczytuje aktywną linię z \\texttt{meinext}, indeksuje tablicę i wykonuje pośredni \\texttt{jalr} do handlera GPIO. Handler potwierdza, że bieżący numer to 18." + }, + { + "kind": "block", + "id": "task02.a4", + "title": "A4 APPLICATION · AKTYWNE — jedno zbocze, jedno wznowienie", + "content_tex": "Program celowo generuje edge przy zamkniętym globalnym MIE. Dzięki temu może najpierw zmierzyć oba pending jako 1. Po otwarciu MIE oczekuje dokładnie jednego handlera, W1C, obu pending równych 0 i wykonania kodu resume." + }, + { + "kind": "block", + "id": "task02.a5", + "title": "A5 FLOW · AKTYWNE — source → pending → enable → dispatch → W1C", + "content_tex": "0→1 ustawia GPIO PENDING. Włączona linia18, MEIE i później MIE dopuszczają trap. Dispatcher wybiera handler18; ISR próbkuje maskę i poziom, zapisuje tę maskę do PENDING jako W1C, a dopiero potem publikuje count. Main wraca i mierzy stan 0." + }, + { + "kind": "block", + "id": "task02.a6", + "title": "A6 STATE · AKTYWNE — IDLE, LATCHED, HANDLING, ACKED, RESUMED", + "content_tex": "IDLE ma input low i pending 0. Rising edge tworzy LATCHED. Otwarcie MIE prowadzi do HANDLING. Zapis W1C tworzy ACKED, a powrót dispatchera RESUMED. Ponowne high pozostaje ACKED, ponieważ nie zaszła zmiana 0→1." + }, + { + "kind": "block", + "id": "task02.a7", + "title": "A7 RUNTIME · AKTYWNE — 0x4 w GPIO i 18 w kontrolerze", + "content_tex": "Raport daje count=1, irq=0x12, source/controller przed 1, pending w ISR 0x4, oba pending po 0 i same-level 0. Listing ma zawierać handler GPIO oraz wspólny dispatcher zakończony \\texttt{mret}." + }, + { + "kind": "block", + "id": "task02.a8", + "title": "A8 PATTERNS · AKTYWNE — acknowledge peripheral before publish", + "content_tex": "Dla poziomowego IRQ najpierw ustal i usuń przyczynę po stronie peryferium, a dopiero potem publikuj zakończenie dla main. Zamknięcie maski może odłożyć obsługę, ale nie jest potwierdzeniem zdarzenia." + }, + { + "kind": "exercise", + "id": "task02.proof", + "title": "Przewidywanie → wykonanie → wniosek", + "prompt_tex": "Rozpisz ścieżkę od zmiany TEST\\_IN 0→1 do wznowienia main. Zaznacz GPIO PENDING, pending linii 18 w kontrolerze, dwa poziomy enable, decyzję dispatchera, zapis W1C i efekt ponownego podania tego samego poziomu.", + "evidence_tex": "Przewidywany łańcuch source--pending--enable--dispatch--effect, log RTL z IRQ18 i stanami przed/po, listing wspólnego dispatchera oraz wniosek wyjaśniający W1C i brak drugiego zbocza dla high→high.", + "criterion": "Jeden handler IRQ18 widzi PENDING=0x4 i poziom high. GPIO source oraz controller pending są 1 przed globalnym enable i 0 po W1C; high→high nie tworzy nowego pending, resume=1, pass=1." + }, + { + "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. Log RTL: pending GPIO i kontrolera przed/po ISR}\\par\\noindent\\dotfill\\par\\noindent\\dotfill\\par\\textbf{3. Dowód dispatchu IRQ18 i zapisu W1C}\\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": [ + "C13.WE01" + ], + "learning_effect_refs": [ + "C13.EN01", + "C13.EK01" + ], + "assessment_criterion_ref": "C13.KW01" + }, + "task03": { + "title": "Quiet-window debounce po trzech zboczach", + "uuid": "a2e3b023-04f1-5863-a4e0-360b5ec69b89", + "prompt_tex": "Dla sekwencji poziomów 1,0,1 oblicz oba odstępy i porównaj z quiet=2000. Wyjaśnij, dlaczego ISR publikuje czas, lecz nie akceptuje przycisku, oraz jak nowe zbocze restartuje okno ciszy.", + "criterion": "Poziomy 1,0,1, count=3 i IRQ18. Oba gapy są dodatnie i mniejsze od quiet=2000; early=0, accepted=1, zaakceptowany poziom high, accepted_after >= quiet i pass=1.", + "conclusion_tex": "", + "render_task_acceptance": false, + "viewpoints": [ + { + "id": "A1", + "status": "enabled", + "title": "CONTEXT — IRQ rejestruje zmianę, nie intencję użytkownika", + "content_tex": "Trzy przejścia TEST\\_IN modelują bounce, nie trzy świadome naciśnięcia. Kontroler potrafi zgłosić rising i falling edge, lecz nie zna quiet window ani znaczenia stabilnego przycisku. Ta semantyka należy do kodu normalnego." + }, + { + "id": "A2", + "status": "enabled", + "title": "STRUCTURE — historia ISR i kandydat main", + "content_tex": "ISR zapisuje trzy pary \\texttt{level,time}, a osobno publikuje ostatni poziom, ostatni czas i count. Main utrzymuje seen count, candidate level oraz candidate time. Krytyczna sekcja chroni snapshot 64-bitowego czasu na RV32." + }, + { + "id": "A3", + "status": "enabled", + "title": "DISPATCH — każde włączone zbocze wybiera GPIO18", + "content_tex": "RISE\\_EN i FALL\\_EN pozwalają trzem przejściom utworzyć pending. External dispatcher trzy razy wybiera wpis 18 i wywołuje ten sam krótki handler. Numer ostatniego handlera oraz count=3 są dowodem decyzji, nie sam fakt zapisu TEST\\_IN." + }, + { + "id": "A4", + "status": "enabled", + "title": "APPLICATION — restart okna po każdym bounce", + "content_tex": "Po każdym nowym count main zastępuje candidate time czasem ostatniego zbocza. Natychmiastowe próby dają early=0. Dopiero stabilny high utrzymany przez co najmniej 2000 taktów daje accepted=1." + }, + { + "id": "A5", + "status": "enabled", + "title": "FLOW — ISR publish, main observe, wait, validate", + "content_tex": "ISR czyta pending, poziom i mtime, zapisuje rekord, wykonuje W1C i na końcu zwiększa count. Main atomowo pobiera publikację, aktualizuje kandydata, mierzy wiek oraz porównuje bieżący IN. Nowe zbocze wraca do początku okna." + }, + { + "id": "A6", + "status": "enabled", + "title": "STATE — HIGH?, LOW?, HIGH?, STABLE_HIGH", + "content_tex": "Pierwsze high jest kandydatem, low unieważnia go, a drugie high tworzy nowego kandydata. Żaden stan z wiekiem mniejszym niż quiet nie jest zaakceptowany. STABLE\\_HIGH powstaje dopiero po pełnym oknie bez kolejnego IRQ." + }, + { + "id": "A7", + "status": "enabled", + "title": "RUNTIME — dwa bounce gapy krótsze od 0x7d0", + "content_tex": "Bieżący RTL raportuje czasy low 0x591, 0x8ea, 0xc43, czyli oba gapy 0x359. Akceptacja następuje po 0x878 od ostatniego edge. Konkretne czasy zależą od buildu; oracle niezależnie sprawdza tylko relacje gap=quiet." + }, + { + "id": "A8", + "status": "enabled", + "title": "PATTERNS — timestamp in ISR, policy in consumer", + "content_tex": "ISR powinien szybko potwierdzić sprzęt i opublikować minimalne dane. Konsument może wtedy zmieniać quiet window, politykę akceptacji lub raportowanie bez wydłużania czasu blokowania innych przerwań." + } + ], + "flow": [ + { + "kind": "block", + "id": "task03.a1", + "title": "A1 CONTEXT · AKTYWNE — IRQ rejestruje zmianę, nie intencję użytkownika", + "content_tex": "\\textbf{Zachowany przykład:} \\nolinkurl{src/tasks/task03_gpio_quiet_window.c}.\\par Trzy przejścia TEST\\_IN modelują bounce, nie trzy świadome naciśnięcia. Kontroler potrafi zgłosić rising i falling edge, lecz nie zna quiet window ani znaczenia stabilnego przycisku. Ta semantyka należy do kodu normalnego." + }, + { + "kind": "block", + "id": "task03.a2", + "title": "A2 STRUCTURE · AKTYWNE — historia ISR i kandydat main", + "content_tex": "ISR zapisuje trzy pary \\texttt{level,time}, a osobno publikuje ostatni poziom, ostatni czas i count. Main utrzymuje seen count, candidate level oraz candidate time. Krytyczna sekcja chroni snapshot 64-bitowego czasu na RV32." + }, + { + "kind": "block", + "id": "task03.a3", + "title": "A3 DISPATCH · AKTYWNE — każde włączone zbocze wybiera GPIO18", + "content_tex": "RISE\\_EN i FALL\\_EN pozwalają trzem przejściom utworzyć pending. External dispatcher trzy razy wybiera wpis 18 i wywołuje ten sam krótki handler. Numer ostatniego handlera oraz count=3 są dowodem decyzji, nie sam fakt zapisu TEST\\_IN." + }, + { + "kind": "block", + "id": "task03.a4", + "title": "A4 APPLICATION · AKTYWNE — restart okna po każdym bounce", + "content_tex": "Po każdym nowym count main zastępuje candidate time czasem ostatniego zbocza. Natychmiastowe próby dają early=0. Dopiero stabilny high utrzymany przez co najmniej 2000 taktów daje accepted=1." + }, + { + "kind": "block", + "id": "task03.a5", + "title": "A5 FLOW · AKTYWNE — ISR publish, main observe, wait, validate", + "content_tex": "ISR czyta pending, poziom i mtime, zapisuje rekord, wykonuje W1C i na końcu zwiększa count. Main atomowo pobiera publikację, aktualizuje kandydata, mierzy wiek oraz porównuje bieżący IN. Nowe zbocze wraca do początku okna." + }, + { + "kind": "block", + "id": "task03.a6", + "title": "A6 STATE · AKTYWNE — HIGH?, LOW?, HIGH?, STABLE_HIGH", + "content_tex": "Pierwsze high jest kandydatem, low unieważnia go, a drugie high tworzy nowego kandydata. Żaden stan z wiekiem mniejszym niż quiet nie jest zaakceptowany. STABLE\\_HIGH powstaje dopiero po pełnym oknie bez kolejnego IRQ." + }, + { + "kind": "block", + "id": "task03.a7", + "title": "A7 RUNTIME · AKTYWNE — dwa bounce gapy krótsze od 0x7d0", + "content_tex": "Bieżący RTL raportuje czasy low 0x591, 0x8ea, 0xc43, czyli oba gapy 0x359. Akceptacja następuje po 0x878 od ostatniego edge. Konkretne czasy zależą od buildu; oracle niezależnie sprawdza tylko relacje gap=quiet." + }, + { + "kind": "block", + "id": "task03.a8", + "title": "A8 PATTERNS · AKTYWNE — timestamp in ISR, policy in consumer", + "content_tex": "ISR powinien szybko potwierdzić sprzęt i opublikować minimalne dane. Konsument może wtedy zmieniać quiet window, politykę akceptacji lub raportowanie bez wydłużania czasu blokowania innych przerwań." + }, + { + "kind": "exercise", + "id": "task03.proof", + "title": "Przewidywanie → wykonanie → wniosek", + "prompt_tex": "Dla sekwencji poziomów 1,0,1 oblicz oba odstępy i porównaj z quiet=2000. Wyjaśnij, dlaczego ISR publikuje czas, lecz nie akceptuje przycisku, oraz jak nowe zbocze restartuje okno ciszy.", + "evidence_tex": "Przewidywana sekwencja kandydatów, log RTL z trzema czasami i poziomami, niezależne przeliczenie gapów oraz accepted\\_after i wniosek przypisujący politykę debounce do main.", + "criterion": "Poziomy 1,0,1, count=3 i IRQ18. Oba gapy są dodatnie i mniejsze od quiet=2000; early=0, accepted=1, zaakceptowany poziom high, accepted_after >= quiet i pass=1." + }, + { + "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. Log RTL: trzy poziomy, czasy i gapy}\\par\\noindent\\dotfill\\par\\noindent\\dotfill\\par\\textbf{3. Dowód quiet window i miejsca decyzji w main}\\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": [ + "C13.WE01" + ], + "learning_effect_refs": [ + "C13.EN01", + "C13.EK01" + ], + "assessment_criterion_ref": "C13.KW01" + }, + "task04": { + "title": "Timer + UART16 + GPIO18 bez RTOS", + "uuid": "ebb18b6a-cf31-5595-9901-ac2ac870296f", + "prompt_tex": "Dla timer tick, bajtu U i rising edge narysuj trzy osobne ścieżki source--pending--enable--dispatcher--ISR--flag--main effect. Wyjaśnij, dlaczego trzy flagi nie są kolejką i jakie ograniczenie przechodzi do serii FreeRTOS.", + "criterion": "Po jednym timer IRQ z mcause=0x80000007, UART IRQ16 z bajtem 0x55 i GPIO IRQ18 z high. Main konsumuje każdą flagę raz, ustawia trzy bity, OUT=0x7, IN=0x17, pass=1.", + "conclusion_tex": "", + "render_task_acceptance": false, + "viewpoints": [ + { + "id": "A1", + "status": "enabled", + "title": "CONTEXT — trzy usługi, wspólny czas CPU", + "content_tex": "Machine timer pochodzi z mtime>=mtimecmp, UART16 z niepustego RX FIFO przy włączonym RX IRQ, a GPIO18 z rising edge zatrzaśniętego w PENDING. TEST\\_RX i TEST\\_IN tworzą tylko bodźce; logika timer/UART/GPIO po nich jest rzeczywistym modelem RTL." + }, + { + "id": "A2", + "status": "enabled", + "title": "STRUCTURE — trzy publikacje i trzy bity efektu", + "content_tex": "Każda usługa ma licznik ISR, payload i flagę. Main ma osobny licznik konsumpcji. Bity OUT 0,1,2 reprezentują odpowiednio efekt GPIO, UART i timera, więc końcowe 0x7 dowodzi wykonania trzech gałęzi bez ukrywania ich w jednej sumie." + }, + { + "id": "A3", + "status": "enabled", + "title": "DISPATCH — slot 7 oraz external 16/18", + "content_tex": "Machine timer cause 7 trafia bezpośrednio do \\texttt{isr\\_machine\\_timer} i wraca przez \\texttt{mret}. Machine external vector trafia do wspólnego dispatchera; \\texttt{meinext} wybiera wpis 16 dla UART albo 18 dla GPIO i wykonuje \\texttt{jalr}." + }, + { + "id": "A4", + "status": "enabled", + "title": "APPLICATION — efekt dopiero po konsumpcji flagi", + "content_tex": "UART handler publikuje U, GPIO handler high, a timer handler tick. Żaden ISR nie ustawia aplikacyjnego bitu OUT. Superloop atomowo zabiera flagę i dopiero jego trzy gałęzie ustawiają 0x2, 0x1 i 0x4." + }, + { + "id": "A5", + "status": "enabled", + "title": "FLOW — source → pending → dispatch → ISR → main", + "content_tex": "Timer: comparator→MTIP→slot7→tick flag→bit2. UART: RX FIFO→IRQ16→external dispatcher→read DATA i flag→bit1. GPIO: edge→PENDING→IRQ18→dispatcher→W1C i flag→bit0. Main używa WFI tylko wtedy, gdy nadal brakuje któregoś efektu." + }, + { + "id": "A6", + "status": "enabled", + "title": "STATE — trzy niezależne PRODUCED/CONSUMED", + "content_tex": "Każda usługa przechodzi IDLE→PRODUCED w ISR i PRODUCED→CONSUMED w main. Stan końcowy wymaga trzech liczników konsumpcji równych 1. Flaga wraca do 0, ale licznik zachowuje dowód przejścia." + }, + { + "id": "A7", + "status": "enabled", + "title": "RUNTIME — cause 7, linie 16/18 i OUT 0x7", + "content_tex": "Raport daje timer count 1 i mcause 0x80000007, UART count 1/irq 0x10/byte 0x55, GPIO count 1/irq 0x12/high oraz trzy main actions po 1. OUT=0x7, a IN=0x17 dodaje widoczny wysoki pin wejściowy 0x10." + }, + { + "id": "A8", + "status": "enabled", + "title": "PATTERNS — ISR-to-main flags with an explicit ceiling", + "content_tex": "Jednokomórkowa flaga jest poprawna tylko wtedy, gdy wystarcza informacja co najmniej jedno zdarzenie. Nie zachowuje liczby ani kolejności wielu produkcji. Ten sufit jest powodem przejścia do kolejek i tasków FreeRTOS, a nie pretekstem do nazywania flagi kolejką." + } + ], + "flow": [ + { + "kind": "block", + "id": "task04.a1", + "title": "A1 CONTEXT · AKTYWNE — trzy usługi, wspólny czas CPU", + "content_tex": "\\textbf{Zachowany przykład:} \\nolinkurl{src/tasks/task04_raw_c_superloop.c}.\\par Machine timer pochodzi z mtime>=mtimecmp, UART16 z niepustego RX FIFO przy włączonym RX IRQ, a GPIO18 z rising edge zatrzaśniętego w PENDING. TEST\\_RX i TEST\\_IN tworzą tylko bodźce; logika timer/UART/GPIO po nich jest rzeczywistym modelem RTL." + }, + { + "kind": "block", + "id": "task04.a2", + "title": "A2 STRUCTURE · AKTYWNE — trzy publikacje i trzy bity efektu", + "content_tex": "Każda usługa ma licznik ISR, payload i flagę. Main ma osobny licznik konsumpcji. Bity OUT 0,1,2 reprezentują odpowiednio efekt GPIO, UART i timera, więc końcowe 0x7 dowodzi wykonania trzech gałęzi bez ukrywania ich w jednej sumie." + }, + { + "kind": "block", + "id": "task04.a3", + "title": "A3 DISPATCH · AKTYWNE — slot 7 oraz external 16/18", + "content_tex": "Machine timer cause 7 trafia bezpośrednio do \\texttt{isr\\_machine\\_timer} i wraca przez \\texttt{mret}. Machine external vector trafia do wspólnego dispatchera; \\texttt{meinext} wybiera wpis 16 dla UART albo 18 dla GPIO i wykonuje \\texttt{jalr}." + }, + { + "kind": "block", + "id": "task04.a4", + "title": "A4 APPLICATION · AKTYWNE — efekt dopiero po konsumpcji flagi", + "content_tex": "UART handler publikuje U, GPIO handler high, a timer handler tick. Żaden ISR nie ustawia aplikacyjnego bitu OUT. Superloop atomowo zabiera flagę i dopiero jego trzy gałęzie ustawiają 0x2, 0x1 i 0x4." + }, + { + "kind": "block", + "id": "task04.a5", + "title": "A5 FLOW · AKTYWNE — source → pending → dispatch → ISR → main", + "content_tex": "Timer: comparator→MTIP→slot7→tick flag→bit2. UART: RX FIFO→IRQ16→external dispatcher→read DATA i flag→bit1. GPIO: edge→PENDING→IRQ18→dispatcher→W1C i flag→bit0. Main używa WFI tylko wtedy, gdy nadal brakuje któregoś efektu." + }, + { + "kind": "block", + "id": "task04.a6", + "title": "A6 STATE · AKTYWNE — trzy niezależne PRODUCED/CONSUMED", + "content_tex": "Każda usługa przechodzi IDLE→PRODUCED w ISR i PRODUCED→CONSUMED w main. Stan końcowy wymaga trzech liczników konsumpcji równych 1. Flaga wraca do 0, ale licznik zachowuje dowód przejścia." + }, + { + "kind": "block", + "id": "task04.a7", + "title": "A7 RUNTIME · AKTYWNE — cause 7, linie 16/18 i OUT 0x7", + "content_tex": "Raport daje timer count 1 i mcause 0x80000007, UART count 1/irq 0x10/byte 0x55, GPIO count 1/irq 0x12/high oraz trzy main actions po 1. OUT=0x7, a IN=0x17 dodaje widoczny wysoki pin wejściowy 0x10." + }, + { + "kind": "block", + "id": "task04.a8", + "title": "A8 PATTERNS · AKTYWNE — ISR-to-main flags with an explicit ceiling", + "content_tex": "Jednokomórkowa flaga jest poprawna tylko wtedy, gdy wystarcza informacja co najmniej jedno zdarzenie. Nie zachowuje liczby ani kolejności wielu produkcji. Ten sufit jest powodem przejścia do kolejek i tasków FreeRTOS, a nie pretekstem do nazywania flagi kolejką." + }, + { + "kind": "exercise", + "id": "task04.proof", + "title": "Przewidywanie → wykonanie → wniosek", + "prompt_tex": "Dla timer tick, bajtu U i rising edge narysuj trzy osobne ścieżki source--pending--enable--dispatcher--ISR--flag--main effect. Wyjaśnij, dlaczego trzy flagi nie są kolejką i jakie ograniczenie przechodzi do serii FreeRTOS.", + "evidence_tex": "Trzy przewidywane ścieżki zdarzeń, log RTL z numerami przerwań i licznikami, listing machine-timer oraz external dispatchera, końcowe OUT/IN i wniosek o granicy flag jednozdarzeniowych.", + "criterion": "Po jednym timer IRQ z mcause=0x80000007, UART IRQ16 z bajtem 0x55 i GPIO IRQ18 z high. Main konsumuje każdą flagę raz, ustawia trzy bity, OUT=0x7, IN=0x17, pass=1." + }, + { + "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. Log RTL: timer, UART16, GPIO18 i efekty main}\\par\\noindent\\dotfill\\par\\noindent\\dotfill\\par\\textbf{3. Dowód dwóch dispatcherów i końcowego OUT/IN}\\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": [ + "C13.WE01" + ], + "learning_effect_refs": [ + "C13.EN01", + "C13.EK01" + ], + "assessment_criterion_ref": "C13.KW01" + } + }, + "tasks_order": [ + "task01", + "task02", + "task03", + "task04" + ] +} diff --git a/json/card_spec.json b/json/card_spec.json new file mode 100644 index 0000000..271a0d8 --- /dev/null +++ b/json/card_spec.json @@ -0,0 +1,302 @@ +{ + "card": { + "number": "13", + "slug": "gpio-edges-debounce", + "title": "GPIO, zbocza i quiet-window debounce", + "topic": "RV32I/Hazard3: polling GPIO, external IRQ18, debounce i końcowy superloop raw C", + "status": "Gotowa", + "version": "v00.01", + "revision_date": "2026-07-20T00:00:00+02:00", + "level": "Rok 1 · C13 · RV32I/Hazard3" + }, + "front": { + "goal": "Uczeń rozdziela fizyczny lub modelowany poziom wejścia, detekcję zbocza, zatrzaśnięty pending, maskowanie kontrolera, wybór handlera i efekt wykonywany później przez main. Potrafi zrealizować quiet-window debounce oraz połączyć timer, UART i GPIO w końcowym superloop bez RTOS.", + "scope": "Cztery przykłady wykonują się na centralnym modelu RTL Hazard3. TEST\u005c_IN i UART TEST\u005c_RX są jawnie wyłącznie bodźcami testbencha. Karta nie udaje modelu RP2350 ani fizycznego pinu. Task01 dowodzi DIR/OUT/IN przez polling, Task02 pełnej ścieżki rising-edge IRQ18 z W1C, Task03 krótkiego ISR i decyzji debounce w main, a Task04 współpracy machine timer, UART IRQ16 i GPIO IRQ18.", + "scope_note": "Każdy przykład ma dokładnie A1–A8. Widok N/D występuje tylko wtedy, gdy dany mechanizm naprawdę nie istnieje." + }, + "scope_headers": ["Typ", "Task", "Idea", "Waga"], + "learning": { + "reasoning_label": "Od poziomu wejścia do efektu aplikacji", + "reasoning": "Uczeń dla każdego zdarzenia wskazuje osobno source, pending, enable, decyzję dispatchera, minimalny efekt ISR i późniejszy efekt normalnego kodu.", + "practice_label": "Dowód na GPIO/UART/timer RTL", + "practice": "Uczeń uruchamia obrazy RV32I z limitem cykli, odczytuje rejestry MMIO i kontrolera przerwań, przelicza czasy bounce i sprawdza, że main, a nie ISR, wykonuje politykę debounce oraz aktualizuje wyjścia.", + "criterion": "Cztery programy kończą się kodem 0 bez timeoutu i nieobsłużonej pułapki. Task01 daje DIR=1 oraz sekwencję IN 2,3,0. Task02 ma jeden IRQ18, PENDING=0x4 w handlerze, source i controller pending 1 przed obsługą oraz 0 po W1C. Task03 zapisuje poziomy 1,0,1, oba odstępy dodatnie i krótsze od quiet=2000, zero wczesnych akceptacji i jedną akceptację po co najmniej quiet. Task04 ma po jednym timer IRQ, UART16 i GPIO18, trzy efekty main, OUT=0x7 oraz IN=0x17.", + "requirement": "Obsługa GPIO i zdarzeń w raw C z jawną granicą bodźca testbench, krótkim ISR, W1C, synchronizacją z main i bez przypisywania modelowi właściwości RP2350." + }, + "sections": [ + { + "title": "1 — Rejestr modelu nie jest fizycznym pinem", + "content_tex": "GPIO modelu zaczyna się pod adresem \u005ctexttt{0xc0000300}. \u005ctexttt{DIR} wybiera kierunek, \u005ctexttt{OUT/OUT\u005c_SET/OUT\u005c_CLR} sterują zatrzaśnięciem wyjściowym, a \u005ctexttt{IN} pokazuje wyjścia dla pinów ustawionych jako output i bodziec zewnętrzny dla pinów input. \u005ctexttt{RISE\u005c_EN} i \u005ctexttt{FALL\u005c_EN} wybierają wykrywane zbocza, a \u005ctexttt{PENDING} zatrzaskuje je do zapisu W1C.\n\n\u005ctexttt{TEST\u005c_IN} istnieje tylko po stronie laboratorium. Pozwala programowi testowemu wywołać zmianę otoczenia bez fizycznego przewodu. Produkcyjny sterownik czyta \u005ctexttt{IN}; nie powinien zawierać zapisu do takiego fixture'u." + }, + { + "title": "2 — Source, pending i enable to trzy różne fakty", + "content_tex": "Zmiana 0 na 1 jest source dla detektora rising edge. Włączony bit \u005ctexttt{RISE\u005c_EN} pozwala zatrzasnąć bit w \u005ctexttt{PENDING}; ten bit utrzymuje poziomową linię GPIO external IRQ18. Kontroler Hazard3 osobno ma per-line enable, priorytet oraz globalne bramki \u005ctexttt{mie.MEIE} i \u005ctexttt{mstatus.MIE}. Dispatcher odczytuje aktywny numer i wywołuje handler z tablicy.\n\nW1C usuwa źródło poziomowego żądania po stronie peryferium. Sam powrót z handlera, odczyt \u005ctexttt{PENDING} ani zamknięcie maski nie potwierdzają zdarzenia." + }, + { + "title": "3 — Debounce jest decyzją czasu w main", + "content_tex": "ISR Task03 robi tylko trzy rzeczy: zapisuje czas i poziom, potwierdza pending przez W1C oraz na końcu publikuje licznik. Main obserwuje kandydata i akceptuje go dopiero wtedy, gdy od ostatniego zbocza minęło quiet window oraz bieżący poziom nadal odpowiada kandydatowi. Każde nowe zbocze przesuwa początek okna.\n\nSekwencja \u005ctexttt{1--0--1} jest kontrolowanym bounce. Oba odstępy są krótsze od 2000 taktów, dlatego żaden z trzech bezpośrednich odczytów nie może zaakceptować stanu. To polityka aplikacji, nie funkcja kontrolera przerwań." + }, + { + "title": "4 — Superloop jest granicą serii raw C", + "content_tex": "Task04 łączy machine timer, UART0 RX external IRQ16 i GPIO external IRQ18. ISR-y publikują flagi, a main konsumuje je i ustawia trzy różne bity wyjściowe. Flaga może skleić wiele produkcji, więc nie jest kolejką; zachowanie liczby i kolejności zdarzeń należy do następnej serii FreeRTOS." + } + ], + "tasks": [ + { + "id": "task01", + "source": "src/tasks/task01_gpio_polling.c", + "chapter": "POLL", + "title": "Polling DIR, OUT i IN", + "idea_tex": "kierunek, latch wyjścia i testbench-only bodziec wejścia", + "priority": "kluczowe", + "key": true, + "prompt_tex": "Przewidź cztery wartości: IN po ustawieniu zewnętrznego pinu 1, OUT po ustawieniu pinu 0, IN przy obu wysokich i IN po wyzerowaniu. Wyjaśnij, dlaczego zapis TEST\u005c_IN jest dozwolony tylko w fixture testbencha.", + "evidence_tex": "Tabela DIR/OUT/IN przed uruchomieniem, log wykonania RTL Hazard3 z kodem wyjścia, odczyt rejestrów MMIO i wniosek oddzielający fixture TEST\u005c_IN od produkcyjnego API GPIO.", + "worksheet_step2": "Log RTL: DIR, OUT i kolejne wartości IN", + "worksheet_step3": "Granica modelu: TEST\u005c_IN kontra fizyczny pin", + "criterion": "Oracle: dir=1, external_high=2, out_after_set=1, both_high=3, final_in=0, pass=1 i kod wyjścia 0. PENDING pozostaje 0, ponieważ detektory zboczy są wyłączone.", + "viewpoints": [ + { + "id": "A1", + "status": "enabled", + "title": "CONTEXT — dwa źródła widocznego IN", + "content_tex": "Dla bitu z \u005ctexttt{DIR=1} widoczne \u005ctexttt{IN} pochodzi z latcha \u005ctexttt{OUT}; dla \u005ctexttt{DIR=0} pochodzi z modelowanego wejścia. \u005ctexttt{TEST\u005c_IN} zmienia tylko tę drugą część i jest bodźcem laboratorium, nie pinem RP2350." + }, + { + "id": "A2", + "status": "enabled", + "title": "STRUCTURE — pin0 output, pin1 input", + "content_tex": "Maska 0x1 wybiera pin wyjściowy, a 0x2 wejściowy. Rejestry SET i CLR modyfikują latch bez read--modify--write. Jeden odczyt \u005ctexttt{IN} składa oba widoki, dlatego przy obu stanach wysokich wynosi 0x3." + }, + { + "id": "A3", + "status": "unavailable", + "title": "DISPATCH", + "reason": "Task01 wyłącza detektory zboczy i przerwania; każdy krok jest bezpośrednim pollingiem MMIO, bez ISR, callbacku ani wyboru handlera." + }, + { + "id": "A4", + "status": "enabled", + "title": "APPLICATION — kontrolowany round trip poziomów", + "content_tex": "Po external high program widzi 0x2. SET pinu0 daje OUT=0x1 i IN=0x3. CLR pinu0 oraz TEST\u005c_IN=0 kończą sekwencję IN=0. Te liczby są bitowymi relacjami modelu, nie numerami pinów konkretnej płytki." + }, + { + "id": "A5", + "status": "enabled", + "title": "FLOW — configure, stimulate, sample, clear", + "content_tex": "Program wyłącza edge enable, czyści pending, ustawia kierunek i stan początkowy. Następnie podaje bodziec wejściowy, próbkuje, ustawia output, próbkuje ponownie i zeruje oba źródła. Każdy pomiar następuje po odpowiadającym mu zapisie MMIO." + }, + { + "id": "A6", + "status": "enabled", + "title": "STATE — 0x2 → 0x3 → 0x0", + "content_tex": "Widoczny stan portu przechodzi kolejno przez tylko input high, oba bity high i oba low. Kierunek pozostaje 0x1 przez cały eksperyment, a pending pozostaje pusty." + }, + { + "id": "A7", + "status": "enabled", + "title": "RUNTIME — rzeczywiste transakcje pod 0xc0000300", + "content_tex": "Log RTL raportuje 1,2,1,3,0 i pass=1. Listing powinien pokazać osobne zapisy do offsetów DIR, TEST\u005c_IN, OUT\u005c_SET i OUT\u005c_CLR oraz odczyty IN; nie ma wejścia do wspólnego dispatchera external IRQ." + }, + { + "id": "A8", + "status": "enabled", + "title": "PATTERNS — polling z jawną granicą fixture", + "content_tex": "Wzorzec produkcyjny konfiguruje kierunek i czyta wejście lub steruje wyjściem. Warstwa testowa może dostarczyć osobny mechanizm wstrzyknięcia, ale jego nazwa, dokumentacja i lokalizacja muszą uniemożliwiać pomylenie z rejestrem sprzętu." + } + ] + }, + { + "id": "task02", + "source": "src/tasks/task02_gpio_rising_irq.c", + "chapter": "IRQ18", + "title": "Rising edge, IRQ18 i W1C", + "idea_tex": "zbocze, pending peryferium, kontroler i resume", + "priority": "kluczowe", + "key": true, + "prompt_tex": "Rozpisz ścieżkę od zmiany TEST\u005c_IN 0→1 do wznowienia main. Zaznacz GPIO PENDING, pending linii 18 w kontrolerze, dwa poziomy enable, decyzję dispatchera, zapis W1C i efekt ponownego podania tego samego poziomu.", + "evidence_tex": "Przewidywany łańcuch source--pending--enable--dispatch--effect, log RTL z IRQ18 i stanami przed/po, listing wspólnego dispatchera oraz wniosek wyjaśniający W1C i brak drugiego zbocza dla high→high.", + "worksheet_step2": "Log RTL: pending GPIO i kontrolera przed/po ISR", + "worksheet_step3": "Dowód dispatchu IRQ18 i zapisu W1C", + "criterion": "Jeden handler IRQ18 widzi PENDING=0x4 i poziom high. GPIO source oraz controller pending są 1 przed globalnym enable i 0 po W1C; high→high nie tworzy nowego pending, resume=1, pass=1.", + "viewpoints": [ + { + "id": "A1", + "status": "enabled", + "title": "CONTEXT — zbocze tworzy zatrzaśnięty fakt", + "content_tex": "Bodziec TEST\u005c_IN zmienia pin2 z 0 na 1. Włączony bit RISE\u005c_EN tworzy bit 0x4 w GPIO PENDING, a ten utrzymuje external IRQ18. TEST\u005c_IN jest sztuczny, lecz dalsza ścieżka przez kontroler i rdzeń jest rzeczywistą ścieżką modelu RTL." + }, + { + "id": "A2", + "status": "enabled", + "title": "STRUCTURE — dwa pending i tablica handlerów", + "content_tex": "Pierwszy pending leży w peryferium jako maska pinów. Drugi jest widokiem aktywnej linii 18 w kontrolerze Hazard3. Tablica \u005ctexttt{\u005c_external\u005c_irq\u005c_table[18]} przechowuje adres zwykłej funkcji handlera." + }, + { + "id": "A3", + "status": "enabled", + "title": "DISPATCH — external vector wybiera linię 18", + "content_tex": "\u005ctexttt{mtvec} wybiera wspólny vector machine external interrupt. \u005ctexttt{irq\u005c_dispatch.S} odczytuje aktywną linię z \u005ctexttt{meinext}, indeksuje tablicę i wykonuje pośredni \u005ctexttt{jalr} do handlera GPIO. Handler potwierdza, że bieżący numer to 18." + }, + { + "id": "A4", + "status": "enabled", + "title": "APPLICATION — jedno zbocze, jedno wznowienie", + "content_tex": "Program celowo generuje edge przy zamkniętym globalnym MIE. Dzięki temu może najpierw zmierzyć oba pending jako 1. Po otwarciu MIE oczekuje dokładnie jednego handlera, W1C, obu pending równych 0 i wykonania kodu resume." + }, + { + "id": "A5", + "status": "enabled", + "title": "FLOW — source → pending → enable → dispatch → W1C", + "content_tex": "0→1 ustawia GPIO PENDING. Włączona linia18, MEIE i później MIE dopuszczają trap. Dispatcher wybiera handler18; ISR próbkuje maskę i poziom, zapisuje tę maskę do PENDING jako W1C, a dopiero potem publikuje count. Main wraca i mierzy stan 0." + }, + { + "id": "A6", + "status": "enabled", + "title": "STATE — IDLE, LATCHED, HANDLING, ACKED, RESUMED", + "content_tex": "IDLE ma input low i pending 0. Rising edge tworzy LATCHED. Otwarcie MIE prowadzi do HANDLING. Zapis W1C tworzy ACKED, a powrót dispatchera RESUMED. Ponowne high pozostaje ACKED, ponieważ nie zaszła zmiana 0→1." + }, + { + "id": "A7", + "status": "enabled", + "title": "RUNTIME — 0x4 w GPIO i 18 w kontrolerze", + "content_tex": "Raport daje count=1, irq=0x12, source/controller przed 1, pending w ISR 0x4, oba pending po 0 i same-level 0. Listing ma zawierać handler GPIO oraz wspólny dispatcher zakończony \u005ctexttt{mret}." + }, + { + "id": "A8", + "status": "enabled", + "title": "PATTERNS — acknowledge peripheral before publish", + "content_tex": "Dla poziomowego IRQ najpierw ustal i usuń przyczynę po stronie peryferium, a dopiero potem publikuj zakończenie dla main. Zamknięcie maski może odłożyć obsługę, ale nie jest potwierdzeniem zdarzenia." + } + ] + }, + { + "id": "task03", + "source": "src/tasks/task03_gpio_quiet_window.c", + "chapter": "DBNC", + "title": "Quiet-window debounce po trzech zboczach", + "idea_tex": "krótki ISR, mtime i decyzja stabilności w main", + "priority": "kluczowe", + "key": true, + "prompt_tex": "Dla sekwencji poziomów 1,0,1 oblicz oba odstępy i porównaj z quiet=2000. Wyjaśnij, dlaczego ISR publikuje czas, lecz nie akceptuje przycisku, oraz jak nowe zbocze restartuje okno ciszy.", + "evidence_tex": "Przewidywana sekwencja kandydatów, log RTL z trzema czasami i poziomami, niezależne przeliczenie gapów oraz accepted\u005c_after i wniosek przypisujący politykę debounce do main.", + "worksheet_step2": "Log RTL: trzy poziomy, czasy i gapy", + "worksheet_step3": "Dowód quiet window i miejsca decyzji w main", + "criterion": "Poziomy 1,0,1, count=3 i IRQ18. Oba gapy są dodatnie i mniejsze od quiet=2000; early=0, accepted=1, zaakceptowany poziom high, accepted_after >= quiet i pass=1.", + "viewpoints": [ + { + "id": "A1", + "status": "enabled", + "title": "CONTEXT — IRQ rejestruje zmianę, nie intencję użytkownika", + "content_tex": "Trzy przejścia TEST\u005c_IN modelują bounce, nie trzy świadome naciśnięcia. Kontroler potrafi zgłosić rising i falling edge, lecz nie zna quiet window ani znaczenia stabilnego przycisku. Ta semantyka należy do kodu normalnego." + }, + { + "id": "A2", + "status": "enabled", + "title": "STRUCTURE — historia ISR i kandydat main", + "content_tex": "ISR zapisuje trzy pary \u005ctexttt{level,time}, a osobno publikuje ostatni poziom, ostatni czas i count. Main utrzymuje seen count, candidate level oraz candidate time. Krytyczna sekcja chroni snapshot 64-bitowego czasu na RV32." + }, + { + "id": "A3", + "status": "enabled", + "title": "DISPATCH — każde włączone zbocze wybiera GPIO18", + "content_tex": "RISE\u005c_EN i FALL\u005c_EN pozwalają trzem przejściom utworzyć pending. External dispatcher trzy razy wybiera wpis 18 i wywołuje ten sam krótki handler. Numer ostatniego handlera oraz count=3 są dowodem decyzji, nie sam fakt zapisu TEST\u005c_IN." + }, + { + "id": "A4", + "status": "enabled", + "title": "APPLICATION — restart okna po każdym bounce", + "content_tex": "Po każdym nowym count main zastępuje candidate time czasem ostatniego zbocza. Natychmiastowe próby dają early=0. Dopiero stabilny high utrzymany przez co najmniej 2000 taktów daje accepted=1." + }, + { + "id": "A5", + "status": "enabled", + "title": "FLOW — ISR publish, main observe, wait, validate", + "content_tex": "ISR czyta pending, poziom i mtime, zapisuje rekord, wykonuje W1C i na końcu zwiększa count. Main atomowo pobiera publikację, aktualizuje kandydata, mierzy wiek oraz porównuje bieżący IN. Nowe zbocze wraca do początku okna." + }, + { + "id": "A6", + "status": "enabled", + "title": "STATE — HIGH?, LOW?, HIGH?, STABLE_HIGH", + "content_tex": "Pierwsze high jest kandydatem, low unieważnia go, a drugie high tworzy nowego kandydata. Żaden stan z wiekiem mniejszym niż quiet nie jest zaakceptowany. STABLE\u005c_HIGH powstaje dopiero po pełnym oknie bez kolejnego IRQ." + }, + { + "id": "A7", + "status": "enabled", + "title": "RUNTIME — dwa bounce gapy krótsze od 0x7d0", + "content_tex": "Bieżący RTL raportuje czasy low 0x591, 0x8ea, 0xc43, czyli oba gapy 0x359. Akceptacja następuje po 0x878 od ostatniego edge. Konkretne czasy zależą od buildu; oracle niezależnie sprawdza tylko relacje gap=quiet." + }, + { + "id": "A8", + "status": "enabled", + "title": "PATTERNS — timestamp in ISR, policy in consumer", + "content_tex": "ISR powinien szybko potwierdzić sprzęt i opublikować minimalne dane. Konsument może wtedy zmieniać quiet window, politykę akceptacji lub raportowanie bez wydłużania czasu blokowania innych przerwań." + } + ] + }, + { + "id": "task04", + "source": "src/tasks/task04_raw_c_superloop.c", + "chapter": "LOOP", + "title": "Timer + UART16 + GPIO18 bez RTOS", + "idea_tex": "trzy źródła, dwa dispatchery, flagi i efekty main", + "priority": "kluczowe", + "key": true, + "prompt_tex": "Dla timer tick, bajtu U i rising edge narysuj trzy osobne ścieżki source--pending--enable--dispatcher--ISR--flag--main effect. Wyjaśnij, dlaczego trzy flagi nie są kolejką i jakie ograniczenie przechodzi do serii FreeRTOS.", + "evidence_tex": "Trzy przewidywane ścieżki zdarzeń, log RTL z numerami przerwań i licznikami, listing machine-timer oraz external dispatchera, końcowe OUT/IN i wniosek o granicy flag jednozdarzeniowych.", + "worksheet_step2": "Log RTL: timer, UART16, GPIO18 i efekty main", + "worksheet_step3": "Dowód dwóch dispatcherów i końcowego OUT/IN", + "criterion": "Po jednym timer IRQ z mcause=0x80000007, UART IRQ16 z bajtem 0x55 i GPIO IRQ18 z high. Main konsumuje każdą flagę raz, ustawia trzy bity, OUT=0x7, IN=0x17, pass=1.", + "viewpoints": [ + { + "id": "A1", + "status": "enabled", + "title": "CONTEXT — trzy usługi, wspólny czas CPU", + "content_tex": "Machine timer pochodzi z mtime>=mtimecmp, UART16 z niepustego RX FIFO przy włączonym RX IRQ, a GPIO18 z rising edge zatrzaśniętego w PENDING. TEST\u005c_RX i TEST\u005c_IN tworzą tylko bodźce; logika timer/UART/GPIO po nich jest rzeczywistym modelem RTL." + }, + { + "id": "A2", + "status": "enabled", + "title": "STRUCTURE — trzy publikacje i trzy bity efektu", + "content_tex": "Każda usługa ma licznik ISR, payload i flagę. Main ma osobny licznik konsumpcji. Bity OUT 0,1,2 reprezentują odpowiednio efekt GPIO, UART i timera, więc końcowe 0x7 dowodzi wykonania trzech gałęzi bez ukrywania ich w jednej sumie." + }, + { + "id": "A3", + "status": "enabled", + "title": "DISPATCH — slot 7 oraz external 16/18", + "content_tex": "Machine timer cause 7 trafia bezpośrednio do \u005ctexttt{isr\u005c_machine\u005c_timer} i wraca przez \u005ctexttt{mret}. Machine external vector trafia do wspólnego dispatchera; \u005ctexttt{meinext} wybiera wpis 16 dla UART albo 18 dla GPIO i wykonuje \u005ctexttt{jalr}." + }, + { + "id": "A4", + "status": "enabled", + "title": "APPLICATION — efekt dopiero po konsumpcji flagi", + "content_tex": "UART handler publikuje U, GPIO handler high, a timer handler tick. Żaden ISR nie ustawia aplikacyjnego bitu OUT. Superloop atomowo zabiera flagę i dopiero jego trzy gałęzie ustawiają 0x2, 0x1 i 0x4." + }, + { + "id": "A5", + "status": "enabled", + "title": "FLOW — source → pending → dispatch → ISR → main", + "content_tex": "Timer: comparator→MTIP→slot7→tick flag→bit2. UART: RX FIFO→IRQ16→external dispatcher→read DATA i flag→bit1. GPIO: edge→PENDING→IRQ18→dispatcher→W1C i flag→bit0. Main używa WFI tylko wtedy, gdy nadal brakuje któregoś efektu." + }, + { + "id": "A6", + "status": "enabled", + "title": "STATE — trzy niezależne PRODUCED/CONSUMED", + "content_tex": "Każda usługa przechodzi IDLE→PRODUCED w ISR i PRODUCED→CONSUMED w main. Stan końcowy wymaga trzech liczników konsumpcji równych 1. Flaga wraca do 0, ale licznik zachowuje dowód przejścia." + }, + { + "id": "A7", + "status": "enabled", + "title": "RUNTIME — cause 7, linie 16/18 i OUT 0x7", + "content_tex": "Raport daje timer count 1 i mcause 0x80000007, UART count 1/irq 0x10/byte 0x55, GPIO count 1/irq 0x12/high oraz trzy main actions po 1. OUT=0x7, a IN=0x17 dodaje widoczny wysoki pin wejściowy 0x10." + }, + { + "id": "A8", + "status": "enabled", + "title": "PATTERNS — ISR-to-main flags with an explicit ceiling", + "content_tex": "Jednokomórkowa flaga jest poprawna tylko wtedy, gdy wystarcza informacja co najmniej jedno zdarzenie. Nie zachowuje liczby ani kolejności wielu produkcji. Ten sufit jest powodem przejścia do kolejek i tasków FreeRTOS, a nie pretekstem do nazywania flagi kolejką." + } + ] + } + ] +} diff --git a/scripts/render_card_layouts.sh b/scripts/render_card_layouts.sh new file mode 100755 index 0000000..e8f3248 --- /dev/null +++ b/scripts/render_card_layouts.sh @@ -0,0 +1,10 @@ +#!/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 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..5d1787d --- /dev/null +++ b/scripts/render_new_pdf.sh @@ -0,0 +1,13 @@ +#!/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 + +if git -C "$repo_root" rev-parse --verify HEAD >/dev/null 2>&1; then + exec "$layouts_root/tools/render_card_pdf_preserving.sh" "$repo_root" +fi +GITEA_SHA=0000000000000000000000000000000000000000 \ + exec "$layouts_root/tools/render_card_pdf_preserving.sh" "$repo_root" + diff --git a/src/tasks/c13_common.h b/src/tasks/c13_common.h new file mode 100644 index 0000000..ac64aa9 --- /dev/null +++ b/src/tasks/c13_common.h @@ -0,0 +1,74 @@ +#ifndef C13_COMMON_H +#define C13_COMMON_H + +#include +#include + +#include "hazard3_irq.h" +#include "tb_cxxrtl_io.h" +#include "tb_gpio_io.h" +#include "tb_uart_io.h" + +#define C13_UART_INDEX 0u +#define C13_UART_IRQ (TB_UART_EXTERNAL_IRQ_BASE + C13_UART_INDEX) +#define C13_GPIO_IRQ TB_GPIO_EXTERNAL_IRQ +#define C13_MACHINE_TIMER_CAUSE UINT32_C(0x80000007) + +static inline __attribute__((always_inline)) uint64_t c13_timer_read64(void) +{ + uint32_t high_before; + uint32_t low; + uint32_t high_after; + + do { + high_before = mm_timer->mtimeh; + low = mm_timer->mtime; + high_after = mm_timer->mtimeh; + } while (high_before != high_after); + + return ((uint64_t)high_after << 32) | low; +} + +static inline __attribute__((always_inline)) void c13_timer_set_compare(uint64_t value) +{ + mm_timer->mtimecmph = UINT32_MAX; + mm_timer->mtimecmp = (uint32_t)value; + mm_timer->mtimecmph = (uint32_t)(value >> 32); +} + +static inline void c13_wait_ticks(uint64_t ticks) +{ + const uint64_t deadline = c13_timer_read64() + ticks; + while (c13_timer_read64() < deadline) { + __asm__ volatile("nop"); + } +} + +static inline bool c13_wait_for(volatile uint32_t *value, uint32_t expected) +{ + for (uint32_t spin = 0; spin < 100000u; ++spin) { + if (*value == expected) { + return true; + } + __asm__ volatile("nop"); + } + return false; +} + +static inline void c13_report_u32(const char *label, uint32_t value) +{ + tb_puts(label); + tb_put_u32(value); +} + +static inline void c13_external_disable(void) +{ + global_irq_enable(false); + external_irq_enable(false); + h3irq_enable(C13_UART_IRQ, false); + h3irq_enable(C13_GPIO_IRQ, false); + tb_uart_rx_irq_enable(C13_UART_INDEX, false); +} + +#endif + diff --git a/src/tasks/task01_gpio_polling.c b/src/tasks/task01_gpio_polling.c new file mode 100644 index 0000000..bf186c0 --- /dev/null +++ b/src/tasks/task01_gpio_polling.c @@ -0,0 +1,51 @@ +#include "c13_common.h" + +#define TASK01_OUTPUT_PIN (UINT32_C(1) << 0) +#define TASK01_INPUT_PIN (UINT32_C(1) << 1) + +volatile uint32_t g_task01_dir; +volatile uint32_t g_task01_out_after_set; +volatile uint32_t g_task01_in_external_high; +volatile uint32_t g_task01_in_both_high; +volatile uint32_t g_task01_in_final; +volatile uint32_t g_task01_pass; + +int main(void) +{ + c13_external_disable(); + tb_gpio_write(TB_GPIO_RISE_EN, 0u); + tb_gpio_write(TB_GPIO_FALL_EN, 0u); + tb_gpio_write(TB_GPIO_PENDING, UINT32_MAX); + + tb_gpio_write(TB_GPIO_DIR, TASK01_OUTPUT_PIN); + tb_gpio_write(TB_GPIO_OUT_CLR, TASK01_OUTPUT_PIN); + tb_gpio_test_set_input(TASK01_INPUT_PIN); + + g_task01_dir = tb_gpio_read(TB_GPIO_DIR); + g_task01_in_external_high = tb_gpio_read(TB_GPIO_IN); + + tb_gpio_write(TB_GPIO_OUT_SET, TASK01_OUTPUT_PIN); + g_task01_out_after_set = tb_gpio_read(TB_GPIO_OUT); + g_task01_in_both_high = tb_gpio_read(TB_GPIO_IN); + + tb_gpio_write(TB_GPIO_OUT_CLR, TASK01_OUTPUT_PIN); + tb_gpio_test_set_input(0u); + g_task01_in_final = tb_gpio_read(TB_GPIO_IN); + + g_task01_pass = + g_task01_dir == TASK01_OUTPUT_PIN && + g_task01_in_external_high == TASK01_INPUT_PIN && + (g_task01_out_after_set & TASK01_OUTPUT_PIN) != 0u && + g_task01_in_both_high == (TASK01_OUTPUT_PIN | TASK01_INPUT_PIN) && + g_task01_in_final == 0u && + tb_gpio_read(TB_GPIO_PENDING) == 0u; + + c13_report_u32("T01 dir=", g_task01_dir); + c13_report_u32("T01 external_high=", g_task01_in_external_high); + c13_report_u32("T01 out_after_set=", g_task01_out_after_set); + c13_report_u32("T01 both_high=", g_task01_in_both_high); + c13_report_u32("T01 final_in=", g_task01_in_final); + c13_report_u32("T01 pass=", g_task01_pass); + return g_task01_pass ? 0 : 1; +} + diff --git a/src/tasks/task02_gpio_rising_irq.c b/src/tasks/task02_gpio_rising_irq.c new file mode 100644 index 0000000..ee4cb08 --- /dev/null +++ b/src/tasks/task02_gpio_rising_irq.c @@ -0,0 +1,92 @@ +#include "c13_common.h" + +#define TASK02_INPUT_PIN (UINT32_C(1) << 2) + +volatile uint32_t g_task02_irq_count; +volatile uint32_t g_task02_irq_number; +volatile uint32_t g_task02_pending_in_handler; +volatile uint32_t g_task02_level_in_handler; +volatile uint32_t g_task02_gpio_pending_before; +volatile uint32_t g_task02_controller_pending_before; +volatile uint32_t g_task02_gpio_pending_after; +volatile uint32_t g_task02_controller_pending_after; +volatile uint32_t g_task02_same_level_pending; +volatile uint32_t g_task02_resumed; +volatile uint32_t g_task02_pass; + +void task02_gpio_handler(void) +{ + const uint32_t pending = tb_gpio_read(TB_GPIO_PENDING); + + g_task02_irq_number = (uint32_t)h3irq_get_current_irq(); + g_task02_pending_in_handler = pending; + g_task02_level_in_handler = tb_gpio_read(TB_GPIO_IN) & TASK02_INPUT_PIN; + tb_gpio_write(TB_GPIO_PENDING, pending); /* W1C: acknowledge the source. */ + g_task02_irq_count = g_task02_irq_count + 1u; +} + +int main(void) +{ + c13_external_disable(); + tb_gpio_write(TB_GPIO_DIR, 0u); + tb_gpio_write(TB_GPIO_RISE_EN, 0u); + tb_gpio_write(TB_GPIO_FALL_EN, 0u); + tb_gpio_write(TB_GPIO_PENDING, UINT32_MAX); + tb_gpio_test_set_input(0u); + + h3irq_set_handler(C13_GPIO_IRQ, task02_gpio_handler); + h3irq_set_priority(C13_GPIO_IRQ, 2u); + h3irq_enable(C13_GPIO_IRQ, true); + external_irq_enable(true); + tb_gpio_write(TB_GPIO_RISE_EN, TASK02_INPUT_PIN); + + /* TEST_IN is laboratory stimulus; the resulting IRQ18 path is real in RTL. */ + tb_gpio_test_set_input(TASK02_INPUT_PIN); + c13_wait_ticks(32u); + g_task02_gpio_pending_before = + (tb_gpio_read(TB_GPIO_PENDING) & TASK02_INPUT_PIN) != 0u; + g_task02_controller_pending_before = h3irq_pending(C13_GPIO_IRQ) ? 1u : 0u; + + global_irq_enable(true); + const bool handled = c13_wait_for(&g_task02_irq_count, 1u); + g_task02_resumed = handled ? 1u : 0u; + global_irq_enable(false); + c13_wait_ticks(32u); + + g_task02_gpio_pending_after = + (tb_gpio_read(TB_GPIO_PENDING) & TASK02_INPUT_PIN) != 0u; + g_task02_controller_pending_after = h3irq_pending(C13_GPIO_IRQ) ? 1u : 0u; + + /* Repeating the same high level is not a second rising edge. */ + tb_gpio_test_set_input(TASK02_INPUT_PIN); + c13_wait_ticks(32u); + g_task02_same_level_pending = + (tb_gpio_read(TB_GPIO_PENDING) & TASK02_INPUT_PIN) != 0u; + + g_task02_pass = handled && + g_task02_irq_count == 1u && + g_task02_irq_number == C13_GPIO_IRQ && + g_task02_pending_in_handler == TASK02_INPUT_PIN && + g_task02_level_in_handler == TASK02_INPUT_PIN && + g_task02_gpio_pending_before == 1u && + g_task02_controller_pending_before == 1u && + g_task02_gpio_pending_after == 0u && + g_task02_controller_pending_after == 0u && + g_task02_same_level_pending == 0u && + g_task02_resumed == 1u; + + c13_external_disable(); + tb_gpio_write(TB_GPIO_RISE_EN, 0u); + c13_report_u32("T02 count=", g_task02_irq_count); + c13_report_u32("T02 irq=", g_task02_irq_number); + c13_report_u32("T02 source_before=", g_task02_gpio_pending_before); + c13_report_u32("T02 controller_before=", g_task02_controller_pending_before); + c13_report_u32("T02 pending_in_handler=", g_task02_pending_in_handler); + c13_report_u32("T02 source_after=", g_task02_gpio_pending_after); + c13_report_u32("T02 controller_after=", g_task02_controller_pending_after); + c13_report_u32("T02 same_level_pending=", g_task02_same_level_pending); + c13_report_u32("T02 resumed=", g_task02_resumed); + c13_report_u32("T02 pass=", g_task02_pass); + return g_task02_pass ? 0 : 1; +} + diff --git a/src/tasks/task03_gpio_quiet_window.c b/src/tasks/task03_gpio_quiet_window.c new file mode 100644 index 0000000..2943732 --- /dev/null +++ b/src/tasks/task03_gpio_quiet_window.c @@ -0,0 +1,152 @@ +#include "c13_common.h" + +#define TASK03_INPUT_PIN (UINT32_C(1) << 3) +#define TASK03_EDGE_COUNT 3u +#define TASK03_BOUNCE_GAP UINT64_C(160) +#define TASK03_QUIET UINT64_C(2000) + +volatile uint32_t g_task03_irq_count; +volatile uint32_t g_task03_irq_number; +volatile uint32_t g_task03_edge_level[TASK03_EDGE_COUNT]; +volatile uint64_t g_task03_edge_time[TASK03_EDGE_COUNT]; +volatile uint32_t g_task03_last_level; +volatile uint64_t g_task03_last_edge_time; +volatile uint32_t g_task03_early_accepts; +volatile uint32_t g_task03_accepted_count; +volatile uint32_t g_task03_accepted_level; +volatile uint64_t g_task03_accept_time; +volatile uint32_t g_task03_pass; + +static uint32_t g_seen_irq_count; +static uint32_t g_candidate_level; +static uint64_t g_candidate_time; + +void task03_gpio_handler(void) +{ + const uint32_t pending = tb_gpio_read(TB_GPIO_PENDING); + const uint32_t level = (tb_gpio_read(TB_GPIO_IN) & TASK03_INPUT_PIN) != 0u; + const uint64_t timestamp = c13_timer_read64(); + const uint32_t index = g_task03_irq_count; + + g_task03_irq_number = (uint32_t)h3irq_get_current_irq(); + if (index < TASK03_EDGE_COUNT) { + g_task03_edge_level[index] = level; + g_task03_edge_time[index] = timestamp; + } + g_task03_last_level = level; + g_task03_last_edge_time = timestamp; + tb_gpio_write(TB_GPIO_PENDING, pending); /* Short ISR: W1C and publish. */ + g_task03_irq_count = index + 1u; +} + +static bool debounce_try_accept(void) +{ + uint32_t irq_count; + uint32_t level; + uint64_t edge_time; + uint64_t now; + + /* Snapshot the ISR publication without pretending a volatile uint64_t is atomic. */ + global_irq_enable(false); + irq_count = g_task03_irq_count; + level = g_task03_last_level; + edge_time = g_task03_last_edge_time; + global_irq_enable(true); + + if (irq_count != g_seen_irq_count) { + g_seen_irq_count = irq_count; + g_candidate_level = level; + g_candidate_time = edge_time; + } + + now = c13_timer_read64(); + if (g_seen_irq_count != 0u && + g_task03_accepted_count == 0u && + now - g_candidate_time >= TASK03_QUIET && + (((tb_gpio_read(TB_GPIO_IN) & TASK03_INPUT_PIN) != 0u) == + (g_candidate_level != 0u))) { + g_task03_accepted_level = g_candidate_level; + g_task03_accept_time = now; + g_task03_accepted_count = 1u; + return true; + } + return false; +} + +int main(void) +{ + bool edge1; + bool edge2; + bool edge3; + + c13_external_disable(); + tb_gpio_write(TB_GPIO_DIR, 0u); + tb_gpio_write(TB_GPIO_RISE_EN, 0u); + tb_gpio_write(TB_GPIO_FALL_EN, 0u); + tb_gpio_write(TB_GPIO_PENDING, UINT32_MAX); + tb_gpio_test_set_input(0u); + + h3irq_set_handler(C13_GPIO_IRQ, task03_gpio_handler); + h3irq_set_priority(C13_GPIO_IRQ, 2u); + h3irq_enable(C13_GPIO_IRQ, true); + external_irq_enable(true); + tb_gpio_write(TB_GPIO_RISE_EN, TASK03_INPUT_PIN); + tb_gpio_write(TB_GPIO_FALL_EN, TASK03_INPUT_PIN); + global_irq_enable(true); + + tb_gpio_test_set_input(TASK03_INPUT_PIN); /* press */ + edge1 = c13_wait_for(&g_task03_irq_count, 1u); + g_task03_early_accepts += debounce_try_accept() ? 1u : 0u; + c13_wait_ticks(TASK03_BOUNCE_GAP); + + tb_gpio_test_set_input(0u); /* bounce low */ + edge2 = c13_wait_for(&g_task03_irq_count, 2u); + g_task03_early_accepts += debounce_try_accept() ? 1u : 0u; + c13_wait_ticks(TASK03_BOUNCE_GAP); + + tb_gpio_test_set_input(TASK03_INPUT_PIN); /* stable high */ + edge3 = c13_wait_for(&g_task03_irq_count, 3u); + g_task03_early_accepts += debounce_try_accept() ? 1u : 0u; + + while (c13_timer_read64() - g_task03_last_edge_time < TASK03_QUIET) { + __asm__ volatile("nop"); + } + (void)debounce_try_accept(); + global_irq_enable(false); + + g_task03_pass = edge1 && edge2 && edge3 && + g_task03_irq_count == TASK03_EDGE_COUNT && + g_task03_irq_number == C13_GPIO_IRQ && + g_task03_edge_level[0] == 1u && + g_task03_edge_level[1] == 0u && + g_task03_edge_level[2] == 1u && + g_task03_edge_time[0] < g_task03_edge_time[1] && + g_task03_edge_time[1] < g_task03_edge_time[2] && + g_task03_edge_time[1] - g_task03_edge_time[0] < TASK03_QUIET && + g_task03_edge_time[2] - g_task03_edge_time[1] < TASK03_QUIET && + g_task03_early_accepts == 0u && + g_task03_accepted_count == 1u && + g_task03_accepted_level == 1u && + g_task03_accept_time - g_task03_edge_time[2] >= TASK03_QUIET && + (tb_gpio_read(TB_GPIO_PENDING) & TASK03_INPUT_PIN) == 0u; + + c13_external_disable(); + tb_gpio_write(TB_GPIO_RISE_EN, 0u); + tb_gpio_write(TB_GPIO_FALL_EN, 0u); + c13_report_u32("T03 count=", g_task03_irq_count); + c13_report_u32("T03 level0=", g_task03_edge_level[0]); + c13_report_u32("T03 level1=", g_task03_edge_level[1]); + c13_report_u32("T03 level2=", g_task03_edge_level[2]); + c13_report_u32("T03 time0_low=", (uint32_t)g_task03_edge_time[0]); + c13_report_u32("T03 time1_low=", (uint32_t)g_task03_edge_time[1]); + c13_report_u32("T03 time2_low=", (uint32_t)g_task03_edge_time[2]); + c13_report_u32("T03 gap01=", (uint32_t)(g_task03_edge_time[1] - g_task03_edge_time[0])); + c13_report_u32("T03 gap12=", (uint32_t)(g_task03_edge_time[2] - g_task03_edge_time[1])); + c13_report_u32("T03 quiet=", (uint32_t)TASK03_QUIET); + c13_report_u32("T03 accepted_after=", (uint32_t)(g_task03_accept_time - g_task03_edge_time[2])); + c13_report_u32("T03 early=", g_task03_early_accepts); + c13_report_u32("T03 accepted=", g_task03_accepted_count); + c13_report_u32("T03 pass=", g_task03_pass); + return g_task03_pass ? 0 : 1; +} + diff --git a/src/tasks/task04_raw_c_superloop.c b/src/tasks/task04_raw_c_superloop.c new file mode 100644 index 0000000..5fa82d9 --- /dev/null +++ b/src/tasks/task04_raw_c_superloop.c @@ -0,0 +1,181 @@ +#include "c13_common.h" + +#define TASK04_GPIO_INPUT (UINT32_C(1) << 4) +#define TASK04_GPIO_EFFECT (UINT32_C(1) << 0) +#define TASK04_UART_EFFECT (UINT32_C(1) << 1) +#define TASK04_TIMER_EFFECT (UINT32_C(1) << 2) +#define TASK04_TIMER_PERIOD UINT64_C(10000) + +volatile uint32_t g_task04_timer_irq_count; +volatile uint32_t g_task04_timer_flag; +volatile uint32_t g_task04_timer_mcause; +volatile uint64_t g_task04_timer_deadline; +volatile uint64_t g_task04_timer_observed; + +volatile uint32_t g_task04_uart_irq_count; +volatile uint32_t g_task04_uart_irq_number; +volatile uint32_t g_task04_uart_byte; +volatile uint32_t g_task04_uart_flag; + +volatile uint32_t g_task04_gpio_irq_count; +volatile uint32_t g_task04_gpio_irq_number; +volatile uint32_t g_task04_gpio_level; +volatile uint32_t g_task04_gpio_flag; + +volatile uint32_t g_task04_main_timer_actions; +volatile uint32_t g_task04_main_uart_actions; +volatile uint32_t g_task04_main_gpio_actions; +volatile uint32_t g_task04_final_out; +volatile uint32_t g_task04_final_in; +volatile uint32_t g_task04_pass; + +void __attribute__((interrupt("machine"))) isr_machine_timer(void) +{ + const uint64_t observed = c13_timer_read64(); + + g_task04_timer_mcause = read_csr(mcause); + g_task04_timer_observed = observed; + g_task04_timer_deadline += TASK04_TIMER_PERIOD; + c13_timer_set_compare(g_task04_timer_deadline); + g_task04_timer_flag = 1u; + g_task04_timer_irq_count = g_task04_timer_irq_count + 1u; +} + +void task04_uart_handler(void) +{ + g_task04_uart_irq_number = (uint32_t)h3irq_get_current_irq(); + g_task04_uart_byte = *tb_uart_reg(C13_UART_INDEX, TB_UART_DATA) & 0xffu; + g_task04_uart_flag = 1u; + g_task04_uart_irq_count = g_task04_uart_irq_count + 1u; +} + +void task04_gpio_handler(void) +{ + const uint32_t pending = tb_gpio_read(TB_GPIO_PENDING); + + g_task04_gpio_irq_number = (uint32_t)h3irq_get_current_irq(); + g_task04_gpio_level = + (tb_gpio_read(TB_GPIO_IN) & TASK04_GPIO_INPUT) != 0u; + tb_gpio_write(TB_GPIO_PENDING, pending); + g_task04_gpio_flag = 1u; + g_task04_gpio_irq_count = g_task04_gpio_irq_count + 1u; +} + +static uint32_t take_flag(volatile uint32_t *flag) +{ + uint32_t value; + + global_irq_enable(false); + value = *flag; + *flag = 0u; + global_irq_enable(true); + return value; +} + +int main(void) +{ + const uint32_t output_mask = + TASK04_GPIO_EFFECT | TASK04_UART_EFFECT | TASK04_TIMER_EFFECT; + + global_irq_enable(false); + timer_irq_enable(false); + external_irq_enable(false); + tb_uart_rx_irq_enable(C13_UART_INDEX, false); + h3irq_enable(C13_UART_IRQ, false); + h3irq_enable(C13_GPIO_IRQ, false); + c13_timer_set_compare(UINT64_MAX); + + tb_gpio_write(TB_GPIO_DIR, output_mask); + tb_gpio_write(TB_GPIO_OUT_CLR, output_mask); + tb_gpio_write(TB_GPIO_RISE_EN, 0u); + tb_gpio_write(TB_GPIO_FALL_EN, 0u); + tb_gpio_write(TB_GPIO_PENDING, UINT32_MAX); + tb_gpio_test_set_input(0u); + + h3irq_set_handler(C13_UART_IRQ, task04_uart_handler); + h3irq_set_handler(C13_GPIO_IRQ, task04_gpio_handler); + h3irq_set_priority(C13_UART_IRQ, 1u); + h3irq_set_priority(C13_GPIO_IRQ, 2u); + h3irq_enable(C13_UART_IRQ, true); + h3irq_enable(C13_GPIO_IRQ, true); + external_irq_enable(true); + tb_uart_rx_irq_enable(C13_UART_INDEX, true); + tb_gpio_write(TB_GPIO_RISE_EN, TASK04_GPIO_INPUT); + + g_task04_timer_deadline = c13_timer_read64() + TASK04_TIMER_PERIOD; + c13_timer_set_compare(g_task04_timer_deadline); + timer_irq_enable(true); + global_irq_enable(true); + + /* Both writes are testbench stimuli, not production peripheral registers. */ + tb_uart_test_inject_rx(C13_UART_INDEX, (uint8_t)'U'); + tb_gpio_test_set_input(TASK04_GPIO_INPUT); + + while (g_task04_main_timer_actions == 0u || + g_task04_main_uart_actions == 0u || + g_task04_main_gpio_actions == 0u) { + if (take_flag(&g_task04_uart_flag) != 0u) { + if (g_task04_uart_byte == (uint32_t)'U') { + tb_gpio_write(TB_GPIO_OUT_SET, TASK04_UART_EFFECT); + } + g_task04_main_uart_actions++; + } + if (take_flag(&g_task04_gpio_flag) != 0u) { + if (g_task04_gpio_level != 0u) { + tb_gpio_write(TB_GPIO_OUT_SET, TASK04_GPIO_EFFECT); + } + g_task04_main_gpio_actions++; + } + if (take_flag(&g_task04_timer_flag) != 0u) { + tb_gpio_write(TB_GPIO_OUT_SET, TASK04_TIMER_EFFECT); + g_task04_main_timer_actions++; + } + if (g_task04_main_timer_actions == 0u || + g_task04_main_uart_actions == 0u || + g_task04_main_gpio_actions == 0u) { + __asm__ volatile("wfi" ::: "memory"); + } + } + + global_irq_enable(false); + timer_irq_enable(false); + c13_timer_set_compare(UINT64_MAX); + c13_external_disable(); + tb_gpio_write(TB_GPIO_RISE_EN, 0u); + + g_task04_final_out = tb_gpio_read(TB_GPIO_OUT) & output_mask; + g_task04_final_in = tb_gpio_read(TB_GPIO_IN) & + (output_mask | TASK04_GPIO_INPUT); + g_task04_pass = + g_task04_timer_irq_count == 1u && + g_task04_timer_mcause == C13_MACHINE_TIMER_CAUSE && + g_task04_timer_observed >= g_task04_timer_deadline - TASK04_TIMER_PERIOD && + g_task04_uart_irq_count == 1u && + g_task04_uart_irq_number == C13_UART_IRQ && + g_task04_uart_byte == (uint32_t)'U' && + g_task04_gpio_irq_count == 1u && + g_task04_gpio_irq_number == C13_GPIO_IRQ && + g_task04_gpio_level == 1u && + g_task04_main_timer_actions == 1u && + g_task04_main_uart_actions == 1u && + g_task04_main_gpio_actions == 1u && + g_task04_final_out == output_mask && + g_task04_final_in == (output_mask | TASK04_GPIO_INPUT); + + c13_report_u32("T04 timer_irq=", g_task04_timer_irq_count); + c13_report_u32("T04 timer_mcause=", g_task04_timer_mcause); + c13_report_u32("T04 uart_irq=", g_task04_uart_irq_count); + c13_report_u32("T04 uart_number=", g_task04_uart_irq_number); + c13_report_u32("T04 uart_byte=", g_task04_uart_byte); + c13_report_u32("T04 gpio_irq=", g_task04_gpio_irq_count); + c13_report_u32("T04 gpio_number=", g_task04_gpio_irq_number); + c13_report_u32("T04 gpio_level=", g_task04_gpio_level); + c13_report_u32("T04 main_timer=", g_task04_main_timer_actions); + c13_report_u32("T04 main_uart=", g_task04_main_uart_actions); + c13_report_u32("T04 main_gpio=", g_task04_main_gpio_actions); + c13_report_u32("T04 final_out=", g_task04_final_out); + c13_report_u32("T04 final_in=", g_task04_final_in); + c13_report_u32("T04 pass=", g_task04_pass); + return g_task04_pass ? 0 : 1; +} + diff --git a/tests/test_card.sh b/tests/test_card.sh new file mode 100755 index 0000000..4c32b76 --- /dev/null +++ b/tests/test_card.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +set -euo pipefail + +root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)" +tmp_dir="$(mktemp -d /tmp/c13-card.XXXXXX)" +cleanup() { + rm -rf -- "$tmp_dir" +} +trap cleanup EXIT HUP INT TERM + +"$root/scripts/render_card_layouts.sh" >/dev/null +"$root/scripts/render_new_pdf.sh" >/dev/null + +pdf="$(find "$root/doc/pdf" -maxdepth 1 -type f \ + -name 'mpabi-inf-c-13-gpio-edges-debounce-*.pdf' -print -quit)" +test -n "$pdf" +qpdf --check "$pdf" >/dev/null +pdftotext -layout "$pdf" "$tmp_dir/card.txt" + +blocks="$(rg -o 'A[1-8] (CONTEXT|STRUCTURE|DISPATCH|APPLICATION|FLOW|STATE|RUNTIME|PATTERNS)' \ + "$tmp_dir/card.txt" | wc -l)" +test "$blocks" -eq 32 + +awk 'BEGIN { RS="\f" } { compact=$0; gsub(/[[:space:]]/, "", compact); if (length(compact) < 100) exit 1 }' \ + "$tmp_dir/card.txt" || { echo "FAIL: empty PDF page" >&2; exit 1; } +awk 'BEGIN { RS="\f" } \ + /A[1-8] (CONTEXT|STRUCTURE|DISPATCH|APPLICATION|FLOW|STATE|RUNTIME|PATTERNS)/ && !/TASK0[1-4]/ { exit 1 }' \ + "$tmp_dir/card.txt" || { echo "FAIL: anonymous A1-A8 page" >&2; exit 1; } + +jq -e ' + .tasks_order == ["task01", "task02", "task03", "task04"] and + all(.tasks[]; + [.viewpoints[].id] == ["A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8"] and + all(.viewpoints[]; .status == "enabled" or .status == "unavailable")) +' "$root/json/card_source.json" >/dev/null +node --check "$root/web/app.js" +printf 'PASS card: 4 tasks, 32 A blocks, valid PDF, no empty/anonymous page\n' + diff --git a/tests/test_hazard3.sh b/tests/test_hazard3.sh new file mode 100755 index 0000000..9e704e7 --- /dev/null +++ b/tests/test_hazard3.sh @@ -0,0 +1,109 @@ +#!/usr/bin/env bash +set -euo pipefail + +root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)" +env_root="${RV_ENV_ROOT:-/home/user/dev/edu/rv32i-hazard3-student-env}" +tb="${HAZARD3_TB:-$env_root/vendor/Hazard3/test/sim/tb_verilator/tb}" +objdump="${RISCV_PREFIX:-riscv64-unknown-elf-}objdump" + +test -x "$tb" +make -C "$root" -s tasks "RV_ENV_ROOT=$env_root" + +run_task() { + local task="$1" + shift + local log="$root/build/$task/oracle.log" + "$tb" --bin "$root/build/$task/prog.bin" --cycles 1000000 \ + --cpuret --logfile "$log" + if grep -Eq 'Unhandled trap|Max cycles reached' "$log"; then + printf 'FAIL %s: trap or timeout\n' "$task" >&2 + sed -n '1,180p' "$log" >&2 + return 1 + fi + local expected + for expected in "$@"; do + grep -Fqx "$expected" "$log" || { + printf 'FAIL %s: missing <%s>\n' "$task" "$expected" >&2 + sed -n '1,180p' "$log" >&2 + return 1 + } + done + printf 'PASS Hazard3 oracle: %s\n' "$task" +} + +run_task task01_gpio_polling \ + 'T01 dir=00000001' \ + 'T01 external_high=00000002' \ + 'T01 out_after_set=00000001' \ + 'T01 both_high=00000003' \ + 'T01 final_in=00000000' \ + 'T01 pass=00000001' + +run_task task02_gpio_rising_irq \ + 'T02 count=00000001' \ + 'T02 irq=00000012' \ + 'T02 source_before=00000001' \ + 'T02 controller_before=00000001' \ + 'T02 pending_in_handler=00000004' \ + 'T02 source_after=00000000' \ + 'T02 controller_after=00000000' \ + 'T02 same_level_pending=00000000' \ + 'T02 resumed=00000001' \ + 'T02 pass=00000001' + +run_task task03_gpio_quiet_window \ + 'T03 count=00000003' \ + 'T03 level0=00000001' \ + 'T03 level1=00000000' \ + 'T03 level2=00000001' \ + 'T03 quiet=000007d0' \ + 'T03 early=00000000' \ + 'T03 accepted=00000001' \ + 'T03 pass=00000001' + +run_task task04_raw_c_superloop \ + 'T04 timer_irq=00000001' \ + 'T04 timer_mcause=80000007' \ + 'T04 uart_irq=00000001' \ + 'T04 uart_number=00000010' \ + 'T04 uart_byte=00000055' \ + 'T04 gpio_irq=00000001' \ + 'T04 gpio_number=00000012' \ + 'T04 gpio_level=00000001' \ + 'T04 main_timer=00000001' \ + 'T04 main_uart=00000001' \ + 'T04 main_gpio=00000001' \ + 'T04 final_out=00000007' \ + 'T04 final_in=00000017' \ + 'T04 pass=00000001' + +# Independent arithmetic oracle for debounce; do not trust only program pass. +t03_log="$root/build/task03_gpio_quiet_window/oracle.log" +mapfile -t times < <(sed -n 's/^T03 time[0-2]_low=//p' "$t03_log") +mapfile -t gaps < <(sed -n 's/^T03 gap[01][12]=//p' "$t03_log") +quiet_hex="$(sed -n 's/^T03 quiet=//p' "$t03_log")" +accepted_hex="$(sed -n 's/^T03 accepted_after=//p' "$t03_log")" +[[ ${#times[@]} -eq 3 && ${#gaps[@]} -eq 2 ]] +quiet=$((16#$quiet_hex)) +accepted_after=$((16#$accepted_hex)) +for i in 0 1; do + first=$((16#${times[$i]})) + second=$((16#${times[$((i + 1))]})) + gap=$((16#${gaps[$i]})) + (( second > first && second - first == gap && gap < quiet )) || { + echo "FAIL task03: invalid bounce interval $i" >&2 + exit 1 + } +done +(( accepted_after >= quiet )) || { + echo "FAIL task03: accepted before the quiet window" >&2 + exit 1 +} + +# The machine-timer handler must return from a trap, not as a normal function. +"$objdump" -d "$root/build/task04_raw_c_superloop/prog.elf" | + sed -n '/:/,/^$/p' | + grep -Eq '[[:space:]]mret$' + +printf 'PASS independent oracle: edge/W1C relations, debounce timing, ISR mret\n' + 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..88a1125 --- /dev/null +++ b/web/card-data.json @@ -0,0 +1,2706 @@ +{ + "schema": "esc-card-react-view.v1", + "card": { + "id": "mpabi-inf-c-13-gpio-edges-debounce", + "series": "c", + "series_title": "C · Freestanding RV32I and K&R", + "number": "13", + "count": "13", + "slug": "gpio-edges-debounce", + "title": "GPIO, zbocza i quiet-window debounce", + "topic": "RV32I/Hazard3: polling GPIO, external IRQ18, debounce i końcowy superloop raw C", + "project": "Freestanding C na RV32I", + "subject": "Informatyka", + "level": "Rok 1 · C13 · RV32I/Hazard3", + "revision_date": "2026-07-20T00:00:00+02:00", + "status": "Gotowa", + "version": "v00.01", + "uuid": "72e2cbba-4658-5de2-a0dc-8b600ee3f7b0", + "author": "M. Pabiszczak", + "year": "2026" + }, + "library": { + "schema": "stem-card-library.v2", + "workspace": "edu", + "subjects": [ + { + "id": "inf", + "title": "INF · Informatyka", + "current": false, + "levels": [ + { + "id": "year-1", + "title": "Rok 1", + "current": false, + "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": false, + "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": false, + "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": 9, + "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\n\n
TITLEGPIO, zbocza i quiet-window debounce
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C na RV32I
SERIESC · Freestanding RV32I and K&R
CARD13/13
SHEET1/9
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID72e2cbba-4658-5de2-a0dc-8b600ee3f7b0CARD UUID29e6021a-d033-5fbe-a5fc-ec03442ac68aAUTHOR  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
", + "left_margin_html": "
TECH
", + "right_margin_html": "
OG
", + "goal_title": "Cel karty", + "goal_html": "

Uczeń rozdziela fizyczny lub modelowany poziom wejścia, detekcję zbocza, zatrzaśnięty pending, maskowanie kontrolera, wybór handlera i efekt wykonywany później przez main. Potrafi zrealizować quiet-window debounce oraz połączyć timer, UART i GPIO w końcowym superloop bez RTOS.

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

Cztery przykłady wykonują się na centralnym modelu RTL Hazard3. TEST_IN i UART TEST_RX są jawnie wyłącznie bodźcami testbencha. Karta nie udaje modelu RP2350 ani fizycznego pinu. Task01 dowodzi DIR/OUT/IN przez polling, Task02 pełnej ścieżki rising-edge IRQ18 z W1C, Task03 krótkiego ISR i decyzji debounce w main, a Task04 współpracy machine timer, UART IRQ16 i GPIO IRQ18. 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": [ + "Typ", + "Task", + "Idea", + "Waga" + ], + "scope_rows": [ + { + "chapter": "POLL", + "task": "Task01", + "idea_html": "

kierunek, latch wyjścia i testbench-only bodziec wejścia

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

zbocze, pending peryferium, kontroler i resume

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

krótki ISR, mtime i decyzja stabilności w main

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

trzy źródła, dwa dispatchery, flagi i efekty main

", + "priority": "kluczowe", + "status": "", + "status_label": "", + "version": "", + "key": true + } + ] + }, + "sections": [ + { + "id": "section-1-content", + "index": 1, + "title": "1 — Rejestr modelu nie jest fizycznym pinem", + "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\n\n
TITLEGPIO, zbocza i quiet-window debounce
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C na RV32I
SERIESC · Freestanding RV32I and K&R
CARD13/13
SHEET2/9
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID72e2cbba-4658-5de2-a0dc-8b600ee3f7b0CARD UUID29e6021a-d033-5fbe-a5fc-ec03442ac68aAUTHOR  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
", + "left_margin_html": "
TECH
", + "right_margin_html": "
OG
", + "content_html": "

GPIO modelu zaczyna się pod adresem 0xc0000300. DIR wybiera kierunek, OUT/OUT_SET/OUT_CLR sterują zatrzaśnięciem wyjściowym, a IN pokazuje wyjścia dla pinów ustawionych jako output i bodziec zewnętrzny dla pinów input. RISE_EN i FALL_EN wybierają wykrywane zbocza, a PENDING zatrzaskuje je do zapisu W1C.

\n

TEST_IN istnieje tylko po stronie laboratorium. Pozwala programowi testowemu wywołać zmianę otoczenia bez fizycznego przewodu. Produkcyjny sterownik czyta IN; nie powinien zawierać zapisu do takiego fixture'u.

", + "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 — Source, pending i enable to trzy różne fakty", + "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\n\n
TITLEGPIO, zbocza i quiet-window debounce
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C na RV32I
SERIESC · Freestanding RV32I and K&R
CARD13/13
SHEET3/9
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID72e2cbba-4658-5de2-a0dc-8b600ee3f7b0CARD UUID29e6021a-d033-5fbe-a5fc-ec03442ac68aAUTHOR  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
", + "left_margin_html": "
TECH
", + "right_margin_html": "
OG
", + "content_html": "

Zmiana 0 na 1 jest source dla detektora rising edge. Włączony bit RISE_EN pozwala zatrzasnąć bit w PENDING; ten bit utrzymuje poziomową linię GPIO external IRQ18. Kontroler Hazard3 osobno ma per-line enable, priorytet oraz globalne bramki mie.MEIE i mstatus.MIE. Dispatcher odczytuje aktywny numer i wywołuje handler z tablicy.

\n

W1C usuwa źródło poziomowego żądania po stronie peryferium. Sam powrót z handlera, odczyt PENDING ani zamknięcie maski nie potwierdzają zdarzenia.

", + "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 — Debounce jest decyzją czasu w main", + "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\n\n
TITLEGPIO, zbocza i quiet-window debounce
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C na RV32I
SERIESC · Freestanding RV32I and K&R
CARD13/13
SHEET4/9
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID72e2cbba-4658-5de2-a0dc-8b600ee3f7b0CARD UUID29e6021a-d033-5fbe-a5fc-ec03442ac68aAUTHOR  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
", + "left_margin_html": "
TECH
", + "right_margin_html": "
OG
", + "content_html": "

ISR Task03 robi tylko trzy rzeczy: zapisuje czas i poziom, potwierdza pending przez W1C oraz na końcu publikuje licznik. Main obserwuje kandydata i akceptuje go dopiero wtedy, gdy od ostatniego zbocza minęło quiet window oraz bieżący poziom nadal odpowiada kandydatowi. Każde nowe zbocze przesuwa początek okna.

\n

Sekwencja 1-0-1 jest kontrolowanym bounce. Oba odstępy są krótsze od 2000 taktów, dlatego żaden z trzech bezpośrednich odczytów nie może zaakceptować stanu. To polityka aplikacji, nie funkcja kontrolera przerwań.

", + "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 — Superloop jest granicą serii raw C", + "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\n\n
TITLEGPIO, zbocza i quiet-window debounce
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C na RV32I
SERIESC · Freestanding RV32I and K&R
CARD13/13
SHEET5/9
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID72e2cbba-4658-5de2-a0dc-8b600ee3f7b0CARD UUID29e6021a-d033-5fbe-a5fc-ec03442ac68aAUTHOR  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
", + "left_margin_html": "
TECH
", + "right_margin_html": "
OG
", + "content_html": "

Task04 łączy machine timer, UART0 RX external IRQ16 i GPIO external IRQ18. ISR-y publikują flagi, a main konsumuje je i ustawia trzy różne bity wyjściowe. Flaga może skleić wiele produkcji, więc nie jest kolejką; zachowanie liczby i kolejności zdarzeń należy do następnej serii FreeRTOS.

", + "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 — Polling DIR, OUT i IN", + "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\n\n
TITLEGPIO, zbocza i quiet-window debounce
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C na RV32I
SERIESC · Freestanding RV32I and K&R
CARD13/13
SHEET6/9
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID72e2cbba-4658-5de2-a0dc-8b600ee3f7b0CARD UUID29e6021a-d033-5fbe-a5fc-ec03442ac68aAUTHOR  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
", + "left_margin_html": "
TECH
", + "right_margin_html": "
OG
", + "content_html": "", + "tasks": [ + { + "ref": "task01", + "title": "Polling DIR, OUT i IN", + "uuid": "223fada6-43e4-532a-9c9b-e17445857214", + "criterion": "Oracle: dir=1, external_high=2, out_after_set=1, both_high=3, final_in=0, pass=1 i kod wyjścia 0. PENDING pozostaje 0, ponieważ detektory zboczy są wyłączone.", + "conclusion_html": "", + "prompt_html": "

Przewidź cztery wartości: IN po ustawieniu zewnętrznego pinu 1, OUT po ustawieniu pinu 0, IN przy obu wysokich i IN po wyzerowaniu. Wyjaśnij, dlaczego zapis TEST_IN jest dozwolony tylko w fixture testbencha.

", + "flow": [ + { + "id": "task01.a1", + "kind": "block", + "title": "A1 CONTEXT · AKTYWNE — dwa źródła widocznego IN", + "content_html": "

Zachowany przykład: \\nolinkurl{src/tasks/task01_gpio_polling.c}. Dla bitu z DIR=1 widoczne IN pochodzi z latcha OUT; dla DIR=0 pochodzi z modelowanego wejścia. TEST_IN zmienia tylko tę drugą część i jest bodźcem laboratorium, nie pinem RP2350.

", + "steps": [] + }, + { + "id": "task01.a2", + "kind": "block", + "title": "A2 STRUCTURE · AKTYWNE — pin0 output, pin1 input", + "content_html": "

Maska 0x1 wybiera pin wyjściowy, a 0x2 wejściowy. Rejestry SET i CLR modyfikują latch bez read-modify-write. Jeden odczyt IN składa oba widoki, dlatego przy obu stanach wysokich wynosi 0x3.

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

N/D. Task01 wyłącza detektory zboczy i przerwania; każdy krok jest bezpośrednim pollingiem MMIO, bez ISR, callbacku ani wyboru handlera.

", + "steps": [] + }, + { + "id": "task01.a4", + "kind": "block", + "title": "A4 APPLICATION · AKTYWNE — kontrolowany round trip poziomów", + "content_html": "

Po external high program widzi 0x2. SET pinu0 daje OUT=0x1 i IN=0x3. CLR pinu0 oraz TEST_IN=0 kończą sekwencję IN=0. Te liczby są bitowymi relacjami modelu, nie numerami pinów konkretnej płytki.

", + "steps": [] + }, + { + "id": "task01.a5", + "kind": "block", + "title": "A5 FLOW · AKTYWNE — configure, stimulate, sample, clear", + "content_html": "

Program wyłącza edge enable, czyści pending, ustawia kierunek i stan początkowy. Następnie podaje bodziec wejściowy, próbkuje, ustawia output, próbkuje ponownie i zeruje oba źródła. Każdy pomiar następuje po odpowiadającym mu zapisie MMIO.

", + "steps": [] + }, + { + "id": "task01.a6", + "kind": "block", + "title": "A6 STATE · AKTYWNE — 0x2 → 0x3 → 0x0", + "content_html": "

Widoczny stan portu przechodzi kolejno przez tylko input high, oba bity high i oba low. Kierunek pozostaje 0x1 przez cały eksperyment, a pending pozostaje pusty.

", + "steps": [] + }, + { + "id": "task01.a7", + "kind": "block", + "title": "A7 RUNTIME · AKTYWNE — rzeczywiste transakcje pod 0xc0000300", + "content_html": "

Log RTL raportuje 1,2,1,3,0 i pass=1. Listing powinien pokazać osobne zapisy do offsetów DIR, TEST_IN, OUT_SET i OUT_CLR oraz odczyty IN; nie ma wejścia do wspólnego dispatchera external IRQ.

", + "steps": [] + }, + { + "id": "task01.a8", + "kind": "block", + "title": "A8 PATTERNS · AKTYWNE — polling z jawną granicą fixture", + "content_html": "

Wzorzec produkcyjny konfiguruje kierunek i czyta wejście lub steruje wyjściem. Warstwa testowa może dostarczyć osobny mechanizm wstrzyknięcia, ale jego nazwa, dokumentacja i lokalizacja muszą uniemożliwiać pomylenie z rejestrem sprzętu.

", + "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. Log RTL: DIR, OUT i kolejne wartości IN \\noindent \\noindent 3. Granica modelu: TEST_IN kontra fizyczny pin \\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 — Rising edge, IRQ18 i W1C", + "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\n\n
TITLEGPIO, zbocza i quiet-window debounce
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C na RV32I
SERIESC · Freestanding RV32I and K&R
CARD13/13
SHEET7/9
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID72e2cbba-4658-5de2-a0dc-8b600ee3f7b0CARD UUID29e6021a-d033-5fbe-a5fc-ec03442ac68aAUTHOR  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
", + "left_margin_html": "
TECH
", + "right_margin_html": "
OG
", + "content_html": "", + "tasks": [ + { + "ref": "task02", + "title": "Rising edge, IRQ18 i W1C", + "uuid": "93fb66db-d0ac-5fc2-811e-5b28e072a346", + "criterion": "Jeden handler IRQ18 widzi PENDING=0x4 i poziom high. GPIO source oraz controller pending są 1 przed globalnym enable i 0 po W1C; high→high nie tworzy nowego pending, resume=1, pass=1.", + "conclusion_html": "", + "prompt_html": "

Rozpisz ścieżkę od zmiany TEST_IN 0→1 do wznowienia main. Zaznacz GPIO PENDING, pending linii 18 w kontrolerze, dwa poziomy enable, decyzję dispatchera, zapis W1C i efekt ponownego podania tego samego poziomu.

", + "flow": [ + { + "id": "task02.a1", + "kind": "block", + "title": "A1 CONTEXT · AKTYWNE — zbocze tworzy zatrzaśnięty fakt", + "content_html": "

Zachowany przykład: \\nolinkurl{src/tasks/task02_gpio_rising_irq.c}. Bodziec TEST_IN zmienia pin2 z 0 na 1. Włączony bit RISE_EN tworzy bit 0x4 w GPIO PENDING, a ten utrzymuje external IRQ18. TEST_IN jest sztuczny, lecz dalsza ścieżka przez kontroler i rdzeń jest rzeczywistą ścieżką modelu RTL.

", + "steps": [] + }, + { + "id": "task02.a2", + "kind": "block", + "title": "A2 STRUCTURE · AKTYWNE — dwa pending i tablica handlerów", + "content_html": "

Pierwszy pending leży w peryferium jako maska pinów. Drugi jest widokiem aktywnej linii 18 w kontrolerze Hazard3. Tablica _external_irq_table[18] przechowuje adres zwykłej funkcji handlera.

", + "steps": [] + }, + { + "id": "task02.a3", + "kind": "block", + "title": "A3 DISPATCH · AKTYWNE — external vector wybiera linię 18", + "content_html": "

mtvec wybiera wspólny vector machine external interrupt. irq_dispatch.S odczytuje aktywną linię z meinext, indeksuje tablicę i wykonuje pośredni jalr do handlera GPIO. Handler potwierdza, że bieżący numer to 18.

", + "steps": [] + }, + { + "id": "task02.a4", + "kind": "block", + "title": "A4 APPLICATION · AKTYWNE — jedno zbocze, jedno wznowienie", + "content_html": "

Program celowo generuje edge przy zamkniętym globalnym MIE. Dzięki temu może najpierw zmierzyć oba pending jako 1. Po otwarciu MIE oczekuje dokładnie jednego handlera, W1C, obu pending równych 0 i wykonania kodu resume.

", + "steps": [] + }, + { + "id": "task02.a5", + "kind": "block", + "title": "A5 FLOW · AKTYWNE — source → pending → enable → dispatch → W1C", + "content_html": "

0→1 ustawia GPIO PENDING. Włączona linia18, MEIE i później MIE dopuszczają trap. Dispatcher wybiera handler18; ISR próbkuje maskę i poziom, zapisuje tę maskę do PENDING jako W1C, a dopiero potem publikuje count. Main wraca i mierzy stan 0.

", + "steps": [] + }, + { + "id": "task02.a6", + "kind": "block", + "title": "A6 STATE · AKTYWNE — IDLE, LATCHED, HANDLING, ACKED, RESUMED", + "content_html": "

IDLE ma input low i pending 0. Rising edge tworzy LATCHED. Otwarcie MIE prowadzi do HANDLING. Zapis W1C tworzy ACKED, a powrót dispatchera RESUMED. Ponowne high pozostaje ACKED, ponieważ nie zaszła zmiana 0→1.

", + "steps": [] + }, + { + "id": "task02.a7", + "kind": "block", + "title": "A7 RUNTIME · AKTYWNE — 0x4 w GPIO i 18 w kontrolerze", + "content_html": "

Raport daje count=1, irq=0x12, source/controller przed 1, pending w ISR 0x4, oba pending po 0 i same-level 0. Listing ma zawierać handler GPIO oraz wspólny dispatcher zakończony mret.

", + "steps": [] + }, + { + "id": "task02.a8", + "kind": "block", + "title": "A8 PATTERNS · AKTYWNE — acknowledge peripheral before publish", + "content_html": "

Dla poziomowego IRQ najpierw ustal i usuń przyczynę po stronie peryferium, a dopiero potem publikuj zakończenie dla main. Zamknięcie maski może odłożyć obsługę, ale nie jest potwierdzeniem zdarzenia.

", + "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. Log RTL: pending GPIO i kontrolera przed/po ISR \\noindent \\noindent 3. Dowód dispatchu IRQ18 i zapisu W1C \\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 — Quiet-window debounce po trzech zboczach", + "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\n\n
TITLEGPIO, zbocza i quiet-window debounce
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C na RV32I
SERIESC · Freestanding RV32I and K&R
CARD13/13
SHEET8/9
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID72e2cbba-4658-5de2-a0dc-8b600ee3f7b0CARD UUID29e6021a-d033-5fbe-a5fc-ec03442ac68aAUTHOR  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
", + "left_margin_html": "
TECH
", + "right_margin_html": "
OG
", + "content_html": "", + "tasks": [ + { + "ref": "task03", + "title": "Quiet-window debounce po trzech zboczach", + "uuid": "a2e3b023-04f1-5863-a4e0-360b5ec69b89", + "criterion": "Poziomy 1,0,1, count=3 i IRQ18. Oba gapy są dodatnie i mniejsze od quiet=2000; early=0, accepted=1, zaakceptowany poziom high, accepted_after >= quiet i pass=1.", + "conclusion_html": "", + "prompt_html": "

Dla sekwencji poziomów 1,0,1 oblicz oba odstępy i porównaj z quiet=2000. Wyjaśnij, dlaczego ISR publikuje czas, lecz nie akceptuje przycisku, oraz jak nowe zbocze restartuje okno ciszy.

", + "flow": [ + { + "id": "task03.a1", + "kind": "block", + "title": "A1 CONTEXT · AKTYWNE — IRQ rejestruje zmianę, nie intencję użytkownika", + "content_html": "

Zachowany przykład: \\nolinkurl{src/tasks/task03_gpio_quiet_window.c}. Trzy przejścia TEST_IN modelują bounce, nie trzy świadome naciśnięcia. Kontroler potrafi zgłosić rising i falling edge, lecz nie zna quiet window ani znaczenia stabilnego przycisku. Ta semantyka należy do kodu normalnego.

", + "steps": [] + }, + { + "id": "task03.a2", + "kind": "block", + "title": "A2 STRUCTURE · AKTYWNE — historia ISR i kandydat main", + "content_html": "

ISR zapisuje trzy pary level,time, a osobno publikuje ostatni poziom, ostatni czas i count. Main utrzymuje seen count, candidate level oraz candidate time. Krytyczna sekcja chroni snapshot 64-bitowego czasu na RV32.

", + "steps": [] + }, + { + "id": "task03.a3", + "kind": "block", + "title": "A3 DISPATCH · AKTYWNE — każde włączone zbocze wybiera GPIO18", + "content_html": "

RISE_EN i FALL_EN pozwalają trzem przejściom utworzyć pending. External dispatcher trzy razy wybiera wpis 18 i wywołuje ten sam krótki handler. Numer ostatniego handlera oraz count=3 są dowodem decyzji, nie sam fakt zapisu TEST_IN.

", + "steps": [] + }, + { + "id": "task03.a4", + "kind": "block", + "title": "A4 APPLICATION · AKTYWNE — restart okna po każdym bounce", + "content_html": "

Po każdym nowym count main zastępuje candidate time czasem ostatniego zbocza. Natychmiastowe próby dają early=0. Dopiero stabilny high utrzymany przez co najmniej 2000 taktów daje accepted=1.

", + "steps": [] + }, + { + "id": "task03.a5", + "kind": "block", + "title": "A5 FLOW · AKTYWNE — ISR publish, main observe, wait, validate", + "content_html": "

ISR czyta pending, poziom i mtime, zapisuje rekord, wykonuje W1C i na końcu zwiększa count. Main atomowo pobiera publikację, aktualizuje kandydata, mierzy wiek oraz porównuje bieżący IN. Nowe zbocze wraca do początku okna.

", + "steps": [] + }, + { + "id": "task03.a6", + "kind": "block", + "title": "A6 STATE · AKTYWNE — HIGH?, LOW?, HIGH?, STABLE_HIGH", + "content_html": "

Pierwsze high jest kandydatem, low unieważnia go, a drugie high tworzy nowego kandydata. Żaden stan z wiekiem mniejszym niż quiet nie jest zaakceptowany. STABLE_HIGH powstaje dopiero po pełnym oknie bez kolejnego IRQ.

", + "steps": [] + }, + { + "id": "task03.a7", + "kind": "block", + "title": "A7 RUNTIME · AKTYWNE — dwa bounce gapy krótsze od 0x7d0", + "content_html": "

Bieżący RTL raportuje czasy low 0x591, 0x8ea, 0xc43, czyli oba gapy 0x359. Akceptacja następuje po 0x878 od ostatniego edge. Konkretne czasy zależą od buildu; oracle niezależnie sprawdza tylko relacje gap<quiet i accepted_after>=quiet.

", + "steps": [] + }, + { + "id": "task03.a8", + "kind": "block", + "title": "A8 PATTERNS · AKTYWNE — timestamp in ISR, policy in consumer", + "content_html": "

ISR powinien szybko potwierdzić sprzęt i opublikować minimalne dane. Konsument może wtedy zmieniać quiet window, politykę akceptacji lub raportowanie bez wydłużania czasu blokowania innych przerwań.

", + "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. Log RTL: trzy poziomy, czasy i gapy \\noindent \\noindent 3. Dowód quiet window i miejsca decyzji w main \\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 — Timer + UART16 + GPIO18 bez RTOS", + "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\n\n
TITLEGPIO, zbocza i quiet-window debounce
VER.v00.01
DATETIME2026-07-20T00:00:00+02:00
PROJECTFreestanding C na RV32I
SERIESC · Freestanding RV32I and K&R
CARD13/13
SHEET9/9
SUBJ.Inf.
PROG.
CORE
SCOPE
LEVEL
POS.
GITEA UUID72e2cbba-4658-5de2-a0dc-8b600ee3f7b0CARD UUID29e6021a-d033-5fbe-a5fc-ec03442ac68aAUTHOR  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
", + "left_margin_html": "
TECH
", + "right_margin_html": "
OG
", + "content_html": "", + "tasks": [ + { + "ref": "task04", + "title": "Timer + UART16 + GPIO18 bez RTOS", + "uuid": "ebb18b6a-cf31-5595-9901-ac2ac870296f", + "criterion": "Po jednym timer IRQ z mcause=0x80000007, UART IRQ16 z bajtem 0x55 i GPIO IRQ18 z high. Main konsumuje każdą flagę raz, ustawia trzy bity, OUT=0x7, IN=0x17, pass=1.", + "conclusion_html": "", + "prompt_html": "

Dla timer tick, bajtu U i rising edge narysuj trzy osobne ścieżki source-pending-enable-dispatcher-ISR-flag-main effect. Wyjaśnij, dlaczego trzy flagi nie są kolejką i jakie ograniczenie przechodzi do serii FreeRTOS.

", + "flow": [ + { + "id": "task04.a1", + "kind": "block", + "title": "A1 CONTEXT · AKTYWNE — trzy usługi, wspólny czas CPU", + "content_html": "

Zachowany przykład: \\nolinkurl{src/tasks/task04_raw_c_superloop.c}. Machine timer pochodzi z mtime>=mtimecmp, UART16 z niepustego RX FIFO przy włączonym RX IRQ, a GPIO18 z rising edge zatrzaśniętego w PENDING. TEST_RX i TEST_IN tworzą tylko bodźce; logika timer/UART/GPIO po nich jest rzeczywistym modelem RTL.

", + "steps": [] + }, + { + "id": "task04.a2", + "kind": "block", + "title": "A2 STRUCTURE · AKTYWNE — trzy publikacje i trzy bity efektu", + "content_html": "

Każda usługa ma licznik ISR, payload i flagę. Main ma osobny licznik konsumpcji. Bity OUT 0,1,2 reprezentują odpowiednio efekt GPIO, UART i timera, więc końcowe 0x7 dowodzi wykonania trzech gałęzi bez ukrywania ich w jednej sumie.

", + "steps": [] + }, + { + "id": "task04.a3", + "kind": "block", + "title": "A3 DISPATCH · AKTYWNE — slot 7 oraz external 16/18", + "content_html": "

Machine timer cause 7 trafia bezpośrednio do isr_machine_timer i wraca przez mret. Machine external vector trafia do wspólnego dispatchera; meinext wybiera wpis 16 dla UART albo 18 dla GPIO i wykonuje jalr.

", + "steps": [] + }, + { + "id": "task04.a4", + "kind": "block", + "title": "A4 APPLICATION · AKTYWNE — efekt dopiero po konsumpcji flagi", + "content_html": "

UART handler publikuje U, GPIO handler high, a timer handler tick. Żaden ISR nie ustawia aplikacyjnego bitu OUT. Superloop atomowo zabiera flagę i dopiero jego trzy gałęzie ustawiają 0x2, 0x1 i 0x4.

", + "steps": [] + }, + { + "id": "task04.a5", + "kind": "block", + "title": "A5 FLOW · AKTYWNE — source → pending → dispatch → ISR → main", + "content_html": "

Timer: comparator→MTIP→slot7→tick flag→bit2. UART: RX FIFO→IRQ16→external dispatcher→read DATA i flag→bit1. GPIO: edge→PENDING→IRQ18→dispatcher→W1C i flag→bit0. Main używa WFI tylko wtedy, gdy nadal brakuje któregoś efektu.

", + "steps": [] + }, + { + "id": "task04.a6", + "kind": "block", + "title": "A6 STATE · AKTYWNE — trzy niezależne PRODUCED/CONSUMED", + "content_html": "

Każda usługa przechodzi IDLE→PRODUCED w ISR i PRODUCED→CONSUMED w main. Stan końcowy wymaga trzech liczników konsumpcji równych 1. Flaga wraca do 0, ale licznik zachowuje dowód przejścia.

", + "steps": [] + }, + { + "id": "task04.a7", + "kind": "block", + "title": "A7 RUNTIME · AKTYWNE — cause 7, linie 16/18 i OUT 0x7", + "content_html": "

Raport daje timer count 1 i mcause 0x80000007, UART count 1/irq 0x10/byte 0x55, GPIO count 1/irq 0x12/high oraz trzy main actions po 1. OUT=0x7, a IN=0x17 dodaje widoczny wysoki pin wejściowy 0x10.

", + "steps": [] + }, + { + "id": "task04.a8", + "kind": "block", + "title": "A8 PATTERNS · AKTYWNE — ISR-to-main flags with an explicit ceiling", + "content_html": "

Jednokomórkowa flaga jest poprawna tylko wtedy, gdy wystarcza informacja co najmniej jedno zdarzenie. Nie zachowuje liczby ani kolejności wielu produkcji. Ten sufit jest powodem przejścia do kolejek i tasków FreeRTOS, a nie pretekstem do nazywania flagi kolejką.

", + "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. Log RTL: timer, UART16, GPIO18 i efekty main \\noindent \\noindent 3. Dowód dwóch dispatcherów i końcowego OUT/IN \\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 — Rejestr modelu nie jest fizycznym pinem" + }, + { + "id": "section-2-content", + "label": "2. 2 — Source, pending i enable to trzy różne fakty" + }, + { + "id": "section-3-content", + "label": "3. 3 — Debounce jest decyzją czasu w main" + }, + { + "id": "section-4-content", + "label": "4. 4 — Superloop jest granicą serii raw C" + }, + { + "id": "section-5-task01", + "label": "5. TASK01 — Polling DIR, OUT i IN" + }, + { + "id": "section-6-task02", + "label": "6. TASK02 — Rising edge, IRQ18 i W1C" + }, + { + "id": "section-7-task03", + "label": "7. TASK03 — Quiet-window debounce po trzech zboczach" + }, + { + "id": "section-8-task04", + "label": "8. TASK04 — Timer + UART16 + GPIO18 bez RTOS" + } + ] +} 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..8adf3e2 --- /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,PHN2ZyBjbGFzcz0idGl0bGUtcXIiIHJvbGU9ImltZyIgYXJpYS1sYWJlbD0iS29kIFFSOiBodHRwczovL3pzbC1naXRlYS5tcGFiaS5wbC9lZHUtaW5mL2xhYi1ydjMyaS1jLWdwaW8tZWRnZXMtZGVib3VuY2UiIHZlcnNpb249JzEuMScgeG1sbnM9J2h0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnJyB4bWxuczp4bGluaz0naHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluaycgd2lkdGg9Jzg1LjAzOTE5NnB0JyBoZWlnaHQ9Jzg1LjAzOTE5NnB0JyB2aWV3Qm94PSctNzIuMDAwMDA0IC03Mi4wMDAwMDQgODUuMDM5MTk2IDg1LjAzOTE5Nic+CjxnIGlkPSdwYWdlMSc+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy03Mi4wMDAwMDQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjkuNDIzMDU5JyB5PSctNzIuMDAwMDA0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY2Ljg0NjExNCcgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02NC4yNjkxNjgnIHk9Jy03Mi4wMDAwMDQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjEuNjkyMjIzJyB5PSctNzIuMDAwMDA0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTU5LjExNTI3OCcgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01Ni41MzgzMzInIHk9Jy03Mi4wMDAwMDQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDYuMjMwNTUxJyB5PSctNzIuMDAwMDA0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTM1LjkyMjc2OScgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zMy4zNDU4MjQnIHk9Jy03Mi4wMDAwMDQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjguMTkxOTMzJyB5PSctNzIuMDAwMDA0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTI1LjYxNDk4OCcgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yMy4wMzgwNDMnIHk9Jy03Mi4wMDAwMDQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTUuMzA3MjA3JyB5PSctNzIuMDAwMDA0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTEyLjczMDI2MScgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00Ljk5OTQyNScgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yLjQyMjQ4JyB5PSctNzIuMDAwMDA0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLjE1NDQ2NScgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzIuNzMxNDExJyB5PSctNzIuMDAwMDA0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nNS4zMDgzNTYnIHk9Jy03Mi4wMDAwMDQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSc3Ljg4NTMwMScgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzEwLjQ2MjI0NycgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy02OS40MjMwNTknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTYuNTM4MzMyJyB5PSctNjkuNDIzMDU5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTUxLjM4NDQ0MicgeT0nLTY5LjQyMzA1OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00OC44MDc0OTYnIHk9Jy02OS40MjMwNTknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDYuMjMwNTUxJyB5PSctNjkuNDIzMDU5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTM1LjkyMjc2OScgeT0nLTY5LjQyMzA1OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zMy4zNDU4MjQnIHk9Jy02OS40MjMwNTknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzAuNzY4ODc5JyB5PSctNjkuNDIzMDU5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTI4LjE5MTkzMycgeT0nLTY5LjQyMzA1OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xNy44ODQxNTInIHk9Jy02OS40MjMwNTknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTIuNzMwMjYxJyB5PSctNjkuNDIzMDU5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTEwLjE1MzMxNicgeT0nLTY5LjQyMzA1OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00Ljk5OTQyNScgeT0nLTY5LjQyMzA1OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzEwLjQ2MjI0NycgeT0nLTY5LjQyMzA1OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy02Ni44NDYxMTQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjYuODQ2MTE0JyB5PSctNjYuODQ2MTE0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY0LjI2OTE2OCcgeT0nLTY2Ljg0NjExNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02MS42OTIyMjMnIHk9Jy02Ni44NDYxMTQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTYuNTM4MzMyJyB5PSctNjYuODQ2MTE0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTUxLjM4NDQ0MicgeT0nLTY2Ljg0NjExNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zNS45MjI3NjknIHk9Jy02Ni44NDYxMTQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjguMTkxOTMzJyB5PSctNjYuODQ2MTE0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIzLjAzODA0MycgeT0nLTY2Ljg0NjExNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00Ljk5OTQyNScgeT0nLTY2Ljg0NjExNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy4xNTQ0NjUnIHk9Jy02Ni44NDYxMTQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScyLjczMTQxMScgeT0nLTY2Ljg0NjExNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzUuMzA4MzU2JyB5PSctNjYuODQ2MTE0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nMTAuNDYyMjQ3JyB5PSctNjYuODQ2MTE0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nLTY0LjI2OTE2OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02Ni44NDYxMTQnIHk9Jy02NC4yNjkxNjgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjQuMjY5MTY4JyB5PSctNjQuMjY5MTY4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTYxLjY5MjIyMycgeT0nLTY0LjI2OTE2OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01Ni41MzgzMzInIHk9Jy02NC4yNjkxNjgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDguODA3NDk2JyB5PSctNjQuMjY5MTY4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQxLjA3NjY2JyB5PSctNjQuMjY5MTY4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTM1LjkyMjc2OScgeT0nLTY0LjI2OTE2OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zMy4zNDU4MjQnIHk9Jy02NC4yNjkxNjgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjMuMDM4MDQzJyB5PSctNjQuMjY5MTY4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIwLjQ2MTA5NycgeT0nLTY0LjI2OTE2OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xNS4zMDcyMDcnIHk9Jy02NC4yNjkxNjgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNC45OTk0MjUnIHk9Jy02NC4yNjkxNjgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScuMTU0NDY1JyB5PSctNjQuMjY5MTY4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nMi43MzE0MTEnIHk9Jy02NC4yNjkxNjgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSc1LjMwODM1NicgeT0nLTY0LjI2OTE2OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzEwLjQ2MjI0NycgeT0nLTY0LjI2OTE2OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy02MS42OTIyMjMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjYuODQ2MTE0JyB5PSctNjEuNjkyMjIzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY0LjI2OTE2OCcgeT0nLTYxLjY5MjIyMycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02MS42OTIyMjMnIHk9Jy02MS42OTIyMjMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTYuNTM4MzMyJyB5PSctNjEuNjkyMjIzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTUxLjM4NDQ0MicgeT0nLTYxLjY5MjIyMycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00OC44MDc0OTYnIHk9Jy02MS42OTIyMjMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDYuMjMwNTUxJyB5PSctNjEuNjkyMjIzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQxLjA3NjY2JyB5PSctNjEuNjkyMjIzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTM4LjQ5OTcxNScgeT0nLTYxLjY5MjIyMycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zNS45MjI3NjknIHk9Jy02MS42OTIyMjMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzMuMzQ1ODI0JyB5PSctNjEuNjkyMjIzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTMwLjc2ODg3OScgeT0nLTYxLjY5MjIyMycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yOC4xOTE5MzMnIHk9Jy02MS42OTIyMjMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjUuNjE0OTg4JyB5PSctNjEuNjkyMjIzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIwLjQ2MTA5NycgeT0nLTYxLjY5MjIyMycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xMi43MzAyNjEnIHk9Jy02MS42OTIyMjMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTAuMTUzMzE2JyB5PSctNjEuNjkyMjIzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQuOTk5NDI1JyB5PSctNjEuNjkyMjIzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLjE1NDQ2NScgeT0nLTYxLjY5MjIyMycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzIuNzMxNDExJyB5PSctNjEuNjkyMjIzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nNS4zMDgzNTYnIHk9Jy02MS42OTIyMjMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScxMC40NjIyNDcnIHk9Jy02MS42OTIyMjMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSctNTkuMTE1Mjc4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTU2LjUzODMzMicgeT0nLTU5LjExNTI3OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01MS4zODQ0NDInIHk9Jy01OS4xMTUyNzgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDYuMjMwNTUxJyB5PSctNTkuMTE1Mjc4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQxLjA3NjY2JyB5PSctNTkuMTE1Mjc4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTM1LjkyMjc2OScgeT0nLTU5LjExNTI3OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zMy4zNDU4MjQnIHk9Jy01OS4xMTUyNzgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzAuNzY4ODc5JyB5PSctNTkuMTE1Mjc4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTI1LjYxNDk4OCcgeT0nLTU5LjExNTI3OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yMy4wMzgwNDMnIHk9Jy01OS4xMTUyNzgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTcuODg0MTUyJyB5PSctNTkuMTE1Mjc4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTE1LjMwNzIwNycgeT0nLTU5LjExNTI3OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00Ljk5OTQyNScgeT0nLTU5LjExNTI3OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzEwLjQ2MjI0NycgeT0nLTU5LjExNTI3OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy01Ni41MzgzMzInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjkuNDIzMDU5JyB5PSctNTYuNTM4MzMyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY2Ljg0NjExNCcgeT0nLTU2LjUzODMzMicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02NC4yNjkxNjgnIHk9Jy01Ni41MzgzMzInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjEuNjkyMjIzJyB5PSctNTYuNTM4MzMyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTU5LjExNTI3OCcgeT0nLTU2LjUzODMzMicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01Ni41MzgzMzInIHk9Jy01Ni41MzgzMzInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTEuMzg0NDQyJyB5PSctNTYuNTM4MzMyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQ2LjIzMDU1MScgeT0nLTU2LjUzODMzMicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00MS4wNzY2NicgeT0nLTU2LjUzODMzMicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zNS45MjI3NjknIHk9Jy01Ni41MzgzMzInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzAuNzY4ODc5JyB5PSctNTYuNTM4MzMyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTI1LjYxNDk4OCcgeT0nLTU2LjUzODMzMicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yMC40NjEwOTcnIHk9Jy01Ni41MzgzMzInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTUuMzA3MjA3JyB5PSctNTYuNTM4MzMyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTEwLjE1MzMxNicgeT0nLTU2LjUzODMzMicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00Ljk5OTQyNScgeT0nLTU2LjUzODMzMicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yLjQyMjQ4JyB5PSctNTYuNTM4MzMyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLjE1NDQ2NScgeT0nLTU2LjUzODMzMicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzIuNzMxNDExJyB5PSctNTYuNTM4MzMyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nNS4zMDgzNTYnIHk9Jy01Ni41MzgzMzInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSc3Ljg4NTMwMScgeT0nLTU2LjUzODMzMicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzEwLjQ2MjI0NycgeT0nLTU2LjUzODMzMicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01MS4zODQ0NDInIHk9Jy01My45NjEzODcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDYuMjMwNTUxJyB5PSctNTMuOTYxMzg3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQzLjY1MzYwNScgeT0nLTUzLjk2MTM4NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zMy4zNDU4MjQnIHk9Jy01My45NjEzODcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjguMTkxOTMzJyB5PSctNTMuOTYxMzg3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTI1LjYxNDk4OCcgeT0nLTUzLjk2MTM4NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yMy4wMzgwNDMnIHk9Jy01My45NjEzODcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTcuODg0MTUyJyB5PSctNTMuOTYxMzg3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTE1LjMwNzIwNycgeT0nLTUzLjk2MTM4NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xMi43MzAyNjEnIHk9Jy01My45NjEzODcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTAuMTUzMzE2JyB5PSctNTMuOTYxMzg3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nLTUxLjM4NDQ0MicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02OS40MjMwNTknIHk9Jy01MS4zODQ0NDInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjQuMjY5MTY4JyB5PSctNTEuMzg0NDQyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTU2LjUzODMzMicgeT0nLTUxLjM4NDQ0MicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01My45NjEzODcnIHk9Jy01MS4zODQ0NDInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDMuNjUzNjA1JyB5PSctNTEuMzg0NDQyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQxLjA3NjY2JyB5PSctNTEuMzg0NDQyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTM4LjQ5OTcxNScgeT0nLTUxLjM4NDQ0MicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zNS45MjI3NjknIHk9Jy01MS4zODQ0NDInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzMuMzQ1ODI0JyB5PSctNTEuMzg0NDQyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTMwLjc2ODg3OScgeT0nLTUxLjM4NDQ0MicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yMC40NjEwOTcnIHk9Jy01MS4zODQ0NDInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTcuODg0MTUyJyB5PSctNTEuMzg0NDQyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTEwLjE1MzMxNicgeT0nLTUxLjM4NDQ0MicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00Ljk5OTQyNScgeT0nLTUxLjM4NDQ0MicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yLjQyMjQ4JyB5PSctNTEuMzg0NDQyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLjE1NDQ2NScgeT0nLTUxLjM4NDQ0MicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzUuMzA4MzU2JyB5PSctNTEuMzg0NDQyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nNy44ODUzMDEnIHk9Jy01MS4zODQ0NDInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSctNDguODA3NDk2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY5LjQyMzA1OScgeT0nLTQ4LjgwNzQ5NicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02Ni44NDYxMTQnIHk9Jy00OC44MDc0OTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjQuMjY5MTY4JyB5PSctNDguODA3NDk2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTU5LjExNTI3OCcgeT0nLTQ4LjgwNzQ5NicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00OC44MDc0OTYnIHk9Jy00OC44MDc0OTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDMuNjUzNjA1JyB5PSctNDguODA3NDk2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQxLjA3NjY2JyB5PSctNDguODA3NDk2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTI4LjE5MTkzMycgeT0nLTQ4LjgwNzQ5NicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xNy44ODQxNTInIHk9Jy00OC44MDc0OTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTUuMzA3MjA3JyB5PSctNDguODA3NDk2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTEwLjE1MzMxNicgeT0nLTQ4LjgwNzQ5NicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy03LjU3NjM3MScgeT0nLTQ4LjgwNzQ5NicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00Ljk5OTQyNScgeT0nLTQ4LjgwNzQ5NicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzIuNzMxNDExJyB5PSctNDguODA3NDk2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nMTAuNDYyMjQ3JyB5PSctNDguODA3NDk2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nLTQ2LjIzMDU1MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02OS40MjMwNTknIHk9Jy00Ni4yMzA1NTEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjYuODQ2MTE0JyB5PSctNDYuMjMwNTUxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTYxLjY5MjIyMycgeT0nLTQ2LjIzMDU1MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01OS4xMTUyNzgnIHk9Jy00Ni4yMzA1NTEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTYuNTM4MzMyJyB5PSctNDYuMjMwNTUxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTUzLjk2MTM4NycgeT0nLTQ2LjIzMDU1MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00My42NTM2MDUnIHk9Jy00Ni4yMzA1NTEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDEuMDc2NjYnIHk9Jy00Ni4yMzA1NTEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzAuNzY4ODc5JyB5PSctNDYuMjMwNTUxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTI4LjE5MTkzMycgeT0nLTQ2LjIzMDU1MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yNS42MTQ5ODgnIHk9Jy00Ni4yMzA1NTEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjMuMDM4MDQzJyB5PSctNDYuMjMwNTUxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIwLjQ2MTA5NycgeT0nLTQ2LjIzMDU1MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xNS4zMDcyMDcnIHk9Jy00Ni4yMzA1NTEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTAuMTUzMzE2JyB5PSctNDYuMjMwNTUxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQuOTk5NDI1JyB5PSctNDYuMjMwNTUxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nMi43MzE0MTEnIHk9Jy00Ni4yMzA1NTEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScxMC40NjIyNDcnIHk9Jy00Ni4yMzA1NTEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSctNDMuNjUzNjA1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY5LjQyMzA1OScgeT0nLTQzLjY1MzYwNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02MS42OTIyMjMnIHk9Jy00My42NTM2MDUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTkuMTE1Mjc4JyB5PSctNDMuNjUzNjA1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQ4LjgwNzQ5NicgeT0nLTQzLjY1MzYwNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00Ni4yMzA1NTEnIHk9Jy00My42NTM2MDUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDMuNjUzNjA1JyB5PSctNDMuNjUzNjA1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQxLjA3NjY2JyB5PSctNDMuNjUzNjA1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTM4LjQ5OTcxNScgeT0nLTQzLjY1MzYwNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yNS42MTQ5ODgnIHk9Jy00My42NTM2MDUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTcuODg0MTUyJyB5PSctNDMuNjUzNjA1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTE1LjMwNzIwNycgeT0nLTQzLjY1MzYwNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00Ljk5OTQyNScgeT0nLTQzLjY1MzYwNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzcuODg1MzAxJyB5PSctNDMuNjUzNjA1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nMTAuNDYyMjQ3JyB5PSctNDMuNjUzNjA1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nLTQxLjA3NjY2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY5LjQyMzA1OScgeT0nLTQxLjA3NjY2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY2Ljg0NjExNCcgeT0nLTQxLjA3NjY2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY0LjI2OTE2OCcgeT0nLTQxLjA3NjY2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTU2LjUzODMzMicgeT0nLTQxLjA3NjY2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTUxLjM4NDQ0MicgeT0nLTQxLjA3NjY2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQ2LjIzMDU1MScgeT0nLTQxLjA3NjY2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQzLjY1MzYwNScgeT0nLTQxLjA3NjY2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTM4LjQ5OTcxNScgeT0nLTQxLjA3NjY2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTI4LjE5MTkzMycgeT0nLTQxLjA3NjY2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTI1LjYxNDk4OCcgeT0nLTQxLjA3NjY2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTE3Ljg4NDE1MicgeT0nLTQxLjA3NjY2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTE1LjMwNzIwNycgeT0nLTQxLjA3NjY2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTcuNTc2MzcxJyB5PSctNDEuMDc2NjYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNC45OTk0MjUnIHk9Jy00MS4wNzY2NicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yLjQyMjQ4JyB5PSctNDEuMDc2NjYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScyLjczMTQxMScgeT0nLTQxLjA3NjY2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nMTAuNDYyMjQ3JyB5PSctNDEuMDc2NjYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjkuNDIzMDU5JyB5PSctMzguNDk5NzE1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY0LjI2OTE2OCcgeT0nLTM4LjQ5OTcxNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02MS42OTIyMjMnIHk9Jy0zOC40OTk3MTUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDguODA3NDk2JyB5PSctMzguNDk5NzE1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQzLjY1MzYwNScgeT0nLTM4LjQ5OTcxNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zNS45MjI3NjknIHk9Jy0zOC40OTk3MTUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjMuMDM4MDQzJyB5PSctMzguNDk5NzE1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIwLjQ2MTA5NycgeT0nLTM4LjQ5OTcxNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xNS4zMDcyMDcnIHk9Jy0zOC40OTk3MTUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTAuMTUzMzE2JyB5PSctMzguNDk5NzE1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQuOTk5NDI1JyB5PSctMzguNDk5NzE1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLjE1NDQ2NScgeT0nLTM4LjQ5OTcxNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzIuNzMxNDExJyB5PSctMzguNDk5NzE1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nNS4zMDgzNTYnIHk9Jy0zOC40OTk3MTUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSc3Ljg4NTMwMScgeT0nLTM4LjQ5OTcxNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzEwLjQ2MjI0NycgeT0nLTM4LjQ5OTcxNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02MS42OTIyMjMnIHk9Jy0zNS45MjI3NjknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTkuMTE1Mjc4JyB5PSctMzUuOTIyNzY5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTU2LjUzODMzMicgeT0nLTM1LjkyMjc2OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01My45NjEzODcnIHk9Jy0zNS45MjI3NjknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTEuMzg0NDQyJyB5PSctMzUuOTIyNzY5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQ4LjgwNzQ5NicgeT0nLTM1LjkyMjc2OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00My42NTM2MDUnIHk9Jy0zNS45MjI3NjknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzUuOTIyNzY5JyB5PSctMzUuOTIyNzY5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTI4LjE5MTkzMycgeT0nLTM1LjkyMjc2OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xMi43MzAyNjEnIHk9Jy0zNS45MjI3NjknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTAuMTUzMzE2JyB5PSctMzUuOTIyNzY5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIuNDIyNDgnIHk9Jy0zNS45MjI3NjknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScuMTU0NDY1JyB5PSctMzUuOTIyNzY5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nMi43MzE0MTEnIHk9Jy0zNS45MjI3NjknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSc3Ljg4NTMwMScgeT0nLTM1LjkyMjc2OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy0zMy4zNDU4MjQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjYuODQ2MTE0JyB5PSctMzMuMzQ1ODI0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY0LjI2OTE2OCcgeT0nLTMzLjM0NTgyNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01OS4xMTUyNzgnIHk9Jy0zMy4zNDU4MjQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTMuOTYxMzg3JyB5PSctMzMuMzQ1ODI0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQzLjY1MzYwNScgeT0nLTMzLjM0NTgyNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zOC40OTk3MTUnIHk9Jy0zMy4zNDU4MjQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzUuOTIyNzY5JyB5PSctMzMuMzQ1ODI0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTMzLjM0NTgyNCcgeT0nLTMzLjM0NTgyNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zMC43Njg4NzknIHk9Jy0zMy4zNDU4MjQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjguMTkxOTMzJyB5PSctMzMuMzQ1ODI0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTI1LjYxNDk4OCcgeT0nLTMzLjM0NTgyNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xNy44ODQxNTInIHk9Jy0zMy4zNDU4MjQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTUuMzA3MjA3JyB5PSctMzMuMzQ1ODI0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTEwLjE1MzMxNicgeT0nLTMzLjM0NTgyNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yLjQyMjQ4JyB5PSctMzMuMzQ1ODI0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLjE1NDQ2NScgeT0nLTMzLjM0NTgyNCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzIuNzMxNDExJyB5PSctMzMuMzQ1ODI0JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nNy44ODUzMDEnIHk9Jy0zMy4zNDU4MjQnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSctMzAuNzY4ODc5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY5LjQyMzA1OScgeT0nLTMwLjc2ODg3OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02NC4yNjkxNjgnIHk9Jy0zMC43Njg4NzknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjEuNjkyMjIzJyB5PSctMzAuNzY4ODc5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTU5LjExNTI3OCcgeT0nLTMwLjc2ODg3OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01Ni41MzgzMzInIHk9Jy0zMC43Njg4NzknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTEuMzg0NDQyJyB5PSctMzAuNzY4ODc5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQ4LjgwNzQ5NicgeT0nLTMwLjc2ODg3OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00MS4wNzY2NicgeT0nLTMwLjc2ODg3OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yOC4xOTE5MzMnIHk9Jy0zMC43Njg4NzknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjMuMDM4MDQzJyB5PSctMzAuNzY4ODc5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTE3Ljg4NDE1MicgeT0nLTMwLjc2ODg3OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xNS4zMDcyMDcnIHk9Jy0zMC43Njg4NzknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTIuNzMwMjYxJyB5PSctMzAuNzY4ODc5JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTEwLjE1MzMxNicgeT0nLTMwLjc2ODg3OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy03LjU3NjM3MScgeT0nLTMwLjc2ODg3OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00Ljk5OTQyNScgeT0nLTMwLjc2ODg3OScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy4xNTQ0NjUnIHk9Jy0zMC43Njg4NzknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScxMC40NjIyNDcnIHk9Jy0zMC43Njg4NzknIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjkuNDIzMDU5JyB5PSctMjguMTkxOTMzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY2Ljg0NjExNCcgeT0nLTI4LjE5MTkzMycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01OS4xMTUyNzgnIHk9Jy0yOC4xOTE5MzMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTEuMzg0NDQyJyB5PSctMjguMTkxOTMzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQ4LjgwNzQ5NicgeT0nLTI4LjE5MTkzMycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00Ni4yMzA1NTEnIHk9Jy0yOC4xOTE5MzMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDEuMDc2NjYnIHk9Jy0yOC4xOTE5MzMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzUuOTIyNzY5JyB5PSctMjguMTkxOTMzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTMwLjc2ODg3OScgeT0nLTI4LjE5MTkzMycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xMi43MzAyNjEnIHk9Jy0yOC4xOTE5MzMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNy41NzYzNzEnIHk9Jy0yOC4xOTE5MzMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScyLjczMTQxMScgeT0nLTI4LjE5MTkzMycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzUuMzA4MzU2JyB5PSctMjguMTkxOTMzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nLTI1LjYxNDk4OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02Ni44NDYxMTQnIHk9Jy0yNS42MTQ5ODgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjQuMjY5MTY4JyB5PSctMjUuNjE0OTg4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTYxLjY5MjIyMycgeT0nLTI1LjYxNDk4OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01OS4xMTUyNzgnIHk9Jy0yNS42MTQ5ODgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTYuNTM4MzMyJyB5PSctMjUuNjE0OTg4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQ4LjgwNzQ5NicgeT0nLTI1LjYxNDk4OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00Ni4yMzA1NTEnIHk9Jy0yNS42MTQ5ODgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDMuNjUzNjA1JyB5PSctMjUuNjE0OTg4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQxLjA3NjY2JyB5PSctMjUuNjE0OTg4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTM4LjQ5OTcxNScgeT0nLTI1LjYxNDk4OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yOC4xOTE5MzMnIHk9Jy0yNS42MTQ5ODgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTUuMzA3MjA3JyB5PSctMjUuNjE0OTg4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTcuNTc2MzcxJyB5PSctMjUuNjE0OTg4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIuNDIyNDgnIHk9Jy0yNS42MTQ5ODgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScyLjczMTQxMScgeT0nLTI1LjYxNDk4OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzcuODg1MzAxJyB5PSctMjUuNjE0OTg4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nMTAuNDYyMjQ3JyB5PSctMjUuNjE0OTg4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY2Ljg0NjExNCcgeT0nLTIzLjAzODA0MycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01My45NjEzODcnIHk9Jy0yMy4wMzgwNDMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDguODA3NDk2JyB5PSctMjMuMDM4MDQzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQxLjA3NjY2JyB5PSctMjMuMDM4MDQzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTI4LjE5MTkzMycgeT0nLTIzLjAzODA0MycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yNS42MTQ5ODgnIHk9Jy0yMy4wMzgwNDMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjAuNDYxMDk3JyB5PSctMjMuMDM4MDQzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTE3Ljg4NDE1MicgeT0nLTIzLjAzODA0MycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xMi43MzAyNjEnIHk9Jy0yMy4wMzgwNDMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNC45OTk0MjUnIHk9Jy0yMy4wMzgwNDMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScuMTU0NDY1JyB5PSctMjMuMDM4MDQzJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nMi43MzE0MTEnIHk9Jy0yMy4wMzgwNDMnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSctMjAuNDYxMDk3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY5LjQyMzA1OScgeT0nLTIwLjQ2MTA5NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02Ni44NDYxMTQnIHk9Jy0yMC40NjEwOTcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTYuNTM4MzMyJyB5PSctMjAuNDYxMDk3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQ2LjIzMDU1MScgeT0nLTIwLjQ2MTA5NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zOC40OTk3MTUnIHk9Jy0yMC40NjEwOTcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzUuOTIyNzY5JyB5PSctMjAuNDYxMDk3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTMwLjc2ODg3OScgeT0nLTIwLjQ2MTA5NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yMy4wMzgwNDMnIHk9Jy0yMC40NjEwOTcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTcuODg0MTUyJyB5PSctMjAuNDYxMDk3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTEwLjE1MzMxNicgeT0nLTIwLjQ2MTA5NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy03LjU3NjM3MScgeT0nLTIwLjQ2MTA5NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzIuNzMxNDExJyB5PSctMjAuNDYxMDk3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nNy44ODUzMDEnIHk9Jy0yMC40NjEwOTcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjkuNDIzMDU5JyB5PSctMTcuODg0MTUyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY2Ljg0NjExNCcgeT0nLTE3Ljg4NDE1MicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02NC4yNjkxNjgnIHk9Jy0xNy44ODQxNTInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTkuMTE1Mjc4JyB5PSctMTcuODg0MTUyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTUzLjk2MTM4NycgeT0nLTE3Ljg4NDE1MicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00Ni4yMzA1NTEnIHk9Jy0xNy44ODQxNTInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDMuNjUzNjA1JyB5PSctMTcuODg0MTUyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTM4LjQ5OTcxNScgeT0nLTE3Ljg4NDE1MicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zMC43Njg4NzknIHk9Jy0xNy44ODQxNTInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjguMTkxOTMzJyB5PSctMTcuODg0MTUyJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTI1LjYxNDk4OCcgeT0nLTE3Ljg4NDE1MicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xMC4xNTMzMTYnIHk9Jy0xNy44ODQxNTInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNy41NzYzNzEnIHk9Jy0xNy44ODQxNTInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNC45OTk0MjUnIHk9Jy0xNy44ODQxNTInIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSc1LjMwODM1NicgeT0nLTE3Ljg4NDE1MicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzEwLjQ2MjI0NycgeT0nLTE3Ljg4NDE1MicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy0xNS4zMDcyMDcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjkuNDIzMDU5JyB5PSctMTUuMzA3MjA3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTYxLjY5MjIyMycgeT0nLTE1LjMwNzIwNycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01Ni41MzgzMzInIHk9Jy0xNS4zMDcyMDcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTMuOTYxMzg3JyB5PSctMTUuMzA3MjA3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQ4LjgwNzQ5NicgeT0nLTE1LjMwNzIwNycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zNS45MjI3NjknIHk9Jy0xNS4zMDcyMDcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjUuNjE0OTg4JyB5PSctMTUuMzA3MjA3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIzLjAzODA0MycgeT0nLTE1LjMwNzIwNycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yMC40NjEwOTcnIHk9Jy0xNS4zMDcyMDcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTcuODg0MTUyJyB5PSctMTUuMzA3MjA3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTE1LjMwNzIwNycgeT0nLTE1LjMwNzIwNycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xMC4xNTMzMTYnIHk9Jy0xNS4zMDcyMDcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMi40MjI0OCcgeT0nLTE1LjMwNzIwNycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzIuNzMxNDExJyB5PSctMTUuMzA3MjA3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nMTAuNDYyMjQ3JyB5PSctMTUuMzA3MjA3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY5LjQyMzA1OScgeT0nLTEyLjczMDI2MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02Ni44NDYxMTQnIHk9Jy0xMi43MzAyNjEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjQuMjY5MTY4JyB5PSctMTIuNzMwMjYxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTU5LjExNTI3OCcgeT0nLTEyLjczMDI2MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00OC44MDc0OTYnIHk9Jy0xMi43MzAyNjEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzguNDk5NzE1JyB5PSctMTIuNzMwMjYxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTMzLjM0NTgyNCcgeT0nLTEyLjczMDI2MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zMC43Njg4NzknIHk9Jy0xMi43MzAyNjEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjAuNDYxMDk3JyB5PSctMTIuNzMwMjYxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTE3Ljg4NDE1MicgeT0nLTEyLjczMDI2MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xMi43MzAyNjEnIHk9Jy0xMi43MzAyNjEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNC45OTk0MjUnIHk9Jy0xMi43MzAyNjEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScuMTU0NDY1JyB5PSctMTIuNzMwMjYxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nMi43MzE0MTEnIHk9Jy0xMi43MzAyNjEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSc3Ljg4NTMwMScgeT0nLTEyLjczMDI2MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzEwLjQ2MjI0NycgeT0nLTEyLjczMDI2MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy0xMC4xNTMzMTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjQuMjY5MTY4JyB5PSctMTAuMTUzMzE2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTYxLjY5MjIyMycgeT0nLTEwLjE1MzMxNicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01Ni41MzgzMzInIHk9Jy0xMC4xNTMzMTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDYuMjMwNTUxJyB5PSctMTAuMTUzMzE2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQxLjA3NjY2JyB5PSctMTAuMTUzMzE2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTM4LjQ5OTcxNScgeT0nLTEwLjE1MzMxNicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zMC43Njg4NzknIHk9Jy0xMC4xNTMzMTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjguMTkxOTMzJyB5PSctMTAuMTUzMzE2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIwLjQ2MTA5NycgeT0nLTEwLjE1MzMxNicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xNy44ODQxNTInIHk9Jy0xMC4xNTMzMTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTAuMTUzMzE2JyB5PSctMTAuMTUzMzE2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTcuNTc2MzcxJyB5PSctMTAuMTUzMzE2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQuOTk5NDI1JyB5PSctMTAuMTUzMzE2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIuNDIyNDgnIHk9Jy0xMC4xNTMzMTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScuMTU0NDY1JyB5PSctMTAuMTUzMzE2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nMi43MzE0MTEnIHk9Jy0xMC4xNTMzMTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTEuMzg0NDQyJyB5PSctNy41NzYzNzEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDguODA3NDk2JyB5PSctNy41NzYzNzEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDMuNjUzNjA1JyB5PSctNy41NzYzNzEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDEuMDc2NjYnIHk9Jy03LjU3NjM3MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yMy4wMzgwNDMnIHk9Jy03LjU3NjM3MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yMC40NjEwOTcnIHk9Jy03LjU3NjM3MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xNy44ODQxNTInIHk9Jy03LjU3NjM3MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xNS4zMDcyMDcnIHk9Jy03LjU3NjM3MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xMi43MzAyNjEnIHk9Jy03LjU3NjM3MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xMC4xNTMzMTYnIHk9Jy03LjU3NjM3MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy4xNTQ0NjUnIHk9Jy03LjU3NjM3MScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzIuNzMxNDExJyB5PSctNy41NzYzNzEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSc1LjMwODM1NicgeT0nLTcuNTc2MzcxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nMTAuNDYyMjQ3JyB5PSctNy41NzYzNzEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSctNC45OTk0MjUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjkuNDIzMDU5JyB5PSctNC45OTk0MjUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjYuODQ2MTE0JyB5PSctNC45OTk0MjUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjQuMjY5MTY4JyB5PSctNC45OTk0MjUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjEuNjkyMjIzJyB5PSctNC45OTk0MjUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTkuMTE1Mjc4JyB5PSctNC45OTk0MjUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTYuNTM4MzMyJyB5PSctNC45OTk0MjUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTEuMzg0NDQyJyB5PSctNC45OTk0MjUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDEuMDc2NjYnIHk9Jy00Ljk5OTQyNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zNS45MjI3NjknIHk9Jy00Ljk5OTQyNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yOC4xOTE5MzMnIHk9Jy00Ljk5OTQyNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yNS42MTQ5ODgnIHk9Jy00Ljk5OTQyNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yMC40NjEwOTcnIHk9Jy00Ljk5OTQyNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xNy44ODQxNTInIHk9Jy00Ljk5OTQyNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xMC4xNTMzMTYnIHk9Jy00Ljk5OTQyNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00Ljk5OTQyNScgeT0nLTQuOTk5NDI1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLjE1NDQ2NScgeT0nLTQuOTk5NDI1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nMi43MzE0MTEnIHk9Jy00Ljk5OTQyNScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzcuODg1MzAxJyB5PSctNC45OTk0MjUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSctMi40MjI0OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01Ni41MzgzMzInIHk9Jy0yLjQyMjQ4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQxLjA3NjY2JyB5PSctMi40MjI0OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zOC40OTk3MTUnIHk9Jy0yLjQyMjQ4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTM1LjkyMjc2OScgeT0nLTIuNDIyNDgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzMuMzQ1ODI0JyB5PSctMi40MjI0OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zMC43Njg4NzknIHk9Jy0yLjQyMjQ4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTI4LjE5MTkzMycgeT0nLTIuNDIyNDgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjUuNjE0OTg4JyB5PSctMi40MjI0OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yMy4wMzgwNDMnIHk9Jy0yLjQyMjQ4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTE3Ljg4NDE1MicgeT0nLTIuNDIyNDgnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTAuMTUzMzE2JyB5PSctMi40MjI0OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy4xNTQ0NjUnIHk9Jy0yLjQyMjQ4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nNy44ODUzMDEnIHk9Jy0yLjQyMjQ4JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nMTAuNDYyMjQ3JyB5PSctMi40MjI0OCcgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy4xNTQ0NjUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjYuODQ2MTE0JyB5PScuMTU0NDY1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY0LjI2OTE2OCcgeT0nLjE1NDQ2NScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02MS42OTIyMjMnIHk9Jy4xNTQ0NjUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTYuNTM4MzMyJyB5PScuMTU0NDY1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQ2LjIzMDU1MScgeT0nLjE1NDQ2NScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00My42NTM2MDUnIHk9Jy4xNTQ0NjUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMzguNDk5NzE1JyB5PScuMTU0NDY1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTM1LjkyMjc2OScgeT0nLjE1NDQ2NScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yOC4xOTE5MzMnIHk9Jy4xNTQ0NjUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjMuMDM4MDQzJyB5PScuMTU0NDY1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIwLjQ2MTA5NycgeT0nLjE1NDQ2NScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xNy44ODQxNTInIHk9Jy4xNTQ0NjUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTAuMTUzMzE2JyB5PScuMTU0NDY1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTcuNTc2MzcxJyB5PScuMTU0NDY1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQuOTk5NDI1JyB5PScuMTU0NDY1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIuNDIyNDgnIHk9Jy4xNTQ0NjUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScuMTU0NDY1JyB5PScuMTU0NDY1JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nMi43MzE0MTEnIHk9Jy4xNTQ0NjUnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSc3Ljg4NTMwMScgeT0nLjE1NDQ2NScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzEwLjQ2MjI0NycgeT0nLjE1NDQ2NScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9JzIuNzMxNDExJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY2Ljg0NjExNCcgeT0nMi43MzE0MTEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjQuMjY5MTY4JyB5PScyLjczMTQxMScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02MS42OTIyMjMnIHk9JzIuNzMxNDExJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTU2LjUzODMzMicgeT0nMi43MzE0MTEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTEuMzg0NDQyJyB5PScyLjczMTQxMScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zNS45MjI3NjknIHk9JzIuNzMxNDExJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTMwLjc2ODg3OScgeT0nMi43MzE0MTEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjguMTkxOTMzJyB5PScyLjczMTQxMScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xMi43MzAyNjEnIHk9JzIuNzMxNDExJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQuOTk5NDI1JyB5PScyLjczMTQxMScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yLjQyMjQ4JyB5PScyLjczMTQxMScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy4xNTQ0NjUnIHk9JzIuNzMxNDExJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nNy44ODUzMDEnIHk9JzIuNzMxNDExJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nMTAuNDYyMjQ3JyB5PScyLjczMTQxMScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9JzUuMzA4MzU2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTY2Ljg0NjExNCcgeT0nNS4zMDgzNTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNjQuMjY5MTY4JyB5PSc1LjMwODM1NicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02MS42OTIyMjMnIHk9JzUuMzA4MzU2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTU2LjUzODMzMicgeT0nNS4zMDgzNTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDguODA3NDk2JyB5PSc1LjMwODM1NicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zOC40OTk3MTUnIHk9JzUuMzA4MzU2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTI4LjE5MTkzMycgeT0nNS4zMDgzNTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjAuNDYxMDk3JyB5PSc1LjMwODM1NicgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xNy44ODQxNTInIHk9JzUuMzA4MzU2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTEwLjE1MzMxNicgeT0nNS4zMDgzNTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNy41NzYzNzEnIHk9JzUuMzA4MzU2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLjE1NDQ2NScgeT0nNS4zMDgzNTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScyLjczMTQxMScgeT0nNS4zMDgzNTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSc3Ljg4NTMwMScgeT0nNS4zMDgzNTYnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScxMC40NjIyNDcnIHk9JzUuMzA4MzU2JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nNy44ODUzMDEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNTYuNTM4MzMyJyB5PSc3Ljg4NTMwMScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01MS4zODQ0NDInIHk9JzcuODg1MzAxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTQ4LjgwNzQ5NicgeT0nNy44ODUzMDEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctNDMuNjUzNjA1JyB5PSc3Ljg4NTMwMScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0zOC40OTk3MTUnIHk9JzcuODg1MzAxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTMzLjM0NTgyNCcgeT0nNy44ODUzMDEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMjguMTkxOTMzJyB5PSc3Ljg4NTMwMScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0yNS42MTQ5ODgnIHk9JzcuODg1MzAxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIwLjQ2MTA5NycgeT0nNy44ODUzMDEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMTcuODg0MTUyJyB5PSc3Ljg4NTMwMScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy0xMi43MzAyNjEnIHk9JzcuODg1MzAxJyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTEwLjE1MzMxNicgeT0nNy44ODUzMDEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSctMi40MjI0OCcgeT0nNy44ODUzMDEnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PScuMTU0NDY1JyB5PSc3Ljg4NTMwMScgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9JzEwLjQ2MjI0NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02OS40MjMwNTknIHk9JzEwLjQ2MjI0NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02Ni44NDYxMTQnIHk9JzEwLjQ2MjI0NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02NC4yNjkxNjgnIHk9JzEwLjQ2MjI0NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy02MS42OTIyMjMnIHk9JzEwLjQ2MjI0NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01OS4xMTUyNzgnIHk9JzEwLjQ2MjI0NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01Ni41MzgzMzInIHk9JzEwLjQ2MjI0NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy01MS4zODQ0NDInIHk9JzEwLjQ2MjI0NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00My42NTM2MDUnIHk9JzEwLjQ2MjI0NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9Jy00MS4wNzY2NicgeT0nMTAuNDYyMjQ3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTM1LjkyMjc2OScgeT0nMTAuNDYyMjQ3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTMzLjM0NTgyNCcgeT0nMTAuNDYyMjQ3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTMwLjc2ODg3OScgeT0nMTAuNDYyMjQ3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTI1LjYxNDk4OCcgeT0nMTAuNDYyMjQ3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIzLjAzODA0MycgeT0nMTAuNDYyMjQ3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTE3Ljg4NDE1MicgeT0nMTAuNDYyMjQ3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTEwLjE1MzMxNicgeT0nMTAuNDYyMjQ3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPHJlY3QgeD0nLTIuNDIyNDgnIHk9JzEwLjQ2MjI0NycgaGVpZ2h0PScyLjU3Njk0NScgd2lkdGg9JzIuNTc2OTQ1Jy8+CjxyZWN0IHg9JzIuNzMxNDExJyB5PScxMC40NjIyNDcnIGhlaWdodD0nMi41NzY5NDUnIHdpZHRoPScyLjU3Njk0NScvPgo8cmVjdCB4PSc3Ljg4NTMwMScgeT0nMTAuNDYyMjQ3JyBoZWlnaHQ9JzIuNTc2OTQ1JyB3aWR0aD0nMi41NzY5NDUnLz4KPC9nPgo8L3N2Zz4=")} + @top-center{content:" TITLE VER. DATETIME \A \A GPIO, zbocza i quiet-window debounce 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 13/13 " counter(page) "/" counter(pages) " \A SUBJ. PROG. CORE SCOPE LEVEL POS. GITEA UUID 72e2cbba-4658-5de2-a0dc-8b600ee3f7b0\A CARD UUID 29e6021a-d033-5fbe-a5fc-ec03442ac68a AUTHOR M. Pabiszczak\A Inf. — — — — — \A \A GITEA https://zsl-gitea.mpabi.pl/edu-inf/lab-rv32i-c-gpio-edges-debounce \A \A HTML https://dce7fb9d-7b2f-5d49-96a2-3a30d3070b84.mpabi.pl/29e6021a-d033-5fbe-a5fc-ec03442ac68a ";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,PHN2ZyBjbGFzcz0idGl0bGUtcXIiIHJvbGU9ImltZyIgYXJpYS1sYWJlbD0iS29kIFFSOiBodHRwczovL2RjZTdmYjlkLTdiMmYtNWQ0OS05NmEyLTNhMzBkMzA3MGI4NC5tcGFiaS5wbC8yOWU2MDIxYS1kMDMzLTVmYmUtYTVmYy1lYzAzNDQyYWM2OGEiIHZlcnNpb249JzEuMScgeG1sbnM9J2h0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnJyB4bWxuczp4bGluaz0naHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluaycgd2lkdGg9Jzg1LjAzOTIyN3B0JyBoZWlnaHQ9Jzg1LjAzOTIyN3B0JyB2aWV3Qm94PSctNzIuMDAwMDA0IC03Mi4wMDAwMDQgODUuMDM5MjI3IDg1LjAzOTIyNyc+CjxnIGlkPSdwYWdlMSc+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy03Mi4wMDAwMDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjkuNzAxNjQ3JyB5PSctNzIuMDAwMDA0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY3LjQwMzI4OScgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02NS4xMDQ5MzInIHk9Jy03Mi4wMDAwMDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjIuODA2NTc0JyB5PSctNzIuMDAwMDA0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTYwLjUwODIxNycgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01OC4yMDk4NTknIHk9Jy03Mi4wMDAwMDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDkuMDE2NDI5JyB5PSctNzIuMDAwMDA0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ0LjQxOTcxNScgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zNS4yMjYyODUnIHk9Jy03Mi4wMDAwMDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjguMzMxMjEyJyB5PSctNzIuMDAwMDA0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE5LjEzNzc4MicgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xNi44Mzk0MjUnIHk9Jy03Mi4wMDAwMDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTIuMjQyNzEnIHk9Jy03Mi4wMDAwMDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMy4wNDkyOCcgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0uNzUwOTIyJyB5PSctNzIuMDAwMDA0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMS41NDc0MzUnIHk9Jy03Mi4wMDAwMDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSczLjg0NTc5MycgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzYuMTQ0MTUnIHk9Jy03Mi4wMDAwMDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSc4LjQ0MjUwNycgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEwLjc0MDg2NScgeT0nLTcyLjAwMDAwNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy02OS43MDE2NDcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTguMjA5ODU5JyB5PSctNjkuNzAxNjQ3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUzLjYxMzE0NCcgeT0nLTY5LjcwMTY0NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00OS4wMTY0MjknIHk9Jy02OS43MDE2NDcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDIuMTIxMzU3JyB5PSctNjkuNzAxNjQ3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM3LjUyNDY0MicgeT0nLTY5LjcwMTY0NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zNS4yMjYyODUnIHk9Jy02OS43MDE2NDcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjYuMDMyODU1JyB5PSctNjkuNzAxNjQ3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTIxLjQzNjE0JyB5PSctNjkuNzAxNjQ3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE0LjU0MTA2NycgeT0nLTY5LjcwMTY0NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy05Ljk0NDM1MicgeT0nLTY5LjcwMTY0NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03LjY0NTk5NScgeT0nLTY5LjcwMTY0NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zLjA0OTI4JyB5PSctNjkuNzAxNjQ3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMTAuNzQwODY1JyB5PSctNjkuNzAxNjQ3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nLTY3LjQwMzI4OScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02Ny40MDMyODknIHk9Jy02Ny40MDMyODknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjUuMTA0OTMyJyB5PSctNjcuNDAzMjg5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTYyLjgwNjU3NCcgeT0nLTY3LjQwMzI4OScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01OC4yMDk4NTknIHk9Jy02Ny40MDMyODknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDQuNDE5NzE1JyB5PSctNjcuNDAzMjg5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM5LjgyMycgeT0nLTY3LjQwMzI4OScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zNy41MjQ2NDInIHk9Jy02Ny40MDMyODknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjYuMDMyODU1JyB5PSctNjcuNDAzMjg5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTIzLjczNDQ5NycgeT0nLTY3LjQwMzI4OScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xNi44Mzk0MjUnIHk9Jy02Ny40MDMyODknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTIuMjQyNzEnIHk9Jy02Ny40MDMyODknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctOS45NDQzNTInIHk9Jy02Ny40MDMyODknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNy42NDU5OTUnIHk9Jy02Ny40MDMyODknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMy4wNDkyOCcgeT0nLTY3LjQwMzI4OScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEuNTQ3NDM1JyB5PSctNjcuNDAzMjg5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMy44NDU3OTMnIHk9Jy02Ny40MDMyODknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSc2LjE0NDE1JyB5PSctNjcuNDAzMjg5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMTAuNzQwODY1JyB5PSctNjcuNDAzMjg5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nLTY1LjEwNDkzMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02Ny40MDMyODknIHk9Jy02NS4xMDQ5MzInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjUuMTA0OTMyJyB5PSctNjUuMTA0OTMyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTYyLjgwNjU3NCcgeT0nLTY1LjEwNDkzMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01OC4yMDk4NTknIHk9Jy02NS4xMDQ5MzInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTMuNjEzMTQ0JyB5PSctNjUuMTA0OTMyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUxLjMxNDc4NycgeT0nLTY1LjEwNDkzMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00OS4wMTY0MjknIHk9Jy02NS4xMDQ5MzInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDQuNDE5NzE1JyB5PSctNjUuMTA0OTMyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQyLjEyMTM1NycgeT0nLTY1LjEwNDkzMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zNy41MjQ2NDInIHk9Jy02NS4xMDQ5MzInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzIuOTI3OTI3JyB5PSctNjUuMTA0OTMyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTI4LjMzMTIxMicgeT0nLTY1LjEwNDkzMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yMS40MzYxNCcgeT0nLTY1LjEwNDkzMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xOS4xMzc3ODInIHk9Jy02NS4xMDQ5MzInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTYuODM5NDI1JyB5PSctNjUuMTA0OTMyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE0LjU0MTA2NycgeT0nLTY1LjEwNDkzMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xMi4yNDI3MScgeT0nLTY1LjEwNDkzMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zLjA0OTI4JyB5PSctNjUuMTA0OTMyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMS41NDc0MzUnIHk9Jy02NS4xMDQ5MzInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSczLjg0NTc5MycgeT0nLTY1LjEwNDkzMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzYuMTQ0MTUnIHk9Jy02NS4xMDQ5MzInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PScxMC43NDA4NjUnIHk9Jy02NS4xMDQ5MzInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSctNjIuODA2NTc0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY3LjQwMzI4OScgeT0nLTYyLjgwNjU3NCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02NS4xMDQ5MzInIHk9Jy02Mi44MDY1NzQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjIuODA2NTc0JyB5PSctNjIuODA2NTc0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTU4LjIwOTg1OScgeT0nLTYyLjgwNjU3NCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01MS4zMTQ3ODcnIHk9Jy02Mi44MDY1NzQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzkuODIzJyB5PSctNjIuODA2NTc0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM1LjIyNjI4NScgeT0nLTYyLjgwNjU3NCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zMC42Mjk1NycgeT0nLTYyLjgwNjU3NCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yOC4zMzEyMTInIHk9Jy02Mi44MDY1NzQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjMuNzM0NDk3JyB5PSctNjIuODA2NTc0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTIxLjQzNjE0JyB5PSctNjIuODA2NTc0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE5LjEzNzc4MicgeT0nLTYyLjgwNjU3NCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zLjA0OTI4JyB5PSctNjIuODA2NTc0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMS41NDc0MzUnIHk9Jy02Mi44MDY1NzQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSczLjg0NTc5MycgeT0nLTYyLjgwNjU3NCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzYuMTQ0MTUnIHk9Jy02Mi44MDY1NzQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PScxMC43NDA4NjUnIHk9Jy02Mi44MDY1NzQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSctNjAuNTA4MjE3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTU4LjIwOTg1OScgeT0nLTYwLjUwODIxNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01My42MTMxNDQnIHk9Jy02MC41MDgyMTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTEuMzE0Nzg3JyB5PSctNjAuNTA4MjE3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ2LjcxODA3MicgeT0nLTYwLjUwODIxNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00NC40MTk3MTUnIHk9Jy02MC41MDgyMTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDIuMTIxMzU3JyB5PSctNjAuNTA4MjE3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM5LjgyMycgeT0nLTYwLjUwODIxNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zNy41MjQ2NDInIHk9Jy02MC41MDgyMTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzIuOTI3OTI3JyB5PSctNjAuNTA4MjE3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTI2LjAzMjg1NScgeT0nLTYwLjUwODIxNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yMy43MzQ0OTcnIHk9Jy02MC41MDgyMTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTYuODM5NDI1JyB5PSctNjAuNTA4MjE3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTkuOTQ0MzUyJyB5PSctNjAuNTA4MjE3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMuMDQ5MjgnIHk9Jy02MC41MDgyMTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PScxMC43NDA4NjUnIHk9Jy02MC41MDgyMTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSctNTguMjA5ODU5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY5LjcwMTY0NycgeT0nLTU4LjIwOTg1OScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02Ny40MDMyODknIHk9Jy01OC4yMDk4NTknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjUuMTA0OTMyJyB5PSctNTguMjA5ODU5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTYyLjgwNjU3NCcgeT0nLTU4LjIwOTg1OScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02MC41MDgyMTcnIHk9Jy01OC4yMDk4NTknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTguMjA5ODU5JyB5PSctNTguMjA5ODU5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUzLjYxMzE0NCcgeT0nLTU4LjIwOTg1OScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00OS4wMTY0MjknIHk9Jy01OC4yMDk4NTknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDQuNDE5NzE1JyB5PSctNTguMjA5ODU5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM5LjgyMycgeT0nLTU4LjIwOTg1OScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zNS4yMjYyODUnIHk9Jy01OC4yMDk4NTknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzAuNjI5NTcnIHk9Jy01OC4yMDk4NTknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjYuMDMyODU1JyB5PSctNTguMjA5ODU5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTIxLjQzNjE0JyB5PSctNTguMjA5ODU5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE2LjgzOTQyNScgeT0nLTU4LjIwOTg1OScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xMi4yNDI3MScgeT0nLTU4LjIwOTg1OScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03LjY0NTk5NScgeT0nLTU4LjIwOTg1OScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zLjA0OTI4JyB5PSctNTguMjA5ODU5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLS43NTA5MjInIHk9Jy01OC4yMDk4NTknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PScxLjU0NzQzNScgeT0nLTU4LjIwOTg1OScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzMuODQ1NzkzJyB5PSctNTguMjA5ODU5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nNi4xNDQxNScgeT0nLTU4LjIwOTg1OScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzguNDQyNTA3JyB5PSctNTguMjA5ODU5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMTAuNzQwODY1JyB5PSctNTguMjA5ODU5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUxLjMxNDc4NycgeT0nLTU1LjkxMTUwMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00OS4wMTY0MjknIHk9Jy01NS45MTE1MDInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDYuNzE4MDcyJyB5PSctNTUuOTExNTAyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMwLjYyOTU3JyB5PSctNTUuOTExNTAyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTI4LjMzMTIxMicgeT0nLTU1LjkxMTUwMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yMy43MzQ0OTcnIHk9Jy01NS45MTE1MDInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTkuMTM3NzgyJyB5PSctNTUuOTExNTAyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE2LjgzOTQyNScgeT0nLTU1LjkxMTUwMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xMi4yNDI3MScgeT0nLTU1LjkxMTUwMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy01My42MTMxNDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjkuNzAxNjQ3JyB5PSctNTMuNjEzMTQ0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY3LjQwMzI4OScgeT0nLTUzLjYxMzE0NCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02NS4xMDQ5MzInIHk9Jy01My42MTMxNDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjIuODA2NTc0JyB5PSctNTMuNjEzMTQ0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTU4LjIwOTg1OScgeT0nLTUzLjYxMzE0NCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01NS45MTE1MDInIHk9Jy01My42MTMxNDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTMuNjEzMTQ0JyB5PSctNTMuNjEzMTQ0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUxLjMxNDc4NycgeT0nLTUzLjYxMzE0NCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00Ni43MTgwNzInIHk9Jy01My42MTMxNDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDIuMTIxMzU3JyB5PSctNTMuNjEzMTQ0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM3LjUyNDY0MicgeT0nLTUzLjYxMzE0NCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zNS4yMjYyODUnIHk9Jy01My42MTMxNDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzIuOTI3OTI3JyB5PSctNTMuNjEzMTQ0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTI2LjAzMjg1NScgeT0nLTUzLjYxMzE0NCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yMS40MzYxNCcgeT0nLTUzLjYxMzE0NCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xNi44Mzk0MjUnIHk9Jy01My42MTMxNDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTQuNTQxMDY3JyB5PSctNTMuNjEzMTQ0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTkuOTQ0MzUyJyB5PSctNTMuNjEzMTQ0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcuNjQ1OTk1JyB5PSctNTMuNjEzMTQ0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUuMzQ3NjM3JyB5PSctNTMuNjEzMTQ0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLS43NTA5MjInIHk9Jy01My42MTMxNDQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSczLjg0NTc5MycgeT0nLTUzLjYxMzE0NCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzguNDQyNTA3JyB5PSctNTMuNjEzMTQ0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nLTUxLjMxNDc4NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02OS43MDE2NDcnIHk9Jy01MS4zMTQ3ODcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjIuODA2NTc0JyB5PSctNTEuMzE0Nzg3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTYwLjUwODIxNycgeT0nLTUxLjMxNDc4NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01NS45MTE1MDInIHk9Jy01MS4zMTQ3ODcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDkuMDE2NDI5JyB5PSctNTEuMzE0Nzg3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ0LjQxOTcxNScgeT0nLTUxLjMxNDc4NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00Mi4xMjEzNTcnIHk9Jy01MS4zMTQ3ODcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzkuODIzJyB5PSctNTEuMzE0Nzg3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMwLjYyOTU3JyB5PSctNTEuMzE0Nzg3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTI4LjMzMTIxMicgeT0nLTUxLjMxNDc4NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xOS4xMzc3ODInIHk9Jy01MS4zMTQ3ODcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTIuMjQyNzEnIHk9Jy01MS4zMTQ3ODcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctLjc1MDkyMicgeT0nLTUxLjMxNDc4NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzMuODQ1NzkzJyB5PSctNTEuMzE0Nzg3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nNi4xNDQxNScgeT0nLTUxLjMxNDc4NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzguNDQyNTA3JyB5PSctNTEuMzE0Nzg3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY5LjcwMTY0NycgeT0nLTQ5LjAxNjQyOScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02NS4xMDQ5MzInIHk9Jy00OS4wMTY0MjknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjIuODA2NTc0JyB5PSctNDkuMDE2NDI5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTYwLjUwODIxNycgeT0nLTQ5LjAxNjQyOScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01OC4yMDk4NTknIHk9Jy00OS4wMTY0MjknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTEuMzE0Nzg3JyB5PSctNDkuMDE2NDI5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ5LjAxNjQyOScgeT0nLTQ5LjAxNjQyOScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zNy41MjQ2NDInIHk9Jy00OS4wMTY0MjknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzIuOTI3OTI3JyB5PSctNDkuMDE2NDI5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMwLjYyOTU3JyB5PSctNDkuMDE2NDI5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTI2LjAzMjg1NScgeT0nLTQ5LjAxNjQyOScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yMy43MzQ0OTcnIHk9Jy00OS4wMTY0MjknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjEuNDM2MTQnIHk9Jy00OS4wMTY0MjknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTQuNTQxMDY3JyB5PSctNDkuMDE2NDI5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTkuOTQ0MzUyJyB5PSctNDkuMDE2NDI5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcuNjQ1OTk1JyB5PSctNDkuMDE2NDI5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMuMDQ5MjgnIHk9Jy00OS4wMTY0MjknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctLjc1MDkyMicgeT0nLTQ5LjAxNjQyOScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEuNTQ3NDM1JyB5PSctNDkuMDE2NDI5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMy44NDU3OTMnIHk9Jy00OS4wMTY0MjknIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSc2LjE0NDE1JyB5PSctNDkuMDE2NDI5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMTAuNzQwODY1JyB5PSctNDkuMDE2NDI5JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nLTQ2LjcxODA3MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02Ny40MDMyODknIHk9Jy00Ni43MTgwNzInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjUuMTA0OTMyJyB5PSctNDYuNzE4MDcyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTYwLjUwODIxNycgeT0nLTQ2LjcxODA3MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01MS4zMTQ3ODcnIHk9Jy00Ni43MTgwNzInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDkuMDE2NDI5JyB5PSctNDYuNzE4MDcyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ0LjQxOTcxNScgeT0nLTQ2LjcxODA3MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zNy41MjQ2NDInIHk9Jy00Ni43MTgwNzInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzUuMjI2Mjg1JyB5PSctNDYuNzE4MDcyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMwLjYyOTU3JyB5PSctNDYuNzE4MDcyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTI4LjMzMTIxMicgeT0nLTQ2LjcxODA3MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yMy43MzQ0OTcnIHk9Jy00Ni43MTgwNzInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTYuODM5NDI1JyB5PSctNDYuNzE4MDcyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTEyLjI0MjcxJyB5PSctNDYuNzE4MDcyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTkuOTQ0MzUyJyB5PSctNDYuNzE4MDcyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLS43NTA5MjInIHk9Jy00Ni43MTgwNzInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSczLjg0NTc5MycgeT0nLTQ2LjcxODA3MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzguNDQyNTA3JyB5PSctNDYuNzE4MDcyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY3LjQwMzI4OScgeT0nLTQ0LjQxOTcxNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01OC4yMDk4NTknIHk9Jy00NC40MTk3MTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDkuMDE2NDI5JyB5PSctNDQuNDE5NzE1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ0LjQxOTcxNScgeT0nLTQ0LjQxOTcxNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00Mi4xMjEzNTcnIHk9Jy00NC40MTk3MTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzkuODIzJyB5PSctNDQuNDE5NzE1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM3LjUyNDY0MicgeT0nLTQ0LjQxOTcxNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zNS4yMjYyODUnIHk9Jy00NC40MTk3MTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzIuOTI3OTI3JyB5PSctNDQuNDE5NzE1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTI2LjAzMjg1NScgeT0nLTQ0LjQxOTcxNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xNi44Mzk0MjUnIHk9Jy00NC40MTk3MTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTQuNTQxMDY3JyB5PSctNDQuNDE5NzE1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTkuOTQ0MzUyJyB5PSctNDQuNDE5NzE1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMuMDQ5MjgnIHk9Jy00NC40MTk3MTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctLjc1MDkyMicgeT0nLTQ0LjQxOTcxNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEuNTQ3NDM1JyB5PSctNDQuNDE5NzE1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMy44NDU3OTMnIHk9Jy00NC40MTk3MTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSc2LjE0NDE1JyB5PSctNDQuNDE5NzE1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMTAuNzQwODY1JyB5PSctNDQuNDE5NzE1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nLTQyLjEyMTM1NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01NS45MTE1MDInIHk9Jy00Mi4xMjEzNTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDkuMDE2NDI5JyB5PSctNDIuMTIxMzU3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMwLjYyOTU3JyB5PSctNDIuMTIxMzU3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTI4LjMzMTIxMicgeT0nLTQyLjEyMTM1NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xOS4xMzc3ODInIHk9Jy00Mi4xMjEzNTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTIuMjQyNzEnIHk9Jy00Mi4xMjEzNTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNy42NDU5OTUnIHk9Jy00Mi4xMjEzNTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNS4zNDc2MzcnIHk9Jy00Mi4xMjEzNTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSc2LjE0NDE1JyB5PSctNDIuMTIxMzU3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nOC40NDI1MDcnIHk9Jy00Mi4xMjEzNTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjIuODA2NTc0JyB5PSctMzkuODIzJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTYwLjUwODIxNycgeT0nLTM5LjgyMycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01OC4yMDk4NTknIHk9Jy0zOS44MjMnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDYuNzE4MDcyJyB5PSctMzkuODIzJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ0LjQxOTcxNScgeT0nLTM5LjgyMycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zNy41MjQ2NDInIHk9Jy0zOS44MjMnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjEuNDM2MTQnIHk9Jy0zOS44MjMnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTYuODM5NDI1JyB5PSctMzkuODIzJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTkuOTQ0MzUyJyB5PSctMzkuODIzJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMuMDQ5MjgnIHk9Jy0zOS44MjMnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctLjc1MDkyMicgeT0nLTM5LjgyMycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzYuMTQ0MTUnIHk9Jy0zOS44MjMnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSc4LjQ0MjUwNycgeT0nLTM5LjgyMycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEwLjc0MDg2NScgeT0nLTM5LjgyMycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy0zNy41MjQ2NDInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjkuNzAxNjQ3JyB5PSctMzcuNTI0NjQyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY3LjQwMzI4OScgeT0nLTM3LjUyNDY0MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01NS45MTE1MDInIHk9Jy0zNy41MjQ2NDInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTMuNjEzMTQ0JyB5PSctMzcuNTI0NjQyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ5LjAxNjQyOScgeT0nLTM3LjUyNDY0MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00Ni43MTgwNzInIHk9Jy0zNy41MjQ2NDInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzkuODIzJyB5PSctMzcuNTI0NjQyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM3LjUyNDY0MicgeT0nLTM3LjUyNDY0MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zNS4yMjYyODUnIHk9Jy0zNy41MjQ2NDInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjMuNzM0NDk3JyB5PSctMzcuNTI0NjQyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTIxLjQzNjE0JyB5PSctMzcuNTI0NjQyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE2LjgzOTQyNScgeT0nLTM3LjUyNDY0MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03LjY0NTk5NScgeT0nLTM3LjUyNDY0MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0uNzUwOTIyJyB5PSctMzcuNTI0NjQyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMS41NDc0MzUnIHk9Jy0zNy41MjQ2NDInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSczLjg0NTc5MycgeT0nLTM3LjUyNDY0MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEwLjc0MDg2NScgeT0nLTM3LjUyNDY0MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy0zNS4yMjYyODUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjcuNDAzMjg5JyB5PSctMzUuMjI2Mjg1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY1LjEwNDkzMicgeT0nLTM1LjIyNjI4NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02Mi44MDY1NzQnIHk9Jy0zNS4yMjYyODUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTguMjA5ODU5JyB5PSctMzUuMjI2Mjg1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUxLjMxNDc4NycgeT0nLTM1LjIyNjI4NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00OS4wMTY0MjknIHk9Jy0zNS4yMjYyODUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDYuNzE4MDcyJyB5PSctMzUuMjI2Mjg1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM3LjUyNDY0MicgeT0nLTM1LjIyNjI4NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zNS4yMjYyODUnIHk9Jy0zNS4yMjYyODUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzIuOTI3OTI3JyB5PSctMzUuMjI2Mjg1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMwLjYyOTU3JyB5PSctMzUuMjI2Mjg1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTI2LjAzMjg1NScgeT0nLTM1LjIyNjI4NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xNC41NDEwNjcnIHk9Jy0zNS4yMjYyODUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTIuMjQyNzEnIHk9Jy0zNS4yMjYyODUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctOS45NDQzNTInIHk9Jy0zNS4yMjYyODUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNy42NDU5OTUnIHk9Jy0zNS4yMjYyODUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNS4zNDc2MzcnIHk9Jy0zNS4yMjYyODUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMy4wNDkyOCcgeT0nLTM1LjIyNjI4NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEuNTQ3NDM1JyB5PSctMzUuMjI2Mjg1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMy44NDU3OTMnIHk9Jy0zNS4yMjYyODUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSc2LjE0NDE1JyB5PSctMzUuMjI2Mjg1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMTAuNzQwODY1JyB5PSctMzUuMjI2Mjg1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTYyLjgwNjU3NCcgeT0nLTMyLjkyNzkyNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01NS45MTE1MDInIHk9Jy0zMi45Mjc5MjcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTMuNjEzMTQ0JyB5PSctMzIuOTI3OTI3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUxLjMxNDc4NycgeT0nLTMyLjkyNzkyNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00OS4wMTY0MjknIHk9Jy0zMi45Mjc5MjcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDQuNDE5NzE1JyB5PSctMzIuOTI3OTI3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQyLjEyMTM1NycgeT0nLTMyLjkyNzkyNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zMi45Mjc5MjcnIHk9Jy0zMi45Mjc5MjcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzAuNjI5NTcnIHk9Jy0zMi45Mjc5MjcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjguMzMxMjEyJyB5PSctMzIuOTI3OTI3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTIzLjczNDQ5NycgeT0nLTMyLjkyNzkyNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yMS40MzYxNCcgeT0nLTMyLjkyNzkyNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xOS4xMzc3ODInIHk9Jy0zMi45Mjc5MjcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSc2LjE0NDE1JyB5PSctMzIuOTI3OTI3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nOC40NDI1MDcnIHk9Jy0zMi45Mjc5MjcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjUuMTA0OTMyJyB5PSctMzAuNjI5NTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjIuODA2NTc0JyB5PSctMzAuNjI5NTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjAuNTA4MjE3JyB5PSctMzAuNjI5NTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTguMjA5ODU5JyB5PSctMzAuNjI5NTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTUuOTExNTAyJyB5PSctMzAuNjI5NTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTMuNjEzMTQ0JyB5PSctMzAuNjI5NTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDIuMTIxMzU3JyB5PSctMzAuNjI5NTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzkuODIzJyB5PSctMzAuNjI5NTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzcuNTI0NjQyJyB5PSctMzAuNjI5NTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzUuMjI2Mjg1JyB5PSctMzAuNjI5NTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTIuMjQyNzEnIHk9Jy0zMC42Mjk1NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy05Ljk0NDM1MicgeT0nLTMwLjYyOTU3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcuNjQ1OTk1JyB5PSctMzAuNjI5NTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNS4zNDc2MzcnIHk9Jy0zMC42Mjk1NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zLjA0OTI4JyB5PSctMzAuNjI5NTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSc2LjE0NDE1JyB5PSctMzAuNjI5NTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSc4LjQ0MjUwNycgeT0nLTMwLjYyOTU3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMTAuNzQwODY1JyB5PSctMzAuNjI5NTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjkuNzAxNjQ3JyB5PSctMjguMzMxMjEyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY3LjQwMzI4OScgeT0nLTI4LjMzMTIxMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01MS4zMTQ3ODcnIHk9Jy0yOC4zMzEyMTInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDQuNDE5NzE1JyB5PSctMjguMzMxMjEyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQyLjEyMTM1NycgeT0nLTI4LjMzMTIxMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yNi4wMzI4NTUnIHk9Jy0yOC4zMzEyMTInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjMuNzM0NDk3JyB5PSctMjguMzMxMjEyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTkuOTQ0MzUyJyB5PSctMjguMzMxMjEyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLS43NTA5MjInIHk9Jy0yOC4zMzEyMTInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PScxMC43NDA4NjUnIHk9Jy0yOC4zMzEyMTInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjkuNzAxNjQ3JyB5PSctMjYuMDMyODU1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTYyLjgwNjU3NCcgeT0nLTI2LjAzMjg1NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01OC4yMDk4NTknIHk9Jy0yNi4wMzI4NTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTUuOTExNTAyJyB5PSctMjYuMDMyODU1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUxLjMxNDc4NycgeT0nLTI2LjAzMjg1NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00NC40MTk3MTUnIHk9Jy0yNi4wMzI4NTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzkuODIzJyB5PSctMjYuMDMyODU1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM3LjUyNDY0MicgeT0nLTI2LjAzMjg1NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zNS4yMjYyODUnIHk9Jy0yNi4wMzI4NTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzIuOTI3OTI3JyB5PSctMjYuMDMyODU1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE5LjEzNzc4MicgeT0nLTI2LjAzMjg1NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xNi44Mzk0MjUnIHk9Jy0yNi4wMzI4NTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTQuNTQxMDY3JyB5PSctMjYuMDMyODU1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcuNjQ1OTk1JyB5PSctMjYuMDMyODU1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMuMDQ5MjgnIHk9Jy0yNi4wMzI4NTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PScxLjU0NzQzNScgeT0nLTI2LjAzMjg1NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzMuODQ1NzkzJyB5PSctMjYuMDMyODU1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nNi4xNDQxNScgeT0nLTI2LjAzMjg1NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzguNDQyNTA3JyB5PSctMjYuMDMyODU1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMTAuNzQwODY1JyB5PSctMjYuMDMyODU1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nLTIzLjczNDQ5NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02OS43MDE2NDcnIHk9Jy0yMy43MzQ0OTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjcuNDAzMjg5JyB5PSctMjMuNzM0NDk3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY1LjEwNDkzMicgeT0nLTIzLjczNDQ5NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02MC41MDgyMTcnIHk9Jy0yMy43MzQ0OTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTMuNjEzMTQ0JyB5PSctMjMuNzM0NDk3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUxLjMxNDc4NycgeT0nLTIzLjczNDQ5NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00OS4wMTY0MjknIHk9Jy0yMy43MzQ0OTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzAuNjI5NTcnIHk9Jy0yMy43MzQ0OTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjguMzMxMjEyJyB5PSctMjMuNzM0NDk3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTI2LjAzMjg1NScgeT0nLTIzLjczNDQ5NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yMS40MzYxNCcgeT0nLTIzLjczNDQ5NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xOS4xMzc3ODInIHk9Jy0yMy43MzQ0OTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTIuMjQyNzEnIHk9Jy0yMy43MzQ0OTcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctLjc1MDkyMicgeT0nLTIzLjczNDQ5NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzguNDQyNTA3JyB5PSctMjMuNzM0NDk3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nLTIxLjQzNjE0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY5LjcwMTY0NycgeT0nLTIxLjQzNjE0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY1LjEwNDkzMicgeT0nLTIxLjQzNjE0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTYyLjgwNjU3NCcgeT0nLTIxLjQzNjE0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTYwLjUwODIxNycgeT0nLTIxLjQzNjE0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTU4LjIwOTg1OScgeT0nLTIxLjQzNjE0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ5LjAxNjQyOScgeT0nLTIxLjQzNjE0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ2LjcxODA3MicgeT0nLTIxLjQzNjE0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ0LjQxOTcxNScgeT0nLTIxLjQzNjE0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM3LjUyNDY0MicgeT0nLTIxLjQzNjE0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMwLjYyOTU3JyB5PSctMjEuNDM2MTQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjYuMDMyODU1JyB5PSctMjEuNDM2MTQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjMuNzM0NDk3JyB5PSctMjEuNDM2MTQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTYuODM5NDI1JyB5PSctMjEuNDM2MTQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTQuNTQxMDY3JyB5PSctMjEuNDM2MTQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctOS45NDQzNTInIHk9Jy0yMS40MzYxNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03LjY0NTk5NScgeT0nLTIxLjQzNjE0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUuMzQ3NjM3JyB5PSctMjEuNDM2MTQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctLjc1MDkyMicgeT0nLTIxLjQzNjE0JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMy44NDU3OTMnIHk9Jy0yMS40MzYxNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzguNDQyNTA3JyB5PSctMjEuNDM2MTQnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PScxMC43NDA4NjUnIHk9Jy0yMS40MzYxNCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02NS4xMDQ5MzInIHk9Jy0xOS4xMzc3ODInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjIuODA2NTc0JyB5PSctMTkuMTM3NzgyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTU1LjkxMTUwMicgeT0nLTE5LjEzNzc4MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01My42MTMxNDQnIHk9Jy0xOS4xMzc3ODInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTEuMzE0Nzg3JyB5PSctMTkuMTM3NzgyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ2LjcxODA3MicgeT0nLTE5LjEzNzc4MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zOS44MjMnIHk9Jy0xOS4xMzc3ODInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzcuNTI0NjQyJyB5PSctMTkuMTM3NzgyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTI2LjAzMjg1NScgeT0nLTE5LjEzNzc4MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yMy43MzQ0OTcnIHk9Jy0xOS4xMzc3ODInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjEuNDM2MTQnIHk9Jy0xOS4xMzc3ODInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTkuMTM3NzgyJyB5PSctMTkuMTM3NzgyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTEyLjI0MjcxJyB5PSctMTkuMTM3NzgyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTkuOTQ0MzUyJyB5PSctMTkuMTM3NzgyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcuNjQ1OTk1JyB5PSctMTkuMTM3NzgyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUuMzQ3NjM3JyB5PSctMTkuMTM3NzgyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMuMDQ5MjgnIHk9Jy0xOS4xMzc3ODInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PScxLjU0NzQzNScgeT0nLTE5LjEzNzc4MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEwLjc0MDg2NScgeT0nLTE5LjEzNzc4MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03Mi4wMDAwMDQnIHk9Jy0xNi44Mzk0MjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjkuNzAxNjQ3JyB5PSctMTYuODM5NDI1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTYyLjgwNjU3NCcgeT0nLTE2LjgzOTQyNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01OC4yMDk4NTknIHk9Jy0xNi44Mzk0MjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTUuOTExNTAyJyB5PSctMTYuODM5NDI1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ5LjAxNjQyOScgeT0nLTE2LjgzOTQyNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00Ni43MTgwNzInIHk9Jy0xNi44Mzk0MjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzcuNTI0NjQyJyB5PSctMTYuODM5NDI1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM1LjIyNjI4NScgeT0nLTE2LjgzOTQyNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zMi45Mjc5MjcnIHk9Jy0xNi44Mzk0MjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzAuNjI5NTcnIHk9Jy0xNi44Mzk0MjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjguMzMxMjEyJyB5PSctMTYuODM5NDI1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTIxLjQzNjE0JyB5PSctMTYuODM5NDI1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE5LjEzNzc4MicgeT0nLTE2LjgzOTQyNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xNi44Mzk0MjUnIHk9Jy0xNi44Mzk0MjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTQuNTQxMDY3JyB5PSctMTYuODM5NDI1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMuMDQ5MjgnIHk9Jy0xNi44Mzk0MjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctLjc1MDkyMicgeT0nLTE2LjgzOTQyNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEuNTQ3NDM1JyB5PSctMTYuODM5NDI1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMy44NDU3OTMnIHk9Jy0xNi44Mzk0MjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSc2LjE0NDE1JyB5PSctMTYuODM5NDI1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nOC40NDI1MDcnIHk9Jy0xNi44Mzk0MjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PScxMC43NDA4NjUnIHk9Jy0xNi44Mzk0MjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSctMTQuNTQxMDY3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY3LjQwMzI4OScgeT0nLTE0LjU0MTA2NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02Mi44MDY1NzQnIHk9Jy0xNC41NDEwNjcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDkuMDE2NDI5JyB5PSctMTQuNTQxMDY3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ0LjQxOTcxNScgeT0nLTE0LjU0MTA2NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00Mi4xMjEzNTcnIHk9Jy0xNC41NDEwNjcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzkuODIzJyB5PSctMTQuNTQxMDY3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTI4LjMzMTIxMicgeT0nLTE0LjU0MTA2NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yMy43MzQ0OTcnIHk9Jy0xNC41NDEwNjcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTkuMTM3NzgyJyB5PSctMTQuNTQxMDY3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE2LjgzOTQyNScgeT0nLTE0LjU0MTA2NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xMi4yNDI3MScgeT0nLTE0LjU0MTA2NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01LjM0NzYzNycgeT0nLTE0LjU0MTA2NycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzMuODQ1NzkzJyB5PSctMTQuNTQxMDY3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nOC40NDI1MDcnIHk9Jy0xNC41NDEwNjcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSctMTIuMjQyNzEnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjcuNDAzMjg5JyB5PSctMTIuMjQyNzEnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjUuMTA0OTMyJyB5PSctMTIuMjQyNzEnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTguMjA5ODU5JyB5PSctMTIuMjQyNzEnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTMuNjEzMTQ0JyB5PSctMTIuMjQyNzEnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTEuMzE0Nzg3JyB5PSctMTIuMjQyNzEnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDIuMTIxMzU3JyB5PSctMTIuMjQyNzEnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzkuODIzJyB5PSctMTIuMjQyNzEnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzcuNTI0NjQyJyB5PSctMTIuMjQyNzEnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzUuMjI2Mjg1JyB5PSctMTIuMjQyNzEnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjYuMDMyODU1JyB5PSctMTIuMjQyNzEnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjMuNzM0NDk3JyB5PSctMTIuMjQyNzEnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjEuNDM2MTQnIHk9Jy0xMi4yNDI3MScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xNi44Mzk0MjUnIHk9Jy0xMi4yNDI3MScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy05Ljk0NDM1MicgeT0nLTEyLjI0MjcxJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcuNjQ1OTk1JyB5PSctMTIuMjQyNzEnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNS4zNDc2MzcnIHk9Jy0xMi4yNDI3MScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zLjA0OTI4JyB5PSctMTIuMjQyNzEnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PScxLjU0NzQzNScgeT0nLTEyLjI0MjcxJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nNi4xNDQxNScgeT0nLTEyLjI0MjcxJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nOC40NDI1MDcnIHk9Jy0xMi4yNDI3MScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEwLjc0MDg2NScgeT0nLTEyLjI0MjcxJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nLTkuOTQ0MzUyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTU1LjkxMTUwMicgeT0nLTkuOTQ0MzUyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUzLjYxMzE0NCcgeT0nLTkuOTQ0MzUyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ5LjAxNjQyOScgeT0nLTkuOTQ0MzUyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ0LjQxOTcxNScgeT0nLTkuOTQ0MzUyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQyLjEyMTM1NycgeT0nLTkuOTQ0MzUyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTIzLjczNDQ5NycgeT0nLTkuOTQ0MzUyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTIxLjQzNjE0JyB5PSctOS45NDQzNTInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctOS45NDQzNTInIHk9Jy05Ljk0NDM1MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01LjM0NzYzNycgeT0nLTkuOTQ0MzUyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMuMDQ5MjgnIHk9Jy05Ljk0NDM1MicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEwLjc0MDg2NScgeT0nLTkuOTQ0MzUyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nLTcuNjQ1OTk1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY3LjQwMzI4OScgeT0nLTcuNjQ1OTk1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTYyLjgwNjU3NCcgeT0nLTcuNjQ1OTk1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTYwLjUwODIxNycgeT0nLTcuNjQ1OTk1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTU4LjIwOTg1OScgeT0nLTcuNjQ1OTk1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTU1LjkxMTUwMicgeT0nLTcuNjQ1OTk1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUzLjYxMzE0NCcgeT0nLTcuNjQ1OTk1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ5LjAxNjQyOScgeT0nLTcuNjQ1OTk1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ0LjQxOTcxNScgeT0nLTcuNjQ1OTk1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM5LjgyMycgeT0nLTcuNjQ1OTk1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM3LjUyNDY0MicgeT0nLTcuNjQ1OTk1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMyLjkyNzkyNycgeT0nLTcuNjQ1OTk1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE0LjU0MTA2NycgeT0nLTcuNjQ1OTk1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcuNjQ1OTk1JyB5PSctNy42NDU5OTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNS4zNDc2MzcnIHk9Jy03LjY0NTk5NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zLjA0OTI4JyB5PSctNy42NDU5OTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctLjc1MDkyMicgeT0nLTcuNjQ1OTk1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMS41NDc0MzUnIHk9Jy03LjY0NTk5NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzMuODQ1NzkzJyB5PSctNy42NDU5OTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSc2LjE0NDE1JyB5PSctNy42NDU5OTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTMuNjEzMTQ0JyB5PSctNS4zNDc2MzcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTEuMzE0Nzg3JyB5PSctNS4zNDc2MzcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzUuMjI2Mjg1JyB5PSctNS4zNDc2MzcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzAuNjI5NTcnIHk9Jy01LjM0NzYzNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yOC4zMzEyMTInIHk9Jy01LjM0NzYzNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yNi4wMzI4NTUnIHk9Jy01LjM0NzYzNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yMy43MzQ0OTcnIHk9Jy01LjM0NzYzNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yMS40MzYxNCcgeT0nLTUuMzQ3NjM3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE5LjEzNzc4MicgeT0nLTUuMzQ3NjM3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE2LjgzOTQyNScgeT0nLTUuMzQ3NjM3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTEyLjI0MjcxJyB5PSctNS4zNDc2MzcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNy42NDU5OTUnIHk9Jy01LjM0NzYzNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEuNTQ3NDM1JyB5PSctNS4zNDc2MzcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSctMy4wNDkyOCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02OS43MDE2NDcnIHk9Jy0zLjA0OTI4JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY3LjQwMzI4OScgeT0nLTMuMDQ5MjgnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjUuMTA0OTMyJyB5PSctMy4wNDkyOCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02Mi44MDY1NzQnIHk9Jy0zLjA0OTI4JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTYwLjUwODIxNycgeT0nLTMuMDQ5MjgnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTguMjA5ODU5JyB5PSctMy4wNDkyOCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01My42MTMxNDQnIHk9Jy0zLjA0OTI4JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ2LjcxODA3MicgeT0nLTMuMDQ5MjgnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDQuNDE5NzE1JyB5PSctMy4wNDkyOCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zNy41MjQ2NDInIHk9Jy0zLjA0OTI4JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM1LjIyNjI4NScgeT0nLTMuMDQ5MjgnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzIuOTI3OTI3JyB5PSctMy4wNDkyOCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yNi4wMzI4NTUnIHk9Jy0zLjA0OTI4JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTIxLjQzNjE0JyB5PSctMy4wNDkyOCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xNi44Mzk0MjUnIHk9Jy0zLjA0OTI4JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE0LjU0MTA2NycgeT0nLTMuMDQ5MjgnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTIuMjQyNzEnIHk9Jy0zLjA0OTI4JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcuNjQ1OTk1JyB5PSctMy4wNDkyOCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zLjA0OTI4JyB5PSctMy4wNDkyOCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEuNTQ3NDM1JyB5PSctMy4wNDkyOCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzguNDQyNTA3JyB5PSctMy4wNDkyOCcgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEwLjc0MDg2NScgeT0nLTMuMDQ5MjgnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSctLjc1MDkyMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01OC4yMDk4NTknIHk9Jy0uNzUwOTIyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUxLjMxNDc4NycgeT0nLS43NTA5MjInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDYuNzE4MDcyJyB5PSctLjc1MDkyMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zOS44MjMnIHk9Jy0uNzUwOTIyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM3LjUyNDY0MicgeT0nLS43NTA5MjInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzUuMjI2Mjg1JyB5PSctLjc1MDkyMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zMC42Mjk1NycgeT0nLS43NTA5MjInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjMuNzM0NDk3JyB5PSctLjc1MDkyMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xNi44Mzk0MjUnIHk9Jy0uNzUwOTIyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTEyLjI0MjcxJyB5PSctLjc1MDkyMicgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy05Ljk0NDM1MicgeT0nLS43NTA5MjInIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNy42NDU5OTUnIHk9Jy0uNzUwOTIyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMS41NDc0MzUnIHk9Jy0uNzUwOTIyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMy44NDU3OTMnIHk9Jy0uNzUwOTIyJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTcyLjAwMDAwNCcgeT0nMS41NDc0MzUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjcuNDAzMjg5JyB5PScxLjU0NzQzNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02NS4xMDQ5MzInIHk9JzEuNTQ3NDM1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTYyLjgwNjU3NCcgeT0nMS41NDc0MzUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTguMjA5ODU5JyB5PScxLjU0NzQzNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01My42MTMxNDQnIHk9JzEuNTQ3NDM1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQ2LjcxODA3MicgeT0nMS41NDc0MzUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzcuNTI0NjQyJyB5PScxLjU0NzQzNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zMi45Mjc5MjcnIHk9JzEuNTQ3NDM1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTI2LjAzMjg1NScgeT0nMS41NDc0MzUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTkuMTM3NzgyJyB5PScxLjU0NzQzNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xNC41NDEwNjcnIHk9JzEuNTQ3NDM1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTkuOTQ0MzUyJyB5PScxLjU0NzQzNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy03LjY0NTk5NScgeT0nMS41NDc0MzUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNS4zNDc2MzcnIHk9JzEuNTQ3NDM1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMuMDQ5MjgnIHk9JzEuNTQ3NDM1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLS43NTA5MjInIHk9JzEuNTQ3NDM1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMS41NDc0MzUnIHk9JzEuNTQ3NDM1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nNi4xNDQxNScgeT0nMS41NDc0MzUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSczLjg0NTc5MycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02Ny40MDMyODknIHk9JzMuODQ1NzkzJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY1LjEwNDkzMicgeT0nMy44NDU3OTMnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjIuODA2NTc0JyB5PSczLjg0NTc5MycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01OC4yMDk4NTknIHk9JzMuODQ1NzkzJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUzLjYxMzE0NCcgeT0nMy44NDU3OTMnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTEuMzE0Nzg3JyB5PSczLjg0NTc5MycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00NC40MTk3MTUnIHk9JzMuODQ1NzkzJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQyLjEyMTM1NycgeT0nMy44NDU3OTMnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzkuODIzJyB5PSczLjg0NTc5MycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zNS4yMjYyODUnIHk9JzMuODQ1NzkzJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMwLjYyOTU3JyB5PSczLjg0NTc5MycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yOC4zMzEyMTInIHk9JzMuODQ1NzkzJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTIzLjczNDQ5NycgeT0nMy44NDU3OTMnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjEuNDM2MTQnIHk9JzMuODQ1NzkzJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE5LjEzNzc4MicgeT0nMy44NDU3OTMnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTYuODM5NDI1JyB5PSczLjg0NTc5MycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xMi4yNDI3MScgeT0nMy44NDU3OTMnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctOS45NDQzNTInIHk9JzMuODQ1NzkzJyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUuMzQ3NjM3JyB5PSczLjg0NTc5MycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zLjA0OTI4JyB5PSczLjg0NTc5MycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEuNTQ3NDM1JyB5PSczLjg0NTc5MycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzguNDQyNTA3JyB5PSczLjg0NTc5MycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEwLjc0MDg2NScgeT0nMy44NDU3OTMnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSc2LjE0NDE1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTY3LjQwMzI4OScgeT0nNi4xNDQxNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy02NS4xMDQ5MzInIHk9JzYuMTQ0MTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjIuODA2NTc0JyB5PSc2LjE0NDE1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTU4LjIwOTg1OScgeT0nNi4xNDQxNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01My42MTMxNDQnIHk9JzYuMTQ0MTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDIuMTIxMzU3JyB5PSc2LjE0NDE1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTM5LjgyMycgeT0nNi4xNDQxNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zNy41MjQ2NDInIHk9JzYuMTQ0MTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzUuMjI2Mjg1JyB5PSc2LjE0NDE1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTMyLjkyNzkyNycgeT0nNi4xNDQxNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zMC42Mjk1NycgeT0nNi4xNDQxNScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yMy43MzQ0OTcnIHk9JzYuMTQ0MTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMTYuODM5NDI1JyB5PSc2LjE0NDE1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLS43NTA5MjInIHk9JzYuMTQ0MTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSc2LjE0NDE1JyB5PSc2LjE0NDE1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nOC40NDI1MDcnIHk9JzYuMTQ0MTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PScxMC43NDA4NjUnIHk9JzYuMTQ0MTUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PSc4LjQ0MjUwNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy01OC4yMDk4NTknIHk9JzguNDQyNTA3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUzLjYxMzE0NCcgeT0nOC40NDI1MDcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDkuMDE2NDI5JyB5PSc4LjQ0MjUwNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy00NC40MTk3MTUnIHk9JzguNDQyNTA3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTQyLjEyMTM1NycgeT0nOC40NDI1MDcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzcuNTI0NjQyJyB5PSc4LjQ0MjUwNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zNS4yMjYyODUnIHk9JzguNDQyNTA3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTI4LjMzMTIxMicgeT0nOC40NDI1MDcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMjMuNzM0NDk3JyB5PSc4LjQ0MjUwNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xOS4xMzc3ODInIHk9JzguNDQyNTA3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTE2LjgzOTQyNScgeT0nOC40NDI1MDcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNy42NDU5OTUnIHk9JzguNDQyNTA3JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTUuMzQ3NjM3JyB5PSc4LjQ0MjUwNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0zLjA0OTI4JyB5PSc4LjQ0MjUwNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEuNTQ3NDM1JyB5PSc4LjQ0MjUwNycgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzEwLjc0MDg2NScgeT0nOC40NDI1MDcnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNzIuMDAwMDA0JyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjkuNzAxNjQ3JyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjcuNDAzMjg5JyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjUuMTA0OTMyJyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjIuODA2NTc0JyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNjAuNTA4MjE3JyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTguMjA5ODU5JyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNTMuNjEzMTQ0JyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDkuMDE2NDI5JyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctNDQuNDE5NzE1JyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzkuODIzJyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzIuOTI3OTI3JyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMzAuNjI5NTcnIHk9JzEwLjc0MDg2NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0yNi4wMzI4NTUnIHk9JzEwLjc0MDg2NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xNi44Mzk0MjUnIHk9JzEwLjc0MDg2NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xNC41NDEwNjcnIHk9JzEwLjc0MDg2NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9Jy0xMi4yNDI3MScgeT0nMTAuNzQwODY1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLTkuOTQ0MzUyJyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSctMy4wNDkyOCcgeT0nMTAuNzQwODY1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nLS43NTA5MjInIHk9JzEwLjc0MDg2NScgaGVpZ2h0PScyLjI5ODM1Nycgd2lkdGg9JzIuMjk4MzU3Jy8+CjxyZWN0IHg9JzMuODQ1NzkzJyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSc2LjE0NDE1JyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8cmVjdCB4PSc4LjQ0MjUwNycgeT0nMTAuNzQwODY1JyBoZWlnaHQ9JzIuMjk4MzU3JyB3aWR0aD0nMi4yOTgzNTcnLz4KPHJlY3QgeD0nMTAuNzQwODY1JyB5PScxMC43NDA4NjUnIGhlaWdodD0nMi4yOTgzNTcnIHdpZHRoPScyLjI5ODM1NycvPgo8L2c+Cjwvc3ZnPg==")} +}